orpc-fn 0.7.0 → 0.9.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 +66 -28
- package/dist/assemble-procedure.d.ts.map +1 -1
- package/dist/assemble-procedure.js +3 -1
- package/dist/assemble-procedure.js.map +1 -1
- package/dist/client.d.ts +13 -3
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +21 -1
- package/dist/client.js.map +1 -1
- package/dist/create-fn.d.ts +63 -5
- package/dist/create-fn.d.ts.map +1 -1
- package/dist/create-fn.js +45 -16
- package/dist/create-fn.js.map +1 -1
- package/dist/expected-client-error.d.ts +6 -0
- package/dist/expected-client-error.d.ts.map +1 -1
- package/dist/expected-client-error.js +16 -0
- package/dist/expected-client-error.js.map +1 -1
- package/dist/hono.d.ts +44 -22
- package/dist/hono.d.ts.map +1 -1
- package/dist/hono.js +51 -20
- package/dist/hono.js.map +1 -1
- package/dist/index.d.ts +1 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +0 -1
- package/dist/index.js.map +1 -1
- package/dist/issues.d.ts +12 -0
- package/dist/issues.d.ts.map +1 -0
- package/dist/issues.js +22 -0
- package/dist/issues.js.map +1 -0
- package/dist/json-schema.d.ts +3 -6
- package/dist/json-schema.d.ts.map +1 -1
- package/dist/json-schema.js +12 -7
- package/dist/json-schema.js.map +1 -1
- package/dist/live/codec.d.ts +2 -0
- package/dist/live/codec.d.ts.map +1 -1
- package/dist/live/codec.js +21 -16
- package/dist/live/codec.js.map +1 -1
- package/dist/live/fn-live.d.ts +6 -19
- package/dist/live/fn-live.d.ts.map +1 -1
- package/dist/live/fn-live.js +15 -23
- package/dist/live/fn-live.js.map +1 -1
- package/dist/live/index.d.ts +2 -2
- package/dist/live/index.d.ts.map +1 -1
- package/dist/live/index.js +1 -1
- package/dist/live/index.js.map +1 -1
- package/dist/live/memory.d.ts +11 -1
- package/dist/live/memory.d.ts.map +1 -1
- package/dist/live/memory.js +14 -1
- package/dist/live/memory.js.map +1 -1
- package/dist/live/pub-sub.d.ts +50 -8
- package/dist/live/pub-sub.d.ts.map +1 -1
- package/dist/live/pub-sub.js +79 -26
- package/dist/live/pub-sub.js.map +1 -1
- package/dist/live/redis-bun.d.ts +6 -1
- package/dist/live/redis-bun.d.ts.map +1 -1
- package/dist/live/redis-bun.js +10 -1
- package/dist/live/redis-bun.js.map +1 -1
- package/dist/live/scoped-change-bus.d.ts +3 -1
- package/dist/live/scoped-change-bus.d.ts.map +1 -1
- package/dist/live/scoped-change-bus.js +3 -0
- package/dist/live/scoped-change-bus.js.map +1 -1
- package/dist/mastra.d.ts +16 -3
- package/dist/mastra.d.ts.map +1 -1
- package/dist/mastra.js +15 -3
- package/dist/mastra.js.map +1 -1
- package/dist/mcp/core.d.ts +31 -14
- package/dist/mcp/core.d.ts.map +1 -1
- package/dist/mcp/core.js +39 -20
- package/dist/mcp/core.js.map +1 -1
- package/dist/mcp/sdk.d.ts +6 -2
- package/dist/mcp/sdk.d.ts.map +1 -1
- package/dist/mcp/sdk.js +9 -3
- package/dist/mcp/sdk.js.map +1 -1
- package/dist/mcp/server.d.ts +6 -2
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +9 -3
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp.d.ts +3 -7
- package/dist/mcp.d.ts.map +1 -1
- package/dist/mcp.js +4 -6
- package/dist/mcp.js.map +1 -1
- package/dist/meta.d.ts +14 -2
- package/dist/meta.d.ts.map +1 -1
- package/dist/meta.js +6 -2
- package/dist/meta.js.map +1 -1
- package/dist/otel.d.ts +16 -4
- package/dist/otel.d.ts.map +1 -1
- package/dist/otel.js +40 -10
- package/dist/otel.js.map +1 -1
- package/dist/react.d.ts +6 -1
- package/dist/react.d.ts.map +1 -1
- package/dist/react.js +5 -1
- package/dist/react.js.map +1 -1
- package/dist/route-options.d.ts.map +1 -1
- package/dist/route-options.js +4 -0
- package/dist/route-options.js.map +1 -1
- package/dist/stream-call.d.ts +15 -0
- package/dist/stream-call.d.ts.map +1 -0
- package/dist/stream-call.js +13 -0
- package/dist/stream-call.js.map +1 -0
- package/dist/timing.d.ts +2 -0
- package/dist/timing.d.ts.map +1 -1
- package/dist/timing.js +2 -0
- package/dist/timing.js.map +1 -1
- package/dist/tool-errors.d.ts +24 -0
- package/dist/tool-errors.d.ts.map +1 -0
- package/dist/tool-errors.js +36 -0
- package/dist/tool-errors.js.map +1 -0
- package/dist/types.d.ts +2 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/vue.d.ts +47 -4
- package/dist/vue.d.ts.map +1 -1
- package/dist/vue.js +39 -9
- package/dist/vue.js.map +1 -1
- package/package.json +2 -2
- package/src/assemble-procedure.ts +3 -1
- package/src/client.ts +26 -2
- package/src/create-fn.ts +149 -19
- package/src/expected-client-error.ts +19 -0
- package/src/hono.ts +120 -41
- package/src/index.ts +3 -2
- package/src/issues.ts +35 -0
- package/src/json-schema.ts +16 -10
- package/src/live/codec.ts +21 -19
- package/src/live/fn-live.ts +18 -36
- package/src/live/index.ts +2 -2
- package/src/live/memory.ts +22 -1
- package/src/live/pub-sub.ts +142 -37
- package/src/live/redis-bun.ts +23 -2
- package/src/live/scoped-change-bus.ts +10 -1
- package/src/mastra.ts +25 -6
- package/src/mcp/core.ts +76 -29
- package/src/mcp/sdk.ts +27 -2
- package/src/mcp/server.ts +27 -2
- package/src/mcp.ts +5 -16
- package/src/meta.ts +28 -4
- package/src/otel.ts +41 -9
- package/src/react.ts +10 -3
- package/src/route-options.ts +8 -0
- package/src/stream-call.ts +15 -0
- package/src/timing.ts +3 -0
- package/src/tool-errors.ts +52 -0
- package/src/types.ts +2 -0
- package/src/vue.ts +92 -19
package/dist/mcp/server.js
CHANGED
|
@@ -1,11 +1,17 @@
|
|
|
1
|
-
import { createToolHandlers, formatMcpResult } from './core.js';
|
|
2
|
-
export { formatMcpResult };
|
|
1
|
+
import { createToolHandlers, formatMcpResult, prepareMcpTools } from './core.js';
|
|
2
|
+
export { formatMcpResult, prepareMcpTools };
|
|
3
3
|
/**
|
|
4
4
|
* Register on the SDK v2 (`@modelcontextprotocol/server`) low-level Server, or
|
|
5
5
|
* on McpServer.server. Declare `capabilities: { tools: {} }` on the Server.
|
|
6
6
|
*/
|
|
7
7
|
export function registerMcpTools(server, router, options) {
|
|
8
|
-
|
|
8
|
+
return install(server, createToolHandlers(prepareMcpTools(router, options), options));
|
|
9
|
+
}
|
|
10
|
+
/** Register tools listed once with {@link prepareMcpTools}, e.g. on a server built per request. */
|
|
11
|
+
export function registerPreparedMcpTools(server, tools, options) {
|
|
12
|
+
return install(server, createToolHandlers(tools, options));
|
|
13
|
+
}
|
|
14
|
+
function install(server, handlers) {
|
|
9
15
|
server.setRequestHandler('tools/list', handlers.list);
|
|
10
16
|
server.setRequestHandler('tools/call', (request, ctx) => handlers.call(request.params.name, request.params.arguments, ctx.mcpReq.signal));
|
|
11
17
|
return handlers.names;
|
package/dist/mcp/server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/mcp/server.ts"],"names":[],"mappings":"AAEA,OAAO,EACN,kBAAkB,EAClB,eAAe,EAEf,MAAM,WAAW,CAAA;AAElB,OAAO,EAAE,eAAe,EAAE,CAAA;
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/mcp/server.ts"],"names":[],"mappings":"AAEA,OAAO,EACN,kBAAkB,EAClB,eAAe,EAGf,eAAe,EAEf,MAAM,WAAW,CAAA;AAElB,OAAO,EAAE,eAAe,EAAE,eAAe,EAAyB,CAAA;AAWlE;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAC/B,MAAyC,EACzC,MAAS,EACT,OAAmC;IAEnC,OAAO,OAAO,CACb,MAAM,EACN,kBAAkB,CAAC,eAAe,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,CAAC,CAC7D,CAAA;AACF,CAAC;AAED,mGAAmG;AACnG,MAAM,UAAU,wBAAwB,CACvC,MAAyC,EACzC,KAA0B,EAC1B,OAA2C;IAE3C,OAAO,OAAO,CAAC,MAAM,EAAE,kBAAkB,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC,CAAA;AAC3D,CAAC;AAED,SAAS,OAAO,CACf,MAAyC,EACzC,QAA0E;IAE1E,MAAM,CAAC,iBAAiB,CAAC,YAAY,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAA;IACrD,MAAM,CAAC,iBAAiB,CAAC,YAAY,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,EAAE,CACvD,QAAQ,CAAC,IAAI,CACZ,OAAO,CAAC,MAAM,CAAC,IAAI,EACnB,OAAO,CAAC,MAAM,CAAC,SAAS,EACxB,GAAG,CAAC,MAAM,CAAC,MAAM,CACjB,CACD,CAAA;IACD,OAAO,QAAQ,CAAC,KAAK,CAAA;AACtB,CAAC","sourcesContent":["import type { CallToolResult, Server } from '@modelcontextprotocol/server'\nimport type { AnyRouter } from '@orpc/server'\nimport {\n\tcreateToolHandlers,\n\tformatMcpResult,\n\ttype McpCallOptions,\n\ttype PreparedMcpTools,\n\tprepareMcpTools,\n\ttype RegisterMcpToolsOptions as CoreOptions\n} from './core.js'\n\nexport { formatMcpResult, prepareMcpTools, type PreparedMcpTools }\n\nexport type RegisterMcpToolsOptions<R extends AnyRouter> = CoreOptions<\n\tR,\n\tCallToolResult\n>\n\n/** Options for registering tools from {@link prepareMcpTools}. */\nexport type RegisterPreparedMcpToolsOptions<R extends AnyRouter> =\n\tMcpCallOptions<R, CallToolResult>\n\n/**\n * Register on the SDK v2 (`@modelcontextprotocol/server`) low-level Server, or\n * on McpServer.server. Declare `capabilities: { tools: {} }` on the Server.\n */\nexport function registerMcpTools<R extends AnyRouter>(\n\tserver: Pick<Server, 'setRequestHandler'>,\n\trouter: R,\n\toptions: RegisterMcpToolsOptions<R>\n): readonly string[] {\n\treturn install(\n\t\tserver,\n\t\tcreateToolHandlers(prepareMcpTools(router, options), options)\n\t)\n}\n\n/** Register tools listed once with {@link prepareMcpTools}, e.g. on a server built per request. */\nexport function registerPreparedMcpTools<R extends AnyRouter>(\n\tserver: Pick<Server, 'setRequestHandler'>,\n\ttools: PreparedMcpTools<R>,\n\toptions: RegisterPreparedMcpToolsOptions<R>\n): readonly string[] {\n\treturn install(server, createToolHandlers(tools, options))\n}\n\nfunction install(\n\tserver: Pick<Server, 'setRequestHandler'>,\n\thandlers: ReturnType<typeof createToolHandlers<AnyRouter, CallToolResult>>\n): readonly string[] {\n\tserver.setRequestHandler('tools/list', handlers.list)\n\tserver.setRequestHandler('tools/call', (request, ctx) =>\n\t\thandlers.call(\n\t\t\trequest.params.name,\n\t\t\trequest.params.arguments,\n\t\t\tctx.mcpReq.signal\n\t\t)\n\t)\n\treturn handlers.names\n}\n"]}
|
package/dist/mcp.d.ts
CHANGED
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
import { type AnyProcedure, type AnyRouter, type TraverseContractProcedureCallbackOptions } from '@orpc/server';
|
|
2
2
|
import { rawInputSchema, type ToolSchema } from './json-schema.js';
|
|
3
|
-
import { toToolName } from './meta.js';
|
|
4
|
-
export { toToolName };
|
|
3
|
+
import { hasTag, type ProcedureFilter, toToolName } from './meta.js';
|
|
4
|
+
export { hasTag, toToolName };
|
|
5
5
|
export { rawInputSchema as toolInputSchema };
|
|
6
|
-
export type { ToolSchema };
|
|
7
|
-
/** Picks procedures; also fits oRPC's `OpenAPIHandler({ filter })`. */
|
|
8
|
-
export type ProcedureFilter = (options: TraverseContractProcedureCallbackOptions) => boolean;
|
|
6
|
+
export type { ProcedureFilter, ToolSchema };
|
|
9
7
|
export type McpTool = {
|
|
10
8
|
/** Tool name: the sanitized `fn` name (`user.me` becomes `user-me`). */
|
|
11
9
|
name: string;
|
|
@@ -22,8 +20,6 @@ export type McpTool = {
|
|
|
22
20
|
};
|
|
23
21
|
};
|
|
24
22
|
};
|
|
25
|
-
/** Procedures whose route has `tag`: `listTools(router, { filter: hasTag('external') })`. */
|
|
26
|
-
export declare const hasTag: (tag: string) => ProcedureFilter;
|
|
27
23
|
/**
|
|
28
24
|
* MCP tool definitions for the procedures in `router` matching `filter`
|
|
29
25
|
* (default: all). These are inspection definitions, not McpServer.registerTool configs.
|
package/dist/mcp.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mcp.d.ts","sourceRoot":"","sources":["../src/mcp.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,KAAK,YAAY,EACjB,KAAK,SAAS,EACd,KAAK,wCAAwC,EAE7C,MAAM,cAAc,CAAA;AAErB,OAAO,EAAE,cAAc,EAAE,KAAK,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAClE,OAAO,EAAc,UAAU,EAAE,MAAM,WAAW,CAAA;
|
|
1
|
+
{"version":3,"file":"mcp.d.ts","sourceRoot":"","sources":["../src/mcp.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,KAAK,YAAY,EACjB,KAAK,SAAS,EACd,KAAK,wCAAwC,EAE7C,MAAM,cAAc,CAAA;AAErB,OAAO,EAAE,cAAc,EAAE,KAAK,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAClE,OAAO,EAAE,MAAM,EAAE,KAAK,eAAe,EAAc,UAAU,EAAE,MAAM,WAAW,CAAA;AAEhF,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,CAAA;AAC7B,OAAO,EAAE,cAAc,IAAI,eAAe,EAAE,CAAA;AAC5C,YAAY,EAAE,eAAe,EAAE,UAAU,EAAE,CAAA;AAE3C,MAAM,MAAM,OAAO,GAAG;IACrB,wEAAwE;IACxE,IAAI,EAAE,MAAM,CAAA;IACZ,SAAS,EAAE,YAAY,CAAA;IACvB,MAAM,EAAE;QACP,WAAW,CAAC,EAAE,MAAM,CAAA;QACpB;;;WAGG;QACH,WAAW,CAAC,EAAE,UAAU,CAAA;QACxB,WAAW,EAAE;YAAE,YAAY,EAAE,OAAO,CAAA;SAAE,CAAA;KACtC,CAAA;CACD,CAAA;AAKD;;;;;;;GAOG;AACH,wBAAgB,SAAS,CACxB,MAAM,EAAE,SAAS,EACjB,OAAO,GAAE;IACR,MAAM,CAAC,EAAE,eAAe,CAAA;IACxB,QAAQ,CAAC,EAAE,eAAe,CAAA;IAC1B,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,wCAAwC,KAAK,MAAM,CAAA;CAC/D,GACJ,OAAO,EAAE,CA0CX"}
|
package/dist/mcp.js
CHANGED
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
import { traverseContractProcedures } from '@orpc/server';
|
|
2
2
|
import { procedureDefinition } from './compatibility.js';
|
|
3
3
|
import { rawInputSchema } from './json-schema.js';
|
|
4
|
-
import { readFnMeta, toToolName } from './meta.js';
|
|
5
|
-
export { toToolName };
|
|
4
|
+
import { hasTag, readFnMeta, toToolName } from './meta.js';
|
|
5
|
+
export { hasTag, toToolName };
|
|
6
6
|
export { rawInputSchema as toolInputSchema };
|
|
7
|
-
/** Procedures whose route has `tag`: `listTools(router, { filter: hasTag('external') })`. */
|
|
8
|
-
export const hasTag = (tag) => ({ contract }) => procedureDefinition(contract).route?.tags?.includes(tag) ?? false;
|
|
9
7
|
const isGet = ({ contract }) => procedureDefinition(contract).route?.method === 'GET';
|
|
10
8
|
/**
|
|
11
9
|
* MCP tool definitions for the procedures in `router` matching `filter`
|
|
@@ -34,8 +32,8 @@ export function listTools(router, options = {}) {
|
|
|
34
32
|
if (previous)
|
|
35
33
|
throw new TypeError(`orpc-fn: MCP tool name collision: ${name}; provide a name override`);
|
|
36
34
|
names.set(name, procedure);
|
|
37
|
-
const { inputSchema
|
|
38
|
-
const description =
|
|
35
|
+
const { inputSchema } = procedureDefinition(procedure);
|
|
36
|
+
const description = meta.description || undefined;
|
|
39
37
|
tools.push({
|
|
40
38
|
name,
|
|
41
39
|
procedure,
|
package/dist/mcp.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mcp.js","sourceRoot":"","sources":["../src/mcp.ts"],"names":[],"mappings":"AAAA,OAAO,EAIN,0BAA0B,EAC1B,MAAM,cAAc,CAAA;AACrB,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAA;AACxD,OAAO,EAAE,cAAc,EAAmB,MAAM,kBAAkB,CAAA;AAClE,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;
|
|
1
|
+
{"version":3,"file":"mcp.js","sourceRoot":"","sources":["../src/mcp.ts"],"names":[],"mappings":"AAAA,OAAO,EAIN,0BAA0B,EAC1B,MAAM,cAAc,CAAA;AACrB,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAA;AACxD,OAAO,EAAE,cAAc,EAAmB,MAAM,kBAAkB,CAAA;AAClE,OAAO,EAAE,MAAM,EAAwB,UAAU,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AAEhF,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,CAAA;AAC7B,OAAO,EAAE,cAAc,IAAI,eAAe,EAAE,CAAA;AAkB5C,MAAM,KAAK,GAAoB,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,CAC/C,mBAAmB,CAAC,QAAQ,CAAC,CAAC,KAAK,EAAE,MAAM,KAAK,KAAK,CAAA;AAEtD;;;;;;;GAOG;AACH,MAAM,UAAU,SAAS,CACxB,MAAiB,EACjB,OAAO,GAIH,EAAE;IAEN,MAAM,EAAE,MAAM,EAAE,QAAQ,GAAG,KAAK,EAAE,GAAG,OAAO,CAAA;IAC5C,MAAM,KAAK,GAAc,EAAE,CAAA;IAC3B,MAAM,KAAK,GAAG,IAAI,GAAG,EAAwB,CAAA;IAC7C,MAAM,UAAU,GAAG,0BAA0B,CAC5C,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,EACpB,CAAC,SAAS,EAAE,EAAE;QACb,IAAI,MAAM,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC;YAAE,OAAM;QACxC,MAAM,SAAS,GAAG,SAAS,CAAC,QAAwB,CAAA;QACpD,MAAM,IAAI,GAAG,UAAU,CAAC,SAAS,CAAC,CAAA;QAClC,IAAI,IAAI,CAAC,MAAM;YACd,MAAM,IAAI,SAAS,CAClB,gCAAgC,IAAI,CAAC,IAAI,IAAI,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,wBAAwB,CAC7F,CAAA;QACF,MAAM,IAAI,GACT,OAAO,CAAC,IAAI,EAAE,CAAC,SAAS,CAAC;YACzB,UAAU,CAAC,IAAI,CAAC,IAAI,IAAI,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAA;QAClD,MAAM,QAAQ,GAAG,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;QAChC,IAAI,QAAQ,KAAK,SAAS;YAAE,OAAM;QAClC,IAAI,QAAQ;YACX,MAAM,IAAI,SAAS,CAClB,qCAAqC,IAAI,2BAA2B,CACpE,CAAA;QACF,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,SAAS,CAAC,CAAA;QAC1B,MAAM,EAAE,WAAW,EAAE,GAAG,mBAAmB,CAAC,SAAS,CAAC,CAAA;QACtD,MAAM,WAAW,GAAG,IAAI,CAAC,WAAW,IAAI,SAAS,CAAA;QACjD,KAAK,CAAC,IAAI,CAAC;YACV,IAAI;YACJ,SAAS;YACT,MAAM,EAAE;gBACP,GAAG,CAAC,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,CAAC;gBACrD,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,cAAc,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACpE,WAAW,EAAE,EAAE,YAAY,EAAE,QAAQ,CAAC,SAAS,CAAC,EAAE;aAClD;SACD,CAAC,CAAA;IACH,CAAC,CACD,CAAA;IACD,IAAI,UAAU,CAAC,MAAM;QACpB,MAAM,IAAI,SAAS,CAClB,0EAA0E,CAC1E,CAAA;IACF,OAAO,KAAK,CAAA;AACb,CAAC","sourcesContent":["import {\n\ttype AnyProcedure,\n\ttype AnyRouter,\n\ttype TraverseContractProcedureCallbackOptions,\n\ttraverseContractProcedures\n} from '@orpc/server'\nimport { procedureDefinition } from './compatibility.js'\nimport { rawInputSchema, type ToolSchema } from './json-schema.js'\nimport { hasTag, type ProcedureFilter, readFnMeta, toToolName } from './meta.js'\n\nexport { hasTag, toToolName }\nexport { rawInputSchema as toolInputSchema }\nexport type { ProcedureFilter, ToolSchema }\n\nexport type McpTool = {\n\t/** Tool name: the sanitized `fn` name (`user.me` becomes `user-me`). */\n\tname: string\n\tprocedure: AnyProcedure\n\tconfig: {\n\t\tdescription?: string\n\t\t/**\n\t\t * Validates and coerces (date strings to `Date`) but returns the raw\n\t\t * input: pass it to `call(procedure, args)`, which parses it.\n\t\t */\n\t\tinputSchema?: ToolSchema\n\t\tannotations: { readOnlyHint: boolean }\n\t}\n}\n\nconst isGet: ProcedureFilter = ({ contract }) =>\n\tprocedureDefinition(contract).route?.method === 'GET'\n\n/**\n * MCP tool definitions for the procedures in `router` matching `filter`\n * (default: all). These are inspection definitions, not McpServer.registerTool configs.\n * Use registerMcpTools from orpc-fn/mcp/sdk for executable registration.\n *\n * `readOnly` sets `readOnlyHint`; it defaults to GET routes, since an MCP\n * client treats anything else as a mutation and may ask for approval.\n */\nexport function listTools(\n\trouter: AnyRouter,\n\toptions: {\n\t\tfilter?: ProcedureFilter\n\t\treadOnly?: ProcedureFilter\n\t\tname?: (options: TraverseContractProcedureCallbackOptions) => string\n\t} = {}\n): McpTool[] {\n\tconst { filter, readOnly = isGet } = options\n\tconst tools: McpTool[] = []\n\tconst names = new Map<string, AnyProcedure>()\n\tconst unresolved = traverseContractProcedures(\n\t\t{ router, path: [] },\n\t\t(traversed) => {\n\t\t\tif (filter && !filter(traversed)) return\n\t\t\tconst procedure = traversed.contract as AnyProcedure\n\t\t\tconst meta = readFnMeta(procedure)\n\t\t\tif (meta.stream)\n\t\t\t\tthrow new TypeError(\n\t\t\t\t\t`orpc-fn: streaming procedure ${meta.name ?? traversed.path.join('.')} cannot be an MCP tool`\n\t\t\t\t)\n\t\t\tconst name =\n\t\t\t\toptions.name?.(traversed) ??\n\t\t\t\ttoToolName(meta.name ?? traversed.path.join('.'))\n\t\t\tconst previous = names.get(name)\n\t\t\tif (previous === procedure) return\n\t\t\tif (previous)\n\t\t\t\tthrow new TypeError(\n\t\t\t\t\t`orpc-fn: MCP tool name collision: ${name}; provide a name override`\n\t\t\t\t)\n\t\t\tnames.set(name, procedure)\n\t\t\tconst { inputSchema } = procedureDefinition(procedure)\n\t\t\tconst description = meta.description || undefined\n\t\t\ttools.push({\n\t\t\t\tname,\n\t\t\t\tprocedure,\n\t\t\t\tconfig: {\n\t\t\t\t\t...(description === undefined ? {} : { description }),\n\t\t\t\t\t...(inputSchema ? { inputSchema: rawInputSchema(inputSchema) } : {}),\n\t\t\t\t\tannotations: { readOnlyHint: readOnly(traversed) }\n\t\t\t\t}\n\t\t\t})\n\t\t}\n\t)\n\tif (unresolved.length)\n\t\tthrow new TypeError(\n\t\t\t'orpc-fn: resolve lazy routers with unlazyRouter before listing MCP tools'\n\t\t)\n\treturn tools\n}\n"]}
|
package/dist/meta.d.ts
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import { type AnySchema } from '@orpc/contract';
|
|
2
2
|
import { type LibraryMeta } from './compatibility.js';
|
|
3
|
-
import type { AnyProcedure } from '@orpc/server';
|
|
3
|
+
import type { AnyProcedure, TraverseContractProcedureCallbackOptions } from '@orpc/server';
|
|
4
|
+
/** Picks procedures; also fits oRPC's `OpenAPIHandler({ filter })`. */
|
|
5
|
+
export type ProcedureFilter = (options: TraverseContractProcedureCallbackOptions) => boolean;
|
|
6
|
+
/** Procedures whose route has `tag`: `listTools(router, { filter: hasTag('external') })`. */
|
|
7
|
+
export declare const hasTag: (tag: string) => ProcedureFilter;
|
|
4
8
|
/**
|
|
5
9
|
* Key under which `fn()` stores its metadata in oRPC's procedure meta
|
|
6
10
|
* (`.meta()`). Living in oRPC's own meta means it survives everything that
|
|
@@ -13,6 +17,10 @@ export type StoredFnMeta<TMeta extends object = Record<string, unknown>, TKey ex
|
|
|
13
17
|
procedure: TKey;
|
|
14
18
|
meta: TMeta;
|
|
15
19
|
stream: boolean;
|
|
20
|
+
/** Guard values set on the route. */
|
|
21
|
+
guards?: Record<string, unknown>;
|
|
22
|
+
/** Guards decided per call through `guardResolvers`. */
|
|
23
|
+
dynamicGuards?: readonly string[];
|
|
16
24
|
};
|
|
17
25
|
export type FnMeta<TMeta extends object = Record<string, unknown>, TKey extends string = string> = {
|
|
18
26
|
/** `fn({ name })`, also the OpenAPI operationId; undefined if not made by `fn()`. */
|
|
@@ -21,7 +29,7 @@ export type FnMeta<TMeta extends object = Record<string, unknown>, TKey extends
|
|
|
21
29
|
procedure: TKey | undefined;
|
|
22
30
|
/** The app's typed meta (`createFn({ meta })`) declared on this route. */
|
|
23
31
|
meta: Partial<TMeta>;
|
|
24
|
-
/** Route
|
|
32
|
+
/** Route description, falling back to summary, falling back to ''. */
|
|
25
33
|
description: string;
|
|
26
34
|
summary: string | undefined;
|
|
27
35
|
method: string | undefined;
|
|
@@ -30,6 +38,10 @@ export type FnMeta<TMeta extends object = Record<string, unknown>, TKey extends
|
|
|
30
38
|
tags: readonly string[];
|
|
31
39
|
inputSchema: AnySchema | undefined;
|
|
32
40
|
outputSchema: AnySchema | undefined;
|
|
41
|
+
/** Guard values set on the route (`permission: 'deal.read'`). */
|
|
42
|
+
guards: Record<string, unknown>;
|
|
43
|
+
/** Guards the route decides per call through `guardResolvers`. */
|
|
44
|
+
dynamicGuards: readonly string[];
|
|
33
45
|
};
|
|
34
46
|
/** Read what `fn()` (and oRPC) recorded on a procedure. */
|
|
35
47
|
type MetaFrom<T> = [LibraryMeta<T>] extends [never] ? Record<string, unknown> : LibraryMeta<T> extends StoredFnMeta<infer M, string> ? M : Record<string, unknown>;
|
package/dist/meta.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"meta.d.ts","sourceRoot":"","sources":["../src/meta.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiC,KAAK,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAC9E,OAAO,EAAE,KAAK,WAAW,EAAuB,MAAM,oBAAoB,CAAA;AAC1E,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"meta.d.ts","sourceRoot":"","sources":["../src/meta.ts"],"names":[],"mappings":"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"}
|
package/dist/meta.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { getEventIteratorSchemaDetails } from '@orpc/contract';
|
|
2
2
|
import { procedureDefinition } from './compatibility.js';
|
|
3
|
+
/** Procedures whose route has `tag`: `listTools(router, { filter: hasTag('external') })`. */
|
|
4
|
+
export const hasTag = (tag) => ({ contract }) => procedureDefinition(contract).route?.tags?.includes(tag) ?? false;
|
|
3
5
|
/**
|
|
4
6
|
* Key under which `fn()` stores its metadata in oRPC's procedure meta
|
|
5
7
|
* (`.meta()`). Living in oRPC's own meta means it survives everything that
|
|
@@ -19,7 +21,7 @@ export function readFnMeta(procedure) {
|
|
|
19
21
|
name: stored?.name,
|
|
20
22
|
procedure: stored?.procedure,
|
|
21
23
|
meta: (stored?.meta ?? {}),
|
|
22
|
-
description: route.
|
|
24
|
+
description: route.description ?? route.summary ?? '',
|
|
23
25
|
summary: route.summary,
|
|
24
26
|
method: route.method,
|
|
25
27
|
path: route.path,
|
|
@@ -27,7 +29,9 @@ export function readFnMeta(procedure) {
|
|
|
27
29
|
stream: stored?.stream === true ||
|
|
28
30
|
getEventIteratorSchemaDetails(def.outputSchema) !== undefined,
|
|
29
31
|
inputSchema: def.inputSchema,
|
|
30
|
-
outputSchema: def.outputSchema
|
|
32
|
+
outputSchema: def.outputSchema,
|
|
33
|
+
guards: stored?.guards ?? {},
|
|
34
|
+
dynamicGuards: stored?.dynamicGuards ?? []
|
|
31
35
|
};
|
|
32
36
|
}
|
|
33
37
|
/** Tool-safe name (`a-z0-9-_`): `Users.Get` becomes `users-get`. */
|
package/dist/meta.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"meta.js","sourceRoot":"","sources":["../src/meta.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,6BAA6B,EAAkB,MAAM,gBAAgB,CAAA;AAC9E,OAAO,EAAoB,mBAAmB,EAAE,MAAM,oBAAoB,CAAA;
|
|
1
|
+
{"version":3,"file":"meta.js","sourceRoot":"","sources":["../src/meta.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,6BAA6B,EAAkB,MAAM,gBAAgB,CAAA;AAC9E,OAAO,EAAoB,mBAAmB,EAAE,MAAM,oBAAoB,CAAA;AAW1E,6FAA6F;AAC7F,MAAM,CAAC,MAAM,MAAM,GAClB,CAAC,GAAW,EAAmB,EAAE,CACjC,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,CAChB,mBAAmB,CAAC,QAAQ,CAAC,CAAC,KAAK,EAAE,IAAI,EAAE,QAAQ,CAAC,GAAG,CAAC,IAAI,KAAK,CAAA;AAEnE;;;;;GAKG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,SAAS,CAAA;AAsDpC,0EAA0E;AAC1E,MAAM,UAAU,UAAU;IACzB,OAAO,EAAO,CAAA;AACf,CAAC;AAED,MAAM,UAAU,UAAU,CACzB,SAAY;IAEZ,MAAM,GAAG,GAAG,mBAAmB,CAAC,SAAS,CAAC,CAAA;IAC1C,MAAM,MAAM,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC,WAAW,CAA6B,CAAA;IAClE,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,IAAI,EAAE,CAAA;IAC7B,OAAO;QACN,IAAI,EAAE,MAAM,EAAE,IAAI;QAClB,SAAS,EAAE,MAAM,EAAE,SAAmC;QACtD,IAAI,EAAE,CAAC,MAAM,EAAE,IAAI,IAAI,EAAE,CAAyB;QAClD,WAAW,EAAE,KAAK,CAAC,WAAW,IAAI,KAAK,CAAC,OAAO,IAAI,EAAE;QACrD,OAAO,EAAE,KAAK,CAAC,OAAO;QACtB,MAAM,EAAE,KAAK,CAAC,MAAM;QACpB,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,IAAI,EAAE,KAAK,CAAC,IAAI,IAAI,EAAE;QACtB,MAAM,EACL,MAAM,EAAE,MAAM,KAAK,IAAI;YACvB,6BAA6B,CAAC,GAAG,CAAC,YAAY,CAAC,KAAK,SAAS;QAC9D,WAAW,EAAE,GAAG,CAAC,WAAW;QAC5B,YAAY,EAAE,GAAG,CAAC,YAAY;QAC9B,MAAM,EAAE,MAAM,EAAE,MAAM,IAAI,EAAE;QAC5B,aAAa,EAAE,MAAM,EAAE,aAAa,IAAI,EAAE;KAC1C,CAAA;AACF,CAAC;AAED,oEAAoE;AACpE,MAAM,UAAU,UAAU,CAAC,IAAY;IACtC,OAAO,IAAI,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,cAAc,EAAE,GAAG,CAAC,CAAA;AACvD,CAAC","sourcesContent":["import { getEventIteratorSchemaDetails, type AnySchema } from '@orpc/contract'\nimport { type LibraryMeta, procedureDefinition } from './compatibility.js'\nimport type {\n\tAnyProcedure,\n\tTraverseContractProcedureCallbackOptions\n} from '@orpc/server'\n\n/** Picks procedures; also fits oRPC's `OpenAPIHandler({ filter })`. */\nexport type ProcedureFilter = (\n\toptions: TraverseContractProcedureCallbackOptions\n) => boolean\n\n/** Procedures whose route has `tag`: `listTools(router, { filter: hasTag('external') })`. */\nexport const hasTag =\n\t(tag: string): ProcedureFilter =>\n\t({ contract }) =>\n\t\tprocedureDefinition(contract).route?.tags?.includes(tag) ?? false\n\n/**\n * Key under which `fn()` stores its metadata in oRPC's procedure meta\n * (`.meta()`). Living in oRPC's own meta means it survives everything that\n * rebuilds a procedure (`os.router()`, `.use()` on a router, lazy routers),\n * unlike a symbol property on the procedure object.\n */\nexport const FN_META_KEY = 'orpc-fn'\n\nexport type StoredFnMeta<\n\tTMeta extends object = Record<string, unknown>,\n\tTKey extends string = string\n> = {\n\tname: string\n\tprocedure: TKey\n\tmeta: TMeta\n\tstream: boolean\n\t/** Guard values set on the route. */\n\tguards?: Record<string, unknown>\n\t/** Guards decided per call through `guardResolvers`. */\n\tdynamicGuards?: readonly string[]\n}\n\nexport type FnMeta<\n\tTMeta extends object = Record<string, unknown>,\n\tTKey extends string = string\n> = {\n\t/** `fn({ name })`, also the OpenAPI operationId; undefined if not made by `fn()`. */\n\tname: string | undefined\n\t/** The `procedures` key the route was built from. */\n\tprocedure: TKey | undefined\n\t/** The app's typed meta (`createFn({ meta })`) declared on this route. */\n\tmeta: Partial<TMeta>\n\t/** Route description, falling back to summary, falling back to ''. */\n\tdescription: string\n\tsummary: string | undefined\n\tmethod: string | undefined\n\tpath: string | undefined\n\tstream: boolean\n\ttags: readonly string[]\n\tinputSchema: AnySchema | undefined\n\toutputSchema: AnySchema | undefined\n\t/** Guard values set on the route (`permission: 'deal.read'`). */\n\tguards: Record<string, unknown>\n\t/** Guards the route decides per call through `guardResolvers`. */\n\tdynamicGuards: readonly string[]\n}\n\n/** Read what `fn()` (and oRPC) recorded on a procedure. */\ntype MetaFrom<T> = [LibraryMeta<T>] extends [never]\n\t? Record<string, unknown>\n\t: LibraryMeta<T> extends StoredFnMeta<infer M, string>\n\t\t? M\n\t\t: Record<string, unknown>\n\ntype KeyFrom<T> = [LibraryMeta<T>] extends [never]\n\t? string\n\t: LibraryMeta<T> extends StoredFnMeta<object, infer K>\n\t\t? K\n\t\t: string\n\n/** Declares the route metadata contract; it does not provide defaults. */\nexport function defineMeta<T extends object>(): T {\n\treturn {} as T\n}\n\nexport function readFnMeta<T extends AnyProcedure>(\n\tprocedure: T\n): FnMeta<MetaFrom<T>, KeyFrom<T>> {\n\tconst def = procedureDefinition(procedure)\n\tconst stored = def.meta?.[FN_META_KEY] as StoredFnMeta | undefined\n\tconst route = def.route ?? {}\n\treturn {\n\t\tname: stored?.name,\n\t\tprocedure: stored?.procedure as KeyFrom<T> | undefined,\n\t\tmeta: (stored?.meta ?? {}) as Partial<MetaFrom<T>>,\n\t\tdescription: route.description ?? route.summary ?? '',\n\t\tsummary: route.summary,\n\t\tmethod: route.method,\n\t\tpath: route.path,\n\t\ttags: route.tags ?? [],\n\t\tstream:\n\t\t\tstored?.stream === true ||\n\t\t\tgetEventIteratorSchemaDetails(def.outputSchema) !== undefined,\n\t\tinputSchema: def.inputSchema,\n\t\toutputSchema: def.outputSchema,\n\t\tguards: stored?.guards ?? {},\n\t\tdynamicGuards: stored?.dynamicGuards ?? []\n\t}\n}\n\n/** Tool-safe name (`a-z0-9-_`): `Users.Get` becomes `users-get`. */\nexport function toToolName(name: string): string {\n\treturn name.toLowerCase().replace(/[^a-z0-9-_]/g, '-')\n}\n"]}
|
package/dist/otel.d.ts
CHANGED
|
@@ -60,12 +60,24 @@ export type Tracing = {
|
|
|
60
60
|
/** Set OK, or ERROR with `error`, and end the span. */
|
|
61
61
|
end(span: SpanLike | undefined, error?: unknown): void;
|
|
62
62
|
};
|
|
63
|
-
export declare function createTracing(otel: OtelApiLike | undefined
|
|
63
|
+
export declare function createTracing(otel: OtelApiLike | undefined,
|
|
64
|
+
/**
|
|
65
|
+
* Errors the caller drives (4xx, aborts). Their span keeps an unset status
|
|
66
|
+
* and no exception event, as OpenTelemetry asks of server spans, so the
|
|
67
|
+
* caller's text stays out of the trace; `fn.error_code` still names them.
|
|
68
|
+
*/
|
|
69
|
+
isExpectedError?: (error: unknown) => boolean): Tracing;
|
|
64
70
|
export declare function errorMessageOf(error: unknown): string;
|
|
65
|
-
/**
|
|
66
|
-
export declare function
|
|
71
|
+
/** An error's string `code` (`ORPCError`'s `NOT_FOUND`, Node's `ECONNRESET`). */
|
|
72
|
+
export declare function errorCodeOf(error: unknown): string | undefined;
|
|
73
|
+
/**
|
|
74
|
+
* Error fields for a log line, named like the `fn.completed` ones. Without
|
|
75
|
+
* `message`, the error's text (written for the caller) is left out.
|
|
76
|
+
*/
|
|
77
|
+
export declare function errorAttributes(error: unknown, message?: boolean): {
|
|
67
78
|
error_type: string;
|
|
68
|
-
|
|
79
|
+
error_code?: string;
|
|
80
|
+
error_message?: string;
|
|
69
81
|
};
|
|
70
82
|
export {};
|
|
71
83
|
//# sourceMappingURL=otel.d.ts.map
|
package/dist/otel.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"otel.d.ts","sourceRoot":"","sources":["../src/otel.ts"],"names":[],"mappings":"AAMA,wDAAwD;AACxD,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAA;AAEtD,6DAA6D;AAC7D,MAAM,WAAW,QAAQ;IACxB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,cAAc,GAAG,OAAO,CAAA;IACzD,SAAS,CAAC,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAA;IAC9D,eAAe,CAAC,SAAS,EAAE,KAAK,GAAG,OAAO,CAAA;IAC1C,GAAG,IAAI,OAAO,CAAA;CACd;AAED,KAAK,eAAe,GAAG;IACtB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAAA;CAC3C,CAAA;AAED,UAAU,UAAU,CAAC,KAAK;IACzB,eAAe,CAAC,CAAC,SAAS,CAAC,IAAI,EAAE,KAAK,KAAK,OAAO,EACjD,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,eAAe,EACxB,EAAE,EAAE,CAAC,GACH,UAAU,CAAC,CAAC,CAAC,CAAA;IAChB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,KAAK,CAAA;CACzD;AAED;;;;GAIG;AACH,MAAM,WAAW,WAAW,CAAC,KAAK,SAAS,QAAQ,GAAG,QAAQ;IAC7D,KAAK,EAAE;QAAE,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,CAAC,KAAK,CAAC,CAAA;KAAE,CAAA;IACrD,cAAc,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAA;IAC7C,QAAQ,EAAE;QACT,QAAQ,EAAE,MAAM,CAAA;QAChB,MAAM,EAAE,MAAM,CAAA;QACd,QAAQ,EAAE,MAAM,CAAA;KAChB,CAAA;IACD,uEAAuE;IACvE,OAAO,EAAE;QACR,MAAM,IAAI,OAAO,CAAA;QACjB,IAAI,CAAC,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,CAAA;KACvC,CAAA;CACD;AAED,wEAAwE;AACxE,MAAM,MAAM,MAAM,CAAC,KAAK,IACvB,KAAK,SAAS,WAAW,CAAC,MAAM,KAAK,CAAC,GAAG,KAAK,GAAG,QAAQ,CAAA;AAE1D,oEAAoE;AACpE,MAAM,MAAM,SAAS,GAAG,CACvB,IAAI,EAAE,QAAQ,GAAG,SAAS,EAC1B,GAAG,KAAK,EAAE,EAAE,GAAG,CAAC,OAAO,CAAC,KACpB,IAAI,CAAA;AAET,MAAM,MAAM,OAAO,GAAG;IACrB;;;;;;OAMG;IACH,MAAM,CAAC,CAAC,EACP,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,UAAU,GAAG,QAAQ,GAAG,UAAU,EACxC,EAAE,EAAE,CAAC,IAAI,EAAE,QAAQ,GAAG,SAAS,KAAK,OAAO,CAAC,CAAC,CAAC,EAC9C,SAAS,CAAC,EAAE,SAAS,GACnB,OAAO,CAAC,CAAC,CAAC,CAAA;IACb,yEAAyE;IACzE,SAAS,CACR,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,QAAQ,EACd,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,GACxC,QAAQ,GAAG,SAAS,CAAA;IACvB,uDAAuD;IACvD,GAAG,CAAC,IAAI,EAAE,QAAQ,GAAG,SAAS,EAAE,KAAK,CAAC,EAAE,OAAO,GAAG,IAAI,CAAA;CACtD,CAAA;AAED,wBAAgB,aAAa,
|
|
1
|
+
{"version":3,"file":"otel.d.ts","sourceRoot":"","sources":["../src/otel.ts"],"names":[],"mappings":"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"}
|
package/dist/otel.js
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
import { isAsyncIteratorObject, onStreamEnd } from './stream.js';
|
|
2
|
-
export function createTracing(otel
|
|
2
|
+
export function createTracing(otel,
|
|
3
|
+
/**
|
|
4
|
+
* Errors the caller drives (4xx, aborts). Their span keeps an unset status
|
|
5
|
+
* and no exception event, as OpenTelemetry asks of server spans, so the
|
|
6
|
+
* caller's text stays out of the trace; `fn.error_code` still names them.
|
|
7
|
+
*/
|
|
8
|
+
isExpectedError = () => false) {
|
|
3
9
|
let tracer;
|
|
4
10
|
try {
|
|
5
11
|
tracer = otel?.trace.getTracer('orpc-fn');
|
|
@@ -15,12 +21,24 @@ export function createTracing(otel) {
|
|
|
15
21
|
span.setStatus({ code: otel.SpanStatusCode.OK });
|
|
16
22
|
}
|
|
17
23
|
else {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
+
const code = errorCodeOf(error[0]);
|
|
25
|
+
if (code !== undefined)
|
|
26
|
+
span.setAttribute('fn.error_code', code);
|
|
27
|
+
let expected = false;
|
|
28
|
+
try {
|
|
29
|
+
expected = isExpectedError(error[0]);
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
/* A failing classifier treats the error as unexpected. */
|
|
33
|
+
}
|
|
34
|
+
if (!expected) {
|
|
35
|
+
span.setStatus({
|
|
36
|
+
code: otel.SpanStatusCode.ERROR,
|
|
37
|
+
message: errorMessageOf(error[0])
|
|
38
|
+
});
|
|
39
|
+
if (error[0] instanceof Error)
|
|
40
|
+
span.recordException(error[0]);
|
|
41
|
+
}
|
|
24
42
|
}
|
|
25
43
|
span.end();
|
|
26
44
|
};
|
|
@@ -112,11 +130,23 @@ export function createTracing(otel) {
|
|
|
112
130
|
export function errorMessageOf(error) {
|
|
113
131
|
return error instanceof Error ? error.message : String(error);
|
|
114
132
|
}
|
|
115
|
-
/**
|
|
116
|
-
export function
|
|
133
|
+
/** An error's string `code` (`ORPCError`'s `NOT_FOUND`, Node's `ECONNRESET`). */
|
|
134
|
+
export function errorCodeOf(error) {
|
|
135
|
+
const code = typeof error === 'object' && error !== null
|
|
136
|
+
? error.code
|
|
137
|
+
: undefined;
|
|
138
|
+
return typeof code === 'string' ? code : undefined;
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Error fields for a log line, named like the `fn.completed` ones. Without
|
|
142
|
+
* `message`, the error's text (written for the caller) is left out.
|
|
143
|
+
*/
|
|
144
|
+
export function errorAttributes(error, message = true) {
|
|
145
|
+
const code = errorCodeOf(error);
|
|
117
146
|
return {
|
|
118
147
|
error_type: error instanceof Error ? error.name : typeof error,
|
|
119
|
-
|
|
148
|
+
...(code === undefined ? {} : { error_code: code }),
|
|
149
|
+
...(message ? { error_message: errorMessageOf(error) } : {})
|
|
120
150
|
};
|
|
121
151
|
}
|
|
122
152
|
function protectSpan(span) {
|
package/dist/otel.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"otel.js","sourceRoot":"","sources":["../src/otel.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n\tisAsyncIteratorObject,\n\tonStreamEnd,\n\ttype StreamScope\n} from './stream.js'\n\n/** Attribute values accepted by OpenTelemetry spans. */\nexport type AttributeValue = string | number | boolean\n\n/** The part of an OpenTelemetry `Span` this package uses. */\nexport interface SpanLike {\n\tsetAttribute(key: string, value: AttributeValue): unknown\n\tsetStatus(status: { code: number; message?: string }): unknown\n\trecordException(exception: Error): unknown\n\tend(): unknown\n}\n\ntype SpanOptionsLike = {\n\tkind?: number\n\tattributes?: Record<string, AttributeValue>\n}\n\ninterface TracerLike<TSpan> {\n\tstartActiveSpan<F extends (span: TSpan) => unknown>(\n\t\tname: string,\n\t\toptions: SpanOptionsLike,\n\t\tfn: F\n\t): ReturnType<F>\n\tstartSpan(name: string, options?: SpanOptionsLike): TSpan\n}\n\n/**\n * The part of `@opentelemetry/api` this package uses. Pass the module itself:\n * `import * as otel from '@opentelemetry/api'` then `createFn({ otel })`.\n * Without it no spans are created and handlers receive `span: undefined`.\n */\nexport interface OtelApiLike<TSpan extends SpanLike = SpanLike> {\n\ttrace: { getTracer(name: string): TracerLike<TSpan> }\n\tSpanStatusCode: { OK: number; ERROR: number }\n\tSpanKind: {\n\t\tINTERNAL: number\n\t\tSERVER: number\n\t\tPRODUCER: number\n\t}\n\t/** Restores a span's context for each step of a stream it returned. */\n\tcontext: {\n\t\tactive(): unknown\n\t\twith<T>(context: never, fn: () => T): T\n\t}\n}\n\n/** The span type of an OpenTelemetry API, or `SpanLike` when absent. */\nexport type SpanOf<TOtel> =\n\tTOtel extends OtelApiLike<infer TSpan> ? TSpan : SpanLike\n\n/** Called once when a span's work is done, before the span ends. */\nexport type OnSettled = (\n\tspan: SpanLike | undefined,\n\t...error: [] | [unknown]\n) => void\n\nexport type Tracing = {\n\t/**\n\t * Run `fn` inside an active span: OK when it resolves, ERROR when it throws,\n\t * ended either way. When `fn` resolves to a stream, the span stays open -\n\t * and active for each step of the stream - until the stream ends.\n\t * `onSettled` runs once at that point, before the span ends. Without\n\t * OpenTelemetry `span` is undefined and `onSettled` still runs.\n\t */\n\tinSpan<T>(\n\t\tname: string,\n\t\tkind: 'INTERNAL' | 'SERVER' | 'PRODUCER',\n\t\tfn: (span: SpanLike | undefined) => Promise<T>,\n\t\tonSettled?: OnSettled\n\t): Promise<T>\n\t/** Start a span that the caller ends with `end` (long-lived streams). */\n\tstartSpan(\n\t\tname: string,\n\t\tkind: 'SERVER',\n\t\tattributes: Record<string, AttributeValue>\n\t): SpanLike | undefined\n\t/** Set OK, or ERROR with `error`, and end the span. */\n\tend(span: SpanLike | undefined, error?: unknown): void\n}\n\nexport function createTracing(otel: OtelApiLike | undefined): Tracing {\n\tlet tracer: TracerLike<SpanLike> | undefined\n\ttry {\n\t\ttracer = otel?.trace.getTracer('orpc-fn')\n\t} catch {\n\t\t/* Missing telemetry cannot prevent execution. */\n\t}\n\tconst end: Tracing['end'] = (span, ...error) => {\n\t\tif (!span || !otel) return\n\t\tspan = protectSpan(span)\n\t\tif (error.length === 0) {\n\t\t\tspan.setStatus({ code: otel.SpanStatusCode.OK })\n\t\t} else {\n\t\t\tspan.setStatus({\n\t\t\t\tcode: otel.SpanStatusCode.ERROR,\n\t\t\t\tmessage: errorMessageOf(error[0])\n\t\t\t})\n\t\t\tif (error[0] instanceof Error) span.recordException(error[0])\n\t\t}\n\t\tspan.end()\n\t}\n\treturn {\n\t\tinSpan(name, kind, fn, onSettled) {\n\t\t\tconst settle = (span: SpanLike | undefined, ...error: [] | [unknown]) => {\n\t\t\t\ttry {\n\t\t\t\t\tonSettled?.(span, ...error)\n\t\t\t\t} catch {\n\t\t\t\t\t/* Telemetry callbacks cannot replace the original result. */\n\t\t\t\t} finally {\n\t\t\t\t\tend(span, ...error)\n\t\t\t\t}\n\t\t\t}\n\t\t\tconst run = async (\n\t\t\t\tspan: SpanLike | undefined,\n\t\t\t\tscope?: StreamScope\n\t\t\t): Promise<Awaited<ReturnType<typeof fn>>> => {\n\t\t\t\tspan = span ? protectSpan(span) : undefined\n\t\t\t\tlet result: Awaited<ReturnType<typeof fn>>\n\t\t\t\ttry {\n\t\t\t\t\tresult = await fn(span)\n\t\t\t\t} catch (error) {\n\t\t\t\t\tsettle(span, error)\n\t\t\t\t\tthrow error\n\t\t\t\t}\n\t\t\t\tif (isAsyncIteratorObject(result)) {\n\t\t\t\t\treturn onStreamEnd(\n\t\t\t\t\t\tresult,\n\t\t\t\t\t\t(...error) => settle(span, ...error),\n\t\t\t\t\t\tscope\n\t\t\t\t\t) as typeof result\n\t\t\t\t}\n\t\t\t\tsettle(span)\n\t\t\t\treturn result\n\t\t\t}\n\t\t\tif (!tracer || !otel) return run(undefined)\n\t\t\tlet started: Promise<Awaited<ReturnType<typeof fn>>> | undefined\n\t\t\ttry {\n\t\t\t\treturn tracer.startActiveSpan(\n\t\t\t\t\tname,\n\t\t\t\t\t{ kind: otel.SpanKind[kind] },\n\t\t\t\t\t(span) => {\n\t\t\t\t\t\tlet active: unknown\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tactive = otel.context.active()\n\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t/* Fall back to the span without scope restoration. */\n\t\t\t\t\t\t}\n\t\t\t\t\t\tstarted = run(span, (step) => {\n\t\t\t\t\t\t\tlet completed: { value: ReturnType<typeof step> } | undefined\n\t\t\t\t\t\t\tlet failed: { error: unknown } | undefined\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\treturn otel.context.with(active as never, () => {\n\t\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\t\tconst value = step()\n\t\t\t\t\t\t\t\t\t\tcompleted = { value }\n\t\t\t\t\t\t\t\t\t\treturn value\n\t\t\t\t\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\t\t\t\t\tfailed = { error }\n\t\t\t\t\t\t\t\t\t\tthrow error\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t\tif (completed) return completed.value\n\t\t\t\t\t\t\t\tif (failed) throw failed.error\n\t\t\t\t\t\t\t\treturn step()\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t})\n\t\t\t\t\t\treturn started\n\t\t\t\t\t}\n\t\t\t\t)\n\t\t\t} catch {\n\t\t\t\treturn started ?? run(undefined)\n\t\t\t}\n\t\t},\n\t\tstartSpan(name, kind, attributes) {\n\t\t\tif (!tracer || !otel) return undefined\n\t\t\ttry {\n\t\t\t\treturn protectSpan(\n\t\t\t\t\ttracer.startSpan(name, { kind: otel.SpanKind[kind], attributes })\n\t\t\t\t)\n\t\t\t} catch {\n\t\t\t\treturn undefined\n\t\t\t}\n\t\t},\n\t\tend\n\t}\n}\n\nexport function errorMessageOf(error: unknown): string {\n\treturn error instanceof Error ? error.message : String(error)\n}\n\n/** Error fields for a log line, named like the `fn.completed` ones. */\nexport function errorAttributes(error: unknown) {\n\treturn {\n\t\terror_type: error instanceof Error ? error.name : typeof error,\n\t\terror_message: errorMessageOf(error)\n\t}\n}\n\nfunction protectSpan<T extends SpanLike>(span: T): T {\n\treturn new Proxy(span, {\n\t\tget(target, key) {\n\t\t\tconst value = Reflect.get(target, key, target)\n\t\t\tif (typeof value !== 'function') return value\n\t\t\tif (\n\t\t\t\t['setAttribute', 'setStatus', 'recordException', 'end'].includes(\n\t\t\t\t\tString(key)\n\t\t\t\t)\n\t\t\t)\n\t\t\t\treturn (...args: unknown[]) => {\n\t\t\t\t\ttry {\n\t\t\t\t\t\treturn value.apply(target, args)\n\t\t\t\t\t} catch {\n\t\t\t\t\t\t/* Ignore exporter failures. */\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\treturn value.bind(target)\n\t\t}\n\t})\n}\n"]}
|
|
1
|
+
{"version":3,"file":"otel.js","sourceRoot":"","sources":["../src/otel.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n\tisAsyncIteratorObject,\n\tonStreamEnd,\n\ttype StreamScope\n} from './stream.js'\n\n/** Attribute values accepted by OpenTelemetry spans. */\nexport type AttributeValue = string | number | boolean\n\n/** The part of an OpenTelemetry `Span` this package uses. */\nexport interface SpanLike {\n\tsetAttribute(key: string, value: AttributeValue): unknown\n\tsetStatus(status: { code: number; message?: string }): unknown\n\trecordException(exception: Error): unknown\n\tend(): unknown\n}\n\ntype SpanOptionsLike = {\n\tkind?: number\n\tattributes?: Record<string, AttributeValue>\n}\n\ninterface TracerLike<TSpan> {\n\tstartActiveSpan<F extends (span: TSpan) => unknown>(\n\t\tname: string,\n\t\toptions: SpanOptionsLike,\n\t\tfn: F\n\t): ReturnType<F>\n\tstartSpan(name: string, options?: SpanOptionsLike): TSpan\n}\n\n/**\n * The part of `@opentelemetry/api` this package uses. Pass the module itself:\n * `import * as otel from '@opentelemetry/api'` then `createFn({ otel })`.\n * Without it no spans are created and handlers receive `span: undefined`.\n */\nexport interface OtelApiLike<TSpan extends SpanLike = SpanLike> {\n\ttrace: { getTracer(name: string): TracerLike<TSpan> }\n\tSpanStatusCode: { OK: number; ERROR: number }\n\tSpanKind: {\n\t\tINTERNAL: number\n\t\tSERVER: number\n\t\tPRODUCER: number\n\t}\n\t/** Restores a span's context for each step of a stream it returned. */\n\tcontext: {\n\t\tactive(): unknown\n\t\twith<T>(context: never, fn: () => T): T\n\t}\n}\n\n/** The span type of an OpenTelemetry API, or `SpanLike` when absent. */\nexport type SpanOf<TOtel> =\n\tTOtel extends OtelApiLike<infer TSpan> ? TSpan : SpanLike\n\n/** Called once when a span's work is done, before the span ends. */\nexport type OnSettled = (\n\tspan: SpanLike | undefined,\n\t...error: [] | [unknown]\n) => void\n\nexport type Tracing = {\n\t/**\n\t * Run `fn` inside an active span: OK when it resolves, ERROR when it throws,\n\t * ended either way. When `fn` resolves to a stream, the span stays open -\n\t * and active for each step of the stream - until the stream ends.\n\t * `onSettled` runs once at that point, before the span ends. Without\n\t * OpenTelemetry `span` is undefined and `onSettled` still runs.\n\t */\n\tinSpan<T>(\n\t\tname: string,\n\t\tkind: 'INTERNAL' | 'SERVER' | 'PRODUCER',\n\t\tfn: (span: SpanLike | undefined) => Promise<T>,\n\t\tonSettled?: OnSettled\n\t): Promise<T>\n\t/** Start a span that the caller ends with `end` (long-lived streams). */\n\tstartSpan(\n\t\tname: string,\n\t\tkind: 'SERVER',\n\t\tattributes: Record<string, AttributeValue>\n\t): SpanLike | undefined\n\t/** Set OK, or ERROR with `error`, and end the span. */\n\tend(span: SpanLike | undefined, error?: unknown): void\n}\n\nexport function createTracing(\n\totel: OtelApiLike | undefined,\n\t/**\n\t * Errors the caller drives (4xx, aborts). Their span keeps an unset status\n\t * and no exception event, as OpenTelemetry asks of server spans, so the\n\t * caller's text stays out of the trace; `fn.error_code` still names them.\n\t */\n\tisExpectedError: (error: unknown) => boolean = () => false\n): Tracing {\n\tlet tracer: TracerLike<SpanLike> | undefined\n\ttry {\n\t\ttracer = otel?.trace.getTracer('orpc-fn')\n\t} catch {\n\t\t/* Missing telemetry cannot prevent execution. */\n\t}\n\tconst end: Tracing['end'] = (span, ...error) => {\n\t\tif (!span || !otel) return\n\t\tspan = protectSpan(span)\n\t\tif (error.length === 0) {\n\t\t\tspan.setStatus({ code: otel.SpanStatusCode.OK })\n\t\t} else {\n\t\t\tconst code = errorCodeOf(error[0])\n\t\t\tif (code !== undefined) span.setAttribute('fn.error_code', code)\n\t\t\tlet expected = false\n\t\t\ttry {\n\t\t\t\texpected = isExpectedError(error[0])\n\t\t\t} catch {\n\t\t\t\t/* A failing classifier treats the error as unexpected. */\n\t\t\t}\n\t\t\tif (!expected) {\n\t\t\t\tspan.setStatus({\n\t\t\t\t\tcode: otel.SpanStatusCode.ERROR,\n\t\t\t\t\tmessage: errorMessageOf(error[0])\n\t\t\t\t})\n\t\t\t\tif (error[0] instanceof Error) span.recordException(error[0])\n\t\t\t}\n\t\t}\n\t\tspan.end()\n\t}\n\treturn {\n\t\tinSpan(name, kind, fn, onSettled) {\n\t\t\tconst settle = (span: SpanLike | undefined, ...error: [] | [unknown]) => {\n\t\t\t\ttry {\n\t\t\t\t\tonSettled?.(span, ...error)\n\t\t\t\t} catch {\n\t\t\t\t\t/* Telemetry callbacks cannot replace the original result. */\n\t\t\t\t} finally {\n\t\t\t\t\tend(span, ...error)\n\t\t\t\t}\n\t\t\t}\n\t\t\tconst run = async (\n\t\t\t\tspan: SpanLike | undefined,\n\t\t\t\tscope?: StreamScope\n\t\t\t): Promise<Awaited<ReturnType<typeof fn>>> => {\n\t\t\t\tspan = span ? protectSpan(span) : undefined\n\t\t\t\tlet result: Awaited<ReturnType<typeof fn>>\n\t\t\t\ttry {\n\t\t\t\t\tresult = await fn(span)\n\t\t\t\t} catch (error) {\n\t\t\t\t\tsettle(span, error)\n\t\t\t\t\tthrow error\n\t\t\t\t}\n\t\t\t\tif (isAsyncIteratorObject(result)) {\n\t\t\t\t\treturn onStreamEnd(\n\t\t\t\t\t\tresult,\n\t\t\t\t\t\t(...error) => settle(span, ...error),\n\t\t\t\t\t\tscope\n\t\t\t\t\t) as typeof result\n\t\t\t\t}\n\t\t\t\tsettle(span)\n\t\t\t\treturn result\n\t\t\t}\n\t\t\tif (!tracer || !otel) return run(undefined)\n\t\t\tlet started: Promise<Awaited<ReturnType<typeof fn>>> | undefined\n\t\t\ttry {\n\t\t\t\treturn tracer.startActiveSpan(\n\t\t\t\t\tname,\n\t\t\t\t\t{ kind: otel.SpanKind[kind] },\n\t\t\t\t\t(span) => {\n\t\t\t\t\t\tlet active: unknown\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tactive = otel.context.active()\n\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t/* Fall back to the span without scope restoration. */\n\t\t\t\t\t\t}\n\t\t\t\t\t\tstarted = run(span, (step) => {\n\t\t\t\t\t\t\tlet completed: { value: ReturnType<typeof step> } | undefined\n\t\t\t\t\t\t\tlet failed: { error: unknown } | undefined\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\treturn otel.context.with(active as never, () => {\n\t\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\t\tconst value = step()\n\t\t\t\t\t\t\t\t\t\tcompleted = { value }\n\t\t\t\t\t\t\t\t\t\treturn value\n\t\t\t\t\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\t\t\t\t\tfailed = { error }\n\t\t\t\t\t\t\t\t\t\tthrow error\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t\tif (completed) return completed.value\n\t\t\t\t\t\t\t\tif (failed) throw failed.error\n\t\t\t\t\t\t\t\treturn step()\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t})\n\t\t\t\t\t\treturn started\n\t\t\t\t\t}\n\t\t\t\t)\n\t\t\t} catch {\n\t\t\t\treturn started ?? run(undefined)\n\t\t\t}\n\t\t},\n\t\tstartSpan(name, kind, attributes) {\n\t\t\tif (!tracer || !otel) return undefined\n\t\t\ttry {\n\t\t\t\treturn protectSpan(\n\t\t\t\t\ttracer.startSpan(name, { kind: otel.SpanKind[kind], attributes })\n\t\t\t\t)\n\t\t\t} catch {\n\t\t\t\treturn undefined\n\t\t\t}\n\t\t},\n\t\tend\n\t}\n}\n\nexport function errorMessageOf(error: unknown): string {\n\treturn error instanceof Error ? error.message : String(error)\n}\n\n/** An error's string `code` (`ORPCError`'s `NOT_FOUND`, Node's `ECONNRESET`). */\nexport function errorCodeOf(error: unknown): string | undefined {\n\tconst code =\n\t\ttypeof error === 'object' && error !== null\n\t\t\t? (error as { code?: unknown }).code\n\t\t\t: undefined\n\treturn typeof code === 'string' ? code : undefined\n}\n\n/**\n * Error fields for a log line, named like the `fn.completed` ones. Without\n * `message`, the error's text (written for the caller) is left out.\n */\nexport function errorAttributes(error: unknown, message = true) {\n\tconst code = errorCodeOf(error)\n\treturn {\n\t\terror_type: error instanceof Error ? error.name : typeof error,\n\t\t...(code === undefined ? {} : { error_code: code }),\n\t\t...(message ? { error_message: errorMessageOf(error) } : {})\n\t}\n}\n\nfunction protectSpan<T extends SpanLike>(span: T): T {\n\treturn new Proxy(span, {\n\t\tget(target, key) {\n\t\t\tconst value = Reflect.get(target, key, target)\n\t\t\tif (typeof value !== 'function') return value\n\t\t\tif (\n\t\t\t\t['setAttribute', 'setStatus', 'recordException', 'end'].includes(\n\t\t\t\t\tString(key)\n\t\t\t\t)\n\t\t\t)\n\t\t\t\treturn (...args: unknown[]) => {\n\t\t\t\t\ttry {\n\t\t\t\t\t\treturn value.apply(target, args)\n\t\t\t\t\t} catch {\n\t\t\t\t\t\t/* Ignore exporter failures. */\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\treturn value.bind(target)\n\t\t}\n\t})\n}\n"]}
|
package/dist/react.d.ts
CHANGED
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
import { type QueryKey, type UseQueryOptions, type UseQueryResult } from '@tanstack/react-query';
|
|
2
2
|
import { type InvalidationStreamOptions, type LiveConnectionStatus } from './realtime.js';
|
|
3
|
+
import { streamCall } from './stream-call.js';
|
|
3
4
|
export type { InvalidationDomain, LiveConnectionStatus } from './realtime.js';
|
|
4
|
-
/**
|
|
5
|
+
/**
|
|
6
|
+
* An oRPC client procedure fits: `client.order.watch`. It gets `streamCall`
|
|
7
|
+
* as its client context, which keeps it out of `createRpcLink`'s batches.
|
|
8
|
+
*/
|
|
5
9
|
export type SubscribeFn<TInput, TEvent> = (input: TInput, options: {
|
|
6
10
|
signal: AbortSignal;
|
|
11
|
+
context: typeof streamCall;
|
|
7
12
|
}) => Promise<AsyncIterable<TEvent>>;
|
|
8
13
|
export type UseOrpcSubscriptionOptions<TInput, TEvent> = {
|
|
9
14
|
/** Run the stream (default: true). */
|
package/dist/react.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"react.d.ts","sourceRoot":"","sources":["../src/react.ts"],"names":[],"mappings":"AAAA,OAAO,EAIN,KAAK,QAAQ,EACb,KAAK,eAAe,EACpB,KAAK,cAAc,EAGnB,MAAM,uBAAuB,CAAA;AAE9B,OAAO,EAIN,KAAK,yBAAyB,EAC9B,KAAK,oBAAoB,EAGzB,MAAM,eAAe,CAAA;
|
|
1
|
+
{"version":3,"file":"react.d.ts","sourceRoot":"","sources":["../src/react.ts"],"names":[],"mappings":"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"}
|
package/dist/react.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { focusManager, hashKey, keepPreviousData, useQuery, useQueryClient } from '@tanstack/react-query';
|
|
2
2
|
import { useEffect, useRef, useState, useSyncExternalStore } from 'react';
|
|
3
3
|
import { createInvalidationCoordinator, createStreamScope, createSubscriptionRunner, seedQueryFn } from './realtime.js';
|
|
4
|
+
import { streamCall } from './stream-call.js';
|
|
4
5
|
const subscribeFocus = (listener) => focusManager.subscribe(listener);
|
|
5
6
|
const getFocus = () => focusManager.isFocused();
|
|
6
7
|
/** Whether the app is focused, from TanStack's `focusManager`. */
|
|
@@ -25,7 +26,10 @@ export function useOrpcSubscription(input, subscribe, options = {}) {
|
|
|
25
26
|
runnerRef.current = createSubscriptionRunner({
|
|
26
27
|
open: (signal) => {
|
|
27
28
|
openedInput = latest.current.input;
|
|
28
|
-
return latest.current.subscribe(openedInput, {
|
|
29
|
+
return latest.current.subscribe(openedInput, {
|
|
30
|
+
signal,
|
|
31
|
+
context: streamCall
|
|
32
|
+
});
|
|
29
33
|
},
|
|
30
34
|
canConnect: () => latest.current.shouldRun,
|
|
31
35
|
shouldReconnect: () => latest.current.shouldRun,
|
package/dist/react.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"react.js","sourceRoot":"","sources":["../src/react.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n\tfocusManager,\n\thashKey,\n\tkeepPreviousData,\n\ttype QueryKey,\n\ttype UseQueryOptions,\n\ttype UseQueryResult,\n\tuseQuery,\n\tuseQueryClient\n} from '@tanstack/react-query'\nimport { useEffect, useRef, useState, useSyncExternalStore } from 'react'\nimport {\n\tcreateInvalidationCoordinator,\n\tcreateStreamScope,\n\tcreateSubscriptionRunner,\n\ttype InvalidationStreamOptions,\n\ttype LiveConnectionStatus,\n\ttype SubscriptionRunner,\n\tseedQueryFn\n} from './realtime.js'\n\nexport type { InvalidationDomain, LiveConnectionStatus } from './realtime.js'\n\n/** An oRPC client procedure fits: `client.order.watch`. */\nexport type SubscribeFn<TInput, TEvent> = (\n\tinput: TInput,\n\toptions: { signal: AbortSignal }\n) => Promise<AsyncIterable<TEvent>>\n\nexport type UseOrpcSubscriptionOptions<TInput, TEvent> = {\n\t/** Run the stream (default: true). */\n\tenabled?: boolean | undefined\n\tonEvent?: (\n\t\tevent: TEvent,\n\t\tmeta: { connectionId: number; input: TInput }\n\t) => void\n\t/** Every successful connect; `connectionId > 1` is a reconnect. */\n\tonConnect?: (connectionId: number) => void\n\tonError?: ((error: Error) => void) | undefined\n\tonClose?: () => void\n\t/**\n\t * Close the stream while the app is not focused (default: true). Focus is\n\t * TanStack's `focusManager`: on React Native, wire it to `AppState` once.\n\t */\n\tpauseWhenUnfocused?: boolean | undefined\n}\n\nconst subscribeFocus = (listener: () => void) =>\n\tfocusManager.subscribe(listener)\nconst getFocus = () => focusManager.isFocused()\n\n/** Whether the app is focused, from TanStack's `focusManager`. */\nfunction useIsFocused(): boolean {\n\treturn useSyncExternalStore(subscribeFocus, getFocus, getFocus)\n}\n\n/**\n * An oRPC event iterator with backoff reconnects that closes while the app is\n * backgrounded. A changed input (compared as JSON) reconnects with a fresh\n * retry budget.\n */\nexport function useOrpcSubscription<TInput, TEvent>(\n\tinput: TInput,\n\tsubscribe: SubscribeFn<TInput, TEvent>,\n\toptions: UseOrpcSubscriptionOptions<TInput, TEvent> = {}\n): { status: LiveConnectionStatus } {\n\tconst { enabled = true, pauseWhenUnfocused = true } = options\n\tconst focused = useIsFocused()\n\tconst shouldRun = enabled && (!pauseWhenUnfocused || focused)\n\tconst [status, setStatus] = useState<LiveConnectionStatus>('idle')\n\n\tconst latest = useRef({ input, subscribe, options, shouldRun })\n\tlatest.current = { input, subscribe, options, shouldRun }\n\n\tconst runnerRef = useRef<SubscriptionRunner | null>(null)\n\tif (!runnerRef.current) {\n\t\tlet openedInput = input\n\t\trunnerRef.current = createSubscriptionRunner<TEvent>({\n\t\t\topen: (signal) => {\n\t\t\t\topenedInput = latest.current.input\n\t\t\t\treturn latest.current.subscribe(openedInput, { signal })\n\t\t\t},\n\t\t\tcanConnect: () => latest.current.shouldRun,\n\t\t\tshouldReconnect: () => latest.current.shouldRun,\n\t\t\tonStatus: setStatus,\n\t\t\tonEvent: (event, connectionId) =>\n\t\t\t\tlatest.current.options.onEvent?.(event, {\n\t\t\t\t\tconnectionId,\n\t\t\t\t\tinput: openedInput\n\t\t\t\t}),\n\t\t\tonConnect: (id) => latest.current.options.onConnect?.(id),\n\t\t\tonError: (error) => latest.current.options.onError?.(error),\n\t\t\tonClose: () => latest.current.options.onClose?.()\n\t\t})\n\t}\n\tconst runner = runnerRef.current\n\tconst serializedInput = JSON.stringify(input)\n\n\t// biome-ignore lint/correctness/useExhaustiveDependencies: a changed input resubscribes\n\tuseEffect(() => {\n\t\tif (!shouldRun) return\n\t\tvoid runner.start()\n\t\treturn () => void runner.disconnect()\n\t}, [runner, shouldRun, serializedInput])\n\n\treturn { status }\n}\n\ntype ApplyEvent<TStreamEvent, TData> = (\n\tevent: TStreamEvent,\n\tprevious: TData | undefined\n) => TData | undefined\n\ntype LiveQueryOptions<\n\tTInput,\n\tTRouteData,\n\tTStreamEvent,\n\tTData,\n\tTSubscriptionInput\n> = {\n\t/** Run the query and its stream (default: true). */\n\tenabled?: boolean | undefined\n\t/** Input for the stream when it differs from the query's. */\n\tsubscriptionInput?: TSubscriptionInput | undefined\n\t/**\n\t * Convert the route output once at fetch time into a differently typed\n\t * cache; `applyEvent` then reduces stream events into that cache.\n\t */\n\tselect?: (data: TRouteData) => TData\n\t/** The raw route output of a seed, before `select` drops fields. */\n\tonSeed?: (data: TRouteData, input: TInput) => void\n\t/**\n\t * Fold a stream event into the cached data. Required when the stream sends\n\t * something other than the cached type (an `fnLive` patch route, or a\n\t * `select`ed cache). Return `undefined` to skip the write.\n\t */\n\tapplyEvent?: ApplyEvent<TStreamEvent, NoInfer<TData>>\n\tonEvent?: (event: TStreamEvent, meta: { connectionId: number }) => void\n\tonError?: ((error: Error) => void) | undefined\n\t/**\n\t * Reconcile a fetched seed with what the stream already wrote. The HTTP\n\t * request can resolve last, so a plain overwrite would drop events that\n\t * arrived while it was in flight. Default: take the fetched value.\n\t */\n\tmergeSeed?: (\n\t\tfetched: NoInfer<TData>,\n\t\tcached: NoInfer<TData> | undefined\n\t) => NoInfer<TData>\n\t/** Show the previous key's data while a new key loads (default: true). */\n\tkeepPreviousData?: boolean\n\t/** Close the stream while the app is not focused (default: true). */\n\tpauseWhenUnfocused?: boolean | undefined\n}\n\ntype LiveQueryOptionsFn<TInput, TData, TError> = (\n\tinput: TInput\n) => UseQueryOptions<TData, TError, TData, QueryKey>\n\ntype LiveQueryResult<TData, TError> = UseQueryResult<TData, TError> & {\n\tliveStatus: LiveConnectionStatus\n}\n\n/**\n * The client half of `fnLive`: the HTTP query seeds the cache, and the live\n * route's stream writes each snapshot into the same cache entry. Marked\n * `meta.live`, so invalidation streams leave it alone.\n *\n * ```tsx\n * const order = useLiveQuery({ id }, (input) => orpc.order.get.queryOptions({ input }), client.order.watch)\n * ```\n *\n * One signature, not overloads: TypeScript fixes an untyped callback's\n * parameters at the first overload it tries, which made valid calls fail.\n */\nexport function useLiveQuery<\n\tTInput,\n\tTRouteData,\n\tTStreamEvent,\n\tTData = TRouteData,\n\tTError = Error,\n\tTSubscriptionInput = TInput\n>(\n\tinput: TInput,\n\tqueryOptionsFn: LiveQueryOptionsFn<TInput, TRouteData, TError>,\n\tsubscribe: SubscribeFn<NoInfer<TSubscriptionInput>, TStreamEvent>,\n\t...options: [TStreamEvent] extends [TData]\n\t\t? [\n\t\t\t\toptions?: LiveQueryOptions<\n\t\t\t\t\tTInput,\n\t\t\t\t\tTRouteData,\n\t\t\t\t\tTStreamEvent,\n\t\t\t\t\tTData,\n\t\t\t\t\tTSubscriptionInput\n\t\t\t\t>\n\t\t\t]\n\t\t: [\n\t\t\t\toptions: LiveQueryOptions<\n\t\t\t\t\tTInput,\n\t\t\t\t\tTRouteData,\n\t\t\t\t\tTStreamEvent,\n\t\t\t\t\tTData,\n\t\t\t\t\tTSubscriptionInput\n\t\t\t\t> & { applyEvent: ApplyEvent<TStreamEvent, NoInfer<TData>> }\n\t\t\t]\n): LiveQueryResult<TData, TError>\nexport function useLiveQuery<\n\tTInput,\n\tTRouteData,\n\tTStreamEvent,\n\tTData,\n\tTError,\n\tTSubscriptionInput\n>(\n\tinput: TInput,\n\tqueryOptionsFn: LiveQueryOptionsFn<TInput, TRouteData, TError>,\n\tsubscribe: SubscribeFn<TSubscriptionInput, TStreamEvent>,\n\toptions: LiveQueryOptions<\n\t\tTInput,\n\t\tTRouteData,\n\t\tTStreamEvent,\n\t\tTData,\n\t\tTSubscriptionInput\n\t> = {}\n): LiveQueryResult<TData, TError> {\n\tconst queryClient = useQueryClient()\n\tconst focused = useIsFocused()\n\tconst [scope] = useState(createStreamScope)\n\n\t// oRPC query options are plain objects; `queryFn` is read through one shape.\n\tconst raw = queryOptionsFn(input) as unknown as {\n\t\tqueryKey: QueryKey\n\t\tqueryFn?: (context: unknown) => Promise<TRouteData>\n\t\tenabled?: UseQueryOptions['enabled']\n\t\tmeta?: Record<string, unknown>\n\t} & Record<string, unknown>\n\tconst keyHash = hashKey(raw.queryKey)\n\tconst latest = useRef({ raw, keyHash, options })\n\tlatest.current = { raw, keyHash, options }\n\n\tconst { status } = useOrpcSubscription(\n\t\t(options.subscriptionInput === undefined\n\t\t\t? input\n\t\t\t: options.subscriptionInput) as TSubscriptionInput,\n\t\tsubscribe,\n\t\t{\n\t\t\tenabled: options.enabled,\n\t\t\tpauseWhenUnfocused: options.pauseWhenUnfocused,\n\t\t\tonError: options.onError,\n\t\t\tonConnect: (connectionId) =>\n\t\t\t\tscope.open(connectionId, latest.current.keyHash),\n\t\t\tonEvent: (event, { connectionId }) => {\n\t\t\t\tconst current = latest.current\n\t\t\t\t// The consumer callback must not see an event for a scope no longer shown.\n\t\t\t\tif (!scope.owns(connectionId, current.keyHash)) return\n\t\t\t\t// Without `applyEvent` the stream event is the cache type (the first overload).\n\t\t\t\tconst applyEvent =\n\t\t\t\t\tcurrent.options.applyEvent ??\n\t\t\t\t\t((streamEvent: TStreamEvent) => streamEvent as unknown as TData)\n\t\t\t\tconst key = current.raw.queryKey\n\t\t\t\tconst next = applyEvent(event, queryClient.getQueryData<TData>(key))\n\t\t\t\tif (next !== undefined) queryClient.setQueryData(key, next)\n\t\t\t\tcurrent.options.onEvent?.(event, { connectionId })\n\t\t\t}\n\t\t}\n\t)\n\n\tconst wrapsSeed = options.select || options.mergeSeed\n\tconst queryFn =\n\t\traw.queryFn && wrapsSeed\n\t\t\t? seedQueryFn(raw.queryFn, {\n\t\t\t\t\tinput,\n\t\t\t\t\treadCache: () => queryClient.getQueryData<TData>(raw.queryKey),\n\t\t\t\t\tselect: options.select,\n\t\t\t\t\tonSeed: options.onSeed,\n\t\t\t\t\tmergeSeed: options.mergeSeed\n\t\t\t\t})\n\t\t\t: raw.queryFn\n\tconst runs = options.enabled !== false && focused\n\tconst query = useQuery({\n\t\t...raw,\n\t\t...(queryFn ? { queryFn } : {}),\n\t\tenabled: runs ? (raw.enabled ?? true) : false,\n\t\t...(options.keepPreviousData === false\n\t\t\t? {}\n\t\t\t: { placeholderData: keepPreviousData }),\n\t\tstaleTime: Number.POSITIVE_INFINITY,\n\t\tmeta: { ...raw.meta, live: true }\n\t} as UseQueryOptions<TData, TError, TData, QueryKey>)\n\n\treturn Object.assign(query, { liveStatus: status })\n}\n\n/**\n * One app-wide stream of `{ domain }` change events that keeps list and count\n * queries fresh: each event invalidates its domain's query keys (debounced),\n * and a reconnect that proves healthy invalidates every domain to cover\n * events lost while it was down. Mount once, in the signed-in shell.\n *\n * ```ts\n * useInvalidationStream({}, client.realtime.subscribeChanges, {\n * enabled: signedIn,\n * domains: { order: { debounceMs: 100, queryKeys: [orpc.order.key()] } }\n * })\n * ```\n */\nexport function useInvalidationStream<\n\tTInput,\n\tTEvent extends { domain: string }\n>(\n\tinput: TInput,\n\tsubscribe: SubscribeFn<TInput, TEvent>,\n\toptions: InvalidationStreamOptions<TEvent> &\n\t\tPick<\n\t\t\tUseOrpcSubscriptionOptions<TInput, TEvent>,\n\t\t\t'enabled' | 'pauseWhenUnfocused'\n\t\t>\n): { status: LiveConnectionStatus } {\n\tconst queryClient = useQueryClient()\n\tconst latestOptions = useRef(options)\n\tlatestOptions.current = options\n\t// `domains`, `refetchType` and `logger` are read on mount; `onEvent` stays current.\n\tconst [coordinator] = useState(() =>\n\t\tcreateInvalidationCoordinator<TEvent>(queryClient, {\n\t\t\t...options,\n\t\t\tonEvent: (event) => latestOptions.current.onEvent?.(event)\n\t\t})\n\t)\n\tuseEffect(() => coordinator.dispose, [coordinator])\n\n\treturn useOrpcSubscription<TInput, TEvent>(input, subscribe, {\n\t\tenabled: options.enabled,\n\t\tpauseWhenUnfocused: options.pauseWhenUnfocused,\n\t\tonEvent: coordinator.event,\n\t\tonConnect: coordinator.connect,\n\t\tonError: coordinator.lost,\n\t\tonClose: coordinator.lost\n\t})\n}\n\n/**\n * Clear the query cache when the signed-in owner of the cached data changes\n * (another user, another organization), so the next one never sees it.\n * `null` means signed out: signing in starts from the cache sign-out emptied.\n * Pass the same owner as the persister's `buster` so a saved cache from\n * someone else is discarded on the next launch too.\n */\nexport function useQueryCacheOwner(owner: string | null): void {\n\tconst queryClient = useQueryClient()\n\tconst previous = useRef(owner)\n\tuseEffect(() => {\n\t\tconst before = previous.current\n\t\tprevious.current = owner\n\t\tif (owner !== before && before !== null) queryClient.clear()\n\t}, [owner, queryClient])\n}\n"]}
|
|
1
|
+
{"version":3,"file":"react.js","sourceRoot":"","sources":["../src/react.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n\tfocusManager,\n\thashKey,\n\tkeepPreviousData,\n\ttype QueryKey,\n\ttype UseQueryOptions,\n\ttype UseQueryResult,\n\tuseQuery,\n\tuseQueryClient\n} from '@tanstack/react-query'\nimport { useEffect, useRef, useState, useSyncExternalStore } from 'react'\nimport {\n\tcreateInvalidationCoordinator,\n\tcreateStreamScope,\n\tcreateSubscriptionRunner,\n\ttype InvalidationStreamOptions,\n\ttype LiveConnectionStatus,\n\ttype SubscriptionRunner,\n\tseedQueryFn\n} from './realtime.js'\nimport { streamCall } from './stream-call.js'\n\nexport type { InvalidationDomain, LiveConnectionStatus } from './realtime.js'\n\n/**\n * An oRPC client procedure fits: `client.order.watch`. It gets `streamCall`\n * as its client context, which keeps it out of `createRpcLink`'s batches.\n */\nexport type SubscribeFn<TInput, TEvent> = (\n\tinput: TInput,\n\toptions: { signal: AbortSignal; context: typeof streamCall }\n) => Promise<AsyncIterable<TEvent>>\n\nexport type UseOrpcSubscriptionOptions<TInput, TEvent> = {\n\t/** Run the stream (default: true). */\n\tenabled?: boolean | undefined\n\tonEvent?: (\n\t\tevent: TEvent,\n\t\tmeta: { connectionId: number; input: TInput }\n\t) => void\n\t/** Every successful connect; `connectionId > 1` is a reconnect. */\n\tonConnect?: (connectionId: number) => void\n\tonError?: ((error: Error) => void) | undefined\n\tonClose?: () => void\n\t/**\n\t * Close the stream while the app is not focused (default: true). Focus is\n\t * TanStack's `focusManager`: on React Native, wire it to `AppState` once.\n\t */\n\tpauseWhenUnfocused?: boolean | undefined\n}\n\nconst subscribeFocus = (listener: () => void) =>\n\tfocusManager.subscribe(listener)\nconst getFocus = () => focusManager.isFocused()\n\n/** Whether the app is focused, from TanStack's `focusManager`. */\nfunction useIsFocused(): boolean {\n\treturn useSyncExternalStore(subscribeFocus, getFocus, getFocus)\n}\n\n/**\n * An oRPC event iterator with backoff reconnects that closes while the app is\n * backgrounded. A changed input (compared as JSON) reconnects with a fresh\n * retry budget.\n */\nexport function useOrpcSubscription<TInput, TEvent>(\n\tinput: TInput,\n\tsubscribe: SubscribeFn<TInput, TEvent>,\n\toptions: UseOrpcSubscriptionOptions<TInput, TEvent> = {}\n): { status: LiveConnectionStatus } {\n\tconst { enabled = true, pauseWhenUnfocused = true } = options\n\tconst focused = useIsFocused()\n\tconst shouldRun = enabled && (!pauseWhenUnfocused || focused)\n\tconst [status, setStatus] = useState<LiveConnectionStatus>('idle')\n\n\tconst latest = useRef({ input, subscribe, options, shouldRun })\n\tlatest.current = { input, subscribe, options, shouldRun }\n\n\tconst runnerRef = useRef<SubscriptionRunner | null>(null)\n\tif (!runnerRef.current) {\n\t\tlet openedInput = input\n\t\trunnerRef.current = createSubscriptionRunner<TEvent>({\n\t\t\topen: (signal) => {\n\t\t\t\topenedInput = latest.current.input\n\t\t\t\treturn latest.current.subscribe(openedInput, {\n\t\t\t\t\tsignal,\n\t\t\t\t\tcontext: streamCall\n\t\t\t\t})\n\t\t\t},\n\t\t\tcanConnect: () => latest.current.shouldRun,\n\t\t\tshouldReconnect: () => latest.current.shouldRun,\n\t\t\tonStatus: setStatus,\n\t\t\tonEvent: (event, connectionId) =>\n\t\t\t\tlatest.current.options.onEvent?.(event, {\n\t\t\t\t\tconnectionId,\n\t\t\t\t\tinput: openedInput\n\t\t\t\t}),\n\t\t\tonConnect: (id) => latest.current.options.onConnect?.(id),\n\t\t\tonError: (error) => latest.current.options.onError?.(error),\n\t\t\tonClose: () => latest.current.options.onClose?.()\n\t\t})\n\t}\n\tconst runner = runnerRef.current\n\tconst serializedInput = JSON.stringify(input)\n\n\t// biome-ignore lint/correctness/useExhaustiveDependencies: a changed input resubscribes\n\tuseEffect(() => {\n\t\tif (!shouldRun) return\n\t\tvoid runner.start()\n\t\treturn () => void runner.disconnect()\n\t}, [runner, shouldRun, serializedInput])\n\n\treturn { status }\n}\n\ntype ApplyEvent<TStreamEvent, TData> = (\n\tevent: TStreamEvent,\n\tprevious: TData | undefined\n) => TData | undefined\n\ntype LiveQueryOptions<\n\tTInput,\n\tTRouteData,\n\tTStreamEvent,\n\tTData,\n\tTSubscriptionInput\n> = {\n\t/** Run the query and its stream (default: true). */\n\tenabled?: boolean | undefined\n\t/** Input for the stream when it differs from the query's. */\n\tsubscriptionInput?: TSubscriptionInput | undefined\n\t/**\n\t * Convert the route output once at fetch time into a differently typed\n\t * cache; `applyEvent` then reduces stream events into that cache.\n\t */\n\tselect?: (data: TRouteData) => TData\n\t/** The raw route output of a seed, before `select` drops fields. */\n\tonSeed?: (data: TRouteData, input: TInput) => void\n\t/**\n\t * Fold a stream event into the cached data. Required when the stream sends\n\t * something other than the cached type (an `fnLive` patch route, or a\n\t * `select`ed cache). Return `undefined` to skip the write.\n\t */\n\tapplyEvent?: ApplyEvent<TStreamEvent, NoInfer<TData>>\n\tonEvent?: (event: TStreamEvent, meta: { connectionId: number }) => void\n\tonError?: ((error: Error) => void) | undefined\n\t/**\n\t * Reconcile a fetched seed with what the stream already wrote. The HTTP\n\t * request can resolve last, so a plain overwrite would drop events that\n\t * arrived while it was in flight. Default: take the fetched value.\n\t */\n\tmergeSeed?: (\n\t\tfetched: NoInfer<TData>,\n\t\tcached: NoInfer<TData> | undefined\n\t) => NoInfer<TData>\n\t/** Show the previous key's data while a new key loads (default: true). */\n\tkeepPreviousData?: boolean\n\t/** Close the stream while the app is not focused (default: true). */\n\tpauseWhenUnfocused?: boolean | undefined\n}\n\ntype LiveQueryOptionsFn<TInput, TData, TError> = (\n\tinput: TInput\n) => UseQueryOptions<TData, TError, TData, QueryKey>\n\ntype LiveQueryResult<TData, TError> = UseQueryResult<TData, TError> & {\n\tliveStatus: LiveConnectionStatus\n}\n\n/**\n * The client half of `fnLive`: the HTTP query seeds the cache, and the live\n * route's stream writes each snapshot into the same cache entry. Marked\n * `meta.live`, so invalidation streams leave it alone.\n *\n * ```tsx\n * const order = useLiveQuery({ id }, (input) => orpc.order.get.queryOptions({ input }), client.order.watch)\n * ```\n *\n * One signature, not overloads: TypeScript fixes an untyped callback's\n * parameters at the first overload it tries, which made valid calls fail.\n */\nexport function useLiveQuery<\n\tTInput,\n\tTRouteData,\n\tTStreamEvent,\n\tTData = TRouteData,\n\tTError = Error,\n\tTSubscriptionInput = TInput\n>(\n\tinput: TInput,\n\tqueryOptionsFn: LiveQueryOptionsFn<TInput, TRouteData, TError>,\n\tsubscribe: SubscribeFn<NoInfer<TSubscriptionInput>, TStreamEvent>,\n\t...options: [TStreamEvent] extends [TData]\n\t\t? [\n\t\t\t\toptions?: LiveQueryOptions<\n\t\t\t\t\tTInput,\n\t\t\t\t\tTRouteData,\n\t\t\t\t\tTStreamEvent,\n\t\t\t\t\tTData,\n\t\t\t\t\tTSubscriptionInput\n\t\t\t\t>\n\t\t\t]\n\t\t: [\n\t\t\t\toptions: LiveQueryOptions<\n\t\t\t\t\tTInput,\n\t\t\t\t\tTRouteData,\n\t\t\t\t\tTStreamEvent,\n\t\t\t\t\tTData,\n\t\t\t\t\tTSubscriptionInput\n\t\t\t\t> & { applyEvent: ApplyEvent<TStreamEvent, NoInfer<TData>> }\n\t\t\t]\n): LiveQueryResult<TData, TError>\nexport function useLiveQuery<\n\tTInput,\n\tTRouteData,\n\tTStreamEvent,\n\tTData,\n\tTError,\n\tTSubscriptionInput\n>(\n\tinput: TInput,\n\tqueryOptionsFn: LiveQueryOptionsFn<TInput, TRouteData, TError>,\n\tsubscribe: SubscribeFn<TSubscriptionInput, TStreamEvent>,\n\toptions: LiveQueryOptions<\n\t\tTInput,\n\t\tTRouteData,\n\t\tTStreamEvent,\n\t\tTData,\n\t\tTSubscriptionInput\n\t> = {}\n): LiveQueryResult<TData, TError> {\n\tconst queryClient = useQueryClient()\n\tconst focused = useIsFocused()\n\tconst [scope] = useState(createStreamScope)\n\n\t// oRPC query options are plain objects; `queryFn` is read through one shape.\n\tconst raw = queryOptionsFn(input) as unknown as {\n\t\tqueryKey: QueryKey\n\t\tqueryFn?: (context: unknown) => Promise<TRouteData>\n\t\tenabled?: UseQueryOptions['enabled']\n\t\tmeta?: Record<string, unknown>\n\t} & Record<string, unknown>\n\tconst keyHash = hashKey(raw.queryKey)\n\tconst latest = useRef({ raw, keyHash, options })\n\tlatest.current = { raw, keyHash, options }\n\n\tconst { status } = useOrpcSubscription(\n\t\t(options.subscriptionInput === undefined\n\t\t\t? input\n\t\t\t: options.subscriptionInput) as TSubscriptionInput,\n\t\tsubscribe,\n\t\t{\n\t\t\tenabled: options.enabled,\n\t\t\tpauseWhenUnfocused: options.pauseWhenUnfocused,\n\t\t\tonError: options.onError,\n\t\t\tonConnect: (connectionId) =>\n\t\t\t\tscope.open(connectionId, latest.current.keyHash),\n\t\t\tonEvent: (event, { connectionId }) => {\n\t\t\t\tconst current = latest.current\n\t\t\t\t// The consumer callback must not see an event for a scope no longer shown.\n\t\t\t\tif (!scope.owns(connectionId, current.keyHash)) return\n\t\t\t\t// Without `applyEvent` the stream event is the cache type (the first overload).\n\t\t\t\tconst applyEvent =\n\t\t\t\t\tcurrent.options.applyEvent ??\n\t\t\t\t\t((streamEvent: TStreamEvent) => streamEvent as unknown as TData)\n\t\t\t\tconst key = current.raw.queryKey\n\t\t\t\tconst next = applyEvent(event, queryClient.getQueryData<TData>(key))\n\t\t\t\tif (next !== undefined) queryClient.setQueryData(key, next)\n\t\t\t\tcurrent.options.onEvent?.(event, { connectionId })\n\t\t\t}\n\t\t}\n\t)\n\n\tconst wrapsSeed = options.select || options.mergeSeed\n\tconst queryFn =\n\t\traw.queryFn && wrapsSeed\n\t\t\t? seedQueryFn(raw.queryFn, {\n\t\t\t\t\tinput,\n\t\t\t\t\treadCache: () => queryClient.getQueryData<TData>(raw.queryKey),\n\t\t\t\t\tselect: options.select,\n\t\t\t\t\tonSeed: options.onSeed,\n\t\t\t\t\tmergeSeed: options.mergeSeed\n\t\t\t\t})\n\t\t\t: raw.queryFn\n\tconst runs = options.enabled !== false && focused\n\tconst query = useQuery({\n\t\t...raw,\n\t\t...(queryFn ? { queryFn } : {}),\n\t\tenabled: runs ? (raw.enabled ?? true) : false,\n\t\t...(options.keepPreviousData === false\n\t\t\t? {}\n\t\t\t: { placeholderData: keepPreviousData }),\n\t\tstaleTime: Number.POSITIVE_INFINITY,\n\t\tmeta: { ...raw.meta, live: true }\n\t} as UseQueryOptions<TData, TError, TData, QueryKey>)\n\n\treturn Object.assign(query, { liveStatus: status })\n}\n\n/**\n * One app-wide stream of `{ domain }` change events that keeps list and count\n * queries fresh: each event invalidates its domain's query keys (debounced),\n * and a reconnect that proves healthy invalidates every domain to cover\n * events lost while it was down. Mount once, in the signed-in shell.\n *\n * ```ts\n * useInvalidationStream({}, client.realtime.subscribeChanges, {\n * enabled: signedIn,\n * domains: { order: { debounceMs: 100, queryKeys: [orpc.order.key()] } }\n * })\n * ```\n */\nexport function useInvalidationStream<\n\tTInput,\n\tTEvent extends { domain: string }\n>(\n\tinput: TInput,\n\tsubscribe: SubscribeFn<TInput, TEvent>,\n\toptions: InvalidationStreamOptions<TEvent> &\n\t\tPick<\n\t\t\tUseOrpcSubscriptionOptions<TInput, TEvent>,\n\t\t\t'enabled' | 'pauseWhenUnfocused'\n\t\t>\n): { status: LiveConnectionStatus } {\n\tconst queryClient = useQueryClient()\n\tconst latestOptions = useRef(options)\n\tlatestOptions.current = options\n\t// `domains`, `refetchType` and `logger` are read on mount; `onEvent` stays current.\n\tconst [coordinator] = useState(() =>\n\t\tcreateInvalidationCoordinator<TEvent>(queryClient, {\n\t\t\t...options,\n\t\t\tonEvent: (event) => latestOptions.current.onEvent?.(event)\n\t\t})\n\t)\n\tuseEffect(() => coordinator.dispose, [coordinator])\n\n\treturn useOrpcSubscription<TInput, TEvent>(input, subscribe, {\n\t\tenabled: options.enabled,\n\t\tpauseWhenUnfocused: options.pauseWhenUnfocused,\n\t\tonEvent: coordinator.event,\n\t\tonConnect: coordinator.connect,\n\t\tonError: coordinator.lost,\n\t\tonClose: coordinator.lost\n\t})\n}\n\n/**\n * Clear the query cache when the signed-in owner of the cached data changes\n * (another user, another organization), so the next one never sees it.\n * `null` means signed out: signing in starts from the cache sign-out emptied.\n * Pass the same owner as the persister's `buster` so a saved cache from\n * someone else is discarded on the next launch too.\n */\nexport function useQueryCacheOwner(owner: string | null): void {\n\tconst queryClient = useQueryClient()\n\tconst previous = useRef(owner)\n\tuseEffect(() => {\n\t\tconst before = previous.current\n\t\tprevious.current = owner\n\t\tif (owner !== before && before !== null) queryClient.clear()\n\t}, [owner, queryClient])\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"route-options.d.ts","sourceRoot":"","sources":["../src/route-options.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,KAAK,SAAS,EACd,KAAK,QAAQ,EAEb,MAAM,gBAAgB,CAAA;AAGvB,KAAK,QAAQ,GAAG,CAAC,MAAM,EAAE;IACxB,KAAK,EAAE,OAAO,CAAA;IACd,OAAO,EAAE,OAAO,CAAA;IAChB,MAAM,EAAE,WAAW,GAAG,SAAS,CAAA;CAC/B,KAAK,OAAO,CAAA;AAab,0EAA0E;AAC1E,wBAAgB,cAAc,CAC7B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAChC,OAAO,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO;
|
|
1
|
+
{"version":3,"file":"route-options.d.ts","sourceRoot":"","sources":["../src/route-options.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,KAAK,SAAS,EACd,KAAK,QAAQ,EAEb,MAAM,gBAAgB,CAAA;AAGvB,KAAK,QAAQ,GAAG,CAAC,MAAM,EAAE;IACxB,KAAK,EAAE,OAAO,CAAA;IACd,OAAO,EAAE,OAAO,CAAA;IAChB,MAAM,EAAE,WAAW,GAAG,SAAS,CAAA;CAC/B,KAAK,OAAO,CAAA;AAab,0EAA0E;AAC1E,wBAAgB,cAAc,CAC7B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAChC,OAAO,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO;aAoEZ,CAAC,MAAM,EAAE,MAAM,CAAC,WAAW,EAAE,OAAO,CAAC,KAAK,OAAO;;;;;UAKpD,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;;YAEtB,QAAQ,GAAG,SAAS;oBACJ,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC;;;EAI3D"}
|
package/dist/route-options.js
CHANGED
|
@@ -42,6 +42,10 @@ export function normalizeRoute(options, isGuard) {
|
|
|
42
42
|
const iterator = getEventIteratorSchemaDetails(output) !== undefined;
|
|
43
43
|
if (stream === false && iterator)
|
|
44
44
|
throw new TypeError('orpc-fn: an event iterator schema cannot declare stream: false');
|
|
45
|
+
if (stream !== true &&
|
|
46
|
+
!iterator &&
|
|
47
|
+
handler.constructor?.name === 'AsyncGeneratorFunction')
|
|
48
|
+
throw new TypeError(`orpc-fn: ${name} has an async generator handler; declare stream: true`);
|
|
45
49
|
for (const [guard, resolver] of Object.entries(guardResolvers)) {
|
|
46
50
|
if (!isGuard(guard))
|
|
47
51
|
throw new TypeError(`orpc-fn: unknown guard resolver "${guard}"`);
|