@trpc/server 11.19.0 → 11.21.1-canary.20.10e2ef98f
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/adapters/aws-lambda/index.d.ts +1 -0
- package/adapters/aws-lambda/index.js +1 -0
- package/adapters/express/index.d.ts +1 -0
- package/adapters/express/index.js +1 -0
- package/adapters/fastify/index.d.ts +1 -0
- package/adapters/fastify/index.js +1 -0
- package/adapters/fetch/index.d.ts +1 -0
- package/adapters/fetch/index.js +1 -0
- package/adapters/next/index.d.ts +1 -0
- package/adapters/next/index.js +1 -0
- package/adapters/next-app-dir/index.d.ts +1 -0
- package/adapters/next-app-dir/index.js +1 -0
- package/adapters/node-http/content-type/form-data/index.d.ts +1 -0
- package/adapters/node-http/content-type/form-data/index.js +1 -0
- package/adapters/node-http/content-type/json/index.d.ts +1 -0
- package/adapters/node-http/content-type/json/index.js +1 -0
- package/adapters/node-http/index.d.ts +1 -0
- package/adapters/node-http/index.js +1 -0
- package/adapters/standalone/index.d.ts +1 -0
- package/adapters/standalone/index.js +1 -0
- package/adapters/ws/index.d.ts +1 -0
- package/adapters/ws/index.js +1 -0
- package/dist/adapters/aws-lambda/index.cjs +2 -2
- package/dist/adapters/aws-lambda/index.d.cts +1 -1
- package/dist/adapters/aws-lambda/index.d.mts +1 -1
- package/dist/adapters/aws-lambda/index.mjs +2 -2
- package/dist/adapters/express.cjs +3 -3
- package/dist/adapters/express.d.cts +2 -2
- package/dist/adapters/express.d.mts +2 -2
- package/dist/adapters/express.mjs +3 -3
- package/dist/adapters/fastify/index.cjs +4 -4
- package/dist/adapters/fastify/index.d.cts +2 -2
- package/dist/adapters/fastify/index.d.mts +2 -2
- package/dist/adapters/fastify/index.mjs +4 -4
- package/dist/adapters/fetch/index.cjs +2 -2
- package/dist/adapters/fetch/index.d.cts +1 -1
- package/dist/adapters/fetch/index.d.mts +1 -1
- package/dist/adapters/fetch/index.mjs +2 -2
- package/dist/adapters/next-app-dir.cjs +7 -7
- package/dist/adapters/next-app-dir.d.cts +1 -1
- package/dist/adapters/next-app-dir.d.mts +1 -1
- package/dist/adapters/next-app-dir.mjs +2 -2
- package/dist/adapters/next.cjs +5 -5
- package/dist/adapters/next.d.cts +2 -2
- package/dist/adapters/next.d.mts +2 -2
- package/dist/adapters/next.mjs +4 -4
- package/dist/adapters/node-http/index.cjs +1 -1
- package/dist/adapters/node-http/index.d.cts +1 -1
- package/dist/adapters/node-http/index.d.mts +1 -1
- package/dist/adapters/node-http/index.mjs +1 -1
- package/dist/adapters/standalone.cjs +3 -3
- package/dist/adapters/standalone.d.cts +2 -2
- package/dist/adapters/standalone.d.mts +2 -2
- package/dist/adapters/standalone.mjs +3 -3
- package/dist/adapters/ws.cjs +1 -1
- package/dist/adapters/ws.d.cts +2 -2
- package/dist/adapters/ws.d.mts +2 -2
- package/dist/adapters/ws.mjs +1 -1
- package/dist/{tracked-BQJb0ANk.cjs → asyncGeneratorDelegate-D2tFgl_z.cjs} +167 -17
- package/dist/{tracked-D4jU_Hb3.mjs → asyncGeneratorDelegate-mPyp1u6d.mjs} +141 -9
- package/dist/asyncGeneratorDelegate-mPyp1u6d.mjs.map +1 -0
- package/dist/{codes-C6ZIq69A.cjs → codes-BwD4QurF.cjs} +9 -0
- package/dist/{codes-D5Ya6_Bi.mjs → codes-D6C_OiJy.mjs} +5 -2
- package/dist/codes-D6C_OiJy.mjs.map +1 -0
- package/dist/{getErrorShape-B0JBUs-i.mjs → getErrorShape-BziUKLM_.mjs} +52 -14
- package/dist/getErrorShape-BziUKLM_.mjs.map +1 -0
- package/dist/{getErrorShape-DeIapApr.cjs → getErrorShape-CVxLwJgN.cjs} +80 -12
- package/dist/http.cjs +2 -2
- package/dist/http.d.cts +1 -1
- package/dist/http.d.mts +1 -1
- package/dist/http.mjs +2 -2
- package/dist/{index-_jAhoJQ7.d.mts → index-BDZDS1SD.d.mts} +2 -2
- package/dist/{index-BHatz_Pu.d.cts.map → index-BDZDS1SD.d.mts.map} +1 -1
- package/dist/{index-BHatz_Pu.d.cts → index-BzKrDvzg.d.cts} +2 -2
- package/dist/{index-_jAhoJQ7.d.mts.map → index-BzKrDvzg.d.cts.map} +1 -1
- package/dist/index.cjs +12 -12
- package/dist/index.d.cts +2 -2
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +2 -2
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +3 -3
- package/dist/{initTRPC-B7UdX-c3.cjs → initTRPC-DLNeKv0z.cjs} +114 -26
- package/dist/{initTRPC-B259os3T.mjs → initTRPC-DpOypWK_.mjs} +95 -19
- package/dist/initTRPC-DpOypWK_.mjs.map +1 -0
- package/dist/{node-http-BUlb5EdB.mjs → node-http-B_z10Yky.mjs} +5 -5
- package/dist/{node-http-BUlb5EdB.mjs.map → node-http-B_z10Yky.mjs.map} +1 -1
- package/dist/{node-http-CikCqjt6.cjs → node-http-Bti3aBT6.cjs} +9 -9
- package/dist/{parseTRPCMessage-MJWDg1vX.mjs → parseTRPCMessage-CSh-CVPr.mjs} +2 -2
- package/dist/{parseTRPCMessage-MJWDg1vX.mjs.map → parseTRPCMessage-CSh-CVPr.mjs.map} +1 -1
- package/dist/{parseTRPCMessage-BxAIUx49.cjs → parseTRPCMessage-RJS87G_t.cjs} +1 -1
- package/dist/{resolveResponse-JtMyT9TQ.mjs → resolveResponse-CrB_9MSD.mjs} +43 -179
- package/dist/resolveResponse-CrB_9MSD.mjs.map +1 -0
- package/dist/{resolveResponse-DLpzHrPG.cjs → resolveResponse-D5JAuwvU.cjs} +90 -226
- package/dist/rpc.cjs +2 -2
- package/dist/rpc.d.cts +1 -1
- package/dist/rpc.d.mts +1 -1
- package/dist/rpc.mjs +2 -2
- package/dist/shared.cjs +1 -1
- package/dist/shared.d.cts +1 -1
- package/dist/shared.d.mts +1 -1
- package/dist/shared.mjs +1 -1
- package/dist/{unstable-core-do-not-import-BK_OKrtM.d.mts → unstable-core-do-not-import-JE3NCpqt.d.mts} +707 -636
- package/dist/unstable-core-do-not-import-JE3NCpqt.d.mts.map +1 -0
- package/dist/{unstable-core-do-not-import-B9ZnrQAU.d.cts → unstable-core-do-not-import-Jynlfuqc.d.cts} +707 -636
- package/dist/unstable-core-do-not-import-Jynlfuqc.d.cts.map +1 -0
- package/dist/unstable-core-do-not-import.cjs +30 -23
- package/dist/unstable-core-do-not-import.d.cts +2 -2
- package/dist/unstable-core-do-not-import.d.mts +2 -2
- package/dist/unstable-core-do-not-import.mjs +7 -7
- package/dist/{ws-BMSSVFiW.cjs → ws-BgBeYgGS.cjs} +22 -22
- package/dist/{ws-C7ZOJJeA.mjs → ws-CNjkWAs9.mjs} +7 -7
- package/dist/{ws-C7ZOJJeA.mjs.map → ws-CNjkWAs9.mjs.map} +1 -1
- package/http/index.d.ts +1 -0
- package/http/index.js +1 -0
- package/observable/index.d.ts +1 -0
- package/observable/index.js +1 -0
- package/package.json +14 -14
- package/rpc/index.d.ts +1 -0
- package/rpc/index.js +1 -0
- package/shared/index.d.ts +1 -0
- package/shared/index.js +1 -0
- package/src/@trpc/server/index.ts +1 -0
- package/src/unstable-core-do-not-import/clientish/inference.ts +12 -0
- package/src/unstable-core-do-not-import/error/formatter.ts +90 -3
- package/src/unstable-core-do-not-import/error/getErrorShape.ts +8 -17
- package/src/unstable-core-do-not-import/initTRPC.ts +10 -7
- package/src/unstable-core-do-not-import/middleware.ts +93 -2
- package/src/unstable-core-do-not-import/procedure.ts +2 -0
- package/src/unstable-core-do-not-import/procedureBuilder.ts +79 -13
- package/src/unstable-core-do-not-import/rootConfig.ts +8 -0
- package/src/unstable-core-do-not-import/stream/jsonl.ts +41 -33
- package/src/unstable-core-do-not-import/utils.ts +4 -0
- package/unstable-core-do-not-import/index.d.ts +1 -0
- package/unstable-core-do-not-import/index.js +1 -0
- package/dist/codes-D5Ya6_Bi.mjs.map +0 -1
- package/dist/getErrorShape-B0JBUs-i.mjs.map +0 -1
- package/dist/initTRPC-B259os3T.mjs.map +0 -1
- package/dist/resolveResponse-JtMyT9TQ.mjs.map +0 -1
- package/dist/tracked-D4jU_Hb3.mjs.map +0 -1
- package/dist/unstable-core-do-not-import-B9ZnrQAU.d.cts.map +0 -1
- package/dist/unstable-core-do-not-import-BK_OKrtM.d.mts.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ws-C7ZOJJeA.mjs","names":["callTRPCProcedure"],"sources":["../src/adapters/wsEncoder.ts","../src/adapters/ws.ts"],"sourcesContent":["/**\n * Encoder for WebSocket wire format.\n * Encodes outgoing messages and decodes incoming messages.\n *\n * @example\n * ```ts\n * const customEncoder: Encoder = {\n * encode: (data) => myFormat.stringify(data),\n * decode: (data) => myFormat.parse(data),\n * };\n * ```\n */\nexport interface Encoder {\n /** Encode data for transmission over the wire */\n encode(data: unknown): string | Uint8Array<ArrayBuffer>;\n /** Decode data received from the wire */\n decode(data: string | ArrayBuffer | Uint8Array): unknown;\n}\n\n/**\n * Default JSON encoder - used when no encoder is specified.\n * This maintains backwards compatibility with existing behavior.\n */\nexport const jsonEncoder: Encoder = {\n encode: (data) => JSON.stringify(data),\n decode: (data) => {\n if (typeof data !== 'string') {\n throw new Error(\n 'jsonEncoder received binary data. JSON uses text frames. ' +\n 'Use a binary encoder for binary data.',\n );\n }\n return JSON.parse(data);\n },\n};\n","import type { IncomingMessage } from 'http';\nimport type ws from 'ws';\nimport type {\n AnyRouter,\n CreateContextCallback,\n inferRouterContext,\n} from '../@trpc/server';\nimport {\n callTRPCProcedure,\n getErrorShape,\n getTRPCErrorFromUnknown,\n transformTRPCResponse,\n TRPCError,\n} from '../@trpc/server';\nimport type { TRPCRequestInfo } from '../@trpc/server/http';\nimport { type BaseHandlerOptions } from '../@trpc/server/http';\nimport { parseTRPCMessage } from '../@trpc/server/rpc';\n// @trpc/server/rpc\nimport type {\n TRPCClientOutgoingMessage,\n TRPCConnectionParamsMessage,\n TRPCReconnectNotification,\n TRPCResponseMessage,\n TRPCResultMessage,\n} from '../@trpc/server/rpc';\nimport { parseConnectionParamsFromUnknown } from '../http';\nimport { isObservable, observableToAsyncIterable } from '../observable';\n// eslint-disable-next-line no-restricted-imports\nimport {\n isAsyncIterable,\n isObject,\n isTrackedEnvelope,\n run,\n type MaybePromise,\n} from '../unstable-core-do-not-import';\n// eslint-disable-next-line no-restricted-imports\nimport type { Result } from '../unstable-core-do-not-import';\n// eslint-disable-next-line no-restricted-imports\nimport { iteratorResource } from '../unstable-core-do-not-import/stream/utils/asyncIterable';\nimport { Unpromise } from '../vendor/unpromise';\nimport { createURL, type NodeHTTPCreateContextFnOptions } from './node-http';\nimport type { Encoder } from './wsEncoder';\nimport { jsonEncoder } from './wsEncoder';\n\n/**\n * Importing ws causes a build error\n * @see https://github.com/trpc/trpc/pull/5279\n */\nconst WEBSOCKET_OPEN = 1; /* ws.WebSocket.OPEN */\n\n/**\n * @public\n */\nexport type CreateWSSContextFnOptions = NodeHTTPCreateContextFnOptions<\n IncomingMessage,\n ws.WebSocket\n>;\n\n/**\n * @public\n */\nexport type CreateWSSContextFn<TRouter extends AnyRouter> = (\n opts: CreateWSSContextFnOptions,\n) => MaybePromise<inferRouterContext<TRouter>>;\n\nexport type WSConnectionHandlerOptions<TRouter extends AnyRouter> =\n BaseHandlerOptions<TRouter, IncomingMessage> &\n CreateContextCallback<\n inferRouterContext<TRouter>,\n CreateWSSContextFn<TRouter>\n >;\n\n/**\n * Web socket server handler\n */\nexport type WSSHandlerOptions<TRouter extends AnyRouter> =\n WSConnectionHandlerOptions<TRouter> & {\n wss: ws.WebSocketServer;\n prefix?: string;\n keepAlive?: {\n /**\n * Enable heartbeat messages\n * @default false\n */\n enabled: boolean;\n /**\n * Heartbeat interval in milliseconds\n * @default 30_000\n */\n pingMs?: number;\n /**\n * Terminate the WebSocket if no pong is received after this many milliseconds\n * @default 5_000\n */\n pongWaitMs?: number;\n };\n /**\n * Disable responding to ping messages from the client\n * **Not recommended** - this is mainly used for testing\n * @default false\n */\n dangerouslyDisablePong?: boolean;\n /**\n * Custom encoder for wire encoding (e.g. custom binary formats)\n * @default jsonEncoder\n */\n experimental_encoder?: Encoder;\n };\n\nexport function getWSConnectionHandler<TRouter extends AnyRouter>(\n opts: WSSHandlerOptions<TRouter>,\n) {\n const { createContext, router } = opts;\n const { transformer } = router._def._config;\n const encoder = opts.experimental_encoder ?? jsonEncoder;\n\n return (client: ws.WebSocket, req: IncomingMessage) => {\n type Context = inferRouterContext<TRouter>;\n type ContextResult = Result<Context>;\n\n const clientSubscriptions = new Map<number | string, AbortController>();\n const abortController = new AbortController();\n\n if (opts.keepAlive?.enabled) {\n const { pingMs, pongWaitMs } = opts.keepAlive;\n handleKeepAlive(client, pingMs, pongWaitMs);\n }\n\n function respond(untransformedJSON: TRPCResponseMessage) {\n client.send(\n encoder.encode(\n transformTRPCResponse(router._def._config, untransformedJSON),\n ),\n );\n }\n\n async function createCtxPromise(\n getConnectionParams: () => TRPCRequestInfo['connectionParams'],\n ): Promise<ContextResult> {\n try {\n return await run(async (): Promise<ContextResult> => {\n ctx = await createContext?.({\n req,\n res: client,\n info: {\n connectionParams: getConnectionParams(),\n calls: [],\n isBatchCall: false,\n accept: null,\n type: 'unknown',\n signal: abortController.signal,\n url: null,\n },\n });\n\n return {\n ok: true,\n value: ctx,\n };\n });\n } catch (cause) {\n const error = getTRPCErrorFromUnknown(cause);\n opts.onError?.({\n error,\n path: undefined,\n type: 'unknown',\n ctx,\n req,\n input: undefined,\n });\n respond({\n id: null,\n error: getErrorShape({\n config: router._def._config,\n error,\n type: 'unknown',\n path: undefined,\n input: undefined,\n ctx,\n }),\n });\n\n // close in next tick\n (globalThis.setImmediate ?? globalThis.setTimeout)(() => {\n client.close();\n });\n return {\n ok: false,\n error,\n };\n }\n }\n\n let ctx: Context | undefined = undefined;\n\n /**\n * promise for initializing the context\n *\n * - the context promise will be created immediately on connection if no connectionParams are expected\n * - if connection params are expected, they will be created once received\n */\n let ctxPromise =\n createURL(req).searchParams.get('connectionParams') === '1'\n ? null\n : createCtxPromise(() => null);\n\n function handleRequest(msg: TRPCClientOutgoingMessage, batchIndex: number) {\n const { id, jsonrpc } = msg;\n\n if (id === null) {\n const error = getTRPCErrorFromUnknown(\n new TRPCError({\n code: 'PARSE_ERROR',\n message: '`id` is required',\n }),\n );\n opts.onError?.({\n error,\n path: undefined,\n type: 'unknown',\n ctx,\n req,\n input: undefined,\n });\n respond({\n id,\n jsonrpc,\n error: getErrorShape({\n config: router._def._config,\n error,\n type: 'unknown',\n path: undefined,\n input: undefined,\n ctx,\n }),\n });\n return;\n }\n if (msg.method === 'subscription.stop') {\n clientSubscriptions.get(id)?.abort();\n return;\n }\n const { path, lastEventId } = msg.params;\n let { input } = msg.params;\n const type = msg.method;\n\n if (lastEventId !== undefined) {\n if (isObject(input)) {\n input = {\n ...input,\n lastEventId: lastEventId,\n };\n } else {\n input ??= {\n lastEventId: lastEventId,\n };\n }\n }\n run(async () => {\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n const res = await ctxPromise!; // asserts context has been set\n if (!res.ok) {\n throw res.error;\n }\n\n const abortController = new AbortController();\n const result = await callTRPCProcedure({\n router,\n path,\n getRawInput: async () => input,\n ctx,\n type,\n signal: abortController.signal,\n batchIndex,\n });\n\n const isIterableResult =\n isAsyncIterable(result) || isObservable(result);\n\n if (type !== 'subscription') {\n if (isIterableResult) {\n throw new TRPCError({\n code: 'UNSUPPORTED_MEDIA_TYPE',\n message: `Cannot return an async iterable or observable from a ${type} procedure with WebSockets`,\n });\n }\n // send the value as data if the method is not a subscription\n respond({\n id,\n jsonrpc,\n result: {\n type: 'data',\n data: result,\n },\n });\n return;\n }\n\n if (!isIterableResult) {\n throw new TRPCError({\n message: `Subscription ${path} did not return an observable or a AsyncGenerator`,\n code: 'INTERNAL_SERVER_ERROR',\n });\n }\n\n /* istanbul ignore next -- @preserve */\n if (client.readyState !== WEBSOCKET_OPEN) {\n // if the client got disconnected whilst initializing the subscription\n // no need to send stopped message if the client is disconnected\n\n return;\n }\n\n /* istanbul ignore next -- @preserve */\n if (clientSubscriptions.has(id)) {\n // duplicate request ids for client\n\n throw new TRPCError({\n message: `Duplicate id ${id}`,\n code: 'BAD_REQUEST',\n });\n }\n\n const iterable = isObservable(result)\n ? observableToAsyncIterable(result, abortController.signal)\n : result;\n\n run(async () => {\n await using iterator = iteratorResource(iterable);\n\n const abortPromise = new Promise<'abort'>((resolve) => {\n abortController.signal.onabort = () => resolve('abort');\n });\n // We need those declarations outside the loop for garbage collection reasons. If they\n // were declared inside, they would not be freed until the next value is present.\n let next:\n | null\n | TRPCError\n | Awaited<\n typeof abortPromise | ReturnType<(typeof iterator)['next']>\n >;\n let result: null | TRPCResultMessage<unknown>['result'];\n\n while (true) {\n next = await Unpromise.race([\n iterator.next().catch(getTRPCErrorFromUnknown),\n abortPromise,\n ]);\n\n if (next === 'abort') {\n await iterator.return?.();\n break;\n }\n if (next instanceof Error) {\n const error = getTRPCErrorFromUnknown(next);\n opts.onError?.({ error, path, type, ctx, req, input });\n respond({\n id,\n jsonrpc,\n error: getErrorShape({\n config: router._def._config,\n error,\n type,\n path,\n input,\n ctx,\n }),\n });\n break;\n }\n if (next.done) {\n break;\n }\n\n result = {\n type: 'data',\n data: next.value,\n };\n\n if (isTrackedEnvelope(next.value)) {\n const [id, data] = next.value;\n result.id = id;\n result.data = {\n id,\n data,\n };\n }\n\n respond({\n id,\n jsonrpc,\n result,\n });\n\n // free up references for garbage collection\n next = null;\n result = null;\n }\n\n respond({\n id,\n jsonrpc,\n result: {\n type: 'stopped',\n },\n });\n clientSubscriptions.delete(id);\n }).catch((cause) => {\n clientSubscriptions.delete(id);\n const error = getTRPCErrorFromUnknown(cause);\n opts.onError?.({ error, path, type, ctx, req, input });\n respond({\n id,\n jsonrpc,\n error: getErrorShape({\n config: router._def._config,\n error,\n type,\n path,\n input,\n ctx,\n }),\n });\n abortController.abort();\n });\n clientSubscriptions.set(id, abortController);\n\n respond({\n id,\n jsonrpc,\n result: {\n type: 'started',\n },\n });\n }).catch((cause) => {\n // procedure threw an error\n const error = getTRPCErrorFromUnknown(cause);\n opts.onError?.({ error, path, type, ctx, req, input });\n respond({\n id,\n jsonrpc,\n error: getErrorShape({\n config: router._def._config,\n error,\n type,\n path,\n input,\n ctx,\n }),\n });\n });\n }\n client.on('message', (rawData, isBinary) => {\n // Handle PING/PONG as text regardless of encoder\n if (!isBinary) {\n // eslint-disable-next-line @typescript-eslint/no-base-to-string\n const msgStr = rawData.toString();\n if (msgStr === 'PONG') {\n return;\n }\n if (msgStr === 'PING') {\n if (!opts.dangerouslyDisablePong) {\n client.send('PONG');\n }\n return;\n }\n }\n\n // Convert rawData to a format our encoder accepts\n // ws gives us Buffer for both text and binary frames\n if (!Buffer.isBuffer(rawData)) {\n const error = new TRPCError({\n code: 'UNPROCESSABLE_CONTENT',\n message: 'Unexpected WebSocket message format',\n });\n respond({\n id: null,\n error: getErrorShape({\n config: router._def._config,\n error,\n type: 'unknown',\n path: undefined,\n input: undefined,\n ctx,\n }),\n });\n return;\n }\n const data: string | Uint8Array = isBinary\n ? rawData\n : rawData.toString('utf8');\n\n if (!ctxPromise) {\n // If the ctxPromise wasn't created immediately, we're expecting the first message to be a TRPCConnectionParamsMessage\n ctxPromise = createCtxPromise(() => {\n let msg;\n try {\n msg = encoder.decode(data) as TRPCConnectionParamsMessage;\n\n if (!isObject(msg)) {\n throw new Error('Message was not an object');\n }\n } catch (cause) {\n throw new TRPCError({\n code: 'PARSE_ERROR',\n message: `Malformed TRPCConnectionParamsMessage`,\n cause,\n });\n }\n\n const connectionParams = parseConnectionParamsFromUnknown(msg.data);\n\n return connectionParams;\n });\n return;\n }\n\n const parsedMsgs = run(() => {\n try {\n const msgJSON: unknown = encoder.decode(data);\n const msgs: unknown[] = Array.isArray(msgJSON) ? msgJSON : [msgJSON];\n\n return msgs.map((raw) => parseTRPCMessage(raw, transformer));\n } catch (cause) {\n const error = new TRPCError({\n code: 'PARSE_ERROR',\n cause,\n });\n\n respond({\n id: null,\n error: getErrorShape({\n config: router._def._config,\n error,\n type: 'unknown',\n path: undefined,\n input: undefined,\n ctx,\n }),\n });\n\n return [];\n }\n });\n\n parsedMsgs.map((msg, index) => handleRequest(msg, index));\n });\n\n // WebSocket errors should be handled, as otherwise unhandled exceptions will crash Node.js.\n // This line was introduced after the following error brought down production systems:\n // \"RangeError: Invalid WebSocket frame: RSV2 and RSV3 must be clear\"\n // Here is the relevant discussion: https://github.com/websockets/ws/issues/1354#issuecomment-774616962\n client.on('error', (cause) => {\n opts.onError?.({\n ctx,\n error: getTRPCErrorFromUnknown(cause),\n input: undefined,\n path: undefined,\n type: 'unknown',\n req,\n });\n });\n\n client.once('close', () => {\n for (const sub of clientSubscriptions.values()) {\n sub.abort();\n }\n clientSubscriptions.clear();\n abortController.abort();\n });\n };\n}\n\n/**\n * Handle WebSocket keep-alive messages\n */\nexport function handleKeepAlive(\n client: ws.WebSocket,\n pingMs = 30_000,\n pongWaitMs = 5_000,\n) {\n let timeout: NodeJS.Timeout | undefined = undefined;\n let ping: NodeJS.Timeout | undefined = undefined;\n\n const schedulePing = () => {\n const scheduleTimeout = () => {\n timeout = setTimeout(() => {\n client.terminate();\n }, pongWaitMs);\n };\n ping = setTimeout(() => {\n client.send('PING');\n\n scheduleTimeout();\n }, pingMs);\n };\n\n const onMessage = () => {\n clearTimeout(ping);\n clearTimeout(timeout);\n\n schedulePing();\n };\n\n client.on('message', onMessage);\n\n client.on('close', () => {\n clearTimeout(ping);\n clearTimeout(timeout);\n });\n\n schedulePing();\n}\n\nexport function applyWSSHandler<TRouter extends AnyRouter>(\n opts: WSSHandlerOptions<TRouter>,\n) {\n const encoder = opts.experimental_encoder ?? jsonEncoder;\n const onConnection = getWSConnectionHandler(opts);\n opts.wss.on('connection', (client, req) => {\n if (opts.prefix && !req.url?.startsWith(opts.prefix)) {\n return;\n }\n\n onConnection(client, req);\n });\n\n return {\n broadcastReconnectNotification: () => {\n const response: TRPCReconnectNotification = {\n id: null,\n method: 'reconnect',\n };\n const data = encoder.encode(response);\n for (const client of opts.wss.clients) {\n if (client.readyState === WEBSOCKET_OPEN) {\n client.send(data);\n }\n }\n },\n };\n}\n\nexport type { Encoder } from './wsEncoder';\nexport { jsonEncoder } from './wsEncoder';\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ws-CNjkWAs9.mjs","names":["callTRPCProcedure"],"sources":["../src/adapters/wsEncoder.ts","../src/adapters/ws.ts"],"sourcesContent":["/**\n * Encoder for WebSocket wire format.\n * Encodes outgoing messages and decodes incoming messages.\n *\n * @example\n * ```ts\n * const customEncoder: Encoder = {\n * encode: (data) => myFormat.stringify(data),\n * decode: (data) => myFormat.parse(data),\n * };\n * ```\n */\nexport interface Encoder {\n /** Encode data for transmission over the wire */\n encode(data: unknown): string | Uint8Array<ArrayBuffer>;\n /** Decode data received from the wire */\n decode(data: string | ArrayBuffer | Uint8Array): unknown;\n}\n\n/**\n * Default JSON encoder - used when no encoder is specified.\n * This maintains backwards compatibility with existing behavior.\n */\nexport const jsonEncoder: Encoder = {\n encode: (data) => JSON.stringify(data),\n decode: (data) => {\n if (typeof data !== 'string') {\n throw new Error(\n 'jsonEncoder received binary data. JSON uses text frames. ' +\n 'Use a binary encoder for binary data.',\n );\n }\n return JSON.parse(data);\n },\n};\n","import type { IncomingMessage } from 'http';\nimport type ws from 'ws';\nimport type {\n AnyRouter,\n CreateContextCallback,\n inferRouterContext,\n} from '../@trpc/server';\nimport {\n callTRPCProcedure,\n getErrorShape,\n getTRPCErrorFromUnknown,\n transformTRPCResponse,\n TRPCError,\n} from '../@trpc/server';\nimport type { TRPCRequestInfo } from '../@trpc/server/http';\nimport { type BaseHandlerOptions } from '../@trpc/server/http';\nimport { parseTRPCMessage } from '../@trpc/server/rpc';\n// @trpc/server/rpc\nimport type {\n TRPCClientOutgoingMessage,\n TRPCConnectionParamsMessage,\n TRPCReconnectNotification,\n TRPCResponseMessage,\n TRPCResultMessage,\n} from '../@trpc/server/rpc';\nimport { parseConnectionParamsFromUnknown } from '../http';\nimport { isObservable, observableToAsyncIterable } from '../observable';\n// eslint-disable-next-line no-restricted-imports\nimport {\n isAsyncIterable,\n isObject,\n isTrackedEnvelope,\n run,\n type MaybePromise,\n} from '../unstable-core-do-not-import';\n// eslint-disable-next-line no-restricted-imports\nimport type { Result } from '../unstable-core-do-not-import';\n// eslint-disable-next-line no-restricted-imports\nimport { iteratorResource } from '../unstable-core-do-not-import/stream/utils/asyncIterable';\nimport { Unpromise } from '../vendor/unpromise';\nimport { createURL, type NodeHTTPCreateContextFnOptions } from './node-http';\nimport type { Encoder } from './wsEncoder';\nimport { jsonEncoder } from './wsEncoder';\n\n/**\n * Importing ws causes a build error\n * @see https://github.com/trpc/trpc/pull/5279\n */\nconst WEBSOCKET_OPEN = 1; /* ws.WebSocket.OPEN */\n\n/**\n * @public\n */\nexport type CreateWSSContextFnOptions = NodeHTTPCreateContextFnOptions<\n IncomingMessage,\n ws.WebSocket\n>;\n\n/**\n * @public\n */\nexport type CreateWSSContextFn<TRouter extends AnyRouter> = (\n opts: CreateWSSContextFnOptions,\n) => MaybePromise<inferRouterContext<TRouter>>;\n\nexport type WSConnectionHandlerOptions<TRouter extends AnyRouter> =\n BaseHandlerOptions<TRouter, IncomingMessage> &\n CreateContextCallback<\n inferRouterContext<TRouter>,\n CreateWSSContextFn<TRouter>\n >;\n\n/**\n * Web socket server handler\n */\nexport type WSSHandlerOptions<TRouter extends AnyRouter> =\n WSConnectionHandlerOptions<TRouter> & {\n wss: ws.WebSocketServer;\n prefix?: string;\n keepAlive?: {\n /**\n * Enable heartbeat messages\n * @default false\n */\n enabled: boolean;\n /**\n * Heartbeat interval in milliseconds\n * @default 30_000\n */\n pingMs?: number;\n /**\n * Terminate the WebSocket if no pong is received after this many milliseconds\n * @default 5_000\n */\n pongWaitMs?: number;\n };\n /**\n * Disable responding to ping messages from the client\n * **Not recommended** - this is mainly used for testing\n * @default false\n */\n dangerouslyDisablePong?: boolean;\n /**\n * Custom encoder for wire encoding (e.g. custom binary formats)\n * @default jsonEncoder\n */\n experimental_encoder?: Encoder;\n };\n\nexport function getWSConnectionHandler<TRouter extends AnyRouter>(\n opts: WSSHandlerOptions<TRouter>,\n) {\n const { createContext, router } = opts;\n const { transformer } = router._def._config;\n const encoder = opts.experimental_encoder ?? jsonEncoder;\n\n return (client: ws.WebSocket, req: IncomingMessage) => {\n type Context = inferRouterContext<TRouter>;\n type ContextResult = Result<Context>;\n\n const clientSubscriptions = new Map<number | string, AbortController>();\n const abortController = new AbortController();\n\n if (opts.keepAlive?.enabled) {\n const { pingMs, pongWaitMs } = opts.keepAlive;\n handleKeepAlive(client, pingMs, pongWaitMs);\n }\n\n function respond(untransformedJSON: TRPCResponseMessage) {\n client.send(\n encoder.encode(\n transformTRPCResponse(router._def._config, untransformedJSON),\n ),\n );\n }\n\n async function createCtxPromise(\n getConnectionParams: () => TRPCRequestInfo['connectionParams'],\n ): Promise<ContextResult> {\n try {\n return await run(async (): Promise<ContextResult> => {\n ctx = await createContext?.({\n req,\n res: client,\n info: {\n connectionParams: getConnectionParams(),\n calls: [],\n isBatchCall: false,\n accept: null,\n type: 'unknown',\n signal: abortController.signal,\n url: null,\n },\n });\n\n return {\n ok: true,\n value: ctx,\n };\n });\n } catch (cause) {\n const error = getTRPCErrorFromUnknown(cause);\n opts.onError?.({\n error,\n path: undefined,\n type: 'unknown',\n ctx,\n req,\n input: undefined,\n });\n respond({\n id: null,\n error: getErrorShape({\n config: router._def._config,\n error,\n type: 'unknown',\n path: undefined,\n input: undefined,\n ctx,\n }),\n });\n\n // close in next tick\n (globalThis.setImmediate ?? globalThis.setTimeout)(() => {\n client.close();\n });\n return {\n ok: false,\n error,\n };\n }\n }\n\n let ctx: Context | undefined = undefined;\n\n /**\n * promise for initializing the context\n *\n * - the context promise will be created immediately on connection if no connectionParams are expected\n * - if connection params are expected, they will be created once received\n */\n let ctxPromise =\n createURL(req).searchParams.get('connectionParams') === '1'\n ? null\n : createCtxPromise(() => null);\n\n function handleRequest(msg: TRPCClientOutgoingMessage, batchIndex: number) {\n const { id, jsonrpc } = msg;\n\n if (id === null) {\n const error = getTRPCErrorFromUnknown(\n new TRPCError({\n code: 'PARSE_ERROR',\n message: '`id` is required',\n }),\n );\n opts.onError?.({\n error,\n path: undefined,\n type: 'unknown',\n ctx,\n req,\n input: undefined,\n });\n respond({\n id,\n jsonrpc,\n error: getErrorShape({\n config: router._def._config,\n error,\n type: 'unknown',\n path: undefined,\n input: undefined,\n ctx,\n }),\n });\n return;\n }\n if (msg.method === 'subscription.stop') {\n clientSubscriptions.get(id)?.abort();\n return;\n }\n const { path, lastEventId } = msg.params;\n let { input } = msg.params;\n const type = msg.method;\n\n if (lastEventId !== undefined) {\n if (isObject(input)) {\n input = {\n ...input,\n lastEventId: lastEventId,\n };\n } else {\n input ??= {\n lastEventId: lastEventId,\n };\n }\n }\n run(async () => {\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n const res = await ctxPromise!; // asserts context has been set\n if (!res.ok) {\n throw res.error;\n }\n\n const abortController = new AbortController();\n const result = await callTRPCProcedure({\n router,\n path,\n getRawInput: async () => input,\n ctx,\n type,\n signal: abortController.signal,\n batchIndex,\n });\n\n const isIterableResult =\n isAsyncIterable(result) || isObservable(result);\n\n if (type !== 'subscription') {\n if (isIterableResult) {\n throw new TRPCError({\n code: 'UNSUPPORTED_MEDIA_TYPE',\n message: `Cannot return an async iterable or observable from a ${type} procedure with WebSockets`,\n });\n }\n // send the value as data if the method is not a subscription\n respond({\n id,\n jsonrpc,\n result: {\n type: 'data',\n data: result,\n },\n });\n return;\n }\n\n if (!isIterableResult) {\n throw new TRPCError({\n message: `Subscription ${path} did not return an observable or a AsyncGenerator`,\n code: 'INTERNAL_SERVER_ERROR',\n });\n }\n\n /* istanbul ignore next -- @preserve */\n if (client.readyState !== WEBSOCKET_OPEN) {\n // if the client got disconnected whilst initializing the subscription\n // no need to send stopped message if the client is disconnected\n\n return;\n }\n\n /* istanbul ignore next -- @preserve */\n if (clientSubscriptions.has(id)) {\n // duplicate request ids for client\n\n throw new TRPCError({\n message: `Duplicate id ${id}`,\n code: 'BAD_REQUEST',\n });\n }\n\n const iterable = isObservable(result)\n ? observableToAsyncIterable(result, abortController.signal)\n : result;\n\n run(async () => {\n await using iterator = iteratorResource(iterable);\n\n const abortPromise = new Promise<'abort'>((resolve) => {\n abortController.signal.onabort = () => resolve('abort');\n });\n // We need those declarations outside the loop for garbage collection reasons. If they\n // were declared inside, they would not be freed until the next value is present.\n let next:\n | null\n | TRPCError\n | Awaited<\n typeof abortPromise | ReturnType<(typeof iterator)['next']>\n >;\n let result: null | TRPCResultMessage<unknown>['result'];\n\n while (true) {\n next = await Unpromise.race([\n iterator.next().catch(getTRPCErrorFromUnknown),\n abortPromise,\n ]);\n\n if (next === 'abort') {\n await iterator.return?.();\n break;\n }\n if (next instanceof Error) {\n const error = getTRPCErrorFromUnknown(next);\n opts.onError?.({ error, path, type, ctx, req, input });\n respond({\n id,\n jsonrpc,\n error: getErrorShape({\n config: router._def._config,\n error,\n type,\n path,\n input,\n ctx,\n }),\n });\n break;\n }\n if (next.done) {\n break;\n }\n\n result = {\n type: 'data',\n data: next.value,\n };\n\n if (isTrackedEnvelope(next.value)) {\n const [id, data] = next.value;\n result.id = id;\n result.data = {\n id,\n data,\n };\n }\n\n respond({\n id,\n jsonrpc,\n result,\n });\n\n // free up references for garbage collection\n next = null;\n result = null;\n }\n\n respond({\n id,\n jsonrpc,\n result: {\n type: 'stopped',\n },\n });\n clientSubscriptions.delete(id);\n }).catch((cause) => {\n clientSubscriptions.delete(id);\n const error = getTRPCErrorFromUnknown(cause);\n opts.onError?.({ error, path, type, ctx, req, input });\n respond({\n id,\n jsonrpc,\n error: getErrorShape({\n config: router._def._config,\n error,\n type,\n path,\n input,\n ctx,\n }),\n });\n abortController.abort();\n });\n clientSubscriptions.set(id, abortController);\n\n respond({\n id,\n jsonrpc,\n result: {\n type: 'started',\n },\n });\n }).catch((cause) => {\n // procedure threw an error\n const error = getTRPCErrorFromUnknown(cause);\n opts.onError?.({ error, path, type, ctx, req, input });\n respond({\n id,\n jsonrpc,\n error: getErrorShape({\n config: router._def._config,\n error,\n type,\n path,\n input,\n ctx,\n }),\n });\n });\n }\n client.on('message', (rawData, isBinary) => {\n // Handle PING/PONG as text regardless of encoder\n if (!isBinary) {\n // eslint-disable-next-line @typescript-eslint/no-base-to-string\n const msgStr = rawData.toString();\n if (msgStr === 'PONG') {\n return;\n }\n if (msgStr === 'PING') {\n if (!opts.dangerouslyDisablePong) {\n client.send('PONG');\n }\n return;\n }\n }\n\n // Convert rawData to a format our encoder accepts\n // ws gives us Buffer for both text and binary frames\n if (!Buffer.isBuffer(rawData)) {\n const error = new TRPCError({\n code: 'UNPROCESSABLE_CONTENT',\n message: 'Unexpected WebSocket message format',\n });\n respond({\n id: null,\n error: getErrorShape({\n config: router._def._config,\n error,\n type: 'unknown',\n path: undefined,\n input: undefined,\n ctx,\n }),\n });\n return;\n }\n const data: string | Uint8Array = isBinary\n ? rawData\n : rawData.toString('utf8');\n\n if (!ctxPromise) {\n // If the ctxPromise wasn't created immediately, we're expecting the first message to be a TRPCConnectionParamsMessage\n ctxPromise = createCtxPromise(() => {\n let msg;\n try {\n msg = encoder.decode(data) as TRPCConnectionParamsMessage;\n\n if (!isObject(msg)) {\n throw new Error('Message was not an object');\n }\n } catch (cause) {\n throw new TRPCError({\n code: 'PARSE_ERROR',\n message: `Malformed TRPCConnectionParamsMessage`,\n cause,\n });\n }\n\n const connectionParams = parseConnectionParamsFromUnknown(msg.data);\n\n return connectionParams;\n });\n return;\n }\n\n const parsedMsgs = run(() => {\n try {\n const msgJSON: unknown = encoder.decode(data);\n const msgs: unknown[] = Array.isArray(msgJSON) ? msgJSON : [msgJSON];\n\n return msgs.map((raw) => parseTRPCMessage(raw, transformer));\n } catch (cause) {\n const error = new TRPCError({\n code: 'PARSE_ERROR',\n cause,\n });\n\n respond({\n id: null,\n error: getErrorShape({\n config: router._def._config,\n error,\n type: 'unknown',\n path: undefined,\n input: undefined,\n ctx,\n }),\n });\n\n return [];\n }\n });\n\n parsedMsgs.map((msg, index) => handleRequest(msg, index));\n });\n\n // WebSocket errors should be handled, as otherwise unhandled exceptions will crash Node.js.\n // This line was introduced after the following error brought down production systems:\n // \"RangeError: Invalid WebSocket frame: RSV2 and RSV3 must be clear\"\n // Here is the relevant discussion: https://github.com/websockets/ws/issues/1354#issuecomment-774616962\n client.on('error', (cause) => {\n opts.onError?.({\n ctx,\n error: getTRPCErrorFromUnknown(cause),\n input: undefined,\n path: undefined,\n type: 'unknown',\n req,\n });\n });\n\n client.once('close', () => {\n for (const sub of clientSubscriptions.values()) {\n sub.abort();\n }\n clientSubscriptions.clear();\n abortController.abort();\n });\n };\n}\n\n/**\n * Handle WebSocket keep-alive messages\n */\nexport function handleKeepAlive(\n client: ws.WebSocket,\n pingMs = 30_000,\n pongWaitMs = 5_000,\n) {\n let timeout: NodeJS.Timeout | undefined = undefined;\n let ping: NodeJS.Timeout | undefined = undefined;\n\n const schedulePing = () => {\n const scheduleTimeout = () => {\n timeout = setTimeout(() => {\n client.terminate();\n }, pongWaitMs);\n };\n ping = setTimeout(() => {\n client.send('PING');\n\n scheduleTimeout();\n }, pingMs);\n };\n\n const onMessage = () => {\n clearTimeout(ping);\n clearTimeout(timeout);\n\n schedulePing();\n };\n\n client.on('message', onMessage);\n\n client.on('close', () => {\n clearTimeout(ping);\n clearTimeout(timeout);\n });\n\n schedulePing();\n}\n\nexport function applyWSSHandler<TRouter extends AnyRouter>(\n opts: WSSHandlerOptions<TRouter>,\n) {\n const encoder = opts.experimental_encoder ?? jsonEncoder;\n const onConnection = getWSConnectionHandler(opts);\n opts.wss.on('connection', (client, req) => {\n if (opts.prefix && !req.url?.startsWith(opts.prefix)) {\n return;\n }\n\n onConnection(client, req);\n });\n\n return {\n broadcastReconnectNotification: () => {\n const response: TRPCReconnectNotification = {\n id: null,\n method: 'reconnect',\n };\n const data = encoder.encode(response);\n for (const client of opts.wss.clients) {\n if (client.readyState === WEBSOCKET_OPEN) {\n client.send(data);\n }\n }\n },\n };\n}\n\nexport type { Encoder } from './wsEncoder';\nexport { jsonEncoder } from './wsEncoder';\n"],"mappings":"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"}
|
package/http/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from '../dist/http';
|
package/http/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
module.exports = require('../dist/http');
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from '../dist/observable';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
module.exports = require('../dist/observable');
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@trpc/server",
|
|
3
3
|
"type": "module",
|
|
4
4
|
"sideEffects": false,
|
|
5
|
-
"version": "11.
|
|
5
|
+
"version": "11.21.1-canary.20.10e2ef98f",
|
|
6
6
|
"description": "The tRPC server library",
|
|
7
7
|
"author": "KATT",
|
|
8
8
|
"license": "MIT",
|
|
@@ -196,33 +196,33 @@
|
|
|
196
196
|
"access": "public"
|
|
197
197
|
},
|
|
198
198
|
"devDependencies": {
|
|
199
|
-
"@fastify/websocket": "
|
|
200
|
-
"@oxc-project/runtime": "0.
|
|
199
|
+
"@fastify/websocket": "^11.3.0",
|
|
200
|
+
"@oxc-project/runtime": "0.152.0",
|
|
201
201
|
"@tanstack/intent": "^0.0.27",
|
|
202
202
|
"@tanstack/react-query": "^5.80.3",
|
|
203
203
|
"@types/aws-lambda": "^8.10.149",
|
|
204
204
|
"@types/express": "^5.0.0",
|
|
205
205
|
"@types/hash-sum": "^1.0.0",
|
|
206
|
-
"@types/node": "
|
|
206
|
+
"@types/node": "^24.13.4",
|
|
207
207
|
"@types/react": "^19.1.0",
|
|
208
208
|
"@types/react-dom": "^19.1.1",
|
|
209
209
|
"@types/ws": "^8.2.0",
|
|
210
|
-
"devalue": "
|
|
211
|
-
"eslint": "
|
|
210
|
+
"devalue": "^5.9.2",
|
|
211
|
+
"eslint": "^10.10.0",
|
|
212
212
|
"express": "^5.0.0",
|
|
213
|
-
"fastify": "
|
|
214
|
-
"fastify-plugin": "
|
|
213
|
+
"fastify": "^5.12.4",
|
|
214
|
+
"fastify-plugin": "^6.0.0",
|
|
215
215
|
"hash-sum": "^2.0.0",
|
|
216
216
|
"myzod": "^1.3.1",
|
|
217
|
-
"next": "
|
|
217
|
+
"next": "^15.5.25",
|
|
218
218
|
"react": "^19.1.0",
|
|
219
219
|
"react-dom": "^19.1.0",
|
|
220
220
|
"superjson": "^1.12.4",
|
|
221
221
|
"superstruct": "^2.0.0",
|
|
222
|
-
"tsdown": "
|
|
223
|
-
"typescript": "
|
|
224
|
-
"valibot": "
|
|
225
|
-
"ws": "
|
|
222
|
+
"tsdown": "0.23.0",
|
|
223
|
+
"typescript": "^7.0.2",
|
|
224
|
+
"valibot": "^1.5.0",
|
|
225
|
+
"ws": "^8.21.3",
|
|
226
226
|
"yup": "^1.0.0",
|
|
227
227
|
"zod": "^4.2.1"
|
|
228
228
|
},
|
|
@@ -238,5 +238,5 @@
|
|
|
238
238
|
"bin": {
|
|
239
239
|
"intent": "./bin/intent.js"
|
|
240
240
|
},
|
|
241
|
-
"gitHead": "
|
|
241
|
+
"gitHead": "10e2ef98f7842b94eb3026e4f9bcfe62cc39b088"
|
|
242
242
|
}
|
package/rpc/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from '../dist/rpc';
|
package/rpc/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
module.exports = require('../dist/rpc');
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from '../dist/shared';
|
package/shared/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
module.exports = require('../dist/shared');
|
|
@@ -22,6 +22,7 @@ export {
|
|
|
22
22
|
type inferRouterContext,
|
|
23
23
|
type inferClientTypes as inferTRPCClientTypes,
|
|
24
24
|
type AnyClientTypes as AnyTRPCClientTypes,
|
|
25
|
+
type inferProcedureErrorShape,
|
|
25
26
|
type inferTransformedProcedureOutput,
|
|
26
27
|
type inferTransformedSubscriptionOutput,
|
|
27
28
|
type AnyProcedure as AnyTRPCProcedure,
|
|
@@ -22,6 +22,18 @@ export type inferTransformedProcedureOutput<
|
|
|
22
22
|
? Serialize<inferProcedureOutput<TProcedure>>
|
|
23
23
|
: inferProcedureOutput<TProcedure>;
|
|
24
24
|
|
|
25
|
+
/**
|
|
26
|
+
* @internal
|
|
27
|
+
*/
|
|
28
|
+
export type inferProcedureErrorShape<
|
|
29
|
+
TInferrable extends InferrableClientTypes,
|
|
30
|
+
TProcedure extends AnyProcedure,
|
|
31
|
+
> = TProcedure['_def']['$types']['errorShape'] extends infer $Shape
|
|
32
|
+
? unknown extends $Shape
|
|
33
|
+
? inferClientTypes<TInferrable>['errorShape']
|
|
34
|
+
: $Shape
|
|
35
|
+
: never;
|
|
36
|
+
|
|
25
37
|
/** @internal */
|
|
26
38
|
export type inferTransformedSubscriptionOutput<
|
|
27
39
|
TInferrable extends InferrableClientTypes,
|
|
@@ -1,22 +1,48 @@
|
|
|
1
|
+
import { getHTTPStatusCodeFromError } from '../http/getHTTPStatusCode';
|
|
1
2
|
import type { ProcedureType } from '../procedure';
|
|
2
3
|
import type {
|
|
3
4
|
TRPC_ERROR_CODE_KEY,
|
|
4
5
|
TRPC_ERROR_CODE_NUMBER,
|
|
5
6
|
TRPCErrorShape,
|
|
6
7
|
} from '../rpc';
|
|
8
|
+
import { TRPC_ERROR_CODES_BY_KEY } from '../rpc';
|
|
9
|
+
import type { Overwrite, Simplify } from '../types';
|
|
7
10
|
import type { TRPCError } from './TRPCError';
|
|
8
11
|
|
|
9
12
|
/**
|
|
10
13
|
* @internal
|
|
11
14
|
*/
|
|
12
|
-
export
|
|
15
|
+
export interface ErrorFormatterOptions<TContext> {
|
|
13
16
|
error: TRPCError;
|
|
14
17
|
type: ProcedureType | 'unknown';
|
|
15
18
|
path: string | undefined;
|
|
16
19
|
input: unknown;
|
|
17
|
-
ctx: TContext
|
|
20
|
+
ctx: TContext;
|
|
18
21
|
shape: DefaultErrorShape;
|
|
19
|
-
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* @internal
|
|
26
|
+
*/
|
|
27
|
+
export type ErrorFormatter<TContext, TShape extends TRPCErrorShape> = (
|
|
28
|
+
opts: ErrorFormatterOptions<TContext | undefined>,
|
|
29
|
+
) => TShape;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* @internal
|
|
33
|
+
*/
|
|
34
|
+
export type ProcedureErrorFormatter<
|
|
35
|
+
TContext,
|
|
36
|
+
TContextOverrides,
|
|
37
|
+
TShape extends TRPCErrorShape | undefined | void,
|
|
38
|
+
> = (
|
|
39
|
+
opts: ErrorFormatterOptions<Simplify<Overwrite<TContext, TContextOverrides>>>,
|
|
40
|
+
) => TShape;
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* @internal
|
|
44
|
+
*/
|
|
45
|
+
export type AnyProcedureErrorFormatter = ProcedureErrorFormatter<any, any, any>;
|
|
20
46
|
|
|
21
47
|
/**
|
|
22
48
|
* @internal
|
|
@@ -45,3 +71,64 @@ export interface DefaultErrorShape extends TRPCErrorShape<DefaultErrorData> {
|
|
|
45
71
|
export const defaultFormatter: ErrorFormatter<any, any> = ({ shape }) => {
|
|
46
72
|
return shape;
|
|
47
73
|
};
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* @internal
|
|
77
|
+
*/
|
|
78
|
+
export function getDefaultErrorShape(opts: {
|
|
79
|
+
error: TRPCError;
|
|
80
|
+
path: string | undefined;
|
|
81
|
+
isDev: boolean;
|
|
82
|
+
}): DefaultErrorShape {
|
|
83
|
+
const shape: DefaultErrorShape = {
|
|
84
|
+
message: opts.error.message,
|
|
85
|
+
code: TRPC_ERROR_CODES_BY_KEY[opts.error.code],
|
|
86
|
+
data: {
|
|
87
|
+
code: opts.error.code,
|
|
88
|
+
httpStatus: getHTTPStatusCodeFromError(opts.error),
|
|
89
|
+
},
|
|
90
|
+
};
|
|
91
|
+
if (opts.isDev && typeof opts.error.stack === 'string') {
|
|
92
|
+
shape.data.stack = opts.error.stack;
|
|
93
|
+
}
|
|
94
|
+
if (typeof opts.path === 'string') {
|
|
95
|
+
shape.data.path = opts.path;
|
|
96
|
+
}
|
|
97
|
+
return shape;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const formattedShapeSymbol = Symbol('trpc_formattedErrorShape');
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* @internal
|
|
104
|
+
*/
|
|
105
|
+
export function setFormattedErrorShape(
|
|
106
|
+
error: TRPCError,
|
|
107
|
+
shape: TRPCErrorShape,
|
|
108
|
+
): asserts error is TRPCError & { [formattedShapeSymbol]: TRPCErrorShape } {
|
|
109
|
+
Object.defineProperty(error, formattedShapeSymbol, {
|
|
110
|
+
value: shape,
|
|
111
|
+
enumerable: false,
|
|
112
|
+
configurable: true,
|
|
113
|
+
writable: true,
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* @internal
|
|
119
|
+
*/
|
|
120
|
+
export function getFormattedErrorShape(
|
|
121
|
+
error: TRPCError,
|
|
122
|
+
): TRPCErrorShape | undefined {
|
|
123
|
+
if (isFormattedErrorShape(error)) {
|
|
124
|
+
return error[formattedShapeSymbol];
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
return undefined;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export function isFormattedErrorShape(
|
|
131
|
+
error: TRPCError,
|
|
132
|
+
): error is TRPCError & { [formattedShapeSymbol]: TRPCErrorShape } {
|
|
133
|
+
return formattedShapeSymbol in error;
|
|
134
|
+
}
|
|
@@ -1,8 +1,6 @@
|
|
|
1
|
-
import { getHTTPStatusCodeFromError } from '../http/getHTTPStatusCode';
|
|
2
1
|
import type { ProcedureType } from '../procedure';
|
|
3
2
|
import type { AnyRootTypes, RootConfig } from '../rootConfig';
|
|
4
|
-
import {
|
|
5
|
-
import type { DefaultErrorShape } from './formatter';
|
|
3
|
+
import { getDefaultErrorShape, getFormattedErrorShape } from './formatter';
|
|
6
4
|
import type { TRPCError } from './TRPCError';
|
|
7
5
|
|
|
8
6
|
/**
|
|
@@ -17,20 +15,13 @@ export function getErrorShape<TRoot extends AnyRootTypes>(opts: {
|
|
|
17
15
|
ctx: TRoot['ctx'] | undefined;
|
|
18
16
|
}): TRoot['errorShape'] {
|
|
19
17
|
const { path, error, config } = opts;
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
code,
|
|
26
|
-
httpStatus: getHTTPStatusCodeFromError(error),
|
|
27
|
-
},
|
|
28
|
-
};
|
|
29
|
-
if (config.isDev && typeof opts.error.stack === 'string') {
|
|
30
|
-
shape.data.stack = opts.error.stack;
|
|
31
|
-
}
|
|
32
|
-
if (typeof path === 'string') {
|
|
33
|
-
shape.data.path = path;
|
|
18
|
+
|
|
19
|
+
// a `.errors()` handler already created the final shape
|
|
20
|
+
const formatted = getFormattedErrorShape(error);
|
|
21
|
+
if (formatted !== undefined) {
|
|
22
|
+
return formatted;
|
|
34
23
|
}
|
|
24
|
+
|
|
25
|
+
const shape = getDefaultErrorShape({ error, path, isDev: config.isDev });
|
|
35
26
|
return config.errorFormatter({ ...opts, shape });
|
|
36
27
|
}
|
|
@@ -8,7 +8,7 @@ import { createMiddlewareFactory } from './middleware';
|
|
|
8
8
|
import type { ProcedureBuilder } from './procedureBuilder';
|
|
9
9
|
import { createBuilder } from './procedureBuilder';
|
|
10
10
|
import type { AnyRootTypes, CreateRootTypes } from './rootConfig';
|
|
11
|
-
import { isServerDefault, type RootConfig } from './rootConfig';
|
|
11
|
+
import { isDevDefault, isServerDefault, type RootConfig } from './rootConfig';
|
|
12
12
|
import type {
|
|
13
13
|
AnyRouter,
|
|
14
14
|
MergeRouters,
|
|
@@ -82,7 +82,8 @@ export interface TRPCRootObject<
|
|
|
82
82
|
UnsetMarker,
|
|
83
83
|
UnsetMarker,
|
|
84
84
|
UnsetMarker,
|
|
85
|
-
false
|
|
85
|
+
false,
|
|
86
|
+
$Root['errorShape']
|
|
86
87
|
>;
|
|
87
88
|
|
|
88
89
|
/**
|
|
@@ -153,10 +154,7 @@ class TRPCBuilder<TContext extends object, TMeta extends object> {
|
|
|
153
154
|
const config: RootConfig<$Root> = {
|
|
154
155
|
...opts,
|
|
155
156
|
transformer: getDataTransformer(opts?.transformer ?? defaultTransformer),
|
|
156
|
-
isDev:
|
|
157
|
-
opts?.isDev ??
|
|
158
|
-
// eslint-disable-next-line @typescript-eslint/dot-notation
|
|
159
|
-
globalThis.process?.env['NODE_ENV'] !== 'production',
|
|
157
|
+
isDev: opts?.isDev ?? isDevDefault(),
|
|
160
158
|
allowOutsideOfServer: opts?.allowOutsideOfServer ?? false,
|
|
161
159
|
errorFormatter: opts?.errorFormatter ?? defaultFormatter,
|
|
162
160
|
isServer: opts?.isServer ?? isServerDefault,
|
|
@@ -187,8 +185,13 @@ class TRPCBuilder<TContext extends object, TMeta extends object> {
|
|
|
187
185
|
* Builder object for creating procedures
|
|
188
186
|
* @see https://trpc.io/docs/v11/server/procedures
|
|
189
187
|
*/
|
|
190
|
-
procedure: createBuilder
|
|
188
|
+
procedure: createBuilder<
|
|
189
|
+
$Root['ctx'],
|
|
190
|
+
$Root['meta'],
|
|
191
|
+
$Root['errorShape']
|
|
192
|
+
>({
|
|
191
193
|
meta: opts?.defaultMeta,
|
|
194
|
+
config,
|
|
192
195
|
}),
|
|
193
196
|
/**
|
|
194
197
|
* Create reusable middlewares
|
|
@@ -1,8 +1,16 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { Observable } from '../observable';
|
|
2
|
+
import { isObservable, observable } from '../observable';
|
|
3
|
+
import type { AnyProcedureErrorFormatter } from './error/formatter';
|
|
4
|
+
import {
|
|
5
|
+
getDefaultErrorShape,
|
|
6
|
+
isFormattedErrorShape,
|
|
7
|
+
setFormattedErrorShape,
|
|
8
|
+
} from './error/formatter';
|
|
9
|
+
import { getTRPCErrorFromUnknown, TRPCError } from './error/TRPCError';
|
|
2
10
|
import type { ParseFn } from './parser';
|
|
3
11
|
import type { ProcedureType } from './procedure';
|
|
4
12
|
import type { GetRawInputFn, Overwrite, Simplify } from './types';
|
|
5
|
-
import { isObject } from './utils';
|
|
13
|
+
import { isAsyncIterable, isObject } from './utils';
|
|
6
14
|
|
|
7
15
|
/** @internal */
|
|
8
16
|
export const middlewareMarker = 'middlewareMarker' as 'middlewareMarker' & {
|
|
@@ -214,6 +222,89 @@ export function createInputMiddleware<TInput>(parse: ParseFn<TInput>) {
|
|
|
214
222
|
return inputMiddleware;
|
|
215
223
|
}
|
|
216
224
|
|
|
225
|
+
/**
|
|
226
|
+
* @internal
|
|
227
|
+
*/
|
|
228
|
+
export function createErrorFormatterMiddleware(
|
|
229
|
+
formatter: AnyProcedureErrorFormatter,
|
|
230
|
+
isDev: boolean,
|
|
231
|
+
) {
|
|
232
|
+
const errorMiddleware: AnyMiddlewareFunction =
|
|
233
|
+
async function errorFormatterMiddleware(opts) {
|
|
234
|
+
const tryFormat = (error: TRPCError): TRPCError => {
|
|
235
|
+
// a handler further down the chain already claimed this error
|
|
236
|
+
if (isFormattedErrorShape(error)) {
|
|
237
|
+
return error;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
const shape = formatter({
|
|
241
|
+
error,
|
|
242
|
+
type: opts.type,
|
|
243
|
+
path: opts.path,
|
|
244
|
+
input: opts.input,
|
|
245
|
+
ctx: opts.ctx,
|
|
246
|
+
shape: getDefaultErrorShape({
|
|
247
|
+
error,
|
|
248
|
+
path: opts.path,
|
|
249
|
+
isDev,
|
|
250
|
+
}),
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
if (shape !== undefined) {
|
|
254
|
+
setFormattedErrorShape(error, shape);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
return error;
|
|
258
|
+
};
|
|
259
|
+
|
|
260
|
+
const tryFormatThrown = (cause: unknown): unknown => {
|
|
261
|
+
const formatted = tryFormat(getTRPCErrorFromUnknown(cause));
|
|
262
|
+
|
|
263
|
+
return isFormattedErrorShape(formatted) ? formatted : cause;
|
|
264
|
+
};
|
|
265
|
+
|
|
266
|
+
async function* wrapIterable(iterable: AsyncIterable<unknown>) {
|
|
267
|
+
try {
|
|
268
|
+
return yield* iterable;
|
|
269
|
+
} catch (cause) {
|
|
270
|
+
throw tryFormatThrown(cause);
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
function wrapObservable(source: Observable<unknown, unknown>) {
|
|
275
|
+
return observable((observer) =>
|
|
276
|
+
source.subscribe({
|
|
277
|
+
next: (value) => observer.next(value),
|
|
278
|
+
error: (cause) => observer.error(tryFormatThrown(cause)),
|
|
279
|
+
complete: () => observer.complete(),
|
|
280
|
+
}),
|
|
281
|
+
);
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
const result = await opts.next();
|
|
285
|
+
|
|
286
|
+
// normal procedures return errors immediately
|
|
287
|
+
if (!result.ok) {
|
|
288
|
+
tryFormat(result.error);
|
|
289
|
+
return result;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
// subscription/streaming procedures need to be enumerated to find errors
|
|
293
|
+
if (isAsyncIterable(result.data)) {
|
|
294
|
+
return { ...result, data: wrapIterable(result.data) };
|
|
295
|
+
}
|
|
296
|
+
if (opts.type === 'subscription' && isObservable(result.data)) {
|
|
297
|
+
return { ...result, data: wrapObservable(result.data) };
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
return result;
|
|
301
|
+
};
|
|
302
|
+
|
|
303
|
+
errorMiddleware._type = 'errors';
|
|
304
|
+
|
|
305
|
+
return errorMiddleware;
|
|
306
|
+
}
|
|
307
|
+
|
|
217
308
|
/**
|
|
218
309
|
* @internal
|
|
219
310
|
*/
|
|
@@ -13,6 +13,7 @@ interface BuiltProcedureDef {
|
|
|
13
13
|
meta: unknown;
|
|
14
14
|
input: unknown;
|
|
15
15
|
output: unknown;
|
|
16
|
+
errorShape?: unknown;
|
|
16
17
|
}
|
|
17
18
|
|
|
18
19
|
/**
|
|
@@ -31,6 +32,7 @@ export interface Procedure<
|
|
|
31
32
|
$types: {
|
|
32
33
|
input: TDef['input'];
|
|
33
34
|
output: TDef['output'];
|
|
35
|
+
errorShape: TDef['errorShape'];
|
|
34
36
|
};
|
|
35
37
|
procedure: true;
|
|
36
38
|
type: TType;
|