orpc-fn 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +48 -32
- package/dist/assemble-procedure.d.ts +13 -0
- package/dist/assemble-procedure.d.ts.map +1 -0
- package/dist/assemble-procedure.js +29 -0
- package/dist/assemble-procedure.js.map +1 -0
- package/dist/bound-call.d.ts +1 -1
- package/dist/bound-call.d.ts.map +1 -1
- package/dist/bound-call.js.map +1 -1
- package/dist/client.d.ts +4 -2
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +4 -2
- package/dist/client.js.map +1 -1
- package/dist/compatibility.d.ts +16 -0
- package/dist/compatibility.d.ts.map +1 -0
- package/dist/compatibility.js +4 -0
- package/dist/compatibility.js.map +1 -0
- package/dist/create-fn.d.ts +30 -34
- package/dist/create-fn.d.ts.map +1 -1
- package/dist/create-fn.js +177 -121
- package/dist/create-fn.js.map +1 -1
- package/dist/expo.d.ts +11 -25
- package/dist/expo.d.ts.map +1 -1
- package/dist/expo.js +25 -30
- package/dist/expo.js.map +1 -1
- package/dist/hono.d.ts +12 -4
- package/dist/hono.d.ts.map +1 -1
- package/dist/hono.js +29 -12
- package/dist/hono.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/json-schema.d.ts +2 -0
- package/dist/json-schema.d.ts.map +1 -1
- package/dist/json-schema.js +11 -0
- package/dist/json-schema.js.map +1 -1
- package/dist/live/codec.d.ts +6 -1
- package/dist/live/codec.d.ts.map +1 -1
- package/dist/live/codec.js +14 -3
- package/dist/live/codec.js.map +1 -1
- package/dist/live/fn-live.d.ts +63 -22
- package/dist/live/fn-live.d.ts.map +1 -1
- package/dist/live/fn-live.js +98 -16
- package/dist/live/fn-live.js.map +1 -1
- package/dist/live/index.d.ts +1 -1
- package/dist/live/index.d.ts.map +1 -1
- package/dist/live/index.js.map +1 -1
- package/dist/live/ioredis.d.ts +4 -1
- package/dist/live/ioredis.d.ts.map +1 -1
- package/dist/live/ioredis.js +21 -2
- package/dist/live/ioredis.js.map +1 -1
- package/dist/live/lifecycle.d.ts +7 -0
- package/dist/live/lifecycle.d.ts.map +1 -0
- package/dist/live/lifecycle.js +36 -0
- package/dist/live/lifecycle.js.map +1 -0
- package/dist/live/memory.d.ts.map +1 -1
- package/dist/live/memory.js +4 -0
- package/dist/live/memory.js.map +1 -1
- package/dist/live/pub-sub.d.ts +76 -12
- package/dist/live/pub-sub.d.ts.map +1 -1
- package/dist/live/pub-sub.js +429 -125
- package/dist/live/pub-sub.js.map +1 -1
- package/dist/live/redis-bun.d.ts +1 -1
- package/dist/live/redis-bun.d.ts.map +1 -1
- package/dist/live/redis-bun.js +3 -5
- package/dist/live/redis-bun.js.map +1 -1
- package/dist/live/redis.d.ts +2 -2
- package/dist/live/redis.d.ts.map +1 -1
- package/dist/live/redis.js +36 -9
- package/dist/live/redis.js.map +1 -1
- package/dist/live/transport.d.ts +5 -1
- package/dist/live/transport.d.ts.map +1 -1
- package/dist/live/transport.js.map +1 -1
- package/dist/logger.d.ts +2 -0
- package/dist/logger.d.ts.map +1 -1
- package/dist/logger.js +21 -0
- package/dist/logger.js.map +1 -1
- package/dist/mastra.d.ts.map +1 -1
- package/dist/mastra.js +16 -7
- package/dist/mastra.js.map +1 -1
- package/dist/mcp/sdk.d.ts +20 -0
- package/dist/mcp/sdk.d.ts.map +1 -0
- package/dist/mcp/sdk.js +82 -0
- package/dist/mcp/sdk.js.map +1 -0
- package/dist/mcp.d.ts +3 -2
- package/dist/mcp.d.ts.map +1 -1
- package/dist/mcp.js +22 -7
- package/dist/mcp.js.map +1 -1
- package/dist/meta.d.ts +15 -7
- package/dist/meta.d.ts.map +1 -1
- package/dist/meta.js +9 -2
- package/dist/meta.js.map +1 -1
- package/dist/otel.d.ts.map +1 -1
- package/dist/otel.js +77 -6
- package/dist/otel.js.map +1 -1
- package/dist/route-options.d.ts +22 -0
- package/dist/route-options.d.ts.map +1 -0
- package/dist/route-options.js +67 -0
- package/dist/route-options.js.map +1 -0
- package/dist/router.d.ts +5 -1
- package/dist/router.d.ts.map +1 -1
- package/dist/router.js +22 -0
- package/dist/router.js.map +1 -1
- package/dist/timing.d.ts +8 -0
- package/dist/timing.d.ts.map +1 -0
- package/dist/timing.js +4 -0
- package/dist/timing.js.map +1 -0
- package/dist/types.d.ts +86 -41
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +6 -2
- package/dist/types.js.map +1 -1
- package/package.json +15 -3
- package/src/assemble-procedure.ts +42 -0
- package/src/bound-call.ts +4 -3
- package/src/client.ts +9 -2
- package/src/compatibility.ts +39 -0
- package/src/create-fn.ts +297 -183
- package/src/expo.ts +49 -44
- package/src/hono.ts +36 -17
- package/src/index.ts +6 -2
- package/src/json-schema.ts +16 -0
- package/src/live/codec.ts +22 -3
- package/src/live/fn-live.ts +244 -69
- package/src/live/index.ts +2 -0
- package/src/live/ioredis.ts +22 -2
- package/src/live/lifecycle.ts +44 -0
- package/src/live/memory.ts +4 -0
- package/src/live/pub-sub.ts +608 -166
- package/src/live/redis-bun.ts +7 -5
- package/src/live/redis.ts +37 -11
- package/src/live/transport.ts +4 -1
- package/src/logger.ts +20 -0
- package/src/mastra.ts +15 -7
- package/src/mcp/sdk.ts +118 -0
- package/src/mcp.ts +48 -20
- package/src/meta.ts +40 -24
- package/src/otel.ts +77 -10
- package/src/route-options.ts +100 -0
- package/src/router.ts +39 -1
- package/src/timing.ts +5 -0
- package/src/types.ts +204 -62
package/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,
|
|
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
|
-
|
|
65
|
-
|
|
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?,
|
|
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
|
|
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`,
|
|
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.
|
|
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.
|
|
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
|
-
|
|
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
|
|
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`
|
|
120
|
-
- `coalesceMs`
|
|
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
|
-
-
|
|
123
|
-
- `
|
|
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
|
-
|
|
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
|
-
|
|
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`.
|
|
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:
|
|
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
|
-
|
|
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
|
-
|
|
164
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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 {
|
|
242
|
+
import { createBetterAuthExpoLink } from 'orpc-fn/expo'
|
|
228
243
|
|
|
229
|
-
const link =
|
|
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"]}
|
package/dist/bound-call.d.ts
CHANGED
|
@@ -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
|
|
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
|
package/dist/bound-call.d.ts.map
CHANGED
|
@@ -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;
|
|
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"}
|
package/dist/bound-call.js.map
CHANGED
|
@@ -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;
|
|
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:
|
|
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
|
package/dist/client.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,aAAa,
|
|
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 }) =>
|
|
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
|
package/dist/client.js.map
CHANGED
|
@@ -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;
|
|
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 @@
|
|
|
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"]}
|
package/dist/create-fn.d.ts
CHANGED
|
@@ -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 {
|
|
7
|
-
import { type AttributeValue, type OtelApiLike, type
|
|
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
|
|
10
|
-
type
|
|
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
|
-
|
|
35
|
-
|
|
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
|
|
34
|
+
* Keys must not reuse route options. False denies, true or void allows.
|
|
39
35
|
*/
|
|
40
|
-
guards?: TGuards & Record<string, Guard<never,
|
|
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:
|
|
43
|
-
*
|
|
38
|
+
* Typed route metadata contract: `meta: defineMeta<AppMeta>()`.
|
|
39
|
+
* Route declarations place values inside their own `meta` object.
|
|
44
40
|
*/
|
|
45
|
-
meta?: TMeta
|
|
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
|
|
59
|
-
onCompleted?: (event:
|
|
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:
|
|
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
|
-
/**
|
|
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
|
|
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
|
package/dist/create-fn.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create-fn.d.ts","sourceRoot":"","sources":["../src/create-fn.ts"],"names":[],"mappings":"
|
|
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,EAGnB,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,kBAAkB,EACvB,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,CAAC;KAC9B,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,GAC9B,kBAAkB,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,GACnC,SAAS,CACX,UAAU,CACT,WAAW,EACX,QAAQ,EACR,OAAO,EACP,OAAO,EACP,KAAK,EACL,IAAI,EACJ,KAAK,EACL,OAAO,EACP,OAAO,CACP,CACD,CA8TA"}
|