orpc-fn 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (141) hide show
  1. package/README.md +48 -32
  2. package/dist/assemble-procedure.d.ts +13 -0
  3. package/dist/assemble-procedure.d.ts.map +1 -0
  4. package/dist/assemble-procedure.js +29 -0
  5. package/dist/assemble-procedure.js.map +1 -0
  6. package/dist/bound-call.d.ts +1 -1
  7. package/dist/bound-call.d.ts.map +1 -1
  8. package/dist/bound-call.js.map +1 -1
  9. package/dist/client.d.ts +4 -2
  10. package/dist/client.d.ts.map +1 -1
  11. package/dist/client.js +4 -2
  12. package/dist/client.js.map +1 -1
  13. package/dist/compatibility.d.ts +16 -0
  14. package/dist/compatibility.d.ts.map +1 -0
  15. package/dist/compatibility.js +4 -0
  16. package/dist/compatibility.js.map +1 -0
  17. package/dist/create-fn.d.ts +30 -34
  18. package/dist/create-fn.d.ts.map +1 -1
  19. package/dist/create-fn.js +177 -121
  20. package/dist/create-fn.js.map +1 -1
  21. package/dist/expo.d.ts +11 -25
  22. package/dist/expo.d.ts.map +1 -1
  23. package/dist/expo.js +25 -30
  24. package/dist/expo.js.map +1 -1
  25. package/dist/hono.d.ts +12 -4
  26. package/dist/hono.d.ts.map +1 -1
  27. package/dist/hono.js +29 -12
  28. package/dist/hono.js.map +1 -1
  29. package/dist/index.d.ts +2 -2
  30. package/dist/index.d.ts.map +1 -1
  31. package/dist/index.js +2 -2
  32. package/dist/index.js.map +1 -1
  33. package/dist/json-schema.d.ts +2 -0
  34. package/dist/json-schema.d.ts.map +1 -1
  35. package/dist/json-schema.js +11 -0
  36. package/dist/json-schema.js.map +1 -1
  37. package/dist/live/codec.d.ts +6 -1
  38. package/dist/live/codec.d.ts.map +1 -1
  39. package/dist/live/codec.js +14 -3
  40. package/dist/live/codec.js.map +1 -1
  41. package/dist/live/fn-live.d.ts +63 -22
  42. package/dist/live/fn-live.d.ts.map +1 -1
  43. package/dist/live/fn-live.js +98 -16
  44. package/dist/live/fn-live.js.map +1 -1
  45. package/dist/live/index.d.ts +1 -1
  46. package/dist/live/index.d.ts.map +1 -1
  47. package/dist/live/index.js.map +1 -1
  48. package/dist/live/ioredis.d.ts +4 -1
  49. package/dist/live/ioredis.d.ts.map +1 -1
  50. package/dist/live/ioredis.js +21 -2
  51. package/dist/live/ioredis.js.map +1 -1
  52. package/dist/live/lifecycle.d.ts +7 -0
  53. package/dist/live/lifecycle.d.ts.map +1 -0
  54. package/dist/live/lifecycle.js +36 -0
  55. package/dist/live/lifecycle.js.map +1 -0
  56. package/dist/live/memory.d.ts.map +1 -1
  57. package/dist/live/memory.js +4 -0
  58. package/dist/live/memory.js.map +1 -1
  59. package/dist/live/pub-sub.d.ts +76 -12
  60. package/dist/live/pub-sub.d.ts.map +1 -1
  61. package/dist/live/pub-sub.js +429 -125
  62. package/dist/live/pub-sub.js.map +1 -1
  63. package/dist/live/redis-bun.d.ts +1 -1
  64. package/dist/live/redis-bun.d.ts.map +1 -1
  65. package/dist/live/redis-bun.js +3 -5
  66. package/dist/live/redis-bun.js.map +1 -1
  67. package/dist/live/redis.d.ts +2 -2
  68. package/dist/live/redis.d.ts.map +1 -1
  69. package/dist/live/redis.js +36 -9
  70. package/dist/live/redis.js.map +1 -1
  71. package/dist/live/transport.d.ts +5 -1
  72. package/dist/live/transport.d.ts.map +1 -1
  73. package/dist/live/transport.js.map +1 -1
  74. package/dist/logger.d.ts +2 -0
  75. package/dist/logger.d.ts.map +1 -1
  76. package/dist/logger.js +21 -0
  77. package/dist/logger.js.map +1 -1
  78. package/dist/mastra.d.ts.map +1 -1
  79. package/dist/mastra.js +16 -7
  80. package/dist/mastra.js.map +1 -1
  81. package/dist/mcp/sdk.d.ts +20 -0
  82. package/dist/mcp/sdk.d.ts.map +1 -0
  83. package/dist/mcp/sdk.js +82 -0
  84. package/dist/mcp/sdk.js.map +1 -0
  85. package/dist/mcp.d.ts +3 -2
  86. package/dist/mcp.d.ts.map +1 -1
  87. package/dist/mcp.js +22 -7
  88. package/dist/mcp.js.map +1 -1
  89. package/dist/meta.d.ts +15 -7
  90. package/dist/meta.d.ts.map +1 -1
  91. package/dist/meta.js +9 -2
  92. package/dist/meta.js.map +1 -1
  93. package/dist/otel.d.ts.map +1 -1
  94. package/dist/otel.js +77 -6
  95. package/dist/otel.js.map +1 -1
  96. package/dist/route-options.d.ts +22 -0
  97. package/dist/route-options.d.ts.map +1 -0
  98. package/dist/route-options.js +67 -0
  99. package/dist/route-options.js.map +1 -0
  100. package/dist/router.d.ts +5 -1
  101. package/dist/router.d.ts.map +1 -1
  102. package/dist/router.js +22 -0
  103. package/dist/router.js.map +1 -1
  104. package/dist/timing.d.ts +8 -0
  105. package/dist/timing.d.ts.map +1 -0
  106. package/dist/timing.js +4 -0
  107. package/dist/timing.js.map +1 -0
  108. package/dist/types.d.ts +86 -41
  109. package/dist/types.d.ts.map +1 -1
  110. package/dist/types.js +6 -2
  111. package/dist/types.js.map +1 -1
  112. package/package.json +15 -3
  113. package/src/assemble-procedure.ts +42 -0
  114. package/src/bound-call.ts +4 -3
  115. package/src/client.ts +9 -2
  116. package/src/compatibility.ts +39 -0
  117. package/src/create-fn.ts +297 -183
  118. package/src/expo.ts +49 -44
  119. package/src/hono.ts +36 -17
  120. package/src/index.ts +6 -2
  121. package/src/json-schema.ts +16 -0
  122. package/src/live/codec.ts +22 -3
  123. package/src/live/fn-live.ts +244 -69
  124. package/src/live/index.ts +2 -0
  125. package/src/live/ioredis.ts +22 -2
  126. package/src/live/lifecycle.ts +44 -0
  127. package/src/live/memory.ts +4 -0
  128. package/src/live/pub-sub.ts +608 -166
  129. package/src/live/redis-bun.ts +7 -5
  130. package/src/live/redis.ts +37 -11
  131. package/src/live/transport.ts +4 -1
  132. package/src/logger.ts +20 -0
  133. package/src/mastra.ts +15 -7
  134. package/src/mcp/sdk.ts +118 -0
  135. package/src/mcp.ts +48 -20
  136. package/src/meta.ts +40 -24
  137. package/src/otel.ts +77 -10
  138. package/src/route-options.ts +100 -0
  139. package/src/router.ts +39 -1
  140. package/src/timing.ts +5 -0
  141. package/src/types.ts +204 -62
package/README.md CHANGED
@@ -29,7 +29,7 @@ export const { fn, fnLive, createPubSub, createRouter } = createFn({
29
29
  default: 'protected',
30
30
  extras: () => ({ db }),
31
31
  guards: {
32
- permission: (required: Permission, { context }) => context.user?.can(required)
32
+ permission: (required: Permission, { context }) => context.user?.can(required) ?? false
33
33
  },
34
34
  otel
35
35
  })
@@ -52,7 +52,7 @@ export const getOrder = fn({
52
52
  })
53
53
  ```
54
54
 
55
- Every call runs in an OpenTelemetry span named `order.get` (for a streaming handler, until the stream ends), runs the `permission` guard, writes `handler_ms` back to `context.timing`, and logs one `fn.completed` line at `info`, `warn` (4xx) or `error` (defects).
55
+ Every call runs in an OpenTelemetry span named `order.get` (for a streaming handler, until the stream ends), runs the `permission` guard, observes input/output validation, and logs one `fn.completed` line at `info`, `warn` (4xx) or `error` (defects).
56
56
 
57
57
  ## `orpc-fn`: `createFn`
58
58
 
@@ -61,31 +61,34 @@ createFn({
61
61
  procedures, // named oRPC builders; the handler context is the builder's context
62
62
  default, // builder used when a route omits `procedure`; leave out to require `procedure` on every route
63
63
  extras, // ({ context, span, signal, name, procedure }) => values (or a promise) merged into handler params
64
- guards, // { key: (value, { context, input, name, meta, signal }) => void } — each key is a typed fn() option
65
- meta, // `{} as { readOnly?: boolean }` — typed fn() options stored on the procedure
64
+ extrasByProcedure, // e.g. { protected: ({ context }) => ({ t: translator(context.user) }) }
65
+ guards, // { key: (value, params) => void | boolean | Promise<void | boolean> } — each key is a typed fn() option
66
+ meta, // defineMeta<AppMeta>() — allowed values of each route's meta object
66
67
  tags, // ['internal', 'external'] — allowed route tags
67
68
  otel, // `import * as otel from '@opentelemetry/api'`; omit for no tracing
68
69
  logger, // (scope, span) => your logger (debug/info/warn/error)
69
70
  spanAttributes, // ({ context, name, procedure, meta }) => extra span attributes
70
71
  onCompleted, // (event) => extra attributes for the fn.completed log
71
72
  isExpectedError, // default: 4xx ORPCError or AbortError
72
- pubsub // { transport, onDrop?, maxQueueSize? } for fnLive / createPubSub
73
+ pubsub // { transport, namespace?, ownsTransport?, maxQueueSize?, maxIngressSize?, maxReplaySize?, initializationTimeoutMs?, onDrop?, onMetric? } for fnLive / createPubSub
73
74
  })
74
75
  ```
75
76
 
76
- It returns `fn`, `fnLive`, `createPubSub`, `createPublisher`, `createRouter`, `readMeta`, `createCall`, `drainPubSubSubscribers` and `activePubSubSubscriberCount`.
77
+ It returns `fn`, `fnLive`, `createPubSub`, `createPublisher`, `createRouter`, `readMeta`, `createCall`, `shutdown`, `drainPubSubSubscribers` and `activePubSubSubscriberCount`.
77
78
 
78
- Procedure builders must not set an input or output schema (`os.input(...)`); put schemas on routes. Guard and meta keys must not reuse a route option name (`name`, `tags`, `input`, …), and guards and meta must not share a key. Both are type errors, and a reserved guard name also throws at startup.
79
+ Procedure builders must not set an input or output schema (`os.input(...)`); put schemas on routes. Guard keys cannot reuse route option names. Application metadata lives in a typed `meta` object and may share names with guards or route options. Unknown top-level route options and extras that shadow built-in handler params are rejected. Scoped extras replace matching shared keys, with handler types reflecting that precedence.
79
80
 
80
- **`fn(options)`** has four overloads (input and output schema, each given or inferred). Route options: `name` (required; operationId and span name), `procedure`, `path`, `method`, `summary`, `description`, `tags`, `deprecated`, `successStatus`, `successDescription`, `inputStructure`, `outputStructure`, every guard key and every meta key. The handler receives `input`, `context`, `call`, `signal`, `span`, `logger` and your extras. With an output schema, the handler returns the schema's input type and callers receive its output type, so `output: z.string().transform(Number)` means the handler returns a string and callers get a number.
81
+ **`fn(options)`** has four overloads (input and output schema, each given or inferred). Route options: `name` (required; operationId and span name), `procedure`, `path`, `method`, `summary`, `description`, `tags`, `deprecated`, `successStatus`, `successDescription`, `inputStructure`, `outputStructure`, configured guard keys, `guardResolvers`, `meta`, `stream` and native `errors` declarations. Core schemas use Standard Schema; Zod 4 remains the default for tool/live adapters. The handler receives `input`, `context`, `call`, `signal`, `span`, `logger`, native typed `errors`, `lastEventId` and your extras. With an output schema, the handler returns the schema's input type and callers receive its output type, so `output: z.string().transform(Number)` means the handler returns a string and callers get a number.
81
82
 
82
- **Guards** run inside the span, before the handler, and only on routes that set their option. Throw (usually an `ORPCError`) to refuse.
83
+ **Guards** run inside the span, before the handler, and only on routes that set their option. Return `false` or throw an `ORPCError` to refuse; `true` and `undefined` allow. Static guards run sequentially in route declaration order, followed by resolved guards in resolver order. Unsupported return values fail types and runtime. For input-dependent checks use `guardResolvers: { permission: ({ input, context }) => requirement }`; these see parsed input. A guard cannot set both a static value and a resolver.
83
84
 
84
85
  **`call(procedure, input)`** calls another procedure with the caller's context and abort signal, inside a `call: <name>` child span. Input and output are typed from the callee. Calling a procedure whose context the caller's context does not satisfy is a type error. Outside a handler (seeders, scripts, tests), use `createCall(context, signal?)` from `createFn`.
85
86
 
86
- **Meta** is stored in oRPC's own procedure meta. It survives `os.router()`, prefixes and lazy routers. Read it with `readMeta(procedure)` (typed) or `readFnMeta(procedure)`.
87
+ **Meta** is stored in oRPC's own procedure meta. It survives `os.router()`, prefixes and lazy routers. Declare the contract with `defineMeta<AppMeta>()` (no runtime defaults), then use `fn({ meta: { readOnly: true }, ... })`. Both `readMeta(procedure)` and `readFnMeta(procedure)` infer metadata from the passed procedure, including procedures from another factory.
87
88
 
88
- Also exported: `isExpectedClientError`, `createBoundedEventQueue`, `createRouter`, `createBoundCall`, and the types `HandlerParams`, `RouteConfig`, `BoundCall`, `FnMeta`, `FnContext`, `FnCompletedEvent`, `ProcedureInput`, `ProcedureOutput`, `ProcedureContext`, `InitialContextOf`, `CurrentContextOf` and `GuardOptions`.
89
+ Completion hooks discriminate by `procedure` and `handlerStarted`. Before handler context exists (auth/input failure), they receive the initial context. Logging, tracing, metrics and completion-hook failures preserve procedure results. Custom log fields cannot overwrite canonical completion fields. Stream completion runs once when the stream ends.
90
+
91
+ Also exported: `defineMeta`, `createStreamManifest`, `createStreamManifestAsync`, `isExpectedClientError`, `createBoundedEventQueue`, `createRouter`, `createBoundCall`, and the types `HandlerParams`, `RouteConfig`, `BoundCall`, `FnMeta`, `FnContext`, `FnCompletedEvent`, `ProcedureInput`, `ProcedureOutput`, `ProcedureContext`, `InitialContextOf`, `CurrentContextOf` and `GuardOptions`.
89
92
 
90
93
  ## `orpc-fn/live`: pub/sub and live queries
91
94
 
@@ -113,20 +116,23 @@ export const listOrders = fnLive({
113
116
  await listOrders.publish({ organizationId, orderId }) // after a write
114
117
  ```
115
118
 
116
- The `subscribe` route first runs `authFn` and subscribes to the channel, then streams the initial snapshot, then a new one per event. A refused subscriber receives nothing, and events published while the snapshot loads are not lost. Snapshots go through the output schema, like the route's own result. Options:
119
+ The `subscribe` route runs builder middleware and the same fn guards/extras/meta/completion policy, then `authFn` and subscribes to the channel, then streams the initial snapshot, then reloads when invalidated (once per coalescing batch). Queue bounds (`maxQueueSize`, `maxIngressSize`, `maxReplaySize`) can be overridden per pub/sub definition or live config. `maxBatchSize` bounds a live coalescing batch (default 1000). `pubsub.onMetric` reports typed queue depths, drops, successful reconnects and parsing failures; keep this synchronous callback fast. Startup waits for a successful broker subscription, bounded by `initializationTimeoutMs` (10000ms by default) and cancellation. A refused subscriber receives nothing, and events published while the snapshot loads are not lost. Snapshots go through the output schema, like the route's own result. Options:
117
120
 
118
121
  - `shouldUpdate` skips an event.
119
- - `transformerFn` folds an event into `previous` instead of re-running the handler. It may return `fnLivePatch(state, emit)` to send a small payload and keep the full state.
120
- - `coalesceMs` batches events that arrive close together.
122
+ - `transformerFn` folds an event into initialized `previous`. It requires a `stateSchema` that validates parsed state. Patches returned by `fnLivePatch(state, emit)` additionally require `emitSchema`. These schemas should not transform already-parsed values. `rerun()` rechecks the current input through the procedure; it cannot change subscriber input.
123
+ - `coalesceMs` performs one rerun for an invalidation batch. Reducers process every event but emit their final full state; ordered patch payloads remain ordered. Batches are bounded (1000 events by default in `streamLiveSnapshots`).
121
124
  - `authFn` and `useBacklog`/`backlogSize`/`backlogTtl` work as on `createPubSub`.
122
- - `overflowMarker` is enqueued when a slow subscriber's queue overflows, once per overflow episode, so the client can resync.
123
- - `safePublish` logs publish errors instead of throwing them.
125
+ - Live queries reload a full snapshot after overflow or reconnect. Raw pub/sub streams fail with `SERVICE_UNAVAILABLE` after detected loss, or emit an application-provided `overflowMarker` that must trigger recovery.
126
+ - `reauthorize` can check access before each live update. Initial authorization covers idle streams; apps that need immediate revocation should close those streams.
127
+ - `safePublish` logs publish errors instead of throwing them; it does not retry or guarantee delivery.
128
+
129
+ **`createPubSub`** returns a typed `subscribe` route plus `publish`, `publishMany` (one atomic round-trip across channels) and typed `getSubscriptionChannelName({ input, context })` / `getPublishChannelName(event)` methods. The shared partial-input `getChannelName` method is deprecated. Publishers pass the event schema's input type; subscribers, filters and channel resolvers get its output type. The raw event travels in oRPC's JSON format, so `Date`, `Map`, `Set` and `BigInt` survive, and each receiver parses it once. Options include `filterFn`, `authFn`, `mirrorChannel`, `overflowMarker`, `procedure`, configured guards and `meta`. Channels may be static or use `channel: { subscribe: ({ input, context }) => key, publish: (parsedEvent) => key }`. Carry publishing tenant keys in the event. A factory `namespace` prefixes channels, mirrors and backlog keys. Each pub/sub definition subscribes to each channel once and parses each payload once for all local subscribers. Each subscriber then runs its filter in arrival order as it reads; its bounded queue holds events before filtering, so `onDrop` counts unfiltered events. Abort and drain release a subscription at once, even one that is not being read. A lost subscription is retried with exponential backoff and jitter. **`createPublisher`** is the publish-only half.
124
130
 
125
- **`createPubSub`** returns a typed `subscribe` route plus `publish`, `publishMany` (one atomic round-trip across channels) and `getChannelName`. Publishers pass the event schema's input type; subscribers, filters and channel resolvers get its output type. The raw event travels in oRPC's JSON format, so `Date`, `Map`, `Set` and `BigInt` survive, and each receiver parses it once. Options: `filterFn`, `authFn`, `mirrorChannel`, `overflowMarker`, `procedure`. Each pub/sub definition subscribes to each channel once and parses each payload once for all local subscribers. Each subscriber then runs its filter in arrival order as it reads; its bounded queue holds events before filtering, so `onDrop` counts unfiltered events. Abort and drain release a subscription at once, even one that is not being read. A lost subscription is retried with exponential backoff and jitter. **`createPublisher`** is the publish-only half.
131
+ **Graceful shutdown:** `await shutdown()` stops new subscriptions/publication, cancels initialization/retries, ends existing streams and awaits cleanup. It closes a supplied transport only with `ownsTransport: true`. A custom transport whose pending `subscribe` cannot be cancelled may resolve later; that late subscription is immediately released. `drainPubSubSubscribers()` remains a synchronous, nonterminal operation. Both are per factory.
126
132
 
127
- **Graceful shutdown:** call `drainPubSubSubscribers()` on SIGTERM. Open streams end cleanly and clients reconnect to the new deployment. Draining is per `createFn` instance.
133
+ Recent event IDs deduplicate replay/live overlap; legacy payloads remain readable. Replay is bounded and TTL-limited, so it is not durable resume. A snapshot may already include a queued delta: reducers must use revisions or idempotence. See [the revision example](examples/adoption/revisions.ts). Parsing ingress, replay staging and subscriber queues are bounded; positive queue/TTL/time options are validated.
128
134
 
129
- **Transports** implement `PubSubTransport` (`publish(messages, backlog?)`, `readBacklog(channel)`, `subscribe(channel, listener, onLost)`):
135
+ **Transports** implement `PubSubTransport` (`publish(messages, backlog?)`, `readBacklog(channel)`, `subscribe(channel, listener, onLost, { onReconnect }?)`):
130
136
 
131
137
  | Subpath | Client | Notes |
132
138
  |---|---|---|
@@ -134,7 +140,7 @@ The `subscribe` route first runs `authFn` and subscribes to the channel, then st
134
140
  | `orpc-fn/live/ioredis` | ioredis 5 | Dedicated subscriber via `duplicate()`; ioredis re-subscribes itself |
135
141
  | `orpc-fn/live/memory` | none | Tests and single-process dev |
136
142
 
137
- A subscriber connection that is lost, or cannot restore its channels after a reconnect, is closed and replaced; nothing it still emits is delivered. The Redis transports publish and maintain backlogs with one Lua script, sent by SHA, with a fallback to `EVAL` when Redis returns `NOSCRIPT`. Call `transport.close()` on shutdown.
143
+ A subscriber connection that is lost, or cannot restore its channels after a reconnect, is closed and replaced; nothing it still emits is delivered. The Redis transports publish and maintain backlogs with one Lua script, sent by SHA, with a fallback to `EVAL` when Redis returns `NOSCRIPT`. Await `transport.close()` when the app owns its lifecycle. The Redis Lua batching adapter supports standalone Redis; Redis Cluster requires compatible key slots and is not promised by this adapter.
138
144
 
139
145
  `streamLiveSnapshots`, `fnLivePatch` and `throwInitialSnapshotError` are exported for custom streams.
140
146
 
@@ -151,21 +157,30 @@ const tool = createMastraTool(getOrder, { requireApproval: true })
151
157
 
152
158
  Options: `id`, `description`, `requireApproval`, `allowMissingInputSchema`, `onExecuteFinish`, `contextKey` (default `'orpcContext'`). Execution goes through oRPC `call`, so middleware and guards apply.
153
159
 
154
- The tool takes the procedure's raw input and returns its parsed output, and `InferToolInput`/`InferToolOutput`/`InferUITools` see exactly those types. Mastra validates the input (coercing date strings) but passes the raw value on, and the procedure parses that raw value: a transform may run twice, but never on its own output. Agent tools need an object input: any other input is a type error and throws.
160
+ The tool takes the procedure's raw input and returns its parsed output, and `InferToolInput`/`InferToolOutput`/`InferUITools` see exactly those types. Mastra validates the input (coercing date strings) but passes the raw value on, and the procedure parses that raw value: transforms/refinements must be pure: SDK validation and procedure execution may run them more than once, always on raw input. Agent tools accept objects and unions of object shapes. Other inputs and streams are rejected. Finish-hook failures preserve execution outcomes.
155
161
 
156
162
  ## `orpc-fn/mcp`
157
163
 
158
164
  Optional peers: `@orpc/zod`, `@orpc/json-schema`.
159
165
 
160
- ```ts
161
- import { hasTag, listTools } from 'orpc-fn/mcp'
166
+ Inspection definitions from `listTools` use Standard Schema and are not `McpServer.registerTool` configs. Executable registration is a separate optional entry point, with SDK `@modelcontextprotocol/sdk` ^1.32.0:
162
167
 
163
- for (const { name, procedure, config } of listTools(router, { filter: hasTag('external') })) {
164
- server.registerTool(name, config, (args) => call(procedure, args, { context }))
165
- }
168
+ ```ts
169
+ import { Server } from '@modelcontextprotocol/sdk/server/index.js'
170
+ import { hasTag } from 'orpc-fn/mcp'
171
+ import { registerMcpTools } from 'orpc-fn/mcp/sdk'
172
+
173
+ const server = new Server({ name: 'api', version: '1.0.0' }, { capabilities: { tools: {} } })
174
+ registerMcpTools(server, router, {
175
+ filter: hasTag('external'),
176
+ context: ({ signal }) => authenticateToolRequest(signal)
177
+ })
178
+ // Connect your SDK transport; see examples/adoption/mcp.ts.
166
179
  ```
167
180
 
168
- Tool names are the sanitized `fn` names (`user.me` becomes `user-me`). Input schemas carry the same JSON Schema as your OpenAPI docs (dates become `string`/`date-time`), and validation turns them back into `Date`s. Validation returns the raw arguments, and `call(procedure, args, { context })` parses those: a transform may run twice, but never on its own output. `readOnlyHint` defaults to GET routes; pass `readOnly` to change it. `hasTag(tag)` also works as an oRPC `OpenAPIHandler` filter.
181
+ The adapter installs the SDK list/call handlers on a low-level `Server` (also accessible as `McpServer.server`). Use one registration per server; these handlers own its tool list. It forwards cancellation, validates/coerces arguments, applies procedure authorization, and formats results as JSON/text MCP content. Override `formatResult` for images, structured content or other presentation. Tool selection is required. Object unions are supported; streams are rejected. Resolve lazy routers first with oRPC's `unlazyRouter`.
182
+
183
+ Sanitized tool-name collisions between distinct procedures throw; identical aliases are deduplicated. Override `name` to resolve deliberate collisions. Tool names are the sanitized `fn` names (`user.me` becomes `user-me`). Input schemas carry the same JSON Schema as your OpenAPI docs (dates become `string`/`date-time`), and validation turns them back into `Date`s. Validation returns the raw arguments, and `call(procedure, args, { context })` parses those: transforms/refinements must be pure: SDK validation and procedure execution may run them more than once, always on raw input. `readOnlyHint` defaults to GET routes; pass `readOnly` to change it. `hasTag(tag)` also works as an oRPC `OpenAPIHandler` filter.
169
184
 
170
185
  ## `orpc-fn/hono`
171
186
 
@@ -186,7 +201,7 @@ mountOrpc(app, {
186
201
 
187
202
  Behaviour:
188
203
 
189
- - The response gets a `Server-Timing` header built from `context.timing`: queue, auth and context if you record them, and handler from `fn`.
204
+ - The response gets a `Server-Timing` header built from the request timing collector: app-recorded queue/auth/context metrics plus library-owned procedure time. Nested calls do not overwrite parent timing; batches aggregate their top-level procedure durations (which may overlap). `fn` does not mutate an arbitrary `context.timing` field. `formatServerTiming` and `finishOrpcHeaders` are available for composed Fetch adapters.
190
205
  - SSE responses get keep-alive comments (15 s) and anti-buffering headers.
191
206
  - RPC calls are batched (`BatchHandlerPlugin`).
192
207
  - Scalar docs are served at the OpenAPI prefix.
@@ -215,7 +230,7 @@ export const orpc = createTanstackQueryUtils(client) // Vue Query or React Query
215
230
  if (hasOrpcErrorCode(error, 'NOT_FOUND')) { /* … */ }
216
231
  ```
217
232
 
218
- `createRpcLink` takes every `RPCLink` option. It also batches parallel calls into one request, matching `mountOrpc`'s server-side batching (`batch: { maxSize, exclude, groups }`, or `false` to turn it off). A batch is one request with one client context, so by default only calls without a client context are batched; pass `groups` to batch calls that share one. A streaming response cannot be batched, and the request doesn't say whether the response will stream, so streaming routes are recognised by name: any path segment containing `subscribe` is sent on its own (`isSubscriptionPath`).
233
+ `createRpcLink` takes every `RPCLink` option. It also batches parallel calls into one request, matching `mountOrpc`'s server-side batching (`batch: { maxSize, exclude, groups }`, or `false` to turn it off). A batch is one request with one client context, so by default only calls without a client context are batched; pass `groups` to batch calls that share one. A streaming response cannot be batched, and the request doesn't say whether the response will stream, so pass `streamPaths` generated from the actual router with `createStreamManifest` (or `createStreamManifestAsync` for lazy routers). Serialize it to a frontend module; importing that data needs no server runtime. Mark custom iterator routes with `stream: true` or use oRPC's `eventIterator` output schema. Generated live/pubsub routes are marked automatically. `batch.exclude` remains an escape hatch, and the legacy `subscribe` naming heuristic remains as a fallback.
219
234
 
220
235
  ## `orpc-fn/expo`
221
236
 
@@ -224,9 +239,9 @@ Expo itself is passed in, not imported. The fetch must resolve to a response wit
224
239
  ```ts
225
240
  import { fetch } from 'expo/fetch'
226
241
  import { Platform } from 'react-native'
227
- import { createExpoLink } from 'orpc-fn/expo'
242
+ import { createBetterAuthExpoLink } from 'orpc-fn/expo'
228
243
 
229
- const link = createExpoLink({
244
+ const link = createBetterAuthExpoLink({
230
245
  url: `${baseUrl}/api/rpc`,
231
246
  fetch,
232
247
  native: Platform.OS !== 'web',
@@ -236,13 +251,14 @@ const link = createExpoLink({
236
251
  })
237
252
  ```
238
253
 
239
- On native, calls go through `expo/fetch`, the only fetch that streams there. The bridge forwards the request body and the abort signal. Without the signal, cancelled subscriptions keep their sockets open, the device's HTTP pool runs out, and later requests hang. Cookies are sent in a header (`credentials: 'omit'`), together with `expo-origin` and `x-skip-oauth-proxy`, the same headers `@better-auth/expo` sends. On the server, `mountOrpc({ normalizeHeaders: normalizeExpoOrigin })` copies `expo-origin` to `origin`. On web, the link uses the platform fetch with cookies. `createExpoFetch` is exported for a custom link.
254
+ On native, calls go through `expo/fetch`, the only fetch that streams there. The bridge forwards the request body and the abort signal. Without the signal, cancelled subscriptions keep their sockets open, the device's HTTP pool runs out, and later requests hang. Cookies are sent in a header (`credentials: 'omit'`), together with `expo-origin` and `x-skip-oauth-proxy`, the same headers `@better-auth/expo` sends. On the server, `mountOrpc({ normalizeHeaders: normalizeExpoOrigin })` copies `expo-origin` to `origin`. The generic `createExpoLink` forwards upstream headers (including async/context-aware resolvers) and adds no provider-specific headers. `createBetterAuthExpoLink` supplies the cookie/origin preset above. On web, the link uses the platform fetch with cookies, or your explicit `webFetch` override. `createExpoFetch` is exported for a custom link.
240
255
 
241
256
  ## Docs
242
257
 
243
258
  - [Migrating an app from an in-repo `lib/fn`](docs/migration.md)
244
259
  - [Decisions: what oRPC already ships and why this exists](docs/decisions.md)
245
260
  - [Releasing](docs/releasing.md)
261
+ - [Independent core, tenant, revision, MCP and Expo examples](examples/adoption/README.md)
246
262
  - [Example: Hono, in-memory pub/sub, two routes and a live query](examples/basic/server.ts)
247
263
 
248
264
  ## License
@@ -0,0 +1,13 @@
1
+ import type { AnySchema } from '@orpc/contract';
2
+ import type { AnyProcedure } from '@orpc/server';
3
+ import type { BuildProcedure } from './types.js';
4
+ export type BuilderChain = {
5
+ route(route: Record<string, unknown>): BuilderChain;
6
+ meta(meta: Record<string, unknown>): BuilderChain;
7
+ input(schema: AnySchema): BuilderChain;
8
+ output(schema: AnySchema): BuilderChain;
9
+ errors(errors: import('@orpc/contract').ErrorMap): BuilderChain;
10
+ handler(handler: Parameters<BuildProcedure>[0]['handler']): AnyProcedure;
11
+ };
12
+ export declare function createProcedureAssembler(procedures: Record<string, BuilderChain>, resolveKey: (key: string | undefined, name: string) => string): BuildProcedure;
13
+ //# sourceMappingURL=assemble-procedure.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"assemble-procedure.d.ts","sourceRoot":"","sources":["../src/assemble-procedure.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAC/C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AAEhD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAEhD,MAAM,MAAM,YAAY,GAAG;IAC1B,KAAK,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,YAAY,CAAA;IACnD,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,YAAY,CAAA;IACjD,KAAK,CAAC,MAAM,EAAE,SAAS,GAAG,YAAY,CAAA;IACtC,MAAM,CAAC,MAAM,EAAE,SAAS,GAAG,YAAY,CAAA;IACvC,MAAM,CAAC,MAAM,EAAE,OAAO,gBAAgB,EAAE,QAAQ,GAAG,YAAY,CAAA;IAC/D,OAAO,CAAC,OAAO,EAAE,UAAU,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,YAAY,CAAA;CACxE,CAAA;AAED,wBAAgB,wBAAwB,CACvC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,EACxC,UAAU,EAAE,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,EAAE,IAAI,EAAE,MAAM,KAAK,MAAM,GAC3D,cAAc,CAwBhB"}
@@ -0,0 +1,29 @@
1
+ import { FN_META_KEY } from './meta.js';
2
+ export function createProcedureAssembler(procedures, resolveKey) {
3
+ return (route) => {
4
+ const key = resolveKey(route.procedure, route.name);
5
+ let builder = procedures[key];
6
+ if (!builder)
7
+ throw new Error(`orpc-fn: unknown procedure "${key}"`);
8
+ const stored = {
9
+ name: route.name,
10
+ procedure: key,
11
+ meta: route.meta,
12
+ stream: route.stream ?? false
13
+ };
14
+ builder = builder
15
+ .route({
16
+ operationId: route.name,
17
+ ...Object.fromEntries(Object.entries(route.route).filter(([, value]) => value !== undefined))
18
+ })
19
+ .meta({ [FN_META_KEY]: stored });
20
+ if (route.errors)
21
+ builder = builder.errors(route.errors);
22
+ if (route.input)
23
+ builder = builder.input(route.input);
24
+ if (route.output)
25
+ builder = builder.output(route.output);
26
+ return builder.handler(route.handler);
27
+ };
28
+ }
29
+ //# sourceMappingURL=assemble-procedure.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"assemble-procedure.js","sourceRoot":"","sources":["../src/assemble-procedure.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAqB,MAAM,WAAW,CAAA;AAY1D,MAAM,UAAU,wBAAwB,CACvC,UAAwC,EACxC,UAA6D;IAE7D,OAAO,CAAC,KAAK,EAAE,EAAE;QAChB,MAAM,GAAG,GAAG,UAAU,CAAC,KAAK,CAAC,SAAS,EAAE,KAAK,CAAC,IAAI,CAAC,CAAA;QACnD,IAAI,OAAO,GAAG,UAAU,CAAC,GAAG,CAAC,CAAA;QAC7B,IAAI,CAAC,OAAO;YAAE,MAAM,IAAI,KAAK,CAAC,+BAA+B,GAAG,GAAG,CAAC,CAAA;QACpE,MAAM,MAAM,GAAiB;YAC5B,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,SAAS,EAAE,GAAG;YACd,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,MAAM,EAAE,KAAK,CAAC,MAAM,IAAI,KAAK;SAC7B,CAAA;QACD,OAAO,GAAG,OAAO;aACf,KAAK,CAAC;YACN,WAAW,EAAE,KAAK,CAAC,IAAI;YACvB,GAAG,MAAM,CAAC,WAAW,CACpB,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,KAAK,KAAK,SAAS,CAAC,CACtE;SACD,CAAC;aACD,IAAI,CAAC,EAAE,CAAC,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC,CAAA;QACjC,IAAI,KAAK,CAAC,MAAM;YAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAA;QACxD,IAAI,KAAK,CAAC,KAAK;YAAE,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;QACrD,IAAI,KAAK,CAAC,MAAM;YAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAA;QACxD,OAAO,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAA;IACtC,CAAC,CAAA;AACF,CAAC","sourcesContent":["import type { AnySchema } from '@orpc/contract'\nimport type { AnyProcedure } from '@orpc/server'\nimport { FN_META_KEY, type StoredFnMeta } from './meta.js'\nimport type { BuildProcedure } from './types.js'\n\nexport type BuilderChain = {\n\troute(route: Record<string, unknown>): BuilderChain\n\tmeta(meta: Record<string, unknown>): BuilderChain\n\tinput(schema: AnySchema): BuilderChain\n\toutput(schema: AnySchema): BuilderChain\n\terrors(errors: import('@orpc/contract').ErrorMap): BuilderChain\n\thandler(handler: Parameters<BuildProcedure>[0]['handler']): AnyProcedure\n}\n\nexport function createProcedureAssembler(\n\tprocedures: Record<string, BuilderChain>,\n\tresolveKey: (key: string | undefined, name: string) => string\n): BuildProcedure {\n\treturn (route) => {\n\t\tconst key = resolveKey(route.procedure, route.name)\n\t\tlet builder = procedures[key]\n\t\tif (!builder) throw new Error(`orpc-fn: unknown procedure \"${key}\"`)\n\t\tconst stored: StoredFnMeta = {\n\t\t\tname: route.name,\n\t\t\tprocedure: key,\n\t\t\tmeta: route.meta,\n\t\t\tstream: route.stream ?? false\n\t\t}\n\t\tbuilder = builder\n\t\t\t.route({\n\t\t\t\toperationId: route.name,\n\t\t\t\t...Object.fromEntries(\n\t\t\t\t\tObject.entries(route.route).filter(([, value]) => value !== undefined)\n\t\t\t\t)\n\t\t\t})\n\t\t\t.meta({ [FN_META_KEY]: stored })\n\t\tif (route.errors) builder = builder.errors(route.errors)\n\t\tif (route.input) builder = builder.input(route.input)\n\t\tif (route.output) builder = builder.output(route.output)\n\t\treturn builder.handler(route.handler)\n\t}\n}\n"]}
@@ -9,7 +9,7 @@ type ContextCheck<TContext, T> = [TContext] extends [ProcedureContext<T>] ? unkn
9
9
  * Calls another procedure with the caller's context and signal. `TContext` is
10
10
  * the caller's context; the callee must accept it.
11
11
  */
12
- export type BoundCall<TContext = any> = <T extends AnyProcedure>(procedure: T & ContextCheck<TContext, T>, input: ProcedureInput<T>) => Promise<ProcedureOutput<T>>;
12
+ export type BoundCall<TContext> = <T extends AnyProcedure>(procedure: T & ContextCheck<TContext, T>, ...args: undefined extends ProcedureInput<T> ? [input?: ProcedureInput<T>] : [input: ProcedureInput<T>]) => Promise<ProcedureOutput<T>>;
13
13
  /**
14
14
  * Creates a bound call: nested calls keep the caller's context and abort
15
15
  * signal and run inside a `call: <name>` child span, so the trace shows the
@@ -1 +1 @@
1
- {"version":3,"file":"bound-call.d.ts","sourceRoot":"","sources":["../src/bound-call.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,YAAY,EAAQ,MAAM,cAAc,CAAA;AAEtD,OAAO,EAAiB,KAAK,OAAO,EAAE,MAAM,WAAW,CAAA;AACvD,OAAO,KAAK,EACX,gBAAgB,EAChB,cAAc,EACd,eAAe,EACf,MAAM,YAAY,CAAA;AAEnB,+EAA+E;AAC/E,KAAK,YAAY,CAAC,QAAQ,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,GACtE,OAAO,GACP;IACA,8DAA8D,EAAE,gBAAgB,CAAC,CAAC,CAAC,CAAA;CACnF,CAAA;AAEH;;;GAGG;AAEH,MAAM,MAAM,SAAS,CAAC,QAAQ,GAAG,GAAG,IAAI,CAAC,CAAC,SAAS,YAAY,EAC9D,SAAS,EAAE,CAAC,GAAG,YAAY,CAAC,QAAQ,EAAE,CAAC,CAAC,EACxC,KAAK,EAAE,cAAc,CAAC,CAAC,CAAC,KACpB,OAAO,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,CAAA;AAIhC;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EACvC,OAAO,EAAE,QAAQ,EACjB,MAAM,CAAC,EAAE,WAAW,EACpB,OAAO,GAAE,OAAmB,GAC1B,SAAS,CAAC,QAAQ,CAAC,CASrB"}
1
+ {"version":3,"file":"bound-call.d.ts","sourceRoot":"","sources":["../src/bound-call.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,YAAY,EAAQ,MAAM,cAAc,CAAA;AAEtD,OAAO,EAAiB,KAAK,OAAO,EAAE,MAAM,WAAW,CAAA;AACvD,OAAO,KAAK,EACX,gBAAgB,EAChB,cAAc,EACd,eAAe,EACf,MAAM,YAAY,CAAA;AAEnB,+EAA+E;AAC/E,KAAK,YAAY,CAAC,QAAQ,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,GACtE,OAAO,GACP;IACA,8DAA8D,EAAE,gBAAgB,CAAC,CAAC,CAAC,CAAA;CACnF,CAAA;AAEH;;;GAGG;AACH,MAAM,MAAM,SAAS,CAAC,QAAQ,IAAI,CAAC,CAAC,SAAS,YAAY,EACxD,SAAS,EAAE,CAAC,GAAG,YAAY,CAAC,QAAQ,EAAE,CAAC,CAAC,EACxC,GAAG,IAAI,EAAE,SAAS,SAAS,cAAc,CAAC,CAAC,CAAC,GACzC,CAAC,KAAK,CAAC,EAAE,cAAc,CAAC,CAAC,CAAC,CAAC,GAC3B,CAAC,KAAK,EAAE,cAAc,CAAC,CAAC,CAAC,CAAC,KACzB,OAAO,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,CAAA;AAIhC;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EACvC,OAAO,EAAE,QAAQ,EACjB,MAAM,CAAC,EAAE,WAAW,EACpB,OAAO,GAAE,OAAmB,GAC1B,SAAS,CAAC,QAAQ,CAAC,CASrB"}
@@ -1 +1 @@
1
- {"version":3,"file":"bound-call.js","sourceRoot":"","sources":["../src/bound-call.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqB,IAAI,EAAE,MAAM,cAAc,CAAA;AACtD,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AACtC,OAAO,EAAE,aAAa,EAAgB,MAAM,WAAW,CAAA;AAwBvD,MAAM,SAAS,GAAG,aAAa,CAAC,SAAS,CAAC,CAAA;AAE1C;;;;;;;GAOG;AACH,MAAM,UAAU,eAAe,CAC9B,OAAiB,EACjB,MAAoB,EACpB,OAAO,GAAY,SAAS;IAE5B,OAAO,CAAC,CAAC,SAAuB,EAAE,KAAc,EAAE,EAAE;QACnD,MAAM,IAAI,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC,IAAI,IAAI,mBAAmB,CAAA;QAC9D,OAAO,OAAO,CAAC,MAAM,CAAC,SAAS,IAAI,EAAE,EAAE,UAAU,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE;YACjE,MAAM,EAAE,cAAc,EAAE,CAAA;YACxB,IAAI,EAAE,YAAY,CAAC,YAAY,EAAE,IAAI,CAAC,CAAA;YACtC,OAAO,IAAI,CAAC,SAAS,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,CAAA;QAC1E,CAAC,CAAC,CAAA;IACH,CAAC,CAAwB,CAAA;AAC1B,CAAC","sourcesContent":["import { type AnyProcedure, call } from '@orpc/server'\nimport { readFnMeta } from './meta.js'\nimport { createTracing, type Tracing } from './otel.js'\nimport type {\n\tProcedureContext,\n\tProcedureInput,\n\tProcedureOutput\n} from './types.js'\n\n/** Rejects a procedure whose context the caller's context does not satisfy. */\ntype ContextCheck<TContext, T> = [TContext] extends [ProcedureContext<T>]\n\t? unknown\n\t: {\n\t\t\t'orpc-fn: the calling context does not satisfy this procedure': ProcedureContext<T>\n\t\t}\n\n/**\n * Calls another procedure with the caller's context and signal. `TContext` is\n * the caller's context; the callee must accept it.\n */\n// biome-ignore lint/suspicious/noExplicitAny: an unbound call accepts any procedure\nexport type BoundCall<TContext = any> = <T extends AnyProcedure>(\n\tprocedure: T & ContextCheck<TContext, T>,\n\tinput: ProcedureInput<T>\n) => Promise<ProcedureOutput<T>>\n\nconst noTracing = createTracing(undefined)\n\n/**\n * Creates a bound call: nested calls keep the caller's context and abort\n * signal and run inside a `call: <name>` child span, so the trace shows the\n * whole call tree. oRPC's `call` runs the callee's own middleware and guards.\n *\n * Handlers get one as `call`. Outside a handler (seeders, tests) use\n * `createCall` from `createFn`, which traces with the instance's OpenTelemetry.\n */\nexport function createBoundCall<TContext>(\n\tcontext: TContext,\n\tsignal?: AbortSignal,\n\ttracing: Tracing = noTracing\n): BoundCall<TContext> {\n\treturn ((procedure: AnyProcedure, input: unknown) => {\n\t\tconst name = readFnMeta(procedure).name ?? 'unknown_procedure'\n\t\treturn tracing.inSpan(`call: ${name}`, 'INTERNAL', async (span) => {\n\t\t\tsignal?.throwIfAborted()\n\t\t\tspan?.setAttribute('rpc.method', name)\n\t\t\treturn call(procedure, input, signal ? { context, signal } : { context })\n\t\t})\n\t}) as BoundCall<TContext>\n}\n"]}
1
+ {"version":3,"file":"bound-call.js","sourceRoot":"","sources":["../src/bound-call.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqB,IAAI,EAAE,MAAM,cAAc,CAAA;AACtD,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AACtC,OAAO,EAAE,aAAa,EAAgB,MAAM,WAAW,CAAA;AAyBvD,MAAM,SAAS,GAAG,aAAa,CAAC,SAAS,CAAC,CAAA;AAE1C;;;;;;;GAOG;AACH,MAAM,UAAU,eAAe,CAC9B,OAAiB,EACjB,MAAoB,EACpB,OAAO,GAAY,SAAS;IAE5B,OAAO,CAAC,CAAC,SAAuB,EAAE,KAAc,EAAE,EAAE;QACnD,MAAM,IAAI,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC,IAAI,IAAI,mBAAmB,CAAA;QAC9D,OAAO,OAAO,CAAC,MAAM,CAAC,SAAS,IAAI,EAAE,EAAE,UAAU,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE;YACjE,MAAM,EAAE,cAAc,EAAE,CAAA;YACxB,IAAI,EAAE,YAAY,CAAC,YAAY,EAAE,IAAI,CAAC,CAAA;YACtC,OAAO,IAAI,CAAC,SAAS,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,CAAA;QAC1E,CAAC,CAAC,CAAA;IACH,CAAC,CAAwB,CAAA;AAC1B,CAAC","sourcesContent":["import { type AnyProcedure, call } from '@orpc/server'\nimport { readFnMeta } from './meta.js'\nimport { createTracing, type Tracing } from './otel.js'\nimport type {\n\tProcedureContext,\n\tProcedureInput,\n\tProcedureOutput\n} from './types.js'\n\n/** Rejects a procedure whose context the caller's context does not satisfy. */\ntype ContextCheck<TContext, T> = [TContext] extends [ProcedureContext<T>]\n\t? unknown\n\t: {\n\t\t\t'orpc-fn: the calling context does not satisfy this procedure': ProcedureContext<T>\n\t\t}\n\n/**\n * Calls another procedure with the caller's context and signal. `TContext` is\n * the caller's context; the callee must accept it.\n */\nexport type BoundCall<TContext> = <T extends AnyProcedure>(\n\tprocedure: T & ContextCheck<TContext, T>,\n\t...args: undefined extends ProcedureInput<T>\n\t\t? [input?: ProcedureInput<T>]\n\t\t: [input: ProcedureInput<T>]\n) => Promise<ProcedureOutput<T>>\n\nconst noTracing = createTracing(undefined)\n\n/**\n * Creates a bound call: nested calls keep the caller's context and abort\n * signal and run inside a `call: <name>` child span, so the trace shows the\n * whole call tree. oRPC's `call` runs the callee's own middleware and guards.\n *\n * Handlers get one as `call`. Outside a handler (seeders, tests) use\n * `createCall` from `createFn`, which traces with the instance's OpenTelemetry.\n */\nexport function createBoundCall<TContext>(\n\tcontext: TContext,\n\tsignal?: AbortSignal,\n\ttracing: Tracing = noTracing\n): BoundCall<TContext> {\n\treturn ((procedure: AnyProcedure, input: unknown) => {\n\t\tconst name = readFnMeta(procedure).name ?? 'unknown_procedure'\n\t\treturn tracing.inSpan(`call: ${name}`, 'INTERNAL', async (span) => {\n\t\t\tsignal?.throwIfAborted()\n\t\t\tspan?.setAttribute('rpc.method', name)\n\t\t\treturn call(procedure, input, signal ? { context, signal } : { context })\n\t\t})\n\t}) as BoundCall<TContext>\n}\n"]}
package/dist/client.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { type ClientContext, type ORPCErrorCode } from '@orpc/client';
1
+ import { type ClientContext, ORPCError, type ORPCErrorCode } from '@orpc/client';
2
2
  import { RPCLink, type RPCLinkOptions } from '@orpc/client/fetch';
3
3
  import { BatchLinkPlugin } from '@orpc/client/plugins';
4
4
  type BatchOptions<T extends ClientContext> = ConstructorParameters<typeof BatchLinkPlugin<T>>[0];
@@ -11,6 +11,8 @@ export type CreateRpcLinkOptions<T extends ClientContext> = RPCLinkOptions<T> &
11
11
  * default only calls without a client context are batched; pass
12
12
  * `groups` to batch calls that share a context (e.g. a token).
13
13
  */
14
+ /** Client-safe manifest generated by createStreamManifest(router). */
15
+ streamPaths?: readonly (readonly string[])[];
14
16
  batch?: boolean | {
15
17
  maxSize?: number;
16
18
  /** Calls that must not be batched. Default: {@link isSubscriptionPath}. */
@@ -39,6 +41,6 @@ export declare function createRpcLink<T extends ClientContext = ClientContext>(o
39
41
  * Typed check for a route error on the client. The RPC link rebuilds thrown
40
42
  * route errors as `ORPCError`, so `instanceof` plus `code` is the contract.
41
43
  */
42
- export declare function hasOrpcErrorCode(error: unknown, code: ORPCErrorCode): boolean;
44
+ export declare function hasOrpcErrorCode<TCode extends ORPCErrorCode>(error: unknown, code: TCode): error is ORPCError<TCode, unknown>;
43
45
  export {};
44
46
  //# sourceMappingURL=client.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,aAAa,EAAa,KAAK,aAAa,EAAE,MAAM,cAAc,CAAA;AAChF,OAAO,EAAE,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,oBAAoB,CAAA;AACjE,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAA;AAEtD,KAAK,YAAY,CAAC,CAAC,SAAS,aAAa,IAAI,qBAAqB,CACjE,OAAO,eAAe,CAAC,CAAC,CAAC,CACzB,CAAC,CAAC,CAAC,CAAA;AAEJ,MAAM,MAAM,oBAAoB,CAAC,CAAC,SAAS,aAAa,IACvD,cAAc,CAAC,CAAC,CAAC,GAAG;IACnB;;;;;;;OAOG;IACH,KAAK,CAAC,EACH,OAAO,GACP;QACA,OAAO,CAAC,EAAE,MAAM,CAAA;QAChB,2EAA2E;QAC3E,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,KAAK,OAAO,CAAA;QAC9C,MAAM,CAAC,EAAE,YAAY,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAA;KACjC,CAAA;CACJ,CAAA;AAEF;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,SAAU,SAAS,MAAM,EAAE,YACU,CAAA;AAEpE;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAAC,CAAC,SAAS,aAAa,GAAG,aAAa,EACpE,OAAO,EAAE,oBAAoB,CAAC,CAAC,CAAC,GAC9B,OAAO,CAAC,CAAC,CAAC,CAyBZ;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,aAAa,GAAG,OAAO,CAE7E"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,aAAa,EAAE,SAAS,EAAE,KAAK,aAAa,EAAE,MAAM,cAAc,CAAA;AAChF,OAAO,EAAE,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,oBAAoB,CAAA;AACjE,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAA;AAEtD,KAAK,YAAY,CAAC,CAAC,SAAS,aAAa,IAAI,qBAAqB,CACjE,OAAO,eAAe,CAAC,CAAC,CAAC,CACzB,CAAC,CAAC,CAAC,CAAA;AAEJ,MAAM,MAAM,oBAAoB,CAAC,CAAC,SAAS,aAAa,IACvD,cAAc,CAAC,CAAC,CAAC,GAAG;IACnB;;;;;;;OAOG;IACH,sEAAsE;IACtE,WAAW,CAAC,EAAE,SAAS,CAAC,SAAS,MAAM,EAAE,CAAC,EAAE,CAAA;IAC5C,KAAK,CAAC,EACH,OAAO,GACP;QACA,OAAO,CAAC,EAAE,MAAM,CAAA;QAChB,2EAA2E;QAC3E,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,KAAK,OAAO,CAAA;QAC9C,MAAM,CAAC,EAAE,YAAY,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAA;KACjC,CAAA;CACJ,CAAA;AAEF;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,SAAU,SAAS,MAAM,EAAE,YACU,CAAA;AAEpE;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAAC,CAAC,SAAS,aAAa,GAAG,aAAa,EACpE,OAAO,EAAE,oBAAoB,CAAC,CAAC,CAAC,GAC9B,OAAO,CAAC,CAAC,CAAC,CA2BZ;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,SAAS,aAAa,EAC3D,KAAK,EAAE,OAAO,EACd,IAAI,EAAE,KAAK,GACT,KAAK,IAAI,SAAS,CAAC,KAAK,EAAE,OAAO,CAAC,CAEpC"}
package/dist/client.js CHANGED
@@ -18,7 +18,8 @@ export const isSubscriptionPath = (path) => path.some((segment) => segment.toLow
18
18
  * ```
19
19
  */
20
20
  export function createRpcLink(options) {
21
- const { batch = true, plugins = [], ...rest } = options;
21
+ const { batch = true, plugins = [], streamPaths, ...rest } = options;
22
+ const streams = new Set(streamPaths?.map((path) => JSON.stringify(path)));
22
23
  if (batch === false)
23
24
  return new RPCLink({ ...rest, plugins });
24
25
  const { maxSize = 25, exclude = isSubscriptionPath, groups } = batch === true ? {} : batch;
@@ -32,7 +33,8 @@ export function createRpcLink(options) {
32
33
  // so the batch's empty context is exactly theirs.
33
34
  { condition: () => true, context: {} }
34
35
  ],
35
- exclude: ({ path, context }) => exclude(path) ||
36
+ exclude: ({ path, context }) => streams.has(JSON.stringify(path)) ||
37
+ exclude(path) ||
36
38
  (groups === undefined && Object.keys(context).length > 0)
37
39
  }),
38
40
  ...plugins
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,SAAS,EAAsB,MAAM,cAAc,CAAA;AAChF,OAAO,EAAE,OAAO,EAAuB,MAAM,oBAAoB,CAAA;AACjE,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAA;AA0BtD;;;;;GAKG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,IAAuB,EAAE,EAAE,CAC7D,IAAI,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,CAAA;AAEpE;;;;;;;;GAQG;AACH,MAAM,UAAU,aAAa,CAC5B,OAAgC;IAEhC,MAAM,EAAE,KAAK,GAAG,IAAI,EAAE,OAAO,GAAG,EAAE,EAAE,GAAG,IAAI,EAAE,GAAG,OAAO,CAAA;IACvD,IAAI,KAAK,KAAK,KAAK;QAAE,OAAO,IAAI,OAAO,CAAI,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,CAAC,CAAA;IAChE,MAAM,EACL,OAAO,GAAG,EAAE,EACZ,OAAO,GAAG,kBAAkB,EAC5B,MAAM,EACN,GAAG,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAA;IAC/B,OAAO,IAAI,OAAO,CAAI;QACrB,GAAG,IAAI;QACP,OAAO,EAAE;YACR,IAAI,eAAe,CAAI;gBACtB,OAAO;gBACP,MAAM,EAAE,MAAM,IAAI;oBACjB,kEAAkE;oBAClE,kDAAkD;oBAClD,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,EAAO,EAAE;iBAC3C;gBACD,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE,CAC9B,OAAO,CAAC,IAAI,CAAC;oBACb,CAAC,MAAM,KAAK,SAAS,IAAI,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;aAC1D,CAAC;YACF,GAAG,OAAO;SACV;KACD,CAAC,CAAA;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAAC,KAAc,EAAE,IAAmB;IACnE,OAAO,KAAK,YAAY,SAAS,IAAI,KAAK,CAAC,IAAI,KAAK,IAAI,CAAA;AACzD,CAAC","sourcesContent":["import { type ClientContext, ORPCError, type ORPCErrorCode } from '@orpc/client'\nimport { RPCLink, type RPCLinkOptions } from '@orpc/client/fetch'\nimport { BatchLinkPlugin } from '@orpc/client/plugins'\n\ntype BatchOptions<T extends ClientContext> = ConstructorParameters<\n\ttypeof BatchLinkPlugin<T>\n>[0]\n\nexport type CreateRpcLinkOptions<T extends ClientContext> =\n\tRPCLinkOptions<T> & {\n\t\t/**\n\t\t * Collapse parallel calls into one HTTP request, matching `mountOrpc`'s\n\t\t * server-side batching. Default: true (25 calls). Pass false to turn off.\n\t\t *\n\t\t * A batch is one HTTP request, so it carries one client context. By\n\t\t * default only calls without a client context are batched; pass\n\t\t * `groups` to batch calls that share a context (e.g. a token).\n\t\t */\n\t\tbatch?:\n\t\t\t| boolean\n\t\t\t| {\n\t\t\t\t\tmaxSize?: number\n\t\t\t\t\t/** Calls that must not be batched. Default: {@link isSubscriptionPath}. */\n\t\t\t\t\texclude?: (path: readonly string[]) => boolean\n\t\t\t\t\tgroups?: BatchOptions<T>['groups']\n\t\t\t }\n\t}\n\n/**\n * Streaming responses cannot be batched, and the request does not say a\n * response will stream - so streaming routes are recognised by name. The\n * default treats any path segment containing `subscribe` as one (the\n * convention `fnLive` routers use: `{ list, subscribe }`).\n */\nexport const isSubscriptionPath = (path: readonly string[]) =>\n\tpath.some((segment) => segment.toLowerCase().includes('subscribe'))\n\n/**\n * `RPCLink` with request batching: a page-load burst becomes one request\n * instead of many queued on the server's event loop.\n *\n * ```ts\n * const client: RouterClient<typeof router> = createORPCClient(createRpcLink({ url }))\n * export const orpc = createTanstackQueryUtils(client)\n * ```\n */\nexport function createRpcLink<T extends ClientContext = ClientContext>(\n\toptions: CreateRpcLinkOptions<T>\n): RPCLink<T> {\n\tconst { batch = true, plugins = [], ...rest } = options\n\tif (batch === false) return new RPCLink<T>({ ...rest, plugins })\n\tconst {\n\t\tmaxSize = 25,\n\t\texclude = isSubscriptionPath,\n\t\tgroups\n\t} = batch === true ? {} : batch\n\treturn new RPCLink<T>({\n\t\t...rest,\n\t\tplugins: [\n\t\t\tnew BatchLinkPlugin<T>({\n\t\t\t\tmaxSize,\n\t\t\t\tgroups: groups ?? [\n\t\t\t\t\t// Only context-free calls reach this group (see `exclude` below),\n\t\t\t\t\t// so the batch's empty context is exactly theirs.\n\t\t\t\t\t{ condition: () => true, context: {} as T }\n\t\t\t\t],\n\t\t\t\texclude: ({ path, context }) =>\n\t\t\t\t\texclude(path) ||\n\t\t\t\t\t(groups === undefined && Object.keys(context).length > 0)\n\t\t\t}),\n\t\t\t...plugins\n\t\t]\n\t})\n}\n\n/**\n * Typed check for a route error on the client. The RPC link rebuilds thrown\n * route errors as `ORPCError`, so `instanceof` plus `code` is the contract.\n */\nexport function hasOrpcErrorCode(error: unknown, code: ORPCErrorCode): boolean {\n\treturn error instanceof ORPCError && error.code === code\n}\n"]}
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,SAAS,EAAsB,MAAM,cAAc,CAAA;AAChF,OAAO,EAAE,OAAO,EAAuB,MAAM,oBAAoB,CAAA;AACjE,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAA;AA4BtD;;;;;GAKG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,IAAuB,EAAE,EAAE,CAC7D,IAAI,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,CAAA;AAEpE;;;;;;;;GAQG;AACH,MAAM,UAAU,aAAa,CAC5B,OAAgC;IAEhC,MAAM,EAAE,KAAK,GAAG,IAAI,EAAE,OAAO,GAAG,EAAE,EAAE,WAAW,EAAE,GAAG,IAAI,EAAE,GAAG,OAAO,CAAA;IACpE,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACzE,IAAI,KAAK,KAAK,KAAK;QAAE,OAAO,IAAI,OAAO,CAAI,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,CAAC,CAAA;IAChE,MAAM,EACL,OAAO,GAAG,EAAE,EACZ,OAAO,GAAG,kBAAkB,EAC5B,MAAM,EACN,GAAG,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAA;IAC/B,OAAO,IAAI,OAAO,CAAI;QACrB,GAAG,IAAI;QACP,OAAO,EAAE;YACR,IAAI,eAAe,CAAI;gBACtB,OAAO;gBACP,MAAM,EAAE,MAAM,IAAI;oBACjB,kEAAkE;oBAClE,kDAAkD;oBAClD,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,EAAO,EAAE;iBAC3C;gBACD,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE,CAC9B,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;oBACjC,OAAO,CAAC,IAAI,CAAC;oBACb,CAAC,MAAM,KAAK,SAAS,IAAI,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;aAC1D,CAAC;YACF,GAAG,OAAO;SACV;KACD,CAAC,CAAA;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAC/B,KAAc,EACd,IAAW;IAEX,OAAO,KAAK,YAAY,SAAS,IAAI,KAAK,CAAC,IAAI,KAAK,IAAI,CAAA;AACzD,CAAC","sourcesContent":["import { type ClientContext, ORPCError, type ORPCErrorCode } from '@orpc/client'\nimport { RPCLink, type RPCLinkOptions } from '@orpc/client/fetch'\nimport { BatchLinkPlugin } from '@orpc/client/plugins'\n\ntype BatchOptions<T extends ClientContext> = ConstructorParameters<\n\ttypeof BatchLinkPlugin<T>\n>[0]\n\nexport type CreateRpcLinkOptions<T extends ClientContext> =\n\tRPCLinkOptions<T> & {\n\t\t/**\n\t\t * Collapse parallel calls into one HTTP request, matching `mountOrpc`'s\n\t\t * server-side batching. Default: true (25 calls). Pass false to turn off.\n\t\t *\n\t\t * A batch is one HTTP request, so it carries one client context. By\n\t\t * default only calls without a client context are batched; pass\n\t\t * `groups` to batch calls that share a context (e.g. a token).\n\t\t */\n\t\t/** Client-safe manifest generated by createStreamManifest(router). */\n\t\tstreamPaths?: readonly (readonly string[])[]\n\t\tbatch?:\n\t\t\t| boolean\n\t\t\t| {\n\t\t\t\t\tmaxSize?: number\n\t\t\t\t\t/** Calls that must not be batched. Default: {@link isSubscriptionPath}. */\n\t\t\t\t\texclude?: (path: readonly string[]) => boolean\n\t\t\t\t\tgroups?: BatchOptions<T>['groups']\n\t\t\t }\n\t}\n\n/**\n * Streaming responses cannot be batched, and the request does not say a\n * response will stream - so streaming routes are recognised by name. The\n * default treats any path segment containing `subscribe` as one (the\n * convention `fnLive` routers use: `{ list, subscribe }`).\n */\nexport const isSubscriptionPath = (path: readonly string[]) =>\n\tpath.some((segment) => segment.toLowerCase().includes('subscribe'))\n\n/**\n * `RPCLink` with request batching: a page-load burst becomes one request\n * instead of many queued on the server's event loop.\n *\n * ```ts\n * const client: RouterClient<typeof router> = createORPCClient(createRpcLink({ url }))\n * export const orpc = createTanstackQueryUtils(client)\n * ```\n */\nexport function createRpcLink<T extends ClientContext = ClientContext>(\n\toptions: CreateRpcLinkOptions<T>\n): RPCLink<T> {\n\tconst { batch = true, plugins = [], streamPaths, ...rest } = options\n\tconst streams = new Set(streamPaths?.map((path) => JSON.stringify(path)))\n\tif (batch === false) return new RPCLink<T>({ ...rest, plugins })\n\tconst {\n\t\tmaxSize = 25,\n\t\texclude = isSubscriptionPath,\n\t\tgroups\n\t} = batch === true ? {} : batch\n\treturn new RPCLink<T>({\n\t\t...rest,\n\t\tplugins: [\n\t\t\tnew BatchLinkPlugin<T>({\n\t\t\t\tmaxSize,\n\t\t\t\tgroups: groups ?? [\n\t\t\t\t\t// Only context-free calls reach this group (see `exclude` below),\n\t\t\t\t\t// so the batch's empty context is exactly theirs.\n\t\t\t\t\t{ condition: () => true, context: {} as T }\n\t\t\t\t],\n\t\t\t\texclude: ({ path, context }) =>\n\t\t\t\t\tstreams.has(JSON.stringify(path)) ||\n\t\t\t\t\texclude(path) ||\n\t\t\t\t\t(groups === undefined && Object.keys(context).length > 0)\n\t\t\t}),\n\t\t\t...plugins\n\t\t]\n\t})\n}\n\n/**\n * Typed check for a route error on the client. The RPC link rebuilds thrown\n * route errors as `ORPCError`, so `instanceof` plus `code` is the contract.\n */\nexport function hasOrpcErrorCode<TCode extends ORPCErrorCode>(\n\terror: unknown,\n\tcode: TCode\n): error is ORPCError<TCode, unknown> {\n\treturn error instanceof ORPCError && error.code === code\n}\n"]}
@@ -0,0 +1,16 @@
1
+ import type { AnySchema, ErrorMap, Meta } from '@orpc/contract';
2
+ import type { Procedure, Route } from '@orpc/server';
3
+ /** All runtime access to oRPC's implementation namespace is audited here. */
4
+ export type ProcedureDefinition = {
5
+ meta?: Record<string, unknown>;
6
+ route?: Route;
7
+ inputSchema?: AnySchema;
8
+ outputSchema?: AnySchema;
9
+ };
10
+ export declare function procedureDefinition(procedure: object): ProcedureDefinition;
11
+ export type NativeMeta<T> = T extends Procedure<infer _I, infer _C, infer _In, infer _Out, infer _E, infer M extends Meta> ? M : Meta;
12
+ export type NativeErrors<T> = T extends Procedure<infer _I, infer _C, infer _In, infer _Out, infer E extends ErrorMap, infer _M> ? E : ErrorMap;
13
+ export type LibraryMeta<T> = NativeMeta<T> extends {
14
+ 'orpc-fn': infer M;
15
+ } ? M : never;
16
+ //# sourceMappingURL=compatibility.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compatibility.d.ts","sourceRoot":"","sources":["../src/compatibility.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAA;AAC/D,OAAO,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,cAAc,CAAA;AAEpD,6EAA6E;AAC7E,MAAM,MAAM,mBAAmB,GAAG;IACjC,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC9B,KAAK,CAAC,EAAE,KAAK,CAAA;IACb,WAAW,CAAC,EAAE,SAAS,CAAA;IACvB,YAAY,CAAC,EAAE,SAAS,CAAA;CACxB,CAAA;AAED,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,GAAG,mBAAmB,CAE1E;AAED,MAAM,MAAM,UAAU,CAAC,CAAC,IACvB,CAAC,SAAS,SAAS,CAClB,MAAM,EAAE,EACR,MAAM,EAAE,EACR,MAAM,GAAG,EACT,MAAM,IAAI,EACV,MAAM,EAAE,EACR,MAAM,CAAC,SAAS,IAAI,CACpB,GACE,CAAC,GACD,IAAI,CAAA;AACR,MAAM,MAAM,YAAY,CAAC,CAAC,IACzB,CAAC,SAAS,SAAS,CAClB,MAAM,EAAE,EACR,MAAM,EAAE,EACR,MAAM,GAAG,EACT,MAAM,IAAI,EACV,MAAM,CAAC,SAAS,QAAQ,EACxB,MAAM,EAAE,CACR,GACE,CAAC,GACD,QAAQ,CAAA;AACZ,MAAM,MAAM,WAAW,CAAC,CAAC,IACxB,UAAU,CAAC,CAAC,CAAC,SAAS;IAAE,SAAS,EAAE,MAAM,CAAC,CAAA;CAAE,GAAG,CAAC,GAAG,KAAK,CAAA"}
@@ -0,0 +1,4 @@
1
+ export function procedureDefinition(procedure) {
2
+ return procedure['~orpc'] ?? {};
3
+ }
4
+ //# sourceMappingURL=compatibility.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compatibility.js","sourceRoot":"","sources":["../src/compatibility.ts"],"names":[],"mappings":"AAWA,MAAM,UAAU,mBAAmB,CAAC,SAAiB;IACpD,OAAQ,SAA+C,CAAC,OAAO,CAAC,IAAI,EAAE,CAAA;AACvE,CAAC","sourcesContent":["import type { AnySchema, ErrorMap, Meta } from '@orpc/contract'\nimport type { Procedure, Route } from '@orpc/server'\n\n/** All runtime access to oRPC's implementation namespace is audited here. */\nexport type ProcedureDefinition = {\n\tmeta?: Record<string, unknown>\n\troute?: Route\n\tinputSchema?: AnySchema\n\toutputSchema?: AnySchema\n}\n\nexport function procedureDefinition(procedure: object): ProcedureDefinition {\n\treturn (procedure as { '~orpc'?: ProcedureDefinition })['~orpc'] ?? {}\n}\n\nexport type NativeMeta<T> =\n\tT extends Procedure<\n\t\tinfer _I,\n\t\tinfer _C,\n\t\tinfer _In,\n\t\tinfer _Out,\n\t\tinfer _E,\n\t\tinfer M extends Meta\n\t>\n\t\t? M\n\t\t: Meta\nexport type NativeErrors<T> =\n\tT extends Procedure<\n\t\tinfer _I,\n\t\tinfer _C,\n\t\tinfer _In,\n\t\tinfer _Out,\n\t\tinfer E extends ErrorMap,\n\t\tinfer _M\n\t>\n\t\t? E\n\t\t: ErrorMap\nexport type LibraryMeta<T> =\n\tNativeMeta<T> extends { 'orpc-fn': infer M } ? M : never\n"]}
@@ -1,23 +1,12 @@
1
- import type { AnyProcedure } from '@orpc/server';
2
1
  import { type BoundCall } from './bound-call.js';
3
2
  import { type FnLive } from './live/fn-live.js';
4
3
  import { type CreatePublisher, type CreatePubSub, type PubSubRuntimeOptions } from './live/pub-sub.js';
5
4
  import { type FnLogger, type LogAttributes } from './logger.js';
6
- import { type FnMeta } from './meta.js';
7
- import { type AttributeValue, type OtelApiLike, type SpanLike, type SpanOf } from './otel.js';
5
+ import { readFnMeta } from './meta.js';
6
+ import { type AttributeValue, type OtelApiLike, type SpanOf } from './otel.js';
8
7
  import { createRouter } from './router.js';
9
- import { type AnyFnContext, type BuilderLike, type FiniteExtras, type Fn, type FnCompletedEvent, type FnDefinition, type Guard, type GuardParams, type MaybePromise, type RejectKeys, type ReservedOptionKey } from './types.js';
10
- type UnionContext<TProcedures extends Record<string, BuilderLike>> = AnyFnContext<{
11
- procedures: TProcedures;
12
- default: string;
13
- extras: object;
14
- guards: object;
15
- meta: object;
16
- tag: string;
17
- span: SpanLike;
18
- logger: FnLogger;
19
- }>;
20
- export type CreateFnOptions<TProcedures extends Record<string, BuilderLike>, TDefault extends keyof TProcedures & string, TExtras extends object, TGuards, TMeta extends object, TTag extends string, TOtel extends OtelApiLike | undefined, TLogger extends FnLogger> = {
8
+ import { type ProcedureHookParams, type CompletedHookEvent, type CurrentContextOf, type BuilderLike, type FiniteExtras, type FiniteScopedExtras, type Fn, type FnDefinition, type Guard, type GuardParams, type MaybePromise, type RejectKeys, type ReservedOptionKey } from './types.js';
9
+ export type CreateFnOptions<TProcedures extends Record<string, BuilderLike>, TDefault extends keyof TProcedures & string, TExtras extends object, TGuards, TMeta extends object, TTag extends string, TOtel extends OtelApiLike | undefined, TLogger extends FnLogger, TScoped extends Partial<Record<keyof TProcedures, object>> = Record<never, never>> = {
21
10
  /** Named oRPC builders, e.g. `{ public: os.$context<Ctx>(), protected: authed }`. */
22
11
  procedures: TProcedures;
23
12
  /**
@@ -26,46 +15,52 @@ export type CreateFnOptions<TProcedures extends Record<string, BuilderLike>, TDe
26
15
  */
27
16
  default?: TDefault;
28
17
  /** Per-call values merged into every handler's params; may be async. */
29
- extras?: (params: {
30
- context: UnionContext<TProcedures>;
18
+ extras?: (params: ProcedureHookParams<TProcedures, {
31
19
  span: SpanOf<TOtel> | undefined;
32
20
  signal: AbortSignal | undefined;
33
21
  name: string;
34
- procedure: string;
35
- }) => MaybePromise<TExtras>;
22
+ }>) => MaybePromise<TExtras>;
23
+ extrasByProcedure?: {
24
+ [K in keyof TScoped & keyof TProcedures]: (params: {
25
+ context: CurrentContextOf<TProcedures[K]>;
26
+ span: SpanOf<TOtel> | undefined;
27
+ signal: AbortSignal | undefined;
28
+ name: string;
29
+ procedure: K;
30
+ }) => MaybePromise<TScoped[K]>;
31
+ };
36
32
  /**
37
33
  * Checks run before the handler; each key becomes a typed `fn()` option.
38
- * Keys must not reuse route options or meta keys.
34
+ * Keys must not reuse route options. False denies, true or void allows.
39
35
  */
40
- guards?: TGuards & Record<string, Guard<never, GuardParams<UnionContext<TProcedures>, TMeta>>> & RejectKeys<NoInfer<TGuards>, ReservedOptionKey | keyof NoInfer<TMeta>, 'orpc-fn: this guard name is a route option or meta key'>;
36
+ guards?: TGuards & Record<string, Guard<never, ProcedureHookParams<TProcedures, Omit<GuardParams<unknown, TMeta>, 'context' | 'procedure'>>>> & RejectKeys<NoInfer<TGuards>, ReservedOptionKey, 'orpc-fn: this guard name is a route option'>;
41
37
  /**
42
- * Typed route metadata: `meta: {} as { readOnly?: boolean }`. Keys become
43
- * `fn()` options and must not reuse route options.
38
+ * Typed route metadata contract: `meta: defineMeta<AppMeta>()`.
39
+ * Route declarations place values inside their own `meta` object.
44
40
  */
45
- meta?: TMeta & RejectKeys<NoInfer<TMeta>, ReservedOptionKey, 'orpc-fn: this meta key is a route option'>;
41
+ meta?: TMeta;
46
42
  /** Allowed route tags: `tags: ['internal', 'external']`. */
47
43
  tags?: readonly TTag[];
48
44
  /** `import * as otel from '@opentelemetry/api'`. Omit for no tracing. */
49
45
  otel?: TOtel;
50
46
  logger?: (scope: string, span: SpanOf<TOtel> | undefined) => TLogger;
51
47
  /** Extra span attributes per call; undefined values are skipped. */
52
- spanAttributes?: (params: {
53
- context: UnionContext<TProcedures>;
48
+ spanAttributes?: (params: ProcedureHookParams<TProcedures, {
54
49
  name: string;
55
- procedure: string;
56
50
  meta: Partial<TMeta>;
57
- }) => Record<string, AttributeValue | undefined>;
58
- /** Called after every handler; returned attributes join the `fn.completed` log. */
59
- onCompleted?: (event: FnCompletedEvent<UnionContext<TProcedures>, SpanOf<TOtel>>) => LogAttributes | undefined | void;
51
+ }>) => Record<string, AttributeValue | undefined>;
52
+ /** Called after the procedure (or stream) settles; returned attributes join the `fn.completed` log. */
53
+ onCompleted?: (event: CompletedHookEvent<TProcedures, SpanOf<TOtel>>) => LogAttributes | undefined | void;
60
54
  /** Errors that are the caller's fault, logged at `warn`. Default: 4xx `ORPCError` or `AbortError`. */
61
55
  isExpectedError?: (error: unknown) => boolean;
62
56
  /** Needed for `fnLive` and `createPubSub`. */
63
57
  pubsub?: PubSubRuntimeOptions;
64
58
  };
65
- type Definition<TProcedures extends Record<string, BuilderLike>, TDefault extends string, TExtras extends object, TGuards, TMeta extends object, TTag extends string, TOtel, TLogger extends FnLogger> = {
59
+ type Definition<TProcedures extends Record<string, BuilderLike>, TDefault extends string, TExtras extends object, TGuards, TMeta extends object, TTag extends string, TOtel, TLogger extends FnLogger, TScoped extends Partial<Record<keyof TProcedures, object>> = Record<never, never>> = {
66
60
  procedures: TProcedures;
67
61
  default: TDefault;
68
62
  extras: TExtras;
63
+ extrasByProcedure: TScoped;
69
64
  guards: TGuards;
70
65
  meta: TMeta;
71
66
  tag: TTag;
@@ -78,13 +73,14 @@ export type FnFactory<TDef extends FnDefinition> = {
78
73
  createPubSub: CreatePubSub<TDef>;
79
74
  createPublisher: CreatePublisher;
80
75
  createRouter: typeof createRouter;
81
- readMeta: (procedure: AnyProcedure) => FnMeta<TDef['meta']>;
76
+ readMeta: typeof readFnMeta;
82
77
  /**
83
78
  * A `call` outside any handler (seeders, scripts, tests), traced with this
84
79
  * instance's OpenTelemetry.
85
80
  */
86
81
  createCall: <TContext>(context: TContext, signal?: AbortSignal) => BoundCall<TContext>;
87
- /** End every open subscription of this instance; returns how many closed. */
82
+ /** Terminal, idempotent shutdown: close streams and await owned resources. */
83
+ shutdown: () => Promise<void>;
88
84
  drainPubSubSubscribers: () => number;
89
85
  activePubSubSubscriberCount: () => number;
90
86
  };
@@ -92,6 +88,6 @@ export type FnFactory<TDef extends FnDefinition> = {
92
88
  * Builds the app's `fn` and friends once. Everything app-specific (auth,
93
89
  * context, database, queues, i18n, permissions) is injected here.
94
90
  */
95
- export declare function createFn<const TProcedures extends Record<string, BuilderLike>, TDefault extends keyof TProcedures & string = never, TExtras extends object = Record<never, never>, TGuards extends object = Record<never, never>, TMeta extends object = Record<never, never>, const TTag extends string = string, TOtel extends OtelApiLike | undefined = undefined, TLogger extends FnLogger = FnLogger>(options: CreateFnOptions<TProcedures, TDefault, TExtras, TGuards, TMeta, TTag, TOtel, TLogger> & FiniteExtras<NoInfer<TExtras>>): FnFactory<Definition<TProcedures, TDefault, TExtras, TGuards, TMeta, TTag, TOtel, TLogger>>;
91
+ export declare function createFn<const TProcedures extends Record<string, BuilderLike>, TDefault extends keyof TProcedures & string = never, TExtras extends object = Record<never, never>, TGuards extends object = Record<never, never>, TMeta extends object = Record<never, never>, const TTag extends string = string, TOtel extends OtelApiLike | undefined = undefined, TLogger extends FnLogger = FnLogger, TScoped extends Partial<Record<keyof TProcedures, object>> = Record<never, never>>(options: CreateFnOptions<TProcedures, TDefault, TExtras, TGuards, TMeta, TTag, TOtel, TLogger, TScoped> & FiniteExtras<NoInfer<TExtras>> & FiniteScopedExtras<NoInfer<TScoped>>): FnFactory<Definition<TProcedures, TDefault, TExtras, TGuards, TMeta, TTag, TOtel, TLogger, TScoped>>;
96
92
  export {};
97
93
  //# sourceMappingURL=create-fn.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"create-fn.d.ts","sourceRoot":"","sources":["../src/create-fn.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"create-fn.d.ts","sourceRoot":"","sources":["../src/create-fn.ts"],"names":[],"mappings":"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"}