silgi 0.53.2 → 0.53.3
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/dist/client/adapters/fetch/index.mjs +2 -0
- package/dist/client/adapters/ofetch/index.mjs +22 -14
- package/dist/client/types.d.mts +7 -2
- package/dist/compile.d.mts +48 -16
- package/dist/compile.mjs +131 -113
- package/dist/core/schema.d.mts +14 -1
- package/dist/core/schema.mjs +22 -2
- package/dist/core/sse.mjs +167 -1
- package/dist/index.d.mts +2 -2
- package/dist/index.mjs +2 -2
- package/package.json +1 -1
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { SilgiError, fromSilgiErrorJSON, isErrorStatus, isSilgiErrorJSON } from "../../../core/error.mjs";
|
|
2
2
|
import { parseEmptyableJSON, stringifyJSON } from "../../../core/utils.mjs";
|
|
3
|
+
import { eventStreamToIterator } from "../../../core/sse.mjs";
|
|
3
4
|
//#region src/client/adapters/fetch/index.ts
|
|
4
5
|
/**
|
|
5
6
|
* Fetch transport — HTTP client for browser and Node.js.
|
|
@@ -29,6 +30,7 @@ var RPCLink = class {
|
|
|
29
30
|
signal: options.signal
|
|
30
31
|
});
|
|
31
32
|
const contentType = response.headers.get("content-type") ?? "";
|
|
33
|
+
if (contentType.includes("text/event-stream") && response.body) return eventStreamToIterator(response.body);
|
|
32
34
|
let responseBody;
|
|
33
35
|
if (contentType.includes("msgpack")) {
|
|
34
36
|
const { decode } = await import("../../../codec/msgpack.mjs");
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { SilgiError, fromSilgiErrorJSON, isSilgiErrorJSON } from "../../../core/error.mjs";
|
|
2
|
+
import { eventStreamToIterator } from "../../../core/sse.mjs";
|
|
2
3
|
import { MSGPACK_CONTENT_TYPE, decode, encode } from "../../../codec/msgpack.mjs";
|
|
3
4
|
import { FetchError, ofetch } from "ofetch";
|
|
4
5
|
//#region src/client/adapters/ofetch/index.ts
|
|
@@ -42,7 +43,7 @@ function createLink(options) {
|
|
|
42
43
|
body = input !== void 0 && input !== null ? devalueEncode(input) : void 0;
|
|
43
44
|
} else body = input !== void 0 && input !== null ? input : void 0;
|
|
44
45
|
try {
|
|
45
|
-
const
|
|
46
|
+
const response = await ofetch.raw(url, {
|
|
46
47
|
method: "POST",
|
|
47
48
|
headers,
|
|
48
49
|
body,
|
|
@@ -55,21 +56,28 @@ function createLink(options) {
|
|
|
55
56
|
onResponse: options.onResponse,
|
|
56
57
|
onRequestError: options.onRequestError,
|
|
57
58
|
onResponseError: options.onResponseError,
|
|
58
|
-
|
|
59
|
-
if (!text) return void 0;
|
|
60
|
-
try {
|
|
61
|
-
return JSON.parse(text);
|
|
62
|
-
} catch {
|
|
63
|
-
return text;
|
|
64
|
-
}
|
|
65
|
-
} }
|
|
59
|
+
responseType: "stream"
|
|
66
60
|
});
|
|
61
|
+
if ((response.headers.get("content-type") ?? "").includes("text/event-stream") && response.body) return eventStreamToIterator(response.body);
|
|
67
62
|
let decoded;
|
|
68
|
-
if (resolvedProtocol === "messagepack")
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
63
|
+
if (resolvedProtocol === "messagepack") {
|
|
64
|
+
const buf = new Uint8Array(await new Response(response.body).arrayBuffer());
|
|
65
|
+
decoded = buf.length > 0 ? decode(buf) : void 0;
|
|
66
|
+
} else if (resolvedProtocol === "devalue") {
|
|
67
|
+
const text = await new Response(response.body).text();
|
|
68
|
+
if (text) {
|
|
69
|
+
const { decode: devalueDecode } = await import("../../../codec/devalue.mjs");
|
|
70
|
+
decoded = devalueDecode(text);
|
|
71
|
+
} else decoded = void 0;
|
|
72
|
+
} else {
|
|
73
|
+
const text = await new Response(response.body).text();
|
|
74
|
+
if (!text) decoded = void 0;
|
|
75
|
+
else try {
|
|
76
|
+
decoded = JSON.parse(text);
|
|
77
|
+
} catch {
|
|
78
|
+
decoded = text;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
73
81
|
if (isSilgiErrorJSON(decoded)) throw fromSilgiErrorJSON(decoded);
|
|
74
82
|
return decoded;
|
|
75
83
|
} catch (error) {
|
package/dist/client/types.d.mts
CHANGED
|
@@ -9,8 +9,13 @@ interface ClientOptions<TContext extends ClientContext = ClientContext> {
|
|
|
9
9
|
}
|
|
10
10
|
/** A single procedure client — callable function */
|
|
11
11
|
type Client<TClientContext extends ClientContext, TInput, TOutput, _TError = SilgiError> = (...args: ClientRest<TClientContext, TInput>) => Promise<TOutput>;
|
|
12
|
-
/**
|
|
13
|
-
|
|
12
|
+
/**
|
|
13
|
+
* A subscription client — resolves to an async iterator. The Promise
|
|
14
|
+
* boundary is the network round-trip (open the SSE/WS connection, see
|
|
15
|
+
* the response headers); the resolved iterator yields each event until
|
|
16
|
+
* the stream ends.
|
|
17
|
+
*/
|
|
18
|
+
type SubscriptionClient<TClientContext extends ClientContext, TInput, TOutput> = (...args: ClientRest<TClientContext, TInput>) => Promise<AsyncIterableIterator<TOutput>>;
|
|
14
19
|
/** Determine argument shape based on input and context optionality */
|
|
15
20
|
type ClientRest<TClientContext extends ClientContext, TInput> = undefined extends TInput ? Record<never, never> extends TClientContext ? [input?: TInput, options?: ClientOptions<TClientContext>] : [input: TInput | undefined, options: ClientOptions<TClientContext>] : Record<never, never> extends TClientContext ? [input: TInput, options?: ClientOptions<TClientContext>] : [input: TInput, options: ClientOptions<TClientContext>];
|
|
16
21
|
/** Recursive nested client — mirrors the router structure */
|
package/dist/compile.d.mts
CHANGED
|
@@ -8,13 +8,30 @@ import { ProcedureDef, WrapDef } from "./types.mjs";
|
|
|
8
8
|
*/
|
|
9
9
|
type CompiledHandler = (ctx: Record<string, unknown>, rawInput: unknown, signal: AbortSignal) => unknown | Promise<unknown>;
|
|
10
10
|
/**
|
|
11
|
-
* Compile a procedure into
|
|
11
|
+
* Compile a procedure into its request handler.
|
|
12
12
|
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
13
|
+
* The generated handler is built as two nested onions:
|
|
14
|
+
*
|
|
15
|
+
* root-wrap onion (outer)
|
|
16
|
+
* └─ guards → input validation → procedure-wrap onion → resolver
|
|
17
|
+
* → output validation (inner)
|
|
18
|
+
*
|
|
19
|
+
* The *inner* handler still selects one of three shapes up front:
|
|
20
|
+
*
|
|
21
|
+
* - fully sync fast-path when there are no procedure wraps and no
|
|
22
|
+
* input/output schemas;
|
|
23
|
+
* - semi-sync when validation is present but no procedure wraps;
|
|
24
|
+
* - full async onion when any procedure wrap is attached.
|
|
25
|
+
*
|
|
26
|
+
* The *outer* handler is only built when `rootWraps` is non-empty.
|
|
27
|
+
* When no root wraps are configured we return the inner handler as
|
|
28
|
+
* is — zero extra closures per request, every fast-path preserved.
|
|
29
|
+
*
|
|
30
|
+
* @param procedure The procedure definition to compile.
|
|
31
|
+
* @param rootWraps Instance-level wraps (from `silgi({ wraps })`).
|
|
32
|
+
* These wrap the *whole* inner pipeline, including
|
|
33
|
+
* guards — that is the contract documented on
|
|
34
|
+
* `SilgiConfig.wraps` (issue #14).
|
|
18
35
|
*/
|
|
19
36
|
declare function compileProcedure(procedure: ProcedureDef, rootWraps?: readonly WrapDef[] | null): CompiledHandler;
|
|
20
37
|
interface CompiledRoute {
|
|
@@ -40,20 +57,35 @@ type CompiledRouterFn = (method: string, path: string) => MatchedRoute<CompiledR
|
|
|
40
57
|
*/
|
|
41
58
|
declare function compileRouter(def: Record<string, unknown>): CompiledRouterFn;
|
|
42
59
|
/**
|
|
43
|
-
* Disposable
|
|
60
|
+
* Disposable context object handed to the pipeline.
|
|
44
61
|
*
|
|
45
|
-
* Adapters use `using ctx = createContext()` so the context is
|
|
46
|
-
* automatically at scope exit — unless ownership has been
|
|
47
|
-
* elsewhere (e.g. to a streaming `Response` that keeps
|
|
48
|
-
* `ctx` after the handler returns). In that case the
|
|
49
|
-
* `detachContext(ctx)` and the new owner is responsible
|
|
62
|
+
* Adapters use `using ctx = createContext()` so the context is
|
|
63
|
+
* disposed automatically at scope exit — unless ownership has been
|
|
64
|
+
* transferred elsewhere (e.g. to a streaming `Response` that keeps
|
|
65
|
+
* reading from `ctx` after the handler returns). In that case the
|
|
66
|
+
* handler calls `detachContext(ctx)` and the new owner is responsible
|
|
67
|
+
* for cleanup.
|
|
50
68
|
*/
|
|
51
69
|
type PooledContext = Record<string, unknown> & Disposable;
|
|
52
70
|
/**
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
* prototype
|
|
71
|
+
* Allocate a fresh pipeline context.
|
|
72
|
+
*
|
|
73
|
+
* The object has a `null` prototype so user-supplied keys cannot
|
|
74
|
+
* accidentally shadow `Object.prototype` members and property lookups
|
|
75
|
+
* stay on the object itself.
|
|
76
|
+
*
|
|
77
|
+
* A `Symbol.dispose` slot is attached so `using ctx = createContext()`
|
|
78
|
+
* runs `releaseContext(ctx)` at scope exit. Streaming responses that
|
|
79
|
+
* outlive the handler scope swap that slot for a no-op via
|
|
80
|
+
* `detachContext` and take ownership.
|
|
81
|
+
*
|
|
82
|
+
* This used to draw from a recycled pool. The pool has been removed —
|
|
83
|
+
* the win was marginal, the indirection was loud, and the tests that
|
|
84
|
+
* pinned "pool readback" behaviour were observing an implementation
|
|
85
|
+
* detail, not a user-visible guarantee. The public API
|
|
86
|
+
* (`createContext` / `detachContext` / `releaseContext` /
|
|
87
|
+
* `PooledContext`) is preserved so existing call sites keep working;
|
|
88
|
+
* only the internals changed.
|
|
57
89
|
*/
|
|
58
90
|
declare function createContext(): PooledContext;
|
|
59
91
|
//#endregion
|
package/dist/compile.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { validateSchema } from "./core/schema.mjs";
|
|
1
|
+
import { SchemaValidatorCrash, validateSchema } from "./core/schema.mjs";
|
|
2
2
|
import { SilgiError } from "./core/error.mjs";
|
|
3
3
|
import { isProcedureDef } from "./core/router-utils.mjs";
|
|
4
4
|
import { RAW_INPUT, ROOT_WRAPS } from "./core/ctx-symbols.mjs";
|
|
@@ -33,6 +33,87 @@ import { addRoute, createRouter, findRoute } from "rou3";
|
|
|
33
33
|
function isThenable(value) {
|
|
34
34
|
return value !== null && typeof value === "object" && typeof value.then === "function";
|
|
35
35
|
}
|
|
36
|
+
/**
|
|
37
|
+
* Defaults to `true` when `process` is unavailable (Workers/browser) so
|
|
38
|
+
* crashes stay loud by default. Read per-crash so tests can flip
|
|
39
|
+
* `NODE_ENV` at runtime — the crash path is cold, the cost is moot.
|
|
40
|
+
*/
|
|
41
|
+
function isDevEnv() {
|
|
42
|
+
if (typeof process === "undefined") return true;
|
|
43
|
+
return process.env?.NODE_ENV !== "production";
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Validate input. A validator that crashes (e.g. a misconstructed
|
|
47
|
+
* Zod v4 schema) becomes a `BAD_REQUEST` with the original throw on
|
|
48
|
+
* `cause` — the client sent something the validator couldn't even
|
|
49
|
+
* evaluate. Soft `ValidationError` results pass through unchanged.
|
|
50
|
+
*/
|
|
51
|
+
function validateInput(schema, value) {
|
|
52
|
+
let validated;
|
|
53
|
+
try {
|
|
54
|
+
validated = validateSchema(schema, value);
|
|
55
|
+
} catch (e) {
|
|
56
|
+
if (e instanceof SchemaValidatorCrash) throw new SilgiError("BAD_REQUEST", {
|
|
57
|
+
message: "Input schema validator crashed",
|
|
58
|
+
cause: e.cause
|
|
59
|
+
});
|
|
60
|
+
throw e;
|
|
61
|
+
}
|
|
62
|
+
if (isThenable(validated)) return validated.catch((e) => {
|
|
63
|
+
if (e instanceof SchemaValidatorCrash) throw new SilgiError("BAD_REQUEST", {
|
|
64
|
+
message: "Input schema validator crashed",
|
|
65
|
+
cause: e.cause
|
|
66
|
+
});
|
|
67
|
+
throw e;
|
|
68
|
+
});
|
|
69
|
+
return validated;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Validate output. A validator that crashes becomes an
|
|
73
|
+
* `INTERNAL_SERVER_ERROR` (server bug, not user input) with the original
|
|
74
|
+
* throw on `cause`. In dev the cause is also `console.error`'d so the
|
|
75
|
+
* stack shows up in the server log — the only signal otherwise is a
|
|
76
|
+
* generic 500.
|
|
77
|
+
*/
|
|
78
|
+
function validateOutput(schema, value) {
|
|
79
|
+
let validated;
|
|
80
|
+
try {
|
|
81
|
+
validated = validateSchema(schema, value);
|
|
82
|
+
} catch (e) {
|
|
83
|
+
if (e instanceof SchemaValidatorCrash) {
|
|
84
|
+
if (isDevEnv()) console.error("[silgi] output schema validator crashed:", e.cause);
|
|
85
|
+
throw new SilgiError("INTERNAL_SERVER_ERROR", {
|
|
86
|
+
message: "Output schema validator crashed",
|
|
87
|
+
cause: e.cause
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
throw e;
|
|
91
|
+
}
|
|
92
|
+
if (isThenable(validated)) return validated.catch((e) => {
|
|
93
|
+
if (e instanceof SchemaValidatorCrash) {
|
|
94
|
+
if (isDevEnv()) console.error("[silgi] output schema validator crashed:", e.cause);
|
|
95
|
+
throw new SilgiError("INTERNAL_SERVER_ERROR", {
|
|
96
|
+
message: "Output schema validator crashed",
|
|
97
|
+
cause: e.cause
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
throw e;
|
|
101
|
+
});
|
|
102
|
+
return validated;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Wrap a subscription's iterator so each yielded item runs through
|
|
106
|
+
* `validateOutput`. The pre-#26 path validated the iterator object
|
|
107
|
+
* itself, which always 400'd because schemas can't find their declared
|
|
108
|
+
* keys on an iterator. A schema crash mid-stream propagates as a thrown
|
|
109
|
+
* error that the SSE encoder turns into an `error` event.
|
|
110
|
+
*/
|
|
111
|
+
async function* validateIteratorOutput(iterator, schema) {
|
|
112
|
+
for await (const item of iterator) {
|
|
113
|
+
const validated = validateOutput(schema, item);
|
|
114
|
+
yield isThenable(validated) ? await validated : validated;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
36
117
|
function createFail(errors) {
|
|
37
118
|
return (code, data) => {
|
|
38
119
|
const def = errors[code];
|
|
@@ -143,49 +224,31 @@ function selectGuardRunner(guards) {
|
|
|
143
224
|
if (guards.length === 0) return void 0;
|
|
144
225
|
return (ctx) => runGuardsSequential(ctx, guards);
|
|
145
226
|
}
|
|
146
|
-
/** Call resolve, then validate output (sync-first, async fallback) */
|
|
147
|
-
/**
|
|
148
|
-
* Call the resolver, then validate the output. Stays sync when the
|
|
149
|
-
* resolver is sync and there is no output schema; switches to
|
|
150
|
-
* `.then()` chaining only once an async boundary appears.
|
|
151
|
-
*/
|
|
152
|
-
function resolveWithOutput(resolveFn, input, ctx, failFn, signal, outputSchema) {
|
|
153
|
-
const output = resolveFn({
|
|
154
|
-
input,
|
|
155
|
-
ctx,
|
|
156
|
-
fail: failFn,
|
|
157
|
-
signal,
|
|
158
|
-
params: ctx.params ?? EMPTY_PARAMS
|
|
159
|
-
});
|
|
160
|
-
if (!outputSchema) return output;
|
|
161
|
-
if (isThenable(output)) return output.then((o) => validateSchema(outputSchema, o));
|
|
162
|
-
return validateSchema(outputSchema, output);
|
|
163
|
-
}
|
|
164
227
|
/**
|
|
165
|
-
*
|
|
228
|
+
* Compile a procedure into its request handler.
|
|
166
229
|
*
|
|
167
|
-
*
|
|
168
|
-
*
|
|
169
|
-
*
|
|
170
|
-
*
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
const input = inputSchema ? validateSchema(inputSchema, rawInput ?? {}) : rawInput;
|
|
175
|
-
if (isThenable(input)) return input.then((resolvedInput) => resolveWithOutput(resolveFn, resolvedInput, ctx, failFn, signal, outputSchema));
|
|
176
|
-
return resolveWithOutput(resolveFn, input, ctx, failFn, signal, outputSchema);
|
|
177
|
-
} catch (e) {
|
|
178
|
-
return Promise.reject(e);
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
/**
|
|
182
|
-
* Compile a procedure into the fastest possible handler.
|
|
230
|
+
* The generated handler is built as two nested onions:
|
|
231
|
+
*
|
|
232
|
+
* root-wrap onion (outer)
|
|
233
|
+
* └─ guards → input validation → procedure-wrap onion → resolver
|
|
234
|
+
* → output validation (inner)
|
|
235
|
+
*
|
|
236
|
+
* The *inner* handler still selects one of three shapes up front:
|
|
183
237
|
*
|
|
184
|
-
*
|
|
185
|
-
*
|
|
186
|
-
* -
|
|
187
|
-
*
|
|
188
|
-
*
|
|
238
|
+
* - fully sync fast-path when there are no procedure wraps and no
|
|
239
|
+
* input/output schemas;
|
|
240
|
+
* - semi-sync when validation is present but no procedure wraps;
|
|
241
|
+
* - full async onion when any procedure wrap is attached.
|
|
242
|
+
*
|
|
243
|
+
* The *outer* handler is only built when `rootWraps` is non-empty.
|
|
244
|
+
* When no root wraps are configured we return the inner handler as
|
|
245
|
+
* is — zero extra closures per request, every fast-path preserved.
|
|
246
|
+
*
|
|
247
|
+
* @param procedure The procedure definition to compile.
|
|
248
|
+
* @param rootWraps Instance-level wraps (from `silgi({ wraps })`).
|
|
249
|
+
* These wrap the *whole* inner pipeline, including
|
|
250
|
+
* guards — that is the contract documented on
|
|
251
|
+
* `SilgiConfig.wraps` (issue #14).
|
|
189
252
|
*/
|
|
190
253
|
function compileProcedure(procedure, rootWraps) {
|
|
191
254
|
const middlewares = procedure.use ?? [];
|
|
@@ -198,6 +261,7 @@ function compileProcedure(procedure, rootWraps) {
|
|
|
198
261
|
const inputSchema = procedure.input;
|
|
199
262
|
const outputSchema = procedure.output;
|
|
200
263
|
const resolveFn = procedure.resolve;
|
|
264
|
+
const isSubscription = procedure.type === "subscription";
|
|
201
265
|
let mergedErrors = procedure.errors;
|
|
202
266
|
for (const guard of guards) if (guard.errors) mergedErrors = mergedErrors ? {
|
|
203
267
|
...mergedErrors,
|
|
@@ -205,43 +269,14 @@ function compileProcedure(procedure, rootWraps) {
|
|
|
205
269
|
} : guard.errors;
|
|
206
270
|
const failFn = mergedErrors ? createFail(mergedErrors) : noopFail;
|
|
207
271
|
const runGuards = selectGuardRunner(guards);
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
if (guardResult && isThenable(guardResult)) return guardResult.then(() => resolveFn({
|
|
213
|
-
input: rawInput,
|
|
214
|
-
ctx,
|
|
215
|
-
fail: failFn,
|
|
216
|
-
signal,
|
|
217
|
-
params: ctx.params ?? EMPTY_PARAMS
|
|
218
|
-
}));
|
|
219
|
-
return resolveFn({
|
|
220
|
-
input: rawInput,
|
|
221
|
-
ctx,
|
|
222
|
-
fail: failFn,
|
|
223
|
-
signal,
|
|
224
|
-
params: ctx.params ?? EMPTY_PARAMS
|
|
225
|
-
});
|
|
226
|
-
} catch (e) {
|
|
227
|
-
return Promise.reject(e);
|
|
272
|
+
const innerHandler = async (ctx, rawInput, signal) => {
|
|
273
|
+
if (runGuards) {
|
|
274
|
+
const guardResult = runGuards(ctx);
|
|
275
|
+
if (guardResult && isThenable(guardResult)) await guardResult;
|
|
228
276
|
}
|
|
229
|
-
};
|
|
230
|
-
else if (procedureWraps.length === 0) innerHandler = (ctx, rawInput, signal) => {
|
|
231
|
-
try {
|
|
232
|
-
const guardResult = runGuards?.(ctx);
|
|
233
|
-
if (guardResult && isThenable(guardResult)) return guardResult.then(() => validateAndResolve(inputSchema, outputSchema, resolveFn, rawInput, ctx, failFn, signal));
|
|
234
|
-
return validateAndResolve(inputSchema, outputSchema, resolveFn, rawInput, ctx, failFn, signal);
|
|
235
|
-
} catch (e) {
|
|
236
|
-
return Promise.reject(e);
|
|
237
|
-
}
|
|
238
|
-
};
|
|
239
|
-
else innerHandler = async (ctx, rawInput, signal) => {
|
|
240
|
-
const guardResult = runGuards?.(ctx);
|
|
241
|
-
if (guardResult && isThenable(guardResult)) await guardResult;
|
|
242
277
|
let input;
|
|
243
278
|
if (inputSchema) {
|
|
244
|
-
const validated =
|
|
279
|
+
const validated = validateInput(inputSchema, rawInput ?? {});
|
|
245
280
|
input = isThenable(validated) ? await validated : validated;
|
|
246
281
|
} else input = rawInput;
|
|
247
282
|
ctx[RAW_INPUT] = input;
|
|
@@ -262,12 +297,13 @@ function compileProcedure(procedure, rootWraps) {
|
|
|
262
297
|
}
|
|
263
298
|
const output = await execute();
|
|
264
299
|
if (!outputSchema) return output;
|
|
265
|
-
|
|
300
|
+
if (isSubscription && output && typeof output === "object" && Symbol.asyncIterator in output) return validateIteratorOutput(output, outputSchema);
|
|
301
|
+
const validated = validateOutput(outputSchema, output);
|
|
266
302
|
return isThenable(validated) ? await validated : validated;
|
|
267
303
|
};
|
|
268
304
|
if (!hasRootWraps) return innerHandler;
|
|
269
305
|
return async (ctx, rawInput, signal) => {
|
|
270
|
-
let execute =
|
|
306
|
+
let execute = () => Promise.resolve(innerHandler(ctx, rawInput, signal));
|
|
271
307
|
for (let i = rootWrapList.length - 1; i >= 0; i--) {
|
|
272
308
|
const wrapFn = rootWrapList[i].fn;
|
|
273
309
|
const next = execute;
|
|
@@ -310,48 +346,30 @@ function compileRouter(def) {
|
|
|
310
346
|
return (method, path) => findRoute(router, method, path);
|
|
311
347
|
}
|
|
312
348
|
/**
|
|
313
|
-
*
|
|
349
|
+
* Allocate a fresh pipeline context.
|
|
314
350
|
*
|
|
315
|
-
*
|
|
316
|
-
*
|
|
317
|
-
*
|
|
318
|
-
* to prevent unbounded growth under burst traffic.
|
|
351
|
+
* The object has a `null` prototype so user-supplied keys cannot
|
|
352
|
+
* accidentally shadow `Object.prototype` members and property lookups
|
|
353
|
+
* stay on the object itself.
|
|
319
354
|
*
|
|
320
|
-
*
|
|
321
|
-
*
|
|
322
|
-
*
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
*
|
|
328
|
-
*
|
|
329
|
-
*
|
|
330
|
-
*
|
|
355
|
+
* A `Symbol.dispose` slot is attached so `using ctx = createContext()`
|
|
356
|
+
* runs `releaseContext(ctx)` at scope exit. Streaming responses that
|
|
357
|
+
* outlive the handler scope swap that slot for a no-op via
|
|
358
|
+
* `detachContext` and take ownership.
|
|
359
|
+
*
|
|
360
|
+
* This used to draw from a recycled pool. The pool has been removed —
|
|
361
|
+
* the win was marginal, the indirection was loud, and the tests that
|
|
362
|
+
* pinned "pool readback" behaviour were observing an implementation
|
|
363
|
+
* detail, not a user-visible guarantee. The public API
|
|
364
|
+
* (`createContext` / `detachContext` / `releaseContext` /
|
|
365
|
+
* `PooledContext`) is preserved so existing call sites keep working;
|
|
366
|
+
* only the internals changed.
|
|
331
367
|
*/
|
|
332
368
|
function createContext() {
|
|
333
|
-
const ctx =
|
|
369
|
+
const ctx = Object.create(null);
|
|
334
370
|
ctx[Symbol.dispose] = disposeContext;
|
|
335
371
|
return ctx;
|
|
336
372
|
}
|
|
337
|
-
function disposeContext() {
|
|
338
|
-
releaseContext(this);
|
|
339
|
-
}
|
|
340
|
-
/**
|
|
341
|
-
* Release a context. Called automatically at `using` scope exit and
|
|
342
|
-
* explicitly by stream handlers when their stream ends.
|
|
343
|
-
*
|
|
344
|
-
* With the pool gone the object itself will be GC'd as soon as its
|
|
345
|
-
* last reference drops, but we still wipe its properties here.
|
|
346
|
-
* Callers (and tests) use "properties were cleared" as the observable
|
|
347
|
-
* signal that release ran exactly once — notably
|
|
348
|
-
* `test/core/context-release.test.ts` tags a context before handing
|
|
349
|
-
* it off and checks the tag is gone once the request completes.
|
|
350
|
-
*/
|
|
351
|
-
function releaseContext(ctx) {
|
|
352
|
-
for (const key of Object.keys(ctx)) delete ctx[key];
|
|
353
|
-
for (const sym of Object.getOwnPropertySymbols(ctx)) delete ctx[sym];
|
|
354
|
-
if (CTX_POOL.length < CTX_POOL_MAX) CTX_POOL.push(ctx);
|
|
355
|
-
}
|
|
373
|
+
function disposeContext() {}
|
|
356
374
|
//#endregion
|
|
357
375
|
export { compileProcedure, compileRouter, createContext };
|
package/dist/core/schema.d.mts
CHANGED
|
@@ -13,8 +13,21 @@ declare class ValidationError extends Error {
|
|
|
13
13
|
issues: readonly SchemaIssue[];
|
|
14
14
|
});
|
|
15
15
|
}
|
|
16
|
+
/**
|
|
17
|
+
* Thrown when a Standard Schema validator itself crashes (e.g. a
|
|
18
|
+
* misconstructed Zod v4 schema). Distinct from `ValidationError` —
|
|
19
|
+
* the *schema* is broken, not the value. `cause` holds the original
|
|
20
|
+
* throw. Only observable on direct `validateSchema()` calls; the
|
|
21
|
+
* pipeline rebrands these as `SilgiError` with `cause` preserved.
|
|
22
|
+
*/
|
|
23
|
+
declare class SchemaValidatorCrash extends Error {
|
|
24
|
+
constructor(options: {
|
|
25
|
+
message?: string;
|
|
26
|
+
cause: unknown;
|
|
27
|
+
});
|
|
28
|
+
}
|
|
16
29
|
/** Sync fast-path: Zod 4 validate() returns sync result — avoid Promise allocation */
|
|
17
30
|
declare function validateSchema(schema: AnySchema, value: unknown): unknown;
|
|
18
31
|
declare function type<TInput, TOutput = TInput>(...args: TInput extends TOutput ? TOutput extends TInput ? [map?: (input: TInput) => TOutput] : [map: (input: TInput) => TOutput] : [map: (input: TInput) => TOutput]): Schema<TInput, TOutput>;
|
|
19
32
|
//#endregion
|
|
20
|
-
export { AnySchema, InferSchemaInput, InferSchemaOutput, Schema, ValidationError, type, validateSchema };
|
|
33
|
+
export { AnySchema, InferSchemaInput, InferSchemaOutput, Schema, SchemaValidatorCrash, ValidationError, type, validateSchema };
|
package/dist/core/schema.mjs
CHANGED
|
@@ -7,9 +7,27 @@ var ValidationError = class extends Error {
|
|
|
7
7
|
this.issues = options.issues;
|
|
8
8
|
}
|
|
9
9
|
};
|
|
10
|
+
/**
|
|
11
|
+
* Thrown when a Standard Schema validator itself crashes (e.g. a
|
|
12
|
+
* misconstructed Zod v4 schema). Distinct from `ValidationError` —
|
|
13
|
+
* the *schema* is broken, not the value. `cause` holds the original
|
|
14
|
+
* throw. Only observable on direct `validateSchema()` calls; the
|
|
15
|
+
* pipeline rebrands these as `SilgiError` with `cause` preserved.
|
|
16
|
+
*/
|
|
17
|
+
var SchemaValidatorCrash = class extends Error {
|
|
18
|
+
constructor(options) {
|
|
19
|
+
super(options.message ?? "Schema validator crashed", { cause: options.cause });
|
|
20
|
+
this.name = "SchemaValidatorCrash";
|
|
21
|
+
}
|
|
22
|
+
};
|
|
10
23
|
/** Sync fast-path: Zod 4 validate() returns sync result — avoid Promise allocation */
|
|
11
24
|
function validateSchema(schema, value) {
|
|
12
|
-
|
|
25
|
+
let result;
|
|
26
|
+
try {
|
|
27
|
+
result = schema["~standard"].validate(value);
|
|
28
|
+
} catch (e) {
|
|
29
|
+
throw new SchemaValidatorCrash({ cause: e });
|
|
30
|
+
}
|
|
13
31
|
if (typeof result?.then !== "function") {
|
|
14
32
|
if ("issues" in result && result.issues) throw new ValidationError({ issues: result.issues });
|
|
15
33
|
return result.value;
|
|
@@ -17,6 +35,8 @@ function validateSchema(schema, value) {
|
|
|
17
35
|
return result.then((r) => {
|
|
18
36
|
if ("issues" in r && r.issues) throw new ValidationError({ issues: r.issues });
|
|
19
37
|
return r.value;
|
|
38
|
+
}, (e) => {
|
|
39
|
+
throw new SchemaValidatorCrash({ cause: e });
|
|
20
40
|
});
|
|
21
41
|
}
|
|
22
42
|
function type(...args) {
|
|
@@ -30,4 +50,4 @@ function type(...args) {
|
|
|
30
50
|
} };
|
|
31
51
|
}
|
|
32
52
|
//#endregion
|
|
33
|
-
export { ValidationError, type, validateSchema };
|
|
53
|
+
export { SchemaValidatorCrash, ValidationError, type, validateSchema };
|
package/dist/core/sse.mjs
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { SilgiError } from "./error.mjs";
|
|
2
|
+
import { AsyncIteratorClass } from "./iterator.mjs";
|
|
2
3
|
//#region src/core/sse.ts
|
|
3
4
|
/**
|
|
4
5
|
* Server-Sent Events
|
|
@@ -60,6 +61,74 @@ function encodeEventMessage(msg) {
|
|
|
60
61
|
return lines.join("\n") + "\n\n";
|
|
61
62
|
}
|
|
62
63
|
/**
|
|
64
|
+
* Incremental SSE decoder for chunked text input.
|
|
65
|
+
*
|
|
66
|
+
* Feed it text as it arrives from the network; it emits a full
|
|
67
|
+
* `EventMessage` through the `onEvent` callback once it has seen a
|
|
68
|
+
* blank-line terminator. The trailing partial event (if any) is held
|
|
69
|
+
* over until the next `feed()` call — or flushed explicitly on stream
|
|
70
|
+
* end via `flush()`.
|
|
71
|
+
*/
|
|
72
|
+
var EventDecoder = class {
|
|
73
|
+
#partial = "";
|
|
74
|
+
#onEvent;
|
|
75
|
+
constructor(onEvent) {
|
|
76
|
+
this.#onEvent = onEvent;
|
|
77
|
+
}
|
|
78
|
+
feed(chunk) {
|
|
79
|
+
this.#partial += chunk;
|
|
80
|
+
const blocks = this.#partial.split("\n\n");
|
|
81
|
+
this.#partial = blocks.pop() ?? "";
|
|
82
|
+
for (const block of blocks) {
|
|
83
|
+
if (!block.trim()) continue;
|
|
84
|
+
const msg = this.#parseBlock(block);
|
|
85
|
+
if (msg) this.#onEvent(msg);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
/** Parse any remaining partial block. Call once at end-of-stream. */
|
|
89
|
+
flush() {
|
|
90
|
+
if (this.#partial.trim()) {
|
|
91
|
+
const msg = this.#parseBlock(this.#partial);
|
|
92
|
+
if (msg) this.#onEvent(msg);
|
|
93
|
+
this.#partial = "";
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
#parseBlock(block) {
|
|
97
|
+
const msg = {};
|
|
98
|
+
let hasContent = false;
|
|
99
|
+
for (const line of block.split("\n")) {
|
|
100
|
+
if (line.startsWith(":")) {
|
|
101
|
+
msg.comment = (msg.comment ? msg.comment + "\n" : "") + line.slice(2);
|
|
102
|
+
hasContent = true;
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
const colon = line.indexOf(":");
|
|
106
|
+
if (colon === -1) continue;
|
|
107
|
+
const field = line.slice(0, colon);
|
|
108
|
+
const value = line.slice(colon + 1).trimStart();
|
|
109
|
+
switch (field) {
|
|
110
|
+
case "event":
|
|
111
|
+
msg.event = value;
|
|
112
|
+
hasContent = true;
|
|
113
|
+
break;
|
|
114
|
+
case "data":
|
|
115
|
+
msg.data = (msg.data ? msg.data + "\n" : "") + value;
|
|
116
|
+
hasContent = true;
|
|
117
|
+
break;
|
|
118
|
+
case "id":
|
|
119
|
+
msg.id = value;
|
|
120
|
+
hasContent = true;
|
|
121
|
+
break;
|
|
122
|
+
case "retry":
|
|
123
|
+
msg.retry = parseInt(value, 10);
|
|
124
|
+
hasContent = true;
|
|
125
|
+
break;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
return hasContent ? msg : null;
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
/**
|
|
63
132
|
* Build an SSE `ReadableStream` that consumes an async iterator.
|
|
64
133
|
*
|
|
65
134
|
* Each yielded value becomes a `message` event; the iterator's return
|
|
@@ -146,5 +215,102 @@ function iteratorToEventStream(iterator, options = {}) {
|
|
|
146
215
|
}
|
|
147
216
|
}).pipeThrough(new TextEncoderStream());
|
|
148
217
|
}
|
|
218
|
+
/**
|
|
219
|
+
* Turn an SSE `ReadableStream` back into an async iterator.
|
|
220
|
+
*
|
|
221
|
+
* `message` events → yielded values (deserialized)
|
|
222
|
+
* `error` events → thrown exceptions
|
|
223
|
+
* `done` event → normal iterator completion
|
|
224
|
+
*
|
|
225
|
+
* The decoder runs on its own microtask loop, buffering decoded events
|
|
226
|
+
* into a queue that `next()` drains. The queue is needed because the
|
|
227
|
+
* network read loop and the consumer run at different cadences.
|
|
228
|
+
*/
|
|
229
|
+
function eventStreamToIterator(stream, options = {}) {
|
|
230
|
+
const deserialize = options.deserialize ?? ((d) => JSON.parse(d));
|
|
231
|
+
const decodedStream = stream.pipeThrough(new TextDecoderStream());
|
|
232
|
+
const reader = decodedStream.getReader();
|
|
233
|
+
const events = [];
|
|
234
|
+
let wakeUp;
|
|
235
|
+
let done = false;
|
|
236
|
+
let error;
|
|
237
|
+
const decoder = new EventDecoder((msg) => {
|
|
238
|
+
events.push(msg);
|
|
239
|
+
wakeUp?.();
|
|
240
|
+
wakeUp = void 0;
|
|
241
|
+
});
|
|
242
|
+
/** Background reader — drains `stream` into `decoder` until end/err. */
|
|
243
|
+
const readLoop = async () => {
|
|
244
|
+
try {
|
|
245
|
+
while (true) {
|
|
246
|
+
const { done: readerDone, value } = await reader.read();
|
|
247
|
+
if (readerDone) {
|
|
248
|
+
decoder.flush();
|
|
249
|
+
done = true;
|
|
250
|
+
wakeUp?.();
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
253
|
+
decoder.feed(value);
|
|
254
|
+
}
|
|
255
|
+
} catch (err) {
|
|
256
|
+
done = true;
|
|
257
|
+
error = err instanceof Error ? err : new Error(String(err));
|
|
258
|
+
wakeUp?.();
|
|
259
|
+
}
|
|
260
|
+
};
|
|
261
|
+
readLoop();
|
|
262
|
+
/** Wait until either a new event lands or the stream ends. */
|
|
263
|
+
const waitForEvent = () => new Promise((resolve) => {
|
|
264
|
+
wakeUp = resolve;
|
|
265
|
+
});
|
|
266
|
+
/** Translate one decoded `EventMessage` into an iterator step. */
|
|
267
|
+
const interpret = (msg) => {
|
|
268
|
+
switch (msg.event) {
|
|
269
|
+
case "message": {
|
|
270
|
+
const value = msg.data ? deserialize(msg.data) : void 0;
|
|
271
|
+
return {
|
|
272
|
+
done: false,
|
|
273
|
+
value: msg.id || msg.retry ? withEventMeta(value, {
|
|
274
|
+
id: msg.id,
|
|
275
|
+
retry: msg.retry
|
|
276
|
+
}) : value
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
case "error": {
|
|
280
|
+
const payload = msg.data ? JSON.parse(msg.data) : {};
|
|
281
|
+
throw new Error(payload.message ?? "Stream error");
|
|
282
|
+
}
|
|
283
|
+
case "done": return {
|
|
284
|
+
done: true,
|
|
285
|
+
value: void 0
|
|
286
|
+
};
|
|
287
|
+
default: return "skip";
|
|
288
|
+
}
|
|
289
|
+
};
|
|
290
|
+
return new AsyncIteratorClass(async () => {
|
|
291
|
+
while (true) {
|
|
292
|
+
if (events.length > 0) {
|
|
293
|
+
const step = interpret(events.shift());
|
|
294
|
+
if (step !== "skip") return step;
|
|
295
|
+
continue;
|
|
296
|
+
}
|
|
297
|
+
if (done) {
|
|
298
|
+
if (error) throw error;
|
|
299
|
+
return {
|
|
300
|
+
done: true,
|
|
301
|
+
value: void 0
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
await waitForEvent();
|
|
305
|
+
}
|
|
306
|
+
}, async () => {
|
|
307
|
+
try {
|
|
308
|
+
await decodedStream.cancel();
|
|
309
|
+
} catch {}
|
|
310
|
+
try {
|
|
311
|
+
reader.releaseLock();
|
|
312
|
+
} catch {}
|
|
313
|
+
});
|
|
314
|
+
}
|
|
149
315
|
//#endregion
|
|
150
|
-
export { encodeEventMessage, getEventMeta, iteratorToEventStream, withEventMeta };
|
|
316
|
+
export { encodeEventMessage, eventStreamToIterator, getEventMeta, iteratorToEventStream, withEventMeta };
|
package/dist/index.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AnySchema, InferSchemaInput, InferSchemaOutput, Schema, ValidationError, type, validateSchema } from "./core/schema.mjs";
|
|
1
|
+
import { AnySchema, InferSchemaInput, InferSchemaOutput, Schema, SchemaValidatorCrash, ValidationError, type, validateSchema } from "./core/schema.mjs";
|
|
2
2
|
import { CronRegistry, ScheduledTaskInfo, TaskDef, TaskEvent, collectCronTasks, createCronRegistry, getScheduledTasks, runTask, setTaskAnalytics, startCronJobs, stopCronJobs } from "./core/task.mjs";
|
|
3
3
|
import { ErrorDef, ErrorDefItem, FailFn, GuardDef, GuardFn, InferClient, InferContextFromUse, InferGuardOutput, Meta, MiddlewareDef, ProcedureDef, ProcedureType, ResolveContext, RouterDef, WrapDef, WrapFn } from "./types.mjs";
|
|
4
4
|
import { ConvertOptions, JSONSchema, SchemaConverter, SchemaRegistry, createSchemaRegistry, schemaToJsonSchema } from "./core/schema-converter.mjs";
|
|
@@ -18,4 +18,4 @@ import { mapInput } from "./map-input.mjs";
|
|
|
18
18
|
import { compileProcedure, compileRouter, createContext } from "./compile.mjs";
|
|
19
19
|
import { ProcedureSummary, collectProcedures, getProcedurePaths, isProcedureDef } from "./core/router-utils.mjs";
|
|
20
20
|
import { LazyRouter, isLazy, lazy, resolveLazy } from "./lazy.mjs";
|
|
21
|
-
export { type AnySchema, AsyncIteratorClass, type BaseContext, type CallableOptions, type ContextBridge, type ConvertOptions, type CronRegistry, type Driver, type ErrorDef, type ErrorDefItem, type EventMeta, type FailFn, type GuardDef, type GuardFn, type InferClient, type InferContextFromUse, type InferGuardOutput, type InferSchemaInput, type InferSchemaOutput, type JSONSchema, type LazyRouter, type LifecycleHooks, type Meta, type MiddlewareDef, type ProcedureBuilder, type ProcedureBuilderWithOutput, type ProcedureDef, type ProcedureSummary, type ProcedureType, type ResolveContext, type RouterDef, type ScalarOptions, type ScheduledTaskInfo, type Schema, type SchemaConverter, type SchemaRegistry, type ServeOptions, type SilgiConfig, SilgiError, type SilgiErrorCode, type SilgiErrorJSON, type SilgiErrorOptions, type SilgiInstance, type SilgiServer, type Storage, type StorageConfig, type StorageValue, type TaskDef, type TaskEvent, ValidationError, type WrapDef, type WrapFn, callable, collectCronTasks, collectProcedures, compileProcedure, compileRouter, createContext, createContextBridge, createCronRegistry, createSchemaRegistry, generateOpenAPI, getEventMeta, getProcedurePaths, getScheduledTasks, initStorage, isDefinedError, isLazy, isProcedureDef, isSilgiError, lazy, lifecycleWrap, mapAsyncIterator, mapInput, resetStorage, resolveLazy, runTask, scalarHTML, schemaToJsonSchema, setTaskAnalytics, silgi, startCronJobs, stopCronJobs, toSilgiError, type, useStorage, validateSchema, withEventMeta };
|
|
21
|
+
export { type AnySchema, AsyncIteratorClass, type BaseContext, type CallableOptions, type ContextBridge, type ConvertOptions, type CronRegistry, type Driver, type ErrorDef, type ErrorDefItem, type EventMeta, type FailFn, type GuardDef, type GuardFn, type InferClient, type InferContextFromUse, type InferGuardOutput, type InferSchemaInput, type InferSchemaOutput, type JSONSchema, type LazyRouter, type LifecycleHooks, type Meta, type MiddlewareDef, type ProcedureBuilder, type ProcedureBuilderWithOutput, type ProcedureDef, type ProcedureSummary, type ProcedureType, type ResolveContext, type RouterDef, type ScalarOptions, type ScheduledTaskInfo, type Schema, type SchemaConverter, type SchemaRegistry, SchemaValidatorCrash, type ServeOptions, type SilgiConfig, SilgiError, type SilgiErrorCode, type SilgiErrorJSON, type SilgiErrorOptions, type SilgiInstance, type SilgiServer, type Storage, type StorageConfig, type StorageValue, type TaskDef, type TaskEvent, ValidationError, type WrapDef, type WrapFn, callable, collectCronTasks, collectProcedures, compileProcedure, compileRouter, createContext, createContextBridge, createCronRegistry, createSchemaRegistry, generateOpenAPI, getEventMeta, getProcedurePaths, getScheduledTasks, initStorage, isDefinedError, isLazy, isProcedureDef, isSilgiError, lazy, lifecycleWrap, mapAsyncIterator, mapInput, resetStorage, resolveLazy, runTask, scalarHTML, schemaToJsonSchema, setTaskAnalytics, silgi, startCronJobs, stopCronJobs, toSilgiError, type, useStorage, validateSchema, withEventMeta };
|
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ValidationError, type, validateSchema } from "./core/schema.mjs";
|
|
1
|
+
import { SchemaValidatorCrash, ValidationError, type, validateSchema } from "./core/schema.mjs";
|
|
2
2
|
import { collectCronTasks, createCronRegistry, getScheduledTasks, runTask, setTaskAnalytics, startCronJobs, stopCronJobs } from "./core/task.mjs";
|
|
3
3
|
import { SilgiError, isDefinedError, isSilgiError, toSilgiError } from "./core/error.mjs";
|
|
4
4
|
import { collectProcedures, getProcedurePaths, isProcedureDef } from "./core/router-utils.mjs";
|
|
@@ -14,4 +14,4 @@ import { mapInput } from "./map-input.mjs";
|
|
|
14
14
|
import { isLazy, lazy, resolveLazy } from "./lazy.mjs";
|
|
15
15
|
import { initStorage, resetStorage, useStorage } from "./core/storage.mjs";
|
|
16
16
|
import { generateOpenAPI, scalarHTML } from "./scalar.mjs";
|
|
17
|
-
export { AsyncIteratorClass, SilgiError, ValidationError, callable, collectCronTasks, collectProcedures, compileProcedure, compileRouter, createContext, createContextBridge, createCronRegistry, createSchemaRegistry, generateOpenAPI, getEventMeta, getProcedurePaths, getScheduledTasks, initStorage, isDefinedError, isLazy, isProcedureDef, isSilgiError, lazy, lifecycleWrap, mapAsyncIterator, mapInput, resetStorage, resolveLazy, runTask, scalarHTML, schemaToJsonSchema, setTaskAnalytics, silgi, startCronJobs, stopCronJobs, toSilgiError, type, useStorage, validateSchema, withEventMeta };
|
|
17
|
+
export { AsyncIteratorClass, SchemaValidatorCrash, SilgiError, ValidationError, callable, collectCronTasks, collectProcedures, compileProcedure, compileRouter, createContext, createContextBridge, createCronRegistry, createSchemaRegistry, generateOpenAPI, getEventMeta, getProcedurePaths, getScheduledTasks, initStorage, isDefinedError, isLazy, isProcedureDef, isSilgiError, lazy, lifecycleWrap, mapAsyncIterator, mapInput, resetStorage, resolveLazy, runTask, scalarHTML, schemaToJsonSchema, setTaskAnalytics, silgi, startCronJobs, stopCronJobs, toSilgiError, type, useStorage, validateSchema, withEventMeta };
|