silgi 0.51.6 → 0.51.8
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 +47 -0
- package/dist/adapters/_fetch-adapter.d.mts +6 -0
- package/dist/adapters/_fetch-adapter.mjs +14 -8
- package/dist/adapters/astro.mjs +1 -1
- package/dist/adapters/nextjs.mjs +1 -1
- package/dist/adapters/remix.mjs +1 -1
- package/dist/adapters/solidstart.mjs +1 -1
- package/dist/adapters/sveltekit.mjs +1 -1
- package/dist/client/client.d.mts +42 -4
- package/dist/client/client.mjs +42 -4
- package/dist/client/server.d.mts +27 -2
- package/dist/client/server.mjs +27 -2
- package/dist/compile.d.mts +10 -1
- package/dist/compile.mjs +13 -4
- package/dist/core/context-bridge.d.mts +49 -0
- package/dist/core/context-bridge.mjs +43 -7
- package/dist/core/context.d.mts +26 -0
- package/dist/core/ctx-symbols.mjs +21 -0
- package/dist/core/error.d.mts +183 -2
- package/dist/core/error.mjs +259 -16
- package/dist/core/handler.d.mts +15 -1
- package/dist/core/handler.mjs +33 -17
- package/dist/core/schema-converter.d.mts +131 -0
- package/dist/core/schema-converter.mjs +82 -0
- package/dist/core/serve.d.mts +2 -2
- package/dist/core/serve.mjs +9 -2
- package/dist/core/task.mjs +2 -2
- package/dist/index.d.mts +5 -2
- package/dist/index.mjs +4 -2
- package/dist/integrations/better-auth/index.d.mts +22 -1
- package/dist/integrations/better-auth/index.mjs +79 -11
- package/dist/integrations/drizzle/index.mjs +22 -5
- package/dist/integrations/zod/converter.d.mts +1 -1
- package/dist/integrations/zod/index.d.mts +29 -2
- package/dist/integrations/zod/index.mjs +60 -1
- package/dist/lazy.d.mts +40 -3
- package/dist/lazy.mjs +40 -3
- package/dist/map-input.mjs +1 -1
- package/dist/plugins/analytics/collector.d.mts +1 -1
- package/dist/plugins/analytics/trace.mjs +1 -1
- package/dist/plugins/analytics/types.d.mts +3 -3
- package/dist/plugins/analytics/utils.mjs +1 -4
- package/dist/plugins/analytics.d.mts +5 -3
- package/dist/plugins/analytics.mjs +16 -29
- package/dist/plugins/cache.mjs +1 -1
- package/dist/plugins/coerce.mjs +1 -1
- package/dist/scalar.d.mts +2 -1
- package/dist/scalar.mjs +9 -30
- package/dist/silgi.d.mts +165 -18
- package/dist/silgi.mjs +50 -12
- package/package.json +7 -3
- package/dist/core/trace-map.d.mts +0 -13
- package/dist/core/trace-map.mjs +0 -13
package/dist/core/handler.mjs
CHANGED
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
import { routerCache } from "./router-utils.mjs";
|
|
2
|
-
import { compileRouter, createContext, releaseContext } from "../compile.mjs";
|
|
2
|
+
import { compileRouter, createContext, detachContext, releaseContext } from "../compile.mjs";
|
|
3
3
|
import { applyContext } from "./dispatch.mjs";
|
|
4
4
|
import { detectResponseFormat, encodeResponse, makeErrorResponse } from "./codec.mjs";
|
|
5
|
-
import { runWithCtx } from "./context-bridge.mjs";
|
|
6
5
|
import { parseInput } from "./input.mjs";
|
|
7
6
|
import { iteratorToEventStream } from "./sse.mjs";
|
|
8
|
-
import { analyticsTraceMap } from "./trace-map.mjs";
|
|
9
7
|
import { parseUrlPath } from "./url.mjs";
|
|
10
8
|
//#region src/core/handler.ts
|
|
11
9
|
/**
|
|
@@ -46,20 +44,25 @@ function wrapStreamWithRelease(source, ctx) {
|
|
|
46
44
|
}
|
|
47
45
|
});
|
|
48
46
|
}
|
|
47
|
+
/**
|
|
48
|
+
* Build the Response for a handler's output. The pooled `ctx` is released
|
|
49
|
+
* by the caller's `using` scope; for streaming outputs we detach `ctx` first
|
|
50
|
+
* so the stream becomes the sole owner (releases on stream end/cancel).
|
|
51
|
+
*/
|
|
49
52
|
function makeResponse(output, route, format, ctx) {
|
|
50
|
-
if (output instanceof Response)
|
|
51
|
-
|
|
52
|
-
|
|
53
|
+
if (output instanceof Response) return output;
|
|
54
|
+
if (output instanceof ReadableStream) {
|
|
55
|
+
detachContext(ctx);
|
|
56
|
+
return new Response(wrapStreamWithRelease(output, ctx), { headers: { "content-type": "application/octet-stream" } });
|
|
53
57
|
}
|
|
54
|
-
if (output instanceof ReadableStream) return new Response(wrapStreamWithRelease(output, ctx), { headers: { "content-type": "application/octet-stream" } });
|
|
55
58
|
if (output && typeof output === "object" && Symbol.asyncIterator in output) {
|
|
59
|
+
detachContext(ctx);
|
|
56
60
|
const stream = iteratorToEventStream(output);
|
|
57
61
|
return new Response(wrapStreamWithRelease(stream, ctx), { headers: {
|
|
58
62
|
"content-type": "text/event-stream",
|
|
59
63
|
"cache-control": "no-cache"
|
|
60
64
|
} });
|
|
61
65
|
}
|
|
62
|
-
releaseContext(ctx);
|
|
63
66
|
const cacheHeaders = route.cacheControl ? { "cache-control": route.cacheControl } : void 0;
|
|
64
67
|
if (format !== "json") return encodeResponse(output, 200, format, cacheHeaders);
|
|
65
68
|
return new Response(JSON.stringify(output), { headers: cacheHeaders ? {
|
|
@@ -81,12 +84,11 @@ function wrapHandler(handler, router, options, prefix) {
|
|
|
81
84
|
if (options.scalar) {
|
|
82
85
|
const { wrapWithScalar } = await import("../scalar.mjs");
|
|
83
86
|
const scalarOpts = typeof options.scalar === "object" ? options.scalar : {};
|
|
84
|
-
h = wrapWithScalar(h, router, scalarOpts, prefix);
|
|
87
|
+
h = wrapWithScalar(h, router, scalarOpts, prefix, options.schemaRegistry);
|
|
85
88
|
}
|
|
86
89
|
if (options.analytics) {
|
|
87
90
|
const { wrapWithAnalytics } = await import("../plugins/analytics.mjs");
|
|
88
|
-
|
|
89
|
-
h = wrapWithAnalytics(h, router, analyticsOpts);
|
|
91
|
+
h = wrapWithAnalytics(h, router, options.analytics, options.schemaRegistry, options.hooks);
|
|
90
92
|
}
|
|
91
93
|
wrapped = h;
|
|
92
94
|
}
|
|
@@ -96,7 +98,7 @@ function wrapHandler(handler, router, options, prefix) {
|
|
|
96
98
|
return initPromise.then(() => wrapped(request));
|
|
97
99
|
};
|
|
98
100
|
}
|
|
99
|
-
function createFetchHandler(routerDef, contextFactory, hooks, prefix) {
|
|
101
|
+
function createFetchHandler(routerDef, contextFactory, hooks, prefix, bridge) {
|
|
100
102
|
let compiledRouter = routerCache.get(routerDef);
|
|
101
103
|
if (!compiledRouter) {
|
|
102
104
|
compiledRouter = compileRouter(routerDef);
|
|
@@ -116,6 +118,13 @@ function createFetchHandler(routerDef, contextFactory, hooks, prefix) {
|
|
|
116
118
|
if (result instanceof Promise) result.catch(() => {});
|
|
117
119
|
} catch {}
|
|
118
120
|
}
|
|
121
|
+
function awaitHook(name, event) {
|
|
122
|
+
if (!hooks) return;
|
|
123
|
+
try {
|
|
124
|
+
const result = hooks.callHook(name, event);
|
|
125
|
+
if (result instanceof Promise) return result.catch(() => {});
|
|
126
|
+
} catch {}
|
|
127
|
+
}
|
|
119
128
|
return async function handleRequest(request) {
|
|
120
129
|
const url = request.url;
|
|
121
130
|
let fullPath = parseUrlPath(url);
|
|
@@ -149,14 +158,17 @@ function createFetchHandler(routerDef, contextFactory, hooks, prefix) {
|
|
|
149
158
|
});
|
|
150
159
|
}
|
|
151
160
|
const format = detectResponseFormat(request);
|
|
152
|
-
|
|
161
|
+
using ctx = createContext();
|
|
153
162
|
let rawInput;
|
|
154
163
|
try {
|
|
155
164
|
const baseCtxResult = contextFactory(request);
|
|
156
165
|
applyContext(ctx, baseCtxResult instanceof Promise ? await baseCtxResult : baseCtxResult);
|
|
157
166
|
if (match.params) ctx.params = match.params;
|
|
158
|
-
const
|
|
159
|
-
|
|
167
|
+
const prepareResult = awaitHook("request:prepare", {
|
|
168
|
+
request,
|
|
169
|
+
ctx
|
|
170
|
+
});
|
|
171
|
+
if (prepareResult) await prepareResult;
|
|
160
172
|
if (!route.passthrough) rawInput = await parseInput(request, url, qMark);
|
|
161
173
|
if (match.params && Object.keys(match.params).length > 0) rawInput = rawInput != null && typeof rawInput === "object" ? {
|
|
162
174
|
...match.params,
|
|
@@ -166,17 +178,21 @@ function createFetchHandler(routerDef, contextFactory, hooks, prefix) {
|
|
|
166
178
|
path: pathname,
|
|
167
179
|
input: rawInput
|
|
168
180
|
});
|
|
169
|
-
const pipelineResult =
|
|
181
|
+
const pipelineResult = bridge ? bridge.run(ctx, () => route.handler(ctx, rawInput, request.signal)) : route.handler(ctx, rawInput, request.signal);
|
|
170
182
|
const output = pipelineResult instanceof Promise ? await pipelineResult : pipelineResult;
|
|
171
183
|
callHook("response", {
|
|
172
184
|
path: pathname,
|
|
173
185
|
output,
|
|
174
186
|
durationMs: 0
|
|
175
187
|
});
|
|
188
|
+
callHook("response:finalize", {
|
|
189
|
+
request,
|
|
190
|
+
ctx,
|
|
191
|
+
output
|
|
192
|
+
});
|
|
176
193
|
const response = makeResponse(output, route, format, ctx);
|
|
177
194
|
return response instanceof Promise ? await response : response;
|
|
178
195
|
} catch (error) {
|
|
179
|
-
releaseContext(ctx);
|
|
180
196
|
callHook("error", {
|
|
181
197
|
path: pathname,
|
|
182
198
|
error
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { AnySchema } from "./schema.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/core/schema-converter.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* JSON Schema subset used for OpenAPI / analytics output.
|
|
6
|
+
*
|
|
7
|
+
* @category Schema
|
|
8
|
+
*/
|
|
9
|
+
interface JSONSchema {
|
|
10
|
+
type?: string | string[];
|
|
11
|
+
format?: string;
|
|
12
|
+
properties?: Record<string, JSONSchema>;
|
|
13
|
+
required?: string[];
|
|
14
|
+
items?: JSONSchema;
|
|
15
|
+
anyOf?: JSONSchema[];
|
|
16
|
+
oneOf?: JSONSchema[];
|
|
17
|
+
allOf?: JSONSchema[];
|
|
18
|
+
enum?: unknown[];
|
|
19
|
+
const?: unknown;
|
|
20
|
+
description?: string;
|
|
21
|
+
title?: string;
|
|
22
|
+
default?: unknown;
|
|
23
|
+
[key: string]: unknown;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Options passed to a converter's `toJsonSchema` method.
|
|
27
|
+
*
|
|
28
|
+
* @category Schema
|
|
29
|
+
*/
|
|
30
|
+
interface ConvertOptions {
|
|
31
|
+
strategy: 'input' | 'output';
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* A converter that translates a specific Standard Schema vendor's schemas
|
|
35
|
+
* into JSON Schema. Pass instances via `silgi({ schemaConverters: [...] })`.
|
|
36
|
+
*
|
|
37
|
+
* @remarks
|
|
38
|
+
* Implement this interface to add OpenAPI / analytics support for a custom
|
|
39
|
+
* schema library. The `vendor` string must match the `~standard.vendor`
|
|
40
|
+
* property reported by the schema library's Standard Schema implementation.
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* ```ts
|
|
44
|
+
* import type { SchemaConverter } from 'silgi'
|
|
45
|
+
*
|
|
46
|
+
* const myConverter: SchemaConverter = {
|
|
47
|
+
* vendor: 'my-lib',
|
|
48
|
+
* toJsonSchema(schema, opts) {
|
|
49
|
+
* return { type: 'string' }
|
|
50
|
+
* },
|
|
51
|
+
* }
|
|
52
|
+
* ```
|
|
53
|
+
*
|
|
54
|
+
* @category Schema
|
|
55
|
+
*/
|
|
56
|
+
interface SchemaConverter {
|
|
57
|
+
/** The Standard Schema `~standard.vendor` string this converter handles (e.g. `"zod"`). */
|
|
58
|
+
vendor: string;
|
|
59
|
+
/**
|
|
60
|
+
* Convert a schema to a JSON Schema object.
|
|
61
|
+
*
|
|
62
|
+
* @param schema - The schema to convert.
|
|
63
|
+
* @param opts - Conversion options including `strategy` (`'input'` | `'output'`).
|
|
64
|
+
* @returns A JSON Schema object. Return `{}` for unsupported/unknown schemas.
|
|
65
|
+
*/
|
|
66
|
+
toJsonSchema(schema: AnySchema, opts: ConvertOptions): JSONSchema;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* A per-instance registry mapping vendor strings to their converters.
|
|
70
|
+
*
|
|
71
|
+
* Built by {@link createSchemaRegistry} and threaded through the handler
|
|
72
|
+
* pipeline to scalar and analytics wrappers.
|
|
73
|
+
*
|
|
74
|
+
* @category Schema
|
|
75
|
+
*/
|
|
76
|
+
type SchemaRegistry = Map<string, SchemaConverter>;
|
|
77
|
+
/**
|
|
78
|
+
* Build a {@link SchemaRegistry} from an array of converters.
|
|
79
|
+
*
|
|
80
|
+
* @param converters - Array of {@link SchemaConverter} objects, each
|
|
81
|
+
* declaring their own `vendor`.
|
|
82
|
+
* @returns A `Map<string, SchemaConverter>` keyed by `converter.vendor`.
|
|
83
|
+
*
|
|
84
|
+
* @example
|
|
85
|
+
* ```ts
|
|
86
|
+
* import { zodConverter } from 'silgi/zod'
|
|
87
|
+
* import { createSchemaRegistry } from 'silgi'
|
|
88
|
+
*
|
|
89
|
+
* const registry = createSchemaRegistry([zodConverter])
|
|
90
|
+
* ```
|
|
91
|
+
*
|
|
92
|
+
* @category Schema
|
|
93
|
+
*/
|
|
94
|
+
declare function createSchemaRegistry(converters?: SchemaConverter[]): SchemaRegistry;
|
|
95
|
+
/**
|
|
96
|
+
* Convert any Standard Schema to JSON Schema.
|
|
97
|
+
*
|
|
98
|
+
* @remarks
|
|
99
|
+
* Resolution order:
|
|
100
|
+
* 1. **Native fast path** — `schema['~standard'].jsonSchema.input()`
|
|
101
|
+
* (Valibot, ArkType, Zod v4, …). No registry needed.
|
|
102
|
+
* 2. **Registry lookup** — finds a converter by
|
|
103
|
+
* `schema['~standard'].vendor`. Registry must be passed explicitly;
|
|
104
|
+
* there is no global mutable state.
|
|
105
|
+
* 3. **Empty schema `{}`** — emits a one-time `console.warn` per vendor
|
|
106
|
+
* when a registry was provided but contained no matching converter.
|
|
107
|
+
* No warn when no registry was passed (caller opted out).
|
|
108
|
+
*
|
|
109
|
+
* @param schema - Any Standard Schema compatible schema object.
|
|
110
|
+
* @param strategy - `'input'` (default) for pre-transform types; `'output'`
|
|
111
|
+
* for post-transform.
|
|
112
|
+
* @param registry - Optional {@link SchemaRegistry} built from
|
|
113
|
+
* {@link createSchemaRegistry}. When omitted the function still handles
|
|
114
|
+
* schemas that expose the native `jsonSchema.input()` fast path.
|
|
115
|
+
* @returns A JSON Schema object. Returns `{}` when conversion is not possible.
|
|
116
|
+
*
|
|
117
|
+
* @example
|
|
118
|
+
* ```ts
|
|
119
|
+
* import { zodConverter } from 'silgi/zod'
|
|
120
|
+
* import { createSchemaRegistry, schemaToJsonSchema } from 'silgi'
|
|
121
|
+
* import { z } from 'zod'
|
|
122
|
+
*
|
|
123
|
+
* const registry = createSchemaRegistry([zodConverter])
|
|
124
|
+
* const json = schemaToJsonSchema(z.object({ name: z.string() }), 'input', registry)
|
|
125
|
+
* ```
|
|
126
|
+
*
|
|
127
|
+
* @category Schema
|
|
128
|
+
*/
|
|
129
|
+
declare function schemaToJsonSchema(schema: AnySchema, strategy?: 'input' | 'output', registry?: SchemaRegistry): JSONSchema;
|
|
130
|
+
//#endregion
|
|
131
|
+
export { ConvertOptions, JSONSchema, SchemaConverter, SchemaRegistry, createSchemaRegistry, schemaToJsonSchema };
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
//#region src/core/schema-converter.ts
|
|
2
|
+
/**
|
|
3
|
+
* Build a {@link SchemaRegistry} from an array of converters.
|
|
4
|
+
*
|
|
5
|
+
* @param converters - Array of {@link SchemaConverter} objects, each
|
|
6
|
+
* declaring their own `vendor`.
|
|
7
|
+
* @returns A `Map<string, SchemaConverter>` keyed by `converter.vendor`.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```ts
|
|
11
|
+
* import { zodConverter } from 'silgi/zod'
|
|
12
|
+
* import { createSchemaRegistry } from 'silgi'
|
|
13
|
+
*
|
|
14
|
+
* const registry = createSchemaRegistry([zodConverter])
|
|
15
|
+
* ```
|
|
16
|
+
*
|
|
17
|
+
* @category Schema
|
|
18
|
+
*/
|
|
19
|
+
function createSchemaRegistry(converters = []) {
|
|
20
|
+
const map = /* @__PURE__ */ new Map();
|
|
21
|
+
for (const converter of converters) map.set(converter.vendor, converter);
|
|
22
|
+
return map;
|
|
23
|
+
}
|
|
24
|
+
const _warnedVendors = /* @__PURE__ */ new Set();
|
|
25
|
+
/**
|
|
26
|
+
* Convert any Standard Schema to JSON Schema.
|
|
27
|
+
*
|
|
28
|
+
* @remarks
|
|
29
|
+
* Resolution order:
|
|
30
|
+
* 1. **Native fast path** — `schema['~standard'].jsonSchema.input()`
|
|
31
|
+
* (Valibot, ArkType, Zod v4, …). No registry needed.
|
|
32
|
+
* 2. **Registry lookup** — finds a converter by
|
|
33
|
+
* `schema['~standard'].vendor`. Registry must be passed explicitly;
|
|
34
|
+
* there is no global mutable state.
|
|
35
|
+
* 3. **Empty schema `{}`** — emits a one-time `console.warn` per vendor
|
|
36
|
+
* when a registry was provided but contained no matching converter.
|
|
37
|
+
* No warn when no registry was passed (caller opted out).
|
|
38
|
+
*
|
|
39
|
+
* @param schema - Any Standard Schema compatible schema object.
|
|
40
|
+
* @param strategy - `'input'` (default) for pre-transform types; `'output'`
|
|
41
|
+
* for post-transform.
|
|
42
|
+
* @param registry - Optional {@link SchemaRegistry} built from
|
|
43
|
+
* {@link createSchemaRegistry}. When omitted the function still handles
|
|
44
|
+
* schemas that expose the native `jsonSchema.input()` fast path.
|
|
45
|
+
* @returns A JSON Schema object. Returns `{}` when conversion is not possible.
|
|
46
|
+
*
|
|
47
|
+
* @example
|
|
48
|
+
* ```ts
|
|
49
|
+
* import { zodConverter } from 'silgi/zod'
|
|
50
|
+
* import { createSchemaRegistry, schemaToJsonSchema } from 'silgi'
|
|
51
|
+
* import { z } from 'zod'
|
|
52
|
+
*
|
|
53
|
+
* const registry = createSchemaRegistry([zodConverter])
|
|
54
|
+
* const json = schemaToJsonSchema(z.object({ name: z.string() }), 'input', registry)
|
|
55
|
+
* ```
|
|
56
|
+
*
|
|
57
|
+
* @category Schema
|
|
58
|
+
*/
|
|
59
|
+
function schemaToJsonSchema(schema, strategy = "input", registry) {
|
|
60
|
+
const std = schema?.["~standard"];
|
|
61
|
+
if (std?.jsonSchema?.input) try {
|
|
62
|
+
const result = std.jsonSchema.input({ target: "draft-2020-12" });
|
|
63
|
+
if (result && typeof result === "object") {
|
|
64
|
+
const { $schema: _, ...rest } = result;
|
|
65
|
+
return rest;
|
|
66
|
+
}
|
|
67
|
+
} catch {}
|
|
68
|
+
const vendor = typeof std?.vendor === "string" ? std.vendor : void 0;
|
|
69
|
+
if (vendor && registry) {
|
|
70
|
+
const converter = registry.get(vendor);
|
|
71
|
+
if (converter) try {
|
|
72
|
+
return converter.toJsonSchema(schema, { strategy });
|
|
73
|
+
} catch {}
|
|
74
|
+
else if (!_warnedVendors.has(vendor)) {
|
|
75
|
+
_warnedVendors.add(vendor);
|
|
76
|
+
console.warn(`[silgi] No schema converter registered for vendor "${vendor}". Pass schemaConverters: [${vendor}Converter] to silgi() to enable OpenAPI / analytics schema generation.`);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return {};
|
|
80
|
+
}
|
|
81
|
+
//#endregion
|
|
82
|
+
export { createSchemaRegistry, schemaToJsonSchema };
|
package/dist/core/serve.d.mts
CHANGED
|
@@ -26,8 +26,8 @@ interface ServeOptions {
|
|
|
26
26
|
hostname?: string;
|
|
27
27
|
/** Enable Scalar API Reference UI at /api/reference and /api/openapi.json */
|
|
28
28
|
scalar?: boolean | ScalarOptions;
|
|
29
|
-
/** Enable analytics dashboard at /api/analytics */
|
|
30
|
-
analytics?:
|
|
29
|
+
/** Enable analytics dashboard at /api/analytics — requires `auth` to be set */
|
|
30
|
+
analytics?: AnalyticsOptions;
|
|
31
31
|
/**
|
|
32
32
|
* WebSocket RPC configuration.
|
|
33
33
|
*
|
package/dist/core/serve.mjs
CHANGED
|
@@ -14,11 +14,18 @@ function routerHasSubscription(def) {
|
|
|
14
14
|
for (const v of Object.values(def)) if (routerHasSubscription(v)) return true;
|
|
15
15
|
return false;
|
|
16
16
|
}
|
|
17
|
-
async function createServeHandler(routerDef, contextFactory, hooks, options) {
|
|
17
|
+
async function createServeHandler(routerDef, contextFactory, hooks, options, schemaRegistry, bridge) {
|
|
18
18
|
const port = options?.port ?? 3e3;
|
|
19
19
|
const hostname = options?.hostname ?? "127.0.0.1";
|
|
20
20
|
const prefix = options?.basePath ? normalizePrefix(options.basePath) : void 0;
|
|
21
|
-
const httpHandler = wrapHandler(createFetchHandler(routerDef, contextFactory, hooks, prefix), routerDef, options
|
|
21
|
+
const httpHandler = wrapHandler(createFetchHandler(routerDef, contextFactory, hooks, prefix, bridge), routerDef, options ? {
|
|
22
|
+
...options,
|
|
23
|
+
schemaRegistry,
|
|
24
|
+
hooks
|
|
25
|
+
} : {
|
|
26
|
+
schemaRegistry,
|
|
27
|
+
hooks
|
|
28
|
+
}, prefix);
|
|
22
29
|
const shutdownOpt = options?.gracefulShutdown ?? true;
|
|
23
30
|
let gracefulShutdown;
|
|
24
31
|
if (typeof shutdownOpt === "object") gracefulShutdown = {
|
package/dist/core/task.mjs
CHANGED
|
@@ -24,13 +24,13 @@ function createTaskFromProcedure(config, resolveFn, inputSchema, use, contextFac
|
|
|
24
24
|
const dispatch = async (rawInput, parentCtx) => {
|
|
25
25
|
const input = inputSchema ? await validateSchema(inputSchema, rawInput) : rawInput;
|
|
26
26
|
const ctx = contextFactory ? await contextFactory() : {};
|
|
27
|
-
const parentTrace = parentCtx?.
|
|
27
|
+
const parentTrace = parentCtx?.trace;
|
|
28
28
|
const spanStart = parentTrace ? performance.now() : 0;
|
|
29
29
|
let reqTrace = null;
|
|
30
30
|
try {
|
|
31
31
|
const { RequestTrace } = await import("../plugins/analytics.mjs");
|
|
32
32
|
reqTrace = new RequestTrace();
|
|
33
|
-
ctx.
|
|
33
|
+
ctx.trace = reqTrace;
|
|
34
34
|
} catch {}
|
|
35
35
|
const t0 = performance.now();
|
|
36
36
|
try {
|
package/dist/index.d.mts
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
import { AnySchema, InferSchemaInput, InferSchemaOutput, Schema, ValidationError, type, validateSchema } from "./core/schema.mjs";
|
|
2
2
|
import { ScheduledTaskInfo, TaskDef, TaskEvent, collectCronTasks, 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
|
+
import { ConvertOptions, JSONSchema, SchemaConverter, SchemaRegistry, createSchemaRegistry, schemaToJsonSchema } from "./core/schema-converter.mjs";
|
|
4
5
|
import { ScalarOptions, generateOpenAPI, scalarHTML } from "./scalar.mjs";
|
|
5
6
|
import { ProcedureBuilder, ProcedureBuilderWithOutput } from "./builder.mjs";
|
|
7
|
+
import { ContextBridge, createContextBridge } from "./core/context-bridge.mjs";
|
|
6
8
|
import { ServeOptions, SilgiServer } from "./core/serve.mjs";
|
|
7
9
|
import { Driver, Storage, StorageConfig, StorageValue, initStorage, resetStorage, useStorage } from "./core/storage.mjs";
|
|
8
10
|
import { SilgiConfig, SilgiInstance, silgi } from "./silgi.mjs";
|
|
9
|
-
import { SilgiError, SilgiErrorCode, SilgiErrorJSON, SilgiErrorOptions, isDefinedError, toSilgiError } from "./core/error.mjs";
|
|
11
|
+
import { SilgiError, SilgiErrorCode, SilgiErrorJSON, SilgiErrorOptions, isDefinedError, isSilgiError, toSilgiError } from "./core/error.mjs";
|
|
12
|
+
import { BaseContext } from "./core/context.mjs";
|
|
10
13
|
import { AsyncIteratorClass, mapAsyncIterator } from "./core/iterator.mjs";
|
|
11
14
|
import { EventMeta, getEventMeta, withEventMeta } from "./core/sse.mjs";
|
|
12
15
|
import { CallableOptions, callable } from "./callable.mjs";
|
|
@@ -14,4 +17,4 @@ import { LifecycleHooks, lifecycleWrap } from "./lifecycle.mjs";
|
|
|
14
17
|
import { mapInput } from "./map-input.mjs";
|
|
15
18
|
import { compileProcedure, compileRouter, createContext } from "./compile.mjs";
|
|
16
19
|
import { LazyRouter, isLazy, lazy, resolveLazy } from "./lazy.mjs";
|
|
17
|
-
export { type AnySchema, AsyncIteratorClass, type CallableOptions, 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 LazyRouter, type LifecycleHooks, type Meta, type MiddlewareDef, type ProcedureBuilder, type ProcedureBuilderWithOutput, type ProcedureDef, type ProcedureType, type ResolveContext, type RouterDef, type ScalarOptions, type ScheduledTaskInfo, type Schema, 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, compileProcedure, compileRouter, createContext, generateOpenAPI, getEventMeta, getScheduledTasks, initStorage, isDefinedError, isLazy, lazy, lifecycleWrap, mapAsyncIterator, mapInput, resetStorage, resolveLazy, runTask, scalarHTML, setTaskAnalytics, silgi, startCronJobs, stopCronJobs, toSilgiError, type, useStorage, validateSchema, withEventMeta };
|
|
20
|
+
export { type AnySchema, AsyncIteratorClass, type BaseContext, type CallableOptions, type ContextBridge, type ConvertOptions, 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 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, compileProcedure, compileRouter, createContext, createContextBridge, createSchemaRegistry, generateOpenAPI, getEventMeta, getScheduledTasks, initStorage, isDefinedError, isLazy, 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,9 +1,11 @@
|
|
|
1
1
|
import { ValidationError, type, validateSchema } from "./core/schema.mjs";
|
|
2
2
|
import { collectCronTasks, getScheduledTasks, runTask, setTaskAnalytics, startCronJobs, stopCronJobs } from "./core/task.mjs";
|
|
3
|
-
import { SilgiError, isDefinedError, toSilgiError } from "./core/error.mjs";
|
|
3
|
+
import { SilgiError, isDefinedError, isSilgiError, toSilgiError } from "./core/error.mjs";
|
|
4
4
|
import { compileProcedure, compileRouter, createContext } from "./compile.mjs";
|
|
5
|
+
import { createContextBridge } from "./core/context-bridge.mjs";
|
|
5
6
|
import { AsyncIteratorClass, mapAsyncIterator } from "./core/iterator.mjs";
|
|
6
7
|
import { getEventMeta, withEventMeta } from "./core/sse.mjs";
|
|
8
|
+
import { createSchemaRegistry, schemaToJsonSchema } from "./core/schema-converter.mjs";
|
|
7
9
|
import { silgi } from "./silgi.mjs";
|
|
8
10
|
import { callable } from "./callable.mjs";
|
|
9
11
|
import { lifecycleWrap } from "./lifecycle.mjs";
|
|
@@ -11,4 +13,4 @@ import { mapInput } from "./map-input.mjs";
|
|
|
11
13
|
import { isLazy, lazy, resolveLazy } from "./lazy.mjs";
|
|
12
14
|
import { initStorage, resetStorage, useStorage } from "./core/storage.mjs";
|
|
13
15
|
import { generateOpenAPI, scalarHTML } from "./scalar.mjs";
|
|
14
|
-
export { AsyncIteratorClass, SilgiError, ValidationError, callable, collectCronTasks, compileProcedure, compileRouter, createContext, generateOpenAPI, getEventMeta, getScheduledTasks, initStorage, isDefinedError, isLazy, lazy, lifecycleWrap, mapAsyncIterator, mapInput, resetStorage, resolveLazy, runTask, scalarHTML, setTaskAnalytics, silgi, startCronJobs, stopCronJobs, toSilgiError, type, useStorage, validateSchema, withEventMeta };
|
|
16
|
+
export { AsyncIteratorClass, SilgiError, ValidationError, callable, collectCronTasks, compileProcedure, compileRouter, createContext, createContextBridge, createSchemaRegistry, generateOpenAPI, getEventMeta, getScheduledTasks, initStorage, isDefinedError, isLazy, isSilgiError, lazy, lifecycleWrap, mapAsyncIterator, mapInput, resetStorage, resolveLazy, runTask, scalarHTML, schemaToJsonSchema, setTaskAnalytics, silgi, startCronJobs, stopCronJobs, toSilgiError, type, useStorage, validateSchema, withEventMeta };
|
|
@@ -1,4 +1,25 @@
|
|
|
1
1
|
//#region src/integrations/better-auth/index.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Associate a silgi context with a `Request` so the Better Auth tracing
|
|
4
|
+
* plugin can read it without mutating the `Request` object.
|
|
5
|
+
*
|
|
6
|
+
* @remarks
|
|
7
|
+
* Prefer this helper over the legacy `(request as any).__silgiCtx = ctx`
|
|
8
|
+
* assignment. The underlying storage is a module-level `WeakMap`, so
|
|
9
|
+
* entries are released automatically when the `Request` is GC'd.
|
|
10
|
+
*
|
|
11
|
+
* @param request - The `Request` currently being handled.
|
|
12
|
+
* @param ctx - The silgi context to associate, typically including `trace`.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```ts
|
|
16
|
+
* import { setRequestContext } from 'silgi/better-auth'
|
|
17
|
+
*
|
|
18
|
+
* setRequestContext(request, ctx)
|
|
19
|
+
* await auth.handler(request)
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
declare function setRequestContext(request: Request, ctx: Record<string, unknown>): void;
|
|
2
23
|
interface TracingConfig {
|
|
3
24
|
/** Capture request body as span input (default: true) */
|
|
4
25
|
captureInput?: boolean;
|
|
@@ -38,4 +59,4 @@ declare function instrumentBetterAuth<T extends Record<string, any>>(auth: T): T
|
|
|
38
59
|
*/
|
|
39
60
|
declare function withCtx<T>(ctx: Record<string, unknown>, fn: () => T): T;
|
|
40
61
|
//#endregion
|
|
41
|
-
export { TracingConfig, instrumentBetterAuth, tracing, withCtx };
|
|
62
|
+
export { TracingConfig, instrumentBetterAuth, setRequestContext, tracing, withCtx };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { createContextBridge } from "../../core/context-bridge.mjs";
|
|
2
2
|
//#region src/integrations/better-auth/index.ts
|
|
3
3
|
/**
|
|
4
4
|
* Silgi + Better Auth tracing integration.
|
|
@@ -6,20 +6,88 @@ import { getCtx, runWithCtx } from "../../core/context-bridge.mjs";
|
|
|
6
6
|
* Provides a Better Auth plugin factory that auto-traces all auth operations
|
|
7
7
|
* (sign-in, sign-up, OAuth, session management, etc.) into silgi analytics.
|
|
8
8
|
*
|
|
9
|
-
* The silgi request context is
|
|
10
|
-
*
|
|
9
|
+
* The silgi request context is associated with a `Request` in three ways,
|
|
10
|
+
* tried in priority order:
|
|
11
|
+
* 1. {@link setRequestContext}(request, ctx) — the blessed API (GC-friendly
|
|
12
|
+
* WeakMap, no mutation of the `Request` object).
|
|
13
|
+
* 2. `(request as any).__silgiCtx = ctx` — legacy property assignment; kept
|
|
14
|
+
* working for existing users but `setRequestContext` is preferred.
|
|
15
|
+
* 3. `silgi.runInContext(ctx, fn)` / `withCtx(ctx, fn)` — AsyncLocalStorage
|
|
16
|
+
* fallback when no Request is in scope (e.g., background jobs).
|
|
11
17
|
*
|
|
12
18
|
* @example
|
|
13
19
|
* ```ts
|
|
14
|
-
* import { tracing } from 'silgi/better-auth'
|
|
20
|
+
* import { tracing, setRequestContext } from 'silgi/better-auth'
|
|
15
21
|
*
|
|
16
22
|
* const auth = betterAuth({
|
|
17
|
-
* plugins: [
|
|
18
|
-
* tracing(), // auto-traces all auth operations
|
|
19
|
-
* ],
|
|
23
|
+
* plugins: [tracing()],
|
|
20
24
|
* })
|
|
25
|
+
*
|
|
26
|
+
* // In your silgi handler:
|
|
27
|
+
* setRequestContext(request, ctx)
|
|
28
|
+
* await auth.handler(request)
|
|
21
29
|
* ```
|
|
22
30
|
*/
|
|
31
|
+
/**
|
|
32
|
+
* Module-level compat bridge — backs the exported `withCtx()` helper so
|
|
33
|
+
* tests and programmatic callers can still install an ambient context
|
|
34
|
+
* without needing a silgi instance. The request path in `handler.ts`
|
|
35
|
+
* uses `silgi.runInContext` on the per-instance bridge and never flows
|
|
36
|
+
* through this one, so there is no inter-instance context collision.
|
|
37
|
+
*
|
|
38
|
+
* @internal
|
|
39
|
+
*/
|
|
40
|
+
const _compatBridge = createContextBridge();
|
|
41
|
+
function getCtx() {
|
|
42
|
+
return _compatBridge.current();
|
|
43
|
+
}
|
|
44
|
+
function runWithCtx(ctx, fn) {
|
|
45
|
+
return _compatBridge.run(ctx, fn);
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Keyed on `Request` identity. GC-friendly: entry auto-released when the
|
|
49
|
+
* `Request` is collected.
|
|
50
|
+
*
|
|
51
|
+
* @internal
|
|
52
|
+
*/
|
|
53
|
+
const _requestContextMap = /* @__PURE__ */ new WeakMap();
|
|
54
|
+
/**
|
|
55
|
+
* Associate a silgi context with a `Request` so the Better Auth tracing
|
|
56
|
+
* plugin can read it without mutating the `Request` object.
|
|
57
|
+
*
|
|
58
|
+
* @remarks
|
|
59
|
+
* Prefer this helper over the legacy `(request as any).__silgiCtx = ctx`
|
|
60
|
+
* assignment. The underlying storage is a module-level `WeakMap`, so
|
|
61
|
+
* entries are released automatically when the `Request` is GC'd.
|
|
62
|
+
*
|
|
63
|
+
* @param request - The `Request` currently being handled.
|
|
64
|
+
* @param ctx - The silgi context to associate, typically including `trace`.
|
|
65
|
+
*
|
|
66
|
+
* @example
|
|
67
|
+
* ```ts
|
|
68
|
+
* import { setRequestContext } from 'silgi/better-auth'
|
|
69
|
+
*
|
|
70
|
+
* setRequestContext(request, ctx)
|
|
71
|
+
* await auth.handler(request)
|
|
72
|
+
* ```
|
|
73
|
+
*/
|
|
74
|
+
function setRequestContext(request, ctx) {
|
|
75
|
+
_requestContextMap.set(request, ctx);
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Internal resolver that tries, in order: WeakMap (new API), legacy
|
|
79
|
+
* `__silgiCtx` property (deprecated but supported), and finally the
|
|
80
|
+
* integration's compat bridge ALS.
|
|
81
|
+
*
|
|
82
|
+
* @internal
|
|
83
|
+
*/
|
|
84
|
+
function resolveRequestContext(request) {
|
|
85
|
+
const fromMap = _requestContextMap.get(request);
|
|
86
|
+
if (fromMap) return fromMap;
|
|
87
|
+
const legacy = request.__silgiCtx;
|
|
88
|
+
if (legacy && typeof legacy === "object") return legacy;
|
|
89
|
+
return getCtx();
|
|
90
|
+
}
|
|
23
91
|
function matchOperation(path) {
|
|
24
92
|
const normalized = path.replace(/^\/+/, "");
|
|
25
93
|
if (normalized.endsWith("/sign-up/email") || normalized === "sign-up/email") return {
|
|
@@ -151,9 +219,9 @@ function tracing(config) {
|
|
|
151
219
|
try {
|
|
152
220
|
const request = ctx.request;
|
|
153
221
|
if (!request) return;
|
|
154
|
-
const silgiCtx = request
|
|
222
|
+
const silgiCtx = resolveRequestContext(request);
|
|
155
223
|
if (!silgiCtx) return;
|
|
156
|
-
const reqTrace = silgiCtx.
|
|
224
|
+
const reqTrace = silgiCtx.trace;
|
|
157
225
|
if (!reqTrace) return;
|
|
158
226
|
const meta = requestMetas.get(request);
|
|
159
227
|
requestMetas.delete(request);
|
|
@@ -284,7 +352,7 @@ function withCtx(ctx, fn) {
|
|
|
284
352
|
}
|
|
285
353
|
function wrapApiMethod(originalFn, operation, method) {
|
|
286
354
|
return async function instrumented(...args) {
|
|
287
|
-
const reqTrace = getCtx()?.
|
|
355
|
+
const reqTrace = getCtx()?.trace;
|
|
288
356
|
if (!reqTrace) return originalFn.apply(this, args);
|
|
289
357
|
const spanName = `auth.api.${operation}`;
|
|
290
358
|
const start = performance.now();
|
|
@@ -328,4 +396,4 @@ function wrapApiMethod(originalFn, operation, method) {
|
|
|
328
396
|
};
|
|
329
397
|
}
|
|
330
398
|
//#endregion
|
|
331
|
-
export { instrumentBetterAuth, tracing, withCtx };
|
|
399
|
+
export { instrumentBetterAuth, setRequestContext, tracing, withCtx };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { createContextBridge } from "../../core/context-bridge.mjs";
|
|
2
2
|
//#region src/integrations/drizzle/index.ts
|
|
3
3
|
/**
|
|
4
4
|
* Silgi + Drizzle ORM tracing integration.
|
|
@@ -31,6 +31,23 @@ import { getCtx, runWithCtx } from "../../core/context-bridge.mjs";
|
|
|
31
31
|
* })
|
|
32
32
|
* ```
|
|
33
33
|
*/
|
|
34
|
+
/**
|
|
35
|
+
* Module-level compat bridge — backs the exported `withCtx()` helper for
|
|
36
|
+
* programmatic and test usage. Production request paths flow through
|
|
37
|
+
* `silgi.runInContext()` via `src/core/handler.ts` and never touch this
|
|
38
|
+
* bridge, so there is no cross-instance context bleed during normal
|
|
39
|
+
* operation. The bridge exists only so `withCtx(ctx, fn)` works without
|
|
40
|
+
* a silgi instance in scope.
|
|
41
|
+
*
|
|
42
|
+
* @internal
|
|
43
|
+
*/
|
|
44
|
+
const _compatBridge = createContextBridge();
|
|
45
|
+
function getCtx() {
|
|
46
|
+
return _compatBridge.current();
|
|
47
|
+
}
|
|
48
|
+
function runWithCtx(ctx, fn) {
|
|
49
|
+
return _compatBridge.run(ctx, fn);
|
|
50
|
+
}
|
|
34
51
|
const INSTRUMENTED = "__silgiDrizzleInstrumented";
|
|
35
52
|
const DEFAULT_DB_SYSTEM = "postgresql";
|
|
36
53
|
const DEFAULT_MAX_QUERY_LENGTH = 1e3;
|
|
@@ -83,7 +100,7 @@ function patchSession(session, cfg, isTx) {
|
|
|
83
100
|
session.prepareQuery = function patchedPrepareQuery(...args) {
|
|
84
101
|
const prepared = originalPrepareQuery.apply(this, args);
|
|
85
102
|
if (!prepared || typeof prepared.execute !== "function") return prepared;
|
|
86
|
-
const reqTrace = getCtx()?.
|
|
103
|
+
const reqTrace = getCtx()?.trace;
|
|
87
104
|
if (!reqTrace) return prepared;
|
|
88
105
|
const queryText = extractQueryText(args[0]) ?? prepared.rawQueryConfig?.text ?? prepared.queryConfig?.text ?? null;
|
|
89
106
|
const originalExecute = prepared.execute.bind(prepared);
|
|
@@ -97,7 +114,7 @@ function patchSession(session, cfg, isTx) {
|
|
|
97
114
|
if (typeof session.query === "function") {
|
|
98
115
|
const originalQuery = session.query.bind(session);
|
|
99
116
|
session.query = function patchedQuery(queryString, params) {
|
|
100
|
-
const reqTrace = getCtx()?.
|
|
117
|
+
const reqTrace = getCtx()?.trace;
|
|
101
118
|
if (!reqTrace) return originalQuery.call(this, queryString, params);
|
|
102
119
|
return traceExecution(reqTrace, cfg, queryString ?? null, isTx, originalQuery, this, [queryString, params]);
|
|
103
120
|
};
|
|
@@ -126,7 +143,7 @@ function patchRawClient(client, cfg) {
|
|
|
126
143
|
if (!methodName) return false;
|
|
127
144
|
const originalMethod = client[methodName].bind(client);
|
|
128
145
|
client[methodName] = function patchedClientMethod(...args) {
|
|
129
|
-
const reqTrace = getCtx()?.
|
|
146
|
+
const reqTrace = getCtx()?.trace;
|
|
130
147
|
if (!reqTrace) return originalMethod.apply(this, args);
|
|
131
148
|
return traceExecution(reqTrace, cfg, extractQueryText(args[0]) ?? null, false, originalMethod, this, args);
|
|
132
149
|
};
|
|
@@ -140,7 +157,7 @@ function patchSessionExecute(session, cfg) {
|
|
|
140
157
|
if (session[INSTRUMENTED]) return false;
|
|
141
158
|
const originalExecute = session.execute.bind(session);
|
|
142
159
|
session.execute = function patchedDeepExecute(...args) {
|
|
143
|
-
const reqTrace = getCtx()?.
|
|
160
|
+
const reqTrace = getCtx()?.trace;
|
|
144
161
|
if (!reqTrace) return originalExecute.apply(this, args);
|
|
145
162
|
return traceExecution(reqTrace, cfg, extractQueryText(args[0]) ?? null, false, originalExecute, this, args);
|
|
146
163
|
};
|
|
@@ -72,4 +72,4 @@ declare class ZodSchemaConverter implements SchemaConverter {
|
|
|
72
72
|
convert(schema: AnySchema, options: ConvertOptions): [boolean, JSONSchema];
|
|
73
73
|
}
|
|
74
74
|
//#endregion
|
|
75
|
-
export { CompositeSchemaConverter, ConvertOptions, JSONSchema,
|
|
75
|
+
export { CompositeSchemaConverter, ConvertOptions, JSONSchema, ZodSchemaConverter };
|