@nifrajs/core 1.3.1 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/diff.d.ts ADDED
@@ -0,0 +1,66 @@
1
+ /**
2
+ * API breaking-change detection over route reflection.
3
+ *
4
+ * `snapshotRoutes` turns an app (or reflected descriptors) into a plain-JSON snapshot — the
5
+ * `standard` validators are dropped, so a snapshot survives `JSON.stringify` and can be committed
6
+ * as a CI baseline. `diffRouteSnapshots` compares two snapshots and classifies every change by
7
+ * wire compatibility, direction-aware:
8
+ *
9
+ * request direction (body/query — what clients SEND): a new required field, a removed field, or
10
+ * a narrowed type breaks existing callers; widening (new optional field, enum superset,
11
+ * required→optional) is compatible.
12
+ * response direction (response/sse/errors — what clients RECEIVE): a removed field, a field made
13
+ * optional, or a widened type breaks existing readers; narrowing (new field, optional→required,
14
+ * enum subset) is compatible.
15
+ *
16
+ * The classifier FAILS CLOSED: a schema change it cannot prove compatible is reported as breaking.
17
+ * Schemas without JSON Schema metadata (validation-only Standard Schemas) cannot be compared and
18
+ * yield `info` — never a silent pass presented as proof.
19
+ */
20
+ import { type JsonSchema, type ReflectedSchemaField } from "./reflection.js";
21
+ /** One schema position in a snapshot: JSON Schema metadata only, no validator. */
22
+ export interface SchemaSnapshot {
23
+ readonly jsonSchema?: JsonSchema;
24
+ readonly fields?: readonly ReflectedSchemaField[];
25
+ }
26
+ export interface RouteSnapshotSchema {
27
+ readonly body?: SchemaSnapshot;
28
+ readonly query?: SchemaSnapshot;
29
+ readonly response?: SchemaSnapshot;
30
+ readonly sse?: SchemaSnapshot;
31
+ readonly errors?: Readonly<Record<string, SchemaSnapshot>>;
32
+ }
33
+ /** One route in a snapshot — plain JSON, safe to persist as a CI baseline. */
34
+ export interface RouteSnapshot {
35
+ readonly method: string;
36
+ readonly path: string;
37
+ readonly schema?: RouteSnapshotSchema;
38
+ }
39
+ export type DiffSeverity = "breaking" | "compatible" | "info";
40
+ export interface RouteChange {
41
+ readonly severity: DiffSeverity;
42
+ readonly method: string;
43
+ readonly path: string;
44
+ /** Which part of the contract changed; "route" for add/remove of the whole route. */
45
+ readonly section: "route" | "body" | "query" | "response" | "sse" | "errors";
46
+ /** The top-level field (or error status) the change is about, when field-granular. */
47
+ readonly field?: string;
48
+ readonly message: string;
49
+ }
50
+ export interface RoutesDiff {
51
+ readonly changes: readonly RouteChange[];
52
+ /** True when any change is `breaking` — the CI-gate signal. */
53
+ readonly hasBreaking: boolean;
54
+ }
55
+ /**
56
+ * Snapshot an app's routes (anything `reflectRoutes` accepts) as plain JSON. Validators are
57
+ * dropped; only introspectable JSON Schema metadata is kept, so the result round-trips through
58
+ * `JSON.stringify` unchanged.
59
+ */
60
+ export declare function snapshotRoutes(source: unknown): readonly RouteSnapshot[];
61
+ /**
62
+ * Diff two route snapshots (`snapshotRoutes` output, possibly restored from JSON). Every change is
63
+ * classified breaking/compatible/info; `hasBreaking` is the CI-gate bit.
64
+ */
65
+ export declare function diffRouteSnapshots(before: readonly RouteSnapshot[], after: readonly RouteSnapshot[]): RoutesDiff;
66
+ //# sourceMappingURL=diff.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diff.d.ts","sourceRoot":"","sources":["../src/diff.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EACL,KAAK,UAAU,EAEf,KAAK,oBAAoB,EAE1B,MAAM,iBAAiB,CAAA;AAExB,kFAAkF;AAClF,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,UAAU,CAAC,EAAE,UAAU,CAAA;IAChC,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,oBAAoB,EAAE,CAAA;CAClD;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,IAAI,CAAC,EAAE,cAAc,CAAA;IAC9B,QAAQ,CAAC,KAAK,CAAC,EAAE,cAAc,CAAA;IAC/B,QAAQ,CAAC,QAAQ,CAAC,EAAE,cAAc,CAAA;IAClC,QAAQ,CAAC,GAAG,CAAC,EAAE,cAAc,CAAA;IAC7B,QAAQ,CAAC,MAAM,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC,CAAA;CAC3D;AAED,8EAA8E;AAC9E,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,MAAM,CAAC,EAAE,mBAAmB,CAAA;CACtC;AAED,MAAM,MAAM,YAAY,GAAG,UAAU,GAAG,YAAY,GAAG,MAAM,CAAA;AAE7D,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,QAAQ,EAAE,YAAY,CAAA;IAC/B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,qFAAqF;IACrF,QAAQ,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,GAAG,OAAO,GAAG,UAAU,GAAG,KAAK,GAAG,QAAQ,CAAA;IAC5E,sFAAsF;IACtF,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CACzB;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,OAAO,EAAE,SAAS,WAAW,EAAE,CAAA;IACxC,+DAA+D;IAC/D,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAA;CAC9B;AAiBD;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,OAAO,GAAG,SAAS,aAAa,EAAE,CAExE;AA+OD;;;GAGG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,SAAS,aAAa,EAAE,EAChC,KAAK,EAAE,SAAS,aAAa,EAAE,GAC9B,UAAU,CA+CZ"}
package/dist/diff.js ADDED
@@ -0,0 +1,264 @@
1
+ /**
2
+ * API breaking-change detection over route reflection.
3
+ *
4
+ * `snapshotRoutes` turns an app (or reflected descriptors) into a plain-JSON snapshot — the
5
+ * `standard` validators are dropped, so a snapshot survives `JSON.stringify` and can be committed
6
+ * as a CI baseline. `diffRouteSnapshots` compares two snapshots and classifies every change by
7
+ * wire compatibility, direction-aware:
8
+ *
9
+ * request direction (body/query — what clients SEND): a new required field, a removed field, or
10
+ * a narrowed type breaks existing callers; widening (new optional field, enum superset,
11
+ * required→optional) is compatible.
12
+ * response direction (response/sse/errors — what clients RECEIVE): a removed field, a field made
13
+ * optional, or a widened type breaks existing readers; narrowing (new field, optional→required,
14
+ * enum subset) is compatible.
15
+ *
16
+ * The classifier FAILS CLOSED: a schema change it cannot prove compatible is reported as breaking.
17
+ * Schemas without JSON Schema metadata (validation-only Standard Schemas) cannot be compared and
18
+ * yield `info` — never a silent pass presented as proof.
19
+ */
20
+ import { reflectRoutes, } from "./reflection.js";
21
+ const schemaSnapshot = (reflection) => {
22
+ if (reflection === undefined)
23
+ return undefined;
24
+ return {
25
+ ...(reflection.jsonSchema !== undefined ? { jsonSchema: reflection.jsonSchema } : {}),
26
+ ...(reflection.fields !== undefined ? { fields: reflection.fields } : {}),
27
+ };
28
+ };
29
+ /**
30
+ * Snapshot an app's routes (anything `reflectRoutes` accepts) as plain JSON. Validators are
31
+ * dropped; only introspectable JSON Schema metadata is kept, so the result round-trips through
32
+ * `JSON.stringify` unchanged.
33
+ */
34
+ export function snapshotRoutes(source) {
35
+ return reflectRoutes(source).map((route) => snapshotRoute(route));
36
+ }
37
+ const snapshotRoute = (route) => {
38
+ const schema = route.schema;
39
+ if (schema === undefined)
40
+ return { method: route.method, path: route.path };
41
+ const errors = {};
42
+ for (const [status, reflection] of Object.entries(schema.errors ?? {})) {
43
+ const snapped = schemaSnapshot(reflection);
44
+ if (snapped !== undefined)
45
+ errors[status] = snapped;
46
+ }
47
+ const body = schemaSnapshot(schema.body);
48
+ const query = schemaSnapshot(schema.query);
49
+ const response = schemaSnapshot(schema.response);
50
+ const sse = schemaSnapshot(schema.sse);
51
+ const snapped = {
52
+ ...(body !== undefined ? { body } : {}),
53
+ ...(query !== undefined ? { query } : {}),
54
+ ...(response !== undefined ? { response } : {}),
55
+ ...(sse !== undefined ? { sse } : {}),
56
+ ...(Object.keys(errors).length > 0 ? { errors } : {}),
57
+ };
58
+ return {
59
+ method: route.method,
60
+ path: route.path,
61
+ ...(Object.keys(snapped).length > 0 ? { schema: snapped } : {}),
62
+ };
63
+ };
64
+ const jsonEqual = (a, b) => JSON.stringify(a) === JSON.stringify(b);
65
+ const enumOf = (schema) => {
66
+ if (typeof schema !== "object" || schema === null)
67
+ return undefined;
68
+ const candidate = schema.enum;
69
+ return Array.isArray(candidate) ? candidate : undefined;
70
+ };
71
+ const withoutEnum = (schema) => {
72
+ if (typeof schema !== "object" || schema === null)
73
+ return schema;
74
+ const { enum: _omitted, ...rest } = schema;
75
+ return rest;
76
+ };
77
+ const isSuperset = (outer, inner) => {
78
+ const keys = new Set(outer.map((value) => JSON.stringify(value)));
79
+ return inner.every((value) => keys.has(JSON.stringify(value)));
80
+ };
81
+ /**
82
+ * Compare two JSON Schemas for one position. Returns the change severity, or `undefined` when
83
+ * they are equivalent. The only refinement proven compatible is an enum-only change in the
84
+ * safe direction (request may widen, response may narrow); everything else fails closed.
85
+ */
86
+ const compareJsonSchema = (direction, before, after) => {
87
+ if (jsonEqual(before, after))
88
+ return undefined;
89
+ const beforeEnum = enumOf(before);
90
+ const afterEnum = enumOf(after);
91
+ if (beforeEnum !== undefined &&
92
+ afterEnum !== undefined &&
93
+ jsonEqual(withoutEnum(before), withoutEnum(after))) {
94
+ const compatible = direction === "request"
95
+ ? isSuperset(afterEnum, beforeEnum)
96
+ : isSuperset(beforeEnum, afterEnum);
97
+ return compatible ? "compatible" : "breaking";
98
+ }
99
+ return "breaking";
100
+ };
101
+ const push = (ctx, severity, message, field) => {
102
+ ctx.changes.push({
103
+ severity,
104
+ method: ctx.method,
105
+ path: ctx.path,
106
+ section: ctx.section,
107
+ ...(field !== undefined ? { field } : {}),
108
+ message,
109
+ });
110
+ };
111
+ const fieldMap = (snapshot) => {
112
+ if (snapshot.fields === undefined)
113
+ return undefined;
114
+ return new Map(snapshot.fields.map((field) => [field.name, field]));
115
+ };
116
+ const diffFields = (ctx, before, after) => {
117
+ const beforeFields = fieldMap(before);
118
+ const afterFields = fieldMap(after);
119
+ if (beforeFields === undefined || afterFields === undefined) {
120
+ // Non-object schemas: compare the whole JSON Schema in one step.
121
+ const severity = compareJsonSchema(ctx.direction, before.jsonSchema, after.jsonSchema);
122
+ if (severity !== undefined)
123
+ push(ctx, severity, `${ctx.section} schema changed`);
124
+ return;
125
+ }
126
+ for (const [name, beforeField] of beforeFields) {
127
+ const afterField = afterFields.get(name);
128
+ if (afterField === undefined) {
129
+ // Request: strict validators reject payloads still sending the field. Response: readers lose it.
130
+ push(ctx, "breaking", `field "${name}" removed`, name);
131
+ continue;
132
+ }
133
+ if (beforeField.required !== afterField.required) {
134
+ const nowRequired = afterField.required;
135
+ const breaking = ctx.direction === "request" ? nowRequired : !nowRequired;
136
+ push(ctx, breaking ? "breaking" : "compatible", `field "${name}" is now ${nowRequired ? "required" : "optional"}`, name);
137
+ }
138
+ const severity = compareJsonSchema(ctx.direction, beforeField.schema, afterField.schema);
139
+ if (severity !== undefined)
140
+ push(ctx, severity, `field "${name}" type changed`, name);
141
+ }
142
+ for (const [name, afterField] of afterFields) {
143
+ if (beforeFields.has(name))
144
+ continue;
145
+ if (ctx.direction === "request") {
146
+ push(ctx, afterField.required ? "breaking" : "compatible", `${afterField.required ? "required" : "optional"} field "${name}" added`, name);
147
+ }
148
+ else {
149
+ push(ctx, "compatible", `field "${name}" added`, name);
150
+ }
151
+ }
152
+ };
153
+ const diffSchemaSection = (ctx, before, after) => {
154
+ if (before === undefined && after === undefined)
155
+ return;
156
+ if (before === undefined) {
157
+ // A new request contract rejects payloads old clients send freely; a new response contract
158
+ // only documents what was already returned.
159
+ push(ctx, ctx.direction === "request" ? "breaking" : "compatible", `${ctx.section} schema added`);
160
+ return;
161
+ }
162
+ if (after === undefined) {
163
+ // Dropping a request contract loosens validation; dropping a response contract removes a
164
+ // documented shape clients (and typed consumers) rely on.
165
+ push(ctx, ctx.direction === "request" ? "compatible" : "breaking", `${ctx.section} schema removed`);
166
+ return;
167
+ }
168
+ if (before.jsonSchema === undefined || after.jsonSchema === undefined) {
169
+ // Validation-only schemas expose no JSON Schema metadata — nothing provable either way.
170
+ if (before.jsonSchema !== after.jsonSchema || before.fields !== after.fields) {
171
+ push(ctx, "info", `${ctx.section} schema is not introspectable — cannot verify compatibility`);
172
+ }
173
+ return;
174
+ }
175
+ diffFields(ctx, before, after);
176
+ };
177
+ const diffErrors = (method, path, changes, before, after) => {
178
+ const beforeEntries = before ?? {};
179
+ const afterEntries = after ?? {};
180
+ for (const [status, beforeSchema] of Object.entries(beforeEntries)) {
181
+ const afterSchema = afterEntries[status];
182
+ if (afterSchema === undefined) {
183
+ // Clients parsing this structured error body lose a documented shape.
184
+ changes.push({
185
+ severity: "breaking",
186
+ method,
187
+ path,
188
+ section: "errors",
189
+ field: status,
190
+ message: `error ${status} removed from the contract`,
191
+ });
192
+ continue;
193
+ }
194
+ const ctx = { method, path, section: "errors", direction: "response", changes };
195
+ if (beforeSchema.jsonSchema === undefined || afterSchema.jsonSchema === undefined) {
196
+ if (!jsonEqual(beforeSchema, afterSchema)) {
197
+ push(ctx, "info", `error ${status} schema is not introspectable`, status);
198
+ }
199
+ continue;
200
+ }
201
+ const severity = compareJsonSchema("response", beforeSchema.jsonSchema, afterSchema.jsonSchema);
202
+ if (severity !== undefined)
203
+ push(ctx, severity, `error ${status} schema changed`, status);
204
+ }
205
+ for (const status of Object.keys(afterEntries)) {
206
+ if (status in beforeEntries)
207
+ continue;
208
+ changes.push({
209
+ severity: "compatible",
210
+ method,
211
+ path,
212
+ section: "errors",
213
+ field: status,
214
+ message: `error ${status} added to the contract`,
215
+ });
216
+ }
217
+ };
218
+ const routeKey = (route) => `${route.method.toUpperCase()} ${route.path}`;
219
+ /**
220
+ * Diff two route snapshots (`snapshotRoutes` output, possibly restored from JSON). Every change is
221
+ * classified breaking/compatible/info; `hasBreaking` is the CI-gate bit.
222
+ */
223
+ export function diffRouteSnapshots(before, after) {
224
+ const changes = [];
225
+ const afterByKey = new Map(after.map((route) => [routeKey(route), route]));
226
+ const beforeKeys = new Set(before.map((route) => routeKey(route)));
227
+ for (const beforeRoute of before) {
228
+ const afterRoute = afterByKey.get(routeKey(beforeRoute));
229
+ if (afterRoute === undefined) {
230
+ changes.push({
231
+ severity: "breaking",
232
+ method: beforeRoute.method,
233
+ path: beforeRoute.path,
234
+ section: "route",
235
+ message: "route removed",
236
+ });
237
+ continue;
238
+ }
239
+ const method = beforeRoute.method;
240
+ const path = beforeRoute.path;
241
+ const beforeSchema = beforeRoute.schema ?? {};
242
+ const afterSchema = afterRoute.schema ?? {};
243
+ for (const section of ["body", "query"]) {
244
+ diffSchemaSection({ method, path, section, direction: "request", changes }, beforeSchema[section], afterSchema[section]);
245
+ }
246
+ for (const section of ["response", "sse"]) {
247
+ diffSchemaSection({ method, path, section, direction: "response", changes }, beforeSchema[section], afterSchema[section]);
248
+ }
249
+ diffErrors(method, path, changes, beforeSchema.errors, afterSchema.errors);
250
+ }
251
+ for (const afterRoute of after) {
252
+ if (beforeKeys.has(routeKey(afterRoute)))
253
+ continue;
254
+ changes.push({
255
+ severity: "compatible",
256
+ method: afterRoute.method,
257
+ path: afterRoute.path,
258
+ section: "route",
259
+ message: "route added",
260
+ });
261
+ }
262
+ return { changes, hasBreaking: changes.some((change) => change.severity === "breaking") };
263
+ }
264
+ //# sourceMappingURL=diff.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diff.js","sourceRoot":"","sources":["../src/diff.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -11,10 +11,12 @@
11
11
  * (it shipped at "0.0.0" through 1.0.0 before those guards existed). Kept narrow (`as const`) so
12
12
  * consumers can pin it at the type level — see `test/version.test-d.ts`.
13
13
  */
14
- export declare const VERSION: "1.3.1";
14
+ export declare const VERSION: "1.5.0";
15
15
  export type Version = typeof VERSION;
16
+ export * from "./diff.js";
16
17
  export { FrameworkError, RouteConfigError, type RouteConfigErrorCode } from "./errors.js";
17
18
  export { FRAMEWORK_NAME, type FrameworkName } from "./internal/brand.js";
19
+ export * from "./reflection.js";
18
20
  export { METHODS, type Method, Router, type RouterMatch } from "./router/router.js";
19
21
  export type { InferInput, InferOutput, StandardIssue, StandardResult, StandardSchemaV1, StandardTypes, ValidationOutcome, } from "./schema/standard.js";
20
22
  export { validateStandard } from "./schema/standard.js";
@@ -24,8 +26,8 @@ export { type ContextForOp, type ContractShape, defineContract, type HandlersFor
24
26
  export { type CookieOptions, parseCookies, serializeCookie, signValue, unsignValue, } from "./server/cookies.js";
25
27
  export { commonSecretPatterns, jsonLogger, type LogFields, type Logger, type RedactOptions, redactLogFields, silentLogger, } from "./server/logger.js";
26
28
  export type { Registry, RouteInfo } from "./server/registry.js";
27
- export { type AnyServer, type DurableObjectNamespaceLike, defineIdentityPlugin, definePlugin, defineRouterPlugin, type ExecutionContext, type Handler, type IdentityPlugin, type McpPromptDescriptor, type McpResourceDescriptor, type Middleware, type NifraPlugin, type NodeServeOutcome, type OnRequestResult, type PromptArgument, type PromptMessage, type RouteDescriptor, type RunningServer, type ScheduledController, type ScheduledHandler, Server, type ServerOptions, server, type ToolAnnotations, toFetchHandler, } from "./server/server.js";
28
- export { type SSEContext, type SSEInit, type SSEMessage, type SSEStream, sse, } from "./server/sse.js";
29
+ export { type AnyServer, type DurableObjectNamespaceLike, defineIdentityPlugin, definePlugin, defineRouterPlugin, type ExecutionContext, type Handler, type IdentityPlugin, type McpPromptDescriptor, type McpResourceDescriptor, type Middleware, type NifraPlugin, type NodeServeOutcome, type OnRequestResult, type PromptArgument, type PromptMessage, type ResponseFinalization, type RouteDescriptor, type RunningServer, type ScheduledController, type ScheduledHandler, Server, type ServerOptions, server, type ToolAnnotations, toFetchHandler, } from "./server/server.js";
30
+ export { type SSEContext, type SSEInit, type SSEMessage, type SSEStream, sse, type TypedSSEStream, typedSSEStream, } from "./server/sse.js";
29
31
  export { type SignatureEncoding, type VerifyWebhookOptions, verifyWebhook, type WebhookFailureReason, type WebhookProvider, type WebhookResult, } from "./server/webhook.js";
30
32
  export type { NifraWebSocket, StandardWebSocket, WebSocketContext, WebSocketData, WebSocketHandler, WebSocketUpgradeOutcome, } from "./server/websocket.js";
31
33
  export { attachWebSocket, TopicRegistry } from "./server/websocket.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;;;;;GAMG;AACH,eAAO,MAAM,OAAO,EAAG,OAAgB,CAAA;AAEvC,MAAM,MAAM,OAAO,GAAG,OAAO,OAAO,CAAA;AAEpC,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,KAAK,oBAAoB,EAAE,MAAM,aAAa,CAAA;AACzF,OAAO,EAAE,cAAc,EAAE,KAAK,aAAa,EAAE,MAAM,qBAAqB,CAAA;AACxE,OAAO,EAAE,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,EAAE,KAAK,WAAW,EAAE,MAAM,oBAAoB,CAAA;AACnF,YAAY,EACV,UAAU,EACV,WAAW,EACX,aAAa,EACb,cAAc,EACd,gBAAgB,EAChB,aAAa,EACb,iBAAiB,GAClB,MAAM,sBAAsB,CAAA;AAC7B,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AACvD,OAAO,EACL,KAAK,aAAa,EAClB,KAAK,UAAU,EACf,MAAM,EACN,KAAK,iBAAiB,EACtB,KAAK,YAAY,EACjB,KAAK,cAAc,EACnB,OAAO,GACR,MAAM,UAAU,CAAA;AACjB,YAAY,EACV,OAAO,EACP,MAAM,EACN,QAAQ,EACR,QAAQ,EACR,gBAAgB,EAChB,WAAW,GACZ,MAAM,qBAAqB,CAAA;AAC5B,OAAO,EACL,KAAK,YAAY,EACjB,KAAK,aAAa,EAClB,cAAc,EACd,KAAK,WAAW,EAChB,SAAS,EACT,KAAK,YAAY,EACjB,KAAK,WAAW,EAChB,KAAK,gBAAgB,EACrB,KAAK,WAAW,GACjB,MAAM,sBAAsB,CAAA;AAC7B,OAAO,EACL,KAAK,aAAa,EAClB,YAAY,EACZ,eAAe,EACf,SAAS,EACT,WAAW,GACZ,MAAM,qBAAqB,CAAA;AAC5B,OAAO,EACL,oBAAoB,EACpB,UAAU,EACV,KAAK,SAAS,EACd,KAAK,MAAM,EACX,KAAK,aAAa,EAClB,eAAe,EACf,YAAY,GACb,MAAM,oBAAoB,CAAA;AAC3B,YAAY,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAA;AAC/D,OAAO,EACL,KAAK,SAAS,EACd,KAAK,0BAA0B,EAC/B,oBAAoB,EACpB,YAAY,EACZ,kBAAkB,EAClB,KAAK,gBAAgB,EACrB,KAAK,OAAO,EACZ,KAAK,cAAc,EACnB,KAAK,mBAAmB,EACxB,KAAK,qBAAqB,EAC1B,KAAK,UAAU,EACf,KAAK,WAAW,EAChB,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACpB,KAAK,cAAc,EACnB,KAAK,aAAa,EAClB,KAAK,eAAe,EACpB,KAAK,aAAa,EAClB,KAAK,mBAAmB,EACxB,KAAK,gBAAgB,EACrB,MAAM,EACN,KAAK,aAAa,EAClB,MAAM,EACN,KAAK,eAAe,EACpB,cAAc,GACf,MAAM,oBAAoB,CAAA;AAC3B,OAAO,EACL,KAAK,UAAU,EACf,KAAK,OAAO,EACZ,KAAK,UAAU,EACf,KAAK,SAAS,EACd,GAAG,GACJ,MAAM,iBAAiB,CAAA;AACxB,OAAO,EACL,KAAK,iBAAiB,EACtB,KAAK,oBAAoB,EACzB,aAAa,EACb,KAAK,oBAAoB,EACzB,KAAK,eAAe,EACpB,KAAK,aAAa,GACnB,MAAM,qBAAqB,CAAA;AAC5B,YAAY,EACV,cAAc,EACd,iBAAiB,EACjB,gBAAgB,EAChB,aAAa,EACb,gBAAgB,EAChB,uBAAuB,GACxB,MAAM,uBAAuB,CAAA;AAC9B,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -11,9 +11,11 @@
11
11
  * (it shipped at "0.0.0" through 1.0.0 before those guards existed). Kept narrow (`as const`) so
12
12
  * consumers can pin it at the type level — see `test/version.test-d.ts`.
13
13
  */
14
- export const VERSION = "1.3.1";
14
+ export const VERSION = "1.5.0";
15
+ export * from "./diff.js";
15
16
  export { FrameworkError, RouteConfigError } from "./errors.js";
16
17
  export { FRAMEWORK_NAME } from "./internal/brand.js";
18
+ export * from "./reflection.js";
17
19
  export { METHODS, Router } from "./router/router.js";
18
20
  export { validateStandard } from "./schema/standard.js";
19
21
  export { robots, sitemap, } from "./seo.js";
@@ -21,7 +23,7 @@ export { defineContract, implement, } from "./server/contract.js";
21
23
  export { parseCookies, serializeCookie, signValue, unsignValue, } from "./server/cookies.js";
22
24
  export { commonSecretPatterns, jsonLogger, redactLogFields, silentLogger, } from "./server/logger.js";
23
25
  export { defineIdentityPlugin, definePlugin, defineRouterPlugin, Server, server, toFetchHandler, } from "./server/server.js";
24
- export { sse, } from "./server/sse.js";
26
+ export { sse, typedSSEStream, } from "./server/sse.js";
25
27
  export { verifyWebhook, } from "./server/webhook.js";
26
28
  export { attachWebSocket, TopicRegistry } from "./server/websocket.js";
27
29
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,OAAO,GAAG,OAAgB,CAAA;AAIvC,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAA6B,MAAM,aAAa,CAAA;AACzF,OAAO,EAAE,cAAc,EAAsB,MAAM,qBAAqB,CAAA;AACxE,OAAO,EAAE,OAAO,EAAe,MAAM,EAAoB,MAAM,oBAAoB,CAAA;AAUnF,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AACvD,OAAO,EAGL,MAAM,EAIN,OAAO,GACR,MAAM,UAAU,CAAA;AASjB,OAAO,EAGL,cAAc,EAEd,SAAS,GAKV,MAAM,sBAAsB,CAAA;AAC7B,OAAO,EAEL,YAAY,EACZ,eAAe,EACf,SAAS,EACT,WAAW,GACZ,MAAM,qBAAqB,CAAA;AAC5B,OAAO,EACL,oBAAoB,EACpB,UAAU,EAIV,eAAe,EACf,YAAY,GACb,MAAM,oBAAoB,CAAA;AAE3B,OAAO,EAGL,oBAAoB,EACpB,YAAY,EACZ,kBAAkB,EAgBlB,MAAM,EAEN,MAAM,EAEN,cAAc,GACf,MAAM,oBAAoB,CAAA;AAC3B,OAAO,EAKL,GAAG,GACJ,MAAM,iBAAiB,CAAA;AACxB,OAAO,EAGL,aAAa,GAId,MAAM,qBAAqB,CAAA;AAS5B,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,OAAO,GAAG,OAAgB,CAAA;AAIvC,cAAc,WAAW,CAAA;AACzB,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAA6B,MAAM,aAAa,CAAA;AACzF,OAAO,EAAE,cAAc,EAAsB,MAAM,qBAAqB,CAAA;AACxE,cAAc,iBAAiB,CAAA;AAC/B,OAAO,EAAE,OAAO,EAAe,MAAM,EAAoB,MAAM,oBAAoB,CAAA;AAUnF,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AACvD,OAAO,EAGL,MAAM,EAIN,OAAO,GACR,MAAM,UAAU,CAAA;AASjB,OAAO,EAGL,cAAc,EAEd,SAAS,GAKV,MAAM,sBAAsB,CAAA;AAC7B,OAAO,EAEL,YAAY,EACZ,eAAe,EACf,SAAS,EACT,WAAW,GACZ,MAAM,qBAAqB,CAAA;AAC5B,OAAO,EACL,oBAAoB,EACpB,UAAU,EAIV,eAAe,EACf,YAAY,GACb,MAAM,oBAAoB,CAAA;AAE3B,OAAO,EAGL,oBAAoB,EACpB,YAAY,EACZ,kBAAkB,EAiBlB,MAAM,EAEN,MAAM,EAEN,cAAc,GACf,MAAM,oBAAoB,CAAA;AAC3B,OAAO,EAKL,GAAG,EAEH,cAAc,GACf,MAAM,iBAAiB,CAAA;AACxB,OAAO,EAGL,aAAa,GAId,MAAM,qBAAqB,CAAA;AAS5B,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAA"}
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Runtime reflection for schemas and registered routes.
3
+ *
4
+ * Standard Schema deliberately standardizes validation, not introspection. This module makes that
5
+ * distinction explicit: `standard` is present when a value can validate, while `jsonSchema` and
6
+ * `fields` are present only when the value carries inspectable JSON Schema metadata. The implementation
7
+ * recognizes Nifra/TypeBox carriers and raw JSON Schema without depending on a validator package.
8
+ */
9
+ import type { StandardSchemaV1 } from "./schema/standard.js";
10
+ import type { ToolAnnotations } from "./server/server.js";
11
+ /** JSON Schema permits either a schema object or the boolean schemas `true` and `false`. */
12
+ export type JsonSchema = boolean | Readonly<Record<string, unknown>>;
13
+ /** One top-level property of an introspectable object schema. */
14
+ export interface ReflectedSchemaField {
15
+ readonly name: string;
16
+ readonly required: boolean;
17
+ readonly schema: JsonSchema;
18
+ }
19
+ /** Validation and introspection capabilities discovered for one schema-like value. */
20
+ export interface SchemaReflection {
21
+ /** The Standard Schema validator, when the value implements Standard Schema v1. */
22
+ readonly standard: StandardSchemaV1 | undefined;
23
+ /** Raw JSON Schema metadata, when the value exposes it or is itself a raw JSON Schema. */
24
+ readonly jsonSchema: JsonSchema | undefined;
25
+ /** Top-level object fields, or `undefined` when the JSON Schema is absent/non-object. */
26
+ readonly fields: readonly ReflectedSchemaField[] | undefined;
27
+ }
28
+ export interface ReflectedRouteSchema {
29
+ readonly body?: SchemaReflection;
30
+ readonly query?: SchemaReflection;
31
+ readonly response?: SchemaReflection;
32
+ readonly errors?: Readonly<Record<string, SchemaReflection>>;
33
+ /** The SSE event-payload schema of a typed streaming route (`app.sse()`). */
34
+ readonly sse?: SchemaReflection;
35
+ }
36
+ export interface ReflectedRoute {
37
+ readonly method: string;
38
+ readonly path: string;
39
+ readonly schema?: ReflectedRouteSchema;
40
+ readonly tool?: {
41
+ readonly name: string;
42
+ readonly description: string;
43
+ readonly annotations?: ToolAnnotations;
44
+ };
45
+ }
46
+ /**
47
+ * Reflect a Standard Schema, Nifra/TypeBox schema carrier, or raw JSON Schema. Never throws.
48
+ * Validation-only schemas have `standard` but no `jsonSchema`; raw JSON Schema has the reverse.
49
+ */
50
+ export declare function reflectSchema(value: unknown): SchemaReflection;
51
+ /**
52
+ * Safely enumerate and normalize route descriptors from an app or descriptor array. Invalid entries
53
+ * are ignored; a missing/throwing `routes()` method yields an empty array.
54
+ */
55
+ export declare function reflectRoutes(source: unknown): readonly ReflectedRoute[];
56
+ //# sourceMappingURL=reflection.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reflection.d.ts","sourceRoot":"","sources":["../src/reflection.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AAC5D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAA;AAEzD,4FAA4F;AAC5F,MAAM,MAAM,UAAU,GAAG,OAAO,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAA;AAEpE,iEAAiE;AACjE,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAA;IAC1B,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAA;CAC5B;AAED,sFAAsF;AACtF,MAAM,WAAW,gBAAgB;IAC/B,mFAAmF;IACnF,QAAQ,CAAC,QAAQ,EAAE,gBAAgB,GAAG,SAAS,CAAA;IAC/C,0FAA0F;IAC1F,QAAQ,CAAC,UAAU,EAAE,UAAU,GAAG,SAAS,CAAA;IAC3C,yFAAyF;IACzF,QAAQ,CAAC,MAAM,EAAE,SAAS,oBAAoB,EAAE,GAAG,SAAS,CAAA;CAC7D;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,IAAI,CAAC,EAAE,gBAAgB,CAAA;IAChC,QAAQ,CAAC,KAAK,CAAC,EAAE,gBAAgB,CAAA;IACjC,QAAQ,CAAC,QAAQ,CAAC,EAAE,gBAAgB,CAAA;IACpC,QAAQ,CAAC,MAAM,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC,CAAA;IAC5D,6EAA6E;IAC7E,QAAQ,CAAC,GAAG,CAAC,EAAE,gBAAgB,CAAA;CAChC;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,MAAM,CAAC,EAAE,oBAAoB,CAAA;IACtC,QAAQ,CAAC,IAAI,CAAC,EAAE;QACd,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;QACrB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;QAC5B,QAAQ,CAAC,WAAW,CAAC,EAAE,eAAe,CAAA;KACvC,CAAA;CACF;AAyED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,gBAAgB,CAI9D;AA6CD;;;GAGG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,OAAO,GAAG,SAAS,cAAc,EAAE,CAexE"}
@@ -0,0 +1,154 @@
1
+ /**
2
+ * Runtime reflection for schemas and registered routes.
3
+ *
4
+ * Standard Schema deliberately standardizes validation, not introspection. This module makes that
5
+ * distinction explicit: `standard` is present when a value can validate, while `jsonSchema` and
6
+ * `fields` are present only when the value carries inspectable JSON Schema metadata. The implementation
7
+ * recognizes Nifra/TypeBox carriers and raw JSON Schema without depending on a validator package.
8
+ */
9
+ const recordOf = (value) => value !== null && typeof value === "object"
10
+ ? value
11
+ : undefined;
12
+ const standardOf = (value) => {
13
+ const record = recordOf(value);
14
+ const standard = recordOf(record?.["~standard"]);
15
+ return standard?.version === 1 && typeof standard.validate === "function"
16
+ ? value
17
+ : undefined;
18
+ };
19
+ const jsonSchemaOf = (value, standard) => {
20
+ const record = recordOf(value);
21
+ if (record !== undefined && "jsonSchema" in record) {
22
+ const carried = record.jsonSchema;
23
+ return normalizeJsonSchema(carried);
24
+ }
25
+ // Some Standard Schema implementations (including TypeBox-shaped adapters) expose an object
26
+ // schema directly rather than through `.jsonSchema`. Only treat an inspectable object shape as
27
+ // metadata here; validation-library internals are otherwise intentionally opaque.
28
+ if (standard !== undefined) {
29
+ return recordOf(record?.properties) !== undefined ? normalizeJsonSchema(record) : undefined;
30
+ }
31
+ // A malformed/opaque Standard Schema marker is not raw JSON Schema metadata.
32
+ if (record !== undefined && "~standard" in record)
33
+ return undefined;
34
+ if (typeof value === "boolean" || record !== undefined)
35
+ return normalizeJsonSchema(value);
36
+ return undefined;
37
+ };
38
+ /** Strip symbol keys and other non-JSON metadata carried by schema-builder objects. */
39
+ const normalizeJsonSchema = (value) => {
40
+ if (typeof value === "boolean")
41
+ return value;
42
+ if (recordOf(value) === undefined)
43
+ return undefined;
44
+ try {
45
+ const normalized = JSON.parse(JSON.stringify(value));
46
+ if (typeof normalized === "boolean")
47
+ return normalized;
48
+ const record = recordOf(normalized);
49
+ if (record === undefined)
50
+ return undefined;
51
+ // `~standard` is a Standard Schema *validation* marker, never valid JSON Schema. A TypeBox-shaped
52
+ // carrier (a JSON Schema object that also carries `~standard`, with no separate `.jsonSchema`) would
53
+ // otherwise leak the marker into emitted OpenAPI / mock / form output.
54
+ if (!("~standard" in record))
55
+ return record;
56
+ const { ["~standard"]: _omitted, ...rest } = record;
57
+ return rest;
58
+ }
59
+ catch {
60
+ return undefined;
61
+ }
62
+ };
63
+ const fieldsOf = (schema) => {
64
+ const record = recordOf(schema);
65
+ const properties = recordOf(record?.properties);
66
+ if (properties === undefined)
67
+ return undefined;
68
+ const required = new Set(Array.isArray(record?.required)
69
+ ? record.required.filter((name) => typeof name === "string")
70
+ : []);
71
+ const fields = [];
72
+ for (const [name, property] of Object.entries(properties)) {
73
+ if (typeof property !== "boolean" && recordOf(property) === undefined)
74
+ continue;
75
+ fields.push({ name, required: required.has(name), schema: property });
76
+ }
77
+ return fields;
78
+ };
79
+ /**
80
+ * Reflect a Standard Schema, Nifra/TypeBox schema carrier, or raw JSON Schema. Never throws.
81
+ * Validation-only schemas have `standard` but no `jsonSchema`; raw JSON Schema has the reverse.
82
+ */
83
+ export function reflectSchema(value) {
84
+ const standard = standardOf(value);
85
+ const jsonSchema = jsonSchemaOf(value, standard);
86
+ return { standard, jsonSchema, fields: fieldsOf(jsonSchema) };
87
+ }
88
+ const routeCandidates = (source) => {
89
+ if (Array.isArray(source))
90
+ return source;
91
+ const record = recordOf(source);
92
+ if (typeof record?.routes !== "function")
93
+ return [];
94
+ try {
95
+ const routes = record.routes();
96
+ return Array.isArray(routes) ? routes : [];
97
+ }
98
+ catch {
99
+ return [];
100
+ }
101
+ };
102
+ const reflectedRouteSchema = (value) => {
103
+ const schema = recordOf(value);
104
+ if (schema === undefined)
105
+ return undefined;
106
+ const errors = recordOf(schema.errors);
107
+ const reflectedErrors = {};
108
+ if (errors !== undefined) {
109
+ for (const [status, errorSchema] of Object.entries(errors)) {
110
+ reflectedErrors[status] = reflectSchema(errorSchema);
111
+ }
112
+ }
113
+ return {
114
+ ...(schema.body !== undefined ? { body: reflectSchema(schema.body) } : {}),
115
+ ...(schema.query !== undefined ? { query: reflectSchema(schema.query) } : {}),
116
+ ...(schema.response !== undefined ? { response: reflectSchema(schema.response) } : {}),
117
+ ...(Object.keys(reflectedErrors).length > 0 ? { errors: reflectedErrors } : {}),
118
+ ...(schema.sse !== undefined ? { sse: reflectSchema(schema.sse) } : {}),
119
+ };
120
+ };
121
+ const reflectedTool = (value) => {
122
+ const tool = recordOf(value);
123
+ if (typeof tool?.name !== "string" || typeof tool.description !== "string")
124
+ return undefined;
125
+ return {
126
+ name: tool.name,
127
+ description: tool.description,
128
+ ...(recordOf(tool.annotations) !== undefined
129
+ ? { annotations: tool.annotations }
130
+ : {}),
131
+ };
132
+ };
133
+ /**
134
+ * Safely enumerate and normalize route descriptors from an app or descriptor array. Invalid entries
135
+ * are ignored; a missing/throwing `routes()` method yields an empty array.
136
+ */
137
+ export function reflectRoutes(source) {
138
+ const reflected = [];
139
+ for (const candidate of routeCandidates(source)) {
140
+ const route = recordOf(candidate);
141
+ if (typeof route?.method !== "string" || typeof route.path !== "string")
142
+ continue;
143
+ const schema = reflectedRouteSchema(route.schema);
144
+ const tool = reflectedTool(route.tool);
145
+ reflected.push({
146
+ method: route.method.toUpperCase(),
147
+ path: route.path,
148
+ ...(schema !== undefined ? { schema } : {}),
149
+ ...(tool !== undefined ? { tool } : {}),
150
+ });
151
+ }
152
+ return reflected;
153
+ }
154
+ //# sourceMappingURL=reflection.js.map