summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--deno.json2
-rw-r--r--hooks/job/queue.ts0
-rw-r--r--hooks/main.ts1
-rwxr-xr-xhooks/server.ts61
-rw-r--r--hooks/server/activity/health.ts0
-rw-r--r--hooks/server/activity/hook.ts0
-rw-r--r--hooks/server/activity/mod.ts8
-rw-r--r--hooks/server/filter/json.ts25
-rw-r--r--hooks/server/filter/method.ts22
-rw-r--r--hooks/server/filter/mod.ts18
-rw-r--r--hooks/server/mod.ts0
-rw-r--r--u/deno.json6
-rw-r--r--u/fn/callable.ts15
-rw-r--r--u/fn/either.ts62
-rw-r--r--u/fn/mod.ts2
-rw-r--r--u/leftpadesque/debug.ts11
-rw-r--r--u/leftpadesque/mod.ts3
-rw-r--r--u/leftpadesque/object.ts (renamed from utils/isObject.ts)0
-rw-r--r--u/leftpadesque/prepend.ts (renamed from utils/prepend.ts)0
-rw-r--r--u/mod.ts4
-rw-r--r--u/process/env.ts10
-rw-r--r--u/process/mod.ts3
-rw-r--r--u/process/run.ts (renamed from utils/run.ts)2
-rw-r--r--u/process/validate_identifier.ts (renamed from utils/validate_identifier.ts)0
-rw-r--r--u/server/mod.ts0
-rw-r--r--u/trace/itrace.ts72
-rw-r--r--u/trace/logger.ts86
-rw-r--r--u/trace/mod.ts3
-rw-r--r--u/trace/trace.ts34
-rw-r--r--utils/either.ts48
-rw-r--r--utils/env.ts5
-rw-r--r--utils/mod.ts8
-rw-r--r--utils/trace.ts130
33 files changed, 388 insertions, 253 deletions
diff --git a/deno.json b/deno.json
index 1dd298e..7c696db 100644
--- a/deno.json
+++ b/deno.json
@@ -1,3 +1,3 @@
{
- "workspace": ["./model", "./worker", "./hooks", "./utils"]
+ "workspace": ["./model", "./worker", "./hooks", "./utils", "./lizutils"]
}
diff --git a/hooks/job/queue.ts b/hooks/job/queue.ts
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/hooks/job/queue.ts
diff --git a/hooks/main.ts b/hooks/main.ts
new file mode 100644
index 0000000..1348e57
--- /dev/null
+++ b/hooks/main.ts
@@ -0,0 +1 @@
+#!/usr/bin/env -S deno run --allow-env --allow-net --allow-run
diff --git a/hooks/server.ts b/hooks/server.ts
index 000c391..9a3f716 100755
--- a/hooks/server.ts
+++ b/hooks/server.ts
@@ -1,5 +1,3 @@
-#!/usr/bin/env -S deno run --allow-env --allow-net --allow-run
-
import {
Either,
getRequiredEnv,
@@ -20,61 +18,6 @@ interface IHealthCheckActivity<R> {
healthCheck(req: R): Promise<Response>;
}
-class HealthCheckActivity implements IHealthCheckActivity<Traceable<Request>> {
- public async healthCheck(
- req: Traceable<Request>,
- ) {
- return await req.bimap(Traceable.withClassTrace(this))
- .map(async (r) => {
- const { logger } = r;
- try {
- getRequiredEnv("LAMINAR_HOST");
- await getStdout(r.map(() => ["laminarc", "show-jobs"]));
- const msg = `think im healthy!! (✿˘◡˘) ready to do work~\n`;
- logger.log(msg);
- return new Response(
- msg,
- { status: 200 },
- );
- } catch (error) {
- logger.error(error);
- return new Response(
- "oh no, i need to eat more vegetables (。•́︿•̀。)...\n",
- { status: 500 },
- );
- }
- }).item;
- }
-}
-
-const aPost = (req: Traceable<Request>): IEither<Response, Request> => {
- const { item: request, logger: _logger } = req;
- const logger = _logger.addTracer(() => "[aPost]");
-
- if (request.method !== "POST") {
- const msg = "that's not how you pet me (⋟﹏⋞) try post instead~";
- logger.warn(msg);
- return Either.left(new Response(msg + "\n", { status: 405 }));
- }
- return Either.right(request);
-};
-
-type JsonTransformer<JsonT, R> = (json: Traceable<JsonT>) => Either<string, R>;
-const aJson =
- <BodyT, JsonT = unknown>(jsonTransformer: JsonTransformer<JsonT, BodyT>) =>
- async (r: Traceable<Request>): Promise<Either<string, BodyT>> => {
- const { item: request, logger } = r;
- try {
- return Either.right<string, JsonT>(await request.json())
- .mapRight(r.move)
- .flatMap(jsonTransformer);
- } catch (_e) {
- const err = "seems to be invalid JSON (>//<) can you fix?";
- logger.warn(err);
- return Either.left(err);
- }
- };
-
interface IJobHookActivity<R> {
processHook(req: R): Promise<Response>;
}
@@ -82,9 +25,7 @@ type GetJobRequest = { jobType: string; args: unknown };
class JobHookActivityImpl implements IJobHookActivity<Traceable<Request>> {
constructor(private readonly queuer: IJobQueuer<Traceable<Job>>) {}
- private getJob<JsonT>(
- u: Traceable<JsonT>,
- ): Either<string, Job> {
+ private getJob<JsonT>(u: Traceable<JsonT>): Either<string, Job> {
const { logger: _logger, item } = u;
const logger = _logger.addTracer(() => "[getJob]");
const couldBeJsonJob = isObject(item) && "arguments" in item &&
diff --git a/hooks/server/activity/health.ts b/hooks/server/activity/health.ts
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/hooks/server/activity/health.ts
diff --git a/hooks/server/activity/hook.ts b/hooks/server/activity/hook.ts
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/hooks/server/activity/hook.ts
diff --git a/hooks/server/activity/mod.ts b/hooks/server/activity/mod.ts
new file mode 100644
index 0000000..0dee57b
--- /dev/null
+++ b/hooks/server/activity/mod.ts
@@ -0,0 +1,8 @@
+import type { RequestFilter } from "../filter/mod.ts";
+
+export class r200 extends Response {
+ public override readonly status = 200;
+}
+
+export interface IActivity extends RequestFilter<r200> {
+}
diff --git a/hooks/server/filter/json.ts b/hooks/server/filter/json.ts
new file mode 100644
index 0000000..bcdd3ee
--- /dev/null
+++ b/hooks/server/filter/json.ts
@@ -0,0 +1,25 @@
+import { Either, type IEither, type Traceable } from "@emprespresso/utils";
+import type { RequestFilter } from "./mod.ts";
+
+type JsonTransformer<JsonT, R> = (
+ json: Traceable<JsonT>,
+) => IEither<Error, R>;
+export const json = <BodyT, JsonT = unknown>(
+ jsonTransformer: JsonTransformer<JsonT, BodyT>,
+): RequestFilter<BodyT> =>
+async (r: Traceable<Request>) => {
+ const { item: request, logger: _logger } = r;
+ const logger = _logger.addTracer(() => "[jsonVerification]");
+
+ const getJson = request.json().catch((errReason) => {
+ const err = "seems to be invalid JSON (>//<) can you fix?";
+ logger.warn(err, errReason);
+ return new Error(err);
+ });
+ return (await Either.fromAsync<Error, JsonT>(getJson))
+ .mapRight(r.move).flatMap(jsonTransformer)
+ .mapLeft((err) => {
+ logger.warn(err);
+ return new Response(err.message, { status: 400 });
+ });
+};
diff --git a/hooks/server/filter/method.ts b/hooks/server/filter/method.ts
new file mode 100644
index 0000000..07fa5ee
--- /dev/null
+++ b/hooks/server/filter/method.ts
@@ -0,0 +1,22 @@
+import { Either, type Traceable } from "@liz-ci/utils";
+import type { RequestFilter } from "./mod.ts";
+
+type HttpMethod = "POST" | "GET" | "HEAD" | "PUT" | "DELETE";
+export const requireMethod =
+ (methods: Array<HttpMethod>): RequestFilter<HttpMethod> =>
+ (req: Traceable<Request>) => {
+ const { item: request, logger: _logger } = req;
+ const logger = _logger.addTracer(() => "[aPost]");
+
+ const { method: _method } = request;
+ const method = <HttpMethod> _method;
+ if (!methods.includes(method)) {
+ const msg = "that's not how you pet me (⋟﹏⋞)~";
+ logger.warn(msg);
+ return Promise.resolve(Either.left<Response, HttpMethod>(
+ new Response(msg + "\n", { status: 405 }),
+ ));
+ }
+
+ return Promise.resolve(Either.right(method));
+ };
diff --git a/hooks/server/filter/mod.ts b/hooks/server/filter/mod.ts
new file mode 100644
index 0000000..bedc678
--- /dev/null
+++ b/hooks/server/filter/mod.ts
@@ -0,0 +1,18 @@
+import type {
+ IEither,
+ ITraceable,
+ ITraceableLogger,
+ TraceableLogger,
+} from "@liz-ci/utils";
+
+export interface RequestFilter<
+ T,
+ L extends ITraceableLogger<L> = TraceableLogger,
+ RIn = ITraceable<Request, L>,
+ Err = Response,
+> {
+ (req: RIn): Promise<IEither<Err, T>>;
+}
+
+export * from "./method.ts";
+export * from "./json.ts";
diff --git a/hooks/server/mod.ts b/hooks/server/mod.ts
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/hooks/server/mod.ts
diff --git a/u/deno.json b/u/deno.json
new file mode 100644
index 0000000..46e74d6
--- /dev/null
+++ b/u/deno.json
@@ -0,0 +1,6 @@
+{
+ "name": "@emprespresso/utils",
+ "version": "0.1.0",
+ "exports": "./mod.ts",
+ "workspace": ["./*"]
+}
diff --git a/u/fn/callable.ts b/u/fn/callable.ts
new file mode 100644
index 0000000..2749947
--- /dev/null
+++ b/u/fn/callable.ts
@@ -0,0 +1,15 @@
+// deno-lint-ignore no-explicit-any
+export interface Callable<T = any, ArgT = any> {
+ (...args: Array<ArgT>): T;
+}
+
+export interface Supplier<T> extends Callable<T, undefined> {
+ (): T;
+}
+
+export interface SideEffect<T> extends Callable<void, T> {
+}
+
+export interface Mapper<T, U> extends Callable<U, T> {
+ (t: T): U;
+}
diff --git a/u/fn/either.ts b/u/fn/either.ts
new file mode 100644
index 0000000..eaf77fd
--- /dev/null
+++ b/u/fn/either.ts
@@ -0,0 +1,62 @@
+import type { Mapper, Supplier } from "./mod.ts";
+
+export interface IEither<E, T> {
+ mapBoth: <Ee, Tt>(
+ errBranch: Mapper<E, Ee>,
+ okBranch: Mapper<T, Tt>,
+ ) => IEither<Ee, Tt>;
+ flatMap: <Tt>(mapper: Mapper<T, IEither<E, Tt>>) => IEither<E, Tt>;
+ mapRight: <Tt>(mapper: Mapper<T, Tt>) => IEither<E, Tt>;
+ mapLeft: <Ee>(mapper: Mapper<E, Ee>) => IEither<Ee, T>;
+}
+
+export class Either<E, T> implements IEither<E, T> {
+ private constructor(private readonly err?: E, private readonly ok?: T) {}
+
+ public mapBoth<Ee, Tt>(
+ errBranch: Mapper<E, Ee>,
+ okBranch: Mapper<T, Tt>,
+ ): Either<Ee, Tt> {
+ if (this.err) return Either.left(errBranch(this.err));
+ return Either.right(okBranch(this.ok!));
+ }
+
+ public flatMap<Tt>(mapper: Mapper<T, Either<E, Tt>>) {
+ if (this.ok) return mapper(this.ok);
+ return Either.left<E, Tt>(this.err!);
+ }
+
+ public mapRight<Tt>(mapper: Mapper<T, Tt>): IEither<E, Tt> {
+ if (this.ok) return Either.right(mapper(this.ok));
+ return Either.left<E, Tt>(this.err!);
+ }
+
+ public mapLeft<Ee>(mapper: Mapper<E, Ee>) {
+ if (this.err) return Either.left<Ee, T>(mapper(this.err));
+ return Either.right<Ee, T>(this.ok!);
+ }
+
+ static left<E, T>(e: E) {
+ return new Either<E, T>(e);
+ }
+
+ static right<E, T>(t: T) {
+ return new Either<E, T>(undefined, t);
+ }
+
+ static fromFailable<E, T>(s: Supplier<T>) {
+ try {
+ return Either.right<E, T>(s());
+ } catch (e) {
+ return Either.left<E, T>(e as E);
+ }
+ }
+
+ static async fromFailableAsync<E, T>(s: Promise<T>) {
+ try {
+ return Either.right<E, T>(await s);
+ } catch (e) {
+ return Either.left<E, T>(e as E);
+ }
+ }
+}
diff --git a/u/fn/mod.ts b/u/fn/mod.ts
new file mode 100644
index 0000000..f0fbe88
--- /dev/null
+++ b/u/fn/mod.ts
@@ -0,0 +1,2 @@
+export * from "./callable.ts";
+export * from "./either.ts";
diff --git a/u/leftpadesque/debug.ts b/u/leftpadesque/debug.ts
new file mode 100644
index 0000000..a9da1f3
--- /dev/null
+++ b/u/leftpadesque/debug.ts
@@ -0,0 +1,11 @@
+const _hasEnv = !Deno.permissions.querySync({ name: "env" });
+
+const _env: "development" | "production" =
+ _hasEnv && (Deno.env.get("ENVIRONMENT") ?? "").toLowerCase().includes("prod")
+ ? "production"
+ : "development";
+export const isProd = () => _env === "production";
+
+const _debug = !isProd() || (_hasEnv &&
+ ["y", "t"].some((Deno.env.get("DEBUG") ?? "").toLowerCase().startsWith));
+export const isDebug = () => _debug;
diff --git a/u/leftpadesque/mod.ts b/u/leftpadesque/mod.ts
new file mode 100644
index 0000000..801846a
--- /dev/null
+++ b/u/leftpadesque/mod.ts
@@ -0,0 +1,3 @@
+export * from "./object.ts";
+export * from "./prepend.ts";
+export * from "./debug.ts";
diff --git a/utils/isObject.ts b/u/leftpadesque/object.ts
index 73f7f80..73f7f80 100644
--- a/utils/isObject.ts
+++ b/u/leftpadesque/object.ts
diff --git a/utils/prepend.ts b/u/leftpadesque/prepend.ts
index 9b77aff..9b77aff 100644
--- a/utils/prepend.ts
+++ b/u/leftpadesque/prepend.ts
diff --git a/u/mod.ts b/u/mod.ts
new file mode 100644
index 0000000..fab6804
--- /dev/null
+++ b/u/mod.ts
@@ -0,0 +1,4 @@
+export * from "./fn/mod.ts";
+export * from "./leftpadesque/mod.ts";
+export * from "./process/mod.ts";
+export * from "./trace/mod.ts";
diff --git a/u/process/env.ts b/u/process/env.ts
new file mode 100644
index 0000000..e80ec4a
--- /dev/null
+++ b/u/process/env.ts
@@ -0,0 +1,10 @@
+import { Either, type IEither } from "@emprespresso/utils";
+
+export const getRequiredEnv = (name: string): IEither<Error, string> =>
+ Either.fromFailable(() => {
+ const value = Deno.env.get(name); // could throw when no permission.
+ if (!value) {
+ throw new Error(`environment variable "${name}" is required D:`);
+ }
+ return value;
+ });
diff --git a/u/process/mod.ts b/u/process/mod.ts
new file mode 100644
index 0000000..3f02d46
--- /dev/null
+++ b/u/process/mod.ts
@@ -0,0 +1,3 @@
+export * from "./env.ts";
+export * from "./run.ts";
+export * from "./validate_identifier.ts";
diff --git a/utils/run.ts b/u/process/run.ts
index 9093863..6dc37d0 100644
--- a/utils/run.ts
+++ b/u/process/run.ts
@@ -1,4 +1,4 @@
-import { Either, type Traceable } from "./mod.ts";
+import { Either, type Traceable } from "@emprespresso/utils";
export class ProcessError extends Error {}
export const getStdout = async (
diff --git a/utils/validate_identifier.ts b/u/process/validate_identifier.ts
index ec8b77b..ec8b77b 100644
--- a/utils/validate_identifier.ts
+++ b/u/process/validate_identifier.ts
diff --git a/u/server/mod.ts b/u/server/mod.ts
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/u/server/mod.ts
diff --git a/u/trace/itrace.ts b/u/trace/itrace.ts
new file mode 100644
index 0000000..b483067
--- /dev/null
+++ b/u/trace/itrace.ts
@@ -0,0 +1,72 @@
+import { Mapper, SideEffect } from "../fn/mod.ts";
+
+export interface ITrace<TracingW> {
+ addTrace: Mapper<TracingW, ITrace<TracingW>>;
+ trace: SideEffect<TracingW>;
+}
+
+export type ITraceableTuple<T, Trace> = [T, Trace];
+export type ITraceableMapper<T, Trace, U, W = ITraceable<T, Trace>> = (
+ w: W,
+) => U;
+
+export interface ITraceable<T, Trace> {
+ readonly item: T;
+ readonly trace: ITrace<Trace>;
+
+ move<U>(u: U): ITraceable<U, Trace>;
+ map: <U>(
+ mapper: ITraceableMapper<T, Trace, U>,
+ ) => ITraceable<U, Trace>;
+ bimap: <U>(
+ mapper: ITraceableMapper<T, Trace, ITraceableTuple<U, Trace>>,
+ ) => ITraceable<U, Trace>;
+ peek: (peek: ITraceableMapper<T, Trace, void>) => ITraceable<T, Trace>;
+ flatMap: <U>(
+ mapper: ITraceableMapper<T, Trace, ITraceable<U, Trace>>,
+ ) => ITraceable<U, Trace>;
+ flatMapAsync<U>(
+ mapper: ITraceableMapper<T, Trace, Promise<ITraceable<U, Trace>>>,
+ ): ITraceable<Promise<U>, Trace>;
+}
+
+export class TraceableImpl<T, L> implements ITraceable<T, L> {
+ protected constructor(
+ readonly item: T,
+ readonly trace: ITrace<L>,
+ ) {}
+
+ public map<U>(mapper: ITraceableMapper<T, L, U>) {
+ const result = mapper(this);
+ return new TraceableImpl(result, this.trace);
+ }
+
+ public flatMap<U>(
+ mapper: ITraceableMapper<T, L, ITraceable<U, L>>,
+ ): ITraceable<U, L> {
+ return mapper(this);
+ }
+
+ public flatMapAsync<U>(
+ mapper: ITraceableMapper<T, L, Promise<ITraceable<U, L>>>,
+ ): ITraceable<Promise<U>, L> {
+ return new TraceableImpl(
+ mapper(this).then(({ item }) => item),
+ this.trace,
+ );
+ }
+
+ public peek(peek: ITraceableMapper<T, L, void>) {
+ peek(this);
+ return this;
+ }
+
+ public move<Tt>(t: Tt): ITraceable<Tt, L> {
+ return this.map(() => t);
+ }
+
+ public bimap<U>(mapper: ITraceableMapper<T, L, ITraceableTuple<U, L>>) {
+ const [item, trace] = mapper(this);
+ return new TraceableImpl(item, this.trace.addTrace(trace));
+ }
+}
diff --git a/u/trace/logger.ts b/u/trace/logger.ts
new file mode 100644
index 0000000..79da367
--- /dev/null
+++ b/u/trace/logger.ts
@@ -0,0 +1,86 @@
+import {
+ isDebug,
+ isObject,
+ type ITrace,
+ type SideEffect,
+ type Supplier,
+} from "@emprespresso/utils";
+
+export interface ILogger {
+ log: (...args: unknown[]) => void;
+ debug: (...args: unknown[]) => void;
+ warn: (...args: unknown[]) => void;
+ error: (...args: unknown[]) => void;
+}
+export type ILoggerLevel = "UNKNOWN" | "INFO" | "WARN" | "DEBUG" | "ERROR";
+const logLevelOrder: Array<ILoggerLevel> = ["DEBUG", "INFO", "WARN", "ERROR"];
+const defaultAllowedLevels = () =>
+ [
+ "UNKNOWN",
+ ...(isDebug() ? ["DEBUG"] : []),
+ "INFO",
+ "WARN",
+ "ERROR",
+ ] as Array<ILoggerLevel>;
+
+export const logWithLevel = (
+ logger: ILogger,
+ level: ILoggerLevel,
+): SideEffect<unknown> => {
+ switch (level) {
+ case "UNKNOWN":
+ case "INFO":
+ return logger.log;
+ case "DEBUG":
+ return logger.debug;
+ case "WARN":
+ return logger.warn;
+ case "ERROR":
+ return logger.error;
+ }
+};
+
+export const LoggerImpl = console;
+
+export type LogTraceSupplier = string | Supplier<string> | {
+ level: ILoggerLevel;
+};
+
+const foldTraces = (traces: Array<LogTraceSupplier>) => {
+ const { line, level } = traces.reduce(
+ (acc: { line: string; level: number }, t) => {
+ if (isObject(t) && "level" in t) {
+ return {
+ ...acc,
+ level: Math.max(logLevelOrder.indexOf(t.level), acc.level),
+ };
+ }
+ const prefix = [
+ acc.line,
+ typeof t === "function" ? t() : t,
+ ].join(" ");
+ return { ...acc, prefix };
+ },
+ { line: "", level: -1 },
+ );
+ return { line, level: logLevelOrder[level] ?? "UNKNOWN" };
+};
+
+const defaultTrace = () => `[${new Date().toISOString()}]`;
+export const LogTrace = (
+ logger: ILogger,
+ traces: Array<LogTraceSupplier> = [defaultTrace],
+ allowedLevels: Supplier<Array<ILoggerLevel>> = defaultAllowedLevels,
+ defaultLevel: ILoggerLevel = "INFO",
+): ITrace<LogTraceSupplier> => {
+ return {
+ addTrace: (trace: LogTraceSupplier) =>
+ LogTrace(logger, traces.concat(trace)),
+ trace: (trace: LogTraceSupplier) => {
+ const { line, level: _level } = foldTraces(traces.concat(trace));
+ if (!allowedLevels().includes(_level)) return;
+ const level = _level === "UNKNOWN" ? defaultLevel : _level;
+ logWithLevel(logger, level)(`[${level}]${line}`);
+ },
+ };
+};
diff --git a/u/trace/mod.ts b/u/trace/mod.ts
new file mode 100644
index 0000000..9c42858
--- /dev/null
+++ b/u/trace/mod.ts
@@ -0,0 +1,3 @@
+export * from "./itrace.ts";
+export * from "./logger.ts";
+export * from "./trace.ts";
diff --git a/u/trace/trace.ts b/u/trace/trace.ts
new file mode 100644
index 0000000..5d5c59b
--- /dev/null
+++ b/u/trace/trace.ts
@@ -0,0 +1,34 @@
+import type { Callable } from "@emprespresso/utils";
+import {
+ type ITraceableMapper,
+ type ITraceableTuple,
+ TraceableImpl,
+ TraceableLogger,
+} from "./mod.ts";
+
+export class Traceable<T> extends TraceableImpl<T, TraceableLogger> {
+ static from<T>(t: T) {
+ return new Traceable(t, new TraceableLogger());
+ }
+
+ static withFunctionTrace<F extends Callable, T>(
+ f: F,
+ ): ITraceableMapper<T, TraceableLogger, ITraceableTuple<T>> {
+ return (t) => [t.item, f.name];
+ }
+
+ static withClassTrace<C extends object, T>(
+ c: C,
+ ): ITraceableMapper<T, TraceableLogger, ITraceableTuple<T>> {
+ return (t) => [t.item, c.constructor.name];
+ }
+
+ static promiseify<T, U>(
+ mapper: ITraceableMapper<T, TraceableLogger, U>,
+ ): ITraceableMapper<Promise<T>, TraceableLogger, Promise<U>> {
+ return (traceablePromise) =>
+ traceablePromise.flatMapAsync(async (t) =>
+ t.move(await t.item).map(mapper)
+ ).item;
+ }
+}
diff --git a/utils/either.ts b/utils/either.ts
deleted file mode 100644
index 10e4f43..0000000
--- a/utils/either.ts
+++ /dev/null
@@ -1,48 +0,0 @@
-export interface IEither<E, T> {
- ok?: T;
- err?: E;
- mapBoth: <Ee, Tt>(
- errBranch: (e: E) => Ee,
- okBranch: (o: T) => Tt,
- ) => IEither<Ee, Tt>;
- mapRight: <Tt>(mapper: (t: T) => Tt) => Either<E, Tt>;
- mapLeft: <Ee>(mapper: (e: E) => Ee) => Either<Ee, T>;
- flatMap: <Ee extends E, Tt>(
- mapper: (e: T) => Either<Ee, Tt>,
- ) => Either<Ee, Tt>;
-}
-
-export class Either<E, T> implements IEither<E, T> {
- private constructor(readonly err?: E, readonly ok?: T) {}
-
- public mapBoth<Ee, Tt>(
- errBranch: (e: E) => Ee,
- okBranch: (t: T) => Tt,
- ): Either<Ee, Tt> {
- if (this.err) return Either.left(errBranch(this.err));
- return Either.right(okBranch(this.ok!));
- }
-
- public flatMap<Ee extends E, Tt>(mapper: (t: T) => Either<Ee, Tt>) {
- if (this.ok) return mapper(this.ok);
- return this;
- }
-
- public mapRight<Tt>(mapper: (t: T) => Tt): Either<E, Tt> {
- if (this.ok) return Either.right(mapper(this.ok));
- return Either.left(this.err!);
- }
-
- public mapLeft<Ee>(mapper: (e: E) => Ee): Either<Ee, T> {
- if (this.err) return Either.left(mapper(this.err));
- return Either.right(this.ok!);
- }
-
- static left<E, T>(e: E) {
- return new Either<E, T>(e);
- }
-
- static right<E, T>(t: T) {
- return new Either<E, T>(undefined, t);
- }
-}
diff --git a/utils/env.ts b/utils/env.ts
deleted file mode 100644
index 31b7ccf..0000000
--- a/utils/env.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-export const getRequiredEnv = (name: string): string => {
- const value = Deno.env.get(name);
- if (!value) throw new Error(`environment variable "${name}" is required D:`);
- return value;
-};
diff --git a/utils/mod.ts b/utils/mod.ts
deleted file mode 100644
index d8cb526..0000000
--- a/utils/mod.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-export * from "./isObject.ts";
-export * from "./trace.ts";
-export * from "./either.ts";
-export * from "./env.ts";
-export * from "./run.ts";
-export * from "./secret.ts";
-export * from "./validate_identifier.ts";
-export * from "./prepend.ts";
diff --git a/utils/trace.ts b/utils/trace.ts
deleted file mode 100644
index 1a5e51d..0000000
--- a/utils/trace.ts
+++ /dev/null
@@ -1,130 +0,0 @@
-export interface Logger {
- log: (...args: unknown[]) => void;
- debug: (...args: unknown[]) => void;
- warn: (...args: unknown[]) => void;
- error: (...args: unknown[]) => void;
-}
-
-type Supplier<T> = () => T;
-type TraceSupplier = Supplier<string>;
-export interface ITraceableLogger<L extends ITraceableLogger<L>>
- extends Logger {
- addTracer: (traceSupplier: TraceSupplier) => L;
-}
-
-export type ITraceableTuple<T> = [T, TraceSupplier];
-export type ITraceableMapper<T, L extends ITraceableLogger<L>, U> = (
- t: ITraceable<T, L>,
-) => U;
-export interface ITraceable<T, L extends ITraceableLogger<L>> {
- item: T;
- logger: L;
-
- map: <U>(mapper: ITraceableMapper<T, L, U>) => ITraceable<U, L>;
- bimap: <U>(
- mapper: ITraceableMapper<T, L, ITraceableTuple<U>>,
- ) => ITraceable<U, L>;
- peek: (peek: ITraceableMapper<T, L, void>) => ITraceable<T, L>;
- flatMap: <U>(
- mapper: ITraceableMapper<T, L, ITraceable<U, L>>,
- ) => ITraceable<U, L>;
- flatMapAsync<U>(
- mapper: ITraceableMapper<T, L, Promise<ITraceable<U, L>>>,
- ): ITraceable<Promise<U>, L>;
- move<Tt>(t: Tt): ITraceable<Tt, L>;
-}
-
-export class TraceableLogger implements ITraceableLogger<TraceableLogger> {
- private readonly logger: Logger = console;
- constructor(
- private readonly traces = [() => `[${new Date().toISOString()}]`],
- ) {
- }
-
- public debug(...args: unknown[]) {
- this.logger.debug("[DEBUG]", ...this.getPrefix(), args);
- }
-
- public log(...args: unknown[]) {
- this.logger.log("[INFO]", ...this.getPrefix(), args);
- }
-
- public warn(...args: unknown[]) {
- this.logger.warn("[WARN]", ...this.getPrefix(), args);
- }
-
- public error(...args: unknown[]) {
- this.logger.error("[ERROR]", ...this.getPrefix(), args);
- }
-
- public addTracer(traceSupplier: TraceSupplier) {
- return new TraceableLogger(this.traces.concat(traceSupplier));
- }
-
- private getPrefix() {
- return this.traces.map((tracer) => tracer());
- }
-}
-
-class TraceableImpl<
- T,
- L extends ITraceableLogger<L>,
-> implements ITraceable<T, L> {
- protected constructor(readonly item: T, readonly logger: L) {}
-
- public map<U>(mapper: ITraceableMapper<T, L, U>) {
- const result = mapper(this);
- return new TraceableImpl(result, this.logger);
- }
-
- public flatMap<U>(
- mapper: ITraceableMapper<T, L, ITraceable<U, L>>,
- ): ITraceable<U, L> {
- return mapper(this);
- }
-
- public flatMapAsync<U>(
- mapper: ITraceableMapper<T, L, Promise<ITraceable<U, L>>>,
- ): ITraceable<Promise<U>, L> {
- return new TraceableImpl(
- mapper(this).then(({ item }) => item),
- this.logger,
- );
- }
-
- public peek(peek: ITraceableMapper<T, L, void>) {
- peek(this);
- return this;
- }
-
- public move<Tt>(t: Tt) {
- return this.map(() => t);
- }
-
- public bimap<U>(mapper: ITraceableMapper<T, L, ITraceableTuple<U>>) {
- const [item, trace] = mapper(this);
- return new TraceableImpl(item, this.logger.addTracer(trace));
- }
-
- static promiseify<T, L extends ITraceableLogger<L>, U>(
- mapper: ITraceableMapper<T, L, U>,
- ): ITraceableMapper<Promise<T>, L, Promise<U>> {
- return (traceablePromise) =>
- traceablePromise.flatMapAsync(async (t) => {
- const item = await t.item;
- return t.map(() => item).map(mapper);
- }).item;
- }
-}
-
-export class Traceable<T> extends TraceableImpl<T, TraceableLogger> {
- static withClassTrace<C extends object, T>(
- c: C,
- ): ITraceableMapper<T, TraceableLogger, ITraceableTuple<T>> {
- return (t) => [t.item, () => c.constructor.name];
- }
-
- static from<T>(t: T) {
- return new Traceable(t, new TraceableLogger());
- }
-}