orpc-fn 0.1.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/LICENSE +21 -0
- package/README.md +250 -0
- package/dist/bound-call.d.ts +23 -0
- package/dist/bound-call.d.ts.map +1 -0
- package/dist/bound-call.js +23 -0
- package/dist/bound-call.js.map +1 -0
- package/dist/client.d.ts +44 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +49 -0
- package/dist/client.js.map +1 -0
- package/dist/create-fn.d.ts +97 -0
- package/dist/create-fn.d.ts.map +1 -0
- package/dist/create-fn.js +224 -0
- package/dist/create-fn.js.map +1 -0
- package/dist/expected-client-error.d.ts +11 -0
- package/dist/expected-client-error.d.ts.map +1 -0
- package/dist/expected-client-error.js +21 -0
- package/dist/expected-client-error.js.map +1 -0
- package/dist/expo.d.ts +66 -0
- package/dist/expo.d.ts.map +1 -0
- package/dist/expo.js +74 -0
- package/dist/expo.js.map +1 -0
- package/dist/hono.d.ts +81 -0
- package/dist/hono.d.ts.map +1 -0
- package/dist/hono.js +138 -0
- package/dist/hono.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/dist/json-schema.d.ts +47 -0
- package/dist/json-schema.d.ts.map +1 -0
- package/dist/json-schema.js +44 -0
- package/dist/json-schema.js.map +1 -0
- package/dist/live/codec.d.ts +9 -0
- package/dist/live/codec.d.ts.map +1 -0
- package/dist/live/codec.js +27 -0
- package/dist/live/codec.js.map +1 -0
- package/dist/live/fn-live.d.ts +155 -0
- package/dist/live/fn-live.d.ts.map +1 -0
- package/dist/live/fn-live.js +210 -0
- package/dist/live/fn-live.js.map +1 -0
- package/dist/live/index.d.ts +4 -0
- package/dist/live/index.d.ts.map +1 -0
- package/dist/live/index.js +5 -0
- package/dist/live/index.js.map +1 -0
- package/dist/live/ioredis.d.ts +29 -0
- package/dist/live/ioredis.d.ts.map +1 -0
- package/dist/live/ioredis.js +49 -0
- package/dist/live/ioredis.js.map +1 -0
- package/dist/live/memory.d.ts +10 -0
- package/dist/live/memory.d.ts.map +1 -0
- package/dist/live/memory.js +45 -0
- package/dist/live/memory.js.map +1 -0
- package/dist/live/pub-sub.d.ts +211 -0
- package/dist/live/pub-sub.d.ts.map +1 -0
- package/dist/live/pub-sub.js +529 -0
- package/dist/live/pub-sub.js.map +1 -0
- package/dist/live/redis-bun.d.ts +26 -0
- package/dist/live/redis-bun.d.ts.map +1 -0
- package/dist/live/redis-bun.js +59 -0
- package/dist/live/redis-bun.js.map +1 -0
- package/dist/live/redis.d.ts +45 -0
- package/dist/live/redis.d.ts.map +1 -0
- package/dist/live/redis.js +214 -0
- package/dist/live/redis.js.map +1 -0
- package/dist/live/transport.d.ts +35 -0
- package/dist/live/transport.d.ts.map +1 -0
- package/dist/live/transport.js +2 -0
- package/dist/live/transport.js.map +1 -0
- package/dist/logger.d.ts +15 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +15 -0
- package/dist/logger.js.map +1 -0
- package/dist/mastra.d.ts +44 -0
- package/dist/mastra.d.ts.map +1 -0
- package/dist/mastra.js +78 -0
- package/dist/mastra.js.map +1 -0
- package/dist/mcp.d.ts +39 -0
- package/dist/mcp.d.ts.map +1 -0
- package/dist/mcp.js +38 -0
- package/dist/mcp.js.map +1 -0
- package/dist/meta.d.ts +35 -0
- package/dist/meta.d.ts.map +1 -0
- package/dist/meta.js +30 -0
- package/dist/meta.js.map +1 -0
- package/dist/otel.d.ts +66 -0
- package/dist/otel.d.ts.map +1 -0
- package/dist/otel.js +63 -0
- package/dist/otel.js.map +1 -0
- package/dist/router.d.ts +13 -0
- package/dist/router.d.ts.map +1 -0
- package/dist/router.js +14 -0
- package/dist/router.js.map +1 -0
- package/dist/stream.d.ts +13 -0
- package/dist/stream.d.ts.map +1 -0
- package/dist/stream.js +44 -0
- package/dist/stream.js.map +1 -0
- package/dist/types.d.ts +196 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +29 -0
- package/dist/types.js.map +1 -0
- package/package.json +157 -0
- package/src/bound-call.ts +50 -0
- package/src/client.ts +82 -0
- package/src/create-fn.ts +461 -0
- package/src/expected-client-error.ts +23 -0
- package/src/expo.ts +127 -0
- package/src/hono.ts +247 -0
- package/src/index.ts +45 -0
- package/src/json-schema.ts +82 -0
- package/src/live/codec.ts +31 -0
- package/src/live/fn-live.ts +470 -0
- package/src/live/index.ts +31 -0
- package/src/live/ioredis.ts +74 -0
- package/src/live/memory.ts +50 -0
- package/src/live/pub-sub.ts +828 -0
- package/src/live/redis-bun.ts +76 -0
- package/src/live/redis.ts +255 -0
- package/src/live/transport.ts +41 -0
- package/src/logger.ts +28 -0
- package/src/mastra.ts +140 -0
- package/src/mcp.ts +73 -0
- package/src/meta.ts +72 -0
- package/src/otel.ts +151 -0
- package/src/router.ts +15 -0
- package/src/stream.ts +54 -0
- package/src/types.ts +389 -0
package/dist/hono.js
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { SmartCoercionPlugin } from '@orpc/json-schema';
|
|
2
|
+
import { OpenAPIHandler } from '@orpc/openapi/fetch';
|
|
3
|
+
import { OpenAPIReferencePlugin } from '@orpc/openapi/plugins';
|
|
4
|
+
import { onError as orpcOnError } from '@orpc/server';
|
|
5
|
+
import { RPCHandler } from '@orpc/server/fetch';
|
|
6
|
+
import { BatchHandlerPlugin } from '@orpc/server/plugins';
|
|
7
|
+
import { ZodToJsonSchemaConverter } from '@orpc/zod/zod4';
|
|
8
|
+
import { isExpectedClientError } from './expected-client-error.js';
|
|
9
|
+
/**
|
|
10
|
+
* Expo native sends `expo-origin` but not `origin`; copy it so cookie-based
|
|
11
|
+
* auth (e.g. Better Auth) sees the origin.
|
|
12
|
+
*/
|
|
13
|
+
export function normalizeExpoOrigin(raw) {
|
|
14
|
+
const expo = raw.get('expo-origin');
|
|
15
|
+
if (!expo || raw.get('origin'))
|
|
16
|
+
return raw;
|
|
17
|
+
const headers = new Headers(raw);
|
|
18
|
+
headers.set('origin', expo);
|
|
19
|
+
return headers;
|
|
20
|
+
}
|
|
21
|
+
export function formatServerTiming(totalMs, timing) {
|
|
22
|
+
const parts = [`total;dur=${totalMs.toFixed(2)}`];
|
|
23
|
+
for (const [key, value] of Object.entries(timing)) {
|
|
24
|
+
if (value !== undefined) {
|
|
25
|
+
parts.push(`${key.replace(/_ms$/, '')};dur=${value.toFixed(2)}`);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return parts.join(', ');
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Response headers plus Server-Timing. For SSE, also disable proxy buffering
|
|
32
|
+
* so keep-alive comments reach the edge (empty `:` lines are otherwise easy
|
|
33
|
+
* for nginx/Fastly to hold until an idle kill). A copy: some responses (e.g.
|
|
34
|
+
* redirects) have immutable headers.
|
|
35
|
+
*/
|
|
36
|
+
function finishHeaders(response, serverTiming) {
|
|
37
|
+
const headers = new Headers(response.headers);
|
|
38
|
+
if (serverTiming) {
|
|
39
|
+
headers.set('Server-Timing', serverTiming);
|
|
40
|
+
headers.append('Access-Control-Expose-Headers', 'Server-Timing');
|
|
41
|
+
}
|
|
42
|
+
if ((headers.get('content-type') ?? '').includes('text/event-stream')) {
|
|
43
|
+
headers.set('Cache-Control', 'no-cache');
|
|
44
|
+
headers.set('X-Accel-Buffering', 'no');
|
|
45
|
+
}
|
|
46
|
+
return headers;
|
|
47
|
+
}
|
|
48
|
+
/** Mount oRPC's RPC and OpenAPI handlers on a Hono app. */
|
|
49
|
+
export function mountOrpc(app, options) {
|
|
50
|
+
const { router, batch = true, serverTiming = true, sseKeepAlive = true } = options;
|
|
51
|
+
const isExpectedError = options.isExpectedError ?? isExpectedClientError;
|
|
52
|
+
const keepAlive = sseKeepAlive === false
|
|
53
|
+
? { eventIteratorKeepAliveEnabled: false }
|
|
54
|
+
: {
|
|
55
|
+
eventIteratorKeepAliveEnabled: true,
|
|
56
|
+
// Explicit keep-alive under proxy idle timers (~30s); oRPC's default is 5s.
|
|
57
|
+
eventIteratorKeepAliveInterval: sseKeepAlive === true ? 15_000 : sseKeepAlive
|
|
58
|
+
};
|
|
59
|
+
const report = (error, { request }) => {
|
|
60
|
+
if (isExpectedError(error))
|
|
61
|
+
return;
|
|
62
|
+
options.onError?.(error, {
|
|
63
|
+
url: request.url.pathname,
|
|
64
|
+
method: request.method
|
|
65
|
+
});
|
|
66
|
+
};
|
|
67
|
+
const mount = (prefix, handler) => {
|
|
68
|
+
app.use(`${prefix}/*`, async (c, next) => {
|
|
69
|
+
const timing = {};
|
|
70
|
+
const queueMs = options.queueMs?.(c.req.raw);
|
|
71
|
+
if (queueMs !== undefined)
|
|
72
|
+
timing.queue_ms = Math.round(queueMs * 100) / 100;
|
|
73
|
+
const started = performance.now();
|
|
74
|
+
const headers = options.normalizeHeaders
|
|
75
|
+
? options.normalizeHeaders(c.req.raw.headers)
|
|
76
|
+
: c.req.raw.headers;
|
|
77
|
+
const context = options.context
|
|
78
|
+
? await options.context(c, { headers, timing })
|
|
79
|
+
: { headers, timing };
|
|
80
|
+
if (context instanceof Response)
|
|
81
|
+
return context;
|
|
82
|
+
const { matched, response } = await handler.handle(c.req.raw, {
|
|
83
|
+
prefix,
|
|
84
|
+
context: context
|
|
85
|
+
});
|
|
86
|
+
if (!matched)
|
|
87
|
+
return next();
|
|
88
|
+
const timed = serverTiming
|
|
89
|
+
? formatServerTiming(performance.now() - started, timing)
|
|
90
|
+
: undefined;
|
|
91
|
+
return c.newResponse(response.body, {
|
|
92
|
+
// oRPC only produces valid HTTP status codes.
|
|
93
|
+
status: response.status,
|
|
94
|
+
headers: finishHeaders(response, timed)
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
};
|
|
98
|
+
if (options.rpcPrefix) {
|
|
99
|
+
const plugins = [...(options.plugins ?? [])];
|
|
100
|
+
if (batch) {
|
|
101
|
+
plugins.push(new BatchHandlerPlugin({
|
|
102
|
+
maxSize: batch === true ? 25 : batch.maxSize
|
|
103
|
+
}));
|
|
104
|
+
}
|
|
105
|
+
mount(options.rpcPrefix, new RPCHandler(router, {
|
|
106
|
+
...keepAlive,
|
|
107
|
+
plugins,
|
|
108
|
+
interceptors: options.onError ? [orpcOnError(report)] : []
|
|
109
|
+
}));
|
|
110
|
+
}
|
|
111
|
+
if (options.openapi) {
|
|
112
|
+
const { openapi } = options;
|
|
113
|
+
const filter = openapi.filter ? { filter: openapi.filter } : {};
|
|
114
|
+
const converters = [new ZodToJsonSchemaConverter()];
|
|
115
|
+
const plugins = [...(openapi.plugins ?? [])];
|
|
116
|
+
if (openapi.smartCoercion) {
|
|
117
|
+
plugins.push(new SmartCoercionPlugin({ schemaConverters: converters }));
|
|
118
|
+
}
|
|
119
|
+
plugins.push(new OpenAPIReferencePlugin({
|
|
120
|
+
docsProvider: 'scalar',
|
|
121
|
+
...(openapi.docsPath ? { docsPath: openapi.docsPath } : {}),
|
|
122
|
+
schemaConverters: converters,
|
|
123
|
+
specGenerateOptions: {
|
|
124
|
+
info: openapi.info ?? { title: 'API', version: '0.0.0' },
|
|
125
|
+
servers: [{ url: openapi.prefix }],
|
|
126
|
+
...filter,
|
|
127
|
+
...openapi.spec
|
|
128
|
+
}
|
|
129
|
+
}));
|
|
130
|
+
mount(openapi.prefix, new OpenAPIHandler(router, {
|
|
131
|
+
...keepAlive,
|
|
132
|
+
...filter,
|
|
133
|
+
plugins,
|
|
134
|
+
interceptors: options.onError ? [orpcOnError(report)] : []
|
|
135
|
+
}));
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
//# sourceMappingURL=hono.js.map
|
package/dist/hono.js.map
ADDED
|
@@ -0,0 +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"]}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export { type BoundCall, createBoundCall } from './bound-call.js';
|
|
2
|
+
export { type CreateFnOptions, createFn, type FnFactory } from './create-fn.js';
|
|
3
|
+
export { isExpectedClientError } from './expected-client-error.js';
|
|
4
|
+
export { createBoundedEventQueue } from './live/pub-sub.js';
|
|
5
|
+
export { createDefaultLogger, type FnLogger, type LogAttributes } from './logger.js';
|
|
6
|
+
export { FN_META_KEY, type FnMeta, readFnMeta } from './meta.js';
|
|
7
|
+
export type { AttributeValue, OtelApiLike, SpanLike, SpanOf, Tracing } from './otel.js';
|
|
8
|
+
export { createRouter } from './router.js';
|
|
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
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +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;AAChE,YAAY,EACX,cAAc,EACd,WAAW,EACX,QAAQ,EACR,MAAM,EACN,OAAO,EACP,MAAM,WAAW,CAAA;AAClB,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAC1C,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
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { createBoundCall } from './bound-call.js';
|
|
2
|
+
export { createFn } from './create-fn.js';
|
|
3
|
+
export { isExpectedClientError } from './expected-client-error.js';
|
|
4
|
+
export { createBoundedEventQueue } from './live/pub-sub.js';
|
|
5
|
+
export { createDefaultLogger } from './logger.js';
|
|
6
|
+
export { FN_META_KEY, readFnMeta } from './meta.js';
|
|
7
|
+
export { createRouter } from './router.js';
|
|
8
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +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;AAQhE,OAAO,EAAE,YAAY,EAAE,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 { 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 { createRouter } 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"]}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { AnySchema } from '@orpc/contract';
|
|
2
|
+
export type JsonSchema = Record<string, unknown>;
|
|
3
|
+
/**
|
|
4
|
+
* A Standard Schema with JSON Schema attached, as MCP SDKs and Mastra expect.
|
|
5
|
+
* `TIn` is what is validated and what `validate` returns.
|
|
6
|
+
*/
|
|
7
|
+
export type ToolSchema<TIn = unknown, TOut = TIn> = {
|
|
8
|
+
'~standard': {
|
|
9
|
+
version: 1;
|
|
10
|
+
vendor: string;
|
|
11
|
+
validate: (value: unknown) => {
|
|
12
|
+
value: TOut;
|
|
13
|
+
issues?: undefined;
|
|
14
|
+
} | {
|
|
15
|
+
issues: ReadonlyArray<{
|
|
16
|
+
message: string;
|
|
17
|
+
}>;
|
|
18
|
+
} | Promise<{
|
|
19
|
+
value: TOut;
|
|
20
|
+
issues?: undefined;
|
|
21
|
+
} | {
|
|
22
|
+
issues: ReadonlyArray<{
|
|
23
|
+
message: string;
|
|
24
|
+
}>;
|
|
25
|
+
}>;
|
|
26
|
+
types?: {
|
|
27
|
+
input: TIn;
|
|
28
|
+
output: TOut;
|
|
29
|
+
};
|
|
30
|
+
jsonSchema: {
|
|
31
|
+
input: (options?: unknown) => JsonSchema;
|
|
32
|
+
output: (options?: unknown) => JsonSchema;
|
|
33
|
+
};
|
|
34
|
+
};
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* Tool input that validates like the procedure but returns the RAW input for
|
|
38
|
+
* the procedure's own input schema to parse. Transforms run in both passes
|
|
39
|
+
* but never on their own output, which handing over the parsed value would do. Zod's JSON Schema export rejects types like
|
|
40
|
+
* `z.date()`; oRPC's converter gives the same JSON Schema as the OpenAPI docs
|
|
41
|
+
* (dates become string/date-time), and clients send those dates as strings,
|
|
42
|
+
* so values are coerced back before validating.
|
|
43
|
+
*/
|
|
44
|
+
export declare function rawInputSchema<TIn>(schema: AnySchema): ToolSchema<TIn>;
|
|
45
|
+
/** Tool output the procedure already validated: described, passed through. */
|
|
46
|
+
export declare function passThroughOutputSchema<TOut>(schema: AnySchema): ToolSchema<TOut>;
|
|
47
|
+
//# sourceMappingURL=json-schema.d.ts.map
|
|
@@ -0,0 +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"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { JsonSchemaCoercer } from '@orpc/json-schema';
|
|
2
|
+
import { ZodToJsonSchemaConverter } from '@orpc/zod/zod4';
|
|
3
|
+
const converter = new ZodToJsonSchemaConverter();
|
|
4
|
+
const coercer = new JsonSchemaCoercer();
|
|
5
|
+
function toJsonSchema(schema, strategy) {
|
|
6
|
+
return converter.convert(schema, { strategy })[1];
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Tool input that validates like the procedure but returns the RAW input for
|
|
10
|
+
* the procedure's own input schema to parse. Transforms run in both passes
|
|
11
|
+
* but never on their own output, which handing over the parsed value would do. Zod's JSON Schema export rejects types like
|
|
12
|
+
* `z.date()`; oRPC's converter gives the same JSON Schema as the OpenAPI docs
|
|
13
|
+
* (dates become string/date-time), and clients send those dates as strings,
|
|
14
|
+
* so values are coerced back before validating.
|
|
15
|
+
*/
|
|
16
|
+
export function rawInputSchema(schema) {
|
|
17
|
+
const jsonSchema = toJsonSchema(schema, 'input');
|
|
18
|
+
return {
|
|
19
|
+
'~standard': {
|
|
20
|
+
version: 1,
|
|
21
|
+
vendor: 'orpc-fn',
|
|
22
|
+
validate: (value) => {
|
|
23
|
+
const coerced = coercer.coerce(jsonSchema, value);
|
|
24
|
+
const finish = (result) => (result.issues ? { issues: result.issues } : { value: coerced });
|
|
25
|
+
const result = schema['~standard'].validate(coerced);
|
|
26
|
+
return result instanceof Promise ? result.then(finish) : finish(result);
|
|
27
|
+
},
|
|
28
|
+
jsonSchema: { input: () => jsonSchema, output: () => jsonSchema }
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
/** Tool output the procedure already validated: described, passed through. */
|
|
33
|
+
export function passThroughOutputSchema(schema) {
|
|
34
|
+
const jsonSchema = toJsonSchema(schema, 'output');
|
|
35
|
+
return {
|
|
36
|
+
'~standard': {
|
|
37
|
+
version: 1,
|
|
38
|
+
vendor: 'orpc-fn',
|
|
39
|
+
validate: (value) => ({ value: value }),
|
|
40
|
+
jsonSchema: { input: () => jsonSchema, output: () => jsonSchema }
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=json-schema.js.map
|
|
@@ -0,0 +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"]}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wire format for pub/sub payloads: oRPC's own JSON serializer, so values
|
|
3
|
+
* plain JSON loses (`Date`, `Map`, `Set`, `BigInt`, `URL`, `undefined`) arrive
|
|
4
|
+
* intact. Payloads without the envelope are read as plain JSON, so a
|
|
5
|
+
* publisher on the old format keeps working during a rolling deploy.
|
|
6
|
+
*/
|
|
7
|
+
export declare function encodePayload(value: unknown): string;
|
|
8
|
+
export declare function decodePayload(payload: string): unknown;
|
|
9
|
+
//# sourceMappingURL=codec.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"codec.d.ts","sourceRoot":"","sources":["../../src/live/codec.ts"],"names":[],"mappings":"AAKA;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAMpD;AAED,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAWtD"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { StandardRPCJsonSerializer } from '@orpc/client/standard';
|
|
2
|
+
const serializer = new StandardRPCJsonSerializer();
|
|
3
|
+
const MARKER = 'orpc-fn';
|
|
4
|
+
/**
|
|
5
|
+
* Wire format for pub/sub payloads: oRPC's own JSON serializer, so values
|
|
6
|
+
* plain JSON loses (`Date`, `Map`, `Set`, `BigInt`, `URL`, `undefined`) arrive
|
|
7
|
+
* intact. Payloads without the envelope are read as plain JSON, so a
|
|
8
|
+
* publisher on the old format keeps working during a rolling deploy.
|
|
9
|
+
*/
|
|
10
|
+
export function encodePayload(value) {
|
|
11
|
+
const [json, meta, maps, blobs] = serializer.serialize(value);
|
|
12
|
+
if (maps.length > 0 || blobs.length > 0) {
|
|
13
|
+
throw new TypeError('orpc-fn: pub/sub events cannot contain files or blobs');
|
|
14
|
+
}
|
|
15
|
+
return JSON.stringify({ [MARKER]: 1, json, meta });
|
|
16
|
+
}
|
|
17
|
+
export function decodePayload(payload) {
|
|
18
|
+
const parsed = JSON.parse(payload);
|
|
19
|
+
if (typeof parsed === 'object' &&
|
|
20
|
+
parsed !== null &&
|
|
21
|
+
parsed[MARKER] === 1) {
|
|
22
|
+
const { json, meta } = parsed;
|
|
23
|
+
return serializer.deserialize(json, meta);
|
|
24
|
+
}
|
|
25
|
+
return parsed;
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=codec.js.map
|
|
@@ -0,0 +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,KAAc;IAC3C,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,IAAI,EAAE,IAAI,EAAE,CAAC,CAAA;AACnD,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;QACd,MAAkC,CAAC,MAAM,CAAC,KAAK,CAAC,EAChD,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","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(value: unknown): 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]: 1, 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(parsed as Record<string, unknown>)[MARKER] === 1\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"]}
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import type { Schema } from '@orpc/contract';
|
|
2
|
+
import { type AnyProcedure } from '@orpc/server';
|
|
3
|
+
import type { ZodType, z } from 'zod';
|
|
4
|
+
import type { FnLogger } from '../logger.js';
|
|
5
|
+
import { type SpanLike } from '../otel.js';
|
|
6
|
+
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
|
+
declare const fnLivePatchMarker: unique symbol;
|
|
9
|
+
/**
|
|
10
|
+
* Transformer result that splits the internal accumulator from the wire
|
|
11
|
+
* payload: `state` becomes the `previous` snapshot for later events while only
|
|
12
|
+
* `emit` is sent to the subscriber. Lets high-frequency streams avoid
|
|
13
|
+
* re-serializing the full snapshot per event.
|
|
14
|
+
*/
|
|
15
|
+
export type FnLivePatch<TOutput, TEmit> = {
|
|
16
|
+
[fnLivePatchMarker]: true;
|
|
17
|
+
state: TOutput;
|
|
18
|
+
emit: TEmit;
|
|
19
|
+
};
|
|
20
|
+
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> = Omit<PublisherConfig, 'name'> & {
|
|
22
|
+
/** Subscribe route name; default `${name}.live`. */
|
|
23
|
+
name?: string;
|
|
24
|
+
eventSchema: TEventSchema;
|
|
25
|
+
channel: ChannelDefinition<TInput, z.output<TEventSchema>, FnContext<TDef, TKey>>;
|
|
26
|
+
/** Fold an event into the snapshot; without it every event re-runs the handler. */
|
|
27
|
+
transformerFn?: (params: HandlerParams<TDef, TInput, TKey> & {
|
|
28
|
+
event: z.output<TEventSchema>;
|
|
29
|
+
previous: TOutput | undefined;
|
|
30
|
+
rerun: (input?: TInput) => Promise<TOutput>;
|
|
31
|
+
}) => MaybePromise<TOutput | FnLivePatch<TOutput, TEmit> | undefined>;
|
|
32
|
+
/** Return false to skip an event. */
|
|
33
|
+
shouldUpdate?: (params: HandlerParams<TDef, TInput, TKey> & {
|
|
34
|
+
event: z.output<TEventSchema>;
|
|
35
|
+
previous: TOutput | undefined;
|
|
36
|
+
}) => MaybePromise<boolean>;
|
|
37
|
+
authFn?: AuthFn<TInput, FnContext<TDef, TKey>>;
|
|
38
|
+
/** Log publish failures instead of throwing them into the publishing route. */
|
|
39
|
+
safePublish?: boolean;
|
|
40
|
+
/** Batch events arriving within this window into one snapshot update. */
|
|
41
|
+
coalesceMs?: number;
|
|
42
|
+
/**
|
|
43
|
+
* When a slow subscriber's queue overflows (drop-oldest), this marker is
|
|
44
|
+
* enqueued INSTEAD of the dropped event so the client resyncs. Return
|
|
45
|
+
* `null` to skip.
|
|
46
|
+
*/
|
|
47
|
+
overflowMarker?: (input: TInput) => z.output<TEventSchema> | null;
|
|
48
|
+
summary?: string;
|
|
49
|
+
description?: string;
|
|
50
|
+
};
|
|
51
|
+
export type FnLiveReturn<TDef extends FnDefinition, TKey extends ProcedureKey<TDef>, TInput extends ObjectSchema, TOutputSchema extends Schema<unknown, unknown>, TOutput, TEventSchema extends ZodType, TEmit = never> = {
|
|
52
|
+
procedure: FnProcedure<TDef, TKey, TInput, TOutputSchema>;
|
|
53
|
+
subscribe: FnProcedure<TDef, TKey, TInput, Schema<AsyncGenerator<TOutput | TEmit>, AsyncGenerator<TOutput | TEmit>>>;
|
|
54
|
+
publish: (event: z.input<TEventSchema>) => Promise<void>;
|
|
55
|
+
getChannelName: (params: Partial<z.output<TInput>> | Partial<z.output<TEventSchema>>, context?: FnContext<TDef, TKey>) => string;
|
|
56
|
+
};
|
|
57
|
+
/**
|
|
58
|
+
* A route plus a subscribe route that streams its result: the initial
|
|
59
|
+
* snapshot, then an update for every event published on the channel.
|
|
60
|
+
*/
|
|
61
|
+
export interface FnLive<TDef extends FnDefinition> {
|
|
62
|
+
<TInput extends ObjectSchema, TOutputSchema extends ZodType, TEventSchema extends ZodType, TKey extends ProcedureKey<TDef> = TDef['default'], TEmit = never>(options: {
|
|
63
|
+
input: TInput;
|
|
64
|
+
output: TOutputSchema;
|
|
65
|
+
handler: (params: HandlerParams<TDef, z.output<TInput>, NoInfer<TKey>> & {
|
|
66
|
+
publish: (event: z.input<TEventSchema>) => Promise<void>;
|
|
67
|
+
}) => 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>(options: {
|
|
71
|
+
input: TInput;
|
|
72
|
+
output?: undefined;
|
|
73
|
+
handler: (params: HandlerParams<TDef, z.output<TInput>, NoInfer<TKey>> & {
|
|
74
|
+
publish: (event: z.input<TEventSchema>) => Promise<void>;
|
|
75
|
+
}) => 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>;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Fail a live subscription whose initial snapshot could not be built.
|
|
81
|
+
*
|
|
82
|
+
* An expected client failure - an `ORPCError` with a 4xx status, e.g. the
|
|
83
|
+
* subscribed resource was not found or access was refused - reaches the
|
|
84
|
+
* subscriber unchanged and is NOT logged as a server fault. Only 5xx and
|
|
85
|
+
* unknown failures are logged. Unknown errors are wrapped as
|
|
86
|
+
* `INTERNAL_SERVER_ERROR`.
|
|
87
|
+
*/
|
|
88
|
+
export declare function throwInitialSnapshotError(err: unknown, liveName: string, logger: Pick<FnLogger, 'error'>,
|
|
89
|
+
/** `createFn`'s `isExpectedError`; default: a 4xx `ORPCError`. */
|
|
90
|
+
isExpected?: (error: unknown) => boolean): never;
|
|
91
|
+
/**
|
|
92
|
+
* Drives a live subscription: yields the initial snapshot, then folds each
|
|
93
|
+
* inbound event into the running snapshot via `apply`, yielding after every
|
|
94
|
+
* change. With `coalesceMs`, events arriving within that window are batched so
|
|
95
|
+
* bursty streams apply together.
|
|
96
|
+
*
|
|
97
|
+
* `apply` may return an {@link FnLivePatch} to keep the full snapshot as the
|
|
98
|
+
* internal accumulator while yielding only the lighter `emit` payload.
|
|
99
|
+
*
|
|
100
|
+
* Invariant: there is never more than one outstanding `source.next()` read. On
|
|
101
|
+
* a coalesce-window timeout the still-pending read is stashed in `pending` and
|
|
102
|
+
* reused by the next `readNext()` - issuing a second concurrent read would
|
|
103
|
+
* strand the in-flight event behind the next one (delivering it "one behind").
|
|
104
|
+
*/
|
|
105
|
+
export declare function streamLiveSnapshots<TEvent, TOutput, TEmit = never>(opts: {
|
|
106
|
+
source: AsyncIterator<TEvent>;
|
|
107
|
+
initial: TOutput;
|
|
108
|
+
coalesceMs?: number | undefined;
|
|
109
|
+
apply: (event: TEvent, previous: TOutput) => MaybePromise<TOutput | FnLivePatch<TOutput, TEmit> | undefined>;
|
|
110
|
+
}): AsyncGenerator<TOutput | TEmit>;
|
|
111
|
+
type RuntimeParams = Record<string, unknown> & {
|
|
112
|
+
input: Record<string, unknown>;
|
|
113
|
+
context: unknown;
|
|
114
|
+
signal: AbortSignal | undefined;
|
|
115
|
+
logger: FnLogger;
|
|
116
|
+
};
|
|
117
|
+
/** `FnLiveConfig` with the generics erased: what the implementation reads. */
|
|
118
|
+
type RuntimeLiveConfig = Omit<ChannelOptions, 'name'> & {
|
|
119
|
+
name?: string;
|
|
120
|
+
transformerFn?: (params: RuntimeParams & Record<string, unknown>) => unknown;
|
|
121
|
+
shouldUpdate?: (params: RuntimeParams & Record<string, unknown>) => unknown;
|
|
122
|
+
safePublish?: boolean;
|
|
123
|
+
coalesceMs?: number;
|
|
124
|
+
summary?: string;
|
|
125
|
+
description?: string;
|
|
126
|
+
};
|
|
127
|
+
/**
|
|
128
|
+
* @internal Wires `fnLive` onto an `fn` and channel runtime of the same
|
|
129
|
+
* instance. `createFn` returns it typed as {@link FnLive}.
|
|
130
|
+
*/
|
|
131
|
+
export declare function createFnLive(runtime: {
|
|
132
|
+
fn: (options: any) => AnyProcedure;
|
|
133
|
+
createChannel: (options: ChannelOptions) => Channel;
|
|
134
|
+
createLogger: (scope: string, span: SpanLike | undefined) => FnLogger;
|
|
135
|
+
isGuard: (option: string) => boolean;
|
|
136
|
+
}): (options: {
|
|
137
|
+
live: RuntimeLiveConfig;
|
|
138
|
+
handler: (params: RuntimeParams) => unknown;
|
|
139
|
+
input: ZodType;
|
|
140
|
+
output?: ZodType;
|
|
141
|
+
name: string;
|
|
142
|
+
procedure?: string;
|
|
143
|
+
summary?: string;
|
|
144
|
+
description?: string;
|
|
145
|
+
tags?: string[];
|
|
146
|
+
} & Record<string, unknown>) => {
|
|
147
|
+
procedure: AnyProcedure;
|
|
148
|
+
subscribe: AnyProcedure;
|
|
149
|
+
publish: (event: unknown) => Promise<void>;
|
|
150
|
+
getChannelName: (params: {
|
|
151
|
+
[x: string]: unknown;
|
|
152
|
+
}, context?: unknown) => string;
|
|
153
|
+
};
|
|
154
|
+
export {};
|
|
155
|
+
//# sourceMappingURL=fn-live.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fn-live.d.ts","sourceRoot":"","sources":["../../src/live/fn-live.ts"],"names":[],"mappings":"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"}
|