summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorElizabeth Hunt <me@liz.coffee>2025-07-27 18:50:33 -0700
committerElizabeth Hunt <me@liz.coffee>2025-07-27 19:31:06 -0700
commit7aa11b7a8abacf81dec20fff21216df35d333756 (patch)
tree40f6a76c37412cf1c5a67f99a4ee30e3aae863c9
parente4df72cd446270cf867ec308995a05e21b3aa601 (diff)
downloadci-7aa11b7a8abacf81dec20fff21216df35d333756.tar.gz
ci-7aa11b7a8abacf81dec20fff21216df35d333756.zip
Pulls in pengueno from npm
-rw-r--r--model/package.json2
-rw-r--r--model/tsconfig.json3
-rw-r--r--package-lock.json41
-rw-r--r--package.json1
-rw-r--r--server/package.json6
-rw-r--r--server/tsconfig.json2
-rw-r--r--tsconfig.json3
-rw-r--r--u/index.ts5
-rw-r--r--u/leftpadesque/debug.ts8
-rw-r--r--u/leftpadesque/index.ts3
-rw-r--r--u/leftpadesque/memoize.ts14
-rw-r--r--u/leftpadesque/prepend.ts5
-rw-r--r--u/package.json47
-rw-r--r--u/process/argv.ts79
-rw-r--r--u/process/env.ts25
-rw-r--r--u/process/exec.ts86
-rw-r--r--u/process/index.ts5
-rw-r--r--u/process/signals.ts49
-rw-r--r--u/process/validate_identifier.ts18
-rw-r--r--u/server/activity/fourohfour.ts28
-rw-r--r--u/server/activity/health.ts49
-rw-r--r--u/server/activity/index.ts8
-rw-r--r--u/server/filter/index.ts34
-rw-r--r--u/server/filter/json.ts42
-rw-r--r--u/server/filter/method.ts30
-rw-r--r--u/server/http/body.ts10
-rw-r--r--u/server/http/index.ts3
-rw-r--r--u/server/http/method.ts1
-rw-r--r--u/server/http/status.ts71
-rw-r--r--u/server/index.ts13
-rw-r--r--u/server/request/index.ts18
-rw-r--r--u/server/request/pengueno.ts44
-rw-r--r--u/server/response/index.ts18
-rw-r--r--u/server/response/json_pengueno.ts29
-rw-r--r--u/server/response/pengueno.ts59
-rw-r--r--u/trace/index.ts5
-rw-r--r--u/trace/itrace.ts91
-rw-r--r--u/trace/log/ansi.ts15
-rw-r--r--u/trace/log/index.ts5
-rw-r--r--u/trace/log/level.ts19
-rw-r--r--u/trace/log/logger.ts5
-rw-r--r--u/trace/log/pretty_json_console.ts39
-rw-r--r--u/trace/log/trace.ts60
-rw-r--r--u/trace/metric/emittable.ts18
-rw-r--r--u/trace/metric/index.ts41
-rw-r--r--u/trace/metric/metric.ts54
-rw-r--r--u/trace/metric/trace.ts59
-rw-r--r--u/trace/trace.ts77
-rw-r--r--u/trace/util.ts59
-rw-r--r--u/tsconfig.json15
-rw-r--r--u/types/collections/cons.ts40
-rw-r--r--u/types/collections/index.ts2
-rw-r--r--u/types/collections/list_zipper.ts70
-rw-r--r--u/types/fn/callable.ts21
-rw-r--r--u/types/fn/either.ts143
-rw-r--r--u/types/fn/index.ts3
-rw-r--r--u/types/fn/optional.ts93
-rw-r--r--u/types/index.ts7
-rw-r--r--u/types/misc.ts3
-rw-r--r--u/types/object.ts1
-rw-r--r--u/types/tagged.ts8
-rw-r--r--worker/package.json4
-rw-r--r--worker/scripts/npm_publish.ts0
-rw-r--r--worker/tsconfig.json2
64 files changed, 34 insertions, 1784 deletions
diff --git a/model/package.json b/model/package.json
index 23cfd52..5d5cec4 100644
--- a/model/package.json
+++ b/model/package.json
@@ -17,7 +17,7 @@
"type-check": "tsc --noEmit"
},
"dependencies": {
- "@emprespresso/pengueno": "*"
+ "@emprespresso/pengueno": "^0.0.5"
},
"files": [
"dist/**/*",
diff --git a/model/tsconfig.json b/model/tsconfig.json
index 7ad21ad..98e457c 100644
--- a/model/tsconfig.json
+++ b/model/tsconfig.json
@@ -10,6 +10,5 @@
"noEmit": false
},
"include": ["**/*.ts"],
- "exclude": ["node_modules", "dist", "**/*.test.ts", "**/*.spec.ts"],
- "references": [{ "path": "../u" }]
+ "exclude": ["node_modules", "dist", "**/*.test.ts", "**/*.spec.ts"]
}
diff --git a/package-lock.json b/package-lock.json
index a04d81d..8522d1f 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -8,7 +8,6 @@
"name": "@emprespresso/ci",
"version": "0.1.0",
"workspaces": [
- "u",
"model",
"server",
"worker"
@@ -41,7 +40,7 @@
"name": "@emprespresso/ci_model",
"version": "0.1.0",
"dependencies": {
- "@emprespresso/pengueno": "*"
+ "@emprespresso/pengueno": "^0.0.5"
}
},
"node_modules/@emprespresso/ci_model": {
@@ -57,8 +56,17 @@
"link": true
},
"node_modules/@emprespresso/pengueno": {
- "resolved": "u",
- "link": true
+ "version": "0.0.5",
+ "resolved": "https://registry.npmjs.org/@emprespresso/pengueno/-/pengueno-0.0.5.tgz",
+ "integrity": "sha512-UvkcchpQfD6EeIaoyeMtBC1WfjF21O+y1WFIM2Nft5R4vRcPefa2xtGHZep7JSE9Fi98sp02LKhY9YAZHxXhCw==",
+ "license": "MIT",
+ "dependencies": {
+ "module-alias": "^2.2.3"
+ },
+ "engines": {
+ "node": ">=22.16.0",
+ "npm": ">=10.0.0"
+ }
},
"node_modules/@eslint-community/eslint-utils": {
"version": "4.7.0",
@@ -1311,9 +1319,9 @@
}
},
"node_modules/hono": {
- "version": "4.8.1",
- "resolved": "https://registry.npmjs.org/hono/-/hono-4.8.1.tgz",
- "integrity": "sha512-ErA2ifywnSmcnB5XDuFqGDfXJ9xuAJR2C/8cZAk6vDaOCzofB8eNlha/wZWIiamREzWk94S9Z7wHsnKQHn7Niw==",
+ "version": "4.8.9",
+ "resolved": "https://registry.npmjs.org/hono/-/hono-4.8.9.tgz",
+ "integrity": "sha512-ERIxkXMRhUxGV7nS/Af52+j2KL60B1eg+k6cPtgzrGughS+espS9KQ7QO0SMnevtmRlBfAcN0mf1jKtO6j/doA==",
"license": "MIT",
"engines": {
"node": ">=16.9.0"
@@ -1576,6 +1584,12 @@
"node": ">=10"
}
},
+ "node_modules/module-alias": {
+ "version": "2.2.3",
+ "resolved": "https://registry.npmjs.org/module-alias/-/module-alias-2.2.3.tgz",
+ "integrity": "sha512-23g5BFj4zdQL/b6tor7Ji+QY4pEfNH784BMslY9Qb0UnJWRAt+lQGLYmRaM0KDBwIG23ffEBELhZDP2rhi9f/Q==",
+ "license": "MIT"
+ },
"node_modules/ms": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
@@ -2268,16 +2282,9 @@
"version": "0.1.0",
"dependencies": {
"@emprespresso/ci_model": "*",
- "@emprespresso/pengueno": "*",
+ "@emprespresso/pengueno": "^0.0.5",
"@hono/node-server": "^1.14.0",
- "hono": "^4.8.0"
- }
- },
- "u": {
- "name": "@emprespresso/pengueno",
- "version": "0.1.0",
- "dependencies": {
- "hono": "^4.8.0"
+ "hono": "^4.8.9"
}
},
"worker": {
@@ -2285,7 +2292,7 @@
"version": "0.1.0",
"dependencies": {
"@emprespresso/ci_model": "*",
- "@emprespresso/pengueno": "*"
+ "@emprespresso/pengueno": "^0.0.5"
},
"devDependencies": {
"copyfiles": "2.4.1"
diff --git a/package.json b/package.json
index cd56ad8..c14f900 100644
--- a/package.json
+++ b/package.json
@@ -4,7 +4,6 @@
"private": true,
"type": "module",
"workspaces": [
- "u",
"model",
"server",
"worker"
diff --git a/server/package.json b/server/package.json
index e5e808e..f29d460 100644
--- a/server/package.json
+++ b/server/package.json
@@ -20,10 +20,10 @@
"format:check": "prettier --check ."
},
"dependencies": {
- "@emprespresso/pengueno": "*",
+ "@emprespresso/pengueno": "^0.0.5",
"@emprespresso/ci_model": "*",
- "hono": "^4.8.0",
- "@hono/node-server": "^1.14.0"
+ "@hono/node-server": "^1.14.0",
+ "hono": "^4.8.9"
},
"files": [
"dist/**/*",
diff --git a/server/tsconfig.json b/server/tsconfig.json
index 58e9147..3858ff4 100644
--- a/server/tsconfig.json
+++ b/server/tsconfig.json
@@ -11,5 +11,5 @@
},
"include": ["**/*.ts"],
"exclude": ["node_modules", "dist", "**/*.test.ts", "**/*.spec.ts"],
- "references": [{ "path": "../u" }, { "path": "../model" }]
+ "references": [{ "path": "../model" }]
}
diff --git a/tsconfig.json b/tsconfig.json
index a28cdaf..83c85af 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -17,7 +17,6 @@
"noFallthroughCasesInSwitch": true,
"lib": ["ES2022"],
"paths": {
- "@emprespresso/pengueno": ["./u/index.ts"],
"@emprespresso/ci_model": ["./model/index.ts"],
"@emprespresso/ci_server": ["./server/index.ts"],
"@emprespresso/ci_worker": ["./worker/index.ts"]
@@ -25,5 +24,5 @@
},
"include": ["**/*.ts", "**/*.js"],
"exclude": ["node_modules", "dist", "**/*.d.ts"],
- "references": [{ "path": "./u" }, { "path": "./model" }, { "path": "./server" }, { "path": "./worker" }]
+ "references": [{ "path": "./model" }, { "path": "./server" }, { "path": "./worker" }]
}
diff --git a/u/index.ts b/u/index.ts
deleted file mode 100644
index e2e0768..0000000
--- a/u/index.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-export * from './leftpadesque/index.js';
-export * from './trace/index.js';
-export * from './process/index.js';
-export * from './server/index.js';
-export * from './types/index.js';
diff --git a/u/leftpadesque/debug.ts b/u/leftpadesque/debug.ts
deleted file mode 100644
index 074e567..0000000
--- a/u/leftpadesque/debug.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-const _hasEnv = true; // Node.js always has access to environment variables
-
-const _env: 'development' | 'production' =
- _hasEnv && (process.env.ENVIRONMENT ?? '').toLowerCase().includes('prod') ? 'production' : 'development';
-export const isProd = () => _env === 'production';
-
-const _debug = !isProd() || (_hasEnv && ['y', 't'].some((process.env.DEBUG ?? '').toLowerCase().startsWith));
-export const isDebug = () => _debug;
diff --git a/u/leftpadesque/index.ts b/u/leftpadesque/index.ts
deleted file mode 100644
index 09a0bd1..0000000
--- a/u/leftpadesque/index.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-export * from './prepend.js';
-export * from './debug.js';
-export * from './memoize.js';
diff --git a/u/leftpadesque/memoize.ts b/u/leftpadesque/memoize.ts
deleted file mode 100644
index 541bd20..0000000
--- a/u/leftpadesque/memoize.ts
+++ /dev/null
@@ -1,14 +0,0 @@
-import type { Callable } from '@emprespresso/pengueno';
-
-export const memoize = <R, F extends Callable<R>>(fn: F): F => {
- const cache = new Map<string, R>();
- return ((...args: unknown[]): R => {
- const key = JSON.stringify(args);
- if (cache.has(key)) {
- return cache.get(key)!;
- }
- const res = fn.apply(args);
- cache.set(key, res);
- return res;
- }) as F;
-};
diff --git a/u/leftpadesque/prepend.ts b/u/leftpadesque/prepend.ts
deleted file mode 100644
index 1819536..0000000
--- a/u/leftpadesque/prepend.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-export const prependWith = (arr: string[], prep: string) =>
- Array(arr.length * 2)
- .fill(0)
- .map((_, i) => i % 2 === 0)
- .map((isPrep, i) => (isPrep ? prep : arr[Math.floor(i / 2)]!));
diff --git a/u/package.json b/u/package.json
deleted file mode 100644
index d38ac4c..0000000
--- a/u/package.json
+++ /dev/null
@@ -1,47 +0,0 @@
-{
- "name": "@emprespresso/pengueno",
- "version": "0.1.0",
- "type": "module",
- "main": "./dist/index.js",
- "types": "./dist/index.d.ts",
- "exports": {
- ".": {
- "types": "./dist/index.d.ts",
- "import": "./dist/index.js"
- },
- "./fn": {
- "types": "./dist/fn/index.d.ts",
- "import": "./dist/fn/index.js"
- },
- "./leftpadesque": {
- "types": "./dist/leftpadesque/index.d.ts",
- "import": "./dist/leftpadesque/index.js"
- },
- "./process": {
- "types": "./dist/process/index.d.ts",
- "import": "./dist/process/index.js"
- },
- "./trace": {
- "types": "./dist/trace/index.d.ts",
- "import": "./dist/trace/index.js"
- },
- "./server": {
- "types": "./dist/server/index.d.ts",
- "import": "./dist/server/index.js"
- }
- },
- "scripts": {
- "build": "tsc",
- "dev": "tsc --watch",
- "clean": "rm -rf dist",
- "type-check": "tsc --noEmit"
- },
- "dependencies": {
- "hono": "^4.8.0"
- },
- "files": [
- "dist/**/*",
- "package.json",
- "README.md"
- ]
-}
diff --git a/u/process/argv.ts b/u/process/argv.ts
deleted file mode 100644
index 396fa96..0000000
--- a/u/process/argv.ts
+++ /dev/null
@@ -1,79 +0,0 @@
-import { Either, type Mapper, type IEither, Optional } from '@emprespresso/pengueno';
-
-export const isArgKey = <K extends string>(k: string): k is K => k.startsWith('--');
-
-interface ArgHandler<V> {
- absent?: V;
- unspecified?: V;
- present: Mapper<string, V>;
-}
-
-export const getArg = <K extends string, V>(
- arg: K,
- argv: Array<string>,
- whenValue: ArgHandler<V>,
-): IEither<Error, V> => {
- const argIndex = Optional.from(argv.findIndex((_argv) => isArgKey(_argv) && _argv.split('=')[0] === arg)).filter(
- (index) => index >= 0 && index < argv.length,
- );
- if (!argIndex.present()) {
- return Optional.from(whenValue.absent)
- .map((v) => Either.right<Error, V>(v))
- .orSome(() =>
- Either.left(
- new Error(`arg ${arg} is not present in arguments list and does not have an 'absent' value`),
- ),
- )
- .get();
- }
-
- return argIndex
- .flatMap((idx) =>
- Optional.from(argv.at(idx)).map((_argv) => (_argv.includes('=') ? _argv.split('=')[1] : argv.at(idx + 1))),
- )
- .filter((next) => !isArgKey(next))
- .map((next) => whenValue.present(next))
- .orSome(() => whenValue.unspecified)
- .map((v) => Either.right<Error, V>(<V>v))
- .get();
-};
-
-type MappedArgs<
- Args extends ReadonlyArray<string>,
- Handlers extends Partial<Record<Args[number], ArgHandler<unknown>>>,
-> = {
- [K in Args[number]]: K extends keyof Handlers ? (Handlers[K] extends ArgHandler<infer T> ? T : string) : string;
-};
-
-export const argv = <
- const Args extends ReadonlyArray<string>,
- const Handlers extends Partial<Record<Args[number], ArgHandler<unknown>>>,
->(
- args: Args,
- handlers?: Handlers,
- argv = process.argv.slice(2),
-): IEither<Error, MappedArgs<Args, Handlers>> => {
- type Result = MappedArgs<Args, Handlers>;
-
- const defaultHandler: ArgHandler<string> = { present: (value: string) => value };
-
- const processArg = (arg: Args[number]): IEither<Error, [Args[number], unknown]> => {
- const handler = handlers?.[arg] ?? defaultHandler;
- return getArg(arg, argv, handler).mapRight((value) => [arg, value] as const);
- };
-
- const res = args
- .map(processArg)
- .reduce(
- (acc: IEither<Error, Partial<Result>>, current: IEither<Error, [Args[number], unknown]>) =>
- acc.flatMap((accValue) =>
- current.mapRight(([key, value]) => ({
- ...accValue,
- [key]: value,
- })),
- ),
- Either.right(<Partial<Result>>{}),
- )
- .mapRight((result) => <Result>result);
- return res;
-};
diff --git a/u/process/env.ts b/u/process/env.ts
deleted file mode 100644
index f59fadf..0000000
--- a/u/process/env.ts
+++ /dev/null
@@ -1,25 +0,0 @@
-import { IOptional, Either, Optional, type IEither, type ObjectFromList } from '@emprespresso/pengueno';
-
-// type safe environment variables
-
-export const getEnv = (name: string): IOptional<string> => Optional.from(process.env[name]);
-
-export const getRequiredEnv = <V extends string>(name: V): IEither<Error, string> =>
- Either.fromFailable(() => getEnv(name).get()).mapLeft(
- () => new Error(`environment variable "${name}" is required D:`),
- );
-
-export const getRequiredEnvVars = <V extends string>(vars: Array<V>): IEither<Error, ObjectFromList<typeof vars>> => {
- type Environment = ObjectFromList<typeof vars>;
- const emptyEnvironment = Either.right<Error, Environment>(<Environment>{});
- const addTo = (env: Environment, key: V, val: string) =>
- <Environment>{
- ...env,
- [key]: val,
- };
- return vars.reduce(
- (environment, key) =>
- environment.joinRight(getRequiredEnv(key), (value, environment) => addTo(environment, key, value)),
- emptyEnvironment,
- );
-};
diff --git a/u/process/exec.ts b/u/process/exec.ts
deleted file mode 100644
index 46b31c4..0000000
--- a/u/process/exec.ts
+++ /dev/null
@@ -1,86 +0,0 @@
-import {
- Either,
- IEither,
- type ITraceable,
- LogLevel,
- LogMetricTraceSupplier,
- Metric,
- TraceUtil,
-} from '@emprespresso/pengueno';
-import { exec } from 'node:child_process';
-
-export type Command = string[] | string;
-export type StdStreams = { stdout: string; stderr: string };
-
-export const CmdMetric = Metric.fromName('Exec').asResult();
-type Environment = Record<string, string>;
-type Options = { streamTraceable?: Array<'stdout' | 'stderr'>; env?: Environment; clearEnv?: boolean };
-export const getStdout = (
- cmd: ITraceable<Command, LogMetricTraceSupplier>,
- options: Options = { streamTraceable: [] },
-): Promise<IEither<Error, string>> =>
- cmd
- .flatMap(TraceUtil.withFunctionTrace(getStdout))
- .flatMap((tCmd) => tCmd.traceScope(() => `Command = ${tCmd.get()}`))
- .map((tCmd) => {
- const cmd = tCmd.get();
- const _exec = typeof cmd === 'string' ? cmd : cmd.join(' ');
- const env = options.clearEnv ? options.env : { ...process.env, ...options.env };
- return Either.fromFailableAsync<Error, StdStreams>(
- new Promise<StdStreams>((res, rej) => {
- const proc = exec(_exec, { env });
- let stdout = '';
- proc.stdout?.on('data', (d) => {
- const s = d.toString();
- stdout += s;
- if (options.streamTraceable?.includes('stdout')) {
- tCmd.trace.trace(s);
- }
- });
- let stderr = '';
- proc.stderr?.on('data', (d) => {
- const s = d.toString();
- stdout += s;
- if (options.streamTraceable?.includes('stderr')) {
- tCmd.trace.trace(s);
- }
- });
-
- proc.on('exit', (code) => {
- const streams = { stdout, stderr };
- if (code === 0) {
- res(streams);
- } else {
- rej(new Error(`exited with non-zero code: ${code}. ${stderr}`));
- }
- });
- }),
- );
- })
- .map(
- TraceUtil.promiseify((tEitherStdStreams) =>
- tEitherStdStreams.get().mapRight(({ stderr, stdout }) => {
- if (stderr) tEitherStdStreams.trace.traceScope(LogLevel.DEBUG).trace(`StdErr = ${stderr}`);
- return stdout;
- }),
- ),
- )
- .peek(TraceUtil.promiseify(TraceUtil.traceResultingEither(CmdMetric)))
- .get();
-
-export const getStdoutMany = (
- cmds: ITraceable<Array<Command>, LogMetricTraceSupplier>,
- options: Options = { streamTraceable: [] },
-): Promise<IEither<Error, Array<string>>> =>
- cmds
- .coExtend((t) => t.get())
- .reduce(
- async (_result, tCmd) => {
- const result = await _result;
- return result.joinRightAsync(
- () => tCmd.map((cmd) => getStdout(cmd, options)).get(),
- (stdout, pre) => pre.concat(stdout),
- );
- },
- Promise.resolve(Either.right<Error, Array<string>>([])),
- );
diff --git a/u/process/index.ts b/u/process/index.ts
deleted file mode 100644
index 2d74a5f..0000000
--- a/u/process/index.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-export * from './exec.js';
-export * from './env.js';
-export * from './validate_identifier.js';
-export * from './argv.js';
-export * from './signals.js';
diff --git a/u/process/signals.ts b/u/process/signals.ts
deleted file mode 100644
index c4feb7a..0000000
--- a/u/process/signals.ts
+++ /dev/null
@@ -1,49 +0,0 @@
-import {
- Either,
- IEither,
- IMetric,
- ITraceable,
- LogMetricTrace,
- LogMetricTraceSupplier,
- Mapper,
- Metric,
- Optional,
- ResultMetric,
- SideEffect,
- TraceUtil,
-} from '@emprespresso/pengueno';
-
-export const SigIntMetric = Metric.fromName('SigInt').asResult();
-export const SigTermMetric = Metric.fromName('SigTerm').asResult();
-
-export interface Closeable<TFailure> {
- readonly close: SideEffect<SideEffect<TFailure | undefined>>;
-}
-
-export class Signals {
- public static async awaitClose<E extends Error>(
- t: ITraceable<Closeable<E>, LogMetricTraceSupplier>,
- ): Promise<IEither<Error, void>> {
- const success: IEither<Error, void> = Either.right(<void>undefined);
- return new Promise<IEither<Error, void>>((res) => {
- const metricizedInterruptHandler = (metric: ResultMetric) => (err: Error | undefined) =>
- t
- .flatMap(TraceUtil.withMetricTrace(metric))
- .peek((_t) => _t.trace.trace('closing'))
- .move(
- Optional.from(err)
- .map((e) => Either.left<Error, void>(e))
- .orSome(() => success)
- .get(),
- )
- .flatMap(TraceUtil.traceResultingEither(metric))
- .map((e) => res(e.get()))
- .peek((_t) => _t.trace.trace('finished'))
- .get();
- const sigintCloser = metricizedInterruptHandler(SigIntMetric);
- const sigtermCloser = metricizedInterruptHandler(SigTermMetric);
- process.on('SIGINT', () => t.flatMap(TraceUtil.withTrace('SIGINT')).get().close(sigintCloser));
- process.on('SIGTERM', () => t.flatMap(TraceUtil.withTrace('SIGTERM')).get().close(sigtermCloser));
- });
- }
-}
diff --git a/u/process/validate_identifier.ts b/u/process/validate_identifier.ts
deleted file mode 100644
index 1ff3791..0000000
--- a/u/process/validate_identifier.ts
+++ /dev/null
@@ -1,18 +0,0 @@
-import { Either, type IEither } from '@emprespresso/pengueno';
-
-export const validateIdentifier = (token: string) => {
- return /^[a-zA-Z0-9_\-:. \/]+$/.test(token) && !token.includes('..');
-};
-
-// ensure {@param obj} is a Record<string, string> with stuff that won't
-// have the potential for shell injection, just to be super safe.
-type InvalidEntry<K, T> = [K, T];
-export const validateExecutionEntries = <T, K extends symbol | number | string = symbol | number | string>(
- obj: Record<K, T>,
-): IEither<Array<InvalidEntry<K, T>>, Record<string, string>> => {
- const invalidEntries = <Array<InvalidEntry<K, T>>>(
- Object.entries(obj).filter((e) => !e.every((x) => typeof x === 'string' && validateIdentifier(x)))
- );
- if (invalidEntries.length > 0) return Either.left(invalidEntries);
- return Either.right(<Record<string, string>>obj);
-};
diff --git a/u/server/activity/fourohfour.ts b/u/server/activity/fourohfour.ts
deleted file mode 100644
index cd90ba0..0000000
--- a/u/server/activity/fourohfour.ts
+++ /dev/null
@@ -1,28 +0,0 @@
-import {
- type IActivity,
- type ITraceable,
- JsonResponse,
- type PenguenoRequest,
- type ServerTrace,
-} from '@emprespresso/pengueno';
-
-const messages = [
- 'D: meow-t found! your api call ran away!',
- '404-bidden! but like...in a cute way >:3 !',
- ':< your data went on a paw-sible vacation!',
- 'uwu~ not found, but found our hearts instead!',
-];
-const randomFourOhFour = () => messages[Math.floor(Math.random() * messages.length)]!;
-
-export interface IFourOhFourActivity {
- fourOhFour: IActivity;
-}
-
-export class FourOhFourActivityImpl implements IFourOhFourActivity {
- public fourOhFour(req: ITraceable<PenguenoRequest, ServerTrace>) {
- return req
- .move(new JsonResponse(req, randomFourOhFour(), { status: 404 }))
- .map((resp) => Promise.resolve(resp.get()))
- .get();
- }
-}
diff --git a/u/server/activity/health.ts b/u/server/activity/health.ts
deleted file mode 100644
index 9396490..0000000
--- a/u/server/activity/health.ts
+++ /dev/null
@@ -1,49 +0,0 @@
-import {
- type IActivity,
- type IEither,
- IMetric,
- type ITraceable,
- JsonResponse,
- LogLevel,
- type Mapper,
- Metric,
- type PenguenoRequest,
- type ServerTrace,
- TraceUtil,
-} from '@emprespresso/pengueno';
-
-export enum HealthCheckInput {
- CHECK,
-}
-export enum HealthCheckOutput {
- YAASSSLAYQUEEN,
-}
-
-export interface IHealthCheckActivity {
- checkHealth: IActivity;
-}
-
-const healthCheckMetric = Metric.fromName('Health').asResult();
-export interface HealthChecker
- extends Mapper<ITraceable<HealthCheckInput, ServerTrace>, Promise<IEither<Error, HealthCheckOutput>>> {}
-export class HealthCheckActivityImpl implements IHealthCheckActivity {
- constructor(private readonly check: HealthChecker) {}
-
- public checkHealth(req: ITraceable<PenguenoRequest, ServerTrace>) {
- return req
- .flatMap(TraceUtil.withFunctionTrace(this.checkHealth))
- .flatMap(TraceUtil.withMetricTrace(healthCheckMetric))
- .flatMap((r) => r.move(HealthCheckInput.CHECK).map((input) => this.check(input)))
- .peek(TraceUtil.promiseify(TraceUtil.traceResultingEither(healthCheckMetric)))
- .map(
- TraceUtil.promiseify((h) => {
- const { status, message } = h.get().fold(
- () => ({ status: 500, message: 'err' }),
- () => ({ status: 200, message: 'ok' }),
- );
- return new JsonResponse(req, message, { status });
- }),
- )
- .get();
- }
-}
diff --git a/u/server/activity/index.ts b/u/server/activity/index.ts
deleted file mode 100644
index fa0a6b2..0000000
--- a/u/server/activity/index.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-import type { ITraceable, PenguenoRequest, PenguenoResponse, ServerTrace } from '@emprespresso/pengueno';
-
-export interface IActivity {
- (req: ITraceable<PenguenoRequest, ServerTrace>): Promise<PenguenoResponse>;
-}
-
-export * from './health.js';
-export * from './fourohfour.js';
diff --git a/u/server/filter/index.ts b/u/server/filter/index.ts
deleted file mode 100644
index 75168c7..0000000
--- a/u/server/filter/index.ts
+++ /dev/null
@@ -1,34 +0,0 @@
-import {
- type IEither,
- type ITraceable,
- LogLevel,
- type PenguenoRequest,
- type ServerTrace,
-} from '@emprespresso/pengueno';
-
-export enum ErrorSource {
- USER = LogLevel.WARN,
- SYSTEM = LogLevel.ERROR,
-}
-
-export class PenguenoError extends Error {
- public readonly source: ErrorSource;
- constructor(
- override readonly message: string,
- public readonly status: number,
- ) {
- super(message);
- this.source = Math.floor(status / 100) === 4 ? ErrorSource.USER : ErrorSource.SYSTEM;
- }
-}
-
-export interface RequestFilter<
- T,
- Err extends PenguenoError = PenguenoError,
- RIn = ITraceable<PenguenoRequest, ServerTrace>,
-> {
- (req: RIn): IEither<Err, T> | Promise<IEither<Err, T>>;
-}
-
-export * from './method.js';
-export * from './json.js';
diff --git a/u/server/filter/json.ts b/u/server/filter/json.ts
deleted file mode 100644
index bc53d47..0000000
--- a/u/server/filter/json.ts
+++ /dev/null
@@ -1,42 +0,0 @@
-import {
- Either,
- type IEither,
- type ITraceable,
- LogLevel,
- Metric,
- PenguenoError,
- type PenguenoRequest,
- type RequestFilter,
- type ServerTrace,
- TraceUtil,
-} from '@emprespresso/pengueno';
-
-export interface JsonTransformer<R, ParsedJson = unknown> {
- (json: ITraceable<ParsedJson, ServerTrace>): IEither<PenguenoError, R>;
-}
-
-const ParseJsonMetric = Metric.fromName('JsonParse').asResult();
-export const jsonModel =
- <MessageT>(jsonTransformer: JsonTransformer<MessageT>): RequestFilter<MessageT> =>
- (r: ITraceable<PenguenoRequest, ServerTrace>) =>
- r
- .flatMap(TraceUtil.withFunctionTrace(jsonModel))
- .flatMap(TraceUtil.withMetricTrace(ParseJsonMetric))
- .map((j) =>
- Either.fromFailableAsync<Error, MessageT>(<Promise<MessageT>>j.get().req.json()).then((either) =>
- either.mapLeft((errReason) => {
- j.trace.traceScope(LogLevel.WARN).trace(errReason);
- return new PenguenoError('seems to be invalid JSON (>//<) can you fix?', 400);
- }),
- ),
- )
- .flatMapAsync(TraceUtil.promiseify(TraceUtil.traceResultingEither(ParseJsonMetric)))
- .map(
- TraceUtil.promiseify((traceableEitherJson) =>
- traceableEitherJson
- .get()
- .mapRight((j) => traceableEitherJson.move(j))
- .flatMap(jsonTransformer),
- ),
- )
- .get();
diff --git a/u/server/filter/method.ts b/u/server/filter/method.ts
deleted file mode 100644
index 7d6aa76..0000000
--- a/u/server/filter/method.ts
+++ /dev/null
@@ -1,30 +0,0 @@
-import {
- Either,
- HttpMethod,
- IEither,
- type ITraceable,
- LogLevel,
- PenguenoError,
- type PenguenoRequest,
- type RequestFilter,
- type ServerTrace,
- TraceUtil,
-} from '@emprespresso/pengueno';
-
-export const requireMethod =
- (methods: Array<HttpMethod>): RequestFilter<HttpMethod> =>
- (req: ITraceable<PenguenoRequest, ServerTrace>) =>
- req
- .flatMap(TraceUtil.withFunctionTrace(requireMethod))
- .map((t): IEither<PenguenoError, HttpMethod> => {
- const {
- req: { method },
- } = t.get();
- if (!methods.includes(method)) {
- const msg = "that's not how you pet me (⋟﹏⋞)~";
- t.trace.traceScope(LogLevel.WARN).trace(msg);
- return Either.left(new PenguenoError(msg, 405));
- }
- return Either.right(method);
- })
- .get();
diff --git a/u/server/http/body.ts b/u/server/http/body.ts
deleted file mode 100644
index 5fc4caa..0000000
--- a/u/server/http/body.ts
+++ /dev/null
@@ -1,10 +0,0 @@
-export type Body =
- | ArrayBuffer
- | AsyncIterable<Uint8Array>
- | Blob
- | FormData
- | Iterable<Uint8Array>
- | NodeJS.ArrayBufferView
- | URLSearchParams
- | null
- | string;
diff --git a/u/server/http/index.ts b/u/server/http/index.ts
deleted file mode 100644
index ef1c039..0000000
--- a/u/server/http/index.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-export * from './body.js';
-export * from './status.js';
-export * from './method.js';
diff --git a/u/server/http/method.ts b/u/server/http/method.ts
deleted file mode 100644
index 172d77a..0000000
--- a/u/server/http/method.ts
+++ /dev/null
@@ -1 +0,0 @@
-export type HttpMethod = 'POST' | 'GET' | 'HEAD' | 'PUT' | 'DELETE' | 'CONNECT' | 'OPTIONS' | 'TRACE' | 'PATCH';
diff --git a/u/server/http/status.ts b/u/server/http/status.ts
deleted file mode 100644
index 15cb30c..0000000
--- a/u/server/http/status.ts
+++ /dev/null
@@ -1,71 +0,0 @@
-export const HttpStatusCodes: Record<number, string> = {
- 100: 'Continue',
- 101: 'Switching Protocols',
- 102: 'Processing (WebDAV)',
- 200: 'OK',
- 201: 'Created',
- 202: 'Accepted',
- 203: 'Non-Authoritative Information',
- 204: 'No Content',
- 205: 'Reset Content',
- 206: 'Partial Content',
- 207: 'Multi-Status (WebDAV)',
- 208: 'Already Reported (WebDAV)',
- 226: 'IM Used',
- 300: 'Multiple Choices',
- 301: 'Moved Permanently',
- 302: 'Found',
- 303: 'See Other',
- 304: 'Not Modified',
- 305: 'Use Proxy',
- 306: '(Unused)',
- 307: 'Temporary Redirect',
- 308: 'Permanent Redirect (experimental)',
- 400: 'Bad Request',
- 401: 'Unauthorized',
- 402: 'Payment Required',
- 403: 'Forbidden',
- 404: 'Not Found',
- 405: 'Method Not Allowed',
- 406: 'Not Acceptable',
- 407: 'Proxy Authentication Required',
- 408: 'Request Timeout',
- 409: 'Conflict',
- 410: 'Gone',
- 411: 'Length Required',
- 412: 'Precondition Failed',
- 413: 'Request Entity Too Large',
- 414: 'Request-URI Too Long',
- 415: 'Unsupported Media Type',
- 416: 'Requested Range Not Satisfiable',
- 417: 'Expectation Failed',
- 418: "I'm a teapot (RFC 2324)",
- 420: 'Enhance Your Calm (Twitter)',
- 422: 'Unprocessable Entity (WebDAV)',
- 423: 'Locked (WebDAV)',
- 424: 'Failed Dependency (WebDAV)',
- 425: 'Reserved for WebDAV',
- 426: 'Upgrade Required',
- 428: 'Precondition Required',
- 429: 'Too Many Requests',
- 431: 'Request Header Fields Too Large',
- 444: 'No Response (Nginx)',
- 449: 'Retry With (Microsoft)',
- 450: 'Blocked by Windows Parental Controls (Microsoft)',
- 451: 'Unavailable For Legal Reasons',
- 499: 'Client Closed Request (Nginx)',
- 500: 'Internal Server Error',
- 501: 'Not Implemented',
- 502: 'Bad Gateway',
- 503: 'Service Unavailable',
- 504: 'Gateway Timeout',
- 505: 'HTTP Version Not Supported',
- 506: 'Variant Also Negotiates (Experimental)',
- 507: 'Insufficient Storage (WebDAV)',
- 508: 'Loop Detected (WebDAV)',
- 509: 'Bandwidth Limit Exceeded (Apache)',
- 510: 'Not Extended',
- 511: 'Network Authentication Required',
- 598: 'Network read timeout error',
- 599: 'Network connect timeout error',
-};
diff --git a/u/server/index.ts b/u/server/index.ts
deleted file mode 100644
index 1cefb71..0000000
--- a/u/server/index.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-import type { ITraceable, LogMetricTraceSupplier, Mapper } from '@emprespresso/pengueno';
-export type ServerTrace = LogMetricTraceSupplier;
-
-export * from './http/index.js';
-export * from './response/index.js';
-export * from './request/index.js';
-export * from './activity/index.js';
-export * from './filter/index.js';
-
-import { PenguenoRequest, PenguenoResponse } from '@emprespresso/pengueno';
-export interface Server {
- readonly serve: Mapper<ITraceable<PenguenoRequest, ServerTrace>, Promise<PenguenoResponse>>;
-}
diff --git a/u/server/request/index.ts b/u/server/request/index.ts
deleted file mode 100644
index 41d59b7..0000000
--- a/u/server/request/index.ts
+++ /dev/null
@@ -1,18 +0,0 @@
-import { HttpMethod } from '@emprespresso/pengueno';
-
-export interface BaseRequest {
- url: string;
- method: HttpMethod;
-
- header(): Record<string, string>;
-
- formData(): Promise<FormData>;
- json(): Promise<unknown>;
- text(): Promise<string>;
-
- param(key: string): string | undefined;
- query(): Record<string, string>;
- queries(): Record<string, string[]>;
-}
-
-export * from './pengueno.js';
diff --git a/u/server/request/pengueno.ts b/u/server/request/pengueno.ts
deleted file mode 100644
index 31563e9..0000000
--- a/u/server/request/pengueno.ts
+++ /dev/null
@@ -1,44 +0,0 @@
-import { BaseRequest, ITraceable, ServerTrace } from '@emprespresso/pengueno';
-
-const greetings = ['hewwo :D', 'hiya cutie', 'boop!', 'sending virtual hugs!', 'stay pawsitive'];
-const penguenoGreeting = () => greetings[Math.floor(Math.random() * greetings.length)];
-
-export class PenguenoRequest {
- private constructor(
- public readonly req: BaseRequest,
- private readonly id: string,
- private readonly at: Date,
- ) {}
-
- public elapsedTimeMs(after = () => Date.now()): number {
- return after() - this.at.getTime();
- }
-
- public getResponseHeaders(): Record<string, string> {
- const RequestId = this.id;
- const RequestReceivedUnix = this.at.getTime();
- const RequestHandleUnix = Date.now();
- const DeltaUnix = this.elapsedTimeMs(() => RequestHandleUnix);
- const Hai = penguenoGreeting();
-
- return Object.entries({
- RequestId,
- RequestReceivedUnix,
- RequestHandleUnix,
- DeltaUnix,
- Hai,
- }).reduce((acc, [key, val]) => ({ ...acc, [key]: val!.toString() }), {});
- }
-
- public static from(request: ITraceable<BaseRequest, ServerTrace>): ITraceable<PenguenoRequest, ServerTrace> {
- const id = crypto.randomUUID();
- return request.bimap((tRequest) => {
- const request = tRequest.get();
- const url = new URL(request.url);
- const { pathname } = url;
- const trace = `RequestId = ${id}, Method = ${request.method}, Path = ${pathname}`;
-
- return { item: new PenguenoRequest(request, id, new Date()), trace };
- });
- }
-}
diff --git a/u/server/response/index.ts b/u/server/response/index.ts
deleted file mode 100644
index 17a2d97..0000000
--- a/u/server/response/index.ts
+++ /dev/null
@@ -1,18 +0,0 @@
-import { Body } from '@emprespresso/pengueno';
-
-export interface BaseResponse {
- status: number;
- statusText: string;
- headers: Record<string, string>;
-
- body(): Body;
-}
-
-export interface ResponseOpts {
- status: number;
- statusText?: string;
- headers?: Record<string, string>;
-}
-
-export * from './pengueno.js';
-export * from './json_pengueno.js';
diff --git a/u/server/response/json_pengueno.ts b/u/server/response/json_pengueno.ts
deleted file mode 100644
index d0b74a8..0000000
--- a/u/server/response/json_pengueno.ts
+++ /dev/null
@@ -1,29 +0,0 @@
-import {
- isEither,
- ITraceable,
- PenguenoRequest,
- PenguenoResponse,
- ResponseOpts,
- ServerTrace,
-} from '@emprespresso/pengueno';
-
-type Jsonable = any;
-export class JsonResponse extends PenguenoResponse {
- constructor(req: ITraceable<PenguenoRequest, ServerTrace>, e: Jsonable, _opts: ResponseOpts) {
- const opts = { ..._opts, headers: { ..._opts.headers, 'Content-Type': 'application/json' } };
- if (isEither<Jsonable, Jsonable>(e)) {
- super(
- req,
- JSON.stringify(
- e.fold(
- (error) => ({ error, ok: undefined }),
- (ok) => ({ ok }),
- ),
- ),
- opts,
- );
- return;
- }
- super(req, JSON.stringify(Math.floor(opts.status / 100) > 4 ? { error: e } : { ok: e }), opts);
- }
-}
diff --git a/u/server/response/pengueno.ts b/u/server/response/pengueno.ts
deleted file mode 100644
index 5a953db..0000000
--- a/u/server/response/pengueno.ts
+++ /dev/null
@@ -1,59 +0,0 @@
-import {
- BaseResponse,
- Body,
- HttpStatusCodes,
- ITraceable,
- Metric,
- Optional,
- PenguenoRequest,
- ResponseOpts,
- ServerTrace,
-} from '@emprespresso/pengueno';
-
-const getHeaders = (req: PenguenoRequest, extraHeaders: Record<string, string>) => {
- const optHeaders = {
- ...req.getResponseHeaders(),
- ...extraHeaders,
- };
- optHeaders['Content-Type'] = (optHeaders['Content-Type'] ?? 'text/plain') + '; charset=utf-8';
- return optHeaders;
-};
-
-const ResponseCodeMetrics = [0, 1, 2, 3, 4, 5].map((x) => Metric.fromName(`response.${x}xx`).asResult());
-export const getResponseMetrics = (status: number, elapsedMs?: number) => {
- const index = Math.floor(status / 100);
- return ResponseCodeMetrics.flatMap((metric, i) =>
- Optional.from(i)
- .filter((i) => i === index)
- .map(() => [metric.count.withValue(1.0)])
- .flatMap((metricValues) =>
- Optional.from(elapsedMs)
- .map((ms) => metricValues.concat(metric.time.withValue(ms)))
- .orSome(() => metricValues),
- )
- .orSome(() => [metric.count.withValue(0.0)])
- .get(),
- );
-};
-
-export class PenguenoResponse implements BaseResponse {
- public readonly statusText: string;
- public readonly status: number;
- public readonly headers: Record<string, string>;
-
- constructor(
- req: ITraceable<PenguenoRequest, ServerTrace>,
- private readonly _body: Body,
- opts: ResponseOpts,
- ) {
- this.headers = getHeaders(req.get(), opts?.headers ?? {});
- this.status = opts.status;
- this.statusText = opts.statusText ?? HttpStatusCodes[this.status]!;
-
- req.trace.trace(getResponseMetrics(opts.status, req.get().elapsedTimeMs()));
- }
-
- public body() {
- return this._body;
- }
-}
diff --git a/u/trace/index.ts b/u/trace/index.ts
deleted file mode 100644
index 332fb52..0000000
--- a/u/trace/index.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-export * from './itrace.js';
-export * from './metric/index.js';
-export * from './log/index.js';
-export * from './trace.js';
-export * from './util.js';
diff --git a/u/trace/itrace.ts b/u/trace/itrace.ts
deleted file mode 100644
index e2019fa..0000000
--- a/u/trace/itrace.ts
+++ /dev/null
@@ -1,91 +0,0 @@
-import type { Mapper, SideEffect, Supplier } from '@emprespresso/pengueno';
-
-/**
- * the "thing" every Trace writer must "trace()".
- */
-type BaseTraceWith = string;
-export type ITraceWith<T> = BaseTraceWith | T;
-export interface ITrace<TraceWith> {
- /**
- * creates a new trace scope which inherits from this trace.
- */
- traceScope: Mapper<ITraceWith<TraceWith>, ITrace<TraceWith>>;
-
- /**
- * does the tracing.
- */
- trace: SideEffect<ITraceWith<TraceWith>>;
-}
-
-export type ITraceableTuple<T, TraceWith> = { item: T; trace: BaseTraceWith | TraceWith };
-export type ITraceableMapper<T, _T, TraceWith> = (w: ITraceable<T, TraceWith>) => _T;
-
-export interface ITraceable<T, Trace = BaseTraceWith> {
- readonly trace: ITrace<Trace>;
- readonly get: Supplier<T>;
-
- readonly move: <_T>(t: _T) => ITraceable<_T, Trace>;
- readonly map: <_T>(mapper: ITraceableMapper<T, _T, Trace>) => ITraceable<_T, Trace>;
- readonly bimap: <_T>(mapper: ITraceableMapper<T, ITraceableTuple<_T, Trace>, Trace>) => ITraceable<_T, Trace>;
- readonly coExtend: <_T>(mapper: ITraceableMapper<T, Array<_T>, Trace>) => Array<ITraceable<_T, Trace>>;
- readonly peek: (peek: ITraceableMapper<T, void, Trace>) => ITraceable<T, Trace>;
-
- readonly traceScope: (mapper: ITraceableMapper<T, Trace, Trace>) => ITraceable<T, Trace>;
-
- readonly flatMap: <_T>(mapper: ITraceableMapper<T, ITraceable<_T, Trace>, Trace>) => ITraceable<_T, Trace>;
- readonly flatMapAsync: <_T>(
- mapper: ITraceableMapper<T, Promise<ITraceable<_T, Trace>>, Trace>,
- ) => ITraceable<Promise<_T>, Trace>;
-}
-
-export class TraceableImpl<T, Trace> implements ITraceable<T, Trace> {
- protected constructor(
- private readonly item: T,
- public readonly trace: ITrace<Trace>,
- ) {}
-
- public map<_T>(mapper: ITraceableMapper<T, _T, Trace>) {
- const result = mapper(this);
- return new TraceableImpl(result, this.trace);
- }
-
- public coExtend<_T>(mapper: ITraceableMapper<T, Array<_T>, Trace>): Array<ITraceable<_T, Trace>> {
- const results = mapper(this);
- return Array.from(results).map((result) => this.move(result));
- }
-
- public flatMap<_T>(mapper: ITraceableMapper<T, ITraceable<_T, Trace>, Trace>): ITraceable<_T, Trace> {
- return mapper(this);
- }
-
- public flatMapAsync<_T>(
- mapper: ITraceableMapper<T, Promise<ITraceable<_T, Trace>>, Trace>,
- ): ITraceable<Promise<_T>, Trace> {
- return new TraceableImpl(
- mapper(this).then((t) => t.get()),
- this.trace,
- );
- }
-
- public traceScope(mapper: ITraceableMapper<T, Trace, Trace>): ITraceable<T, Trace> {
- return new TraceableImpl(this.get(), this.trace.traceScope(mapper(this)));
- }
-
- public peek(peek: ITraceableMapper<T, void, Trace>) {
- peek(this);
- return this;
- }
-
- public move<_T>(t: _T): ITraceable<_T, Trace> {
- return this.map(() => t);
- }
-
- public bimap<_T>(mapper: ITraceableMapper<T, ITraceableTuple<_T, Trace>, Trace>) {
- const { item, trace: _trace } = mapper(this);
- return this.move(item).traceScope(() => <Trace>_trace);
- }
-
- public get() {
- return this.item;
- }
-}
diff --git a/u/trace/log/ansi.ts b/u/trace/log/ansi.ts
deleted file mode 100644
index 7ff16a3..0000000
--- a/u/trace/log/ansi.ts
+++ /dev/null
@@ -1,15 +0,0 @@
-export const ANSI = {
- RESET: '\x1b[0m',
- BOLD: '\x1b[1m',
- DIM: '\x1b[2m',
- RED: '\x1b[31m',
- GREEN: '\x1b[32m',
- YELLOW: '\x1b[33m',
- BLUE: '\x1b[34m',
- MAGENTA: '\x1b[35m',
- CYAN: '\x1b[36m',
- WHITE: '\x1b[37m',
- BRIGHT_RED: '\x1b[91m',
- BRIGHT_YELLOW: '\x1b[93m',
- GRAY: '\x1b[90m',
-};
diff --git a/u/trace/log/index.ts b/u/trace/log/index.ts
deleted file mode 100644
index 670e333..0000000
--- a/u/trace/log/index.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-export * from './ansi.js';
-export * from './level.js';
-export * from './logger.js';
-export * from './pretty_json_console.js';
-export * from './trace.js';
diff --git a/u/trace/log/level.ts b/u/trace/log/level.ts
deleted file mode 100644
index 027dd71..0000000
--- a/u/trace/log/level.ts
+++ /dev/null
@@ -1,19 +0,0 @@
-export enum LogLevel {
- UNKNOWN = 'UNKNOWN',
- INFO = 'INFO',
- WARN = 'WARN',
- DEBUG = 'DEBUG',
- ERROR = 'ERROR',
- SYS = 'SYS',
-}
-
-export const logLevelOrder: Array<LogLevel> = [
- LogLevel.DEBUG,
- LogLevel.INFO,
- LogLevel.WARN,
- LogLevel.ERROR,
- LogLevel.SYS,
-];
-
-export const isLogLevel = (l: unknown): l is LogLevel =>
- typeof l === 'string' && logLevelOrder.some((level) => level === l);
diff --git a/u/trace/log/logger.ts b/u/trace/log/logger.ts
deleted file mode 100644
index 3ced60a..0000000
--- a/u/trace/log/logger.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-import { LogLevel } from './level.js';
-
-export interface ILogger {
- readonly log: (level: LogLevel, ...args: string[]) => void;
-}
diff --git a/u/trace/log/pretty_json_console.ts b/u/trace/log/pretty_json_console.ts
deleted file mode 100644
index 758af51..0000000
--- a/u/trace/log/pretty_json_console.ts
+++ /dev/null
@@ -1,39 +0,0 @@
-import { ANSI, LogLevel, ILogger } from './index.js';
-
-export class PrettyJsonConsoleLogger implements ILogger {
- public log(level: LogLevel, ...trace: string[]) {
- const message = JSON.stringify(
- {
- level,
- trace,
- },
- null,
- 4,
- );
- const styled = `${this.getStyle(level)}${message}${ANSI.RESET}\n`;
- this.getStream(level)(styled);
- }
-
- private getStream(level: LogLevel) {
- if (level === LogLevel.ERROR) {
- return console.error;
- }
- return console.log;
- }
-
- private getStyle(level: LogLevel) {
- switch (level) {
- case LogLevel.UNKNOWN:
- case LogLevel.INFO:
- return `${ANSI.MAGENTA}`;
- case LogLevel.DEBUG:
- return `${ANSI.CYAN}`;
- case LogLevel.WARN:
- return `${ANSI.BRIGHT_YELLOW}`;
- case LogLevel.ERROR:
- return `${ANSI.BRIGHT_RED}`;
- case LogLevel.SYS:
- return `${ANSI.DIM}${ANSI.BLUE}`;
- }
- }
-}
diff --git a/u/trace/log/trace.ts b/u/trace/log/trace.ts
deleted file mode 100644
index 3f9f1b2..0000000
--- a/u/trace/log/trace.ts
+++ /dev/null
@@ -1,60 +0,0 @@
-import { isDebug, ITrace, ITraceWith, memoize, Supplier } from '@emprespresso/pengueno';
-import { ILogger, isLogLevel, LogLevel, logLevelOrder, PrettyJsonConsoleLogger } from './index.js';
-
-export type LogTraceSupplier = ITraceWith<Supplier<string>> | ITraceWith<Error>;
-
-export class LogTrace implements ITrace<LogTraceSupplier> {
- constructor(
- private readonly logger: ILogger = new PrettyJsonConsoleLogger(),
- private readonly traces: Array<LogTraceSupplier> = [defaultTrace],
- private readonly defaultLevel: LogLevel = LogLevel.INFO,
- private readonly allowedLevels: Supplier<Set<LogLevel>> = defaultAllowedLevelsSupplier,
- ) {}
-
- public traceScope(trace: LogTraceSupplier): ITrace<LogTraceSupplier> {
- return new LogTrace(this.logger, this.traces.concat(trace), this.defaultLevel, this.allowedLevels);
- }
-
- public trace(trace: LogTraceSupplier) {
- const { traces, level: _level } = this.foldTraces(this.traces.concat(trace));
- if (!this.allowedLevels().has(_level)) return;
-
- const level = _level === LogLevel.UNKNOWN ? this.defaultLevel : _level;
- this.logger.log(level, ...traces);
- }
-
- private foldTraces(_traces: Array<LogTraceSupplier>) {
- const _logTraces = _traces.map((trace) => (typeof trace === 'function' ? trace() : trace));
- const _level = _logTraces
- .filter((trace) => isLogLevel(trace))
- .reduce((acc, level) => Math.max(logLevelOrder.indexOf(level), acc), -1);
- const level = logLevelOrder[_level] ?? LogLevel.UNKNOWN;
-
- const traces = _logTraces
- .filter((trace) => !isLogLevel(trace))
- .map((trace) => {
- if (typeof trace === 'object') {
- return `TracedException.Name = ${trace.name}, TracedException.Message = ${trace.message}, TracedException.Stack = ${trace.stack}`;
- }
- return trace;
- });
- return {
- level,
- traces,
- };
- }
-}
-
-const defaultTrace = () => `TimeStamp = ${new Date().toISOString()}`;
-const defaultAllowedLevels = memoize(
- (isDebug: boolean) =>
- new Set([
- LogLevel.UNKNOWN,
- ...(isDebug ? [LogLevel.DEBUG] : []),
- LogLevel.INFO,
- LogLevel.WARN,
- LogLevel.ERROR,
- LogLevel.SYS,
- ]),
-);
-const defaultAllowedLevelsSupplier = () => defaultAllowedLevels(isDebug());
diff --git a/u/trace/metric/emittable.ts b/u/trace/metric/emittable.ts
deleted file mode 100644
index f3441ec..0000000
--- a/u/trace/metric/emittable.ts
+++ /dev/null
@@ -1,18 +0,0 @@
-import { IEmittableMetric, MetricValue, MetricValueTag, Unit } from './index.js';
-
-export class EmittableMetric implements IEmittableMetric {
- constructor(
- public readonly name: string,
- public readonly unit: Unit,
- ) {}
-
- public withValue(value: number): MetricValue {
- return {
- name: this.name,
- unit: this.unit,
- emissionTimestamp: Date.now(),
- value,
- _tag: MetricValueTag,
- };
- }
-}
diff --git a/u/trace/metric/index.ts b/u/trace/metric/index.ts
deleted file mode 100644
index 72c37d2..0000000
--- a/u/trace/metric/index.ts
+++ /dev/null
@@ -1,41 +0,0 @@
-import { isTagged, Tagged, type Mapper } from '@emprespresso/pengueno';
-
-export enum Unit {
- COUNT = 'COUNT',
- MILLISECONDS = 'MILLISECONDS',
-}
-
-export const MetricValueTag = 'MetricValue' as const;
-export type MetricValueTag = typeof MetricValueTag;
-export const isMetricValue = (t: unknown): t is MetricValue => isTagged(t, MetricValueTag);
-export interface MetricValue extends Tagged<MetricValueTag> {
- readonly name: string;
- readonly unit: Unit;
- readonly value: number;
- readonly emissionTimestamp: number;
-}
-
-export interface IEmittableMetric {
- readonly name: string;
- readonly unit: Unit;
- readonly withValue: Mapper<number, MetricValue>;
-}
-
-export const IMetricTag = 'IMetric' as const;
-export type IMetricTag = typeof IMetricTag;
-export const isIMetric = (t: unknown): t is IMetric => isTagged(t, IMetricTag);
-export interface IMetric extends Tagged<IMetricTag> {
- readonly count: IEmittableMetric;
- readonly time: IEmittableMetric;
- readonly parent: undefined | IMetric;
-}
-
-export interface IResultMetric extends IMetric {
- readonly failure: IMetric;
- readonly success: IMetric;
- readonly warn: IMetric;
-}
-
-export * from './emittable.js';
-export * from './metric.js';
-export * from './trace.js';
diff --git a/u/trace/metric/metric.ts b/u/trace/metric/metric.ts
deleted file mode 100644
index 8ef339f..0000000
--- a/u/trace/metric/metric.ts
+++ /dev/null
@@ -1,54 +0,0 @@
-import { EmittableMetric, IMetric, IMetricTag, IResultMetric, Unit } from './index.js';
-
-class _Tagged {
- protected constructor(public readonly _tag = IMetricTag) {}
-}
-
-export class Metric extends _Tagged implements IMetric {
- private static DELIM = '.';
-
- protected constructor(
- public readonly name: string,
- public readonly parent: undefined | IMetric = undefined,
- public readonly count = new EmittableMetric(Metric.join(name, 'count'), Unit.COUNT),
- public readonly time = new EmittableMetric(Metric.join(name, 'time'), Unit.MILLISECONDS),
- ) {
- super();
- }
-
- public child(_name: string): Metric {
- const childName = Metric.join(this.name, _name);
- return new Metric(childName, this);
- }
-
- public asResult() {
- return ResultMetric.from(this);
- }
-
- static join(...name: Array<string>) {
- return name.join(Metric.DELIM);
- }
-
- static fromName(name: string): Metric {
- return new Metric(name);
- }
-}
-
-export class ResultMetric extends Metric implements IResultMetric {
- protected constructor(
- public readonly name: string,
- public readonly parent: undefined | IMetric = undefined,
- public readonly failure: IMetric,
- public readonly success: IMetric,
- public readonly warn: IMetric,
- ) {
- super(name, parent);
- }
-
- static from(metric: Metric) {
- const failure = metric.child('failure');
- const success = metric.child('success');
- const warn = metric.child('warn');
- return new ResultMetric(metric.name, metric.parent, failure, success, warn);
- }
-}
diff --git a/u/trace/metric/trace.ts b/u/trace/metric/trace.ts
deleted file mode 100644
index 0c5fe37..0000000
--- a/u/trace/metric/trace.ts
+++ /dev/null
@@ -1,59 +0,0 @@
-import { IMetric, isIMetric, isMetricValue, ITrace, ITraceWith, MetricValue, SideEffect } from '@emprespresso/pengueno';
-
-export type MetricsTraceSupplier =
- | ITraceWith<IMetric | MetricValue | undefined>
- | Array<ITraceWith<IMetric | MetricValue | undefined>>;
-export const isMetricsTraceSupplier = (t: unknown): t is MetricsTraceSupplier =>
- isMetricValue(t) || isIMetric(t) || (Array.isArray(t) && t.every((_m) => isMetricValue(_m) || isIMetric(_m)));
-
-export class MetricsTrace implements ITrace<MetricsTraceSupplier> {
- constructor(
- private readonly metricConsumer: SideEffect<Array<MetricValue>>,
- private readonly activeTraces: ReadonlyMap<IMetric, number> = new Map(),
- private readonly completedTraces: ReadonlySet<IMetric> = new Set(),
- ) {}
-
- public traceScope(trace: MetricsTraceSupplier): MetricsTrace {
- const now = Date.now();
- const metricsToTrace = (Array.isArray(trace) ? trace : [trace]).filter(isIMetric);
-
- const initialTraces = new Map(metricsToTrace.map((metric) => [metric, now]));
-
- return new MetricsTrace(this.metricConsumer, initialTraces);
- }
-
- public trace(metrics: MetricsTraceSupplier): MetricsTrace {
- if (!metrics || typeof metrics === 'string') {
- return this;
- }
-
- const now = Date.now();
- const allMetrics = Array.isArray(metrics) ? metrics : [metrics];
-
- // partition the incoming metrics
- const valuesToEmit = allMetrics.filter(isMetricValue);
- const traceableMetrics = allMetrics.filter(isIMetric);
-
- const metricsToStart = traceableMetrics.filter((m) => !this.activeTraces.has(m));
- const metricsToEnd = traceableMetrics.filter((m) => this.activeTraces.has(m) && !this.completedTraces.has(m));
-
- // the new metrics to emit based on traces ending *now*
- const endedMetricValues = metricsToEnd.flatMap((metric) => [
- metric.count.withValue(1.0),
- metric.time.withValue(now - this.activeTraces.get(metric)!),
- ]);
-
- const allMetricsToEmit = [...valuesToEmit, ...endedMetricValues];
- if (allMetricsToEmit.length > 0) {
- this.metricConsumer(allMetricsToEmit);
- }
-
- // the next immutable state
- const nextActiveTraces = new Map([
- ...this.activeTraces,
- ...metricsToStart.map((m): [IMetric, number] => [m, now]),
- ]);
- const nextCompletedTraces = new Set([...this.completedTraces, ...metricsToEnd]);
- return new MetricsTrace(this.metricConsumer, nextActiveTraces, nextCompletedTraces);
- }
-}
diff --git a/u/trace/trace.ts b/u/trace/trace.ts
deleted file mode 100644
index bde83a3..0000000
--- a/u/trace/trace.ts
+++ /dev/null
@@ -1,77 +0,0 @@
-import {
- isMetricsTraceSupplier,
- type ITrace,
- type ITraceable,
- type ITraceWith,
- LogLevel,
- LogTrace,
- type LogTraceSupplier,
- MetricsTrace,
- type MetricsTraceSupplier,
- type MetricValue,
- TraceableImpl,
-} from './index.js';
-
-export class LogTraceable<T> extends TraceableImpl<T, LogTraceSupplier> {
- public static LogTrace = new LogTrace();
- static of<T>(t: T) {
- return new LogTraceable(t, LogTraceable.LogTrace);
- }
-}
-
-const getEmbeddedMetricConsumer = (logTrace: ITrace<LogTraceSupplier>) => (metrics: Array<MetricValue>) => {
- if (metrics.length === 0) return;
- logTrace.traceScope(LogLevel.SYS).trace(`Metrics = <metrics>${JSON.stringify(metrics)}</metrics>`);
-};
-
-export class EmbeddedMetricsTraceable<T> extends TraceableImpl<T, MetricsTraceSupplier> {
- public static MetricsTrace = new MetricsTrace(getEmbeddedMetricConsumer(LogTraceable.LogTrace));
-
- static of<T>(t: T, metricsTrace = EmbeddedMetricsTraceable.MetricsTrace) {
- return new EmbeddedMetricsTraceable(t, metricsTrace);
- }
-}
-
-export type LogMetricTraceSupplier = ITraceWith<LogTraceSupplier | MetricsTraceSupplier>;
-export class LogMetricTrace implements ITrace<LogMetricTraceSupplier> {
- constructor(
- private logTrace: ITrace<LogTraceSupplier>,
- private metricsTrace: ITrace<MetricsTraceSupplier>,
- ) {}
-
- // public traceScope(trace: LogTraceSupplier | MetricsTraceSupplier): LogMetricTrace {
- // if (isMetricsTraceSupplier(trace)) {
- // this.metricsTrace = this.metricsTrace.traceScope(trace);
- // return this;
- // }
- // this.logTrace = this.logTrace.traceScope(trace);
- // return this;
- // }
- public traceScope(trace: LogTraceSupplier | MetricsTraceSupplier): LogMetricTrace {
- if (isMetricsTraceSupplier(trace)) {
- return new LogMetricTrace(this.logTrace, this.metricsTrace.traceScope(trace));
- }
- return new LogMetricTrace(this.logTrace.traceScope(trace), this.metricsTrace);
- }
-
- public trace(trace: LogTraceSupplier | MetricsTraceSupplier) {
- if (isMetricsTraceSupplier(trace)) {
- this.metricsTrace.trace(trace);
- return this;
- }
- this.logTrace.trace(trace);
- return this;
- }
-}
-
-export class LogMetricTraceable<T> extends TraceableImpl<T, MetricsTraceSupplier | LogTraceSupplier> {
- static ofLogTraceable<T>(t: ITraceable<T, LogTraceSupplier>) {
- const metricsTrace = new MetricsTrace(getEmbeddedMetricConsumer(t.trace));
- return new LogMetricTraceable(t.get(), new LogMetricTrace(t.trace, metricsTrace));
- }
-
- static of<T>(t: T) {
- const logTrace = LogTraceable.of(t);
- return LogMetricTraceable.ofLogTraceable(logTrace);
- }
-}
diff --git a/u/trace/util.ts b/u/trace/util.ts
deleted file mode 100644
index ec67571..0000000
--- a/u/trace/util.ts
+++ /dev/null
@@ -1,59 +0,0 @@
-import {
- IEither,
- IMetric,
- isEither,
- ITraceable,
- ITraceWith,
- LogLevel,
- ResultMetric,
- type Callable,
- type ITraceableMapper,
-} from '@emprespresso/pengueno';
-
-export class TraceUtil {
- static promiseify<T, U, Trace>(
- mapper: ITraceableMapper<T, U, Trace>,
- ): ITraceableMapper<Promise<T>, Promise<U>, Trace> {
- return (traceablePromise) =>
- traceablePromise.flatMapAsync(async (t) => t.move(await t.get()).map(mapper)).get();
- }
-
- static traceResultingEither<TErr, TOk, Trace>(
- metric?: ResultMetric,
- warnOnFailure = false,
- ): ITraceableMapper<IEither<TErr, TOk>, ITraceable<IEither<TErr, TOk>, Trace>, Trace> {
- return (t) => {
- if (metric)
- t.trace.trace(
- t.get().fold(
- (_err) => <Trace>(warnOnFailure ? metric.warn : metric.failure),
- (_ok) => <Trace>metric.success,
- ),
- );
- return t.traceScope((_t) =>
- _t.get().fold(
- (_err) => <Trace>(warnOnFailure ? LogLevel.WARN : LogLevel.ERROR),
- (_ok) => <Trace>LogLevel.INFO,
- ),
- );
- };
- }
-
- static withTrace<T, Trace, _Trace extends ITraceWith<Trace>>(
- trace: _Trace,
- ): ITraceableMapper<T, ITraceable<T, Trace>, Trace> {
- return (t) => t.traceScope(() => <Trace>trace);
- }
-
- static withMetricTrace<T, Trace>(metric: IMetric): ITraceableMapper<T, ITraceable<T, Trace>, Trace> {
- return TraceUtil.withTrace(<Trace>metric);
- }
-
- static withFunctionTrace<F extends Callable, T, Trace>(f: F): ITraceableMapper<T, ITraceable<T, Trace>, Trace> {
- return TraceUtil.withTrace(<Trace>`fn.${f.name}`);
- }
-
- static withClassTrace<C extends object, T, Trace>(c: C): ITraceableMapper<T, ITraceable<T, Trace>, Trace> {
- return TraceUtil.withTrace(<Trace>`class.${c.constructor.name}`);
- }
-}
diff --git a/u/tsconfig.json b/u/tsconfig.json
deleted file mode 100644
index 80e5ff4..0000000
--- a/u/tsconfig.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "extends": "../tsconfig.json",
- "compilerOptions": {
- "outDir": "./dist",
- "rootDir": "./",
- "composite": true,
- "declaration": true,
- "declarationMap": true,
- "sourceMap": true,
- "noEmit": false,
- "moduleResolution": "node"
- },
- "include": ["**/*.ts"],
- "exclude": ["node_modules", "dist", "**/*.test.ts", "**/*.spec.ts"]
-}
diff --git a/u/types/collections/cons.ts b/u/types/collections/cons.ts
deleted file mode 100644
index 05dbe7c..0000000
--- a/u/types/collections/cons.ts
+++ /dev/null
@@ -1,40 +0,0 @@
-import { IOptional, Mapper, Optional } from '@emprespresso/pengueno';
-
-export interface ICons<T> extends Iterable<T> {
- readonly value: T;
- readonly next: IOptional<ICons<T>>;
-
- readonly replace: Mapper<T, ICons<T>>;
- readonly before: Mapper<IOptional<ICons<T>>, ICons<T>>;
-}
-
-export class Cons<T> implements ICons<T> {
- constructor(
- public readonly value: T,
- public readonly next: IOptional<ICons<T>> = Optional.none(),
- ) {}
-
- public before(head: IOptional<ICons<T>>): ICons<T> {
- return new Cons<T>(this.value, head);
- }
-
- public replace(_value: T): ICons<T> {
- return new Cons<T>(_value, this.next);
- }
-
- *[Symbol.iterator]() {
- for (let cur = Optional.some<ICons<T>>(this); cur.present(); cur = cur.flatMap((cur) => cur.next)) {
- yield cur.get().value;
- }
- }
-
- static addOnto<T>(items: Iterable<T>, tail: IOptional<ICons<T>>): IOptional<ICons<T>> {
- return Array.from(items)
- .reverse()
- .reduce((cons, value) => Optional.from<ICons<T>>(new Cons<T>(value, cons)), tail);
- }
-
- static from<T>(items: Iterable<T>): IOptional<ICons<T>> {
- return Cons.addOnto(items, Optional.none());
- }
-}
diff --git a/u/types/collections/index.ts b/u/types/collections/index.ts
deleted file mode 100644
index 69e5d0b..0000000
--- a/u/types/collections/index.ts
+++ /dev/null
@@ -1,2 +0,0 @@
-export * from './cons.js';
-export * from './list_zipper.js';
diff --git a/u/types/collections/list_zipper.ts b/u/types/collections/list_zipper.ts
deleted file mode 100644
index 3df15b5..0000000
--- a/u/types/collections/list_zipper.ts
+++ /dev/null
@@ -1,70 +0,0 @@
-import { Cons, ICons } from './cons.js';
-import { IOptional, Mapper, Optional, Supplier } from '@emprespresso/pengueno';
-
-export interface IZipper<T> extends Iterable<T> {
- readonly read: Supplier<IOptional<T>>;
- readonly next: Supplier<IOptional<IZipper<T>>>;
- readonly previous: Supplier<IOptional<IZipper<T>>>;
-
- readonly prependChunk: Mapper<Iterable<T>, IZipper<T>>;
- readonly prepend: Mapper<T, IZipper<T>>;
- readonly remove: Supplier<IZipper<T>>;
- readonly replace: Mapper<T, IZipper<T>>;
-}
-
-export class ListZipper<T> implements IZipper<T> {
- private constructor(
- private readonly reversedPathToHead: IOptional<ICons<T>>,
- private readonly currentHead: IOptional<ICons<T>>,
- ) {}
-
- public read(): IOptional<T> {
- return this.currentHead.map(({ value }) => value);
- }
-
- public next(): IOptional<IZipper<T>> {
- return this.currentHead.map<IZipper<T>>(
- (head) => new ListZipper<T>(Optional.some(head.before(this.reversedPathToHead)), head.next),
- );
- }
-
- public previous(): IOptional<IZipper<T>> {
- return this.reversedPathToHead.map<IZipper<T>>(
- (lastVisited) => new ListZipper<T>(lastVisited.next, Optional.some(lastVisited.before(this.currentHead))),
- );
- }
-
- public prependChunk(values: Iterable<T>): IZipper<T> {
- return new ListZipper<T>(Cons.addOnto(Array.from(values).reverse(), this.reversedPathToHead), this.currentHead);
- }
-
- public prepend(value: T): IZipper<T> {
- return this.prependChunk([value]);
- }
-
- public remove(): IZipper<T> {
- const newHead = this.currentHead.flatMap((right) => right.next);
- return new ListZipper<T>(this.reversedPathToHead, newHead);
- }
-
- public replace(value: T): IZipper<T> {
- const newHead = this.currentHead.map((right) => right.replace(value));
- return new ListZipper<T>(this.reversedPathToHead, newHead);
- }
-
- *[Symbol.iterator]() {
- let head: ListZipper<T> = this;
- for (let prev = head.previous(); prev.present(); prev = prev.flatMap((p) => p.previous())) {
- head = <ListZipper<T>>prev.get();
- }
- if (head.currentHead.present()) yield* head.currentHead.get();
- }
-
- public collection() {
- return Array.from(this);
- }
-
- static from<T>(iterable: Iterable<T>): ListZipper<T> {
- return new ListZipper(Optional.none(), Cons.from(iterable));
- }
-}
diff --git a/u/types/fn/callable.ts b/u/types/fn/callable.ts
deleted file mode 100644
index 60d747b..0000000
--- a/u/types/fn/callable.ts
+++ /dev/null
@@ -1,21 +0,0 @@
-export interface Callable<T = any, ArgT = any> {
- (...args: Array<ArgT>): T;
-}
-
-export interface Supplier<T> extends Callable<T, undefined> {
- (): T;
-}
-
-export interface Mapper<T, U> extends Callable<U, T> {
- (t: T): U;
-}
-
-export interface Predicate<T> extends Mapper<T, boolean> {}
-
-export interface BiMapper<T, U, R> extends Callable {
- (t: T, u: U): R;
-}
-
-export interface SideEffect<T> extends Mapper<T, void> {}
-
-export interface BiSideEffect<T, U> extends BiMapper<T, U, void> {}
diff --git a/u/types/fn/either.ts b/u/types/fn/either.ts
deleted file mode 100644
index 0f65859..0000000
--- a/u/types/fn/either.ts
+++ /dev/null
@@ -1,143 +0,0 @@
-import {
- BiMapper,
- IOptional,
- type Mapper,
- Optional,
- Predicate,
- type Supplier,
- Tagged,
- isTagged,
-} from '@emprespresso/pengueno';
-
-export const IEitherTag = 'IEither' as const;
-export type IEitherTag = typeof IEitherTag;
-export const isEither = <E, T>(o: unknown): o is IEither<E, T> => isTagged(o, IEitherTag);
-export interface IEither<E, T> extends Tagged<IEitherTag> {
- readonly left: Supplier<IOptional<E>>;
- readonly right: Supplier<IOptional<T>>;
-
- readonly mapRight: <_T>(mapper: Mapper<T, _T>) => IEither<E, _T>;
- readonly filter: (mapper: Predicate<T>) => IEither<E, T>;
- readonly mapLeft: <_E>(mapper: Mapper<E, _E>) => IEither<_E, T>;
- readonly mapBoth: <_E, _T>(errBranch: Mapper<E, _E>, okBranch: Mapper<T, _T>) => IEither<_E, _T>;
-
- readonly flatMap: <_T>(mapper: Mapper<T, IEither<E, _T>>) => IEither<E, _T>;
- readonly flatMapAsync: <_T>(mapper: Mapper<T, Promise<IEither<E, _T>>>) => Promise<IEither<E, _T>>;
-
- readonly moveRight: <_T>(t: _T) => IEither<E, _T>;
- readonly fold: <_T>(leftFolder: Mapper<E, _T>, rightFolder: Mapper<T, _T>) => _T;
- readonly joinRight: <O, _T>(other: IEither<E, O>, mapper: (a: O, b: T) => _T) => IEither<E, _T>;
- readonly joinRightAsync: <O, _T>(
- other: (() => Promise<IEither<E, O>>) | Promise<IEither<E, O>>,
- mapper: (a: O, b: T) => _T,
- ) => Promise<IEither<E, _T>>;
-}
-
-const ELeftTag = 'E.Left' as const;
-type ELeftTag = typeof ELeftTag;
-export const isLeft = <E>(o: unknown): o is Left<E> => isTagged(o, ELeftTag);
-interface Left<E> extends Tagged<ELeftTag> {
- err: E;
-}
-
-const ERightTag = 'E.Right' as const;
-type ERightTag = typeof ERightTag;
-export const isRight = <T>(o: unknown): o is Right<T> => isTagged(o, ERightTag);
-interface Right<T> extends Tagged<ERightTag> {
- ok: T;
-}
-
-class _Tagged implements Tagged<IEitherTag> {
- protected constructor(public readonly _tag = IEitherTag) {}
-}
-
-export class Either<E, T> extends _Tagged implements IEither<E, T> {
- protected constructor(private readonly self: Left<E> | Right<T>) {
- super();
- }
-
- public moveRight<_T>(t: _T) {
- return this.mapRight(() => t);
- }
-
- public mapBoth<_E, _T>(errBranch: Mapper<E, _E>, okBranch: Mapper<T, _T>): IEither<_E, _T> {
- if (isLeft(this.self)) return Either.left(errBranch(this.self.err));
- return Either.right(okBranch(this.self.ok));
- }
-
- public mapRight<_T>(mapper: Mapper<T, _T>): IEither<E, _T> {
- if (isRight(this.self)) return Either.right(mapper(this.self.ok));
- return Either.left(this.self.err);
- }
-
- public mapLeft<_E>(mapper: Mapper<E, _E>): IEither<_E, T> {
- if (isLeft(this.self)) return Either.left(mapper(this.self.err));
- return Either.right(this.self.ok);
- }
-
- public flatMap<_T>(mapper: Mapper<T, IEither<E, _T>>): IEither<E, _T> {
- if (isRight(this.self)) return mapper(this.self.ok);
- return Either.left<E, _T>(this.self.err);
- }
-
- public filter(mapper: Predicate<T>): IEither<E, T> {
- if (isLeft(this.self)) return Either.left<E, T>(this.self.err);
- return Either.fromFailable<E, T>(() => this.right().filter(mapper).get());
- }
-
- public async flatMapAsync<_T>(mapper: Mapper<T, Promise<IEither<E, _T>>>): Promise<IEither<E, _T>> {
- if (isLeft(this.self)) return Promise.resolve(Either.left(this.self.err));
- return await mapper(this.self.ok).catch((err) => Either.left(err));
- }
-
- public fold<_T>(leftFolder: Mapper<E, _T>, rightFolder: Mapper<T, _T>): _T {
- if (isLeft(this.self)) return leftFolder(this.self.err);
- return rightFolder(this.self.ok);
- }
-
- public left(): IOptional<E> {
- if (isLeft(this.self)) return Optional.from(this.self.err) as IOptional<E>;
- return Optional.none();
- }
-
- public right(): IOptional<T> {
- if (isRight(this.self)) return Optional.from(this.self.ok) as IOptional<T>;
- return Optional.none();
- }
-
- public joinRight<O, _T>(other: IEither<E, O>, mapper: BiMapper<O, T, _T>) {
- return this.flatMap((t) => other.mapRight((o) => mapper(o, t)));
- }
-
- public joinRightAsync<O, _T>(
- other: Supplier<Promise<IEither<E, O>>> | Promise<IEither<E, O>>,
- mapper: BiMapper<O, T, _T>,
- ) {
- return this.flatMapAsync(async (t) => {
- const o = typeof other === 'function' ? other() : other;
- return await o.then((other) => other.mapRight((o) => mapper(o, t)));
- });
- }
-
- static left<E, T>(e: E): IEither<E, T> {
- return new Either({ err: e, _tag: ELeftTag });
- }
-
- static right<E, T>(t: T): IEither<E, T> {
- return new Either({ ok: t, _tag: ERightTag });
- }
-
- static fromFailable<E, T>(s: Supplier<T>): IEither<E, T> {
- try {
- return Either.right(s());
- } catch (e) {
- return Either.left(e as E);
- }
- }
-
- static async fromFailableAsync<E, T>(s: Supplier<Promise<T>> | Promise<T>): Promise<IEither<E, T>> {
- return await (typeof s === 'function' ? s() : s)
- .then((t: T) => Either.right<E, T>(t))
- .catch((e: E) => Either.left<E, T>(e));
- }
-}
diff --git a/u/types/fn/index.ts b/u/types/fn/index.ts
deleted file mode 100644
index 780c86c..0000000
--- a/u/types/fn/index.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-export * from './callable.js';
-export * from './either.js';
-export * from './optional.js';
diff --git a/u/types/fn/optional.ts b/u/types/fn/optional.ts
deleted file mode 100644
index 504e496..0000000
--- a/u/types/fn/optional.ts
+++ /dev/null
@@ -1,93 +0,0 @@
-import { type Mapper, Predicate, type Supplier, Tagged, isTagged } from '@emprespresso/pengueno';
-
-export type MaybeGiven<T> = T | undefined | null;
-
-export const IOptionalTag = 'IOptional' as const;
-export type IOptionalTag = typeof IOptionalTag;
-export const isOptional = <T>(o: unknown): o is IOptional<T> => isTagged(o, IOptionalTag);
-export class IOptionalEmptyError extends Error {}
-export interface IOptional<t, T extends NonNullable<t> = NonNullable<t>> extends Tagged<IOptionalTag>, Iterable<T> {
- readonly move: <_T>(t: MaybeGiven<_T>) => IOptional<_T>;
- readonly map: <_T>(mapper: Mapper<T, MaybeGiven<_T>>) => IOptional<_T>;
- readonly filter: (mapper: Predicate<T>) => IOptional<T>;
- readonly flatMap: <_T>(mapper: Mapper<T, MaybeGiven<IOptional<_T>>>) => IOptional<_T>;
- readonly orSome: (supplier: Supplier<MaybeGiven<t>>) => IOptional<T>;
- readonly get: Supplier<T>;
- readonly present: Supplier<boolean>;
-}
-
-type OSomeTag = typeof OSomeTag;
-const OSomeTag = 'O.Some' as const;
-interface Some<T> extends Tagged<OSomeTag> {
- value: NonNullable<T>;
-}
-
-const ONoneTag = 'O.None' as const;
-type ONoneTag = typeof ONoneTag;
-interface None extends Tagged<ONoneTag> {}
-
-const isNone = (o: unknown): o is None => isTagged(o, ONoneTag);
-const isSome = <T>(o: unknown): o is Some<T> => isTagged(o, OSomeTag);
-
-class _Tagged implements Tagged<IOptionalTag> {
- protected constructor(public readonly _tag = IOptionalTag) {}
-}
-
-export class Optional<t, T extends NonNullable<t> = NonNullable<t>> extends _Tagged implements IOptional<T> {
- private constructor(private readonly self: Some<T> | None) {
- super();
- }
-
- public move<_T>(t: MaybeGiven<_T>): IOptional<_T> {
- return this.map(() => t);
- }
-
- public orSome(supplier: Supplier<MaybeGiven<t>>): IOptional<T> {
- if (isNone(this.self)) return Optional.from(supplier());
- return this;
- }
-
- public get(): T {
- if (isNone(this.self)) throw new IOptionalEmptyError('called get() on None optional');
- return this.self.value;
- }
-
- public filter(mapper: Predicate<T>): IOptional<T> {
- if (isNone(this.self) || !mapper(this.self.value)) return Optional.none();
- return Optional.some(this.self.value);
- }
-
- public map<_T>(mapper: Mapper<T, MaybeGiven<_T>>): IOptional<_T> {
- if (isNone(this.self)) return Optional.none();
- return Optional.from(mapper(this.self.value)) as IOptional<_T>;
- }
-
- public flatMap<_T>(mapper: Mapper<T, MaybeGiven<IOptional<_T>>>): IOptional<_T> {
- if (isNone(this.self)) return Optional.none();
- return Optional.from(mapper(this.self.value))
- .orSome(() => Optional.none())
- .get();
- }
-
- public present() {
- return isSome(this.self);
- }
-
- *[Symbol.iterator]() {
- if (isSome(this.self)) yield this.self.value;
- }
-
- static some<t, T extends NonNullable<t> = NonNullable<t>>(value: T): IOptional<T> {
- return new Optional({ value, _tag: OSomeTag });
- }
-
- private static readonly _none = new Optional({ _tag: ONoneTag });
- static none<T>(): IOptional<T> {
- return this._none as unknown as IOptional<T>;
- }
-
- static from<t, T extends NonNullable<t> = NonNullable<t>>(value: MaybeGiven<t>): IOptional<T> {
- if (value === null || value === undefined) return Optional.none<T>();
- return Optional.some(<T>value);
- }
-}
diff --git a/u/types/index.ts b/u/types/index.ts
deleted file mode 100644
index fc1b15a..0000000
--- a/u/types/index.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-export * from './misc.js';
-
-export * from './object.js';
-export * from './tagged.js';
-
-export * from './fn/index.js';
-export * from './collections/index.js';
diff --git a/u/types/misc.ts b/u/types/misc.ts
deleted file mode 100644
index 77833c4..0000000
--- a/u/types/misc.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-export type ObjectFromList<T extends ReadonlyArray<string | number | symbol>, V = string> = {
- [K in T extends ReadonlyArray<infer U> ? U : never]: V;
-};
diff --git a/u/types/object.ts b/u/types/object.ts
deleted file mode 100644
index fe97999..0000000
--- a/u/types/object.ts
+++ /dev/null
@@ -1 +0,0 @@
-export const isObject = (o: unknown): o is object => typeof o === 'object' && !Array.isArray(o) && !!o;
diff --git a/u/types/tagged.ts b/u/types/tagged.ts
deleted file mode 100644
index 351e4c9..0000000
--- a/u/types/tagged.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-import { isObject } from './index.js';
-
-export interface Tagged<TTag> {
- _tag: TTag;
-}
-
-export const isTagged = <TTag>(o: unknown, tag: TTag): o is Tagged<TTag> =>
- !!(isObject(o) && '_tag' in o && o._tag === tag);
diff --git a/worker/package.json b/worker/package.json
index a3cfcd6..4db8dba 100644
--- a/worker/package.json
+++ b/worker/package.json
@@ -17,8 +17,8 @@
"type-check": "tsc --noEmit"
},
"dependencies": {
- "@emprespresso/pengueno": "*",
- "@emprespresso/ci_model": "*"
+ "@emprespresso/ci_model": "*",
+ "@emprespresso/pengueno": "^0.0.5"
},
"devDependencies": {
"copyfiles": "2.4.1"
diff --git a/worker/scripts/npm_publish.ts b/worker/scripts/npm_publish.ts
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/worker/scripts/npm_publish.ts
diff --git a/worker/tsconfig.json b/worker/tsconfig.json
index 58e9147..3858ff4 100644
--- a/worker/tsconfig.json
+++ b/worker/tsconfig.json
@@ -11,5 +11,5 @@
},
"include": ["**/*.ts"],
"exclude": ["node_modules", "dist", "**/*.test.ts", "**/*.spec.ts"],
- "references": [{ "path": "../u" }, { "path": "../model" }]
+ "references": [{ "path": "../model" }]
}