diff options
author | Elizabeth Hunt <me@liz.coffee> | 2025-06-20 14:53:38 -0700 |
---|---|---|
committer | Elizabeth Hunt <me@liz.coffee> | 2025-06-20 14:53:38 -0700 |
commit | d4791f3d357634daf506fb8f91cc5332a794c421 (patch) | |
tree | 1bb01d2d4d8fa74d83bb6f99f2c8aa4146ca2d11 /u/server/filter | |
parent | d7e8d31c94cd713a2f4cf799e20e993acc69e361 (diff) | |
download | ci-d4791f3d357634daf506fb8f91cc5332a794c421.tar.gz ci-d4791f3d357634daf506fb8f91cc5332a794c421.zip |
Move to nodejs
Diffstat (limited to 'u/server/filter')
-rw-r--r-- | u/server/filter/index.ts | 34 | ||||
-rw-r--r-- | u/server/filter/json.ts | 92 | ||||
-rw-r--r-- | u/server/filter/method.ts | 67 | ||||
-rw-r--r-- | u/server/filter/mod.ts | 35 |
4 files changed, 106 insertions, 122 deletions
diff --git a/u/server/filter/index.ts b/u/server/filter/index.ts new file mode 100644 index 0000000..62a584d --- /dev/null +++ b/u/server/filter/index.ts @@ -0,0 +1,34 @@ +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): 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 index 145d1be..527d483 100644 --- a/u/server/filter/json.ts +++ b/u/server/filter/json.ts @@ -1,54 +1,50 @@ import { - Either, - type IEither, - type ITraceable, - LogLevel, - Metric, - PenguenoError, - type PenguenoRequest, - type RequestFilter, - type ServerTrace, - TraceUtil, -} from "@emprespresso/pengueno"; + 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>; + (json: ITraceable<ParsedJson, ServerTrace>): IEither<PenguenoError, R>; } -const ParseJsonMetric = Metric.fromName("JsonParse"); +const ParseJsonMetric = Metric.fromName('JsonParse'); export const jsonModel = - <MessageT>( - jsonTransformer: JsonTransformer<MessageT>, - ): RequestFilter<MessageT> => - (r: ITraceable<PenguenoRequest, ServerTrace>) => - r - .bimap(TraceUtil.withFunctionTrace(jsonModel)) - .bimap(TraceUtil.withMetricTrace(ParseJsonMetric)) - .map((j) => - Either.fromFailableAsync<Error, MessageT>(() => j.get().json()).then( - (either) => - either.mapLeft((errReason) => { - j.trace.addTrace(LogLevel.WARN).trace(errReason); - return new PenguenoError( - "seems to be invalid JSON (>//<) can you fix?", - 400, - ); - }), - ), - ) - .peek( - TraceUtil.promiseify((traceableEither) => - traceableEither.get().fold(({ isLeft }) => - traceableEither.trace.trace(ParseJsonMetric[isLeft ? "failure" : "success"]) - ), - ), - ) - .map( - TraceUtil.promiseify((traceableEitherJson) => - traceableEitherJson - .get() - .mapRight((j) => traceableEitherJson.move(j)) - .flatMap(jsonTransformer), - ), - ) - .get(); + <MessageT>(jsonTransformer: JsonTransformer<MessageT>): RequestFilter<MessageT> => + (r: ITraceable<PenguenoRequest, ServerTrace>) => + r + .bimap(TraceUtil.withFunctionTrace(jsonModel)) + .bimap(TraceUtil.withMetricTrace(ParseJsonMetric)) + .map((j) => + Either.fromFailableAsync<Error, MessageT>(<Promise<MessageT>>j.get().json()).then((either) => + either.mapLeft((errReason) => { + j.trace.addTrace(LogLevel.WARN).trace(errReason); + return new PenguenoError('seems to be invalid JSON (>//<) can you fix?', 400); + }), + ), + ) + .peek( + TraceUtil.promiseify((traceableEither) => + traceableEither + .get() + .fold(({ isLeft }) => + traceableEither.trace.trace(ParseJsonMetric[isLeft ? 'failure' : 'success']), + ), + ), + ) + .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 index 9901c6f..5ca5716 100644 --- a/u/server/filter/method.ts +++ b/u/server/filter/method.ts @@ -1,43 +1,32 @@ import { - Either, - type ITraceable, - LogLevel, - PenguenoError, - type PenguenoRequest, - type RequestFilter, - type ServerTrace, - TraceUtil, -} from "@emprespresso/pengueno"; + Either, + type ITraceable, + LogLevel, + PenguenoError, + type PenguenoRequest, + type RequestFilter, + type ServerTrace, + TraceUtil, +} from '@emprespresso/pengueno'; -type HttpMethod = - | "POST" - | "GET" - | "HEAD" - | "PUT" - | "DELETE" - | "CONNECT" - | "OPTIONS" - | "TRACE" - | "PATCH"; +type HttpMethod = 'POST' | 'GET' | 'HEAD' | 'PUT' | 'DELETE' | 'CONNECT' | 'OPTIONS' | 'TRACE' | 'PATCH'; export const requireMethod = - (methods: Array<HttpMethod>): RequestFilter<HttpMethod> => - (req: ITraceable<PenguenoRequest, ServerTrace>) => - req - .bimap(TraceUtil.withFunctionTrace(requireMethod)) - .move(Promise.resolve(req.get())) - .map( - TraceUtil.promiseify((t) => { - const { method: _method } = t.get(); - const method = <HttpMethod>_method; - if (!methods.includes(method)) { - const msg = "that's not how you pet me (⋟﹏⋞)~"; - t.trace.addTrace(LogLevel.WARN).trace(msg); - return Either.left<PenguenoError, HttpMethod>( - new PenguenoError(msg, 405), - ); - } - return Either.right<PenguenoError, HttpMethod>(method); - }), - ) - .get(); + (methods: Array<HttpMethod>): RequestFilter<HttpMethod> => + (req: ITraceable<PenguenoRequest, ServerTrace>) => + req + .bimap(TraceUtil.withFunctionTrace(requireMethod)) + .move(Promise.resolve(req.get())) + .map( + TraceUtil.promiseify((t) => { + const { method: _method } = t.get(); + const method = <HttpMethod>_method; + if (!methods.includes(method)) { + const msg = "that's not how you pet me (⋟﹏⋞)~"; + t.trace.addTrace(LogLevel.WARN).trace(msg); + return Either.left<PenguenoError, HttpMethod>(new PenguenoError(msg, 405)); + } + return Either.right<PenguenoError, HttpMethod>(method); + }), + ) + .get(); diff --git a/u/server/filter/mod.ts b/u/server/filter/mod.ts deleted file mode 100644 index 0e0a4cb..0000000 --- a/u/server/filter/mod.ts +++ /dev/null @@ -1,35 +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): Promise<IEither<Err, T>>; -} - -export * from "./method.ts"; -export * from "./json.ts"; |