orpc-fn 0.1.0 → 0.3.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 +70 -33
- 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/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +56 -0
- package/dist/cli.js.map +1 -0
- 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 +67 -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 +81 -13
- package/dist/live/pub-sub.d.ts.map +1 -1
- package/dist/live/pub-sub.js +437 -126
- 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/core.d.ts +41 -0
- package/dist/mcp/core.d.ts.map +1 -0
- package/dist/mcp/core.js +61 -0
- package/dist/mcp/core.js.map +1 -0
- package/dist/mcp/sdk.d.ts +12 -0
- package/dist/mcp/sdk.d.ts.map +1 -0
- package/dist/mcp/sdk.js +14 -0
- package/dist/mcp/sdk.js.map +1 -0
- package/dist/mcp/server.d.ts +11 -0
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/mcp/server.js +13 -0
- package/dist/mcp/server.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 +13 -1
- package/dist/router.d.ts.map +1 -1
- package/dist/router.js +35 -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 +96 -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 +28 -3
- package/src/assemble-procedure.ts +42 -0
- package/src/bound-call.ts +4 -3
- package/src/cli.ts +68 -0
- package/src/client.ts +9 -2
- package/src/compatibility.ts +39 -0
- package/src/create-fn.ts +295 -182
- package/src/expo.ts +49 -44
- package/src/hono.ts +36 -17
- package/src/index.ts +7 -2
- package/src/json-schema.ts +16 -0
- package/src/live/codec.ts +22 -3
- package/src/live/fn-live.ts +248 -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 +619 -168
- 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/core.ts +102 -0
- package/src/mcp/sdk.ts +36 -0
- package/src/mcp/server.ts +35 -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 +58 -1
- package/src/timing.ts +5 -0
- package/src/types.ts +186 -62
package/dist/otel.js
CHANGED
|
@@ -1,9 +1,16 @@
|
|
|
1
1
|
import { isAsyncIteratorObject, onStreamEnd } from './stream.js';
|
|
2
2
|
export function createTracing(otel) {
|
|
3
|
-
|
|
3
|
+
let tracer;
|
|
4
|
+
try {
|
|
5
|
+
tracer = otel?.trace.getTracer('orpc-fn');
|
|
6
|
+
}
|
|
7
|
+
catch {
|
|
8
|
+
/* Missing telemetry cannot prevent execution. */
|
|
9
|
+
}
|
|
4
10
|
const end = (span, ...error) => {
|
|
5
11
|
if (!span || !otel)
|
|
6
12
|
return;
|
|
13
|
+
span = protectSpan(span);
|
|
7
14
|
if (error.length === 0) {
|
|
8
15
|
span.setStatus({ code: otel.SpanStatusCode.OK });
|
|
9
16
|
}
|
|
@@ -23,11 +30,15 @@ export function createTracing(otel) {
|
|
|
23
30
|
try {
|
|
24
31
|
onSettled?.(span, ...error);
|
|
25
32
|
}
|
|
33
|
+
catch {
|
|
34
|
+
/* Telemetry callbacks cannot replace the original result. */
|
|
35
|
+
}
|
|
26
36
|
finally {
|
|
27
37
|
end(span, ...error);
|
|
28
38
|
}
|
|
29
39
|
};
|
|
30
40
|
const run = async (span, scope) => {
|
|
41
|
+
span = span ? protectSpan(span) : undefined;
|
|
31
42
|
let result;
|
|
32
43
|
try {
|
|
33
44
|
result = await fn(span);
|
|
@@ -44,15 +55,56 @@ export function createTracing(otel) {
|
|
|
44
55
|
};
|
|
45
56
|
if (!tracer || !otel)
|
|
46
57
|
return run(undefined);
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
return
|
|
50
|
-
|
|
58
|
+
let started;
|
|
59
|
+
try {
|
|
60
|
+
return tracer.startActiveSpan(name, { kind: otel.SpanKind[kind] }, (span) => {
|
|
61
|
+
let active;
|
|
62
|
+
try {
|
|
63
|
+
active = otel.context.active();
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
/* Fall back to the span without scope restoration. */
|
|
67
|
+
}
|
|
68
|
+
started = run(span, (step) => {
|
|
69
|
+
let completed;
|
|
70
|
+
let failed;
|
|
71
|
+
try {
|
|
72
|
+
return otel.context.with(active, () => {
|
|
73
|
+
try {
|
|
74
|
+
const value = step();
|
|
75
|
+
completed = { value };
|
|
76
|
+
return value;
|
|
77
|
+
}
|
|
78
|
+
catch (error) {
|
|
79
|
+
failed = { error };
|
|
80
|
+
throw error;
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
catch {
|
|
85
|
+
if (completed)
|
|
86
|
+
return completed.value;
|
|
87
|
+
if (failed)
|
|
88
|
+
throw failed.error;
|
|
89
|
+
return step();
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
return started;
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
catch {
|
|
96
|
+
return started ?? run(undefined);
|
|
97
|
+
}
|
|
51
98
|
},
|
|
52
99
|
startSpan(name, kind, attributes) {
|
|
53
100
|
if (!tracer || !otel)
|
|
54
101
|
return undefined;
|
|
55
|
-
|
|
102
|
+
try {
|
|
103
|
+
return protectSpan(tracer.startSpan(name, { kind: otel.SpanKind[kind], attributes }));
|
|
104
|
+
}
|
|
105
|
+
catch {
|
|
106
|
+
return undefined;
|
|
107
|
+
}
|
|
56
108
|
},
|
|
57
109
|
end
|
|
58
110
|
};
|
|
@@ -60,4 +112,23 @@ export function createTracing(otel) {
|
|
|
60
112
|
export function errorMessageOf(error) {
|
|
61
113
|
return error instanceof Error ? error.message : String(error);
|
|
62
114
|
}
|
|
115
|
+
function protectSpan(span) {
|
|
116
|
+
return new Proxy(span, {
|
|
117
|
+
get(target, key) {
|
|
118
|
+
const value = Reflect.get(target, key, target);
|
|
119
|
+
if (typeof value !== 'function')
|
|
120
|
+
return value;
|
|
121
|
+
if (['setAttribute', 'setStatus', 'recordException', 'end'].includes(String(key)))
|
|
122
|
+
return (...args) => {
|
|
123
|
+
try {
|
|
124
|
+
return value.apply(target, args);
|
|
125
|
+
}
|
|
126
|
+
catch {
|
|
127
|
+
/* Ignore exporter failures. */
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
return value.bind(target);
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
}
|
|
63
134
|
//# sourceMappingURL=otel.js.map
|
package/dist/otel.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"otel.js","sourceRoot":"","sources":["../src/otel.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n\tisAsyncIteratorObject,\n\tonStreamEnd,\n\ttype StreamScope\n} from './stream.js'\n\n/** Attribute values accepted by OpenTelemetry spans. */\nexport type AttributeValue = string | number | boolean\n\n/** The part of an OpenTelemetry `Span` this package uses. */\nexport interface SpanLike {\n\tsetAttribute(key: string, value: AttributeValue): unknown\n\tsetStatus(status: { code: number; message?: string }): unknown\n\trecordException(exception: Error): unknown\n\tend(): unknown\n}\n\ntype SpanOptionsLike = {\n\tkind?: number\n\tattributes?: Record<string, AttributeValue>\n}\n\ninterface TracerLike<TSpan> {\n\tstartActiveSpan<F extends (span: TSpan) => unknown>(\n\t\tname: string,\n\t\toptions: SpanOptionsLike,\n\t\tfn: F\n\t): ReturnType<F>\n\tstartSpan(name: string, options?: SpanOptionsLike): TSpan\n}\n\n/**\n * The part of `@opentelemetry/api` this package uses. Pass the module itself:\n * `import * as otel from '@opentelemetry/api'` then `createFn({ otel })`.\n * Without it no spans are created and handlers receive `span: undefined`.\n */\nexport interface OtelApiLike<TSpan extends SpanLike = SpanLike> {\n\ttrace: { getTracer(name: string): TracerLike<TSpan> }\n\tSpanStatusCode: { OK: number; ERROR: number }\n\tSpanKind: {\n\t\tINTERNAL: number\n\t\tSERVER: number\n\t\tPRODUCER: number\n\t}\n\t/** Restores a span's context for each step of a stream it returned. */\n\tcontext: {\n\t\tactive(): unknown\n\t\twith<T>(context: never, fn: () => T): T\n\t}\n}\n\n/** The span type of an OpenTelemetry API, or `SpanLike` when absent. */\nexport type SpanOf<TOtel> =\n\tTOtel extends OtelApiLike<infer TSpan> ? TSpan : SpanLike\n\n/** Called once when a span's work is done, before the span ends. */\nexport type OnSettled = (\n\tspan: SpanLike | undefined,\n\t...error: [] | [unknown]\n) => void\n\nexport type Tracing = {\n\t/**\n\t * Run `fn` inside an active span: OK when it resolves, ERROR when it throws,\n\t * ended either way. When `fn` resolves to a stream, the span stays open -\n\t * and active for each step of the stream - until the stream ends.\n\t * `onSettled` runs once at that point, before the span ends. Without\n\t * OpenTelemetry `span` is undefined and `onSettled` still runs.\n\t */\n\tinSpan<T>(\n\t\tname: string,\n\t\tkind: 'INTERNAL' | 'SERVER' | 'PRODUCER',\n\t\tfn: (span: SpanLike | undefined) => Promise<T>,\n\t\tonSettled?: OnSettled\n\t): Promise<T>\n\t/** Start a span that the caller ends with `end` (long-lived streams). */\n\tstartSpan(\n\t\tname: string,\n\t\tkind: 'SERVER',\n\t\tattributes: Record<string, AttributeValue>\n\t): SpanLike | undefined\n\t/** Set OK, or ERROR with `error`, and end the span. */\n\tend(span: SpanLike | undefined, error?: unknown): void\n}\n\nexport function createTracing(otel: OtelApiLike | undefined): Tracing {\n\tconst tracer = otel?.trace.getTracer('orpc-fn')\n\tconst end: Tracing['end'] = (span, ...error) => {\n\t\tif (!span || !otel) return\n\t\tif (error.length === 0) {\n\t\t\tspan.setStatus({ code: otel.SpanStatusCode.OK })\n\t\t} else {\n\t\t\tspan.setStatus({\n\t\t\t\tcode: otel.SpanStatusCode.ERROR,\n\t\t\t\tmessage: errorMessageOf(error[0])\n\t\t\t})\n\t\t\tif (error[0] instanceof Error) span.recordException(error[0])\n\t\t}\n\t\tspan.end()\n\t}\n\treturn {\n\t\tinSpan(name, kind, fn, onSettled) {\n\t\t\tconst settle = (span: SpanLike | undefined, ...error: [] | [unknown]) => {\n\t\t\t\ttry {\n\t\t\t\t\tonSettled?.(span, ...error)\n\t\t\t\t} finally {\n\t\t\t\t\tend(span, ...error)\n\t\t\t\t}\n\t\t\t}\n\t\t\tconst run = async (\n\t\t\t\tspan: SpanLike | undefined,\n\t\t\t\tscope?: StreamScope\n\t\t\t): Promise<Awaited<ReturnType<typeof fn>>> => {\n\t\t\t\tlet result: Awaited<ReturnType<typeof fn>>\n\t\t\t\ttry {\n\t\t\t\t\tresult = await fn(span)\n\t\t\t\t} catch (error) {\n\t\t\t\t\tsettle(span, error)\n\t\t\t\t\tthrow error\n\t\t\t\t}\n\t\t\t\tif (isAsyncIteratorObject(result)) {\n\t\t\t\t\treturn onStreamEnd(\n\t\t\t\t\t\tresult,\n\t\t\t\t\t\t(...error) => settle(span, ...error),\n\t\t\t\t\t\tscope\n\t\t\t\t\t) as typeof result\n\t\t\t\t}\n\t\t\t\tsettle(span)\n\t\t\t\treturn result\n\t\t\t}\n\t\t\tif (!tracer || !otel) return run(undefined)\n\t\t\treturn tracer.startActiveSpan(\n\t\t\t\tname,\n\t\t\t\t{ kind: otel.SpanKind[kind] },\n\t\t\t\t(span) => {\n\t\t\t\t\tconst active = otel.context.active()\n\t\t\t\t\treturn run(span, (step) => otel.context.with(active as never, step))\n\t\t\t\t}\n\t\t\t)\n\t\t},\n\t\tstartSpan(name, kind, attributes) {\n\t\t\tif (!tracer || !otel) return undefined\n\t\t\treturn tracer.startSpan(name, { kind: otel.SpanKind[kind], attributes })\n\t\t},\n\t\tend\n\t}\n}\n\nexport function errorMessageOf(error: unknown): string {\n\treturn error instanceof Error ? error.message : String(error)\n}\n"]}
|
|
1
|
+
{"version":3,"file":"otel.js","sourceRoot":"","sources":["../src/otel.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n\tisAsyncIteratorObject,\n\tonStreamEnd,\n\ttype StreamScope\n} from './stream.js'\n\n/** Attribute values accepted by OpenTelemetry spans. */\nexport type AttributeValue = string | number | boolean\n\n/** The part of an OpenTelemetry `Span` this package uses. */\nexport interface SpanLike {\n\tsetAttribute(key: string, value: AttributeValue): unknown\n\tsetStatus(status: { code: number; message?: string }): unknown\n\trecordException(exception: Error): unknown\n\tend(): unknown\n}\n\ntype SpanOptionsLike = {\n\tkind?: number\n\tattributes?: Record<string, AttributeValue>\n}\n\ninterface TracerLike<TSpan> {\n\tstartActiveSpan<F extends (span: TSpan) => unknown>(\n\t\tname: string,\n\t\toptions: SpanOptionsLike,\n\t\tfn: F\n\t): ReturnType<F>\n\tstartSpan(name: string, options?: SpanOptionsLike): TSpan\n}\n\n/**\n * The part of `@opentelemetry/api` this package uses. Pass the module itself:\n * `import * as otel from '@opentelemetry/api'` then `createFn({ otel })`.\n * Without it no spans are created and handlers receive `span: undefined`.\n */\nexport interface OtelApiLike<TSpan extends SpanLike = SpanLike> {\n\ttrace: { getTracer(name: string): TracerLike<TSpan> }\n\tSpanStatusCode: { OK: number; ERROR: number }\n\tSpanKind: {\n\t\tINTERNAL: number\n\t\tSERVER: number\n\t\tPRODUCER: number\n\t}\n\t/** Restores a span's context for each step of a stream it returned. */\n\tcontext: {\n\t\tactive(): unknown\n\t\twith<T>(context: never, fn: () => T): T\n\t}\n}\n\n/** The span type of an OpenTelemetry API, or `SpanLike` when absent. */\nexport type SpanOf<TOtel> =\n\tTOtel extends OtelApiLike<infer TSpan> ? TSpan : SpanLike\n\n/** Called once when a span's work is done, before the span ends. */\nexport type OnSettled = (\n\tspan: SpanLike | undefined,\n\t...error: [] | [unknown]\n) => void\n\nexport type Tracing = {\n\t/**\n\t * Run `fn` inside an active span: OK when it resolves, ERROR when it throws,\n\t * ended either way. When `fn` resolves to a stream, the span stays open -\n\t * and active for each step of the stream - until the stream ends.\n\t * `onSettled` runs once at that point, before the span ends. Without\n\t * OpenTelemetry `span` is undefined and `onSettled` still runs.\n\t */\n\tinSpan<T>(\n\t\tname: string,\n\t\tkind: 'INTERNAL' | 'SERVER' | 'PRODUCER',\n\t\tfn: (span: SpanLike | undefined) => Promise<T>,\n\t\tonSettled?: OnSettled\n\t): Promise<T>\n\t/** Start a span that the caller ends with `end` (long-lived streams). */\n\tstartSpan(\n\t\tname: string,\n\t\tkind: 'SERVER',\n\t\tattributes: Record<string, AttributeValue>\n\t): SpanLike | undefined\n\t/** Set OK, or ERROR with `error`, and end the span. */\n\tend(span: SpanLike | undefined, error?: unknown): void\n}\n\nexport function createTracing(otel: OtelApiLike | undefined): Tracing {\n\tlet tracer: TracerLike<SpanLike> | undefined\n\ttry {\n\t\ttracer = otel?.trace.getTracer('orpc-fn')\n\t} catch {\n\t\t/* Missing telemetry cannot prevent execution. */\n\t}\n\tconst end: Tracing['end'] = (span, ...error) => {\n\t\tif (!span || !otel) return\n\t\tspan = protectSpan(span)\n\t\tif (error.length === 0) {\n\t\t\tspan.setStatus({ code: otel.SpanStatusCode.OK })\n\t\t} else {\n\t\t\tspan.setStatus({\n\t\t\t\tcode: otel.SpanStatusCode.ERROR,\n\t\t\t\tmessage: errorMessageOf(error[0])\n\t\t\t})\n\t\t\tif (error[0] instanceof Error) span.recordException(error[0])\n\t\t}\n\t\tspan.end()\n\t}\n\treturn {\n\t\tinSpan(name, kind, fn, onSettled) {\n\t\t\tconst settle = (span: SpanLike | undefined, ...error: [] | [unknown]) => {\n\t\t\t\ttry {\n\t\t\t\t\tonSettled?.(span, ...error)\n\t\t\t\t} catch {\n\t\t\t\t\t/* Telemetry callbacks cannot replace the original result. */\n\t\t\t\t} finally {\n\t\t\t\t\tend(span, ...error)\n\t\t\t\t}\n\t\t\t}\n\t\t\tconst run = async (\n\t\t\t\tspan: SpanLike | undefined,\n\t\t\t\tscope?: StreamScope\n\t\t\t): Promise<Awaited<ReturnType<typeof fn>>> => {\n\t\t\t\tspan = span ? protectSpan(span) : undefined\n\t\t\t\tlet result: Awaited<ReturnType<typeof fn>>\n\t\t\t\ttry {\n\t\t\t\t\tresult = await fn(span)\n\t\t\t\t} catch (error) {\n\t\t\t\t\tsettle(span, error)\n\t\t\t\t\tthrow error\n\t\t\t\t}\n\t\t\t\tif (isAsyncIteratorObject(result)) {\n\t\t\t\t\treturn onStreamEnd(\n\t\t\t\t\t\tresult,\n\t\t\t\t\t\t(...error) => settle(span, ...error),\n\t\t\t\t\t\tscope\n\t\t\t\t\t) as typeof result\n\t\t\t\t}\n\t\t\t\tsettle(span)\n\t\t\t\treturn result\n\t\t\t}\n\t\t\tif (!tracer || !otel) return run(undefined)\n\t\t\tlet started: Promise<Awaited<ReturnType<typeof fn>>> | undefined\n\t\t\ttry {\n\t\t\t\treturn tracer.startActiveSpan(\n\t\t\t\t\tname,\n\t\t\t\t\t{ kind: otel.SpanKind[kind] },\n\t\t\t\t\t(span) => {\n\t\t\t\t\t\tlet active: unknown\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tactive = otel.context.active()\n\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t/* Fall back to the span without scope restoration. */\n\t\t\t\t\t\t}\n\t\t\t\t\t\tstarted = run(span, (step) => {\n\t\t\t\t\t\t\tlet completed: { value: ReturnType<typeof step> } | undefined\n\t\t\t\t\t\t\tlet failed: { error: unknown } | undefined\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\treturn otel.context.with(active as never, () => {\n\t\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\t\tconst value = step()\n\t\t\t\t\t\t\t\t\t\tcompleted = { value }\n\t\t\t\t\t\t\t\t\t\treturn value\n\t\t\t\t\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\t\t\t\t\tfailed = { error }\n\t\t\t\t\t\t\t\t\t\tthrow error\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t\tif (completed) return completed.value\n\t\t\t\t\t\t\t\tif (failed) throw failed.error\n\t\t\t\t\t\t\t\treturn step()\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t})\n\t\t\t\t\t\treturn started\n\t\t\t\t\t}\n\t\t\t\t)\n\t\t\t} catch {\n\t\t\t\treturn started ?? run(undefined)\n\t\t\t}\n\t\t},\n\t\tstartSpan(name, kind, attributes) {\n\t\t\tif (!tracer || !otel) return undefined\n\t\t\ttry {\n\t\t\t\treturn protectSpan(\n\t\t\t\t\ttracer.startSpan(name, { kind: otel.SpanKind[kind], attributes })\n\t\t\t\t)\n\t\t\t} catch {\n\t\t\t\treturn undefined\n\t\t\t}\n\t\t},\n\t\tend\n\t}\n}\n\nexport function errorMessageOf(error: unknown): string {\n\treturn error instanceof Error ? error.message : String(error)\n}\n\nfunction protectSpan<T extends SpanLike>(span: T): T {\n\treturn new Proxy(span, {\n\t\tget(target, key) {\n\t\t\tconst value = Reflect.get(target, key, target)\n\t\t\tif (typeof value !== 'function') return value\n\t\t\tif (\n\t\t\t\t['setAttribute', 'setStatus', 'recordException', 'end'].includes(\n\t\t\t\t\tString(key)\n\t\t\t\t)\n\t\t\t)\n\t\t\t\treturn (...args: unknown[]) => {\n\t\t\t\t\ttry {\n\t\t\t\t\t\treturn value.apply(target, args)\n\t\t\t\t\t} catch {\n\t\t\t\t\t\t/* Ignore exporter failures. */\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\treturn value.bind(target)\n\t\t}\n\t})\n}\n"]}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { type AnySchema, type ErrorMap } from '@orpc/contract';
|
|
2
|
+
type Resolver = (params: {
|
|
3
|
+
input: unknown;
|
|
4
|
+
context: unknown;
|
|
5
|
+
signal: AbortSignal | undefined;
|
|
6
|
+
}) => unknown;
|
|
7
|
+
/** Runtime validation for JavaScript callers and spread route options. */
|
|
8
|
+
export declare function normalizeRoute(options: Record<string, unknown>, isGuard: (key: string) => boolean): {
|
|
9
|
+
handler: (params: Record<PropertyKey, unknown>) => unknown;
|
|
10
|
+
input: AnySchema | undefined;
|
|
11
|
+
output: AnySchema | undefined;
|
|
12
|
+
name: string;
|
|
13
|
+
procedure: string | undefined;
|
|
14
|
+
meta: Record<string, unknown>;
|
|
15
|
+
stream: boolean;
|
|
16
|
+
errors: ErrorMap | undefined;
|
|
17
|
+
guardResolvers: Record<string, Resolver>;
|
|
18
|
+
route: Record<string, unknown>;
|
|
19
|
+
guardChecks: [string, unknown][];
|
|
20
|
+
};
|
|
21
|
+
export {};
|
|
22
|
+
//# sourceMappingURL=route-options.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"route-options.d.ts","sourceRoot":"","sources":["../src/route-options.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,KAAK,SAAS,EACd,KAAK,QAAQ,EAEb,MAAM,gBAAgB,CAAA;AAGvB,KAAK,QAAQ,GAAG,CAAC,MAAM,EAAE;IACxB,KAAK,EAAE,OAAO,CAAA;IACd,OAAO,EAAE,OAAO,CAAA;IAChB,MAAM,EAAE,WAAW,GAAG,SAAS,CAAA;CAC/B,KAAK,OAAO,CAAA;AAab,0EAA0E;AAC1E,wBAAgB,cAAc,CAC7B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAChC,OAAO,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO;aA4DZ,CAAC,MAAM,EAAE,MAAM,CAAC,WAAW,EAAE,OAAO,CAAC,KAAK,OAAO;;;;;UAKpD,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;;YAEtB,QAAQ,GAAG,SAAS;oBACJ,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC;;;EAI3D"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { getEventIteratorSchemaDetails } from '@orpc/contract';
|
|
2
|
+
import { ROUTE_OPTION_KEYS } from './types.js';
|
|
3
|
+
function schemaOption(schema, name) {
|
|
4
|
+
if (schema === undefined)
|
|
5
|
+
return undefined;
|
|
6
|
+
if (typeof schema !== 'object' ||
|
|
7
|
+
schema === null ||
|
|
8
|
+
!('~standard' in schema) ||
|
|
9
|
+
typeof schema['~standard']?.validate !== 'function')
|
|
10
|
+
throw new TypeError(`orpc-fn: ${name} must be a Standard Schema`);
|
|
11
|
+
return schema;
|
|
12
|
+
}
|
|
13
|
+
/** Runtime validation for JavaScript callers and spread route options. */
|
|
14
|
+
export function normalizeRoute(options, isGuard) {
|
|
15
|
+
const { handler, input: rawInput, output: rawOutput, name, procedure, meta: appMeta = {}, stream, errors, guardResolvers = {}, ...rest } = options;
|
|
16
|
+
if (typeof name !== 'string' || !name || typeof handler !== 'function')
|
|
17
|
+
throw new TypeError('orpc-fn: routes require a name and handler');
|
|
18
|
+
if (procedure !== undefined && typeof procedure !== 'string')
|
|
19
|
+
throw new TypeError('orpc-fn: procedure must be a configured key');
|
|
20
|
+
if (typeof appMeta !== 'object' || appMeta === null || Array.isArray(appMeta))
|
|
21
|
+
throw new TypeError('orpc-fn: meta must be an object');
|
|
22
|
+
if (stream !== undefined && typeof stream !== 'boolean')
|
|
23
|
+
throw new TypeError('orpc-fn: stream must be boolean');
|
|
24
|
+
if (typeof guardResolvers !== 'object' ||
|
|
25
|
+
guardResolvers === null ||
|
|
26
|
+
Array.isArray(guardResolvers))
|
|
27
|
+
throw new TypeError('orpc-fn: guardResolvers must be an object');
|
|
28
|
+
const input = schemaOption(rawInput, 'input');
|
|
29
|
+
const output = schemaOption(rawOutput, 'output');
|
|
30
|
+
const route = {};
|
|
31
|
+
const guardChecks = [];
|
|
32
|
+
for (const [option, value] of Object.entries(rest)) {
|
|
33
|
+
if (ROUTE_OPTION_KEYS.includes(option))
|
|
34
|
+
route[option] = value;
|
|
35
|
+
else if (isGuard(option)) {
|
|
36
|
+
if (value !== undefined)
|
|
37
|
+
guardChecks.push([option, value]);
|
|
38
|
+
}
|
|
39
|
+
else
|
|
40
|
+
throw new TypeError(`orpc-fn: unknown route option "${option}"; put application metadata in meta`);
|
|
41
|
+
}
|
|
42
|
+
const iterator = getEventIteratorSchemaDetails(output) !== undefined;
|
|
43
|
+
if (stream === false && iterator)
|
|
44
|
+
throw new TypeError('orpc-fn: an event iterator schema cannot declare stream: false');
|
|
45
|
+
for (const [guard, resolver] of Object.entries(guardResolvers)) {
|
|
46
|
+
if (!isGuard(guard))
|
|
47
|
+
throw new TypeError(`orpc-fn: unknown guard resolver "${guard}"`);
|
|
48
|
+
if (typeof resolver !== 'function')
|
|
49
|
+
throw new TypeError(`orpc-fn: guard resolver "${guard}" must be a function`);
|
|
50
|
+
if (guardChecks.some(([key]) => key === guard))
|
|
51
|
+
throw new TypeError(`orpc-fn: guard "${guard}" has both a value and resolver`);
|
|
52
|
+
}
|
|
53
|
+
return {
|
|
54
|
+
handler: handler,
|
|
55
|
+
input,
|
|
56
|
+
output,
|
|
57
|
+
name,
|
|
58
|
+
procedure,
|
|
59
|
+
meta: appMeta,
|
|
60
|
+
stream: stream === true || iterator,
|
|
61
|
+
errors: errors,
|
|
62
|
+
guardResolvers: guardResolvers,
|
|
63
|
+
route,
|
|
64
|
+
guardChecks
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=route-options.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"route-options.js","sourceRoot":"","sources":["../src/route-options.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n\ttype AnySchema,\n\ttype ErrorMap,\n\tgetEventIteratorSchemaDetails\n} from '@orpc/contract'\nimport { ROUTE_OPTION_KEYS } from './types.js'\n\ntype Resolver = (params: {\n\tinput: unknown\n\tcontext: unknown\n\tsignal: AbortSignal | undefined\n}) => unknown\nfunction schemaOption(schema: unknown, name: string): AnySchema | undefined {\n\tif (schema === undefined) return undefined\n\tif (\n\t\ttypeof schema !== 'object' ||\n\t\tschema === null ||\n\t\t!('~standard' in schema) ||\n\t\ttypeof (schema as AnySchema)['~standard']?.validate !== 'function'\n\t)\n\t\tthrow new TypeError(`orpc-fn: ${name} must be a Standard Schema`)\n\treturn schema as AnySchema\n}\n\n/** Runtime validation for JavaScript callers and spread route options. */\nexport function normalizeRoute(\n\toptions: Record<string, unknown>,\n\tisGuard: (key: string) => boolean\n) {\n\tconst {\n\t\thandler,\n\t\tinput: rawInput,\n\t\toutput: rawOutput,\n\t\tname,\n\t\tprocedure,\n\t\tmeta: appMeta = {},\n\t\tstream,\n\t\terrors,\n\t\tguardResolvers = {},\n\t\t...rest\n\t} = options\n\tif (typeof name !== 'string' || !name || typeof handler !== 'function')\n\t\tthrow new TypeError('orpc-fn: routes require a name and handler')\n\tif (procedure !== undefined && typeof procedure !== 'string')\n\t\tthrow new TypeError('orpc-fn: procedure must be a configured key')\n\tif (typeof appMeta !== 'object' || appMeta === null || Array.isArray(appMeta))\n\t\tthrow new TypeError('orpc-fn: meta must be an object')\n\tif (stream !== undefined && typeof stream !== 'boolean')\n\t\tthrow new TypeError('orpc-fn: stream must be boolean')\n\tif (\n\t\ttypeof guardResolvers !== 'object' ||\n\t\tguardResolvers === null ||\n\t\tArray.isArray(guardResolvers)\n\t)\n\t\tthrow new TypeError('orpc-fn: guardResolvers must be an object')\n\tconst input = schemaOption(rawInput, 'input')\n\tconst output = schemaOption(rawOutput, 'output')\n\tconst route: Record<string, unknown> = {}\n\tconst guardChecks: Array<[string, unknown]> = []\n\tfor (const [option, value] of Object.entries(rest)) {\n\t\tif ((ROUTE_OPTION_KEYS as readonly string[]).includes(option))\n\t\t\troute[option] = value\n\t\telse if (isGuard(option)) {\n\t\t\tif (value !== undefined) guardChecks.push([option, value])\n\t\t} else\n\t\t\tthrow new TypeError(\n\t\t\t\t`orpc-fn: unknown route option \"${option}\"; put application metadata in meta`\n\t\t\t)\n\t}\n\tconst iterator = getEventIteratorSchemaDetails(output) !== undefined\n\tif (stream === false && iterator)\n\t\tthrow new TypeError(\n\t\t\t'orpc-fn: an event iterator schema cannot declare stream: false'\n\t\t)\n\tfor (const [guard, resolver] of Object.entries(guardResolvers)) {\n\t\tif (!isGuard(guard))\n\t\t\tthrow new TypeError(`orpc-fn: unknown guard resolver \"${guard}\"`)\n\t\tif (typeof resolver !== 'function')\n\t\t\tthrow new TypeError(\n\t\t\t\t`orpc-fn: guard resolver \"${guard}\" must be a function`\n\t\t\t)\n\t\tif (guardChecks.some(([key]) => key === guard))\n\t\t\tthrow new TypeError(\n\t\t\t\t`orpc-fn: guard \"${guard}\" has both a value and resolver`\n\t\t\t)\n\t}\n\treturn {\n\t\thandler: handler as (params: Record<PropertyKey, unknown>) => unknown,\n\t\tinput,\n\t\toutput,\n\t\tname,\n\t\tprocedure,\n\t\tmeta: appMeta as Record<string, unknown>,\n\t\tstream: stream === true || iterator,\n\t\terrors: errors as ErrorMap | undefined,\n\t\tguardResolvers: guardResolvers as Record<string, Resolver>,\n\t\troute,\n\t\tguardChecks\n\t}\n}\n"]}
|
package/dist/router.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type AnyRouter } from '@orpc/server';
|
|
2
2
|
/**
|
|
3
3
|
* Creates a router object from routes or nested routers.
|
|
4
4
|
* Simply returns the routes as a const object for type inference.
|
|
@@ -10,4 +10,16 @@ import type { AnyRouter } from '@orpc/server';
|
|
|
10
10
|
* ```
|
|
11
11
|
*/
|
|
12
12
|
export declare function createRouter<T extends AnyRouter>(routes: T): Readonly<T>;
|
|
13
|
+
/** Serialize these paths to a frontend module; this helper belongs on the server. */
|
|
14
|
+
export declare function createStreamManifest(router: AnyRouter): readonly (readonly string[])[];
|
|
15
|
+
/** Resolve lazy routers before generating the same serializable path manifest. */
|
|
16
|
+
export declare function createStreamManifestAsync(router: AnyRouter): Promise<readonly (readonly string[])[]>;
|
|
17
|
+
/**
|
|
18
|
+
* Deterministic module source for a stream manifest: paths sorted, `json`
|
|
19
|
+
* as an array, `ts` as `export const <name>`. Used by `orpc-fn stream-manifest`.
|
|
20
|
+
*/
|
|
21
|
+
export declare function renderStreamManifest(paths: readonly (readonly string[])[], options: {
|
|
22
|
+
format: 'json' | 'ts';
|
|
23
|
+
name?: string | undefined;
|
|
24
|
+
}): string;
|
|
13
25
|
//# sourceMappingURL=router.d.ts.map
|
package/dist/router.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../src/router.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../src/router.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,KAAK,SAAS,EAId,MAAM,cAAc,CAAA;AAGrB;;;;;;;;;GASG;AACH,wBAAgB,YAAY,CAAC,CAAC,SAAS,SAAS,EAAE,MAAM,EAAE,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAExE;AAED,qFAAqF;AACrF,wBAAgB,oBAAoB,CACnC,MAAM,EAAE,SAAS,GACf,SAAS,CAAC,SAAS,MAAM,EAAE,CAAC,EAAE,CAahC;AAED,kFAAkF;AAClF,wBAAsB,yBAAyB,CAC9C,MAAM,EAAE,SAAS,GACf,OAAO,CAAC,SAAS,CAAC,SAAS,MAAM,EAAE,CAAC,EAAE,CAAC,CASzC;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CACnC,KAAK,EAAE,SAAS,CAAC,SAAS,MAAM,EAAE,CAAC,EAAE,EACrC,OAAO,EAAE;IAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,GAC3D,MAAM,CAUR"}
|
package/dist/router.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { resolveContractProcedures, traverseContractProcedures } from '@orpc/server';
|
|
2
|
+
import { readFnMeta } from './meta.js';
|
|
1
3
|
/**
|
|
2
4
|
* Creates a router object from routes or nested routers.
|
|
3
5
|
* Simply returns the routes as a const object for type inference.
|
|
@@ -11,4 +13,37 @@
|
|
|
11
13
|
export function createRouter(routes) {
|
|
12
14
|
return routes;
|
|
13
15
|
}
|
|
16
|
+
/** Serialize these paths to a frontend module; this helper belongs on the server. */
|
|
17
|
+
export function createStreamManifest(router) {
|
|
18
|
+
const paths = [];
|
|
19
|
+
const unresolved = traverseContractProcedures({ router, path: [] }, ({ contract, path }) => {
|
|
20
|
+
if (readFnMeta(contract).stream)
|
|
21
|
+
paths.push([...path]);
|
|
22
|
+
});
|
|
23
|
+
if (unresolved.length)
|
|
24
|
+
throw new TypeError('orpc-fn: lazy routers require createStreamManifestAsync');
|
|
25
|
+
return paths;
|
|
26
|
+
}
|
|
27
|
+
/** Resolve lazy routers before generating the same serializable path manifest. */
|
|
28
|
+
export async function createStreamManifestAsync(router) {
|
|
29
|
+
const paths = [];
|
|
30
|
+
await resolveContractProcedures({ router, path: [] }, ({ contract, path }) => {
|
|
31
|
+
if (readFnMeta(contract).stream)
|
|
32
|
+
paths.push([...path]);
|
|
33
|
+
});
|
|
34
|
+
return paths;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Deterministic module source for a stream manifest: paths sorted, `json`
|
|
38
|
+
* as an array, `ts` as `export const <name>`. Used by `orpc-fn stream-manifest`.
|
|
39
|
+
*/
|
|
40
|
+
export function renderStreamManifest(paths, options) {
|
|
41
|
+
const lines = paths
|
|
42
|
+
.map((path) => `\t[${path.map((segment) => JSON.stringify(segment)).join(', ')}]`)
|
|
43
|
+
.sort();
|
|
44
|
+
const array = lines.length ? `[\n${lines.join(',\n')}\n]` : '[]';
|
|
45
|
+
if (options.format === 'json')
|
|
46
|
+
return `${array}\n`;
|
|
47
|
+
return `// Generated by \`orpc-fn stream-manifest\`. Do not edit.\nexport const ${options.name ?? 'streamPaths'}: readonly (readonly string[])[] = ${array}\n`;
|
|
48
|
+
}
|
|
14
49
|
//# sourceMappingURL=router.js.map
|
package/dist/router.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"router.js","sourceRoot":"","sources":["../src/router.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"router.js","sourceRoot":"","sources":["../src/router.ts"],"names":[],"mappings":"AAAA,OAAO,EAGN,yBAAyB,EACzB,0BAA0B,EAC1B,MAAM,cAAc,CAAA;AACrB,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AAEtC;;;;;;;;;GASG;AACH,MAAM,UAAU,YAAY,CAAsB,MAAS;IAC1D,OAAO,MAAM,CAAA;AACd,CAAC;AAED,qFAAqF;AACrF,MAAM,UAAU,oBAAoB,CACnC,MAAiB;IAEjB,MAAM,KAAK,GAAe,EAAE,CAAA;IAC5B,MAAM,UAAU,GAAG,0BAA0B,CAC5C,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,EACpB,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,EAAE;QACtB,IAAI,UAAU,CAAC,QAAwB,CAAC,CAAC,MAAM;YAAE,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,CAAA;IACvE,CAAC,CACD,CAAA;IACD,IAAI,UAAU,CAAC,MAAM;QACpB,MAAM,IAAI,SAAS,CAClB,yDAAyD,CACzD,CAAA;IACF,OAAO,KAAK,CAAA;AACb,CAAC;AAED,kFAAkF;AAClF,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAC9C,MAAiB;IAEjB,MAAM,KAAK,GAAe,EAAE,CAAA;IAC5B,MAAM,yBAAyB,CAC9B,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,EACpB,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,EAAE;QACtB,IAAI,UAAU,CAAC,QAAwB,CAAC,CAAC,MAAM;YAAE,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,CAAA;IACvE,CAAC,CACD,CAAA;IACD,OAAO,KAAK,CAAA;AACb,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,oBAAoB,CACnC,KAAqC,EACrC,OAA6D;IAE7D,MAAM,KAAK,GAAG,KAAK;SACjB,GAAG,CACH,CAAC,IAAI,EAAE,EAAE,CACR,MAAM,IAAI,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CACnE;SACA,IAAI,EAAE,CAAA;IACR,MAAM,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAA;IAChE,IAAI,OAAO,CAAC,MAAM,KAAK,MAAM;QAAE,OAAO,GAAG,KAAK,IAAI,CAAA;IAClD,OAAO,2EAA2E,OAAO,CAAC,IAAI,IAAI,aAAa,sCAAsC,KAAK,IAAI,CAAA;AAC/J,CAAC","sourcesContent":["import {\n\ttype AnyRouter,\n\ttype AnyProcedure,\n\tresolveContractProcedures,\n\ttraverseContractProcedures\n} from '@orpc/server'\nimport { readFnMeta } from './meta.js'\n\n/**\n * Creates a router object from routes or nested routers.\n * Simply returns the routes as a const object for type inference.\n *\n * @example\n * ```ts\n * const items = createRouter({ getItem, updateItem })\n * export const api = createRouter({ metabase, items })\n * ```\n */\nexport function createRouter<T extends AnyRouter>(routes: T): Readonly<T> {\n\treturn routes\n}\n\n/** Serialize these paths to a frontend module; this helper belongs on the server. */\nexport function createStreamManifest(\n\trouter: AnyRouter\n): readonly (readonly string[])[] {\n\tconst paths: string[][] = []\n\tconst unresolved = traverseContractProcedures(\n\t\t{ router, path: [] },\n\t\t({ contract, path }) => {\n\t\t\tif (readFnMeta(contract as AnyProcedure).stream) paths.push([...path])\n\t\t}\n\t)\n\tif (unresolved.length)\n\t\tthrow new TypeError(\n\t\t\t'orpc-fn: lazy routers require createStreamManifestAsync'\n\t\t)\n\treturn paths\n}\n\n/** Resolve lazy routers before generating the same serializable path manifest. */\nexport async function createStreamManifestAsync(\n\trouter: AnyRouter\n): Promise<readonly (readonly string[])[]> {\n\tconst paths: string[][] = []\n\tawait resolveContractProcedures(\n\t\t{ router, path: [] },\n\t\t({ contract, path }) => {\n\t\t\tif (readFnMeta(contract as AnyProcedure).stream) paths.push([...path])\n\t\t}\n\t)\n\treturn paths\n}\n\n/**\n * Deterministic module source for a stream manifest: paths sorted, `json`\n * as an array, `ts` as `export const <name>`. Used by `orpc-fn stream-manifest`.\n */\nexport function renderStreamManifest(\n\tpaths: readonly (readonly string[])[],\n\toptions: { format: 'json' | 'ts'; name?: string | undefined }\n): string {\n\tconst lines = paths\n\t\t.map(\n\t\t\t(path) =>\n\t\t\t\t`\\t[${path.map((segment) => JSON.stringify(segment)).join(', ')}]`\n\t\t)\n\t\t.sort()\n\tconst array = lines.length ? `[\\n${lines.join(',\\n')}\\n]` : '[]'\n\tif (options.format === 'json') return `${array}\\n`\n\treturn `// Generated by \\`orpc-fn stream-manifest\\`. Do not edit.\\nexport const ${options.name ?? 'streamPaths'}: readonly (readonly string[])[] = ${array}\\n`\n}\n"]}
|
package/dist/timing.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/** Internal bridge shared by the execution middleware and HTTP adapters. */
|
|
2
|
+
export declare const REQUEST_TIMING: unique symbol;
|
|
3
|
+
export type InvocationTiming = {
|
|
4
|
+
procedureMs: number;
|
|
5
|
+
calls: number;
|
|
6
|
+
};
|
|
7
|
+
export declare const RAW_INPUT: unique symbol;
|
|
8
|
+
//# sourceMappingURL=timing.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"timing.d.ts","sourceRoot":"","sources":["../src/timing.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAC5E,eAAO,MAAM,cAAc,eAAkC,CAAA;AAC7D,MAAM,MAAM,gBAAgB,GAAG;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAA;AAErE,eAAO,MAAM,SAAS,eAA6B,CAAA"}
|
package/dist/timing.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"timing.js","sourceRoot":"","sources":["../src/timing.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAC5E,MAAM,CAAC,MAAM,cAAc,GAAG,MAAM,CAAC,uBAAuB,CAAC,CAAA;AAG7D,MAAM,CAAC,MAAM,SAAS,GAAG,MAAM,CAAC,kBAAkB,CAAC,CAAA","sourcesContent":["/** Internal bridge shared by the execution middleware and HTTP adapters. */\nexport const REQUEST_TIMING = Symbol('orpc-fn.requestTiming')\nexport type InvocationTiming = { procedureMs: number; calls: number }\n\nexport const RAW_INPUT = Symbol('orpc-fn.rawInput')\n"]}
|
package/dist/types.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import type { AnySchema, ErrorMap, InferSchemaInput, InferSchemaOutput,
|
|
1
|
+
import type { AnySchema, ErrorMap, InferSchemaInput, InferSchemaOutput, MergedErrorMap, Schema } from '@orpc/contract';
|
|
2
2
|
import type { AnyProcedure, DecoratedProcedure, Procedure, Route } from '@orpc/server';
|
|
3
|
-
import type {
|
|
3
|
+
import type { createORPCErrorConstructorMap } from '@orpc/server';
|
|
4
|
+
import type { StoredFnMeta } from './meta.js';
|
|
5
|
+
import type { NativeErrors, NativeMeta } from './compatibility.js';
|
|
4
6
|
import type { BoundCall } from './bound-call.js';
|
|
5
7
|
import type { FnLogger } from './logger.js';
|
|
6
8
|
import type { SpanLike } from './otel.js';
|
|
@@ -28,13 +30,13 @@ export type DistributiveOmit<T, K extends PropertyKey> = T extends unknown ? Omi
|
|
|
28
30
|
/** `fn()` options passed to oRPC's `.route()`; `RouteConfig` is derived from it. */
|
|
29
31
|
export declare const ROUTE_OPTION_KEYS: readonly ["path", "method", "summary", "description", "deprecated", "successStatus", "successDescription", "inputStructure", "outputStructure", "tags"];
|
|
30
32
|
/**
|
|
31
|
-
* `fn()` option names owned by the route itself. Guard
|
|
33
|
+
* `fn()` option names owned by the route itself. Guard keys must not
|
|
32
34
|
* reuse them: such an option would be read as the route option and the guard
|
|
33
35
|
* would never run.
|
|
34
36
|
*/
|
|
35
|
-
export declare const RESERVED_OPTION_KEYS: readonly ["path", "method", "summary", "description", "deprecated", "successStatus", "successDescription", "inputStructure", "outputStructure", "tags", "name", "procedure", "input", "output", "handler", "live", "operationId"];
|
|
37
|
+
export declare const RESERVED_OPTION_KEYS: readonly ["path", "method", "summary", "description", "deprecated", "successStatus", "successDescription", "inputStructure", "outputStructure", "tags", "name", "procedure", "input", "output", "handler", "live", "operationId", "meta", "stream", "errors", "guardResolvers"];
|
|
36
38
|
export type ReservedOptionKey = (typeof RESERVED_OPTION_KEYS)[number];
|
|
37
|
-
/** @internal Builds one route from a
|
|
39
|
+
/** @internal Builds one route from a selected native procedure builder. */
|
|
38
40
|
export type BuildProcedure = (options: {
|
|
39
41
|
name: string;
|
|
40
42
|
procedure: string | undefined;
|
|
@@ -42,25 +44,33 @@ export type BuildProcedure = (options: {
|
|
|
42
44
|
meta: Record<string, unknown>;
|
|
43
45
|
input?: AnySchema | undefined;
|
|
44
46
|
output?: AnySchema | undefined;
|
|
47
|
+
stream?: boolean;
|
|
48
|
+
errors?: ErrorMap;
|
|
45
49
|
handler: (options: {
|
|
46
50
|
input: unknown;
|
|
47
|
-
context: Record<string, unknown>;
|
|
51
|
+
context: Record<string | symbol, unknown>;
|
|
48
52
|
signal?: AbortSignal;
|
|
53
|
+
lastEventId?: string;
|
|
54
|
+
errors: ReturnType<typeof createORPCErrorConstructorMap>;
|
|
49
55
|
}) => unknown;
|
|
50
56
|
}) => AnyProcedure;
|
|
51
57
|
/** Turns every key of `T` found in `K` into a readable type error. */
|
|
52
58
|
export type RejectKeys<T, K extends PropertyKey, TMessage extends string> = {
|
|
53
59
|
[P in Extract<keyof T, K>]: TMessage;
|
|
54
60
|
};
|
|
61
|
+
/** Params every handler receives; extras may not reuse these names. */
|
|
62
|
+
type HandlerParamKey = 'input' | 'context' | 'call' | 'signal' | 'span' | 'logger' | 'errors' | 'lastEventId';
|
|
55
63
|
/**
|
|
56
64
|
* Handler extras must have known keys: an index signature would claim every
|
|
57
65
|
* handler param. Intersected into `createFn`'s options to reject it.
|
|
58
66
|
*/
|
|
59
|
-
export type FiniteExtras<T> = string extends keyof T ? {
|
|
67
|
+
export type FiniteExtras<T> = T extends unknown ? string extends keyof T ? {
|
|
60
68
|
extras: 'orpc-fn: extras need known keys, not an index signature';
|
|
61
69
|
} : number extends keyof T ? {
|
|
62
70
|
extras: 'orpc-fn: extras need known keys, not an index signature';
|
|
63
|
-
} : unknown
|
|
71
|
+
} : Extract<keyof T, HandlerParamKey> extends never ? unknown : {
|
|
72
|
+
extras: 'orpc-fn: extras cannot shadow handler parameters';
|
|
73
|
+
} : never;
|
|
64
74
|
type ProcedureOf<TBuilder> = TBuilder extends {
|
|
65
75
|
handler(handler: never): infer TProcedure;
|
|
66
76
|
} ? TProcedure : never;
|
|
@@ -68,16 +78,8 @@ type ProcedureOf<TBuilder> = TBuilder extends {
|
|
|
68
78
|
export type InitialContextOf<TBuilder> = ProcedureContext<ProcedureOf<TBuilder>>;
|
|
69
79
|
/** Context the handler sees, after the builder's middleware. */
|
|
70
80
|
export type CurrentContextOf<TBuilder> = ProcedureOf<TBuilder> extends Procedure<infer _TInitial, infer TContext, infer _TIn, infer _TOut, infer _TErrors, infer _TMeta> ? TContext : never;
|
|
71
|
-
type ErrorMapOf<TBuilder> = ProcedureOf<TBuilder
|
|
72
|
-
|
|
73
|
-
errorMap: infer T extends ErrorMap;
|
|
74
|
-
};
|
|
75
|
-
} ? T : ErrorMap;
|
|
76
|
-
type MetaOf<TBuilder> = ProcedureOf<TBuilder> extends {
|
|
77
|
-
'~orpc': {
|
|
78
|
-
meta: infer T extends Meta;
|
|
79
|
-
};
|
|
80
|
-
} ? T : Meta;
|
|
81
|
+
export type ErrorMapOf<TBuilder> = NativeErrors<ProcedureOf<TBuilder>>;
|
|
82
|
+
type MetaOf<TBuilder> = NativeMeta<ProcedureOf<TBuilder>>;
|
|
81
83
|
/**
|
|
82
84
|
* Everything `createFn` inferred from its options. Route types read from it;
|
|
83
85
|
* apps rarely spell it out.
|
|
@@ -86,6 +88,7 @@ export type FnDefinition = {
|
|
|
86
88
|
procedures: Record<string, BuilderLike>;
|
|
87
89
|
default: string;
|
|
88
90
|
extras: object;
|
|
91
|
+
extrasByProcedure?: Partial<Record<string, object>>;
|
|
89
92
|
guards: object;
|
|
90
93
|
meta: object;
|
|
91
94
|
tag: string;
|
|
@@ -114,11 +117,15 @@ export type GuardParams<TContext, TMeta> = {
|
|
|
114
117
|
* `fn({...})`; the guard runs only on routes that set it. Throw (usually an
|
|
115
118
|
* `ORPCError`) to refuse the call.
|
|
116
119
|
*/
|
|
117
|
-
export type Guard<TValue, TParams> = (value: TValue, params: TParams) =>
|
|
120
|
+
export type Guard<TValue, TParams> = (value: TValue, params: TParams) => MaybePromise<void | boolean>;
|
|
118
121
|
export type GuardOptions<TGuards> = {
|
|
119
122
|
[K in keyof TGuards]?: TGuards[K] extends (value: infer TValue, params: never) => unknown ? TValue : never;
|
|
120
123
|
};
|
|
121
|
-
|
|
124
|
+
/** Match object spread: scoped extras replace shared keys, preserving unions. */
|
|
125
|
+
type MergeExtras<TShared, TScoped> = TShared extends unknown ? TScoped extends unknown ? Omit<TShared, keyof TScoped> & TScoped : never : never;
|
|
126
|
+
export type HandlerParams<TDef extends FnDefinition, TInput, TKey extends ProcedureKey<TDef>, TErrors extends ErrorMap = Record<never, never>> = DistributiveOmit<MergeExtras<TDef['extras'], TDef extends {
|
|
127
|
+
extrasByProcedure: infer E;
|
|
128
|
+
} ? TKey extends keyof E ? E[TKey] : object : object>, HandlerParamKey> & {
|
|
122
129
|
input: TInput;
|
|
123
130
|
context: FnContext<TDef, TKey>;
|
|
124
131
|
/** Calls another procedure with this context and signal, in a child span. */
|
|
@@ -128,6 +135,8 @@ export type HandlerParams<TDef extends FnDefinition, TInput, TKey extends Proced
|
|
|
128
135
|
/** Active OpenTelemetry span, undefined when `createFn({ otel })` is not set. */
|
|
129
136
|
span: TDef['span'] | undefined;
|
|
130
137
|
logger: TDef['logger'];
|
|
138
|
+
lastEventId: string | undefined;
|
|
139
|
+
errors: ReturnType<typeof createORPCErrorConstructorMap<MergedErrorMap<ErrorMapOf<TDef['procedures'][TKey]>, TErrors>>>;
|
|
131
140
|
};
|
|
132
141
|
/** Route options shared by every `fn()` overload. */
|
|
133
142
|
export type RouteConfig<TTag extends string = string> = Pick<Route, Exclude<(typeof ROUTE_OPTION_KEYS)[number], 'tags'>> & {
|
|
@@ -135,7 +144,18 @@ export type RouteConfig<TTag extends string = string> = Pick<Route, Exclude<(typ
|
|
|
135
144
|
name: string;
|
|
136
145
|
tags?: TTag[];
|
|
137
146
|
};
|
|
138
|
-
export type FnRouteOptions<TDef extends FnDefinition, TKey extends ProcedureKey<TDef>> = RouteConfig<TDef['tag']> & GuardOptions<TDef['guards']> &
|
|
147
|
+
export type FnRouteOptions<TDef extends FnDefinition, TKey extends ProcedureKey<TDef>, TInput = unknown, TErrors extends ErrorMap = Record<never, never>> = RouteConfig<TDef['tag']> & GuardOptions<TDef['guards']> & {
|
|
148
|
+
meta?: TDef['meta'];
|
|
149
|
+
stream?: boolean;
|
|
150
|
+
errors?: TErrors;
|
|
151
|
+
guardResolvers?: {
|
|
152
|
+
[K in keyof TDef['guards']]?: (params: {
|
|
153
|
+
input: TInput;
|
|
154
|
+
context: FnContext<TDef, TKey>;
|
|
155
|
+
signal: AbortSignal | undefined;
|
|
156
|
+
}) => MaybePromise<GuardOptions<TDef['guards']>[K]>;
|
|
157
|
+
};
|
|
158
|
+
} & ProcedureOption<TDef, TKey>;
|
|
139
159
|
/**
|
|
140
160
|
* Which `createFn({ procedures })` builder a route uses. Optional when
|
|
141
161
|
* `createFn` has a `default`; required on every route when it has none.
|
|
@@ -145,40 +165,42 @@ export type ProcedureOption<TDef extends FnDefinition, TKey extends ProcedureKey
|
|
|
145
165
|
} : {
|
|
146
166
|
procedure?: TKey;
|
|
147
167
|
};
|
|
148
|
-
export type FnProcedure<TDef extends FnDefinition, TKey extends ProcedureKey<TDef>, TInputSchema extends Schema<unknown, unknown>, TOutputSchema extends Schema<unknown, unknown>> = DecoratedProcedure<InitialContextOf<TDef['procedures'][TKey]>, FnContext<TDef, TKey>, TInputSchema, TOutputSchema, ErrorMapOf<TDef['procedures'][TKey]>, MetaOf<TDef['procedures'][TKey]
|
|
149
|
-
|
|
150
|
-
|
|
168
|
+
export type FnProcedure<TDef extends FnDefinition, TKey extends ProcedureKey<TDef>, TInputSchema extends Schema<unknown, unknown>, TOutputSchema extends Schema<unknown, unknown>, TErrors extends ErrorMap = Record<never, never>> = DecoratedProcedure<InitialContextOf<TDef['procedures'][TKey]>, FnContext<TDef, TKey>, TInputSchema, TOutputSchema, MergedErrorMap<ErrorMapOf<TDef['procedures'][TKey]>, TErrors>, MetaOf<TDef['procedures'][TKey]> & {
|
|
169
|
+
'orpc-fn': StoredFnMeta<TDef['meta'], TKey>;
|
|
170
|
+
}>;
|
|
171
|
+
type InputOf<T> = [T] extends [AnySchema] ? InferSchemaOutput<T> : unknown;
|
|
172
|
+
type ReturnOf<TOut, TReturn> = [TOut] extends [AnySchema] ? InferSchemaInput<TOut> : TReturn;
|
|
151
173
|
/** `fn()`: four overloads for input/output schema × inferred. */
|
|
152
174
|
export interface Fn<TDef extends FnDefinition> {
|
|
153
|
-
<TInput extends
|
|
175
|
+
<TInput extends AnySchema, TOut extends AnySchema, TKey extends ProcedureKey<TDef> = TDef['default'], TErrors extends ErrorMap = Record<never, never>>(options: {
|
|
154
176
|
input: TInput;
|
|
155
177
|
output: TOut;
|
|
156
|
-
handler: (params: HandlerParams<TDef,
|
|
157
|
-
} & FnRouteOptions<TDef, TKey>): FnProcedure<TDef, TKey, TInput, TOut>;
|
|
158
|
-
<TInput extends
|
|
178
|
+
handler: (params: HandlerParams<TDef, InferSchemaOutput<TInput>, NoInfer<TKey>, TErrors>) => MaybePromise<InferSchemaInput<TOut>>;
|
|
179
|
+
} & FnRouteOptions<TDef, TKey, InferSchemaOutput<TInput>, TErrors>): FnProcedure<TDef, TKey, TInput, TOut, TErrors>;
|
|
180
|
+
<TInput extends AnySchema, TReturn, TKey extends ProcedureKey<TDef> = TDef['default'], TErrors extends ErrorMap = Record<never, never>>(options: {
|
|
159
181
|
input: TInput;
|
|
160
182
|
output?: undefined;
|
|
161
|
-
handler: (params: HandlerParams<TDef,
|
|
162
|
-
} & FnRouteOptions<TDef, TKey>): FnProcedure<TDef, TKey, TInput, Schema<TReturn, TReturn
|
|
163
|
-
<TOut extends
|
|
183
|
+
handler: (params: HandlerParams<TDef, InferSchemaOutput<TInput>, NoInfer<TKey>, TErrors>) => MaybePromise<TReturn>;
|
|
184
|
+
} & FnRouteOptions<TDef, TKey, InferSchemaOutput<TInput>, TErrors>): FnProcedure<TDef, TKey, TInput, Schema<TReturn, TReturn>, TErrors>;
|
|
185
|
+
<TOut extends AnySchema, TKey extends ProcedureKey<TDef> = TDef['default'], TErrors extends ErrorMap = Record<never, never>>(options: {
|
|
164
186
|
input?: undefined;
|
|
165
187
|
output: TOut;
|
|
166
|
-
handler: (params: HandlerParams<TDef, unknown, NoInfer<TKey
|
|
167
|
-
} & FnRouteOptions<TDef, TKey>): FnProcedure<TDef, TKey, Schema<unknown, unknown>, TOut>;
|
|
168
|
-
<TReturn, TKey extends ProcedureKey<TDef> = TDef['default']
|
|
188
|
+
handler: (params: HandlerParams<TDef, unknown, NoInfer<TKey>, TErrors>) => MaybePromise<InferSchemaInput<TOut>>;
|
|
189
|
+
} & FnRouteOptions<TDef, TKey, unknown, TErrors>): FnProcedure<TDef, TKey, Schema<unknown, unknown>, TOut, TErrors>;
|
|
190
|
+
<TReturn, TKey extends ProcedureKey<TDef> = TDef['default'], TErrors extends ErrorMap = Record<never, never>>(options: {
|
|
169
191
|
input?: undefined;
|
|
170
192
|
output?: undefined;
|
|
171
|
-
handler: (params: HandlerParams<TDef, unknown, NoInfer<TKey
|
|
172
|
-
} & FnRouteOptions<TDef, TKey>): FnProcedure<TDef, TKey, Schema<unknown, unknown>, Schema<TReturn, TReturn
|
|
173
|
-
<TReturn, TInput extends
|
|
193
|
+
handler: (params: HandlerParams<TDef, unknown, NoInfer<TKey>, TErrors>) => MaybePromise<TReturn>;
|
|
194
|
+
} & FnRouteOptions<TDef, TKey, unknown, TErrors>): FnProcedure<TDef, TKey, Schema<unknown, unknown>, Schema<TReturn, TReturn>, TErrors>;
|
|
195
|
+
<TReturn, TInput extends AnySchema | undefined = undefined, TOut extends AnySchema | undefined = undefined, TKey extends ProcedureKey<TDef> = TDef['default'], TErrors extends ErrorMap = Record<never, never>>(options: {
|
|
174
196
|
input?: TInput;
|
|
175
197
|
output?: TOut;
|
|
176
|
-
handler: (params: HandlerParams<TDef, InputOf<TInput>, NoInfer<TKey
|
|
177
|
-
} & FnRouteOptions<TDef, TKey>): FnProcedure<TDef, TKey, [
|
|
198
|
+
handler: (params: HandlerParams<TDef, InputOf<TInput>, NoInfer<TKey>, TErrors>) => MaybePromise<ReturnOf<TOut, TReturn>>;
|
|
199
|
+
} & FnRouteOptions<TDef, TKey, InputOf<TInput>, TErrors>): FnProcedure<TDef, TKey, [
|
|
178
200
|
TInput
|
|
179
|
-
] extends [
|
|
201
|
+
] extends [AnySchema] ? TInput : Schema<unknown, unknown>, [
|
|
180
202
|
TOut
|
|
181
|
-
] extends [
|
|
203
|
+
] extends [AnySchema] ? TOut : Schema<TReturn, TReturn>, TErrors>;
|
|
182
204
|
}
|
|
183
205
|
/** What `fn.completed` reports, and what `onCompleted` receives. */
|
|
184
206
|
export type FnCompletedEvent<TContext = unknown, TSpan = SpanLike> = {
|
|
@@ -186,11 +208,44 @@ export type FnCompletedEvent<TContext = unknown, TSpan = SpanLike> = {
|
|
|
186
208
|
procedure: string;
|
|
187
209
|
durationMs: number;
|
|
188
210
|
success: boolean;
|
|
211
|
+
/** False when authentication or input validation prevented handler execution. */
|
|
212
|
+
handlerStarted: boolean;
|
|
189
213
|
error: unknown;
|
|
190
214
|
input: unknown;
|
|
191
215
|
context: TContext;
|
|
192
216
|
span: TSpan | undefined;
|
|
193
217
|
meta: Record<string, unknown>;
|
|
194
218
|
};
|
|
219
|
+
/** Factory hooks retain the builder key/context relationship. */
|
|
220
|
+
export type ProcedureHookParams<TProcedures extends Record<string, BuilderLike>, TExtra = object> = {
|
|
221
|
+
[K in keyof TProcedures & string]: TExtra & {
|
|
222
|
+
procedure: K;
|
|
223
|
+
context: CurrentContextOf<TProcedures[K]>;
|
|
224
|
+
};
|
|
225
|
+
}[keyof TProcedures & string];
|
|
226
|
+
export type CompletedHookEvent<TProcedures extends Record<string, BuilderLike>, TSpan> = {
|
|
227
|
+
[K in keyof TProcedures & string]: Omit<FnCompletedEvent<unknown, TSpan>, 'context' | 'procedure' | 'handlerStarted'> & {
|
|
228
|
+
procedure: K;
|
|
229
|
+
} & ({
|
|
230
|
+
handlerStarted: true;
|
|
231
|
+
context: CurrentContextOf<TProcedures[K]>;
|
|
232
|
+
} | {
|
|
233
|
+
handlerStarted: false;
|
|
234
|
+
context: InitialContextOf<TProcedures[K]>;
|
|
235
|
+
});
|
|
236
|
+
}[keyof TProcedures & string];
|
|
237
|
+
/**
|
|
238
|
+
* Intersected into each scoped extras function's return type: rejects index
|
|
239
|
+
* signatures and handler-parameter names at the offending property. A
|
|
240
|
+
* top-level conditional over the whole map broke inference when zero-argument
|
|
241
|
+
* and context-reading functions were mixed.
|
|
242
|
+
*/
|
|
243
|
+
export type ScopedExtrasGuard<T> = (string extends keyof T ? {
|
|
244
|
+
'orpc-fn: scoped extras need finite keys': never;
|
|
245
|
+
} : number extends keyof T ? {
|
|
246
|
+
'orpc-fn: scoped extras need finite keys': never;
|
|
247
|
+
} : unknown) & {
|
|
248
|
+
[K in HandlerParamKey]?: never;
|
|
249
|
+
};
|
|
195
250
|
export {};
|
|
196
251
|
//# sourceMappingURL=types.d.ts.map
|