summaryrefslogtreecommitdiff
path: root/u
diff options
context:
space:
mode:
Diffstat (limited to 'u')
-rw-r--r--u/deno.json2
-rw-r--r--u/fn/either.ts4
-rw-r--r--u/mod.ts1
-rw-r--r--u/process/env.ts2
-rw-r--r--u/process/run.ts97
-rw-r--r--u/process/validate_identifier.ts19
-rw-r--r--u/server/activity/health.ts39
-rw-r--r--u/server/activity/mod.ts8
-rw-r--r--u/server/filter/json.ts32
-rw-r--r--u/server/filter/method.ts37
-rw-r--r--u/server/filter/mod.ts13
-rw-r--r--u/server/mod.ts1
-rw-r--r--u/trace/itrace.ts68
-rw-r--r--u/trace/logger.ts67
-rw-r--r--u/trace/trace.ts40
15 files changed, 320 insertions, 110 deletions
diff --git a/u/deno.json b/u/deno.json
index 46e74d6..26b08bf 100644
--- a/u/deno.json
+++ b/u/deno.json
@@ -1,5 +1,5 @@
{
- "name": "@emprespresso/utils",
+ "name": "@emprespresso/pengueno",
"version": "0.1.0",
"exports": "./mod.ts",
"workspace": ["./*"]
diff --git a/u/fn/either.ts b/u/fn/either.ts
index eaf77fd..12240d0 100644
--- a/u/fn/either.ts
+++ b/u/fn/either.ts
@@ -1,4 +1,4 @@
-import type { Mapper, Supplier } from "./mod.ts";
+import type { Mapper, Supplier } from "@emprespresso/pengueno";
export interface IEither<E, T> {
mapBoth: <Ee, Tt>(
@@ -21,7 +21,7 @@ export class Either<E, T> implements IEither<E, T> {
return Either.right(okBranch(this.ok!));
}
- public flatMap<Tt>(mapper: Mapper<T, Either<E, Tt>>) {
+ public flatMap<Tt>(mapper: Mapper<T, Either<E, Tt>>): Either<E, Tt> {
if (this.ok) return mapper(this.ok);
return Either.left<E, Tt>(this.err!);
}
diff --git a/u/mod.ts b/u/mod.ts
index fab6804..8397ce6 100644
--- a/u/mod.ts
+++ b/u/mod.ts
@@ -2,3 +2,4 @@ export * from "./fn/mod.ts";
export * from "./leftpadesque/mod.ts";
export * from "./process/mod.ts";
export * from "./trace/mod.ts";
+export * from "./server/mod.ts";
diff --git a/u/process/env.ts b/u/process/env.ts
index c3ae800..26e1158 100644
--- a/u/process/env.ts
+++ b/u/process/env.ts
@@ -1,4 +1,4 @@
-import { Either, type IEither } from "@emprespresso/utils";
+import { Either, type IEither } from "@emprespresso/pengueno";
export const getRequiredEnv = (name: string): IEither<Error, string> =>
Either
diff --git a/u/process/run.ts b/u/process/run.ts
index 6dc37d0..670f567 100644
--- a/u/process/run.ts
+++ b/u/process/run.ts
@@ -1,40 +1,63 @@
-import { Either, type Traceable } from "@emprespresso/utils";
+import {
+ Either,
+ type IEither,
+ type ITraceable,
+ LogLevel,
+ TraceUtil,
+} from "@emprespresso/pengueno";
+
+type Command = string[] | string;
+type CommandOutputDecoded = {
+ code: number;
+ stdoutText: string;
+ stderrText: string;
+};
export class ProcessError extends Error {}
-export const getStdout = async (
- { item: cmd, logger: _logger }: Traceable<string[] | string>,
+export const getStdout = (
+ c: ITraceable<Command>,
options: Deno.CommandOptions = {},
-): Promise<Either<ProcessError, string>> => {
- const logger = _logger.addTracer(() => "[getStdout]");
-
- logger.log(`:> im gonna run this command!`, cmd);
- const [exec, ...args] = (typeof cmd === "string") ? cmd.split(" ") : cmd;
- const command = new Deno.Command(exec, {
- args,
- stdout: "piped",
- stderr: "piped",
- ...options,
- });
-
- try {
- const { code, stdout, stderr } = await command.output();
- const stdoutText = new TextDecoder().decode(stdout);
- const stderrText = new TextDecoder().decode(stderr);
-
- if (code !== 0) {
- logger.error(`i weceived an exit code of ${code} i wanna zeroooo :<`);
- return Either.left<ProcessError, string>(
- new ProcessError(`command failed\n${stderrText}`),
- );
- }
-
- logger.log("yay! i got code 0 :3", cmd);
- return Either.right<ProcessError, string>(stdoutText);
- } catch (e) {
- logger.error(`o.o wat`, e);
- if (e instanceof Error) {
- return Either.left<ProcessError, string>(e);
- }
- throw new Error("unknown error " + e);
- }
-};
+): Promise<IEither<ProcessError, string>> =>
+ c.bimap(TraceUtil.withFunctionTrace(getStdout))
+ .map(({ item: cmd, trace }) => {
+ trace.trace(`:> im gonna run this command! ${cmd}`);
+ const [exec, ...args] = (typeof cmd === "string") ? cmd.split(" ") : cmd;
+ return new Deno.Command(exec, {
+ args,
+ stdout: "piped",
+ stderr: "piped",
+ ...options,
+ }).output();
+ })
+ .map(({ item: p }) =>
+ Either.fromFailableAsync<Error, Deno.CommandOutput>(p)
+ )
+ .map(
+ TraceUtil.promiseify(({ item: eitherOutput, trace }) =>
+ eitherOutput.flatMap(({ code, stderr, stdout }) =>
+ Either
+ .fromFailable<Error, CommandOutputDecoded>(() => {
+ const stdoutText = new TextDecoder().decode(stdout);
+ const stderrText = new TextDecoder().decode(stderr);
+ return { code, stdoutText, stderrText };
+ })
+ .mapLeft((e) => {
+ trace.addTrace(LogLevel.ERROR).trace(`o.o wat ${e}`);
+ return new ProcessError(`${e}`);
+ })
+ .flatMap((decodedOutput): Either<ProcessError, string> => {
+ const { code, stdoutText, stderrText } = decodedOutput;
+ trace.addTrace(LogLevel.DEBUG).trace(
+ `stderr hehehe ${stderrText}`,
+ );
+ if (code !== 0) {
+ const msg =
+ `i weceived an exit code of ${code} i wanna zewoooo :<`;
+ trace.addTrace(LogLevel.ERROR).trace(msg);
+ return Either.left(new ProcessError(msg));
+ }
+ return Either.right(stdoutText);
+ })
+ )
+ ),
+ ).item;
diff --git a/u/process/validate_identifier.ts b/u/process/validate_identifier.ts
index ec8b77b..32952a6 100644
--- a/u/process/validate_identifier.ts
+++ b/u/process/validate_identifier.ts
@@ -1,4 +1,4 @@
-import { Either } from "./mod.ts";
+import { Either, type IEither } from "@emprespresso/pengueno";
export const validateIdentifier = (token: string) => {
return (/^[a-zA-Z0-9_\-:. \/]+$/).test(token) && !token.includes("..");
@@ -6,11 +6,18 @@ export const validateIdentifier = (token: string) => {
// ensure {@param obj} is a Record<string, string> with stuff that won't
// have the potential for shell injection, just to be super safe.
-export const validateExecutionEntries = (
- obj: Record<string, unknown>,
-): Either<Array<[string, unknown]>, Record<string, string>> => {
- const invalidEntries = Object.entries(obj).filter((e) =>
- !e.every((x) => typeof x === "string" && validateIdentifier(x))
+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/health.ts b/u/server/activity/health.ts
new file mode 100644
index 0000000..bf1f52c
--- /dev/null
+++ b/u/server/activity/health.ts
@@ -0,0 +1,39 @@
+import {
+ Either,
+ getRequiredEnv,
+ getStdout,
+ type ITraceable,
+ LogLevel,
+ type Mapper,
+ TraceUtil,
+} from "@emprespresso/pengueno";
+
+type HealthCheckInput = "healthy?";
+type HealthCheckOutput = "healthy!";
+
+const HealthCheckActivity = <Trace>(
+ check: Mapper<
+ ITraceable<HealthCheckInput, Trace>,
+ Promise<Either<Error, HealthCheckOutput>>
+ >,
+) =>
+(req: ITraceable<Request, Trace>) =>
+ req.bimap(TraceUtil.withFunctionTrace(HealthCheckActivity))
+ .flatMap((r) => r.move(<HealthCheckInput> "healthy?"))
+ .map(check)
+ .map(TraceUtil.promiseify(({ item: health, trace }) => {
+ health.mapBoth((e) => {
+ trace.addTrace(LogLevel.ERROR).trace(`${e}`);
+ return new Response(
+ "oh no, i need to eat more vegetables (。•́︿•̀。)...\n",
+ { status: 500 },
+ );
+ }, (_healthy) => {
+ const msg = `think im healthy!! (✿˘◡˘) ready to do work~`;
+ trace.trace(msg);
+ return new Response(
+ msg + "\n",
+ { status: 200 },
+ );
+ });
+ }));
diff --git a/u/server/activity/mod.ts b/u/server/activity/mod.ts
new file mode 100644
index 0000000..6908c26
--- /dev/null
+++ b/u/server/activity/mod.ts
@@ -0,0 +1,8 @@
+import type { RequestFilter } from "@emprespresso/pengueno";
+
+export class r200 extends Response {
+ public override readonly status = 200;
+}
+
+export interface IActivity<Trace> extends RequestFilter<r200, Trace> {
+}
diff --git a/u/server/filter/json.ts b/u/server/filter/json.ts
new file mode 100644
index 0000000..3f11915
--- /dev/null
+++ b/u/server/filter/json.ts
@@ -0,0 +1,32 @@
+import {
+ Either,
+ type IEither,
+ type ITraceable,
+ LogLevel,
+ type RequestFilter,
+ TraceUtil,
+} from "@emprespresso/pengueno";
+
+type JsonTransformer<JsonT, R> = (
+ json: ITraceable<JsonT>,
+) => IEither<Error, R>;
+export const json = <BodyT, Trace, JsonT = unknown>(
+ jsonTransformer: JsonTransformer<JsonT, BodyT>,
+): RequestFilter<BodyT, Trace> =>
+(r: ITraceable<Request, Trace>) =>
+ r.bimap(TraceUtil.withFunctionTrace(json))
+ .map(({ item: request }) => Either.fromFailableAsync(request.json()))
+ .map(
+ TraceUtil.promiseify(({ item: eitherJson, trace }) =>
+ eitherJson.mapLeft((errReason) => {
+ trace.addTrace(LogLevel.WARN).trace(`${errReason}`);
+ const err = "seems to be invalid JSON (>//<) can you fix?";
+ return new Error(err);
+ })
+ .flatMap(jsonTransformer)
+ .mapLeft((err) => {
+ trace.addTrace(LogLevel.WARN).trace(`${err}`);
+ return new Response(err.message, { status: 400 });
+ })
+ ),
+ ).item;
diff --git a/u/server/filter/method.ts b/u/server/filter/method.ts
new file mode 100644
index 0000000..2bf45a0
--- /dev/null
+++ b/u/server/filter/method.ts
@@ -0,0 +1,37 @@
+import {
+ Either,
+ type ITraceable,
+ LogLevel,
+ type RequestFilter,
+ TraceUtil,
+} from "@emprespresso/pengueno";
+
+type HttpMethod =
+ | "POST"
+ | "GET"
+ | "HEAD"
+ | "PUT"
+ | "DELETE"
+ | "CONNECT"
+ | "OPTIONS"
+ | "TRACE"
+ | "PATCH";
+
+export const requireMethod =
+ <Trace>(methods: Array<HttpMethod>): RequestFilter<HttpMethod, Trace> =>
+ (req: ITraceable<Request, Trace>) =>
+ req.bimap(TraceUtil.withFunctionTrace(requireMethod))
+ .map(({ item }) => Promise.resolve(item))
+ .map(TraceUtil.promiseify(({ item: request, trace }) => {
+ const { method: _method } = request;
+ const method = <HttpMethod> _method;
+ if (!methods.includes(method)) {
+ const msg = "that's not how you pet me (⋟﹏⋞)~";
+ trace.addTrace(LogLevel.WARN).trace(msg);
+ return Either.left<Response, HttpMethod>(
+ new Response(msg + "\n", { status: 405 }),
+ );
+ }
+
+ return Either.right<Response, HttpMethod>(method);
+ })).item;
diff --git a/u/server/filter/mod.ts b/u/server/filter/mod.ts
new file mode 100644
index 0000000..3256d35
--- /dev/null
+++ b/u/server/filter/mod.ts
@@ -0,0 +1,13 @@
+import type { IEither, ITraceable } from "@emprespresso/pengueno";
+
+export interface RequestFilter<
+ T,
+ Trace,
+ RIn = ITraceable<Request, Trace>,
+ Err = Response,
+> {
+ (req: RIn): Promise<IEither<Err, T>>;
+}
+
+export * from "./method.ts";
+export * from "./json.ts";
diff --git a/u/server/mod.ts b/u/server/mod.ts
index e69de29..556771d 100644
--- a/u/server/mod.ts
+++ b/u/server/mod.ts
@@ -0,0 +1 @@
+export * from "./filter/mod.ts";
diff --git a/u/trace/itrace.ts b/u/trace/itrace.ts
index b483067..b9b750d 100644
--- a/u/trace/itrace.ts
+++ b/u/trace/itrace.ts
@@ -1,71 +1,95 @@
-import { Mapper, SideEffect } from "../fn/mod.ts";
+import type { Mapper, SideEffect } from "@emprespresso/pengueno";
-export interface ITrace<TracingW> {
- addTrace: Mapper<TracingW, ITrace<TracingW>>;
- trace: SideEffect<TracingW>;
+// the "thing" every Trace writer must "trace()"
+type BaseTraceWith = string;
+export type ITraceWith<T> = BaseTraceWith | T;
+export interface ITrace<TraceWith> {
+ addTrace: Mapper<ITraceWith<TraceWith>, ITrace<TraceWith>>;
+ trace: SideEffect<ITraceWith<TraceWith>>;
}
-export type ITraceableTuple<T, Trace> = [T, Trace];
-export type ITraceableMapper<T, Trace, U, W = ITraceable<T, Trace>> = (
+export type ITraceableTuple<T, TraceWith> = [T, BaseTraceWith | TraceWith];
+export type ITraceableMapper<
+ T,
+ U,
+ TraceWith,
+ W = ITraceable<T, TraceWith>,
+> = (
w: W,
) => U;
-export interface ITraceable<T, Trace> {
+export interface ITraceable<T, Trace = BaseTraceWith> {
readonly item: T;
readonly trace: ITrace<Trace>;
move<U>(u: U): ITraceable<U, Trace>;
map: <U>(
- mapper: ITraceableMapper<T, Trace, U>,
+ mapper: ITraceableMapper<T, U, Trace>,
) => ITraceable<U, Trace>;
bimap: <U>(
- mapper: ITraceableMapper<T, Trace, ITraceableTuple<U, Trace>>,
+ mapper: ITraceableMapper<T, ITraceableTuple<U, Trace>, Trace>,
) => ITraceable<U, Trace>;
- peek: (peek: ITraceableMapper<T, Trace, void>) => ITraceable<T, Trace>;
+ peek: (peek: ITraceableMapper<T, void, Trace>) => ITraceable<T, Trace>;
flatMap: <U>(
- mapper: ITraceableMapper<T, Trace, ITraceable<U, Trace>>,
+ mapper: ITraceableMapper<T, ITraceable<U, Trace>, Trace>,
) => ITraceable<U, Trace>;
flatMapAsync<U>(
- mapper: ITraceableMapper<T, Trace, Promise<ITraceable<U, Trace>>>,
+ mapper: ITraceableMapper<T, Promise<ITraceable<U, Trace>>, Trace>,
): ITraceable<Promise<U>, Trace>;
}
-export class TraceableImpl<T, L> implements ITraceable<T, L> {
+export class TraceableImpl<T, TraceWith> implements ITraceable<T, TraceWith> {
protected constructor(
readonly item: T,
- readonly trace: ITrace<L>,
+ readonly trace: ITrace<TraceWith>,
) {}
- public map<U>(mapper: ITraceableMapper<T, L, U>) {
+ public map<U>(
+ mapper: ITraceableMapper<T, U, TraceWith>,
+ ) {
const result = mapper(this);
return new TraceableImpl(result, this.trace);
}
public flatMap<U>(
- mapper: ITraceableMapper<T, L, ITraceable<U, L>>,
- ): ITraceable<U, L> {
+ mapper: ITraceableMapper<
+ T,
+ ITraceable<U, TraceWith>,
+ TraceWith
+ >,
+ ): ITraceable<U, TraceWith> {
return mapper(this);
}
public flatMapAsync<U>(
- mapper: ITraceableMapper<T, L, Promise<ITraceable<U, L>>>,
- ): ITraceable<Promise<U>, L> {
+ mapper: ITraceableMapper<
+ T,
+ Promise<ITraceable<U, TraceWith>>,
+ TraceWith
+ >,
+ ): ITraceable<Promise<U>, TraceWith> {
return new TraceableImpl(
mapper(this).then(({ item }) => item),
this.trace,
);
}
- public peek(peek: ITraceableMapper<T, L, void>) {
+ public peek(peek: ITraceableMapper<T, void, TraceWith>) {
peek(this);
return this;
}
- public move<Tt>(t: Tt): ITraceable<Tt, L> {
+ public move<Tt>(t: Tt): ITraceable<Tt, TraceWith> {
return this.map(() => t);
}
- public bimap<U>(mapper: ITraceableMapper<T, L, ITraceableTuple<U, L>>) {
+ public bimap<U>(
+ mapper: ITraceableMapper<
+ T,
+ ITraceableTuple<U, TraceWith>,
+ TraceWith
+ >,
+ ) {
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
index 79da367..4f3c856 100644
--- a/u/trace/logger.ts
+++ b/u/trace/logger.ts
@@ -1,10 +1,9 @@
import {
isDebug,
- isObject,
type ITrace,
type SideEffect,
type Supplier,
-} from "@emprespresso/utils";
+} from "@emprespresso/pengueno";
export interface ILogger {
log: (...args: unknown[]) => void;
@@ -12,74 +11,88 @@ export interface ILogger {
warn: (...args: unknown[]) => void;
error: (...args: unknown[]) => void;
}
-export type ILoggerLevel = "UNKNOWN" | "INFO" | "WARN" | "DEBUG" | "ERROR";
-const logLevelOrder: Array<ILoggerLevel> = ["DEBUG", "INFO", "WARN", "ERROR"];
+export enum LogLevel {
+ UNKNOWN = "UNKNOWN",
+ INFO = "INFO",
+ WARN = "WARN",
+ DEBUG = "DEBUG",
+ ERROR = "ERROR",
+}
+const logLevelOrder: Array<LogLevel> = [
+ LogLevel.DEBUG,
+ LogLevel.INFO,
+ LogLevel.WARN,
+ LogLevel.ERROR,
+];
+export const isLogLevel = (l: string): l is LogLevel =>
+ logLevelOrder.some((level) => <string> level === l);
+
const defaultAllowedLevels = () =>
[
- "UNKNOWN",
- ...(isDebug() ? ["DEBUG"] : []),
- "INFO",
- "WARN",
- "ERROR",
- ] as Array<ILoggerLevel>;
+ LogLevel.UNKNOWN,
+ ...(isDebug() ? [LogLevel.DEBUG] : []),
+ LogLevel.INFO,
+ LogLevel.WARN,
+ LogLevel.ERROR,
+ ] as Array<LogLevel>;
export const logWithLevel = (
logger: ILogger,
- level: ILoggerLevel,
+ level: LogLevel,
): SideEffect<unknown> => {
switch (level) {
- case "UNKNOWN":
- case "INFO":
+ case LogLevel.UNKNOWN:
+ case LogLevel.INFO:
return logger.log;
- case "DEBUG":
+ case LogLevel.DEBUG:
return logger.debug;
- case "WARN":
+ case LogLevel.WARN:
return logger.warn;
- case "ERROR":
+ case LogLevel.ERROR:
return logger.error;
}
};
export const LoggerImpl = console;
-export type LogTraceSupplier = string | Supplier<string> | {
- level: ILoggerLevel;
-};
+export type LogTraceSupplier = string | Supplier<string>;
const foldTraces = (traces: Array<LogTraceSupplier>) => {
const { line, level } = traces.reduce(
(acc: { line: string; level: number }, t) => {
- if (isObject(t) && "level" in t) {
+ const val = typeof t === "function" ? t() : t;
+ if (isLogLevel(val)) {
return {
...acc,
- level: Math.max(logLevelOrder.indexOf(t.level), acc.level),
+ level: Math.max(logLevelOrder.indexOf(val), acc.level),
};
}
const prefix = [
acc.line,
- typeof t === "function" ? t() : t,
+ val,
].join(" ");
return { ...acc, prefix };
},
{ line: "", level: -1 },
);
- return { line, level: logLevelOrder[level] ?? "UNKNOWN" };
+ return { line, level: logLevelOrder[level] ?? LogLevel.UNKNOWN };
};
const defaultTrace = () => `[${new Date().toISOString()}]`;
export const LogTrace = (
logger: ILogger,
traces: Array<LogTraceSupplier> = [defaultTrace],
- allowedLevels: Supplier<Array<ILoggerLevel>> = defaultAllowedLevels,
- defaultLevel: ILoggerLevel = "INFO",
+ allowedLevels: Supplier<Array<LogLevel>> = defaultAllowedLevels,
+ defaultLevel: LogLevel = LogLevel.INFO,
): ITrace<LogTraceSupplier> => {
return {
addTrace: (trace: LogTraceSupplier) =>
- LogTrace(logger, traces.concat(trace)),
+ LogTrace(logger, traces.concat(trace), allowedLevels, defaultLevel),
trace: (trace: LogTraceSupplier) => {
const { line, level: _level } = foldTraces(traces.concat(trace));
if (!allowedLevels().includes(_level)) return;
- const level = _level === "UNKNOWN" ? defaultLevel : _level;
+
+ const level = _level === LogLevel.UNKNOWN ? defaultLevel : _level;
logWithLevel(logger, level)(`[${level}]${line}`);
},
};
diff --git a/u/trace/trace.ts b/u/trace/trace.ts
index 5d5c59b..1d3d2d8 100644
--- a/u/trace/trace.ts
+++ b/u/trace/trace.ts
@@ -1,31 +1,43 @@
-import type { Callable } from "@emprespresso/utils";
import {
+ type Callable,
type ITraceableMapper,
type ITraceableTuple,
+ LoggerImpl,
+ LogTrace,
+ type LogTraceSupplier,
TraceableImpl,
- TraceableLogger,
-} from "./mod.ts";
+} from "@emprespresso/pengueno";
-export class Traceable<T> extends TraceableImpl<T, TraceableLogger> {
+export class LogTraceable<T> extends TraceableImpl<T, LogTraceSupplier> {
static from<T>(t: T) {
- return new Traceable(t, new TraceableLogger());
+ return new LogTraceable(t, LogTrace(LoggerImpl));
}
+}
- static withFunctionTrace<F extends Callable, T>(
+export class TraceUtil {
+ static withFunctionTrace<F extends Callable, T, Trace>(
f: F,
- ): ITraceableMapper<T, TraceableLogger, ITraceableTuple<T>> {
- return (t) => [t.item, f.name];
+ ): ITraceableMapper<
+ T,
+ ITraceableTuple<T, Trace>,
+ Trace
+ > {
+ return (t) => [t.item, `[${f.name}]`];
}
- static withClassTrace<C extends object, T>(
+ static withClassTrace<C extends object, T, Trace>(
c: C,
- ): ITraceableMapper<T, TraceableLogger, ITraceableTuple<T>> {
- return (t) => [t.item, c.constructor.name];
+ ): ITraceableMapper<
+ T,
+ ITraceableTuple<T, Trace>,
+ Trace
+ > {
+ return (t) => [t.item, `[${c.constructor.name}]`];
}
- static promiseify<T, U>(
- mapper: ITraceableMapper<T, TraceableLogger, U>,
- ): ITraceableMapper<Promise<T>, TraceableLogger, Promise<U>> {
+ 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.item).map(mapper)