orpc-fn 0.4.0 → 0.5.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 (90) hide show
  1. package/README.md +146 -4
  2. package/dist/client.d.ts +29 -0
  3. package/dist/client.d.ts.map +1 -1
  4. package/dist/client.js +49 -0
  5. package/dist/client.js.map +1 -1
  6. package/dist/create-fn.d.ts.map +1 -1
  7. package/dist/create-fn.js +0 -1
  8. package/dist/create-fn.js.map +1 -1
  9. package/dist/hono.d.ts +12 -1
  10. package/dist/hono.d.ts.map +1 -1
  11. package/dist/hono.js +15 -1
  12. package/dist/hono.js.map +1 -1
  13. package/dist/live/fn-live.d.ts +1 -6
  14. package/dist/live/fn-live.d.ts.map +1 -1
  15. package/dist/live/fn-live.js +2 -18
  16. package/dist/live/fn-live.js.map +1 -1
  17. package/dist/live/index.d.ts +3 -1
  18. package/dist/live/index.d.ts.map +1 -1
  19. package/dist/live/index.js +2 -0
  20. package/dist/live/index.js.map +1 -1
  21. package/dist/live/invalidation-stream.d.ts +52 -0
  22. package/dist/live/invalidation-stream.d.ts.map +1 -0
  23. package/dist/live/invalidation-stream.js +98 -0
  24. package/dist/live/invalidation-stream.js.map +1 -0
  25. package/dist/live/ioredis.d.ts +1 -0
  26. package/dist/live/ioredis.d.ts.map +1 -1
  27. package/dist/live/ioredis.js +1 -0
  28. package/dist/live/ioredis.js.map +1 -1
  29. package/dist/live/memory.d.ts +2 -1
  30. package/dist/live/memory.d.ts.map +1 -1
  31. package/dist/live/memory.js +6 -1
  32. package/dist/live/memory.js.map +1 -1
  33. package/dist/live/pub-sub.d.ts +5 -0
  34. package/dist/live/pub-sub.d.ts.map +1 -1
  35. package/dist/live/pub-sub.js +16 -3
  36. package/dist/live/pub-sub.js.map +1 -1
  37. package/dist/live/redis-bun.d.ts +3 -0
  38. package/dist/live/redis-bun.d.ts.map +1 -1
  39. package/dist/live/redis-bun.js +1 -0
  40. package/dist/live/redis-bun.js.map +1 -1
  41. package/dist/live/redis.d.ts +4 -1
  42. package/dist/live/redis.d.ts.map +1 -1
  43. package/dist/live/redis.js +14 -2
  44. package/dist/live/redis.js.map +1 -1
  45. package/dist/live/scoped-change-bus.d.ts +45 -0
  46. package/dist/live/scoped-change-bus.d.ts.map +1 -0
  47. package/dist/live/scoped-change-bus.js +38 -0
  48. package/dist/live/scoped-change-bus.js.map +1 -0
  49. package/dist/live/transport.d.ts +11 -0
  50. package/dist/live/transport.d.ts.map +1 -1
  51. package/dist/live/transport.js.map +1 -1
  52. package/dist/procedure-cli.d.ts +25 -0
  53. package/dist/procedure-cli.d.ts.map +1 -0
  54. package/dist/procedure-cli.js +67 -0
  55. package/dist/procedure-cli.js.map +1 -0
  56. package/dist/react.d.ts +116 -0
  57. package/dist/react.d.ts.map +1 -0
  58. package/dist/react.js +156 -0
  59. package/dist/react.js.map +1 -0
  60. package/dist/realtime.d.ts +114 -0
  61. package/dist/realtime.d.ts.map +1 -0
  62. package/dist/realtime.js +316 -0
  63. package/dist/realtime.js.map +1 -0
  64. package/dist/vue/testing.d.ts +67 -0
  65. package/dist/vue/testing.d.ts.map +1 -0
  66. package/dist/vue/testing.js +225 -0
  67. package/dist/vue/testing.js.map +1 -0
  68. package/dist/vue.d.ts +211 -0
  69. package/dist/vue.d.ts.map +1 -0
  70. package/dist/vue.js +312 -0
  71. package/dist/vue.js.map +1 -0
  72. package/package.json +51 -3
  73. package/src/client.ts +57 -0
  74. package/src/create-fn.ts +0 -1
  75. package/src/hono.ts +22 -2
  76. package/src/live/fn-live.ts +3 -22
  77. package/src/live/index.ts +12 -1
  78. package/src/live/invalidation-stream.ts +142 -0
  79. package/src/live/ioredis.ts +2 -0
  80. package/src/live/memory.ts +11 -2
  81. package/src/live/pub-sub.ts +23 -2
  82. package/src/live/redis-bun.ts +3 -0
  83. package/src/live/redis.ts +33 -6
  84. package/src/live/scoped-change-bus.ts +98 -0
  85. package/src/live/transport.ts +12 -0
  86. package/src/procedure-cli.ts +99 -0
  87. package/src/react.ts +355 -0
  88. package/src/realtime.ts +416 -0
  89. package/src/vue/testing.ts +296 -0
  90. package/src/vue.ts +783 -0
package/README.md CHANGED
@@ -130,13 +130,49 @@ The `subscribe` route runs builder middleware and the same fn guards/extras/meta
130
130
  - `reauthorize` can check access before each live update. Initial authorization covers idle streams; apps that need immediate revocation should close those streams.
131
131
  - `safePublish` logs publish errors instead of throwing them; it does not retry or guarantee delivery.
132
132
 
133
- **`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.
133
+ **`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. `safePublish` logs a failed publish (`pubsub.publish_failed`) instead of throwing, as on `fnLive`. **`createPublisher`** is the publish-only half.
134
+
135
+ **`defineScopedChangeBus`** binds `createPubSub` to one scope rule, for buses that tell everyone in a scope (usually an organization) "this changed". Each bus names a channel `prefix`; events go to `${prefix}:${scope}`. Publishing is safe by default, since buses publish after committed writes. `bus.channel` lets an `fnLive` share the bus's events.
136
+
137
+ ```ts
138
+ import { defineScopedChangeBus, invalidationStream } from 'orpc-fn/live'
139
+
140
+ const defineChangeBus = defineScopedChangeBus(createPubSub, {
141
+ subscribe: (context) => activeOrganizationId(context), // throw to refuse
142
+ publish: (event: { organizationId: string }) => event.organizationId
143
+ })
144
+ export const dealChanges = defineChangeBus({
145
+ name: 'deal.subscribe',
146
+ prefix: 'deal:change',
147
+ inputSchema: z.object({}),
148
+ eventSchema: z.object({ organizationId: z.string(), dealId: z.string() })
149
+ })
150
+ ```
151
+
152
+ **`invalidationStream`** fans several streams into one stream of `{ domain }` events, so a client holds one connection and invalidates queries per domain. `events` optionally forwards fields from a source event, for example to raise an alert. Sources are called with `{}` and the caller's context. Equal events that queue while the consumer is busy collapse into one. When one source ends (a deploy drain) the stream ends, when one throws the stream throws, and every source is closed either way.
153
+
154
+ ```ts
155
+ export const subscribeChanges = fn({
156
+ name: 'realtime.subscribeChanges',
157
+ stream: true,
158
+ input: z.object({}),
159
+ handler: ({ context, signal }) =>
160
+ invalidationStream({
161
+ context,
162
+ signal,
163
+ sources: { deal: dealChanges.subscribe, workItem: workItemChanges.subscribe },
164
+ events: { deal: (event) => (event.kind === 'won' ? { dealId: event.dealId } : undefined) }
165
+ })
166
+ })
167
+ ```
168
+
169
+ On the client, `useInvalidationStream` from `orpc-fn/vue` or `orpc-fn/react` consumes it; its `domains` map is typed from the route's domains.
134
170
 
135
171
  **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`, and a lazy `transport: () => …` only if it was ever created; it is never created during or after shutdown. 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.
136
172
 
137
173
  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.
138
174
 
139
- **Transports** implement `PubSubTransport` (`publish(messages, backlog?)`, `readBacklog(channel)`, `subscribe(channel, listener, onLost, { onReconnect }?)`):
175
+ **Transports** implement `PubSubTransport` (`publish(messages, backlog?)`, `readBacklog(channel)`, `subscribe(channel, listener, onLost, { onReconnect }?)` and optional `stats()`):
140
176
 
141
177
  | Subpath | Client | Notes |
142
178
  |---|---|---|
@@ -144,7 +180,16 @@ Recent event IDs deduplicate replay/live overlap; legacy payloads remain readabl
144
180
  | `orpc-fn/live/ioredis` | ioredis 5 | Dedicated subscriber via `duplicate()`; ioredis re-subscribes itself |
145
181
  | `orpc-fn/live/memory` | none | Tests and single-process dev |
146
182
 
147
- 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.
183
+ 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.
184
+
185
+ All three return `stats()`: `{ channels, listeners, subscriberConnected }` on this instance. With `activePubSubSubscriberCount()` from `createFn` that covers pub/sub gauges; a transport opens no connection until the first subscribe, so it can be created eagerly:
186
+
187
+ ```ts
188
+ const transport = bunRedisTransport(redis)
189
+ createFn({ /* … */, pubsub: { transport, ownsTransport: true } })
190
+ meter.createObservableGauge('pubsub_subscribed_channels').addCallback((g) => g.observe(transport.stats().channels))
191
+ meter.createObservableGauge('pubsub_redis_subscriber_connected').addCallback((g) => g.observe(transport.stats().subscriberConnected ? 1 : 0))
192
+ ``` The Redis Lua batching adapter supports standalone Redis; Redis Cluster requires compatible key slots and is not promised by this adapter.
148
193
 
149
194
  `streamLiveSnapshots`, `fnLivePatch` and `throwInitialSnapshotError` are exported for custom streams.
150
195
 
@@ -196,6 +241,32 @@ The adapter installs the SDK list/call handlers on a low-level `Server` (also ac
196
241
 
197
242
  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.
198
243
 
244
+ ## `orpc-fn/cli`
245
+
246
+ Optional peer: `hanzio` ^3.1.0 (`hanzio/cli`).
247
+
248
+ ```ts
249
+ import { defineCli } from 'hanzio/cli'
250
+ import { procedureCommands } from 'orpc-fn/cli'
251
+
252
+ const updateDeal = fn({
253
+ name: 'deal.update',
254
+ summary: 'Move a deal to another stage', // the command's help
255
+ meta: { cli: true },
256
+ input: z.object({ id: z.string().meta({ positional: true }), stage: z.string() }),
257
+ handler: async ({ input, context }) => { /* ... */ }
258
+ })
259
+
260
+ await defineCli({
261
+ name: 'app',
262
+ globals: z.object({ as: z.string().optional() }),
263
+ context: async ({ as }) => ({ user: as ? await loadUser(as) : undefined }),
264
+ commands: procedureCommands(router)
265
+ }).run() // app deal update d_1 --stage won --as ada@example.com
266
+ ```
267
+
268
+ `procedureCommands(router)` turns the routes declared with `meta: { cli: true }` into commands nested like the router, kebab-cased (`dealRoom.update` is `deal-room update`); add `cli?: boolean` to your meta type, or select routes with `filter`. Flags and positionals come from the route's `z.object()` input. A command calls the procedure through oRPC with the CLI's context, so middleware, guards and tracing run as over HTTP; `context: (cliContext, meta) => ...` maps that context per procedure and can refuse with a `CliError`. A 4xx `ORPCError` prints as `CODE: message`; anything else keeps its stack. Streams and non-object inputs throw when the commands are built. The procedure parses the already-validated flags again, so transforms must accept their own output.
269
+
199
270
  ## `orpc-fn/hono`
200
271
 
201
272
  Optional peers: `hono`, `@orpc/openapi`, `@orpc/zod`, `@orpc/json-schema`.
@@ -221,6 +292,7 @@ Behaviour:
221
292
  - Scalar docs are served at the OpenAPI prefix.
222
293
  - `onError` sees only unexpected errors.
223
294
  - `openapi.filter`, `openapi.smartCoercion` and `openapi.spec` (for security schemes) cover an external API with its own auth.
295
+ - `markRequestArrival(request)` at the front door (`Bun.serve({ fetch })`, before routing) makes `queue_ms` the time until the procedure runs: in-process queueing no handler timer sees. Pass `queueMs` to measure it another way.
224
296
  - `context` builds the router's context and is checked against it: it is required when `{ headers, timing }` alone does not satisfy the router. It may return a `Response`, for example a 401.
225
297
 
226
298
  ## `orpc-fn/client`
@@ -242,8 +314,11 @@ export const client: RouterClient<typeof router> = createORPCClient(link)
242
314
  export const orpc = createTanstackQueryUtils(client) // Vue Query or React Query
243
315
 
244
316
  if (hasOrpcErrorCode(error, 'NOT_FOUND')) { /* … */ }
317
+ toast(userFacingErrorMessage(error, t('errors.generic'))) // server text only when it opts in
245
318
  ```
246
319
 
320
+ Route error messages are developer text, so `userFacingErrorMessage` shows your localized fallback unless the server opted in with `new ORPCError('BAD_REQUEST', { message, data: { userMessage } })`. `queryCacheSerializer` is a `serialize`/`deserialize` pair for TanStack Query persisters that round-trips `Date`s and the other types oRPC sends.
321
+
247
322
  `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. The `orpc-fn` CLI does that, resolving lazy routers, sorting paths and writing only on change:
248
323
 
249
324
  ```sh
@@ -272,7 +347,74 @@ const link = createBetterAuthExpoLink({
272
347
  })
273
348
  ```
274
349
 
275
- 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.
350
+ On native, calls go through `expo/fetch`, the only fetch that streams there. In Expo SDK 55, cancelling a stream makes `expo/fetch` close its body twice and throw `Invalid state: Controller is already closed`; patch `src/winter/fetch/FetchResponse.ts` so its `didComplete` and `didFailWithError` listeners return when `isControllerClosed` is already set (with `bun patch expo` or `patch-package`). 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.
351
+
352
+ ## `orpc-fn/vue`
353
+
354
+ Peers: `vue`, `@tanstack/vue-query`.
355
+
356
+ ```ts
357
+ // main.ts
358
+ app.use(VueQueryPlugin, { queryClient })
359
+ provideOrpc(app, { client, utils: orpc })
360
+
361
+ declare module 'orpc-fn/vue' {
362
+ interface Register { client: typeof client; utils: typeof orpc }
363
+ }
364
+ ```
365
+
366
+ ```ts
367
+ const { useQuery, useMutation, invalidate } = useApiClient()
368
+ const orders = useQuery((o) => o.order.list.queryOptions({ input: { search: search.value } }))
369
+ const save = useMutation((o) => o.order.update.mutationOptions({ onSuccess: () => invalidate((o) => o.order.key()) }))
370
+
371
+ // The client half of `fnLive`: HTTP seeds the cache, the stream keeps it current.
372
+ const order = useLiveQuery(
373
+ () => ({ id: props.id }),
374
+ (input, o) => o.order.get.queryOptions({ input }),
375
+ (o) => o.order.watch.call // the composable passes the input and an abort signal
376
+ )
377
+
378
+ // Once, in the signed-in shell: one stream of `{ domain }` events invalidates list queries.
379
+ useInvalidationStream({}, (o) => o.realtime.subscribeChanges.call, {
380
+ domains: { order: { debounceMs: 100, queryKeys: [orpc.order.key()] } },
381
+ logger
382
+ })
383
+ ```
384
+
385
+ `useOrpcSubscription` (also `useApiClient().useSubscription`) reconnects with jittered backoff and closes while the page is hidden (`respectVisibility: false` keeps it). `useLiveQuery` writes each stream event under the key it was opened for, so an event in flight from a previous input is dropped. A stream whose events are not the cached type (an `fnLive` patch route, or a `select`ed cache) does not compile without `applyEvent`, and the stream's input must match the query's unless you pass `subscriptionInput`. Use `mergeSeed` when the seed can resolve after stream events. For large live payloads such as chat timelines, pass vue-query's `shallow: true` in the query options so the data is not made deeply reactive; mutate it only through `setQueryData`. Live queries carry `meta.live`, so invalidation streams skip them. Leave `refetchType` at TanStack's `'active'`: `'all'` refetches every cached query of a domain on each event, including screens nobody has open, which refetch on their next visit anyway. `useSubscriptionInvalidates` treats a stream as a "something changed" ping, and `useQueryErrorMessage` is `userFacingErrorMessage` as a computed. A surface that talks to another API passes `orpc` to each composable instead of using `provideOrpc`.
386
+
387
+ `orpc-fn/vue/testing` runs composables in a real app without a DOM: `withOrpcApp(setup, { utils })`, `createTestStream()` for a subscription the test drives (`await stream.push(event)` resolves once it was handled), and `createOrpcMock({ fn: mock })` for a deep stand-in of the utils.
388
+
389
+ ## `orpc-fn/react`
390
+
391
+ Peers: `react`, `@tanstack/react-query`. Works on React Native: pausing follows TanStack's `focusManager`, so wire it to `AppState` once, as TanStack recommends:
392
+
393
+ ```ts
394
+ focusManager.setEventListener((setFocused) => {
395
+ const subscription = AppState.addEventListener('change', (state) => setFocused(state === 'active'))
396
+ return () => subscription.remove()
397
+ })
398
+ ```
399
+
400
+ ```tsx
401
+ const { status } = useOrpcSubscription({ id }, client.order.watch, { onEvent: (order) => setOrder(order) })
402
+
403
+ // Same contract as the Vue `useLiveQuery`, with the client procedure passed as is.
404
+ // For a large cache your `applyEvent` keeps immutable, pass `structuralSharing: false` in the query options.
405
+ const order = useLiveQuery({ id }, (input) => orpc.order.get.queryOptions({ input }), client.order.watch)
406
+
407
+ useInvalidationStream({}, client.realtime.subscribeChanges, {
408
+ enabled: signedIn,
409
+ domains: { order: { debounceMs: 500, queryKeys: [orpc.order.list.key()] } }
410
+ })
411
+
412
+ // Persist the cache per user: the buster drops someone else's saved cache, the hook clears memory.
413
+ const owner = session ? `${session.user.id}:${session.activeOrganizationId ?? ''}` : null
414
+ useQueryCacheOwner(owner)
415
+ const persister = createAsyncStoragePersister({ storage: AsyncStorage, ...queryCacheSerializer })
416
+ <PersistQueryClientProvider client={queryClient} persistOptions={{ persister, buster: owner ?? '' }} />
417
+ ```
276
418
 
277
419
  ## Docs
278
420
 
package/dist/client.d.ts CHANGED
@@ -42,5 +42,34 @@ export declare function createRpcLink<T extends ClientContext = ClientContext>(o
42
42
  * route errors as `ORPCError`, so `instanceof` plus `code` is the contract.
43
43
  */
44
44
  export declare function hasOrpcErrorCode<TCode extends ORPCErrorCode>(error: unknown, code: TCode): error is ORPCError<TCode, unknown>;
45
+ /**
46
+ * The server's message, only when the backend marked it user-safe by putting
47
+ * a `userMessage` string on the error's `data`. Route error messages are
48
+ * developer text (English, internal model names), so they are not shown by
49
+ * default; they stay on the error for logs and error tracking.
50
+ *
51
+ * ```ts
52
+ * throw new ORPCError('BAD_REQUEST', {
53
+ * message: 'Deal has no pipeline stage', // logs, telemetry
54
+ * data: { userMessage: 'Choose a stage first.' } // the user reads this
55
+ * })
56
+ * ```
57
+ */
58
+ export declare function userSafeServerMessage(error: unknown): string | null;
59
+ /** User-facing text for a caught error: the opted-in server message, else your localized fallback. */
60
+ export declare function userFacingErrorMessage(error: unknown, fallback: string): string;
61
+ /**
62
+ * `serialize`/`deserialize` for a TanStack Query persister. API payloads carry
63
+ * `Date`s (and maybe `Map`s, `Set`s, `BigInt`s) that plain JSON returns as
64
+ * strings; oRPC's own serializer round-trips them.
65
+ *
66
+ * ```ts
67
+ * createAsyncStoragePersister({ storage: AsyncStorage, ...queryCacheSerializer })
68
+ * ```
69
+ */
70
+ export declare const queryCacheSerializer: {
71
+ serialize(value: unknown): string;
72
+ deserialize<T>(text: string): T;
73
+ };
45
74
  export {};
46
75
  //# 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,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"}
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;AAGtD,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;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAQnE;AAED,sGAAsG;AACtG,wBAAgB,sBAAsB,CACrC,KAAK,EAAE,OAAO,EACd,QAAQ,EAAE,MAAM,GACd,MAAM,CAER;AAID;;;;;;;;GAQG;AACH,eAAO,MAAM,oBAAoB;IAChC,SAAS,QAAQ,OAAO,GAAG,MAAM;IAIjC,WAAW,CAAC,CAAC,QAAQ,MAAM,GAAG,CAAC;CAO/B,CAAA"}
package/dist/client.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import { ORPCError } from '@orpc/client';
2
2
  import { RPCLink } from '@orpc/client/fetch';
3
3
  import { BatchLinkPlugin } from '@orpc/client/plugins';
4
+ import { StandardRPCJsonSerializer } from '@orpc/client/standard';
4
5
  /**
5
6
  * Streaming responses cannot be batched, and the request does not say a
6
7
  * response will stream - so streaming routes are recognised by name. The
@@ -48,4 +49,52 @@ export function createRpcLink(options) {
48
49
  export function hasOrpcErrorCode(error, code) {
49
50
  return error instanceof ORPCError && error.code === code;
50
51
  }
52
+ /**
53
+ * The server's message, only when the backend marked it user-safe by putting
54
+ * a `userMessage` string on the error's `data`. Route error messages are
55
+ * developer text (English, internal model names), so they are not shown by
56
+ * default; they stay on the error for logs and error tracking.
57
+ *
58
+ * ```ts
59
+ * throw new ORPCError('BAD_REQUEST', {
60
+ * message: 'Deal has no pipeline stage', // logs, telemetry
61
+ * data: { userMessage: 'Choose a stage first.' } // the user reads this
62
+ * })
63
+ * ```
64
+ */
65
+ export function userSafeServerMessage(error) {
66
+ if (!(error instanceof ORPCError))
67
+ return null;
68
+ const data = error.data;
69
+ if (typeof data !== 'object' || data === null)
70
+ return null;
71
+ const userMessage = data.userMessage;
72
+ return typeof userMessage === 'string' && userMessage.trim().length > 0
73
+ ? userMessage
74
+ : null;
75
+ }
76
+ /** User-facing text for a caught error: the opted-in server message, else your localized fallback. */
77
+ export function userFacingErrorMessage(error, fallback) {
78
+ return userSafeServerMessage(error) ?? fallback;
79
+ }
80
+ const cacheSerializer = new StandardRPCJsonSerializer();
81
+ /**
82
+ * `serialize`/`deserialize` for a TanStack Query persister. API payloads carry
83
+ * `Date`s (and maybe `Map`s, `Set`s, `BigInt`s) that plain JSON returns as
84
+ * strings; oRPC's own serializer round-trips them.
85
+ *
86
+ * ```ts
87
+ * createAsyncStoragePersister({ storage: AsyncStorage, ...queryCacheSerializer })
88
+ * ```
89
+ */
90
+ export const queryCacheSerializer = {
91
+ serialize(value) {
92
+ const [json, meta] = cacheSerializer.serialize(value);
93
+ return JSON.stringify({ json, meta });
94
+ },
95
+ deserialize(text) {
96
+ const { json, meta } = JSON.parse(text);
97
+ return cacheSerializer.deserialize(json, meta);
98
+ }
99
+ };
51
100
  //# sourceMappingURL=client.js.map
@@ -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;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"]}
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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","sourcesContent":["import { type ClientContext, ORPCError, type ORPCErrorCode } from '@orpc/client'\nimport { RPCLink, type RPCLinkOptions } from '@orpc/client/fetch'\nimport { BatchLinkPlugin } from '@orpc/client/plugins'\nimport { StandardRPCJsonSerializer } from '@orpc/client/standard'\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\n/**\n * The server's message, only when the backend marked it user-safe by putting\n * a `userMessage` string on the error's `data`. Route error messages are\n * developer text (English, internal model names), so they are not shown by\n * default; they stay on the error for logs and error tracking.\n *\n * ```ts\n * throw new ORPCError('BAD_REQUEST', {\n * message: 'Deal has no pipeline stage', // logs, telemetry\n * data: { userMessage: 'Choose a stage first.' } // the user reads this\n * })\n * ```\n */\nexport function userSafeServerMessage(error: unknown): string | null {\n\tif (!(error instanceof ORPCError)) return null\n\tconst data: unknown = error.data\n\tif (typeof data !== 'object' || data === null) return null\n\tconst userMessage = (data as { userMessage?: unknown }).userMessage\n\treturn typeof userMessage === 'string' && userMessage.trim().length > 0\n\t\t? userMessage\n\t\t: null\n}\n\n/** User-facing text for a caught error: the opted-in server message, else your localized fallback. */\nexport function userFacingErrorMessage(\n\terror: unknown,\n\tfallback: string\n): string {\n\treturn userSafeServerMessage(error) ?? fallback\n}\n\nconst cacheSerializer = new StandardRPCJsonSerializer()\n\n/**\n * `serialize`/`deserialize` for a TanStack Query persister. API payloads carry\n * `Date`s (and maybe `Map`s, `Set`s, `BigInt`s) that plain JSON returns as\n * strings; oRPC's own serializer round-trips them.\n *\n * ```ts\n * createAsyncStoragePersister({ storage: AsyncStorage, ...queryCacheSerializer })\n * ```\n */\nexport const queryCacheSerializer = {\n\tserialize(value: unknown): string {\n\t\tconst [json, meta] = cacheSerializer.serialize(value)\n\t\treturn JSON.stringify({ json, meta })\n\t},\n\tdeserialize<T>(text: string): T {\n\t\tconst { json, meta } = JSON.parse(text) as {\n\t\t\tjson: unknown\n\t\t\tmeta: Parameters<typeof cacheSerializer.deserialize>[1]\n\t\t}\n\t\treturn cacheSerializer.deserialize(json, meta) as T\n\t}\n}\n"]}
@@ -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":"AAQA,OAAO,EAAE,KAAK,SAAS,EAAmB,MAAM,iBAAiB,CAAA;AAEjE,OAAO,EAAgB,KAAK,MAAM,EAAE,MAAM,mBAAmB,CAAA;AAC7D,OAAO,EACN,KAAK,eAAe,EACpB,KAAK,YAAY,EAEjB,KAAK,oBAAoB,EACzB,MAAM,mBAAmB,CAAA;AAC1B,OAAO,EAGN,KAAK,QAAQ,EACb,KAAK,aAAa,EAClB,MAAM,aAAa,CAAA;AACpB,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AACtC,OAAO,EACN,KAAK,cAAc,EAInB,KAAK,WAAW,EAEhB,KAAK,MAAM,EACX,MAAM,WAAW,CAAA;AAElB,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAC1C,OAAO,EACN,KAAK,mBAAmB,EACxB,KAAK,kBAAkB,EACvB,KAAK,gBAAgB,EACrB,KAAK,WAAW,EAChB,KAAK,YAAY,EACjB,KAAK,iBAAiB,EACtB,KAAK,EAAE,EAEP,KAAK,YAAY,EACjB,KAAK,KAAK,EACV,KAAK,WAAW,EAChB,KAAK,YAAY,EACjB,KAAK,UAAU,EAEf,KAAK,iBAAiB,EACtB,MAAM,YAAY,CAAA;AA4BnB,MAAM,MAAM,eAAe,CAC1B,WAAW,SAAS,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,EAC/C,QAAQ,SAAS,MAAM,WAAW,GAAG,MAAM,EAC3C,OAAO,SAAS,MAAM,EACtB,OAAO,EACP,KAAK,SAAS,MAAM,EACpB,IAAI,SAAS,MAAM,EACnB,KAAK,SAAS,WAAW,GAAG,SAAS,EACrC,OAAO,SAAS,QAAQ,EACxB,OAAO,SAAS,OAAO,CAAC,MAAM,CAAC,MAAM,WAAW,EAAE,MAAM,CAAC,CAAC,GAAG,MAAM,CAClE,KAAK,EACL,KAAK,CACL,IACE;IACH,qFAAqF;IACrF,UAAU,EAAE,WAAW,CAAA;IACvB;;;OAGG;IACH,OAAO,CAAC,EAAE,QAAQ,CAAA;IAClB,wEAAwE;IACxE,MAAM,CAAC,EAAE,CACR,MAAM,EAAE,mBAAmB,CAC1B,WAAW,EACX;QACC,IAAI,EAAE,MAAM,CAAC,KAAK,CAAC,GAAG,SAAS,CAAA;QAC/B,MAAM,EAAE,WAAW,GAAG,SAAS,CAAA;QAC/B,IAAI,EAAE,MAAM,CAAA;KACZ,CACD,KACG,YAAY,CAAC,OAAO,CAAC,CAAA;IAC1B,iBAAiB,CAAC,EAAE;SAClB,CAAC,IAAI,MAAM,OAAO,GAAG,MAAM,WAAW,GAAG,CAAC,MAAM,EAAE;YAClD,OAAO,EAAE,gBAAgB,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAA;YACzC,IAAI,EAAE,MAAM,CAAC,KAAK,CAAC,GAAG,SAAS,CAAA;YAC/B,MAAM,EAAE,WAAW,GAAG,SAAS,CAAA;YAC/B,IAAI,EAAE,MAAM,CAAA;YACZ,SAAS,EAAE,CAAC,CAAA;SACZ,KAAK,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,iBAAiB,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;KACvE,CAAA;IACD;;;OAGG;IACH,MAAM,CAAC,EAAE,OAAO,GACf,MAAM,CACL,MAAM,EACN,KAAK,CACJ,KAAK,EACL,mBAAmB,CAClB,WAAW,EACX,IAAI,CAAC,WAAW,CAAC,OAAO,EAAE,KAAK,CAAC,EAAE,SAAS,GAAG,WAAW,CAAC,CAC1D,CACD,CACD,GACD,UAAU,CACT,OAAO,CAAC,OAAO,CAAC,EAChB,iBAAiB,EACjB,4CAA4C,CAC5C,CAAA;IACF;;;OAGG;IACH,IAAI,CAAC,EAAE,KAAK,CAAA;IACZ,4DAA4D;IAC5D,IAAI,CAAC,EAAE,SAAS,IAAI,EAAE,CAAA;IACtB,yEAAyE;IACzE,IAAI,CAAC,EAAE,KAAK,CAAA;IACZ,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,KAAK,CAAC,GAAG,SAAS,KAAK,OAAO,CAAA;IACpE,oEAAoE;IACpE,cAAc,CAAC,EAAE,CAChB,MAAM,EAAE,mBAAmB,CAC1B,WAAW,EACX;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,OAAO,CAAC,KAAK,CAAC,CAAA;KAAE,CACtC,KACG,MAAM,CAAC,MAAM,EAAE,cAAc,GAAG,SAAS,CAAC,CAAA;IAC/C,uGAAuG;IACvG,WAAW,CAAC,EAAE,CACb,KAAK,EAAE,kBAAkB,CAAC,WAAW,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,KAEjD,aAAa,GAAG,SAAS,GAAG,IAAI,CAAA;IACrC,sGAAsG;IACtG,eAAe,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,OAAO,CAAA;IAC7C,8CAA8C;IAC9C,MAAM,CAAC,EAAE,oBAAoB,CAAA;CAC7B,CAAA;AAED,KAAK,UAAU,CACd,WAAW,SAAS,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,EAC/C,QAAQ,SAAS,MAAM,EACvB,OAAO,SAAS,MAAM,EACtB,OAAO,EACP,KAAK,SAAS,MAAM,EACpB,IAAI,SAAS,MAAM,EACnB,KAAK,EACL,OAAO,SAAS,QAAQ,EACxB,OAAO,SAAS,OAAO,CAAC,MAAM,CAAC,MAAM,WAAW,EAAE,MAAM,CAAC,CAAC,GAAG,MAAM,CAClE,KAAK,EACL,KAAK,CACL,IACE;IACH,UAAU,EAAE,WAAW,CAAA;IACvB,OAAO,EAAE,QAAQ,CAAA;IACjB,MAAM,EAAE,OAAO,CAAA;IACf,iBAAiB,EAAE,OAAO,CAAA;IAC1B,MAAM,EAAE,OAAO,CAAA;IACf,IAAI,EAAE,KAAK,CAAA;IACX,GAAG,EAAE,IAAI,CAAA;IACT,IAAI,EAAE,MAAM,CAAC,KAAK,CAAC,CAAA;IACnB,MAAM,EAAE,OAAO,CAAA;CACf,CAAA;AAED,MAAM,MAAM,SAAS,CAAC,IAAI,SAAS,YAAY,IAAI;IAClD,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,CAAA;IACZ,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,CAAA;IACpB,YAAY,EAAE,YAAY,CAAC,IAAI,CAAC,CAAA;IAChC,eAAe,EAAE,eAAe,CAAA;IAChC,YAAY,EAAE,OAAO,YAAY,CAAA;IACjC,QAAQ,EAAE,OAAO,UAAU,CAAA;IAC3B;;;OAGG;IACH,UAAU,EAAE,CAAC,QAAQ,EACpB,OAAO,EAAE,QAAQ,EACjB,MAAM,CAAC,EAAE,WAAW,KAChB,SAAS,CAAC,QAAQ,CAAC,CAAA;IACxB,8EAA8E;IAC9E,QAAQ,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;IAC7B,sBAAsB,EAAE,MAAM,MAAM,CAAA;IACpC,2BAA2B,EAAE,MAAM,MAAM,CAAA;CACzC,CAAA;AAED;;;GAGG;AACH,wBAAgB,QAAQ,CACvB,KAAK,CAAC,WAAW,SAAS,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,EACrD,QAAQ,SAAS,MAAM,WAAW,GAAG,MAAM,GAAG,KAAK,EACnD,OAAO,SAAS,MAAM,GAAG,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,EAC7C,OAAO,SAAS,MAAM,GAAG,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,EAC7C,KAAK,SAAS,MAAM,GAAG,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,EAC3C,KAAK,CAAC,IAAI,SAAS,MAAM,GAAG,MAAM,EAClC,KAAK,SAAS,WAAW,GAAG,SAAS,GAAG,SAAS,EACjD,OAAO,SAAS,QAAQ,GAAG,QAAQ,EACnC,OAAO,SAAS,OAAO,CAAC,MAAM,CAAC,MAAM,WAAW,EAAE,MAAM,CAAC,CAAC,GAAG,MAAM,CAClE,KAAK,EACL,KAAK,CACL,EAED,OAAO,EAAE,eAAe,CACvB,WAAW,EACX,QAAQ,EACR,OAAO,EACP,OAAO,EACP,KAAK,EACL,IAAI,EACJ,KAAK,EACL,OAAO,EACP,OAAO,CACP,GACA,YAAY,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,GAC7B,SAAS,CACX,UAAU,CACT,WAAW,EACX,QAAQ,EACR,OAAO,EACP,OAAO,EACP,KAAK,EACL,IAAI,EACJ,KAAK,EACL,OAAO,EACP,OAAO,CACP,CACD,CAwTA"}
package/dist/create-fn.js CHANGED
@@ -259,7 +259,6 @@ export function createFn(options) {
259
259
  fnLive: createFnLive({
260
260
  fn,
261
261
  createChannel: live.createChannel,
262
- createLogger,
263
262
  isGuard
264
263
  }),
265
264
  createPubSub: live.createPubSub,
@@ -1 +1 @@
1
- {"version":3,"file":"create-fn.js","sourceRoot":"","sources":["../src/create-fn.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n\ttype BuilderChain,\n\tcreateProcedureAssembler\n} from './assemble-procedure.js'\nimport { isAsyncIteratorObject } from './stream.js'\nimport { normalizeRoute } from './route-options.js'\nimport { type AnyProcedure, ORPCError, os } from '@orpc/server'\nimport { procedureDefinition } from './compatibility.js'\nimport { type BoundCall, createBoundCall } from './bound-call.js'\nimport { isExpectedClientError } from './expected-client-error.js'\nimport { createFnLive, type FnLive } from './live/fn-live.js'\nimport {\n\ttype CreatePublisher,\n\ttype CreatePubSub,\n\tcreateLiveRuntime,\n\ttype PubSubRuntimeOptions\n} from './live/pub-sub.js'\nimport {\n\tcreateDefaultLogger,\n\tprotectLogger,\n\ttype FnLogger,\n\ttype LogAttributes\n} from './logger.js'\nimport { readFnMeta } from './meta.js'\nimport {\n\ttype AttributeValue,\n\tcreateTracing,\n\terrorAttributes,\n\terrorMessageOf,\n\ttype OtelApiLike,\n\ttype SpanLike,\n\ttype SpanOf\n} from './otel.js'\nimport { RAW_INPUT, REQUEST_TIMING, type InvocationTiming } from './timing.js'\nimport { createRouter } from './router.js'\nimport {\n\ttype ProcedureHookParams,\n\ttype CompletedHookEvent,\n\ttype CurrentContextOf,\n\ttype BuilderLike,\n\ttype FiniteExtras,\n\ttype ScopedExtrasGuard,\n\ttype Fn,\n\ttype FnCompletedEvent,\n\ttype FnDefinition,\n\ttype Guard,\n\ttype GuardParams,\n\ttype MaybePromise,\n\ttype RejectKeys,\n\tRESERVED_OPTION_KEYS,\n\ttype ReservedOptionKey\n} from './types.js'\n\n/** `CreateFnOptions` with the generics erased: what the implementation reads. */\ntype RuntimeOptions = {\n\tprocedures: Record<string, BuilderChain>\n\tdefault?: string\n\textras?: (params: Record<string, unknown>) => unknown\n\textrasByProcedure?: Record<\n\t\tstring,\n\t\t(params: Record<string, unknown>) => unknown\n\t>\n\tguards?: Record<\n\t\tstring,\n\t\t(value: unknown, params: GuardParams<unknown, unknown>) => unknown\n\t>\n\totel?: OtelApiLike\n\tlogger?: (scope: string, span: SpanLike | undefined) => FnLogger\n\tspanAttributes?: (params: {\n\t\tcontext: unknown\n\t\tname: string\n\t\tprocedure: string\n\t\tmeta: Record<string, unknown>\n\t}) => Record<string, AttributeValue | undefined>\n\tonCompleted?: (event: FnCompletedEvent) => LogAttributes | undefined\n\tisExpectedError?: (error: unknown) => boolean\n\tpubsub?: PubSubRuntimeOptions\n}\n\nexport type CreateFnOptions<\n\tTProcedures extends Record<string, BuilderLike>,\n\tTDefault extends keyof TProcedures & string,\n\tTExtras extends object,\n\tTGuards,\n\tTMeta extends object,\n\tTTag extends string,\n\tTOtel extends OtelApiLike | undefined,\n\tTLogger extends FnLogger,\n\tTScoped extends Partial<Record<keyof TProcedures, object>> = Record<\n\t\tnever,\n\t\tnever\n\t>\n> = {\n\t/** Named oRPC builders, e.g. `{ public: os.$context<Ctx>(), protected: authed }`. */\n\tprocedures: TProcedures\n\t/**\n\t * Builder used when a route omits `procedure`. Leave it out to make every\n\t * route name its procedure, so none gets one by accident.\n\t */\n\tdefault?: TDefault\n\t/** Per-call values merged into every handler's params; may be async. */\n\textras?: (\n\t\tparams: ProcedureHookParams<\n\t\t\tTProcedures,\n\t\t\t{\n\t\t\t\tspan: SpanOf<TOtel> | undefined\n\t\t\t\tsignal: AbortSignal | undefined\n\t\t\t\tname: string\n\t\t\t}\n\t\t>\n\t) => MaybePromise<TExtras>\n\textrasByProcedure?: {\n\t\t[K in keyof TScoped & keyof TProcedures]: (params: {\n\t\t\tcontext: CurrentContextOf<TProcedures[K]>\n\t\t\tspan: SpanOf<TOtel> | undefined\n\t\t\tsignal: AbortSignal | undefined\n\t\t\tname: string\n\t\t\tprocedure: K\n\t\t}) => MaybePromise<TScoped[K] & ScopedExtrasGuard<NoInfer<TScoped[K]>>>\n\t}\n\t/**\n\t * Checks run before the handler; each key becomes a typed `fn()` option.\n\t * Keys must not reuse route options. False denies, true or void allows.\n\t */\n\tguards?: TGuards &\n\t\tRecord<\n\t\t\tstring,\n\t\t\tGuard<\n\t\t\t\tnever,\n\t\t\t\tProcedureHookParams<\n\t\t\t\t\tTProcedures,\n\t\t\t\t\tOmit<GuardParams<unknown, TMeta>, 'context' | 'procedure'>\n\t\t\t\t>\n\t\t\t>\n\t\t> &\n\t\tRejectKeys<\n\t\t\tNoInfer<TGuards>,\n\t\t\tReservedOptionKey,\n\t\t\t'orpc-fn: this guard name is a route option'\n\t\t>\n\t/**\n\t * Typed route metadata contract: `meta: defineMeta<AppMeta>()`.\n\t * Route declarations place values inside their own `meta` object.\n\t */\n\tmeta?: TMeta\n\t/** Allowed route tags: `tags: ['internal', 'external']`. */\n\ttags?: readonly TTag[]\n\t/** `import * as otel from '@opentelemetry/api'`. Omit for no tracing. */\n\totel?: TOtel\n\tlogger?: (scope: string, span: SpanOf<TOtel> | undefined) => TLogger\n\t/** Extra span attributes per call; undefined values are skipped. */\n\tspanAttributes?: (\n\t\tparams: ProcedureHookParams<\n\t\t\tTProcedures,\n\t\t\t{ name: string; meta: Partial<TMeta> }\n\t\t>\n\t) => Record<string, AttributeValue | undefined>\n\t/** Called after the procedure (or stream) settles; returned attributes join the `fn.completed` log. */\n\tonCompleted?: (\n\t\tevent: CompletedHookEvent<TProcedures, SpanOf<TOtel>>\n\t\t// biome-ignore lint/suspicious/noConfusingVoidType: lets hooks that return nothing type-check\n\t) => LogAttributes | undefined | void\n\t/** Errors that are the caller's fault, logged at `warn`. Default: 4xx `ORPCError` or `AbortError`. */\n\tisExpectedError?: (error: unknown) => boolean\n\t/** Needed for `fnLive` and `createPubSub`. */\n\tpubsub?: PubSubRuntimeOptions\n}\n\ntype Definition<\n\tTProcedures extends Record<string, BuilderLike>,\n\tTDefault extends string,\n\tTExtras extends object,\n\tTGuards,\n\tTMeta extends object,\n\tTTag extends string,\n\tTOtel,\n\tTLogger extends FnLogger,\n\tTScoped extends Partial<Record<keyof TProcedures, object>> = Record<\n\t\tnever,\n\t\tnever\n\t>\n> = {\n\tprocedures: TProcedures\n\tdefault: TDefault\n\textras: TExtras\n\textrasByProcedure: TScoped\n\tguards: TGuards\n\tmeta: TMeta\n\ttag: TTag\n\tspan: SpanOf<TOtel>\n\tlogger: TLogger\n}\n\nexport type FnFactory<TDef extends FnDefinition> = {\n\tfn: Fn<TDef>\n\tfnLive: FnLive<TDef>\n\tcreatePubSub: CreatePubSub<TDef>\n\tcreatePublisher: CreatePublisher\n\tcreateRouter: typeof createRouter\n\treadMeta: typeof readFnMeta\n\t/**\n\t * A `call` outside any handler (seeders, scripts, tests), traced with this\n\t * instance's OpenTelemetry.\n\t */\n\tcreateCall: <TContext>(\n\t\tcontext: TContext,\n\t\tsignal?: AbortSignal\n\t) => BoundCall<TContext>\n\t/** Terminal, idempotent shutdown: close streams and await owned resources. */\n\tshutdown: () => Promise<void>\n\tdrainPubSubSubscribers: () => number\n\tactivePubSubSubscriberCount: () => number\n}\n\n/**\n * Builds the app's `fn` and friends once. Everything app-specific (auth,\n * context, database, queues, i18n, permissions) is injected here.\n */\nexport function createFn<\n\tconst TProcedures extends Record<string, BuilderLike>,\n\tTDefault extends keyof TProcedures & string = never,\n\tTExtras extends object = Record<never, never>,\n\tTGuards extends object = Record<never, never>,\n\tTMeta extends object = Record<never, never>,\n\tconst TTag extends string = string,\n\tTOtel extends OtelApiLike | undefined = undefined,\n\tTLogger extends FnLogger = FnLogger,\n\tTScoped extends Partial<Record<keyof TProcedures, object>> = Record<\n\t\tnever,\n\t\tnever\n\t>\n>(\n\toptions: CreateFnOptions<\n\t\tTProcedures,\n\t\tTDefault,\n\t\tTExtras,\n\t\tTGuards,\n\t\tTMeta,\n\t\tTTag,\n\t\tTOtel,\n\t\tTLogger,\n\t\tTScoped\n\t> &\n\t\tFiniteExtras<NoInfer<TExtras>>\n): FnFactory<\n\tDefinition<\n\t\tTProcedures,\n\t\tTDefault,\n\t\tTExtras,\n\t\tTGuards,\n\t\tTMeta,\n\t\tTTag,\n\t\tTOtel,\n\t\tTLogger,\n\t\tTScoped\n\t>\n> {\n\tconst runtime = options as unknown as RuntimeOptions\n\tconst tracing = createTracing(runtime.otel)\n\tconst defaultLogger = protectLogger(createDefaultLogger('fn'))\n\tconst createLogger = (\n\t\tscope: string,\n\t\tspan: SpanLike | undefined\n\t): FnLogger => {\n\t\ttry {\n\t\t\treturn protectLogger(\n\t\t\t\truntime.logger?.(scope, span) ??\n\t\t\t\t\t(scope === 'fn' ? defaultLogger : createDefaultLogger(scope))\n\t\t\t)\n\t\t} catch {\n\t\t\treturn defaultLogger\n\t\t}\n\t}\n\tconst isExpectedError = runtime.isExpectedError ?? isExpectedClientError\n\tconst guards = runtime.guards ?? {}\n\tconst isGuard = (option: string) => Object.hasOwn(guards, option)\n\tfor (const guard of Object.keys(guards)) {\n\t\tif (typeof guards[guard] !== 'function')\n\t\t\tthrow new TypeError(`orpc-fn: guard ${guard} must be a function`)\n\t\tif ((RESERVED_OPTION_KEYS as readonly string[]).includes(guard)) {\n\t\t\tthrow new Error(\n\t\t\t\t`orpc-fn: guard \"${guard}\" reuses a route option name; rename it`\n\t\t\t)\n\t\t}\n\t}\n\tif (runtime.default && !Object.hasOwn(runtime.procedures, runtime.default))\n\t\tthrow new TypeError(`orpc-fn: unknown default procedure ${runtime.default}`)\n\tfor (const [key, builder] of Object.entries(runtime.procedures)) {\n\t\tconst def = procedureDefinition(builder)\n\t\tif (def?.inputSchema !== undefined || def?.outputSchema !== undefined) {\n\t\t\tthrow new Error(\n\t\t\t\t`orpc-fn: procedure \"${key}\" sets an input or output schema; set schemas on routes instead`\n\t\t\t)\n\t\t}\n\t}\n\n\tconst resolveKey = (procedure: string | undefined, name: string) => {\n\t\tconst key = procedure ?? runtime.default\n\t\tif (key === undefined) {\n\t\t\tthrow new Error(\n\t\t\t\t`orpc-fn: \"${name}\" needs a procedure; createFn has no default`\n\t\t\t)\n\t\t}\n\t\treturn key\n\t}\n\n\tconst buildProcedure = createProcedureAssembler(\n\t\truntime.procedures,\n\t\tresolveKey\n\t)\n\n\tconst invocation = Symbol('orpc-fn.invocation')\n\ttype Invocation = {\n\t\tspan: SpanLike | undefined\n\t\tlogger: FnLogger\n\t\tinput: unknown\n\t\tcontext: unknown\n\t\thandlerStarted: boolean\n\t\trawInput: unknown\n\t}\n\t// The overload-to-runtime boundary is adapted once at the returned factory.\n\tconst fn = (routeOptions: Record<string, unknown>): AnyProcedure => {\n\t\tconst {\n\t\t\thandler,\n\t\t\tinput,\n\t\t\toutput,\n\t\t\tname,\n\t\t\tprocedure,\n\t\t\tmeta,\n\t\t\tstream,\n\t\t\terrors,\n\t\t\tguardResolvers,\n\t\t\troute,\n\t\t\tguardChecks\n\t\t} = normalizeRoute(routeOptions, isGuard)\n\t\tconst key = resolveKey(procedure, name)\n\t\tconst built = buildProcedure({\n\t\t\tname,\n\t\t\tprocedure: key,\n\t\t\troute,\n\t\t\tmeta,\n\t\t\tinput,\n\t\t\toutput,\n\t\t\tstream,\n\t\t\t...(errors ? { errors } : {}),\n\t\t\thandler: async (params) => {\n\t\t\t\tconst { context, signal } = params\n\t\t\t\tconst state = context[invocation] as Invocation\n\t\t\t\tconst { [invocation]: _invocation, ...observedContext } = context\n\t\t\t\tstate.context = observedContext\n\t\t\t\tstate.input = params.input\n\t\t\t\tstate.handlerStarted = true\n\t\t\t\ttry {\n\t\t\t\t\tconst attributes = runtime.spanAttributes?.({\n\t\t\t\t\t\tcontext,\n\t\t\t\t\t\tname,\n\t\t\t\t\t\tprocedure: key,\n\t\t\t\t\t\tmeta\n\t\t\t\t\t})\n\t\t\t\t\tfor (const [attribute, value] of Object.entries(attributes ?? {}))\n\t\t\t\t\t\tif (value !== undefined) state.span?.setAttribute(attribute, value)\n\t\t\t\t} catch (error) {\n\t\t\t\t\tstate.logger.warn('spanAttributes hook failed', {\n\t\t\t\t\t\terror: errorMessageOf(error)\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t\tconst resolvedChecks = [...guardChecks]\n\t\t\t\tfor (const [guard, resolver] of Object.entries(guardResolvers)) {\n\t\t\t\t\tconst value = await resolver({ input: params.input, context, signal })\n\t\t\t\t\tif (value !== undefined) resolvedChecks.push([guard, value])\n\t\t\t\t}\n\t\t\t\tfor (const [guard, value] of resolvedChecks) {\n\t\t\t\t\tconst result = await guards[guard]?.(value, {\n\t\t\t\t\t\tcontext,\n\t\t\t\t\t\tinput: params.input,\n\t\t\t\t\t\tname,\n\t\t\t\t\t\tprocedure: key,\n\t\t\t\t\t\tmeta,\n\t\t\t\t\t\tsignal\n\t\t\t\t\t})\n\t\t\t\t\tif (result === false)\n\t\t\t\t\t\tthrow new ORPCError('FORBIDDEN', {\n\t\t\t\t\t\t\tmessage: `Guard \"${guard}\" denied this call`\n\t\t\t\t\t\t})\n\t\t\t\t\tif (result !== undefined && result !== true)\n\t\t\t\t\t\tthrow new TypeError(\n\t\t\t\t\t\t\t`orpc-fn: guard \"${guard}\" must return void or boolean`\n\t\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t\tconst extraParams = {\n\t\t\t\t\tcontext,\n\t\t\t\t\tspan: state.span,\n\t\t\t\t\tsignal,\n\t\t\t\t\tname,\n\t\t\t\t\tprocedure: key\n\t\t\t\t}\n\t\t\t\tconst shared = await runtime.extras?.(extraParams)\n\t\t\t\tconst scoped = await runtime.extrasByProcedure?.[key]?.(extraParams)\n\t\t\t\tconst extras = {\n\t\t\t\t\t...(shared as object | undefined),\n\t\t\t\t\t...(scoped as object | undefined)\n\t\t\t\t}\n\t\t\t\tif (extras && typeof extras === 'object') {\n\t\t\t\t\tfor (const reserved of [\n\t\t\t\t\t\t'input',\n\t\t\t\t\t\t'context',\n\t\t\t\t\t\t'call',\n\t\t\t\t\t\t'signal',\n\t\t\t\t\t\t'span',\n\t\t\t\t\t\t'logger',\n\t\t\t\t\t\t'errors',\n\t\t\t\t\t\t'lastEventId'\n\t\t\t\t\t]) {\n\t\t\t\t\t\tif (Object.hasOwn(extras, reserved))\n\t\t\t\t\t\t\tthrow new TypeError(\n\t\t\t\t\t\t\t\t`orpc-fn: extra \"${reserved}\" shadows a handler parameter`\n\t\t\t\t\t\t\t)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn handler({\n\t\t\t\t\t...(extras as object | undefined),\n\t\t\t\t\tinput: params.input,\n\t\t\t\t\tcontext,\n\t\t\t\t\tcall: createBoundCall(context, signal, tracing),\n\t\t\t\t\tsignal,\n\t\t\t\t\tspan: state.span,\n\t\t\t\t\tlogger: state.logger,\n\t\t\t\t\terrors: params.errors,\n\t\t\t\t\tlastEventId: params.lastEventId,\n\t\t\t\t\t[RAW_INPUT]: state.rawInput\n\t\t\t\t})\n\t\t\t}\n\t\t})\n\t\t// Prepending middleware shifts oRPC's validation indexes, covering auth,\n\t\t// input validation, output validation, and the final stream lifetime.\n\t\treturn os\n\t\t\t.use(async ({ context, next }, rawInput) => {\n\t\t\t\tconst started = performance.now()\n\t\t\t\tconst state: Invocation = {\n\t\t\t\t\tspan: undefined,\n\t\t\t\t\tlogger: defaultLogger,\n\t\t\t\t\tinput: undefined,\n\t\t\t\t\tcontext,\n\t\t\t\t\thandlerStarted: false,\n\t\t\t\t\trawInput\n\t\t\t\t}\n\t\t\t\tconst result = await tracing.inSpan(\n\t\t\t\t\tname,\n\t\t\t\t\t'SERVER',\n\t\t\t\t\tasync (span) => {\n\t\t\t\t\t\tstate.span = span\n\t\t\t\t\t\tstate.logger = createLogger('fn', span)\n\t\t\t\t\t\tspan?.setAttribute('fn.operation', name)\n\t\t\t\t\t\tspan?.setAttribute('fn.procedure', key)\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tconst result = await next({ context: { [invocation]: state } })\n\t\t\t\t\t\t\tif (isAsyncIteratorObject(result.output) !== stream) {\n\t\t\t\t\t\t\t\tif (isAsyncIteratorObject(result.output)) {\n\t\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\t\tawait result.output.return?.()\n\t\t\t\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t\t\t\t/* Release the unexpected stream. */\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\tthrow new TypeError(\n\t\t\t\t\t\t\t\t\t`orpc-fn: ${name} returned a result inconsistent with stream; declare stream: true for iterators`\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn result.output\n\t\t\t\t\t\t} finally {\n\t\t\t\t\t\t\tconst timing = (context as Record<symbol, unknown>)[\n\t\t\t\t\t\t\t\tREQUEST_TIMING\n\t\t\t\t\t\t\t] as InvocationTiming | undefined\n\t\t\t\t\t\t\tif (timing && !(context as Record<symbol, unknown>)[invocation]) {\n\t\t\t\t\t\t\t\ttiming.procedureMs += performance.now() - started\n\t\t\t\t\t\t\t\ttiming.calls++\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t(span, ...error) => {\n\t\t\t\t\t\tconst durationMs =\n\t\t\t\t\t\t\tMath.round((performance.now() - started) * 100) / 100\n\t\t\t\t\t\tspan?.setAttribute('fn.duration_ms', durationMs)\n\t\t\t\t\t\tlogCompleted(state.logger, {\n\t\t\t\t\t\t\tname,\n\t\t\t\t\t\t\tprocedure: key,\n\t\t\t\t\t\t\tdurationMs,\n\t\t\t\t\t\t\tsuccess: error.length === 0,\n\t\t\t\t\t\t\terror: error[0],\n\t\t\t\t\t\t\tinput: state.input,\n\t\t\t\t\t\t\tcontext: state.context,\n\t\t\t\t\t\t\tspan,\n\t\t\t\t\t\t\tmeta,\n\t\t\t\t\t\t\thandlerStarted: state.handlerStarted\n\t\t\t\t\t\t})\n\t\t\t\t\t}\n\t\t\t\t)\n\t\t\t\treturn { output: result, context }\n\t\t\t})\n\t\t\t.router({ route: built }).route\n\t}\n\n\tconst logCompleted = (logger: FnLogger, event: FnCompletedEvent) => {\n\t\tconst { error, success } = event\n\t\tlet extra: LogAttributes | undefined\n\t\ttry {\n\t\t\textra = runtime.onCompleted?.(event)\n\t\t} catch (hookError) {\n\t\t\tlogger.warn('onCompleted hook failed', {\n\t\t\t\terror: errorMessageOf(hookError)\n\t\t\t})\n\t\t}\n\t\tlet expected = false\n\t\ttry {\n\t\t\texpected = isExpectedError(error)\n\t\t} catch {\n\t\t\texpected = isExpectedClientError(error)\n\t\t}\n\t\tconst level = success ? 'info' : expected ? 'warn' : 'error'\n\t\tlogger[level]('fn.completed', {\n\t\t\t...extra,\n\t\t\tevent: 'fn.completed',\n\t\t\toperation: event.name,\n\t\t\tprocedure: event.procedure,\n\t\t\tduration_ms: event.durationMs,\n\t\t\tstatus: success ? 'success' : 'failed',\n\t\t\t...(error === undefined ? {} : errorAttributes(error))\n\t\t})\n\t}\n\n\tconst live = createLiveRuntime({\n\t\tfn,\n\t\ttracing,\n\t\tcreateLogger,\n\t\tpubsub: runtime.pubsub\n\t})\n\n\t// The runtimes are untyped; `Fn`, `FnLive`, `CreatePubSub` and\n\t// `CreatePublisher` are their typed surface.\n\treturn {\n\t\tfn,\n\t\tfnLive: createFnLive({\n\t\t\tfn,\n\t\t\tcreateChannel: live.createChannel,\n\t\t\tcreateLogger,\n\t\t\tisGuard\n\t\t}),\n\t\tcreatePubSub: live.createPubSub,\n\t\tcreatePublisher: live.createPublisher,\n\t\tcreateRouter,\n\t\treadMeta: readFnMeta,\n\t\tcreateCall: <TContext>(context: TContext, signal?: AbortSignal) =>\n\t\t\tcreateBoundCall(context, signal, tracing),\n\t\tshutdown: live.shutdown,\n\t\tdrainPubSubSubscribers: live.drainPubSubSubscribers,\n\t\tactivePubSubSubscriberCount: live.activePubSubSubscriberCount\n\t} as unknown as FnFactory<\n\t\tDefinition<\n\t\t\tTProcedures,\n\t\t\tTDefault,\n\t\t\tTExtras,\n\t\t\tTGuards,\n\t\t\tTMeta,\n\t\t\tTTag,\n\t\t\tTOtel,\n\t\t\tTLogger,\n\t\t\tTScoped\n\t\t>\n\t>\n}\n"]}
1
+ {"version":3,"file":"create-fn.js","sourceRoot":"","sources":["../src/create-fn.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n\ttype BuilderChain,\n\tcreateProcedureAssembler\n} from './assemble-procedure.js'\nimport { isAsyncIteratorObject } from './stream.js'\nimport { normalizeRoute } from './route-options.js'\nimport { type AnyProcedure, ORPCError, os } from '@orpc/server'\nimport { procedureDefinition } from './compatibility.js'\nimport { type BoundCall, createBoundCall } from './bound-call.js'\nimport { isExpectedClientError } from './expected-client-error.js'\nimport { createFnLive, type FnLive } from './live/fn-live.js'\nimport {\n\ttype CreatePublisher,\n\ttype CreatePubSub,\n\tcreateLiveRuntime,\n\ttype PubSubRuntimeOptions\n} from './live/pub-sub.js'\nimport {\n\tcreateDefaultLogger,\n\tprotectLogger,\n\ttype FnLogger,\n\ttype LogAttributes\n} from './logger.js'\nimport { readFnMeta } from './meta.js'\nimport {\n\ttype AttributeValue,\n\tcreateTracing,\n\terrorAttributes,\n\terrorMessageOf,\n\ttype OtelApiLike,\n\ttype SpanLike,\n\ttype SpanOf\n} from './otel.js'\nimport { RAW_INPUT, REQUEST_TIMING, type InvocationTiming } from './timing.js'\nimport { createRouter } from './router.js'\nimport {\n\ttype ProcedureHookParams,\n\ttype CompletedHookEvent,\n\ttype CurrentContextOf,\n\ttype BuilderLike,\n\ttype FiniteExtras,\n\ttype ScopedExtrasGuard,\n\ttype Fn,\n\ttype FnCompletedEvent,\n\ttype FnDefinition,\n\ttype Guard,\n\ttype GuardParams,\n\ttype MaybePromise,\n\ttype RejectKeys,\n\tRESERVED_OPTION_KEYS,\n\ttype ReservedOptionKey\n} from './types.js'\n\n/** `CreateFnOptions` with the generics erased: what the implementation reads. */\ntype RuntimeOptions = {\n\tprocedures: Record<string, BuilderChain>\n\tdefault?: string\n\textras?: (params: Record<string, unknown>) => unknown\n\textrasByProcedure?: Record<\n\t\tstring,\n\t\t(params: Record<string, unknown>) => unknown\n\t>\n\tguards?: Record<\n\t\tstring,\n\t\t(value: unknown, params: GuardParams<unknown, unknown>) => unknown\n\t>\n\totel?: OtelApiLike\n\tlogger?: (scope: string, span: SpanLike | undefined) => FnLogger\n\tspanAttributes?: (params: {\n\t\tcontext: unknown\n\t\tname: string\n\t\tprocedure: string\n\t\tmeta: Record<string, unknown>\n\t}) => Record<string, AttributeValue | undefined>\n\tonCompleted?: (event: FnCompletedEvent) => LogAttributes | undefined\n\tisExpectedError?: (error: unknown) => boolean\n\tpubsub?: PubSubRuntimeOptions\n}\n\nexport type CreateFnOptions<\n\tTProcedures extends Record<string, BuilderLike>,\n\tTDefault extends keyof TProcedures & string,\n\tTExtras extends object,\n\tTGuards,\n\tTMeta extends object,\n\tTTag extends string,\n\tTOtel extends OtelApiLike | undefined,\n\tTLogger extends FnLogger,\n\tTScoped extends Partial<Record<keyof TProcedures, object>> = Record<\n\t\tnever,\n\t\tnever\n\t>\n> = {\n\t/** Named oRPC builders, e.g. `{ public: os.$context<Ctx>(), protected: authed }`. */\n\tprocedures: TProcedures\n\t/**\n\t * Builder used when a route omits `procedure`. Leave it out to make every\n\t * route name its procedure, so none gets one by accident.\n\t */\n\tdefault?: TDefault\n\t/** Per-call values merged into every handler's params; may be async. */\n\textras?: (\n\t\tparams: ProcedureHookParams<\n\t\t\tTProcedures,\n\t\t\t{\n\t\t\t\tspan: SpanOf<TOtel> | undefined\n\t\t\t\tsignal: AbortSignal | undefined\n\t\t\t\tname: string\n\t\t\t}\n\t\t>\n\t) => MaybePromise<TExtras>\n\textrasByProcedure?: {\n\t\t[K in keyof TScoped & keyof TProcedures]: (params: {\n\t\t\tcontext: CurrentContextOf<TProcedures[K]>\n\t\t\tspan: SpanOf<TOtel> | undefined\n\t\t\tsignal: AbortSignal | undefined\n\t\t\tname: string\n\t\t\tprocedure: K\n\t\t}) => MaybePromise<TScoped[K] & ScopedExtrasGuard<NoInfer<TScoped[K]>>>\n\t}\n\t/**\n\t * Checks run before the handler; each key becomes a typed `fn()` option.\n\t * Keys must not reuse route options. False denies, true or void allows.\n\t */\n\tguards?: TGuards &\n\t\tRecord<\n\t\t\tstring,\n\t\t\tGuard<\n\t\t\t\tnever,\n\t\t\t\tProcedureHookParams<\n\t\t\t\t\tTProcedures,\n\t\t\t\t\tOmit<GuardParams<unknown, TMeta>, 'context' | 'procedure'>\n\t\t\t\t>\n\t\t\t>\n\t\t> &\n\t\tRejectKeys<\n\t\t\tNoInfer<TGuards>,\n\t\t\tReservedOptionKey,\n\t\t\t'orpc-fn: this guard name is a route option'\n\t\t>\n\t/**\n\t * Typed route metadata contract: `meta: defineMeta<AppMeta>()`.\n\t * Route declarations place values inside their own `meta` object.\n\t */\n\tmeta?: TMeta\n\t/** Allowed route tags: `tags: ['internal', 'external']`. */\n\ttags?: readonly TTag[]\n\t/** `import * as otel from '@opentelemetry/api'`. Omit for no tracing. */\n\totel?: TOtel\n\tlogger?: (scope: string, span: SpanOf<TOtel> | undefined) => TLogger\n\t/** Extra span attributes per call; undefined values are skipped. */\n\tspanAttributes?: (\n\t\tparams: ProcedureHookParams<\n\t\t\tTProcedures,\n\t\t\t{ name: string; meta: Partial<TMeta> }\n\t\t>\n\t) => Record<string, AttributeValue | undefined>\n\t/** Called after the procedure (or stream) settles; returned attributes join the `fn.completed` log. */\n\tonCompleted?: (\n\t\tevent: CompletedHookEvent<TProcedures, SpanOf<TOtel>>\n\t\t// biome-ignore lint/suspicious/noConfusingVoidType: lets hooks that return nothing type-check\n\t) => LogAttributes | undefined | void\n\t/** Errors that are the caller's fault, logged at `warn`. Default: 4xx `ORPCError` or `AbortError`. */\n\tisExpectedError?: (error: unknown) => boolean\n\t/** Needed for `fnLive` and `createPubSub`. */\n\tpubsub?: PubSubRuntimeOptions\n}\n\ntype Definition<\n\tTProcedures extends Record<string, BuilderLike>,\n\tTDefault extends string,\n\tTExtras extends object,\n\tTGuards,\n\tTMeta extends object,\n\tTTag extends string,\n\tTOtel,\n\tTLogger extends FnLogger,\n\tTScoped extends Partial<Record<keyof TProcedures, object>> = Record<\n\t\tnever,\n\t\tnever\n\t>\n> = {\n\tprocedures: TProcedures\n\tdefault: TDefault\n\textras: TExtras\n\textrasByProcedure: TScoped\n\tguards: TGuards\n\tmeta: TMeta\n\ttag: TTag\n\tspan: SpanOf<TOtel>\n\tlogger: TLogger\n}\n\nexport type FnFactory<TDef extends FnDefinition> = {\n\tfn: Fn<TDef>\n\tfnLive: FnLive<TDef>\n\tcreatePubSub: CreatePubSub<TDef>\n\tcreatePublisher: CreatePublisher\n\tcreateRouter: typeof createRouter\n\treadMeta: typeof readFnMeta\n\t/**\n\t * A `call` outside any handler (seeders, scripts, tests), traced with this\n\t * instance's OpenTelemetry.\n\t */\n\tcreateCall: <TContext>(\n\t\tcontext: TContext,\n\t\tsignal?: AbortSignal\n\t) => BoundCall<TContext>\n\t/** Terminal, idempotent shutdown: close streams and await owned resources. */\n\tshutdown: () => Promise<void>\n\tdrainPubSubSubscribers: () => number\n\tactivePubSubSubscriberCount: () => number\n}\n\n/**\n * Builds the app's `fn` and friends once. Everything app-specific (auth,\n * context, database, queues, i18n, permissions) is injected here.\n */\nexport function createFn<\n\tconst TProcedures extends Record<string, BuilderLike>,\n\tTDefault extends keyof TProcedures & string = never,\n\tTExtras extends object = Record<never, never>,\n\tTGuards extends object = Record<never, never>,\n\tTMeta extends object = Record<never, never>,\n\tconst TTag extends string = string,\n\tTOtel extends OtelApiLike | undefined = undefined,\n\tTLogger extends FnLogger = FnLogger,\n\tTScoped extends Partial<Record<keyof TProcedures, object>> = Record<\n\t\tnever,\n\t\tnever\n\t>\n>(\n\toptions: CreateFnOptions<\n\t\tTProcedures,\n\t\tTDefault,\n\t\tTExtras,\n\t\tTGuards,\n\t\tTMeta,\n\t\tTTag,\n\t\tTOtel,\n\t\tTLogger,\n\t\tTScoped\n\t> &\n\t\tFiniteExtras<NoInfer<TExtras>>\n): FnFactory<\n\tDefinition<\n\t\tTProcedures,\n\t\tTDefault,\n\t\tTExtras,\n\t\tTGuards,\n\t\tTMeta,\n\t\tTTag,\n\t\tTOtel,\n\t\tTLogger,\n\t\tTScoped\n\t>\n> {\n\tconst runtime = options as unknown as RuntimeOptions\n\tconst tracing = createTracing(runtime.otel)\n\tconst defaultLogger = protectLogger(createDefaultLogger('fn'))\n\tconst createLogger = (\n\t\tscope: string,\n\t\tspan: SpanLike | undefined\n\t): FnLogger => {\n\t\ttry {\n\t\t\treturn protectLogger(\n\t\t\t\truntime.logger?.(scope, span) ??\n\t\t\t\t\t(scope === 'fn' ? defaultLogger : createDefaultLogger(scope))\n\t\t\t)\n\t\t} catch {\n\t\t\treturn defaultLogger\n\t\t}\n\t}\n\tconst isExpectedError = runtime.isExpectedError ?? isExpectedClientError\n\tconst guards = runtime.guards ?? {}\n\tconst isGuard = (option: string) => Object.hasOwn(guards, option)\n\tfor (const guard of Object.keys(guards)) {\n\t\tif (typeof guards[guard] !== 'function')\n\t\t\tthrow new TypeError(`orpc-fn: guard ${guard} must be a function`)\n\t\tif ((RESERVED_OPTION_KEYS as readonly string[]).includes(guard)) {\n\t\t\tthrow new Error(\n\t\t\t\t`orpc-fn: guard \"${guard}\" reuses a route option name; rename it`\n\t\t\t)\n\t\t}\n\t}\n\tif (runtime.default && !Object.hasOwn(runtime.procedures, runtime.default))\n\t\tthrow new TypeError(`orpc-fn: unknown default procedure ${runtime.default}`)\n\tfor (const [key, builder] of Object.entries(runtime.procedures)) {\n\t\tconst def = procedureDefinition(builder)\n\t\tif (def?.inputSchema !== undefined || def?.outputSchema !== undefined) {\n\t\t\tthrow new Error(\n\t\t\t\t`orpc-fn: procedure \"${key}\" sets an input or output schema; set schemas on routes instead`\n\t\t\t)\n\t\t}\n\t}\n\n\tconst resolveKey = (procedure: string | undefined, name: string) => {\n\t\tconst key = procedure ?? runtime.default\n\t\tif (key === undefined) {\n\t\t\tthrow new Error(\n\t\t\t\t`orpc-fn: \"${name}\" needs a procedure; createFn has no default`\n\t\t\t)\n\t\t}\n\t\treturn key\n\t}\n\n\tconst buildProcedure = createProcedureAssembler(\n\t\truntime.procedures,\n\t\tresolveKey\n\t)\n\n\tconst invocation = Symbol('orpc-fn.invocation')\n\ttype Invocation = {\n\t\tspan: SpanLike | undefined\n\t\tlogger: FnLogger\n\t\tinput: unknown\n\t\tcontext: unknown\n\t\thandlerStarted: boolean\n\t\trawInput: unknown\n\t}\n\t// The overload-to-runtime boundary is adapted once at the returned factory.\n\tconst fn = (routeOptions: Record<string, unknown>): AnyProcedure => {\n\t\tconst {\n\t\t\thandler,\n\t\t\tinput,\n\t\t\toutput,\n\t\t\tname,\n\t\t\tprocedure,\n\t\t\tmeta,\n\t\t\tstream,\n\t\t\terrors,\n\t\t\tguardResolvers,\n\t\t\troute,\n\t\t\tguardChecks\n\t\t} = normalizeRoute(routeOptions, isGuard)\n\t\tconst key = resolveKey(procedure, name)\n\t\tconst built = buildProcedure({\n\t\t\tname,\n\t\t\tprocedure: key,\n\t\t\troute,\n\t\t\tmeta,\n\t\t\tinput,\n\t\t\toutput,\n\t\t\tstream,\n\t\t\t...(errors ? { errors } : {}),\n\t\t\thandler: async (params) => {\n\t\t\t\tconst { context, signal } = params\n\t\t\t\tconst state = context[invocation] as Invocation\n\t\t\t\tconst { [invocation]: _invocation, ...observedContext } = context\n\t\t\t\tstate.context = observedContext\n\t\t\t\tstate.input = params.input\n\t\t\t\tstate.handlerStarted = true\n\t\t\t\ttry {\n\t\t\t\t\tconst attributes = runtime.spanAttributes?.({\n\t\t\t\t\t\tcontext,\n\t\t\t\t\t\tname,\n\t\t\t\t\t\tprocedure: key,\n\t\t\t\t\t\tmeta\n\t\t\t\t\t})\n\t\t\t\t\tfor (const [attribute, value] of Object.entries(attributes ?? {}))\n\t\t\t\t\t\tif (value !== undefined) state.span?.setAttribute(attribute, value)\n\t\t\t\t} catch (error) {\n\t\t\t\t\tstate.logger.warn('spanAttributes hook failed', {\n\t\t\t\t\t\terror: errorMessageOf(error)\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t\tconst resolvedChecks = [...guardChecks]\n\t\t\t\tfor (const [guard, resolver] of Object.entries(guardResolvers)) {\n\t\t\t\t\tconst value = await resolver({ input: params.input, context, signal })\n\t\t\t\t\tif (value !== undefined) resolvedChecks.push([guard, value])\n\t\t\t\t}\n\t\t\t\tfor (const [guard, value] of resolvedChecks) {\n\t\t\t\t\tconst result = await guards[guard]?.(value, {\n\t\t\t\t\t\tcontext,\n\t\t\t\t\t\tinput: params.input,\n\t\t\t\t\t\tname,\n\t\t\t\t\t\tprocedure: key,\n\t\t\t\t\t\tmeta,\n\t\t\t\t\t\tsignal\n\t\t\t\t\t})\n\t\t\t\t\tif (result === false)\n\t\t\t\t\t\tthrow new ORPCError('FORBIDDEN', {\n\t\t\t\t\t\t\tmessage: `Guard \"${guard}\" denied this call`\n\t\t\t\t\t\t})\n\t\t\t\t\tif (result !== undefined && result !== true)\n\t\t\t\t\t\tthrow new TypeError(\n\t\t\t\t\t\t\t`orpc-fn: guard \"${guard}\" must return void or boolean`\n\t\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t\tconst extraParams = {\n\t\t\t\t\tcontext,\n\t\t\t\t\tspan: state.span,\n\t\t\t\t\tsignal,\n\t\t\t\t\tname,\n\t\t\t\t\tprocedure: key\n\t\t\t\t}\n\t\t\t\tconst shared = await runtime.extras?.(extraParams)\n\t\t\t\tconst scoped = await runtime.extrasByProcedure?.[key]?.(extraParams)\n\t\t\t\tconst extras = {\n\t\t\t\t\t...(shared as object | undefined),\n\t\t\t\t\t...(scoped as object | undefined)\n\t\t\t\t}\n\t\t\t\tif (extras && typeof extras === 'object') {\n\t\t\t\t\tfor (const reserved of [\n\t\t\t\t\t\t'input',\n\t\t\t\t\t\t'context',\n\t\t\t\t\t\t'call',\n\t\t\t\t\t\t'signal',\n\t\t\t\t\t\t'span',\n\t\t\t\t\t\t'logger',\n\t\t\t\t\t\t'errors',\n\t\t\t\t\t\t'lastEventId'\n\t\t\t\t\t]) {\n\t\t\t\t\t\tif (Object.hasOwn(extras, reserved))\n\t\t\t\t\t\t\tthrow new TypeError(\n\t\t\t\t\t\t\t\t`orpc-fn: extra \"${reserved}\" shadows a handler parameter`\n\t\t\t\t\t\t\t)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn handler({\n\t\t\t\t\t...(extras as object | undefined),\n\t\t\t\t\tinput: params.input,\n\t\t\t\t\tcontext,\n\t\t\t\t\tcall: createBoundCall(context, signal, tracing),\n\t\t\t\t\tsignal,\n\t\t\t\t\tspan: state.span,\n\t\t\t\t\tlogger: state.logger,\n\t\t\t\t\terrors: params.errors,\n\t\t\t\t\tlastEventId: params.lastEventId,\n\t\t\t\t\t[RAW_INPUT]: state.rawInput\n\t\t\t\t})\n\t\t\t}\n\t\t})\n\t\t// Prepending middleware shifts oRPC's validation indexes, covering auth,\n\t\t// input validation, output validation, and the final stream lifetime.\n\t\treturn os\n\t\t\t.use(async ({ context, next }, rawInput) => {\n\t\t\t\tconst started = performance.now()\n\t\t\t\tconst state: Invocation = {\n\t\t\t\t\tspan: undefined,\n\t\t\t\t\tlogger: defaultLogger,\n\t\t\t\t\tinput: undefined,\n\t\t\t\t\tcontext,\n\t\t\t\t\thandlerStarted: false,\n\t\t\t\t\trawInput\n\t\t\t\t}\n\t\t\t\tconst result = await tracing.inSpan(\n\t\t\t\t\tname,\n\t\t\t\t\t'SERVER',\n\t\t\t\t\tasync (span) => {\n\t\t\t\t\t\tstate.span = span\n\t\t\t\t\t\tstate.logger = createLogger('fn', span)\n\t\t\t\t\t\tspan?.setAttribute('fn.operation', name)\n\t\t\t\t\t\tspan?.setAttribute('fn.procedure', key)\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tconst result = await next({ context: { [invocation]: state } })\n\t\t\t\t\t\t\tif (isAsyncIteratorObject(result.output) !== stream) {\n\t\t\t\t\t\t\t\tif (isAsyncIteratorObject(result.output)) {\n\t\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\t\tawait result.output.return?.()\n\t\t\t\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t\t\t\t/* Release the unexpected stream. */\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\tthrow new TypeError(\n\t\t\t\t\t\t\t\t\t`orpc-fn: ${name} returned a result inconsistent with stream; declare stream: true for iterators`\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn result.output\n\t\t\t\t\t\t} finally {\n\t\t\t\t\t\t\tconst timing = (context as Record<symbol, unknown>)[\n\t\t\t\t\t\t\t\tREQUEST_TIMING\n\t\t\t\t\t\t\t] as InvocationTiming | undefined\n\t\t\t\t\t\t\tif (timing && !(context as Record<symbol, unknown>)[invocation]) {\n\t\t\t\t\t\t\t\ttiming.procedureMs += performance.now() - started\n\t\t\t\t\t\t\t\ttiming.calls++\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t(span, ...error) => {\n\t\t\t\t\t\tconst durationMs =\n\t\t\t\t\t\t\tMath.round((performance.now() - started) * 100) / 100\n\t\t\t\t\t\tspan?.setAttribute('fn.duration_ms', durationMs)\n\t\t\t\t\t\tlogCompleted(state.logger, {\n\t\t\t\t\t\t\tname,\n\t\t\t\t\t\t\tprocedure: key,\n\t\t\t\t\t\t\tdurationMs,\n\t\t\t\t\t\t\tsuccess: error.length === 0,\n\t\t\t\t\t\t\terror: error[0],\n\t\t\t\t\t\t\tinput: state.input,\n\t\t\t\t\t\t\tcontext: state.context,\n\t\t\t\t\t\t\tspan,\n\t\t\t\t\t\t\tmeta,\n\t\t\t\t\t\t\thandlerStarted: state.handlerStarted\n\t\t\t\t\t\t})\n\t\t\t\t\t}\n\t\t\t\t)\n\t\t\t\treturn { output: result, context }\n\t\t\t})\n\t\t\t.router({ route: built }).route\n\t}\n\n\tconst logCompleted = (logger: FnLogger, event: FnCompletedEvent) => {\n\t\tconst { error, success } = event\n\t\tlet extra: LogAttributes | undefined\n\t\ttry {\n\t\t\textra = runtime.onCompleted?.(event)\n\t\t} catch (hookError) {\n\t\t\tlogger.warn('onCompleted hook failed', {\n\t\t\t\terror: errorMessageOf(hookError)\n\t\t\t})\n\t\t}\n\t\tlet expected = false\n\t\ttry {\n\t\t\texpected = isExpectedError(error)\n\t\t} catch {\n\t\t\texpected = isExpectedClientError(error)\n\t\t}\n\t\tconst level = success ? 'info' : expected ? 'warn' : 'error'\n\t\tlogger[level]('fn.completed', {\n\t\t\t...extra,\n\t\t\tevent: 'fn.completed',\n\t\t\toperation: event.name,\n\t\t\tprocedure: event.procedure,\n\t\t\tduration_ms: event.durationMs,\n\t\t\tstatus: success ? 'success' : 'failed',\n\t\t\t...(error === undefined ? {} : errorAttributes(error))\n\t\t})\n\t}\n\n\tconst live = createLiveRuntime({\n\t\tfn,\n\t\ttracing,\n\t\tcreateLogger,\n\t\tpubsub: runtime.pubsub\n\t})\n\n\t// The runtimes are untyped; `Fn`, `FnLive`, `CreatePubSub` and\n\t// `CreatePublisher` are their typed surface.\n\treturn {\n\t\tfn,\n\t\tfnLive: createFnLive({\n\t\t\tfn,\n\t\t\tcreateChannel: live.createChannel,\n\t\t\tisGuard\n\t\t}),\n\t\tcreatePubSub: live.createPubSub,\n\t\tcreatePublisher: live.createPublisher,\n\t\tcreateRouter,\n\t\treadMeta: readFnMeta,\n\t\tcreateCall: <TContext>(context: TContext, signal?: AbortSignal) =>\n\t\t\tcreateBoundCall(context, signal, tracing),\n\t\tshutdown: live.shutdown,\n\t\tdrainPubSubSubscribers: live.drainPubSubSubscribers,\n\t\tactivePubSubSubscriberCount: live.activePubSubSubscriberCount\n\t} as unknown as FnFactory<\n\t\tDefinition<\n\t\t\tTProcedures,\n\t\t\tTDefault,\n\t\t\tTExtras,\n\t\t\tTGuards,\n\t\t\tTMeta,\n\t\t\tTTag,\n\t\t\tTOtel,\n\t\t\tTLogger,\n\t\t\tTScoped\n\t\t>\n\t>\n}\n"]}
package/dist/hono.d.ts CHANGED
@@ -57,7 +57,10 @@ export type MountOrpcOptions<E extends Env, R extends AnyRouter> = ContextOption
57
57
  plugins?: Plugin<InferRouterInitialContext<R>>[];
58
58
  /** Rewrite request headers before they reach the context (see `normalizeExpoOrigin`). */
59
59
  normalizeHeaders?: (headers: Headers) => Headers;
60
- /** Time spent before the handler ran, reported as `queue`. */
60
+ /**
61
+ * Time spent before the handler ran, reported as `queue`. Default: time
62
+ * since {@link markRequestArrival}, when the server marked the request.
63
+ */
61
64
  queueMs?: (request: Request) => number | undefined;
62
65
  /**
63
66
  * Unexpected procedure errors (oRPC turns thrown errors into responses, so
@@ -70,6 +73,14 @@ export type MountOrpcOptions<E extends Env, R extends AnyRouter> = ContextOption
70
73
  /** Default: 4xx `ORPCError` or `AbortError`. */
71
74
  isExpectedError?: (error: unknown) => boolean;
72
75
  };
76
+ /**
77
+ * Marks a request at the server's front door (`Bun.serve({ fetch })`), before
78
+ * routing and middleware. `mountOrpc` reports the time until the procedure
79
+ * runs as `queue_ms`: in-process queueing no handler timer can see.
80
+ */
81
+ export declare function markRequestArrival(request: Request): void;
82
+ /** Milliseconds since {@link markRequestArrival}, or undefined when unmarked. */
83
+ export declare function msSinceRequestArrival(request: Request): number | undefined;
73
84
  /**
74
85
  * Expo native sends `expo-origin` but not `origin`; copy it so cookie-based
75
86
  * auth (e.g. Better Auth) sees the origin.
@@ -1 +1 @@
1
- {"version":3,"file":"hono.d.ts","sourceRoot":"","sources":["../src/hono.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"hono.d.ts","sourceRoot":"","sources":["../src/hono.ts"],"names":[],"mappings":"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"}
package/dist/hono.js CHANGED
@@ -7,6 +7,20 @@ import { BatchHandlerPlugin } from '@orpc/server/plugins';
7
7
  import { ZodToJsonSchemaConverter } from '@orpc/zod/zod4';
8
8
  import { REQUEST_TIMING } from './timing.js';
9
9
  import { isExpectedClientError } from './expected-client-error.js';
10
+ const arrivals = new WeakMap();
11
+ /**
12
+ * Marks a request at the server's front door (`Bun.serve({ fetch })`), before
13
+ * routing and middleware. `mountOrpc` reports the time until the procedure
14
+ * runs as `queue_ms`: in-process queueing no handler timer can see.
15
+ */
16
+ export function markRequestArrival(request) {
17
+ arrivals.set(request, performance.now());
18
+ }
19
+ /** Milliseconds since {@link markRequestArrival}, or undefined when unmarked. */
20
+ export function msSinceRequestArrival(request) {
21
+ const arrivedAt = arrivals.get(request);
22
+ return arrivedAt === undefined ? undefined : performance.now() - arrivedAt;
23
+ }
10
24
  /**
11
25
  * Expo native sends `expo-origin` but not `origin`; copy it so cookie-based
12
26
  * auth (e.g. Better Auth) sees the origin.
@@ -73,7 +87,7 @@ export function mountOrpc(app, options) {
73
87
  const mount = (prefix, handler) => {
74
88
  app.use(`${prefix}/*`, async (c, next) => {
75
89
  const timing = {};
76
- const queueMs = options.queueMs?.(c.req.raw);
90
+ const queueMs = (options.queueMs ?? msSinceRequestArrival)(c.req.raw);
77
91
  if (queueMs !== undefined)
78
92
  timing.queue_ms = Math.round(queueMs * 100) / 100;
79
93
  const started = performance.now();