UNPKG

@trpc/server

Version:

The tRPC server library

585 lines (583 loc) • 20 kB
import { d as isObject, f as mergeWithoutOverrides, s as emptyObject, u as isFunction } from "./codes-nbrm_zWY.mjs"; import { g as createRecursiveProxy, i as defaultFormatter, n as _objectSpread2, r as _defineProperty } from "./getErrorShape-B5jPKHJ3.mjs"; //#region src/unstable-core-do-not-import/error/TRPCError.ts var UnknownCauseError = class extends Error { constructor(cause) { super(getMessage(cause)); Object.assign(this, cause); if (isErrorLike(cause)) { if (typeof cause.name === "string") this.name = cause.name; if (typeof cause.stack === "string") this.stack = cause.stack; } } }; function getMessage(cause) { if ("message" in cause) return String(cause.message); } /** * Errors from another realm (e.g. `node:vm`, iframes) fail `instanceof Error` * but still carry the `[object Error]` brand. */ function isErrorLike(value) { return value instanceof Error || Object.prototype.toString.call(value) === "[object Error]"; } function getCauseFromUnknown(cause) { if (cause instanceof Error) return cause; const type = typeof cause; if (type === "undefined" || type === "function" || cause === null) return; if (type !== "object") return new Error(String(cause)); if (isObject(cause)) return new UnknownCauseError(cause); } /** * Turns anything thrown into a `TRPCError`. A `TRPCError` is returned as * is; anything else becomes an `INTERNAL_SERVER_ERROR` with it as the * cause. */ function getTRPCErrorFromUnknown(cause) { if (cause instanceof TRPCError) return cause; if (cause instanceof Error && cause.name === "TRPCError") return cause; const trpcError = new TRPCError({ code: "INTERNAL_SERVER_ERROR", cause }); if (isErrorLike(cause) && cause.stack) trpcError.stack = cause.stack; return trpcError; } /** * An error with a tRPC error code, which sets the HTTP status and the code * the client sees. Throw it from resolvers and middlewares. * @example * ```ts * throw new TRPCError({ code: 'NOT_FOUND', message: 'No such post' }); * ``` * @see https://trpc.io/docs/server/error-handling#throwing-errors */ var TRPCError = class extends Error { constructor(opts) { var _ref, _opts$message, _this$cause; const cause = getCauseFromUnknown(opts.cause); const message = (_ref = (_opts$message = opts.message) !== null && _opts$message !== void 0 ? _opts$message : cause === null || cause === void 0 ? void 0 : cause.message) !== null && _ref !== void 0 ? _ref : opts.code; super(message, { cause }); _defineProperty(this, "cause", void 0); _defineProperty(this, "code", void 0); this.code = opts.code; this.name = "TRPCError"; (_this$cause = this.cause) !== null && _this$cause !== void 0 || (this.cause = cause); } }; //#endregion //#region src/unstable-core-do-not-import/transformer.ts /** * @internal */ function getDataTransformer(transformer) { if ("input" in transformer) return transformer; return { input: transformer, output: transformer }; } /** * @internal */ const defaultTransformer = { input: { serialize: (obj) => obj, deserialize: (obj) => obj }, output: { serialize: (obj) => obj, deserialize: (obj) => obj } }; function transformTRPCResponseItem(config, item) { if ("error" in item) return _objectSpread2(_objectSpread2({}, item), {}, { error: config.transformer.output.serialize(item.error) }); if ("data" in item.result) return _objectSpread2(_objectSpread2({}, item), {}, { result: _objectSpread2(_objectSpread2({}, item.result), {}, { data: config.transformer.output.serialize(item.result.data) }) }); return item; } /** * Serializes a response, or a list of them, with the router's output * transformer. Meant for custom adapters. **/ function transformTRPCResponse(config, itemOrItems) { return Array.isArray(itemOrItems) ? itemOrItems.map((item) => transformTRPCResponseItem(config, item)) : transformTRPCResponseItem(config, itemOrItems); } /** @internal */ function transformResultInner(response, transformer) { if ("error" in response) { const error = transformer.deserialize(response.error); return { ok: false, error: _objectSpread2(_objectSpread2({}, response), {}, { error }) }; } return { ok: true, result: _objectSpread2(_objectSpread2({}, response.result), (!response.result.type || response.result.type === "data") && { type: "data", data: transformer.deserialize(response.result.data) }) }; } var TransformResultError = class extends Error { constructor() { super("Unable to transform response from server"); } }; /** * Transforms and validates that the result is a valid TRPCResponse * @internal */ function transformResult(response, transformer) { let result; try { result = transformResultInner(response, transformer); } catch (_unused) { throw new TransformResultError(); } if (!result.ok && (!isObject(result.error.error) || typeof result.error.error["code"] !== "number")) throw new TransformResultError(); if (result.ok && !isObject(result.result)) throw new TransformResultError(); return result; } //#endregion //#region src/unstable-core-do-not-import/router.ts /** * @internal */ const lazyMarker = "lazyMarker"; function once(fn) { const uncalled = Symbol(); let result = uncalled; return () => { if (result === uncalled) result = fn(); return result; }; } /** * Loads a router on its first call instead of at startup, which can make * cold starts faster. Pass a function that imports the router, or a module * whose only export is the router. * @example * ```ts * const appRouter = router({ * slow: lazy(() => import('./slow.js').then((m) => m.slowRouter)), * }); * ``` * @see https://trpc.io/docs/server/merging-routers#lazy-load */ function lazy(importRouter) { async function resolve() { const mod = await importRouter(); if (isRouter(mod)) return mod; const routers = Object.values(mod); if (routers.length !== 1 || !isRouter(routers[0])) throw new Error("Invalid router module - either define exactly 1 export or return the router directly.\nExample: `lazy(() => import('./slow.js').then((m) => m.slowRouter))`"); return routers[0]; } resolve[lazyMarker] = true; return resolve; } function isLazy(input) { return typeof input === "function" && lazyMarker in input; } function isRouter(value) { return isObject(value) && isObject(value["_def"]) && "router" in value["_def"]; } const emptyRouter = { _ctx: null, _errorShape: null, _meta: null, queries: {}, mutations: {}, subscriptions: {}, errorFormatter: defaultFormatter, transformer: defaultTransformer }; /** * Reserved words that can't be used as router or procedure names */ const reservedWords = [ "then", "call", "apply" ]; function getRouterInput(router) { const input = Object.assign(emptyObject(), router._def.record); for (const loader of Object.values(router._def.lazy)) { let record = input; for (const key of loader.path) record = record[key] = Object.assign(emptyObject(), record[key]); record[loader.key] = loader.ref; } return input; } /** * @internal */ function createRouterFactory(config) { function createRouterInner(input) { const reservedWordsUsed = new Set(Object.keys(input).filter((v) => reservedWords.includes(v))); if (reservedWordsUsed.size > 0) throw new Error("Reserved words used in `router({})` call: " + Array.from(reservedWordsUsed).join(", ")); const procedures = emptyObject(); const lazy = emptyObject(); function createLazyLoader(opts) { return { ref: opts.ref, path: opts.path, key: opts.key, load: once(async () => { const router = await opts.ref(); const lazyPath = [...opts.path, opts.key]; const lazyKey = lazyPath.join("."); opts.aggregate[opts.key] = step(getRouterInput(router), lazyPath); delete lazy[lazyKey]; }) }; } const separator = config.pathSeparator; function step(from, path = []) { const aggregate = emptyObject(); for (const [key, item] of Object.entries(from !== null && from !== void 0 ? from : {})) { if (separator !== "." && key.includes(separator)) throw new Error(`Key "${[...path, key].join(".")}" contains the pathSeparator ${JSON.stringify(separator)}, so its URL would be ambiguous. Rename it or pick another pathSeparator.`); if (isLazy(item)) { lazy[[...path, key].join(".")] = createLazyLoader({ path, ref: item, key, aggregate }); continue; } if (isRouter(item)) { aggregate[key] = step(getRouterInput(item), [...path, key]); continue; } if (!isProcedure(item)) { aggregate[key] = step(item, [...path, key]); continue; } const newPath = [...path, key].join("."); if (procedures[newPath]) throw new Error(`Duplicate key: ${newPath}`); procedures[newPath] = item; aggregate[key] = item; } return aggregate; } const record = step(input); const _def = _objectSpread2(_objectSpread2({ _config: config, router: true, procedures, lazy }, emptyRouter), {}, { record }); return _objectSpread2(_objectSpread2({}, record), {}, { _def, createCaller: createCallerFactory()({ _def }) }); } return createRouterInner; } function isProcedure(procedureOrRouter) { return typeof procedureOrRouter === "function"; } /** * @internal */ async function getProcedureAtPath(router, path) { const { _def } = router; let procedure = _def.procedures[path]; while (!procedure) { const key = Object.keys(_def.lazy).find((key) => path === key || path.startsWith(key + ".")); if (!key) return null; await _def.lazy[key].load(); procedure = _def.procedures[path]; } return procedure; } /** * Calls the procedure at `path`, throwing `NOT_FOUND` if there's none of * that type. * @internal */ async function callProcedure(opts) { const { type, path } = opts; const proc = await getProcedureAtPath(opts.router, path); if (!proc || !isProcedure(proc) || proc._def.type !== type && !opts.allowMethodOverride) throw new TRPCError({ code: "NOT_FOUND", message: `No "${type}"-procedure on path "${path}"` }); /* istanbul ignore if -- @preserve */ if (proc._def.type !== type && opts.allowMethodOverride && proc._def.type === "subscription") throw new TRPCError({ code: "METHOD_NOT_SUPPORTED", message: `Method override is not supported for subscriptions` }); return proc(opts); } function createCallerFactory() { return function createCallerInner(router) { const { _def } = router; return function createCaller(ctxOrCallback, opts) { return createRecursiveProxy(async (innerOpts) => { const { path, args } = innerOpts; const fullPath = path.join("."); if (path.length === 1 && path[0] === "_def") return _def; const procedure = await getProcedureAtPath(router, fullPath); let ctx = void 0; try { if (!procedure) throw new TRPCError({ code: "NOT_FOUND", message: `No procedure found on path "${path}"` }); ctx = isFunction(ctxOrCallback) ? await Promise.resolve(ctxOrCallback()) : ctxOrCallback; return await procedure({ path: fullPath, getRawInput: async () => args[0], ctx, type: procedure._def.type, signal: opts === null || opts === void 0 ? void 0 : opts.signal, batchIndex: 0 }); } catch (cause) { var _opts$onError, _procedure$_def$type; opts === null || opts === void 0 || (_opts$onError = opts.onError) === null || _opts$onError === void 0 || _opts$onError.call(opts, { ctx, error: getTRPCErrorFromUnknown(cause), input: args[0], path: fullPath, type: (_procedure$_def$type = procedure === null || procedure === void 0 ? void 0 : procedure._def.type) !== null && _procedure$_def$type !== void 0 ? _procedure$_def$type : "unknown" }); throw cause; } }); }; }; } function mergeRouters(...routerList) { var _routerList$, _routerList$2; const record = mergeWithoutOverrides({}, ...[...new Set(routerList)].map((r) => getRouterInput(r))); return createRouterFactory({ errorFormatter: routerList.reduce((currentErrorFormatter, nextRouter) => { if (nextRouter._def._config.errorFormatter && nextRouter._def._config.errorFormatter !== defaultFormatter) { if (currentErrorFormatter !== defaultFormatter && currentErrorFormatter !== nextRouter._def._config.errorFormatter) throw new Error("You seem to have several error formatters"); return nextRouter._def._config.errorFormatter; } return currentErrorFormatter; }, defaultFormatter), transformer: routerList.reduce((prev, current) => { if (current._def._config.transformer && current._def._config.transformer !== defaultTransformer) { if (prev !== defaultTransformer && prev !== current._def._config.transformer) throw new Error("You seem to have several transformers"); return current._def._config.transformer; } return prev; }, defaultTransformer), pathSeparator: routerList.reduce((prev, current) => { const next = current._def._config.pathSeparator; if (next === ".") return prev; if (prev !== "." && prev !== next) throw new Error("You seem to have several pathSeparators"); return next; }, "."), isDev: routerList.every((r) => r._def._config.isDev), allowOutsideOfServer: routerList.every((r) => r._def._config.allowOutsideOfServer), isServer: routerList.every((r) => r._def._config.isServer), $types: (_routerList$ = routerList[0]) === null || _routerList$ === void 0 ? void 0 : _routerList$._def._config.$types, sse: (_routerList$2 = routerList[0]) === null || _routerList$2 === void 0 ? void 0 : _routerList$2._def._config.sse })(record); } //#endregion //#region src/unstable-core-do-not-import/http/pathSeparator.ts /** * Applies the `'.'` default to a user-given `pathSeparator` option. Call it * once, where the option is read. * @internal */ function resolvePathSeparator(value) { return value !== null && value !== void 0 ? value : "."; } /** * `post.byId` → `post~byId`, for building URLs. * @internal */ function procedurePathToURLPath(path, separator) { if (separator === ".") return path; return path.split(".").join(separator); } /** * `post~byId` → `post.byId`, for reading URLs. Dotted paths still resolve, * so clients can move to the separator after the server does. * @internal */ function urlPathToProcedurePath(path, separator) { if (separator === ".") return path; return path.split(separator).join("."); } //#endregion //#region \0@oxc-project+runtime@0.149.0/helpers/esm/OverloadYield.js function _OverloadYield(e, d) { this.v = e, this.k = d; } //#endregion //#region \0@oxc-project+runtime@0.149.0/helpers/esm/wrapAsyncGenerator.js function _wrapAsyncGenerator(e) { return function() { return new AsyncGenerator(e.apply(this, arguments)); }; } function AsyncGenerator(e) { var r, t; function resume(r, t) { try { var n = e[r](t), o = n.value, u = o instanceof _OverloadYield; Promise.resolve(u ? o.v : o).then(function(t) { if (u) { var i = "return" === r ? "return" : "next"; if (!o.k || t.done) return resume(i, t); t = e[i](t).value; } settle(n.done ? "return" : "normal", t); }, function(e) { resume("throw", e); }); } catch (e) { settle("throw", e); } } function settle(e, n) { switch (e) { case "return": r.resolve({ value: n, done: !0 }); break; case "throw": r.reject(n); break; default: r.resolve({ value: n, done: !1 }); } (r = r.next) ? resume(r.key, r.arg) : t = null; } this._invoke = function(e, n) { return new Promise(function(o, u) { var i = { key: e, arg: n, resolve: o, reject: u, next: null }; t ? t = t.next = i : (r = t = i, resume(e, n)); }); }, "function" != typeof e["return"] && (this["return"] = void 0); } AsyncGenerator.prototype["function" == typeof Symbol && Symbol.asyncIterator || "@@asyncIterator"] = function() { return this; }, AsyncGenerator.prototype.next = function(e) { return this._invoke("next", e); }, AsyncGenerator.prototype["throw"] = function(e) { return this._invoke("throw", e); }, AsyncGenerator.prototype["return"] = function(e) { return this._invoke("return", e); }; //#endregion //#region \0@oxc-project+runtime@0.149.0/helpers/esm/asyncIterator.js function _asyncIterator(r) { var n, t, o, e = 2; for ("undefined" != typeof Symbol && (t = Symbol.asyncIterator, o = Symbol.iterator); e--;) { if (t && null != (n = r[t])) return n.call(r); if (o && null != (n = r[o])) return new AsyncFromSyncIterator(n.call(r)); t = "@@asyncIterator", o = "@@iterator"; } throw new TypeError("Object is not async iterable"); } function AsyncFromSyncIterator(r) { function AsyncFromSyncIteratorContinuation(r) { if (Object(r) !== r) return Promise.reject(/* @__PURE__ */ new TypeError(r + " is not an object.")); var n = r.done; return Promise.resolve(r.value).then(function(r) { return { value: r, done: n }; }); } return AsyncFromSyncIterator = function AsyncFromSyncIterator(r) { this.s = r, this.n = r.next; }, AsyncFromSyncIterator.prototype = { s: null, n: null, next: function next() { return AsyncFromSyncIteratorContinuation(this.n.apply(this.s, arguments)); }, "return": function _return(r) { var n = this.s["return"]; return void 0 === n ? Promise.resolve({ value: r, done: !0 }) : AsyncFromSyncIteratorContinuation(n.apply(this.s, arguments)); }, "throw": function _throw(r) { var n = this.s["return"]; return void 0 === n ? Promise.reject(r) : AsyncFromSyncIteratorContinuation(n.apply(this.s, arguments)); } }, new AsyncFromSyncIterator(r); } //#endregion //#region src/unstable-core-do-not-import/stream/tracked.ts const trackedSymbol = Symbol(); /** * Wraps an event with an id, so a client can resume from it. * @deprecated Use `tracked(id, data)` instead. */ function sse(event) { return tracked(event.id, event.data); } /** Whether a value was made by `tracked()`. */ function isTrackedEnvelope(value) { return Array.isArray(value) && value[2] === trackedSymbol; } /** * Gives a subscription event an id. When the connection drops, the client * reconnects with the last id it got, as `input.lastEventId`, so the * subscription can resume from there. The id can't be empty. * @example * ```ts * yield tracked(post.id, post); * ``` * @see https://trpc.io/docs/server/subscriptions#tracked */ function tracked(id, data) { if (id === "") throw new Error("`id` must not be an empty string as empty string is the same as not setting the id at all"); if (/[\0\n\r]/.test(id)) throw new Error("`id` must not contain line breaks or null characters as they are not allowed in a Server-Sent Events id"); return [ id, data, trackedSymbol ]; } //#endregion //#region \0@oxc-project+runtime@0.149.0/helpers/esm/asyncGeneratorDelegate.js function _asyncGeneratorDelegate(t) { var e = {}, n = !1; function pump(e, r) { return n = !0, r = new Promise(function(n) { n(t[e](r)); }), { done: !1, value: new _OverloadYield(r, 1) }; } return e["undefined" != typeof Symbol && Symbol.iterator || "@@iterator"] = function() { return this; }, e.next = function(t) { return n ? (n = !1, t) : pump("next", t); }, "function" == typeof t["throw"] && (e["throw"] = function(t) { if (n) throw n = !1, t; return pump("throw", t); }), "function" == typeof t["return"] && (e["return"] = function(t) { return n ? (n = !1, t) : pump("return", t); }), e; } //#endregion export { getTRPCErrorFromUnknown as C, getCauseFromUnknown as S, defaultTransformer as _, _asyncIterator as a, transformTRPCResponse as b, procedurePathToURLPath as c, callProcedure as d, createCallerFactory as f, mergeRouters as g, lazy as h, tracked as i, resolvePathSeparator as l, getProcedureAtPath as m, isTrackedEnvelope as n, _wrapAsyncGenerator as o, createRouterFactory as p, sse as r, _OverloadYield as s, _asyncGeneratorDelegate as t, urlPathToProcedurePath as u, getDataTransformer as v, TRPCError as x, transformResult as y }; //# sourceMappingURL=asyncGeneratorDelegate-JWx0LJUD.mjs.map