UNPKG

zagora

Version:

A minimalist, type-safe, error-safe typed functions in 214 lines of TypeScript based on Zod v4. No batteries, just functions. Simple alternative to oRPC and tRPC.

124 lines (122 loc) 4.15 kB
import { z } from "zod"; //#region src/index.ts function zagora() { return new FluentBuilder(); } const za = zagora(); var FluentBuilder = class FluentBuilder { _inputTuple = null; _output = null; _err = null; input(tuple) { const next = new FluentBuilder(); next._inputTuple = tuple; next._output = this._output; next._err = this._err; return next; } output(schema) { const next = new FluentBuilder(); next._inputTuple = this._inputTuple; next._output = schema; next._err = this._err; return next; } errors(schema) { const next = new FluentBuilder(); next._inputTuple = this._inputTuple; next._output = this._output; next._err = schema; return next; } errorsMap(map) { const next = new FluentBuilder(); next._inputTuple = this._inputTuple; next._output = this._output; next._err = map; return next; } handler(impl) { if (!this._inputTuple) throw new Error(".input(z.tuple(...)) must be called first"); if (!this._output) throw new Error(".output(...) must be called first"); const tuple = this._inputTuple; const items = tuple?._def?.items ?? tuple?._def?.tuple ?? []; const outputSchema = this._output; const errSchema = this._err; const isOmittable = (s) => { const tn = s?._def?.typeName; return tn === "ZodOptional" || tn === "ZodDefault"; }; let minRequired = 0; for (let i = items.length - 1; i >= 0; --i) if (!isOmittable(items[i])) { minRequired = i + 1; break; } const tupleParsers = []; for (let k = minRequired; k <= items.length; ++k) { const prefix = items.slice(0, k); tupleParsers.push(z.tuple(prefix)); } const inputParser = tupleParsers.length === 1 ? tupleParsers[0] : z.union(tupleParsers); const runtimeErrSchema = errSchema && !(errSchema instanceof Object && !("parse" in errSchema)) ? errSchema : void 0; const wrapper = async (...rawArgs) => { const parsed = inputParser.safeParse(rawArgs); if (!parsed.success) return [null, parsed.error]; const provided = parsed.data; const finalArgs = [...provided]; for (let i = provided.length; i < items.length; ++i) { const p = items[i].safeParse(void 0); if (!p.success) return [null, p.error]; finalArgs.push(p.data); } try { const rawResult = await impl(...finalArgs); if (Array.isArray(rawResult) && rawResult.length === 2) { const [maybeOut, maybeErr] = rawResult; if (maybeErr != null) { if (errSchema && typeof errSchema === "object" && !("parse" in errSchema)) { for (const k of Object.keys(errSchema)) { const sch = errSchema[k]; const r = sch.safeParse(maybeErr); if (r.success) return [null, r.data]; } return [null, maybeErr instanceof Error ? maybeErr : new Error(String(maybeErr ?? "unknown"))]; } if (runtimeErrSchema) { const r = await runtimeErrSchema.safeParseAsync(maybeErr); if (!r.success) return [null, r.error]; return [null, r.data]; } return [null, maybeErr instanceof Error ? maybeErr : new Error(String(maybeErr ?? "unknown"))]; } const po$1 = await outputSchema.safeParseAsync(maybeOut); if (!po$1.success) return [null, po$1.error]; return [po$1.data, null]; } const po = await outputSchema.safeParseAsync(rawResult); if (!po.success) return [null, po.error]; return [po.data, null]; } catch (err) { if (errSchema && typeof errSchema === "object" && !("parse" in errSchema)) { for (const k of Object.keys(errSchema)) { const sch = errSchema[k]; const r = sch.safeParse(err); if (r.success) return [null, r.data]; } return [null, err instanceof Error ? err : new Error(String(err ?? "unknown"))]; } if (runtimeErrSchema) { const r = await runtimeErrSchema.safeParseAsync(err); if (!r.success) return [null, r.error]; return [null, r.data]; } return [null, err instanceof Error ? err : new Error(String(err ?? "unknown"))]; } }; const forwardImpl = (...args) => wrapper(...args); const forward = forwardImpl; return forward; } }; //#endregion export { FluentBuilder, z, za, zagora };