orpc-fn 0.1.0 → 0.2.0
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/README.md +48 -32
- package/dist/assemble-procedure.d.ts +13 -0
- package/dist/assemble-procedure.d.ts.map +1 -0
- package/dist/assemble-procedure.js +29 -0
- package/dist/assemble-procedure.js.map +1 -0
- package/dist/bound-call.d.ts +1 -1
- package/dist/bound-call.d.ts.map +1 -1
- package/dist/bound-call.js.map +1 -1
- package/dist/client.d.ts +4 -2
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +4 -2
- package/dist/client.js.map +1 -1
- package/dist/compatibility.d.ts +16 -0
- package/dist/compatibility.d.ts.map +1 -0
- package/dist/compatibility.js +4 -0
- package/dist/compatibility.js.map +1 -0
- package/dist/create-fn.d.ts +30 -34
- package/dist/create-fn.d.ts.map +1 -1
- package/dist/create-fn.js +177 -121
- package/dist/create-fn.js.map +1 -1
- package/dist/expo.d.ts +11 -25
- package/dist/expo.d.ts.map +1 -1
- package/dist/expo.js +25 -30
- package/dist/expo.js.map +1 -1
- package/dist/hono.d.ts +12 -4
- package/dist/hono.d.ts.map +1 -1
- package/dist/hono.js +29 -12
- package/dist/hono.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/json-schema.d.ts +2 -0
- package/dist/json-schema.d.ts.map +1 -1
- package/dist/json-schema.js +11 -0
- package/dist/json-schema.js.map +1 -1
- package/dist/live/codec.d.ts +6 -1
- package/dist/live/codec.d.ts.map +1 -1
- package/dist/live/codec.js +14 -3
- package/dist/live/codec.js.map +1 -1
- package/dist/live/fn-live.d.ts +63 -22
- package/dist/live/fn-live.d.ts.map +1 -1
- package/dist/live/fn-live.js +98 -16
- package/dist/live/fn-live.js.map +1 -1
- package/dist/live/index.d.ts +1 -1
- package/dist/live/index.d.ts.map +1 -1
- package/dist/live/index.js.map +1 -1
- package/dist/live/ioredis.d.ts +4 -1
- package/dist/live/ioredis.d.ts.map +1 -1
- package/dist/live/ioredis.js +21 -2
- package/dist/live/ioredis.js.map +1 -1
- package/dist/live/lifecycle.d.ts +7 -0
- package/dist/live/lifecycle.d.ts.map +1 -0
- package/dist/live/lifecycle.js +36 -0
- package/dist/live/lifecycle.js.map +1 -0
- package/dist/live/memory.d.ts.map +1 -1
- package/dist/live/memory.js +4 -0
- package/dist/live/memory.js.map +1 -1
- package/dist/live/pub-sub.d.ts +76 -12
- package/dist/live/pub-sub.d.ts.map +1 -1
- package/dist/live/pub-sub.js +429 -125
- package/dist/live/pub-sub.js.map +1 -1
- package/dist/live/redis-bun.d.ts +1 -1
- package/dist/live/redis-bun.d.ts.map +1 -1
- package/dist/live/redis-bun.js +3 -5
- package/dist/live/redis-bun.js.map +1 -1
- package/dist/live/redis.d.ts +2 -2
- package/dist/live/redis.d.ts.map +1 -1
- package/dist/live/redis.js +36 -9
- package/dist/live/redis.js.map +1 -1
- package/dist/live/transport.d.ts +5 -1
- package/dist/live/transport.d.ts.map +1 -1
- package/dist/live/transport.js.map +1 -1
- package/dist/logger.d.ts +2 -0
- package/dist/logger.d.ts.map +1 -1
- package/dist/logger.js +21 -0
- package/dist/logger.js.map +1 -1
- package/dist/mastra.d.ts.map +1 -1
- package/dist/mastra.js +16 -7
- package/dist/mastra.js.map +1 -1
- package/dist/mcp/sdk.d.ts +20 -0
- package/dist/mcp/sdk.d.ts.map +1 -0
- package/dist/mcp/sdk.js +82 -0
- package/dist/mcp/sdk.js.map +1 -0
- package/dist/mcp.d.ts +3 -2
- package/dist/mcp.d.ts.map +1 -1
- package/dist/mcp.js +22 -7
- package/dist/mcp.js.map +1 -1
- package/dist/meta.d.ts +15 -7
- package/dist/meta.d.ts.map +1 -1
- package/dist/meta.js +9 -2
- package/dist/meta.js.map +1 -1
- package/dist/otel.d.ts.map +1 -1
- package/dist/otel.js +77 -6
- package/dist/otel.js.map +1 -1
- package/dist/route-options.d.ts +22 -0
- package/dist/route-options.d.ts.map +1 -0
- package/dist/route-options.js +67 -0
- package/dist/route-options.js.map +1 -0
- package/dist/router.d.ts +5 -1
- package/dist/router.d.ts.map +1 -1
- package/dist/router.js +22 -0
- package/dist/router.js.map +1 -1
- package/dist/timing.d.ts +8 -0
- package/dist/timing.d.ts.map +1 -0
- package/dist/timing.js +4 -0
- package/dist/timing.js.map +1 -0
- package/dist/types.d.ts +86 -41
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +6 -2
- package/dist/types.js.map +1 -1
- package/package.json +15 -3
- package/src/assemble-procedure.ts +42 -0
- package/src/bound-call.ts +4 -3
- package/src/client.ts +9 -2
- package/src/compatibility.ts +39 -0
- package/src/create-fn.ts +297 -183
- package/src/expo.ts +49 -44
- package/src/hono.ts +36 -17
- package/src/index.ts +6 -2
- package/src/json-schema.ts +16 -0
- package/src/live/codec.ts +22 -3
- package/src/live/fn-live.ts +244 -69
- package/src/live/index.ts +2 -0
- package/src/live/ioredis.ts +22 -2
- package/src/live/lifecycle.ts +44 -0
- package/src/live/memory.ts +4 -0
- package/src/live/pub-sub.ts +608 -166
- package/src/live/redis-bun.ts +7 -5
- package/src/live/redis.ts +37 -11
- package/src/live/transport.ts +4 -1
- package/src/logger.ts +20 -0
- package/src/mastra.ts +15 -7
- package/src/mcp/sdk.ts +118 -0
- package/src/mcp.ts +48 -20
- package/src/meta.ts +40 -24
- package/src/otel.ts +77 -10
- package/src/route-options.ts +100 -0
- package/src/router.ts +39 -1
- package/src/timing.ts +5 -0
- package/src/types.ts +204 -62
package/dist/expo.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"expo.js","sourceRoot":"","sources":["../src/expo.ts"],"names":[],"mappings":"AAEA,OAAO,EAA6B,aAAa,EAAE,MAAM,aAAa,CAAA;AAwBtE;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,eAAe,CAAC,
|
|
1
|
+
{"version":3,"file":"expo.js","sourceRoot":"","sources":["../src/expo.ts"],"names":[],"mappings":"AAEA,OAAO,EAA6B,aAAa,EAAE,MAAM,aAAa,CAAA;AAwBtE;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,eAAe,CAAC,OAK/B;IACA,OAAO,KAAK,EACX,OAAgB,EAChB,IAA0D,EACtC,EAAE;QACtB,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;YACrB,OAAO,CAAC,OAAO,CAAC,QAAQ,IAAI,UAAU,CAAC,KAAK,CAAC,CAAC,OAAO,EAAE;gBACtD,GAAG,IAAI;gBACP,WAAW,EAAE,SAAS;aACtB,CAAC,CAAA;QACH,CAAC;QACD,MAAM,OAAO,GAAG,OAAO,CAAC,MAAM,KAAK,KAAK,IAAI,OAAO,CAAC,MAAM,KAAK,MAAM,CAAA;QACrE,MAAM,IAAI,GAAG,OAAO,CAAC,CAAC,CAAC,MAAM,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,SAAS,CAAA;QAC9D,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,EAAE;YACjD,MAAM,EAAE,OAAO,CAAC,MAAM;YACtB,OAAO,EAAE,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;YACtD,GAAG,IAAI;YACP,GAAG,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC;YACvC,MAAM,EAAE,OAAO,CAAC,MAAM;YACtB,WAAW,EAAE,MAAM;SACnB,CAAC,CAAA;QACF,yEAAyE;QACzE,oEAAoE;QACpE,OAAO,QAAoB,CAAA;IAC5B,CAAC,CAAA;AACF,CAAC;AAYD,0EAA0E;AAC1E,MAAM,UAAU,cAAc,CAC7B,OAAiC;IAEjC,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,IAAI,EAAE,GAAG,OAAO,CAAA;IACpD,OAAO,aAAa,CAAI;QACvB,GAAG,IAAI;QACP,KAAK,EAAE,eAAe,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;KAC5E,CAAC,CAAA;AACH,CAAC;AAgBD,kFAAkF;AAClF,MAAM,UAAU,wBAAwB,CAEtC,OAA2C;IAC5C,MAAM,EAAE,SAAS,EAAE,aAAa,EAAE,OAAO,EAAE,YAAY,EAAE,GAAG,IAAI,EAAE,GAAG,OAAO,CAAA;IAC5E,OAAO,cAAc,CAAI;QACxB,GAAG,IAAI;QACP,OAAO,EAAE,KAAK,EAAE,GAAG,IAAI,EAAE,EAAE;YAC1B,MAAM,QAAQ,GACb,OAAO,YAAY,KAAK,UAAU;gBACjC,CAAC,CAAC,MAAM,YAAY,CAAC,GAAG,IAAI,CAAC;gBAC7B,CAAC,CAAC,MAAM,YAAY,CAAA;YACtB,MAAM,OAAO,GAAG,IAAI,OAAO,CAC1B,QAAoD,CACpD,CAAA;YACD,MAAM,MAAM,GAAG,MAAM,SAAS,EAAE,EAAE,CAAA;YAClC,IAAI,MAAM;gBAAE,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAA;YACzC,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;gBACpB,OAAO,CAAC,GAAG,CAAC,oBAAoB,EAAE,MAAM,CAAC,CAAA;gBACzC,MAAM,MAAM,GAAG,MAAM,aAAa,EAAE,EAAE,CAAA;gBACtC,IAAI,MAAM;oBAAE,OAAO,CAAC,GAAG,CAAC,aAAa,EAAE,MAAM,CAAC,CAAA;YAC/C,CAAC;YACD,OAAO,OAAO,CAAA;QACf,CAAC;KACD,CAAC,CAAA;AACH,CAAC","sourcesContent":["import type { ClientContext } from '@orpc/client'\nimport type { RPCLink } from '@orpc/client/fetch'\nimport { type CreateRpcLinkOptions, createRpcLink } from './client.js'\n\n/** What `fetch` from `expo/fetch` accepts from this bridge. */\nexport type ExpoFetchInit = {\n\tmethod: string\n\theaders: Record<string, string>\n\tbody?: ArrayBuffer\n\tsignal: AbortSignal\n\tcredentials: 'omit'\n\tredirect?: NonNullable<RequestInit['redirect']>\n}\n\n/** The response members oRPC reads; `expo/fetch`'s `FetchResponse` has them. */\nexport type ExpoResponse = Pick<\n\tResponse,\n\t'status' | 'headers' | 'body' | 'text' | 'blob' | 'formData'\n>\n\n/** `fetch` from `expo/fetch` (the only fetch that streams on native). */\nexport type ExpoFetch = (\n\turl: string,\n\tinit: ExpoFetchInit\n) => Promise<ExpoResponse>\n\n/**\n * oRPC's link `fetch` for React Native, built on `expo/fetch`.\n *\n * oRPC carries the input and the abort signal on the `Request`, not in\n * `init`, and the call is rebuilt for `expo/fetch`, so both are forwarded\n * explicitly: the body so the server receives the input, and the signal so a\n * cancelled subscription closes its socket. Without the signal, connections\n * leak and exhaust the device's HTTP pool after a few navigations, and every\n * later request hangs.\n *\n * Native sends cookies by header (see `createExpoLink`), so it omits the\n * credentialed cookie jar. On web it uses the platform `fetch` with cookies.\n */\nexport function createExpoFetch(options: {\n\tfetch: ExpoFetch\n\t/** `Platform.OS !== 'web'`. */\n\tnative: boolean\n\twebFetch?: (request: Request, init?: RequestInit) => Promise<Response>\n}) {\n\treturn async (\n\t\trequest: Request,\n\t\tinit?: { redirect?: NonNullable<RequestInit['redirect']> }\n\t): Promise<Response> => {\n\t\tif (!options.native) {\n\t\t\treturn (options.webFetch ?? globalThis.fetch)(request, {\n\t\t\t\t...init,\n\t\t\t\tcredentials: 'include'\n\t\t\t})\n\t\t}\n\t\tconst hasBody = request.method !== 'GET' && request.method !== 'HEAD'\n\t\tconst body = hasBody ? await request.arrayBuffer() : undefined\n\t\tconst response = await options.fetch(request.url, {\n\t\t\tmethod: request.method,\n\t\t\theaders: Object.fromEntries(request.headers.entries()),\n\t\t\t...init,\n\t\t\t...(body === undefined ? {} : { body }),\n\t\t\tsignal: request.signal,\n\t\t\tcredentials: 'omit'\n\t\t})\n\t\t// Not rebuilt with `new Response(...)`: React Native's Response polyfill\n\t\t// cannot stream a body. oRPC reads only the `ExpoResponse` members.\n\t\treturn response as Response\n\t}\n}\n\nexport type CreateExpoLinkOptions<T extends ClientContext> = Omit<\n\tCreateRpcLinkOptions<T>,\n\t'fetch'\n> & {\n\tfetch: ExpoFetch\n\tnative: boolean\n\t/** Explicit browser fetch override; native always uses expo/fetch. */\n\twebFetch?: (request: Request, init?: RequestInit) => Promise<Response>\n}\n\n/** Generic streaming bridge with upstream async/context-aware headers. */\nexport function createExpoLink<T extends ClientContext = ClientContext>(\n\toptions: CreateExpoLinkOptions<T>\n): RPCLink<T> {\n\tconst { fetch, native, webFetch, ...rest } = options\n\treturn createRpcLink<T>({\n\t\t...rest,\n\t\tfetch: createExpoFetch({ fetch, native, ...(webFetch ? { webFetch } : {}) })\n\t})\n}\n\nexport type CreateBetterAuthExpoLinkOptions<T extends ClientContext> =\n\tCreateExpoLinkOptions<T> & {\n\t\tgetCookie?: () =>\n\t\t\t| string\n\t\t\t| null\n\t\t\t| undefined\n\t\t\t| Promise<string | null | undefined>\n\t\tgetExpoOrigin?: () =>\n\t\t\t| string\n\t\t\t| null\n\t\t\t| undefined\n\t\t\t| Promise<string | null | undefined>\n\t}\n\n/** Better Auth's native cookie/origin headers, kept behind an explicit preset. */\nexport function createBetterAuthExpoLink<\n\tT extends ClientContext = ClientContext\n>(options: CreateBetterAuthExpoLinkOptions<T>): RPCLink<T> {\n\tconst { getCookie, getExpoOrigin, headers: extraHeaders, ...rest } = options\n\treturn createExpoLink<T>({\n\t\t...rest,\n\t\theaders: async (...args) => {\n\t\t\tconst supplied =\n\t\t\t\ttypeof extraHeaders === 'function'\n\t\t\t\t\t? await extraHeaders(...args)\n\t\t\t\t\t: await extraHeaders\n\t\t\tconst headers = new Headers(\n\t\t\t\tsupplied as ConstructorParameters<typeof Headers>[0]\n\t\t\t)\n\t\t\tconst cookie = await getCookie?.()\n\t\t\tif (cookie) headers.set('Cookie', cookie)\n\t\t\tif (options.native) {\n\t\t\t\theaders.set('x-skip-oauth-proxy', 'true')\n\t\t\t\tconst origin = await getExpoOrigin?.()\n\t\t\t\tif (origin) headers.set('expo-origin', origin)\n\t\t\t}\n\t\t\treturn headers\n\t\t}\n\t})\n}\n"]}
|
package/dist/hono.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { OpenAPIGeneratorGenerateOptions } from '@orpc/openapi';
|
|
1
2
|
import { type AnyRouter, type InferRouterInitialContext } from '@orpc/server';
|
|
2
3
|
import type { StandardHandlerPlugin } from '@orpc/server/standard';
|
|
3
4
|
import type { Context as HonoContext, Env, Hono } from 'hono';
|
|
@@ -21,7 +22,7 @@ type ContextOption<E extends Env, R extends AnyRouter> = BaseContext extends Inf
|
|
|
21
22
|
context: ContextFactory<E, R>;
|
|
22
23
|
};
|
|
23
24
|
type Path = `/${string}`;
|
|
24
|
-
type Plugin = StandardHandlerPlugin<
|
|
25
|
+
type Plugin<T extends object> = StandardHandlerPlugin<T>;
|
|
25
26
|
export type MountOrpcOptions<E extends Env, R extends AnyRouter> = ContextOption<E, R> & {
|
|
26
27
|
router: R;
|
|
27
28
|
/** Mount the RPC handler (oRPC's `RPCLink`) here. Omit to skip it. */
|
|
@@ -41,8 +42,8 @@ export type MountOrpcOptions<E extends Env, R extends AnyRouter> = ContextOption
|
|
|
41
42
|
/** Turn JSON strings back into `Date`s etc. for `z.date()` inputs. */
|
|
42
43
|
smartCoercion?: boolean;
|
|
43
44
|
/** Extra spec fields, e.g. `components.securitySchemes` and `security`. */
|
|
44
|
-
spec?:
|
|
45
|
-
plugins?: Plugin[];
|
|
45
|
+
spec?: Omit<OpenAPIGeneratorGenerateOptions, 'filter'>;
|
|
46
|
+
plugins?: Plugin<InferRouterInitialContext<R>>[];
|
|
46
47
|
};
|
|
47
48
|
/** Collapse parallel RPC calls into one HTTP request. Default: true (25 calls). */
|
|
48
49
|
batch?: boolean | {
|
|
@@ -53,7 +54,7 @@ export type MountOrpcOptions<E extends Env, R extends AnyRouter> = ContextOption
|
|
|
53
54
|
/** SSE keep-alive comments every N ms (default 15000), or false. */
|
|
54
55
|
sseKeepAlive?: boolean | number;
|
|
55
56
|
/** Extra RPC plugins (e.g. `CORSPlugin`). */
|
|
56
|
-
plugins?: Plugin[];
|
|
57
|
+
plugins?: Plugin<InferRouterInitialContext<R>>[];
|
|
57
58
|
/** Rewrite request headers before they reach the context (see `normalizeExpoOrigin`). */
|
|
58
59
|
normalizeHeaders?: (headers: Headers) => Headers;
|
|
59
60
|
/** Time spent before the handler ran, reported as `queue`. */
|
|
@@ -75,6 +76,13 @@ export type MountOrpcOptions<E extends Env, R extends AnyRouter> = ContextOption
|
|
|
75
76
|
*/
|
|
76
77
|
export declare function normalizeExpoOrigin(raw: Headers): Headers;
|
|
77
78
|
export declare function formatServerTiming(totalMs: number, timing: Record<string, number | undefined>): string;
|
|
79
|
+
/**
|
|
80
|
+
* Response headers plus Server-Timing. For SSE, also disable proxy buffering
|
|
81
|
+
* so keep-alive comments reach the edge (empty `:` lines are otherwise easy
|
|
82
|
+
* for nginx/Fastly to hold until an idle kill). A copy: some responses (e.g.
|
|
83
|
+
* redirects) have immutable headers.
|
|
84
|
+
*/
|
|
85
|
+
export declare function finishOrpcHeaders(response: Response, serverTiming: string | undefined): Headers;
|
|
78
86
|
/** Mount oRPC's RPC and OpenAPI handlers on a Hono app. */
|
|
79
87
|
export declare function mountOrpc<E extends Env, R extends AnyRouter>(app: Hono<E>, options: MountOrpcOptions<E, R>): void;
|
|
80
88
|
export {};
|
package/dist/hono.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hono.d.ts","sourceRoot":"","sources":["../src/hono.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"hono.d.ts","sourceRoot":"","sources":["../src/hono.ts"],"names":[],"mappings":"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"}
|
package/dist/hono.js
CHANGED
|
@@ -5,6 +5,7 @@ import { onError as orpcOnError } from '@orpc/server';
|
|
|
5
5
|
import { RPCHandler } from '@orpc/server/fetch';
|
|
6
6
|
import { BatchHandlerPlugin } from '@orpc/server/plugins';
|
|
7
7
|
import { ZodToJsonSchemaConverter } from '@orpc/zod/zod4';
|
|
8
|
+
import { REQUEST_TIMING } from './timing.js';
|
|
8
9
|
import { isExpectedClientError } from './expected-client-error.js';
|
|
9
10
|
/**
|
|
10
11
|
* Expo native sends `expo-origin` but not `origin`; copy it so cookie-based
|
|
@@ -33,7 +34,7 @@ export function formatServerTiming(totalMs, timing) {
|
|
|
33
34
|
* for nginx/Fastly to hold until an idle kill). A copy: some responses (e.g.
|
|
34
35
|
* redirects) have immutable headers.
|
|
35
36
|
*/
|
|
36
|
-
function
|
|
37
|
+
export function finishOrpcHeaders(response, serverTiming) {
|
|
37
38
|
const headers = new Headers(response.headers);
|
|
38
39
|
if (serverTiming) {
|
|
39
40
|
headers.set('Server-Timing', serverTiming);
|
|
@@ -57,12 +58,17 @@ export function mountOrpc(app, options) {
|
|
|
57
58
|
eventIteratorKeepAliveInterval: sseKeepAlive === true ? 15_000 : sseKeepAlive
|
|
58
59
|
};
|
|
59
60
|
const report = (error, { request }) => {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
61
|
+
try {
|
|
62
|
+
if (isExpectedError(error))
|
|
63
|
+
return;
|
|
64
|
+
options.onError?.(error, {
|
|
65
|
+
url: request.url.pathname,
|
|
66
|
+
method: request.method
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
/* Error reporting cannot replace transport outcomes. */
|
|
71
|
+
}
|
|
66
72
|
};
|
|
67
73
|
const mount = (prefix, handler) => {
|
|
68
74
|
app.use(`${prefix}/*`, async (c, next) => {
|
|
@@ -79,24 +85,33 @@ export function mountOrpc(app, options) {
|
|
|
79
85
|
: { headers, timing };
|
|
80
86
|
if (context instanceof Response)
|
|
81
87
|
return context;
|
|
88
|
+
const invocationTiming = { procedureMs: 0, calls: 0 };
|
|
82
89
|
const { matched, response } = await handler.handle(c.req.raw, {
|
|
83
90
|
prefix,
|
|
84
|
-
context:
|
|
91
|
+
context: {
|
|
92
|
+
...context,
|
|
93
|
+
[REQUEST_TIMING]: invocationTiming
|
|
94
|
+
}
|
|
85
95
|
});
|
|
86
96
|
if (!matched)
|
|
87
97
|
return next();
|
|
88
98
|
const timed = serverTiming
|
|
89
|
-
? formatServerTiming(performance.now() - started,
|
|
99
|
+
? formatServerTiming(performance.now() - started, {
|
|
100
|
+
...timing,
|
|
101
|
+
handler_ms: invocationTiming.procedureMs
|
|
102
|
+
})
|
|
90
103
|
: undefined;
|
|
91
104
|
return c.newResponse(response.body, {
|
|
92
105
|
// oRPC only produces valid HTTP status codes.
|
|
93
106
|
status: response.status,
|
|
94
|
-
headers:
|
|
107
|
+
headers: finishOrpcHeaders(response, timed)
|
|
95
108
|
});
|
|
96
109
|
});
|
|
97
110
|
};
|
|
98
111
|
if (options.rpcPrefix) {
|
|
99
|
-
const plugins = [
|
|
112
|
+
const plugins = [
|
|
113
|
+
...(options.plugins ?? [])
|
|
114
|
+
];
|
|
100
115
|
if (batch) {
|
|
101
116
|
plugins.push(new BatchHandlerPlugin({
|
|
102
117
|
maxSize: batch === true ? 25 : batch.maxSize
|
|
@@ -112,7 +127,9 @@ export function mountOrpc(app, options) {
|
|
|
112
127
|
const { openapi } = options;
|
|
113
128
|
const filter = openapi.filter ? { filter: openapi.filter } : {};
|
|
114
129
|
const converters = [new ZodToJsonSchemaConverter()];
|
|
115
|
-
const plugins = [
|
|
130
|
+
const plugins = [
|
|
131
|
+
...(openapi.plugins ?? [])
|
|
132
|
+
];
|
|
116
133
|
if (openapi.smartCoercion) {
|
|
117
134
|
plugins.push(new SmartCoercionPlugin({ schemaConverters: converters }));
|
|
118
135
|
}
|
package/dist/hono.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hono.js","sourceRoot":"","sources":["../src/hono.ts"],"names":[],"mappings":"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","sourcesContent":["import { SmartCoercionPlugin } from '@orpc/json-schema'\nimport { OpenAPIHandler } from '@orpc/openapi/fetch'\nimport { OpenAPIReferencePlugin } from '@orpc/openapi/plugins'\nimport {\n\ttype AnyRouter,\n\ttype InferRouterInitialContext,\n\tonError as orpcOnError\n} from '@orpc/server'\nimport { RPCHandler } from '@orpc/server/fetch'\nimport { BatchHandlerPlugin } from '@orpc/server/plugins'\nimport type { StandardHandlerPlugin } from '@orpc/server/standard'\nimport { ZodToJsonSchemaConverter } from '@orpc/zod/zod4'\nimport type { Context as HonoContext, Env, Hono } from 'hono'\nimport type { StatusCode } from 'hono/utils/http-status'\nimport { isExpectedClientError } from './expected-client-error.js'\nimport type { ProcedureFilter } from './mcp.js'\n\n/** Per-request timings in ms; `fn()` adds `handler_ms`. Sent as Server-Timing. */\nexport type RequestTiming = Record<string, number>\n\n/** What every request starts with; the default context when `context` is omitted. */\nexport type BaseContext = { headers: Headers; timing: RequestTiming }\n\n/**\n * Builds the router's initial context from the request. Return a `Response`\n * to answer (e.g. 401) instead.\n */\nexport type ContextFactory<E extends Env, R extends AnyRouter> = (\n\tc: HonoContext<E>,\n\tbase: BaseContext\n) =>\n\t| InferRouterInitialContext<R>\n\t| Response\n\t| Promise<InferRouterInitialContext<R> | Response>\n\n/** `context` is optional only when the base context already satisfies the router. */\ntype ContextOption<E extends Env, R extends AnyRouter> =\n\tBaseContext extends InferRouterInitialContext<R>\n\t\t? { context?: ContextFactory<E, R> }\n\t\t: { context: ContextFactory<E, R> }\n\ntype Path = `/${string}`\n// biome-ignore lint/suspicious/noExplicitAny: plugins are context-agnostic here\ntype Plugin = StandardHandlerPlugin<any>\n\nexport type MountOrpcOptions<\n\tE extends Env,\n\tR extends AnyRouter\n> = ContextOption<E, R> & {\n\trouter: R\n\t/** Mount the RPC handler (oRPC's `RPCLink`) here. Omit to skip it. */\n\trpcPrefix?: Path\n\t/** Mount the OpenAPI (REST) handler and its Scalar docs here. */\n\topenapi?: {\n\t\tprefix: Path\n\t\tinfo?: { title: string; version: string; description?: string }\n\t\t/** Docs page, relative to `prefix` (default '/'); the spec is at `/spec.json`. */\n\t\tdocsPath?: Path\n\t\t/** Only expose matching procedures (also filters the spec). */\n\t\tfilter?: ProcedureFilter\n\t\t/** Turn JSON strings back into `Date`s etc. for `z.date()` inputs. */\n\t\tsmartCoercion?: boolean\n\t\t/** Extra spec fields, e.g. `components.securitySchemes` and `security`. */\n\t\tspec?: Record<string, unknown>\n\t\tplugins?: Plugin[]\n\t}\n\t/** Collapse parallel RPC calls into one HTTP request. Default: true (25 calls). */\n\tbatch?: boolean | { maxSize: number }\n\t/** Add a Server-Timing header from the request timing. Default: true */\n\tserverTiming?: boolean\n\t/** SSE keep-alive comments every N ms (default 15000), or false. */\n\tsseKeepAlive?: boolean | number\n\t/** Extra RPC plugins (e.g. `CORSPlugin`). */\n\tplugins?: Plugin[]\n\t/** Rewrite request headers before they reach the context (see `normalizeExpoOrigin`). */\n\tnormalizeHeaders?: (headers: Headers) => Headers\n\t/** Time spent before the handler ran, reported as `queue`. */\n\tqueueMs?: (request: Request) => number | undefined\n\t/**\n\t * Unexpected procedure errors (oRPC turns thrown errors into responses, so\n\t * Hono's `onError` never sees them). Expected client errors are skipped.\n\t */\n\tonError?: (error: unknown, request: { url: string; method: string }) => void\n\t/** Default: 4xx `ORPCError` or `AbortError`. */\n\tisExpectedError?: (error: unknown) => boolean\n}\n\n/**\n * Expo native sends `expo-origin` but not `origin`; copy it so cookie-based\n * auth (e.g. Better Auth) sees the origin.\n */\nexport function normalizeExpoOrigin(raw: Headers): Headers {\n\tconst expo = raw.get('expo-origin')\n\tif (!expo || raw.get('origin')) return raw\n\tconst headers = new Headers(raw)\n\theaders.set('origin', expo)\n\treturn headers\n}\n\nexport function formatServerTiming(\n\ttotalMs: number,\n\ttiming: Record<string, number | undefined>\n): string {\n\tconst parts = [`total;dur=${totalMs.toFixed(2)}`]\n\tfor (const [key, value] of Object.entries(timing)) {\n\t\tif (value !== undefined) {\n\t\t\tparts.push(`${key.replace(/_ms$/, '')};dur=${value.toFixed(2)}`)\n\t\t}\n\t}\n\treturn parts.join(', ')\n}\n\n/**\n * Response headers plus Server-Timing. For SSE, also disable proxy buffering\n * so keep-alive comments reach the edge (empty `:` lines are otherwise easy\n * for nginx/Fastly to hold until an idle kill). A copy: some responses (e.g.\n * redirects) have immutable headers.\n */\nfunction finishHeaders(\n\tresponse: Response,\n\tserverTiming: string | undefined\n): Headers {\n\tconst headers = new Headers(response.headers)\n\tif (serverTiming) {\n\t\theaders.set('Server-Timing', serverTiming)\n\t\theaders.append('Access-Control-Expose-Headers', 'Server-Timing')\n\t}\n\tif ((headers.get('content-type') ?? '').includes('text/event-stream')) {\n\t\theaders.set('Cache-Control', 'no-cache')\n\t\theaders.set('X-Accel-Buffering', 'no')\n\t}\n\treturn headers\n}\n\n/** Mount oRPC's RPC and OpenAPI handlers on a Hono app. */\nexport function mountOrpc<E extends Env, R extends AnyRouter>(\n\tapp: Hono<E>,\n\toptions: MountOrpcOptions<E, R>\n): void {\n\tconst {\n\t\trouter,\n\t\tbatch = true,\n\t\tserverTiming = true,\n\t\tsseKeepAlive = true\n\t} = options\n\tconst isExpectedError = options.isExpectedError ?? isExpectedClientError\n\tconst keepAlive =\n\t\tsseKeepAlive === false\n\t\t\t? { eventIteratorKeepAliveEnabled: false }\n\t\t\t: {\n\t\t\t\t\teventIteratorKeepAliveEnabled: true,\n\t\t\t\t\t// Explicit keep-alive under proxy idle timers (~30s); oRPC's default is 5s.\n\t\t\t\t\teventIteratorKeepAliveInterval:\n\t\t\t\t\t\tsseKeepAlive === true ? 15_000 : sseKeepAlive\n\t\t\t\t}\n\tconst report = (\n\t\terror: unknown,\n\t\t{ request }: { request: { url: URL; method: string } }\n\t) => {\n\t\tif (isExpectedError(error)) return\n\t\toptions.onError?.(error, {\n\t\t\turl: request.url.pathname,\n\t\t\tmethod: request.method\n\t\t})\n\t}\n\n\tconst mount = (prefix: Path, handler: Pick<RPCHandler<object>, 'handle'>) => {\n\t\tapp.use(`${prefix}/*`, async (c, next) => {\n\t\t\tconst timing: RequestTiming = {}\n\t\t\tconst queueMs = options.queueMs?.(c.req.raw)\n\t\t\tif (queueMs !== undefined)\n\t\t\t\ttiming.queue_ms = Math.round(queueMs * 100) / 100\n\t\t\tconst started = performance.now()\n\t\t\tconst headers = options.normalizeHeaders\n\t\t\t\t? options.normalizeHeaders(c.req.raw.headers)\n\t\t\t\t: c.req.raw.headers\n\t\t\tconst context = options.context\n\t\t\t\t? await options.context(c, { headers, timing })\n\t\t\t\t: { headers, timing }\n\t\t\tif (context instanceof Response) return context\n\t\t\tconst { matched, response } = await handler.handle(c.req.raw, {\n\t\t\t\tprefix,\n\t\t\t\tcontext: context as object\n\t\t\t})\n\t\t\tif (!matched) return next()\n\t\t\tconst timed = serverTiming\n\t\t\t\t? formatServerTiming(performance.now() - started, timing)\n\t\t\t\t: undefined\n\t\t\treturn c.newResponse(response.body, {\n\t\t\t\t// oRPC only produces valid HTTP status codes.\n\t\t\t\tstatus: response.status as StatusCode,\n\t\t\t\theaders: finishHeaders(response, timed)\n\t\t\t})\n\t\t})\n\t}\n\n\tif (options.rpcPrefix) {\n\t\tconst plugins: Plugin[] = [...(options.plugins ?? [])]\n\t\tif (batch) {\n\t\t\tplugins.push(\n\t\t\t\tnew BatchHandlerPlugin({\n\t\t\t\t\tmaxSize: batch === true ? 25 : batch.maxSize\n\t\t\t\t})\n\t\t\t)\n\t\t}\n\t\tmount(\n\t\t\toptions.rpcPrefix,\n\t\t\tnew RPCHandler(router, {\n\t\t\t\t...keepAlive,\n\t\t\t\tplugins,\n\t\t\t\tinterceptors: options.onError ? [orpcOnError(report)] : []\n\t\t\t})\n\t\t)\n\t}\n\n\tif (options.openapi) {\n\t\tconst { openapi } = options\n\t\tconst filter = openapi.filter ? { filter: openapi.filter } : {}\n\t\tconst converters = [new ZodToJsonSchemaConverter()]\n\t\tconst plugins: Plugin[] = [...(openapi.plugins ?? [])]\n\t\tif (openapi.smartCoercion) {\n\t\t\tplugins.push(new SmartCoercionPlugin({ schemaConverters: converters }))\n\t\t}\n\t\tplugins.push(\n\t\t\tnew OpenAPIReferencePlugin({\n\t\t\t\tdocsProvider: 'scalar',\n\t\t\t\t...(openapi.docsPath ? { docsPath: openapi.docsPath } : {}),\n\t\t\t\tschemaConverters: converters,\n\t\t\t\tspecGenerateOptions: {\n\t\t\t\t\tinfo: openapi.info ?? { title: 'API', version: '0.0.0' },\n\t\t\t\t\tservers: [{ url: openapi.prefix }],\n\t\t\t\t\t...filter,\n\t\t\t\t\t...openapi.spec\n\t\t\t\t}\n\t\t\t})\n\t\t)\n\t\tmount(\n\t\t\topenapi.prefix,\n\t\t\tnew OpenAPIHandler(router, {\n\t\t\t\t...keepAlive,\n\t\t\t\t...filter,\n\t\t\t\tplugins,\n\t\t\t\tinterceptors: options.onError ? [orpcOnError(report)] : []\n\t\t\t})\n\t\t)\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"hono.js","sourceRoot":"","sources":["../src/hono.ts"],"names":[],"mappings":"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","sourcesContent":["import { SmartCoercionPlugin } from '@orpc/json-schema'\nimport type { OpenAPIGeneratorGenerateOptions } from '@orpc/openapi'\nimport { OpenAPIHandler } from '@orpc/openapi/fetch'\nimport { OpenAPIReferencePlugin } from '@orpc/openapi/plugins'\nimport {\n\ttype AnyRouter,\n\ttype InferRouterInitialContext,\n\tonError as orpcOnError\n} from '@orpc/server'\nimport { RPCHandler } from '@orpc/server/fetch'\nimport { BatchHandlerPlugin } from '@orpc/server/plugins'\nimport type { StandardHandlerPlugin } from '@orpc/server/standard'\nimport { ZodToJsonSchemaConverter } from '@orpc/zod/zod4'\nimport type { Context as HonoContext, Env, Hono } from 'hono'\nimport type { StatusCode } from 'hono/utils/http-status'\nimport { REQUEST_TIMING, type InvocationTiming } from './timing.js'\nimport { isExpectedClientError } from './expected-client-error.js'\nimport type { ProcedureFilter } from './mcp.js'\n\n/** Per-request timings in ms; `fn()` adds `handler_ms`. Sent as Server-Timing. */\nexport type RequestTiming = Record<string, number>\n\n/** What every request starts with; the default context when `context` is omitted. */\nexport type BaseContext = { headers: Headers; timing: RequestTiming }\n\n/**\n * Builds the router's initial context from the request. Return a `Response`\n * to answer (e.g. 401) instead.\n */\nexport type ContextFactory<E extends Env, R extends AnyRouter> = (\n\tc: HonoContext<E>,\n\tbase: BaseContext\n) =>\n\t| InferRouterInitialContext<R>\n\t| Response\n\t| Promise<InferRouterInitialContext<R> | Response>\n\n/** `context` is optional only when the base context already satisfies the router. */\ntype ContextOption<E extends Env, R extends AnyRouter> =\n\tBaseContext extends InferRouterInitialContext<R>\n\t\t? { context?: ContextFactory<E, R> }\n\t\t: { context: ContextFactory<E, R> }\n\ntype Path = `/${string}`\ntype Plugin<T extends object> = StandardHandlerPlugin<T>\n\nexport type MountOrpcOptions<\n\tE extends Env,\n\tR extends AnyRouter\n> = ContextOption<E, R> & {\n\trouter: R\n\t/** Mount the RPC handler (oRPC's `RPCLink`) here. Omit to skip it. */\n\trpcPrefix?: Path\n\t/** Mount the OpenAPI (REST) handler and its Scalar docs here. */\n\topenapi?: {\n\t\tprefix: Path\n\t\tinfo?: { title: string; version: string; description?: string }\n\t\t/** Docs page, relative to `prefix` (default '/'); the spec is at `/spec.json`. */\n\t\tdocsPath?: Path\n\t\t/** Only expose matching procedures (also filters the spec). */\n\t\tfilter?: ProcedureFilter\n\t\t/** Turn JSON strings back into `Date`s etc. for `z.date()` inputs. */\n\t\tsmartCoercion?: boolean\n\t\t/** Extra spec fields, e.g. `components.securitySchemes` and `security`. */\n\t\tspec?: Omit<OpenAPIGeneratorGenerateOptions, 'filter'>\n\t\tplugins?: Plugin<InferRouterInitialContext<R>>[]\n\t}\n\t/** Collapse parallel RPC calls into one HTTP request. Default: true (25 calls). */\n\tbatch?: boolean | { maxSize: number }\n\t/** Add a Server-Timing header from the request timing. Default: true */\n\tserverTiming?: boolean\n\t/** SSE keep-alive comments every N ms (default 15000), or false. */\n\tsseKeepAlive?: boolean | number\n\t/** Extra RPC plugins (e.g. `CORSPlugin`). */\n\tplugins?: Plugin<InferRouterInitialContext<R>>[]\n\t/** Rewrite request headers before they reach the context (see `normalizeExpoOrigin`). */\n\tnormalizeHeaders?: (headers: Headers) => Headers\n\t/** Time spent before the handler ran, reported as `queue`. */\n\tqueueMs?: (request: Request) => number | undefined\n\t/**\n\t * Unexpected procedure errors (oRPC turns thrown errors into responses, so\n\t * Hono's `onError` never sees them). Expected client errors are skipped.\n\t */\n\tonError?: (error: unknown, request: { url: string; method: string }) => void\n\t/** Default: 4xx `ORPCError` or `AbortError`. */\n\tisExpectedError?: (error: unknown) => boolean\n}\n\n/**\n * Expo native sends `expo-origin` but not `origin`; copy it so cookie-based\n * auth (e.g. Better Auth) sees the origin.\n */\nexport function normalizeExpoOrigin(raw: Headers): Headers {\n\tconst expo = raw.get('expo-origin')\n\tif (!expo || raw.get('origin')) return raw\n\tconst headers = new Headers(raw)\n\theaders.set('origin', expo)\n\treturn headers\n}\n\nexport function formatServerTiming(\n\ttotalMs: number,\n\ttiming: Record<string, number | undefined>\n): string {\n\tconst parts = [`total;dur=${totalMs.toFixed(2)}`]\n\tfor (const [key, value] of Object.entries(timing)) {\n\t\tif (value !== undefined) {\n\t\t\tparts.push(`${key.replace(/_ms$/, '')};dur=${value.toFixed(2)}`)\n\t\t}\n\t}\n\treturn parts.join(', ')\n}\n\n/**\n * Response headers plus Server-Timing. For SSE, also disable proxy buffering\n * so keep-alive comments reach the edge (empty `:` lines are otherwise easy\n * for nginx/Fastly to hold until an idle kill). A copy: some responses (e.g.\n * redirects) have immutable headers.\n */\nexport function finishOrpcHeaders(\n\tresponse: Response,\n\tserverTiming: string | undefined\n): Headers {\n\tconst headers = new Headers(response.headers)\n\tif (serverTiming) {\n\t\theaders.set('Server-Timing', serverTiming)\n\t\theaders.append('Access-Control-Expose-Headers', 'Server-Timing')\n\t}\n\tif ((headers.get('content-type') ?? '').includes('text/event-stream')) {\n\t\theaders.set('Cache-Control', 'no-cache')\n\t\theaders.set('X-Accel-Buffering', 'no')\n\t}\n\treturn headers\n}\n\n/** Mount oRPC's RPC and OpenAPI handlers on a Hono app. */\nexport function mountOrpc<E extends Env, R extends AnyRouter>(\n\tapp: Hono<E>,\n\toptions: MountOrpcOptions<E, R>\n): void {\n\tconst {\n\t\trouter,\n\t\tbatch = true,\n\t\tserverTiming = true,\n\t\tsseKeepAlive = true\n\t} = options\n\tconst isExpectedError = options.isExpectedError ?? isExpectedClientError\n\tconst keepAlive =\n\t\tsseKeepAlive === false\n\t\t\t? { eventIteratorKeepAliveEnabled: false }\n\t\t\t: {\n\t\t\t\t\teventIteratorKeepAliveEnabled: true,\n\t\t\t\t\t// Explicit keep-alive under proxy idle timers (~30s); oRPC's default is 5s.\n\t\t\t\t\teventIteratorKeepAliveInterval:\n\t\t\t\t\t\tsseKeepAlive === true ? 15_000 : sseKeepAlive\n\t\t\t\t}\n\tconst report = (\n\t\terror: unknown,\n\t\t{ request }: { request: { url: URL; method: string } }\n\t) => {\n\t\ttry {\n\t\t\tif (isExpectedError(error)) return\n\t\t\toptions.onError?.(error, {\n\t\t\t\turl: request.url.pathname,\n\t\t\t\tmethod: request.method\n\t\t\t})\n\t\t} catch {\n\t\t\t/* Error reporting cannot replace transport outcomes. */\n\t\t}\n\t}\n\n\tconst mount = (\n\t\tprefix: Path,\n\t\thandler: Pick<RPCHandler<InferRouterInitialContext<R>>, 'handle'>\n\t) => {\n\t\tapp.use(`${prefix}/*`, async (c, next) => {\n\t\t\tconst timing: RequestTiming = {}\n\t\t\tconst queueMs = options.queueMs?.(c.req.raw)\n\t\t\tif (queueMs !== undefined)\n\t\t\t\ttiming.queue_ms = Math.round(queueMs * 100) / 100\n\t\t\tconst started = performance.now()\n\t\t\tconst headers = options.normalizeHeaders\n\t\t\t\t? options.normalizeHeaders(c.req.raw.headers)\n\t\t\t\t: c.req.raw.headers\n\t\t\tconst context = options.context\n\t\t\t\t? await options.context(c, { headers, timing })\n\t\t\t\t: { headers, timing }\n\t\t\tif (context instanceof Response) return context\n\t\t\tconst invocationTiming: InvocationTiming = { procedureMs: 0, calls: 0 }\n\t\t\tconst { matched, response } = await handler.handle(c.req.raw, {\n\t\t\t\tprefix,\n\t\t\t\tcontext: {\n\t\t\t\t\t...context,\n\t\t\t\t\t[REQUEST_TIMING]: invocationTiming\n\t\t\t\t} as InferRouterInitialContext<R>\n\t\t\t})\n\t\t\tif (!matched) return next()\n\t\t\tconst timed = serverTiming\n\t\t\t\t? formatServerTiming(performance.now() - started, {\n\t\t\t\t\t\t...timing,\n\t\t\t\t\t\thandler_ms: invocationTiming.procedureMs\n\t\t\t\t\t})\n\t\t\t\t: undefined\n\t\t\treturn c.newResponse(response.body, {\n\t\t\t\t// oRPC only produces valid HTTP status codes.\n\t\t\t\tstatus: response.status as StatusCode,\n\t\t\t\theaders: finishOrpcHeaders(response, timed)\n\t\t\t})\n\t\t})\n\t}\n\n\tif (options.rpcPrefix) {\n\t\tconst plugins: Plugin<InferRouterInitialContext<R>>[] = [\n\t\t\t...(options.plugins ?? [])\n\t\t]\n\t\tif (batch) {\n\t\t\tplugins.push(\n\t\t\t\tnew BatchHandlerPlugin({\n\t\t\t\t\tmaxSize: batch === true ? 25 : batch.maxSize\n\t\t\t\t})\n\t\t\t)\n\t\t}\n\t\tmount(\n\t\t\toptions.rpcPrefix,\n\t\t\tnew RPCHandler(router, {\n\t\t\t\t...keepAlive,\n\t\t\t\tplugins,\n\t\t\t\tinterceptors: options.onError ? [orpcOnError(report)] : []\n\t\t\t})\n\t\t)\n\t}\n\n\tif (options.openapi) {\n\t\tconst { openapi } = options\n\t\tconst filter = openapi.filter ? { filter: openapi.filter } : {}\n\t\tconst converters = [new ZodToJsonSchemaConverter()]\n\t\tconst plugins: Plugin<InferRouterInitialContext<R>>[] = [\n\t\t\t...(openapi.plugins ?? [])\n\t\t]\n\t\tif (openapi.smartCoercion) {\n\t\t\tplugins.push(new SmartCoercionPlugin({ schemaConverters: converters }))\n\t\t}\n\t\tplugins.push(\n\t\t\tnew OpenAPIReferencePlugin({\n\t\t\t\tdocsProvider: 'scalar',\n\t\t\t\t...(openapi.docsPath ? { docsPath: openapi.docsPath } : {}),\n\t\t\t\tschemaConverters: converters,\n\t\t\t\tspecGenerateOptions: {\n\t\t\t\t\tinfo: openapi.info ?? { title: 'API', version: '0.0.0' },\n\t\t\t\t\tservers: [{ url: openapi.prefix }],\n\t\t\t\t\t...filter,\n\t\t\t\t\t...openapi.spec\n\t\t\t\t}\n\t\t\t})\n\t\t)\n\t\tmount(\n\t\t\topenapi.prefix,\n\t\t\tnew OpenAPIHandler(router, {\n\t\t\t\t...keepAlive,\n\t\t\t\t...filter,\n\t\t\t\tplugins,\n\t\t\t\tinterceptors: options.onError ? [orpcOnError(report)] : []\n\t\t\t})\n\t\t)\n\t}\n}\n"]}
|
package/dist/index.d.ts
CHANGED
|
@@ -3,8 +3,8 @@ export { type CreateFnOptions, createFn, type FnFactory } from './create-fn.js';
|
|
|
3
3
|
export { isExpectedClientError } from './expected-client-error.js';
|
|
4
4
|
export { createBoundedEventQueue } from './live/pub-sub.js';
|
|
5
5
|
export { createDefaultLogger, type FnLogger, type LogAttributes } from './logger.js';
|
|
6
|
-
export { FN_META_KEY, type FnMeta, readFnMeta } from './meta.js';
|
|
6
|
+
export { defineMeta, FN_META_KEY, type FnMeta, readFnMeta } from './meta.js';
|
|
7
7
|
export type { AttributeValue, OtelApiLike, SpanLike, SpanOf, Tracing } from './otel.js';
|
|
8
|
-
export { createRouter } from './router.js';
|
|
8
|
+
export { createRouter, createStreamManifest, createStreamManifestAsync } from './router.js';
|
|
9
9
|
export type { AnyFnContext, BuilderLike, CurrentContextOf, Fn, FnCompletedEvent, FnContext, FnDefinition, FnProcedure, FnRouteOptions, Guard, GuardOptions, GuardParams, HandlerParams, InitialContextOf, ProcedureContext, ProcedureInput, ProcedureKey, ProcedureOption, ProcedureOutput, ReservedOptionKey, RouteConfig } from './types.js';
|
|
10
10
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AACjE,OAAO,EACN,KAAK,eAAe,EACpB,QAAQ,EACR,KAAK,SAAS,EACd,MAAM,gBAAgB,CAAA;AACvB,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAA;AAClE,OAAO,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAA;AAC3D,OAAO,EACN,mBAAmB,EACnB,KAAK,QAAQ,EACb,KAAK,aAAa,EAClB,MAAM,aAAa,CAAA;AACpB,OAAO,EAAE,WAAW,EAAE,KAAK,MAAM,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AACjE,OAAO,EACN,KAAK,eAAe,EACpB,QAAQ,EACR,KAAK,SAAS,EACd,MAAM,gBAAgB,CAAA;AACvB,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAA;AAClE,OAAO,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAA;AAC3D,OAAO,EACN,mBAAmB,EACnB,KAAK,QAAQ,EACb,KAAK,aAAa,EAClB,MAAM,aAAa,CAAA;AACpB,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,KAAK,MAAM,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AAC5E,YAAY,EACX,cAAc,EACd,WAAW,EACX,QAAQ,EACR,MAAM,EACN,OAAO,EACP,MAAM,WAAW,CAAA;AAClB,OAAO,EACN,YAAY,EACZ,oBAAoB,EACpB,yBAAyB,EACzB,MAAM,aAAa,CAAA;AACpB,YAAY,EACX,YAAY,EACZ,WAAW,EACX,gBAAgB,EAChB,EAAE,EACF,gBAAgB,EAChB,SAAS,EACT,YAAY,EACZ,WAAW,EACX,cAAc,EACd,KAAK,EACL,YAAY,EACZ,WAAW,EACX,aAAa,EACb,gBAAgB,EAChB,gBAAgB,EAChB,cAAc,EACd,YAAY,EACZ,eAAe,EACf,eAAe,EACf,iBAAiB,EACjB,WAAW,EACX,MAAM,YAAY,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -3,6 +3,6 @@ export { createFn } from './create-fn.js';
|
|
|
3
3
|
export { isExpectedClientError } from './expected-client-error.js';
|
|
4
4
|
export { createBoundedEventQueue } from './live/pub-sub.js';
|
|
5
5
|
export { createDefaultLogger } from './logger.js';
|
|
6
|
-
export { FN_META_KEY, readFnMeta } from './meta.js';
|
|
7
|
-
export { createRouter } from './router.js';
|
|
6
|
+
export { defineMeta, FN_META_KEY, readFnMeta } from './meta.js';
|
|
7
|
+
export { createRouter, createStreamManifest, createStreamManifestAsync } from './router.js';
|
|
8
8
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkB,eAAe,EAAE,MAAM,iBAAiB,CAAA;AACjE,OAAO,EAEN,QAAQ,EAER,MAAM,gBAAgB,CAAA;AACvB,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAA;AAClE,OAAO,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAA;AAC3D,OAAO,EACN,mBAAmB,EAGnB,MAAM,aAAa,CAAA;AACpB,OAAO,EAAE,WAAW,EAAe,UAAU,EAAE,MAAM,WAAW,CAAA;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkB,eAAe,EAAE,MAAM,iBAAiB,CAAA;AACjE,OAAO,EAEN,QAAQ,EAER,MAAM,gBAAgB,CAAA;AACvB,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAA;AAClE,OAAO,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAA;AAC3D,OAAO,EACN,mBAAmB,EAGnB,MAAM,aAAa,CAAA;AACpB,OAAO,EAAE,UAAU,EAAE,WAAW,EAAe,UAAU,EAAE,MAAM,WAAW,CAAA;AAQ5E,OAAO,EACN,YAAY,EACZ,oBAAoB,EACpB,yBAAyB,EACzB,MAAM,aAAa,CAAA","sourcesContent":["export { type BoundCall, createBoundCall } from './bound-call.js'\nexport {\n\ttype CreateFnOptions,\n\tcreateFn,\n\ttype FnFactory\n} from './create-fn.js'\nexport { isExpectedClientError } from './expected-client-error.js'\nexport { createBoundedEventQueue } from './live/pub-sub.js'\nexport {\n\tcreateDefaultLogger,\n\ttype FnLogger,\n\ttype LogAttributes\n} from './logger.js'\nexport { defineMeta, FN_META_KEY, type FnMeta, readFnMeta } from './meta.js'\nexport type {\n\tAttributeValue,\n\tOtelApiLike,\n\tSpanLike,\n\tSpanOf,\n\tTracing\n} from './otel.js'\nexport {\n\tcreateRouter,\n\tcreateStreamManifest,\n\tcreateStreamManifestAsync\n} from './router.js'\nexport type {\n\tAnyFnContext,\n\tBuilderLike,\n\tCurrentContextOf,\n\tFn,\n\tFnCompletedEvent,\n\tFnContext,\n\tFnDefinition,\n\tFnProcedure,\n\tFnRouteOptions,\n\tGuard,\n\tGuardOptions,\n\tGuardParams,\n\tHandlerParams,\n\tInitialContextOf,\n\tProcedureContext,\n\tProcedureInput,\n\tProcedureKey,\n\tProcedureOption,\n\tProcedureOutput,\n\tReservedOptionKey,\n\tRouteConfig\n} from './types.js'\n"]}
|
package/dist/json-schema.d.ts
CHANGED
|
@@ -44,4 +44,6 @@ export type ToolSchema<TIn = unknown, TOut = TIn> = {
|
|
|
44
44
|
export declare function rawInputSchema<TIn>(schema: AnySchema): ToolSchema<TIn>;
|
|
45
45
|
/** Tool output the procedure already validated: described, passed through. */
|
|
46
46
|
export declare function passThroughOutputSchema<TOut>(schema: AnySchema): ToolSchema<TOut>;
|
|
47
|
+
/** Tool protocols permit unions only when every branch accepts an object. */
|
|
48
|
+
export declare function isObjectJsonSchema(schema: JsonSchema): boolean;
|
|
47
49
|
//# sourceMappingURL=json-schema.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"json-schema.d.ts","sourceRoot":"","sources":["../src/json-schema.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAI/C,MAAM,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;AAEhD;;;GAGG;AACH,MAAM,MAAM,UAAU,CAAC,GAAG,GAAG,OAAO,EAAE,IAAI,GAAG,GAAG,IAAI;IACnD,WAAW,EAAE;QACZ,OAAO,EAAE,CAAC,CAAA;QACV,MAAM,EAAE,MAAM,CAAA;QACd,QAAQ,EAAE,CACT,KAAK,EAAE,OAAO,KAEZ;YAAE,KAAK,EAAE,IAAI,CAAC;YAAC,MAAM,CAAC,EAAE,SAAS,CAAA;SAAE,GACnC;YAAE,MAAM,EAAE,aAAa,CAAC;gBAAE,OAAO,EAAE,MAAM,CAAA;aAAE,CAAC,CAAA;SAAE,GAC9C,OAAO,CACL;YAAE,KAAK,EAAE,IAAI,CAAC;YAAC,MAAM,CAAC,EAAE,SAAS,CAAA;SAAE,GACnC;YAAE,MAAM,EAAE,aAAa,CAAC;gBAAE,OAAO,EAAE,MAAM,CAAA;aAAE,CAAC,CAAA;SAAE,CAC/C,CAAA;QACJ,KAAK,CAAC,EAAE;YAAE,KAAK,EAAE,GAAG,CAAC;YAAC,MAAM,EAAE,IAAI,CAAA;SAAE,CAAA;QACpC,UAAU,EAAE;YACX,KAAK,EAAE,CAAC,OAAO,CAAC,EAAE,OAAO,KAAK,UAAU,CAAA;YACxC,MAAM,EAAE,CAAC,OAAO,CAAC,EAAE,OAAO,KAAK,UAAU,CAAA;SACzC,CAAA;KACD,CAAA;CACD,CAAA;AAYD;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,GAAG,UAAU,CAAC,GAAG,CAAC,CAiBtE;AAED,8EAA8E;AAC9E,wBAAgB,uBAAuB,CAAC,IAAI,EAC3C,MAAM,EAAE,SAAS,GACf,UAAU,CAAC,IAAI,CAAC,CAUlB"}
|
|
1
|
+
{"version":3,"file":"json-schema.d.ts","sourceRoot":"","sources":["../src/json-schema.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAI/C,MAAM,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;AAEhD;;;GAGG;AACH,MAAM,MAAM,UAAU,CAAC,GAAG,GAAG,OAAO,EAAE,IAAI,GAAG,GAAG,IAAI;IACnD,WAAW,EAAE;QACZ,OAAO,EAAE,CAAC,CAAA;QACV,MAAM,EAAE,MAAM,CAAA;QACd,QAAQ,EAAE,CACT,KAAK,EAAE,OAAO,KAEZ;YAAE,KAAK,EAAE,IAAI,CAAC;YAAC,MAAM,CAAC,EAAE,SAAS,CAAA;SAAE,GACnC;YAAE,MAAM,EAAE,aAAa,CAAC;gBAAE,OAAO,EAAE,MAAM,CAAA;aAAE,CAAC,CAAA;SAAE,GAC9C,OAAO,CACL;YAAE,KAAK,EAAE,IAAI,CAAC;YAAC,MAAM,CAAC,EAAE,SAAS,CAAA;SAAE,GACnC;YAAE,MAAM,EAAE,aAAa,CAAC;gBAAE,OAAO,EAAE,MAAM,CAAA;aAAE,CAAC,CAAA;SAAE,CAC/C,CAAA;QACJ,KAAK,CAAC,EAAE;YAAE,KAAK,EAAE,GAAG,CAAC;YAAC,MAAM,EAAE,IAAI,CAAA;SAAE,CAAA;QACpC,UAAU,EAAE;YACX,KAAK,EAAE,CAAC,OAAO,CAAC,EAAE,OAAO,KAAK,UAAU,CAAA;YACxC,MAAM,EAAE,CAAC,OAAO,CAAC,EAAE,OAAO,KAAK,UAAU,CAAA;SACzC,CAAA;KACD,CAAA;CACD,CAAA;AAYD;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,GAAG,UAAU,CAAC,GAAG,CAAC,CAiBtE;AAED,8EAA8E;AAC9E,wBAAgB,uBAAuB,CAAC,IAAI,EAC3C,MAAM,EAAE,SAAS,GACf,UAAU,CAAC,IAAI,CAAC,CAUlB;AAED,6EAA6E;AAC7E,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,UAAU,GAAG,OAAO,CAa9D"}
|
package/dist/json-schema.js
CHANGED
|
@@ -41,4 +41,15 @@ export function passThroughOutputSchema(schema) {
|
|
|
41
41
|
}
|
|
42
42
|
};
|
|
43
43
|
}
|
|
44
|
+
/** Tool protocols permit unions only when every branch accepts an object. */
|
|
45
|
+
export function isObjectJsonSchema(schema) {
|
|
46
|
+
if (schema.type === 'object')
|
|
47
|
+
return true;
|
|
48
|
+
const union = schema.anyOf ?? schema.oneOf;
|
|
49
|
+
return (Array.isArray(union) &&
|
|
50
|
+
union.length > 0 &&
|
|
51
|
+
union.every((branch) => typeof branch === 'object' &&
|
|
52
|
+
branch !== null &&
|
|
53
|
+
isObjectJsonSchema(branch)));
|
|
54
|
+
}
|
|
44
55
|
//# sourceMappingURL=json-schema.js.map
|
package/dist/json-schema.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"json-schema.js","sourceRoot":"","sources":["../src/json-schema.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AACrD,OAAO,EAAE,wBAAwB,EAAE,MAAM,gBAAgB,CAAA;AA6BzD,MAAM,SAAS,GAAG,IAAI,wBAAwB,EAAE,CAAA;AAChD,MAAM,OAAO,GAAG,IAAI,iBAAiB,EAAE,CAAA;AAEvC,SAAS,YAAY,CACpB,MAAiB,EACjB,QAA4B;IAE5B,OAAO,SAAS,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAe,CAAA;AAChE,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,cAAc,CAAM,MAAiB;IACpD,MAAM,UAAU,GAAG,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAChD,OAAO;QACN,WAAW,EAAE;YACZ,OAAO,EAAE,CAAC;YACV,MAAM,EAAE,SAAS;YACjB,QAAQ,EAAE,CAAC,KAAK,EAAE,EAAE;gBACnB,MAAM,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,UAAU,EAAE,KAAK,CAAQ,CAAA;gBACxD,MAAM,MAAM,GAAG,CACd,MAA+D,EAC9D,EAAE,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAA;gBACrE,MAAM,MAAM,GAAG,MAAM,CAAC,WAAW,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAA;gBACpD,OAAO,MAAM,YAAY,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAA;YACxE,CAAC;YACD,UAAU,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,UAAU,EAAE;SACjE;KACD,CAAA;AACF,CAAC;AAED,8EAA8E;AAC9E,MAAM,UAAU,uBAAuB,CACtC,MAAiB;IAEjB,MAAM,UAAU,GAAG,YAAY,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAA;IACjD,OAAO;QACN,WAAW,EAAE;YACZ,OAAO,EAAE,CAAC;YACV,MAAM,EAAE,SAAS;YACjB,QAAQ,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,KAAa,EAAE,CAAC;YAC/C,UAAU,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,UAAU,EAAE;SACjE;KACD,CAAA;AACF,CAAC","sourcesContent":["import type { AnySchema } from '@orpc/contract'\nimport { JsonSchemaCoercer } from '@orpc/json-schema'\nimport { ZodToJsonSchemaConverter } from '@orpc/zod/zod4'\n\nexport type JsonSchema = Record<string, unknown>\n\n/**\n * A Standard Schema with JSON Schema attached, as MCP SDKs and Mastra expect.\n * `TIn` is what is validated and what `validate` returns.\n */\nexport type ToolSchema<TIn = unknown, TOut = TIn> = {\n\t'~standard': {\n\t\tversion: 1\n\t\tvendor: string\n\t\tvalidate: (\n\t\t\tvalue: unknown\n\t\t) =>\n\t\t\t| { value: TOut; issues?: undefined }\n\t\t\t| { issues: ReadonlyArray<{ message: string }> }\n\t\t\t| Promise<\n\t\t\t\t\t| { value: TOut; issues?: undefined }\n\t\t\t\t\t| { issues: ReadonlyArray<{ message: string }> }\n\t\t\t >\n\t\ttypes?: { input: TIn; output: TOut }\n\t\tjsonSchema: {\n\t\t\tinput: (options?: unknown) => JsonSchema\n\t\t\toutput: (options?: unknown) => JsonSchema\n\t\t}\n\t}\n}\n\nconst converter = new ZodToJsonSchemaConverter()\nconst coercer = new JsonSchemaCoercer()\n\nfunction toJsonSchema(\n\tschema: AnySchema,\n\tstrategy: 'input' | 'output'\n): JsonSchema {\n\treturn converter.convert(schema, { strategy })[1] as JsonSchema\n}\n\n/**\n * Tool input that validates like the procedure but returns the RAW input for\n * the procedure's own input schema to parse. Transforms run in both passes\n * but never on their own output, which handing over the parsed value would do. Zod's JSON Schema export rejects types like\n * `z.date()`; oRPC's converter gives the same JSON Schema as the OpenAPI docs\n * (dates become string/date-time), and clients send those dates as strings,\n * so values are coerced back before validating.\n */\nexport function rawInputSchema<TIn>(schema: AnySchema): ToolSchema<TIn> {\n\tconst jsonSchema = toJsonSchema(schema, 'input')\n\treturn {\n\t\t'~standard': {\n\t\t\tversion: 1,\n\t\t\tvendor: 'orpc-fn',\n\t\t\tvalidate: (value) => {\n\t\t\t\tconst coerced = coercer.coerce(jsonSchema, value) as TIn\n\t\t\t\tconst finish = (\n\t\t\t\t\tresult: Awaited<ReturnType<AnySchema['~standard']['validate']>>\n\t\t\t\t) => (result.issues ? { issues: result.issues } : { value: coerced })\n\t\t\t\tconst result = schema['~standard'].validate(coerced)\n\t\t\t\treturn result instanceof Promise ? result.then(finish) : finish(result)\n\t\t\t},\n\t\t\tjsonSchema: { input: () => jsonSchema, output: () => jsonSchema }\n\t\t}\n\t}\n}\n\n/** Tool output the procedure already validated: described, passed through. */\nexport function passThroughOutputSchema<TOut>(\n\tschema: AnySchema\n): ToolSchema<TOut> {\n\tconst jsonSchema = toJsonSchema(schema, 'output')\n\treturn {\n\t\t'~standard': {\n\t\t\tversion: 1,\n\t\t\tvendor: 'orpc-fn',\n\t\t\tvalidate: (value) => ({ value: value as TOut }),\n\t\t\tjsonSchema: { input: () => jsonSchema, output: () => jsonSchema }\n\t\t}\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"json-schema.js","sourceRoot":"","sources":["../src/json-schema.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AACrD,OAAO,EAAE,wBAAwB,EAAE,MAAM,gBAAgB,CAAA;AA6BzD,MAAM,SAAS,GAAG,IAAI,wBAAwB,EAAE,CAAA;AAChD,MAAM,OAAO,GAAG,IAAI,iBAAiB,EAAE,CAAA;AAEvC,SAAS,YAAY,CACpB,MAAiB,EACjB,QAA4B;IAE5B,OAAO,SAAS,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAe,CAAA;AAChE,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,cAAc,CAAM,MAAiB;IACpD,MAAM,UAAU,GAAG,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAChD,OAAO;QACN,WAAW,EAAE;YACZ,OAAO,EAAE,CAAC;YACV,MAAM,EAAE,SAAS;YACjB,QAAQ,EAAE,CAAC,KAAK,EAAE,EAAE;gBACnB,MAAM,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,UAAU,EAAE,KAAK,CAAQ,CAAA;gBACxD,MAAM,MAAM,GAAG,CACd,MAA+D,EAC9D,EAAE,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAA;gBACrE,MAAM,MAAM,GAAG,MAAM,CAAC,WAAW,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAA;gBACpD,OAAO,MAAM,YAAY,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAA;YACxE,CAAC;YACD,UAAU,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,UAAU,EAAE;SACjE;KACD,CAAA;AACF,CAAC;AAED,8EAA8E;AAC9E,MAAM,UAAU,uBAAuB,CACtC,MAAiB;IAEjB,MAAM,UAAU,GAAG,YAAY,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAA;IACjD,OAAO;QACN,WAAW,EAAE;YACZ,OAAO,EAAE,CAAC;YACV,MAAM,EAAE,SAAS;YACjB,QAAQ,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,KAAa,EAAE,CAAC;YAC/C,UAAU,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,UAAU,EAAE;SACjE;KACD,CAAA;AACF,CAAC;AAED,6EAA6E;AAC7E,MAAM,UAAU,kBAAkB,CAAC,MAAkB;IACpD,IAAI,MAAM,CAAC,IAAI,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAA;IACzC,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,IAAI,MAAM,CAAC,KAAK,CAAA;IAC1C,OAAO,CACN,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QACpB,KAAK,CAAC,MAAM,GAAG,CAAC;QAChB,KAAK,CAAC,KAAK,CACV,CAAC,MAAM,EAAE,EAAE,CACV,OAAO,MAAM,KAAK,QAAQ;YAC1B,MAAM,KAAK,IAAI;YACf,kBAAkB,CAAC,MAAM,CAAC,CAC3B,CACD,CAAA;AACF,CAAC","sourcesContent":["import type { AnySchema } from '@orpc/contract'\nimport { JsonSchemaCoercer } from '@orpc/json-schema'\nimport { ZodToJsonSchemaConverter } from '@orpc/zod/zod4'\n\nexport type JsonSchema = Record<string, unknown>\n\n/**\n * A Standard Schema with JSON Schema attached, as MCP SDKs and Mastra expect.\n * `TIn` is what is validated and what `validate` returns.\n */\nexport type ToolSchema<TIn = unknown, TOut = TIn> = {\n\t'~standard': {\n\t\tversion: 1\n\t\tvendor: string\n\t\tvalidate: (\n\t\t\tvalue: unknown\n\t\t) =>\n\t\t\t| { value: TOut; issues?: undefined }\n\t\t\t| { issues: ReadonlyArray<{ message: string }> }\n\t\t\t| Promise<\n\t\t\t\t\t| { value: TOut; issues?: undefined }\n\t\t\t\t\t| { issues: ReadonlyArray<{ message: string }> }\n\t\t\t >\n\t\ttypes?: { input: TIn; output: TOut }\n\t\tjsonSchema: {\n\t\t\tinput: (options?: unknown) => JsonSchema\n\t\t\toutput: (options?: unknown) => JsonSchema\n\t\t}\n\t}\n}\n\nconst converter = new ZodToJsonSchemaConverter()\nconst coercer = new JsonSchemaCoercer()\n\nfunction toJsonSchema(\n\tschema: AnySchema,\n\tstrategy: 'input' | 'output'\n): JsonSchema {\n\treturn converter.convert(schema, { strategy })[1] as JsonSchema\n}\n\n/**\n * Tool input that validates like the procedure but returns the RAW input for\n * the procedure's own input schema to parse. Transforms run in both passes\n * but never on their own output, which handing over the parsed value would do. Zod's JSON Schema export rejects types like\n * `z.date()`; oRPC's converter gives the same JSON Schema as the OpenAPI docs\n * (dates become string/date-time), and clients send those dates as strings,\n * so values are coerced back before validating.\n */\nexport function rawInputSchema<TIn>(schema: AnySchema): ToolSchema<TIn> {\n\tconst jsonSchema = toJsonSchema(schema, 'input')\n\treturn {\n\t\t'~standard': {\n\t\t\tversion: 1,\n\t\t\tvendor: 'orpc-fn',\n\t\t\tvalidate: (value) => {\n\t\t\t\tconst coerced = coercer.coerce(jsonSchema, value) as TIn\n\t\t\t\tconst finish = (\n\t\t\t\t\tresult: Awaited<ReturnType<AnySchema['~standard']['validate']>>\n\t\t\t\t) => (result.issues ? { issues: result.issues } : { value: coerced })\n\t\t\t\tconst result = schema['~standard'].validate(coerced)\n\t\t\t\treturn result instanceof Promise ? result.then(finish) : finish(result)\n\t\t\t},\n\t\t\tjsonSchema: { input: () => jsonSchema, output: () => jsonSchema }\n\t\t}\n\t}\n}\n\n/** Tool output the procedure already validated: described, passed through. */\nexport function passThroughOutputSchema<TOut>(\n\tschema: AnySchema\n): ToolSchema<TOut> {\n\tconst jsonSchema = toJsonSchema(schema, 'output')\n\treturn {\n\t\t'~standard': {\n\t\t\tversion: 1,\n\t\t\tvendor: 'orpc-fn',\n\t\t\tvalidate: (value) => ({ value: value as TOut }),\n\t\t\tjsonSchema: { input: () => jsonSchema, output: () => jsonSchema }\n\t\t}\n\t}\n}\n\n/** Tool protocols permit unions only when every branch accepts an object. */\nexport function isObjectJsonSchema(schema: JsonSchema): boolean {\n\tif (schema.type === 'object') return true\n\tconst union = schema.anyOf ?? schema.oneOf\n\treturn (\n\t\tArray.isArray(union) &&\n\t\tunion.length > 0 &&\n\t\tunion.every(\n\t\t\t(branch) =>\n\t\t\t\ttypeof branch === 'object' &&\n\t\t\t\tbranch !== null &&\n\t\t\t\tisObjectJsonSchema(branch)\n\t\t)\n\t)\n}\n"]}
|
package/dist/live/codec.d.ts
CHANGED
|
@@ -4,6 +4,11 @@
|
|
|
4
4
|
* intact. Payloads without the envelope are read as plain JSON, so a
|
|
5
5
|
* publisher on the old format keeps working during a rolling deploy.
|
|
6
6
|
*/
|
|
7
|
-
export declare function encodePayload(value: unknown): string;
|
|
7
|
+
export declare function encodePayload(value: unknown, id?: string): string;
|
|
8
8
|
export declare function decodePayload(payload: string): unknown;
|
|
9
|
+
/** IDs distinguish replay/live overlap; legacy payloads remain readable. */
|
|
10
|
+
export declare function decodeMessage(payload: string): {
|
|
11
|
+
id: string | undefined;
|
|
12
|
+
value: unknown;
|
|
13
|
+
};
|
|
9
14
|
//# sourceMappingURL=codec.d.ts.map
|
package/dist/live/codec.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"codec.d.ts","sourceRoot":"","sources":["../../src/live/codec.ts"],"names":[],"mappings":"AAKA;;;;;GAKG;AACH,wBAAgB,aAAa,
|
|
1
|
+
{"version":3,"file":"codec.d.ts","sourceRoot":"","sources":["../../src/live/codec.ts"],"names":[],"mappings":"AAKA;;;;;GAKG;AACH,wBAAgB,aAAa,CAC5B,KAAK,EAAE,OAAO,EACd,EAAE,GAAE,MAA4B,GAC9B,MAAM,CAMR;AAED,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAWtD;AAED,4EAA4E;AAC5E,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG;IAC/C,EAAE,EAAE,MAAM,GAAG,SAAS,CAAA;IACtB,KAAK,EAAE,OAAO,CAAA;CACd,CAUA"}
|
package/dist/live/codec.js
CHANGED
|
@@ -7,21 +7,32 @@ const MARKER = 'orpc-fn';
|
|
|
7
7
|
* intact. Payloads without the envelope are read as plain JSON, so a
|
|
8
8
|
* publisher on the old format keeps working during a rolling deploy.
|
|
9
9
|
*/
|
|
10
|
-
export function encodePayload(value) {
|
|
10
|
+
export function encodePayload(value, id = crypto.randomUUID()) {
|
|
11
11
|
const [json, meta, maps, blobs] = serializer.serialize(value);
|
|
12
12
|
if (maps.length > 0 || blobs.length > 0) {
|
|
13
13
|
throw new TypeError('orpc-fn: pub/sub events cannot contain files or blobs');
|
|
14
14
|
}
|
|
15
|
-
return JSON.stringify({ [MARKER]:
|
|
15
|
+
return JSON.stringify({ [MARKER]: 2, id, json, meta });
|
|
16
16
|
}
|
|
17
17
|
export function decodePayload(payload) {
|
|
18
18
|
const parsed = JSON.parse(payload);
|
|
19
19
|
if (typeof parsed === 'object' &&
|
|
20
20
|
parsed !== null &&
|
|
21
|
-
parsed[MARKER]
|
|
21
|
+
[1, 2].includes(Number(parsed[MARKER]))) {
|
|
22
22
|
const { json, meta } = parsed;
|
|
23
23
|
return serializer.deserialize(json, meta);
|
|
24
24
|
}
|
|
25
25
|
return parsed;
|
|
26
26
|
}
|
|
27
|
+
/** IDs distinguish replay/live overlap; legacy payloads remain readable. */
|
|
28
|
+
export function decodeMessage(payload) {
|
|
29
|
+
const envelope = JSON.parse(payload);
|
|
30
|
+
const id = typeof envelope === 'object' &&
|
|
31
|
+
envelope !== null &&
|
|
32
|
+
envelope[MARKER] === 2 &&
|
|
33
|
+
typeof envelope.id === 'string'
|
|
34
|
+
? envelope.id
|
|
35
|
+
: undefined;
|
|
36
|
+
return { id, value: decodePayload(payload) };
|
|
37
|
+
}
|
|
27
38
|
//# sourceMappingURL=codec.js.map
|
package/dist/live/codec.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"codec.js","sourceRoot":"","sources":["../../src/live/codec.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,yBAAyB,EAAE,MAAM,uBAAuB,CAAA;AAEjE,MAAM,UAAU,GAAG,IAAI,yBAAyB,EAAE,CAAA;AAClD,MAAM,MAAM,GAAG,SAAS,CAAA;AAExB;;;;;GAKG;AACH,MAAM,UAAU,aAAa,CAAC,
|
|
1
|
+
{"version":3,"file":"codec.js","sourceRoot":"","sources":["../../src/live/codec.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,yBAAyB,EAAE,MAAM,uBAAuB,CAAA;AAEjE,MAAM,UAAU,GAAG,IAAI,yBAAyB,EAAE,CAAA;AAClD,MAAM,MAAM,GAAG,SAAS,CAAA;AAExB;;;;;GAKG;AACH,MAAM,UAAU,aAAa,CAC5B,KAAc,EACd,EAAE,GAAW,MAAM,CAAC,UAAU,EAAE;IAEhC,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,CAAC,GAAG,UAAU,CAAC,SAAS,CAAC,KAAK,CAAC,CAAA;IAC7D,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACzC,MAAM,IAAI,SAAS,CAAC,uDAAuD,CAAC,CAAA;IAC7E,CAAC;IACD,OAAO,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAA;AACvD,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,OAAe;IAC5C,MAAM,MAAM,GAAY,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAA;IAC3C,IACC,OAAO,MAAM,KAAK,QAAQ;QAC1B,MAAM,KAAK,IAAI;QACf,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAE,MAAkC,CAAC,MAAM,CAAC,CAAC,CAAC,EACnE,CAAC;QACF,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,MAAqC,CAAA;QAC5D,OAAO,UAAU,CAAC,WAAW,CAAC,IAAI,EAAE,IAAI,CAAC,CAAA;IAC1C,CAAC;IACD,OAAO,MAAM,CAAA;AACd,CAAC;AAED,4EAA4E;AAC5E,MAAM,UAAU,aAAa,CAAC,OAAe;IAI5C,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAY,CAAA;IAC/C,MAAM,EAAE,GACP,OAAO,QAAQ,KAAK,QAAQ;QAC5B,QAAQ,KAAK,IAAI;QAChB,QAAoC,CAAC,MAAM,CAAC,KAAK,CAAC;QACnD,OAAQ,QAAoC,CAAC,EAAE,KAAK,QAAQ;QAC3D,CAAC,CAAE,QAA2B,CAAC,EAAE;QACjC,CAAC,CAAC,SAAS,CAAA;IACb,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,aAAa,CAAC,OAAO,CAAC,EAAE,CAAA;AAC7C,CAAC","sourcesContent":["import { StandardRPCJsonSerializer } from '@orpc/client/standard'\n\nconst serializer = new StandardRPCJsonSerializer()\nconst MARKER = 'orpc-fn'\n\n/**\n * Wire format for pub/sub payloads: oRPC's own JSON serializer, so values\n * plain JSON loses (`Date`, `Map`, `Set`, `BigInt`, `URL`, `undefined`) arrive\n * intact. Payloads without the envelope are read as plain JSON, so a\n * publisher on the old format keeps working during a rolling deploy.\n */\nexport function encodePayload(\n\tvalue: unknown,\n\tid: string = crypto.randomUUID()\n): string {\n\tconst [json, meta, maps, blobs] = serializer.serialize(value)\n\tif (maps.length > 0 || blobs.length > 0) {\n\t\tthrow new TypeError('orpc-fn: pub/sub events cannot contain files or blobs')\n\t}\n\treturn JSON.stringify({ [MARKER]: 2, id, json, meta })\n}\n\nexport function decodePayload(payload: string): unknown {\n\tconst parsed: unknown = JSON.parse(payload)\n\tif (\n\t\ttypeof parsed === 'object' &&\n\t\tparsed !== null &&\n\t\t[1, 2].includes(Number((parsed as Record<string, unknown>)[MARKER]))\n\t) {\n\t\tconst { json, meta } = parsed as { json: unknown; meta: [] }\n\t\treturn serializer.deserialize(json, meta)\n\t}\n\treturn parsed\n}\n\n/** IDs distinguish replay/live overlap; legacy payloads remain readable. */\nexport function decodeMessage(payload: string): {\n\tid: string | undefined\n\tvalue: unknown\n} {\n\tconst envelope = JSON.parse(payload) as unknown\n\tconst id =\n\t\ttypeof envelope === 'object' &&\n\t\tenvelope !== null &&\n\t\t(envelope as Record<string, unknown>)[MARKER] === 2 &&\n\t\ttypeof (envelope as Record<string, unknown>).id === 'string'\n\t\t\t? (envelope as { id: string }).id\n\t\t\t: undefined\n\treturn { id, value: decodePayload(payload) }\n}\n"]}
|
package/dist/live/fn-live.d.ts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import type { Schema } from '@orpc/contract';
|
|
1
|
+
import type { AnySchema, ErrorMap, Schema } from '@orpc/contract';
|
|
2
2
|
import { type AnyProcedure } from '@orpc/server';
|
|
3
3
|
import type { ZodType, z } from 'zod';
|
|
4
|
+
import { RAW_INPUT } from '../timing.js';
|
|
4
5
|
import type { FnLogger } from '../logger.js';
|
|
5
6
|
import { type SpanLike } from '../otel.js';
|
|
6
7
|
import type { FnContext, FnDefinition, FnProcedure, FnRouteOptions, HandlerParams, MaybePromise, ProcedureKey } from '../types.js';
|
|
7
|
-
import type { AuthFn, Channel, ChannelDefinition, ChannelOptions, ObjectSchema, PublisherConfig } from './pub-sub.js';
|
|
8
|
+
import type { AuthFn, Channel, ChannelDefinition, ChannelOptions, ChannelQueueOptions, ObjectSchema, PublisherConfig } from './pub-sub.js';
|
|
8
9
|
declare const fnLivePatchMarker: unique symbol;
|
|
9
10
|
/**
|
|
10
11
|
* Transformer result that splits the internal accumulator from the wire
|
|
@@ -18,27 +19,31 @@ export type FnLivePatch<TOutput, TEmit> = {
|
|
|
18
19
|
emit: TEmit;
|
|
19
20
|
};
|
|
20
21
|
export declare function fnLivePatch<TOutput, TEmit>(state: TOutput, emit: TEmit): FnLivePatch<TOutput, TEmit>;
|
|
21
|
-
export type FnLiveConfig<TDef extends FnDefinition, TInput, TEventSchema extends ZodType, TOutput, TKey extends ProcedureKey<TDef>, TEmit = never
|
|
22
|
+
export type FnLiveConfig<TDef extends FnDefinition, TInput, TEventSchema extends ZodType, TOutput, TKey extends ProcedureKey<TDef>, TEmit = never, TErrors extends ErrorMap = Record<never, never>> = Omit<PublisherConfig, 'name'> & ChannelQueueOptions & {
|
|
22
23
|
/** Subscribe route name; default `${name}.live`. */
|
|
23
24
|
name?: string;
|
|
25
|
+
/** Validates parsed reducer state without reapplying an output transform. Required with a transformer. */
|
|
26
|
+
stateSchema?: Schema<TOutput, TOutput>;
|
|
27
|
+
/** Validates patch payloads. Required when a transformer returns fnLivePatch. */
|
|
28
|
+
emitSchema?: Schema<TEmit, TEmit>;
|
|
29
|
+
/** Optional access check before each update; idle streams keep their initial authorization. */
|
|
30
|
+
reauthorize?: AuthFn<TInput, FnContext<TDef, TKey>>;
|
|
24
31
|
eventSchema: TEventSchema;
|
|
25
32
|
channel: ChannelDefinition<TInput, z.output<TEventSchema>, FnContext<TDef, TKey>>;
|
|
26
33
|
/** Fold an event into the snapshot; without it every event re-runs the handler. */
|
|
27
|
-
transformerFn?:
|
|
28
|
-
event: z.output<TEventSchema>;
|
|
29
|
-
previous: TOutput | undefined;
|
|
30
|
-
rerun: (input?: TInput) => Promise<TOutput>;
|
|
31
|
-
}) => MaybePromise<TOutput | FnLivePatch<TOutput, TEmit> | undefined>;
|
|
34
|
+
transformerFn?: FnLiveConfigTransformer<TDef, TInput, TEventSchema, TOutput, TKey, TEmit, TErrors>;
|
|
32
35
|
/** Return false to skip an event. */
|
|
33
|
-
shouldUpdate?: (params: HandlerParams<TDef, TInput, TKey> & {
|
|
36
|
+
shouldUpdate?: (params: HandlerParams<TDef, TInput, TKey, TErrors> & {
|
|
34
37
|
event: z.output<TEventSchema>;
|
|
35
|
-
previous: TOutput
|
|
38
|
+
previous: TOutput;
|
|
36
39
|
}) => MaybePromise<boolean>;
|
|
37
40
|
authFn?: AuthFn<TInput, FnContext<TDef, TKey>>;
|
|
38
41
|
/** Log publish failures instead of throwing them into the publishing route. */
|
|
39
42
|
safePublish?: boolean;
|
|
40
43
|
/** Batch events arriving within this window into one snapshot update. */
|
|
41
44
|
coalesceMs?: number;
|
|
45
|
+
/** Maximum events collected in one coalescing batch (default 1000). */
|
|
46
|
+
maxBatchSize?: number;
|
|
42
47
|
/**
|
|
43
48
|
* When a slow subscriber's queue overflows (drop-oldest), this marker is
|
|
44
49
|
* enqueued INSTEAD of the dropped event so the client resyncs. Return
|
|
@@ -47,11 +52,29 @@ export type FnLiveConfig<TDef extends FnDefinition, TInput, TEventSchema extends
|
|
|
47
52
|
overflowMarker?: (input: TInput) => z.output<TEventSchema> | null;
|
|
48
53
|
summary?: string;
|
|
49
54
|
description?: string;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
55
|
+
} & ({
|
|
56
|
+
transformerFn?: undefined;
|
|
57
|
+
} | {
|
|
58
|
+
transformerFn: FnLiveConfigTransformer<TDef, TInput, TEventSchema, TOutput, TKey, TEmit, TErrors>;
|
|
59
|
+
stateSchema: Schema<TOutput, TOutput>;
|
|
60
|
+
}) & ([TEmit] extends [never] ? object : {
|
|
61
|
+
emitSchema: Schema<TEmit, TEmit>;
|
|
62
|
+
});
|
|
63
|
+
type FnLiveConfigTransformer<TDef extends FnDefinition, TInput, TEventSchema extends ZodType, TOutput, TKey extends ProcedureKey<TDef>, TEmit, TErrors extends ErrorMap> = (params: HandlerParams<TDef, TInput, TKey, TErrors> & {
|
|
64
|
+
event: z.output<TEventSchema>;
|
|
65
|
+
previous: TOutput;
|
|
66
|
+
rerun: () => Promise<TOutput>;
|
|
67
|
+
}) => MaybePromise<TOutput | FnLivePatch<TOutput, TEmit> | undefined>;
|
|
68
|
+
export type FnLiveReturn<TDef extends FnDefinition, TKey extends ProcedureKey<TDef>, TInput extends ObjectSchema, TOutputSchema extends Schema<unknown, unknown>, TOutput, TEventSchema extends ZodType, TEmit = never, TErrors extends ErrorMap = Record<never, never>> = {
|
|
69
|
+
procedure: FnProcedure<TDef, TKey, TInput, TOutputSchema, TErrors>;
|
|
70
|
+
subscribe: FnProcedure<TDef, TKey, TInput, Schema<AsyncGenerator<TOutput | TEmit>, AsyncGenerator<TOutput | TEmit>>, TErrors>;
|
|
54
71
|
publish: (event: z.input<TEventSchema>) => Promise<void>;
|
|
72
|
+
getSubscriptionChannelName: (params: {
|
|
73
|
+
input: z.output<TInput>;
|
|
74
|
+
context: FnContext<TDef, TKey>;
|
|
75
|
+
}) => string;
|
|
76
|
+
getPublishChannelName: (event: z.output<TEventSchema>) => string;
|
|
77
|
+
/** @deprecated Prefer the separate required-input resolver methods. */
|
|
55
78
|
getChannelName: (params: Partial<z.output<TInput>> | Partial<z.output<TEventSchema>>, context?: FnContext<TDef, TKey>) => string;
|
|
56
79
|
};
|
|
57
80
|
/**
|
|
@@ -59,22 +82,22 @@ export type FnLiveReturn<TDef extends FnDefinition, TKey extends ProcedureKey<TD
|
|
|
59
82
|
* snapshot, then an update for every event published on the channel.
|
|
60
83
|
*/
|
|
61
84
|
export interface FnLive<TDef extends FnDefinition> {
|
|
62
|
-
<TInput extends ObjectSchema, TOutputSchema extends ZodType, TEventSchema extends ZodType, TKey extends ProcedureKey<TDef> = TDef['default'], TEmit = never
|
|
85
|
+
<TInput extends ObjectSchema, TOutputSchema extends ZodType, TEventSchema extends ZodType, TKey extends ProcedureKey<TDef> = TDef['default'], TEmit = never, TErrors extends ErrorMap = Record<never, never>>(options: {
|
|
63
86
|
input: TInput;
|
|
64
87
|
output: TOutputSchema;
|
|
65
|
-
handler: (params: HandlerParams<TDef, z.output<TInput>, NoInfer<TKey
|
|
88
|
+
handler: (params: HandlerParams<TDef, z.output<TInput>, NoInfer<TKey>, TErrors> & {
|
|
66
89
|
publish: (event: z.input<TEventSchema>) => Promise<void>;
|
|
67
90
|
}) => MaybePromise<z.input<TOutputSchema>>;
|
|
68
|
-
live: FnLiveConfig<TDef, z.output<TInput>, TEventSchema, z.output<TOutputSchema>, NoInfer<TKey>, TEmit>;
|
|
69
|
-
} & FnRouteOptions<TDef, TKey>): FnLiveReturn<TDef, TKey, TInput, TOutputSchema, z.output<TOutputSchema>, TEventSchema, TEmit>;
|
|
70
|
-
<TInput extends ObjectSchema, TOutput, TEventSchema extends ZodType, TKey extends ProcedureKey<TDef> = TDef['default'], TEmit = never
|
|
91
|
+
live: FnLiveConfig<TDef, z.output<TInput>, TEventSchema, z.output<TOutputSchema>, NoInfer<TKey>, TEmit, TErrors>;
|
|
92
|
+
} & FnRouteOptions<TDef, TKey, z.output<TInput>, TErrors>): FnLiveReturn<TDef, TKey, TInput, TOutputSchema, z.output<TOutputSchema>, TEventSchema, TEmit, TErrors>;
|
|
93
|
+
<TInput extends ObjectSchema, TOutput, TEventSchema extends ZodType, TKey extends ProcedureKey<TDef> = TDef['default'], TEmit = never, TErrors extends ErrorMap = Record<never, never>>(options: {
|
|
71
94
|
input: TInput;
|
|
72
95
|
output?: undefined;
|
|
73
|
-
handler: (params: HandlerParams<TDef, z.output<TInput>, NoInfer<TKey
|
|
96
|
+
handler: (params: HandlerParams<TDef, z.output<TInput>, NoInfer<TKey>, TErrors> & {
|
|
74
97
|
publish: (event: z.input<TEventSchema>) => Promise<void>;
|
|
75
98
|
}) => MaybePromise<TOutput>;
|
|
76
|
-
live: FnLiveConfig<TDef, z.output<TInput>, TEventSchema, TOutput, NoInfer<TKey>, TEmit>;
|
|
77
|
-
} & FnRouteOptions<TDef, TKey>): FnLiveReturn<TDef, TKey, TInput, Schema<TOutput, TOutput>, TOutput, TEventSchema, TEmit>;
|
|
99
|
+
live: FnLiveConfig<TDef, z.output<TInput>, TEventSchema, TOutput, NoInfer<TKey>, TEmit, TErrors>;
|
|
100
|
+
} & FnRouteOptions<TDef, TKey, z.output<TInput>, TErrors>): FnLiveReturn<TDef, TKey, TInput, Schema<TOutput, TOutput>, TOutput, TEventSchema, TEmit, TErrors>;
|
|
78
101
|
}
|
|
79
102
|
/**
|
|
80
103
|
* Fail a live subscription whose initial snapshot could not be built.
|
|
@@ -104,6 +127,9 @@ isExpected?: (error: unknown) => boolean): never;
|
|
|
104
127
|
*/
|
|
105
128
|
export declare function streamLiveSnapshots<TEvent, TOutput, TEmit = never>(opts: {
|
|
106
129
|
source: AsyncIterator<TEvent>;
|
|
130
|
+
/** Maximum events retained in one coalescing batch. */
|
|
131
|
+
maxBatchSize?: number;
|
|
132
|
+
applyBatch?: (events: readonly TEvent[], previous: TOutput) => MaybePromise<TOutput | undefined>;
|
|
107
133
|
initial: TOutput;
|
|
108
134
|
coalesceMs?: number | undefined;
|
|
109
135
|
apply: (event: TEvent, previous: TOutput) => MaybePromise<TOutput | FnLivePatch<TOutput, TEmit> | undefined>;
|
|
@@ -113,14 +139,20 @@ type RuntimeParams = Record<string, unknown> & {
|
|
|
113
139
|
context: unknown;
|
|
114
140
|
signal: AbortSignal | undefined;
|
|
115
141
|
logger: FnLogger;
|
|
142
|
+
call: (procedure: AnyProcedure, input: unknown) => Promise<unknown>;
|
|
143
|
+
[RAW_INPUT]: unknown;
|
|
116
144
|
};
|
|
117
145
|
/** `FnLiveConfig` with the generics erased: what the implementation reads. */
|
|
118
146
|
type RuntimeLiveConfig = Omit<ChannelOptions, 'name'> & {
|
|
119
147
|
name?: string;
|
|
148
|
+
stateSchema?: AnySchema;
|
|
149
|
+
emitSchema?: AnySchema;
|
|
150
|
+
reauthorize?: AuthFn<Record<string, unknown>, unknown>;
|
|
120
151
|
transformerFn?: (params: RuntimeParams & Record<string, unknown>) => unknown;
|
|
121
152
|
shouldUpdate?: (params: RuntimeParams & Record<string, unknown>) => unknown;
|
|
122
153
|
safePublish?: boolean;
|
|
123
154
|
coalesceMs?: number;
|
|
155
|
+
maxBatchSize?: number;
|
|
124
156
|
summary?: string;
|
|
125
157
|
description?: string;
|
|
126
158
|
};
|
|
@@ -150,6 +182,15 @@ export declare function createFnLive(runtime: {
|
|
|
150
182
|
getChannelName: (params: {
|
|
151
183
|
[x: string]: unknown;
|
|
152
184
|
}, context?: unknown) => string;
|
|
185
|
+
getSubscriptionChannelName: (params: {
|
|
186
|
+
input: {
|
|
187
|
+
[x: string]: unknown;
|
|
188
|
+
};
|
|
189
|
+
context: unknown;
|
|
190
|
+
}) => string;
|
|
191
|
+
getPublishChannelName: (event: {
|
|
192
|
+
[x: string]: unknown;
|
|
193
|
+
}) => string;
|
|
153
194
|
};
|
|
154
195
|
export {};
|
|
155
196
|
//# sourceMappingURL=fn-live.d.ts.map
|