silgi 0.51.8 → 0.52.1
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/builder.d.mts +21 -1
- package/dist/core/handler.mjs +1 -1
- package/dist/core/router-utils.d.mts +43 -0
- package/dist/core/router-utils.mjs +38 -1
- package/dist/error-mapper.d.mts +32 -0
- package/dist/error-mapper.mjs +63 -0
- package/dist/index.d.mts +4 -1
- package/dist/index.mjs +4 -1
- package/dist/integrations/ai/index.mjs +2 -11
- package/dist/route-kit.d.mts +48 -0
- package/dist/route-kit.mjs +12 -0
- package/dist/scalar.mjs +2 -11
- package/package.json +1 -1
package/dist/builder.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { AnySchema, InferSchemaInput, InferSchemaOutput } from "./core/schema.mjs";
|
|
2
2
|
import { TaskDef, TaskEvent } from "./core/task.mjs";
|
|
3
|
-
import { ErrorDef, GuardDef, Meta, ProcedureDef, ProcedureType, ResolveContext, Route, WrapDef } from "./types.mjs";
|
|
3
|
+
import { ErrorDef, GuardDef, Meta, MiddlewareDef, ProcedureDef, ProcedureType, ResolveContext, Route, WrapDef } from "./types.mjs";
|
|
4
4
|
|
|
5
5
|
//#region src/builder.d.ts
|
|
6
6
|
/** Initial builder — no input, no output, no errors yet */
|
|
@@ -9,6 +9,17 @@ interface ProcedureBuilder<TType extends ProcedureType, TBaseCtx extends Record<
|
|
|
9
9
|
$use<TReturn extends Record<string, unknown> | void, TGErrors extends ErrorDef = {}>(guard: GuardDef<any, TReturn, TGErrors>): ProcedureBuilder<TType, TBaseCtx, TReturn extends Record<string, unknown> ? TCtx & TReturn : TCtx, TInput, TGErrors & TErrors>;
|
|
10
10
|
/** Add a wrap middleware — does not change context type */
|
|
11
11
|
$use(wrap: WrapDef<any>): ProcedureBuilder<TType, TBaseCtx, TCtx, TInput, TErrors>;
|
|
12
|
+
/**
|
|
13
|
+
* Add a middleware of unknown variant (`GuardDef | WrapDef`).
|
|
14
|
+
*
|
|
15
|
+
* @remarks
|
|
16
|
+
* Used by factory-pattern builders that accept middleware through a
|
|
17
|
+
* dependency boundary where the concrete variant isn't known at the
|
|
18
|
+
* call site. Context is not enriched — if you need guard-added fields
|
|
19
|
+
* in `.$resolve()`, pass the guard with its concrete type or use
|
|
20
|
+
* `defineRouteKit` to bind the ctx shape up front.
|
|
21
|
+
*/
|
|
22
|
+
$use(mw: MiddlewareDef): ProcedureBuilder<TType, TBaseCtx, TCtx, TInput, TErrors>;
|
|
12
23
|
/** Set input schema */
|
|
13
24
|
$input<TSchema extends AnySchema>(schema: TSchema): ProcedureBuilder<TType, TBaseCtx, TCtx, InferSchemaOutput<TSchema>, TErrors>;
|
|
14
25
|
/** Set output schema — enables return type autocomplete */
|
|
@@ -35,6 +46,15 @@ interface ProcedureBuilderWithOutput<TType extends ProcedureType, TBaseCtx exten
|
|
|
35
46
|
$use<TReturn extends Record<string, unknown> | void, TGErrors extends ErrorDef = {}>(guard: GuardDef<any, TReturn, TGErrors>): ProcedureBuilderWithOutput<TType, TBaseCtx, TReturn extends Record<string, unknown> ? TCtx & TReturn : TCtx, TInput, TOutputResolved, TGErrors & TErrors>;
|
|
36
47
|
/** Add a wrap middleware — does not change context type */
|
|
37
48
|
$use(wrap: WrapDef<any>): ProcedureBuilderWithOutput<TType, TBaseCtx, TCtx, TInput, TOutputResolved, TErrors>;
|
|
49
|
+
/**
|
|
50
|
+
* Add a middleware of unknown variant (`GuardDef | WrapDef`).
|
|
51
|
+
*
|
|
52
|
+
* @remarks
|
|
53
|
+
* Used by factory-pattern builders that accept middleware through a
|
|
54
|
+
* dependency boundary where the concrete variant isn't known at the
|
|
55
|
+
* call site.
|
|
56
|
+
*/
|
|
57
|
+
$use(mw: MiddlewareDef): ProcedureBuilderWithOutput<TType, TBaseCtx, TCtx, TInput, TOutputResolved, TErrors>;
|
|
38
58
|
/** Set typed errors */
|
|
39
59
|
$errors<TNewErrors extends ErrorDef>(errors: TNewErrors): ProcedureBuilderWithOutput<TType, TBaseCtx, TCtx, TInput, TOutputResolved, TNewErrors & TErrors>;
|
|
40
60
|
/** Set route metadata */
|
package/dist/core/handler.mjs
CHANGED
|
@@ -170,7 +170,7 @@ function createFetchHandler(routerDef, contextFactory, hooks, prefix, bridge) {
|
|
|
170
170
|
});
|
|
171
171
|
if (prepareResult) await prepareResult;
|
|
172
172
|
if (!route.passthrough) rawInput = await parseInput(request, url, qMark);
|
|
173
|
-
if (match.params
|
|
173
|
+
if (match.params) rawInput = rawInput != null && typeof rawInput === "object" ? {
|
|
174
174
|
...match.params,
|
|
175
175
|
...rawInput
|
|
176
176
|
} : match.params;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { ProcedureDef, RouterDef } from "../types.mjs";
|
|
2
|
+
import { compileRouter } from "../compile.mjs";
|
|
3
|
+
|
|
4
|
+
//#region src/core/router-utils.d.ts
|
|
5
|
+
declare function isProcedureDef(value: unknown): value is ProcedureDef;
|
|
6
|
+
/**
|
|
7
|
+
* Walk a router tree and invoke `cb` for every procedure.
|
|
8
|
+
*
|
|
9
|
+
* @remarks
|
|
10
|
+
* Depth-first traversal. `path` is the segment list from the router
|
|
11
|
+
* root to the procedure (e.g. `['users', 'list']`). Use this when you
|
|
12
|
+
* need the live `ProcedureDef` reference (e.g. to read `.input`,
|
|
13
|
+
* `.output`, `.route`, `.meta`). For a flat list of paths only, use
|
|
14
|
+
* {@link getProcedurePaths}.
|
|
15
|
+
*/
|
|
16
|
+
declare function collectProcedures(router: RouterDef, cb: (path: string[], proc: ProcedureDef) => void): void;
|
|
17
|
+
/**
|
|
18
|
+
* Flat list of every procedure in a router tree.
|
|
19
|
+
*
|
|
20
|
+
* @remarks
|
|
21
|
+
* Each entry carries the dot-joined path (e.g. `'users.list'`), the
|
|
22
|
+
* effective HTTP path (from `$route({ path })` or auto-derived), the
|
|
23
|
+
* method, the procedure kind and a direct reference to the
|
|
24
|
+
* `ProcedureDef`. Useful for generating client stubs, auditing the
|
|
25
|
+
* surface, or writing custom dashboards.
|
|
26
|
+
*/
|
|
27
|
+
interface ProcedureSummary {
|
|
28
|
+
/** Dot-joined segment path, e.g. `'users.list'`. */
|
|
29
|
+
name: string;
|
|
30
|
+
/** Router tree segments, e.g. `['users', 'list']`. */
|
|
31
|
+
segments: string[];
|
|
32
|
+
/** HTTP path used by the handler (auto or `$route`-overridden). */
|
|
33
|
+
httpPath: string;
|
|
34
|
+
/** HTTP method (uppercase), or `'*'` when wildcarded. */
|
|
35
|
+
method: string;
|
|
36
|
+
/** Procedure kind — `'query'`, `'mutation'`, `'subscription'`. */
|
|
37
|
+
type: ProcedureDef['type'];
|
|
38
|
+
/** Live `ProcedureDef` reference. */
|
|
39
|
+
procedure: ProcedureDef;
|
|
40
|
+
}
|
|
41
|
+
declare function getProcedurePaths(router: RouterDef): ProcedureSummary[];
|
|
42
|
+
//#endregion
|
|
43
|
+
export { ProcedureSummary, collectProcedures, getProcedurePaths, isProcedureDef };
|
|
@@ -4,6 +4,43 @@ const routerCache = /* @__PURE__ */ new WeakMap();
|
|
|
4
4
|
function isProcedureDef(value) {
|
|
5
5
|
return typeof value === "object" && value !== null && "type" in value && "resolve" in value && typeof value.resolve === "function";
|
|
6
6
|
}
|
|
7
|
+
/**
|
|
8
|
+
* Walk a router tree and invoke `cb` for every procedure.
|
|
9
|
+
*
|
|
10
|
+
* @remarks
|
|
11
|
+
* Depth-first traversal. `path` is the segment list from the router
|
|
12
|
+
* root to the procedure (e.g. `['users', 'list']`). Use this when you
|
|
13
|
+
* need the live `ProcedureDef` reference (e.g. to read `.input`,
|
|
14
|
+
* `.output`, `.route`, `.meta`). For a flat list of paths only, use
|
|
15
|
+
* {@link getProcedurePaths}.
|
|
16
|
+
*/
|
|
17
|
+
function collectProcedures(router, cb) {
|
|
18
|
+
walk(router, [], cb);
|
|
19
|
+
}
|
|
20
|
+
function walk(node, path, cb) {
|
|
21
|
+
if (isProcedureDef(node)) {
|
|
22
|
+
cb(path, node);
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
if (typeof node === "object" && node !== null) for (const [key, child] of Object.entries(node)) walk(child, [...path, key], cb);
|
|
26
|
+
}
|
|
27
|
+
function getProcedurePaths(router) {
|
|
28
|
+
const out = [];
|
|
29
|
+
walk(router, [], (segments, proc) => {
|
|
30
|
+
const route = proc.route;
|
|
31
|
+
const httpPath = route?.path ?? "/" + segments.join("/");
|
|
32
|
+
const method = route?.method?.toUpperCase() ?? "POST";
|
|
33
|
+
out.push({
|
|
34
|
+
name: segments.join("."),
|
|
35
|
+
segments,
|
|
36
|
+
httpPath,
|
|
37
|
+
method,
|
|
38
|
+
type: proc.type,
|
|
39
|
+
procedure: proc
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
return out;
|
|
43
|
+
}
|
|
7
44
|
function assignPaths(def, prefix = []) {
|
|
8
45
|
const result = {};
|
|
9
46
|
for (const [key, value] of Object.entries(def)) {
|
|
@@ -19,4 +56,4 @@ function assignPaths(def, prefix = []) {
|
|
|
19
56
|
return result;
|
|
20
57
|
}
|
|
21
58
|
//#endregion
|
|
22
|
-
export { assignPaths, isProcedureDef, routerCache };
|
|
59
|
+
export { assignPaths, collectProcedures, getProcedurePaths, isProcedureDef, routerCache };
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { SilgiError } from "./core/error.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/error-mapper.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* Map a caught error into a {@link SilgiError}, or return `undefined` to
|
|
6
|
+
* rethrow the original error untouched. `SilgiError` instances always
|
|
7
|
+
* pass through unchanged — the mapper is not invoked for them.
|
|
8
|
+
*/
|
|
9
|
+
type DomainErrorMapper = (error: unknown) => SilgiError | undefined;
|
|
10
|
+
/**
|
|
11
|
+
* Create a resolver wrapper that runs `mapper` on every thrown error.
|
|
12
|
+
*
|
|
13
|
+
* @param mapper - Called with the caught error; return a `SilgiError` to
|
|
14
|
+
* replace it, or `undefined` to rethrow the original.
|
|
15
|
+
* @returns A function that wraps a resolver and applies the mapping.
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```ts
|
|
19
|
+
* const handleErrors = mapDomainErrors((e) => {
|
|
20
|
+
* if (e instanceof MyDomainError) {
|
|
21
|
+
* return new SilgiError(e.code, { status: e.status, message: e.message, defined: true })
|
|
22
|
+
* }
|
|
23
|
+
* })
|
|
24
|
+
*
|
|
25
|
+
* k.$resolve(handleErrors(async ({ input, ctx }) => {
|
|
26
|
+
* return await service.run(input, ctx)
|
|
27
|
+
* }))
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
declare function mapDomainErrors(mapper: DomainErrorMapper): <TArgs extends unknown[], TReturn>(fn: (...args: TArgs) => TReturn | Promise<TReturn>) => (...args: TArgs) => Promise<TReturn>;
|
|
31
|
+
//#endregion
|
|
32
|
+
export { DomainErrorMapper, mapDomainErrors };
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { isSilgiError } from "./core/error.mjs";
|
|
2
|
+
//#region src/error-mapper.ts
|
|
3
|
+
/**
|
|
4
|
+
* mapDomainErrors — convert service-layer errors into SilgiError.
|
|
5
|
+
*
|
|
6
|
+
* @remarks
|
|
7
|
+
* Library service layers typically throw a domain error (no HTTP
|
|
8
|
+
* knowledge), and route handlers convert them to {@link SilgiError}
|
|
9
|
+
* before returning. Writing the same try/catch wrapper in every
|
|
10
|
+
* resolver is boilerplate; `mapDomainErrors` replaces it with a single
|
|
11
|
+
* mapper function that runs on every thrown error.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```ts
|
|
15
|
+
* class DomainError extends Error {
|
|
16
|
+
* constructor(public code: string, public status: number, message: string) { super(message) }
|
|
17
|
+
* }
|
|
18
|
+
*
|
|
19
|
+
* const toSilgi = mapDomainErrors((e) => {
|
|
20
|
+
* if (e instanceof DomainError) {
|
|
21
|
+
* return new SilgiError(e.code, { status: e.status, message: e.message, defined: true })
|
|
22
|
+
* }
|
|
23
|
+
* })
|
|
24
|
+
*
|
|
25
|
+
* k.$resolve(toSilgi(async ({ input }) => service.doThing(input)))
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
/**
|
|
29
|
+
* Create a resolver wrapper that runs `mapper` on every thrown error.
|
|
30
|
+
*
|
|
31
|
+
* @param mapper - Called with the caught error; return a `SilgiError` to
|
|
32
|
+
* replace it, or `undefined` to rethrow the original.
|
|
33
|
+
* @returns A function that wraps a resolver and applies the mapping.
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* ```ts
|
|
37
|
+
* const handleErrors = mapDomainErrors((e) => {
|
|
38
|
+
* if (e instanceof MyDomainError) {
|
|
39
|
+
* return new SilgiError(e.code, { status: e.status, message: e.message, defined: true })
|
|
40
|
+
* }
|
|
41
|
+
* })
|
|
42
|
+
*
|
|
43
|
+
* k.$resolve(handleErrors(async ({ input, ctx }) => {
|
|
44
|
+
* return await service.run(input, ctx)
|
|
45
|
+
* }))
|
|
46
|
+
* ```
|
|
47
|
+
*/
|
|
48
|
+
function mapDomainErrors(mapper) {
|
|
49
|
+
return function wrap(fn) {
|
|
50
|
+
return async (...args) => {
|
|
51
|
+
try {
|
|
52
|
+
return await fn(...args);
|
|
53
|
+
} catch (e) {
|
|
54
|
+
if (isSilgiError(e)) throw e;
|
|
55
|
+
const mapped = mapper(e);
|
|
56
|
+
if (mapped) throw mapped;
|
|
57
|
+
throw e;
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
//#endregion
|
|
63
|
+
export { mapDomainErrors };
|
package/dist/index.d.mts
CHANGED
|
@@ -9,6 +9,8 @@ import { ServeOptions, SilgiServer } from "./core/serve.mjs";
|
|
|
9
9
|
import { Driver, Storage, StorageConfig, StorageValue, initStorage, resetStorage, useStorage } from "./core/storage.mjs";
|
|
10
10
|
import { SilgiConfig, SilgiInstance, silgi } from "./silgi.mjs";
|
|
11
11
|
import { SilgiError, SilgiErrorCode, SilgiErrorJSON, SilgiErrorOptions, isDefinedError, isSilgiError, toSilgiError } from "./core/error.mjs";
|
|
12
|
+
import { DomainErrorMapper, mapDomainErrors } from "./error-mapper.mjs";
|
|
13
|
+
import { GuardDeps, GuardMap, RouteKit, RouteKitDeps, defineRouteKit } from "./route-kit.mjs";
|
|
12
14
|
import { BaseContext } from "./core/context.mjs";
|
|
13
15
|
import { AsyncIteratorClass, mapAsyncIterator } from "./core/iterator.mjs";
|
|
14
16
|
import { EventMeta, getEventMeta, withEventMeta } from "./core/sse.mjs";
|
|
@@ -16,5 +18,6 @@ import { CallableOptions, callable } from "./callable.mjs";
|
|
|
16
18
|
import { LifecycleHooks, lifecycleWrap } from "./lifecycle.mjs";
|
|
17
19
|
import { mapInput } from "./map-input.mjs";
|
|
18
20
|
import { compileProcedure, compileRouter, createContext } from "./compile.mjs";
|
|
21
|
+
import { ProcedureSummary, collectProcedures, getProcedurePaths, isProcedureDef } from "./core/router-utils.mjs";
|
|
19
22
|
import { LazyRouter, isLazy, lazy, resolveLazy } from "./lazy.mjs";
|
|
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 };
|
|
23
|
+
export { type AnySchema, AsyncIteratorClass, type BaseContext, type CallableOptions, type ContextBridge, type ConvertOptions, type DomainErrorMapper, type Driver, type ErrorDef, type ErrorDefItem, type EventMeta, type FailFn, type GuardDef, type GuardDeps, type GuardFn, type GuardMap, 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 RouteKit, type RouteKitDeps, 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, createSchemaRegistry, defineRouteKit, generateOpenAPI, getEventMeta, getProcedurePaths, getScheduledTasks, initStorage, isDefinedError, isLazy, isProcedureDef, isSilgiError, lazy, lifecycleWrap, mapAsyncIterator, mapDomainErrors, mapInput, resetStorage, resolveLazy, runTask, scalarHTML, schemaToJsonSchema, setTaskAnalytics, silgi, startCronJobs, stopCronJobs, toSilgiError, type, useStorage, validateSchema, withEventMeta };
|
package/dist/index.mjs
CHANGED
|
@@ -1,16 +1,19 @@
|
|
|
1
1
|
import { ValidationError, type, validateSchema } from "./core/schema.mjs";
|
|
2
2
|
import { collectCronTasks, getScheduledTasks, runTask, setTaskAnalytics, startCronJobs, stopCronJobs } from "./core/task.mjs";
|
|
3
3
|
import { SilgiError, isDefinedError, isSilgiError, toSilgiError } from "./core/error.mjs";
|
|
4
|
+
import { collectProcedures, getProcedurePaths, isProcedureDef } from "./core/router-utils.mjs";
|
|
4
5
|
import { compileProcedure, compileRouter, createContext } from "./compile.mjs";
|
|
5
6
|
import { createContextBridge } from "./core/context-bridge.mjs";
|
|
6
7
|
import { AsyncIteratorClass, mapAsyncIterator } from "./core/iterator.mjs";
|
|
7
8
|
import { getEventMeta, withEventMeta } from "./core/sse.mjs";
|
|
8
9
|
import { createSchemaRegistry, schemaToJsonSchema } from "./core/schema-converter.mjs";
|
|
9
10
|
import { silgi } from "./silgi.mjs";
|
|
11
|
+
import { mapDomainErrors } from "./error-mapper.mjs";
|
|
12
|
+
import { defineRouteKit } from "./route-kit.mjs";
|
|
10
13
|
import { callable } from "./callable.mjs";
|
|
11
14
|
import { lifecycleWrap } from "./lifecycle.mjs";
|
|
12
15
|
import { mapInput } from "./map-input.mjs";
|
|
13
16
|
import { isLazy, lazy, resolveLazy } from "./lazy.mjs";
|
|
14
17
|
import { initStorage, resetStorage, useStorage } from "./core/storage.mjs";
|
|
15
18
|
import { generateOpenAPI, scalarHTML } from "./scalar.mjs";
|
|
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 };
|
|
19
|
+
export { AsyncIteratorClass, SilgiError, ValidationError, callable, collectCronTasks, collectProcedures, compileProcedure, compileRouter, createContext, createContextBridge, createSchemaRegistry, defineRouteKit, generateOpenAPI, getEventMeta, getProcedurePaths, getScheduledTasks, initStorage, isDefinedError, isLazy, isProcedureDef, isSilgiError, lazy, lifecycleWrap, mapAsyncIterator, mapDomainErrors, mapInput, resetStorage, resolveLazy, runTask, scalarHTML, schemaToJsonSchema, setTaskAnalytics, silgi, startCronJobs, stopCronJobs, toSilgiError, type, useStorage, validateSchema, withEventMeta };
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { collectProcedures } from "../../core/router-utils.mjs";
|
|
1
2
|
import { compileProcedure } from "../../compile.mjs";
|
|
2
3
|
import { jsonSchema, tool } from "ai";
|
|
3
4
|
//#region src/integrations/ai/index.ts
|
|
@@ -53,23 +54,13 @@ function procedureToTool(name, procedure, options) {
|
|
|
53
54
|
*/
|
|
54
55
|
function routerToTools(router, options) {
|
|
55
56
|
const tools = {};
|
|
56
|
-
collectProcedures(router,
|
|
57
|
+
collectProcedures(router, (path, proc) => {
|
|
57
58
|
const flatName = path.join("_");
|
|
58
59
|
if (options?.filter && !options.filter(flatName, proc)) return;
|
|
59
60
|
tools[flatName] = procedureToTool(flatName, proc, { description: options?.descriptions?.[flatName] });
|
|
60
61
|
});
|
|
61
62
|
return tools;
|
|
62
63
|
}
|
|
63
|
-
function isProcedureDef(v) {
|
|
64
|
-
return typeof v === "object" && v !== null && "type" in v && "resolve" in v;
|
|
65
|
-
}
|
|
66
|
-
function collectProcedures(node, path, cb) {
|
|
67
|
-
if (isProcedureDef(node)) {
|
|
68
|
-
cb(path, node);
|
|
69
|
-
return;
|
|
70
|
-
}
|
|
71
|
-
if (typeof node === "object" && node !== null) for (const [key, child] of Object.entries(node)) collectProcedures(child, [...path, key], cb);
|
|
72
|
-
}
|
|
73
64
|
/** Simple Zod → JSON Schema for AI tool parameters */
|
|
74
65
|
function zodToJsonSchemaSimple(schema) {
|
|
75
66
|
const zod = schema?._zod ?? schema?._def;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { ErrorDef, GuardDef } from "./types.mjs";
|
|
2
|
+
import { SilgiInstance } from "./silgi.mjs";
|
|
3
|
+
|
|
4
|
+
//#region src/route-kit.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* Shape of a `guards` map passed to a kit route. Each entry declares the
|
|
7
|
+
* context additions that specific guard contributes.
|
|
8
|
+
*/
|
|
9
|
+
type GuardMap = Record<string, Record<string, unknown> | void>;
|
|
10
|
+
/** Convert a `GuardMap` into the deps object shape passed to kit builders. */
|
|
11
|
+
type GuardDeps<TGuards extends GuardMap> = { [K in keyof TGuards]: GuardDef<any, TGuards[K], ErrorDef> };
|
|
12
|
+
/** Deps injected into a kit route builder — the instance plus the typed guards. */
|
|
13
|
+
type RouteKitDeps<TCtx extends Record<string, unknown>, TGuards extends GuardMap> = {
|
|
14
|
+
s: SilgiInstance<TCtx>;
|
|
15
|
+
} & GuardDeps<TGuards>;
|
|
16
|
+
/**
|
|
17
|
+
* Return value of `defineRouteKit<Ctx>()`.
|
|
18
|
+
*
|
|
19
|
+
* @remarks
|
|
20
|
+
* Use {@link RouteKit.route} to declare a single route that depends on a
|
|
21
|
+
* named set of guards. The kit carries no runtime state — it only
|
|
22
|
+
* binds the ctx shape for inference.
|
|
23
|
+
*/
|
|
24
|
+
interface RouteKit<TCtx extends Record<string, unknown>> {
|
|
25
|
+
/**
|
|
26
|
+
* Declare a route factory.
|
|
27
|
+
*
|
|
28
|
+
* @typeParam TGuards - Map of guard name → context additions. Empty by
|
|
29
|
+
* default; pass an explicit shape when the route depends on guards.
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* ```ts
|
|
33
|
+
* kit.route<{ auth: { user: User } }>()(({ s, auth }) =>
|
|
34
|
+
* s.$use(auth).$resolve(({ ctx }) => ctx.user)
|
|
35
|
+
* )
|
|
36
|
+
* ```
|
|
37
|
+
*/
|
|
38
|
+
route: <TGuards extends GuardMap = {}>() => <TReturn>(builder: (deps: RouteKitDeps<TCtx, TGuards>) => TReturn) => (deps: RouteKitDeps<TCtx, TGuards>) => TReturn;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Create a context-bound route kit for isolated packages.
|
|
42
|
+
*
|
|
43
|
+
* @typeParam TCtx - Base context shape the server will provide. Flows
|
|
44
|
+
* into every route's resolver through the injected `s` instance.
|
|
45
|
+
*/
|
|
46
|
+
declare function defineRouteKit<TCtx extends Record<string, unknown>>(): RouteKit<TCtx>;
|
|
47
|
+
//#endregion
|
|
48
|
+
export { GuardDeps, GuardMap, RouteKit, RouteKitDeps, defineRouteKit };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
//#region src/route-kit.ts
|
|
2
|
+
/**
|
|
3
|
+
* Create a context-bound route kit for isolated packages.
|
|
4
|
+
*
|
|
5
|
+
* @typeParam TCtx - Base context shape the server will provide. Flows
|
|
6
|
+
* into every route's resolver through the injected `s` instance.
|
|
7
|
+
*/
|
|
8
|
+
function defineRouteKit() {
|
|
9
|
+
return { route: () => (builder) => builder };
|
|
10
|
+
}
|
|
11
|
+
//#endregion
|
|
12
|
+
export { defineRouteKit };
|
package/dist/scalar.mjs
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { collectProcedures } from "./core/router-utils.mjs";
|
|
1
2
|
import { schemaToJsonSchema } from "./core/schema-converter.mjs";
|
|
2
3
|
//#region src/scalar.ts
|
|
3
4
|
/**
|
|
@@ -35,7 +36,7 @@ function generateOpenAPI(router, options = {}, basePath = "", registry) {
|
|
|
35
36
|
const schemaToJsonSchema$1 = (schema, strategy = "input") => schemaToJsonSchema(schema, strategy, registry);
|
|
36
37
|
const paths = {};
|
|
37
38
|
const tags = /* @__PURE__ */ new Map();
|
|
38
|
-
collectProcedures(router,
|
|
39
|
+
collectProcedures(router, (path, proc) => {
|
|
39
40
|
const route = proc.route;
|
|
40
41
|
const { httpPath: routePath, pathParams } = toOpenAPIPath(route?.path ?? "/" + path.join("/"));
|
|
41
42
|
const httpPath = basePath ? basePath.replace(/\/$/, "") + routePath : routePath;
|
|
@@ -260,16 +261,6 @@ function scalarHTML(specUrl, options = {}) {
|
|
|
260
261
|
function escapeHtml(s) {
|
|
261
262
|
return s.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<").replace(/>/g, ">");
|
|
262
263
|
}
|
|
263
|
-
function isProcedureDef(value) {
|
|
264
|
-
return typeof value === "object" && value !== null && "type" in value && "resolve" in value && typeof value.resolve === "function";
|
|
265
|
-
}
|
|
266
|
-
function collectProcedures(node, path, cb) {
|
|
267
|
-
if (isProcedureDef(node)) {
|
|
268
|
-
cb(path, node);
|
|
269
|
-
return;
|
|
270
|
-
}
|
|
271
|
-
if (typeof node === "object" && node !== null) for (const [key, child] of Object.entries(node)) collectProcedures(child, [...path, key], cb);
|
|
272
|
-
}
|
|
273
264
|
function objectSchemaToParams(schema) {
|
|
274
265
|
if (schema.type !== "object" || !schema.properties) return [];
|
|
275
266
|
const required = new Set(schema.required ?? []);
|