@nifrajs/core 1.6.0 → 1.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +20 -0
- package/dist/assurance.d.ts +80 -0
- package/dist/assurance.d.ts.map +1 -0
- package/dist/assurance.js +162 -0
- package/dist/assurance.js.map +1 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/internal/route-assurance.d.ts +36 -0
- package/dist/internal/route-assurance.d.ts.map +1 -0
- package/dist/internal/route-assurance.js +118 -0
- package/dist/internal/route-assurance.js.map +1 -0
- package/dist/reflection.d.ts +2 -0
- package/dist/reflection.d.ts.map +1 -1
- package/dist/reflection.js +12 -1
- package/dist/reflection.js.map +1 -1
- package/dist/server/registry.d.ts +18 -1
- package/dist/server/registry.d.ts.map +1 -1
- package/dist/server/server.d.ts +34 -0
- package/dist/server/server.d.ts.map +1 -1
- package/dist/server/server.js +104 -5
- package/dist/server/server.js.map +1 -1
- package/package.json +6 -1
- package/src/assurance.ts +263 -0
- package/src/index.ts +2 -1
- package/src/internal/route-assurance.ts +166 -0
- package/src/reflection.ts +13 -1
- package/src/server/registry.ts +18 -1
- package/src/server/server.ts +121 -5
package/README.md
CHANGED
|
@@ -31,6 +31,26 @@ export type App = typeof app // hand this to @nifrajs/client for end-to-end type
|
|
|
31
31
|
- **Hardening built in.** `stop({ drainMs })` graceful shutdown (+ opt-in SIGTERM/
|
|
32
32
|
SIGINT), `requestTimeoutMs` (+ `ctx.signal`), a streaming body-size cap, and a
|
|
33
33
|
redacting structured `Logger`.
|
|
34
|
+
- **Route assurance.** Official auth, CSRF, body-limit, rate-limit, idempotency,
|
|
35
|
+
IP-restriction, and security-header modules publish reflection-safe enforcement evidence.
|
|
36
|
+
An ordered `AssurancePolicy` classifies every route and fails closed on missing or forbidden
|
|
37
|
+
evidence without adding work to the request path.
|
|
38
|
+
|
|
39
|
+
```ts
|
|
40
|
+
import { defineAssurancePolicy, evaluateRouteAssurance, NIFRA_ASSURANCE } from "@nifrajs/core/assurance"
|
|
41
|
+
|
|
42
|
+
const policy = defineAssurancePolicy({
|
|
43
|
+
rules: [
|
|
44
|
+
{ name: "health", match: { paths: ["/health"] }, require: [] },
|
|
45
|
+
{ name: "mutation", match: { methods: ["POST", "PUT", "PATCH", "DELETE"] },
|
|
46
|
+
require: [NIFRA_ASSURANCE.AUTHENTICATED, NIFRA_ASSURANCE.CSRF] },
|
|
47
|
+
{ name: "read", match: { methods: ["GET", "HEAD"] },
|
|
48
|
+
require: [NIFRA_ASSURANCE.AUTHENTICATED] },
|
|
49
|
+
],
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
evaluateRouteAssurance(app, policy).ok // pure reflection-time evaluation
|
|
53
|
+
```
|
|
34
54
|
|
|
35
55
|
ESM-only; requires Bun at runtime. MIT.
|
|
36
56
|
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Route assurance: reflection-time proof that every route is classified and carries the enforcement
|
|
3
|
+
* evidence its policy requires. Evaluation is pure and never runs on the request hot path.
|
|
4
|
+
*/
|
|
5
|
+
import type { AssuranceDeclaration, AssuranceEvidence, AssuranceScope } from "./internal/route-assurance.js";
|
|
6
|
+
import { withRouteAssurance } from "./internal/route-assurance.js";
|
|
7
|
+
import { type ReflectedRoute } from "./reflection.js";
|
|
8
|
+
import type { Method } from "./router/router.js";
|
|
9
|
+
export type { AssuranceDeclaration, AssuranceEvidence, AssuranceScope };
|
|
10
|
+
export { withRouteAssurance };
|
|
11
|
+
/** Canonical evidence ids emitted by Nifra's official middleware modules. */
|
|
12
|
+
export declare const NIFRA_ASSURANCE: Readonly<{
|
|
13
|
+
readonly AUTHENTICATED: "nifra.authenticated";
|
|
14
|
+
readonly BODY_BOUNDED: "nifra.body-bounded";
|
|
15
|
+
readonly CSRF: "nifra.csrf";
|
|
16
|
+
readonly IDEMPOTENCY_KEY: "nifra.idempotency-key";
|
|
17
|
+
readonly IP_RESTRICTED: "nifra.ip-restricted";
|
|
18
|
+
readonly RATE_LIMITED: "nifra.rate-limited";
|
|
19
|
+
readonly SECURITY_HEADERS: "nifra.security-headers";
|
|
20
|
+
}>;
|
|
21
|
+
export interface AssuranceRouteSelector {
|
|
22
|
+
/** Omit for every method. */
|
|
23
|
+
readonly methods?: readonly Method[];
|
|
24
|
+
/** Absolute route globs. `*` matches one segment; final `**` matches zero or more. */
|
|
25
|
+
readonly paths?: readonly string[];
|
|
26
|
+
/** Restrict the rule to MCP tool routes (`true`) or non-tool routes (`false`). */
|
|
27
|
+
readonly tools?: boolean;
|
|
28
|
+
}
|
|
29
|
+
export interface AssuranceRule {
|
|
30
|
+
/** Stable human-readable classification included in diagnostics. */
|
|
31
|
+
readonly name: string;
|
|
32
|
+
readonly match: AssuranceRouteSelector;
|
|
33
|
+
/** Evidence ids the route must carry. */
|
|
34
|
+
readonly require?: readonly string[];
|
|
35
|
+
/** Evidence ids the route must not carry (useful for public webhooks and health routes). */
|
|
36
|
+
readonly forbid?: readonly string[];
|
|
37
|
+
}
|
|
38
|
+
export interface AssurancePolicy {
|
|
39
|
+
/** First matching rule owns a route. Put exceptions before broad defaults. */
|
|
40
|
+
readonly rules: readonly AssuranceRule[];
|
|
41
|
+
/** Default `error`: an unclassified route fails closed. */
|
|
42
|
+
readonly unmatched?: "error" | "ignore";
|
|
43
|
+
/** Default false: reject an empty reflected source so a wrong import cannot pass CI silently. */
|
|
44
|
+
readonly allowEmpty?: boolean;
|
|
45
|
+
}
|
|
46
|
+
export type AssuranceFindingCode = "no-routes" | "unclassified-route" | "missing-evidence" | "forbidden-evidence";
|
|
47
|
+
export interface AssuranceFinding {
|
|
48
|
+
readonly code: AssuranceFindingCode;
|
|
49
|
+
readonly method: string;
|
|
50
|
+
readonly path: string;
|
|
51
|
+
readonly rule?: string;
|
|
52
|
+
readonly evidence?: string;
|
|
53
|
+
readonly message: string;
|
|
54
|
+
}
|
|
55
|
+
export interface AssuredRoute {
|
|
56
|
+
readonly method: string;
|
|
57
|
+
readonly path: string;
|
|
58
|
+
readonly rule?: string;
|
|
59
|
+
readonly evidence: readonly AssuranceEvidence[];
|
|
60
|
+
readonly missing: readonly string[];
|
|
61
|
+
readonly forbidden: readonly string[];
|
|
62
|
+
}
|
|
63
|
+
export interface AssuranceReport {
|
|
64
|
+
readonly ok: boolean;
|
|
65
|
+
readonly routes: readonly AssuredRoute[];
|
|
66
|
+
readonly findings: readonly AssuranceFinding[];
|
|
67
|
+
}
|
|
68
|
+
export interface AssuranceConfig {
|
|
69
|
+
readonly source: unknown;
|
|
70
|
+
readonly policy: AssurancePolicy;
|
|
71
|
+
}
|
|
72
|
+
/** Validate and freeze an ordered assurance policy. */
|
|
73
|
+
export declare function defineAssurancePolicy(policy: AssurancePolicy): AssurancePolicy;
|
|
74
|
+
/** Identity helper for a `nifra.assurance.ts` default export. */
|
|
75
|
+
export declare function defineAssuranceConfig(config: AssuranceConfig): AssuranceConfig;
|
|
76
|
+
/** Shared selector semantics for policy rules and framework adapters. */
|
|
77
|
+
export declare function matchesAssuranceSelector(route: Pick<ReflectedRoute, "method" | "path" | "tool">, selector: AssuranceRouteSelector): boolean;
|
|
78
|
+
/** Evaluate reflected route evidence against the first matching policy rule. */
|
|
79
|
+
export declare function evaluateRouteAssurance(source: unknown, policyInput: AssurancePolicy): AssuranceReport;
|
|
80
|
+
//# sourceMappingURL=assurance.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"assurance.d.ts","sourceRoot":"","sources":["../src/assurance.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EACV,oBAAoB,EACpB,iBAAiB,EACjB,cAAc,EACf,MAAM,+BAA+B,CAAA;AACtC,OAAO,EAKL,kBAAkB,EACnB,MAAM,+BAA+B,CAAA;AACtC,OAAO,EAAE,KAAK,cAAc,EAAiB,MAAM,iBAAiB,CAAA;AACpE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAA;AAEhD,YAAY,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,cAAc,EAAE,CAAA;AACvE,OAAO,EAAE,kBAAkB,EAAE,CAAA;AAE7B,6EAA6E;AAC7E,eAAO,MAAM,eAAe;;;;;;;;EAAsB,CAAA;AAElD,MAAM,WAAW,sBAAsB;IACrC,6BAA6B;IAC7B,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IACpC,sFAAsF;IACtF,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IAClC,kFAAkF;IAClF,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CACzB;AAED,MAAM,WAAW,aAAa;IAC5B,oEAAoE;IACpE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,KAAK,EAAE,sBAAsB,CAAA;IACtC,yCAAyC;IACzC,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IACpC,4FAA4F;IAC5F,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;CACpC;AAED,MAAM,WAAW,eAAe;IAC9B,8EAA8E;IAC9E,QAAQ,CAAC,KAAK,EAAE,SAAS,aAAa,EAAE,CAAA;IACxC,2DAA2D;IAC3D,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAA;IACvC,iGAAiG;IACjG,QAAQ,CAAC,UAAU,CAAC,EAAE,OAAO,CAAA;CAC9B;AAED,MAAM,MAAM,oBAAoB,GAC5B,WAAW,GACX,oBAAoB,GACpB,kBAAkB,GAClB,oBAAoB,CAAA;AAExB,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,IAAI,EAAE,oBAAoB,CAAA;IACnC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CACzB;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,QAAQ,EAAE,SAAS,iBAAiB,EAAE,CAAA;IAC/C,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAA;IACnC,QAAQ,CAAC,SAAS,EAAE,SAAS,MAAM,EAAE,CAAA;CACtC;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,EAAE,EAAE,OAAO,CAAA;IACpB,QAAQ,CAAC,MAAM,EAAE,SAAS,YAAY,EAAE,CAAA;IACxC,QAAQ,CAAC,QAAQ,EAAE,SAAS,gBAAgB,EAAE,CAAA;CAC/C;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAA;IACxB,QAAQ,CAAC,MAAM,EAAE,eAAe,CAAA;CACjC;AAsBD,uDAAuD;AACvD,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,eAAe,GAAG,eAAe,CA2D9E;AAED,iEAAiE;AACjE,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,eAAe,GAAG,eAAe,CAE9E;AAED,yEAAyE;AACzE,wBAAgB,wBAAwB,CACtC,KAAK,EAAE,IAAI,CAAC,cAAc,EAAE,QAAQ,GAAG,MAAM,GAAG,MAAM,CAAC,EACvD,QAAQ,EAAE,sBAAsB,GAC/B,OAAO,CAOT;AAED,gFAAgF;AAChF,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,OAAO,EACf,WAAW,EAAE,eAAe,GAC3B,eAAe,CAqEjB"}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Route assurance: reflection-time proof that every route is classified and carries the enforcement
|
|
3
|
+
* evidence its policy requires. Evaluation is pure and never runs on the request hot path.
|
|
4
|
+
*/
|
|
5
|
+
import { NIFRA_ASSURANCE_IDS, routeGlob, validEvidenceId, validMethod, withRouteAssurance, } from "./internal/route-assurance.js";
|
|
6
|
+
import { reflectRoutes } from "./reflection.js";
|
|
7
|
+
export { withRouteAssurance };
|
|
8
|
+
/** Canonical evidence ids emitted by Nifra's official middleware modules. */
|
|
9
|
+
export const NIFRA_ASSURANCE = NIFRA_ASSURANCE_IDS;
|
|
10
|
+
const nonEmpty = (value) => value.trim() !== "";
|
|
11
|
+
function normalizeEvidenceIds(values, label) {
|
|
12
|
+
const out = [];
|
|
13
|
+
const seen = new Set();
|
|
14
|
+
for (const value of values ?? []) {
|
|
15
|
+
if (!validEvidenceId(value)) {
|
|
16
|
+
throw new Error(`route assurance: invalid ${label} evidence id ${JSON.stringify(value)}`);
|
|
17
|
+
}
|
|
18
|
+
if (!seen.has(value)) {
|
|
19
|
+
seen.add(value);
|
|
20
|
+
out.push(value);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
return Object.freeze(out);
|
|
24
|
+
}
|
|
25
|
+
/** Validate and freeze an ordered assurance policy. */
|
|
26
|
+
export function defineAssurancePolicy(policy) {
|
|
27
|
+
if (policy.unmatched !== undefined &&
|
|
28
|
+
policy.unmatched !== "error" &&
|
|
29
|
+
policy.unmatched !== "ignore") {
|
|
30
|
+
throw new Error(`route assurance: invalid unmatched mode ${JSON.stringify(policy.unmatched)}`);
|
|
31
|
+
}
|
|
32
|
+
if (policy.allowEmpty !== undefined && typeof policy.allowEmpty !== "boolean") {
|
|
33
|
+
throw new Error(`route assurance: allowEmpty must be boolean`);
|
|
34
|
+
}
|
|
35
|
+
const names = new Set();
|
|
36
|
+
const rules = policy.rules.map((rule) => {
|
|
37
|
+
if (typeof rule.name !== "string" || !nonEmpty(rule.name)) {
|
|
38
|
+
throw new Error("route assurance: rule name must be non-empty");
|
|
39
|
+
}
|
|
40
|
+
const name = rule.name.trim();
|
|
41
|
+
if (names.has(name))
|
|
42
|
+
throw new Error(`route assurance: duplicate rule name ${JSON.stringify(name)}`);
|
|
43
|
+
names.add(name);
|
|
44
|
+
if (rule.match.tools !== undefined && typeof rule.match.tools !== "boolean") {
|
|
45
|
+
throw new Error(`route assurance: rule ${JSON.stringify(name)} tools selector must be boolean`);
|
|
46
|
+
}
|
|
47
|
+
const methods = rule.match.methods?.map((method) => method.toUpperCase());
|
|
48
|
+
for (const method of methods ?? []) {
|
|
49
|
+
if (!validMethod(method)) {
|
|
50
|
+
throw new Error(`route assurance: unsupported HTTP method ${JSON.stringify(method)}`);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
const paths = rule.match.paths?.map((path) => {
|
|
54
|
+
routeGlob(path);
|
|
55
|
+
return path;
|
|
56
|
+
});
|
|
57
|
+
const required = normalizeEvidenceIds(rule.require, "required");
|
|
58
|
+
const forbidden = normalizeEvidenceIds(rule.forbid, "forbidden");
|
|
59
|
+
const overlap = required.find((id) => forbidden.includes(id));
|
|
60
|
+
if (overlap !== undefined) {
|
|
61
|
+
throw new Error(`route assurance: rule ${JSON.stringify(name)} both requires and forbids ${overlap}`);
|
|
62
|
+
}
|
|
63
|
+
return Object.freeze({
|
|
64
|
+
name,
|
|
65
|
+
match: Object.freeze({
|
|
66
|
+
...(methods !== undefined ? { methods: Object.freeze(methods) } : {}),
|
|
67
|
+
...(paths !== undefined ? { paths: Object.freeze(paths) } : {}),
|
|
68
|
+
...(rule.match.tools !== undefined ? { tools: rule.match.tools } : {}),
|
|
69
|
+
}),
|
|
70
|
+
require: required,
|
|
71
|
+
forbid: forbidden,
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
return Object.freeze({
|
|
75
|
+
rules: Object.freeze(rules),
|
|
76
|
+
unmatched: policy.unmatched ?? "error",
|
|
77
|
+
allowEmpty: policy.allowEmpty ?? false,
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
/** Identity helper for a `nifra.assurance.ts` default export. */
|
|
81
|
+
export function defineAssuranceConfig(config) {
|
|
82
|
+
return Object.freeze({ source: config.source, policy: defineAssurancePolicy(config.policy) });
|
|
83
|
+
}
|
|
84
|
+
/** Shared selector semantics for policy rules and framework adapters. */
|
|
85
|
+
export function matchesAssuranceSelector(route, selector) {
|
|
86
|
+
const { methods, paths, tools } = selector;
|
|
87
|
+
if (methods !== undefined && !methods.includes(route.method))
|
|
88
|
+
return false;
|
|
89
|
+
if (paths !== undefined && !paths.some((pattern) => routeGlob(pattern).test(route.path)))
|
|
90
|
+
return false;
|
|
91
|
+
if (tools !== undefined && (route.tool !== undefined) !== tools)
|
|
92
|
+
return false;
|
|
93
|
+
return true;
|
|
94
|
+
}
|
|
95
|
+
/** Evaluate reflected route evidence against the first matching policy rule. */
|
|
96
|
+
export function evaluateRouteAssurance(source, policyInput) {
|
|
97
|
+
const policy = defineAssurancePolicy(policyInput);
|
|
98
|
+
const findings = [];
|
|
99
|
+
const routes = [];
|
|
100
|
+
const reflected = reflectRoutes(source);
|
|
101
|
+
if (reflected.length === 0 && policy.allowEmpty !== true) {
|
|
102
|
+
findings.push({
|
|
103
|
+
code: "no-routes",
|
|
104
|
+
method: "*",
|
|
105
|
+
path: "*",
|
|
106
|
+
message: "route assurance source reflected zero routes (set allowEmpty: true if intentional)",
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
for (const route of reflected) {
|
|
110
|
+
const rule = policy.rules.find((candidate) => matchesAssuranceSelector(route, candidate.match));
|
|
111
|
+
const evidence = route.assurance ?? [];
|
|
112
|
+
const evidenceIds = new Set(evidence.map((item) => item.id));
|
|
113
|
+
if (rule === undefined) {
|
|
114
|
+
if (policy.unmatched !== "ignore") {
|
|
115
|
+
findings.push({
|
|
116
|
+
code: "unclassified-route",
|
|
117
|
+
method: route.method,
|
|
118
|
+
path: route.path,
|
|
119
|
+
message: `${route.method} ${route.path} is not classified by an assurance rule`,
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
routes.push({ method: route.method, path: route.path, evidence, missing: [], forbidden: [] });
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
const missing = (rule.require ?? []).filter((id) => !evidenceIds.has(id));
|
|
126
|
+
const forbidden = (rule.forbid ?? []).filter((id) => evidenceIds.has(id));
|
|
127
|
+
for (const id of missing) {
|
|
128
|
+
findings.push({
|
|
129
|
+
code: "missing-evidence",
|
|
130
|
+
method: route.method,
|
|
131
|
+
path: route.path,
|
|
132
|
+
rule: rule.name,
|
|
133
|
+
evidence: id,
|
|
134
|
+
message: `${route.method} ${route.path} (${rule.name}) is missing ${id}`,
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
for (const id of forbidden) {
|
|
138
|
+
findings.push({
|
|
139
|
+
code: "forbidden-evidence",
|
|
140
|
+
method: route.method,
|
|
141
|
+
path: route.path,
|
|
142
|
+
rule: rule.name,
|
|
143
|
+
evidence: id,
|
|
144
|
+
message: `${route.method} ${route.path} (${rule.name}) carries forbidden ${id}`,
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
routes.push({
|
|
148
|
+
method: route.method,
|
|
149
|
+
path: route.path,
|
|
150
|
+
rule: rule.name,
|
|
151
|
+
evidence,
|
|
152
|
+
missing: Object.freeze(missing),
|
|
153
|
+
forbidden: Object.freeze(forbidden),
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
return Object.freeze({
|
|
157
|
+
ok: findings.length === 0,
|
|
158
|
+
routes: Object.freeze(routes),
|
|
159
|
+
findings: Object.freeze(findings),
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
//# sourceMappingURL=assurance.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"assurance.js","sourceRoot":"","sources":["../src/assurance.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAOH,OAAO,EACL,mBAAmB,EACnB,SAAS,EACT,eAAe,EACf,WAAW,EACX,kBAAkB,GACnB,MAAM,+BAA+B,CAAA;AACtC,OAAO,EAAuB,aAAa,EAAE,MAAM,iBAAiB,CAAA;AAIpE,OAAO,EAAE,kBAAkB,EAAE,CAAA;AAE7B,6EAA6E;AAC7E,MAAM,CAAC,MAAM,eAAe,GAAG,mBAAmB,CAAA;AAiElD,MAAM,QAAQ,GAAG,CAAC,KAAa,EAAW,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,CAAA;AAEhE,SAAS,oBAAoB,CAC3B,MAAqC,EACrC,KAAa;IAEb,MAAM,GAAG,GAAa,EAAE,CAAA;IACxB,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAA;IAC9B,KAAK,MAAM,KAAK,IAAI,MAAM,IAAI,EAAE,EAAE,CAAC;QACjC,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,EAAE,CAAC;YAC5B,MAAM,IAAI,KAAK,CAAC,4BAA4B,KAAK,gBAAgB,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC,CAAA;QAC3F,CAAC;QACD,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;YACrB,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;YACf,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QACjB,CAAC;IACH,CAAC;IACD,OAAO,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;AAC3B,CAAC;AAED,uDAAuD;AACvD,MAAM,UAAU,qBAAqB,CAAC,MAAuB;IAC3D,IACE,MAAM,CAAC,SAAS,KAAK,SAAS;QAC9B,MAAM,CAAC,SAAS,KAAK,OAAO;QAC5B,MAAM,CAAC,SAAS,KAAK,QAAQ,EAC7B,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,2CAA2C,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC,CAAA;IAChG,CAAC;IACD,IAAI,MAAM,CAAC,UAAU,KAAK,SAAS,IAAI,OAAO,MAAM,CAAC,UAAU,KAAK,SAAS,EAAE,CAAC;QAC9E,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAA;IAChE,CAAC;IACD,MAAM,KAAK,GAAG,IAAI,GAAG,EAAU,CAAA;IAC/B,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAiB,EAAE;QACrD,IAAI,OAAO,IAAI,CAAC,IAAI,KAAK,QAAQ,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YAC1D,MAAM,IAAI,KAAK,CAAC,8CAA8C,CAAC,CAAA;QACjE,CAAC;QACD,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAA;QAC7B,IAAI,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC;YACjB,MAAM,IAAI,KAAK,CAAC,wCAAwC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;QACjF,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;QACf,IAAI,IAAI,CAAC,KAAK,CAAC,KAAK,KAAK,SAAS,IAAI,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;YAC5E,MAAM,IAAI,KAAK,CACb,yBAAyB,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,iCAAiC,CAC/E,CAAA;QACH,CAAC;QACD,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC,CAAA;QACzE,KAAK,MAAM,MAAM,IAAI,OAAO,IAAI,EAAE,EAAE,CAAC;YACnC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,EAAE,CAAC;gBACzB,MAAM,IAAI,KAAK,CAAC,4CAA4C,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC,CAAA;YACvF,CAAC;QACH,CAAC;QACD,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;YAC3C,SAAS,CAAC,IAAI,CAAC,CAAA;YACf,OAAO,IAAI,CAAA;QACb,CAAC,CAAC,CAAA;QACF,MAAM,QAAQ,GAAG,oBAAoB,CAAC,IAAI,CAAC,OAAO,EAAE,UAAU,CAAC,CAAA;QAC/D,MAAM,SAAS,GAAG,oBAAoB,CAAC,IAAI,CAAC,MAAM,EAAE,WAAW,CAAC,CAAA;QAChE,MAAM,OAAO,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,SAAS,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAA;QAC7D,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;YAC1B,MAAM,IAAI,KAAK,CACb,yBAAyB,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,8BAA8B,OAAO,EAAE,CACrF,CAAA;QACH,CAAC;QACD,OAAO,MAAM,CAAC,MAAM,CAAC;YACnB,IAAI;YACJ,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC;gBACnB,GAAG,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,CAAC,OAAmB,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACjF,GAAG,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC/D,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aACvE,CAAC;YACF,OAAO,EAAE,QAAQ;YACjB,MAAM,EAAE,SAAS;SAClB,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IACF,OAAO,MAAM,CAAC,MAAM,CAAC;QACnB,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC;QAC3B,SAAS,EAAE,MAAM,CAAC,SAAS,IAAI,OAAO;QACtC,UAAU,EAAE,MAAM,CAAC,UAAU,IAAI,KAAK;KACvC,CAAC,CAAA;AACJ,CAAC;AAED,iEAAiE;AACjE,MAAM,UAAU,qBAAqB,CAAC,MAAuB;IAC3D,OAAO,MAAM,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,qBAAqB,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAA;AAC/F,CAAC;AAED,yEAAyE;AACzE,MAAM,UAAU,wBAAwB,CACtC,KAAuD,EACvD,QAAgC;IAEhC,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,QAAQ,CAAA;IAC1C,IAAI,OAAO,KAAK,SAAS,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAgB,CAAC;QAAE,OAAO,KAAK,CAAA;IACpF,IAAI,KAAK,KAAK,SAAS,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACtF,OAAO,KAAK,CAAA;IACd,IAAI,KAAK,KAAK,SAAS,IAAI,CAAC,KAAK,CAAC,IAAI,KAAK,SAAS,CAAC,KAAK,KAAK;QAAE,OAAO,KAAK,CAAA;IAC7E,OAAO,IAAI,CAAA;AACb,CAAC;AAED,gFAAgF;AAChF,MAAM,UAAU,sBAAsB,CACpC,MAAe,EACf,WAA4B;IAE5B,MAAM,MAAM,GAAG,qBAAqB,CAAC,WAAW,CAAC,CAAA;IACjD,MAAM,QAAQ,GAAuB,EAAE,CAAA;IACvC,MAAM,MAAM,GAAmB,EAAE,CAAA;IACjC,MAAM,SAAS,GAAG,aAAa,CAAC,MAAM,CAAC,CAAA;IAEvC,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,IAAI,MAAM,CAAC,UAAU,KAAK,IAAI,EAAE,CAAC;QACzD,QAAQ,CAAC,IAAI,CAAC;YACZ,IAAI,EAAE,WAAW;YACjB,MAAM,EAAE,GAAG;YACX,IAAI,EAAE,GAAG;YACT,OAAO,EAAE,oFAAoF;SAC9F,CAAC,CAAA;IACJ,CAAC;IAED,KAAK,MAAM,KAAK,IAAI,SAAS,EAAE,CAAC;QAC9B,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,wBAAwB,CAAC,KAAK,EAAE,SAAS,CAAC,KAAK,CAAC,CAAC,CAAA;QAC/F,MAAM,QAAQ,GAAG,KAAK,CAAC,SAAS,IAAI,EAAE,CAAA;QACtC,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAA;QAC5D,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;YACvB,IAAI,MAAM,CAAC,SAAS,KAAK,QAAQ,EAAE,CAAC;gBAClC,QAAQ,CAAC,IAAI,CAAC;oBACZ,IAAI,EAAE,oBAAoB;oBAC1B,MAAM,EAAE,KAAK,CAAC,MAAM;oBACpB,IAAI,EAAE,KAAK,CAAC,IAAI;oBAChB,OAAO,EAAE,GAAG,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC,IAAI,yCAAyC;iBAChF,CAAC,CAAA;YACJ,CAAC;YACD,MAAM,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC,CAAA;YAC7F,SAAQ;QACV,CAAC;QAED,MAAM,OAAO,GAAG,CAAC,IAAI,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAA;QACzE,MAAM,SAAS,GAAG,CAAC,IAAI,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAA;QACzE,KAAK,MAAM,EAAE,IAAI,OAAO,EAAE,CAAC;YACzB,QAAQ,CAAC,IAAI,CAAC;gBACZ,IAAI,EAAE,kBAAkB;gBACxB,MAAM,EAAE,KAAK,CAAC,MAAM;gBACpB,IAAI,EAAE,KAAK,CAAC,IAAI;gBAChB,IAAI,EAAE,IAAI,CAAC,IAAI;gBACf,QAAQ,EAAE,EAAE;gBACZ,OAAO,EAAE,GAAG,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC,IAAI,KAAK,IAAI,CAAC,IAAI,gBAAgB,EAAE,EAAE;aACzE,CAAC,CAAA;QACJ,CAAC;QACD,KAAK,MAAM,EAAE,IAAI,SAAS,EAAE,CAAC;YAC3B,QAAQ,CAAC,IAAI,CAAC;gBACZ,IAAI,EAAE,oBAAoB;gBAC1B,MAAM,EAAE,KAAK,CAAC,MAAM;gBACpB,IAAI,EAAE,KAAK,CAAC,IAAI;gBAChB,IAAI,EAAE,IAAI,CAAC,IAAI;gBACf,QAAQ,EAAE,EAAE;gBACZ,OAAO,EAAE,GAAG,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC,IAAI,KAAK,IAAI,CAAC,IAAI,uBAAuB,EAAE,EAAE;aAChF,CAAC,CAAA;QACJ,CAAC;QACD,MAAM,CAAC,IAAI,CAAC;YACV,MAAM,EAAE,KAAK,CAAC,MAAM;YACpB,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,QAAQ;YACR,OAAO,EAAE,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC;YAC/B,SAAS,EAAE,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC;SACpC,CAAC,CAAA;IACJ,CAAC;IAED,OAAO,MAAM,CAAC,MAAM,CAAC;QACnB,EAAE,EAAE,QAAQ,CAAC,MAAM,KAAK,CAAC;QACzB,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC;QAC7B,QAAQ,EAAE,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC;KAClC,CAAC,CAAA;AACJ,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -11,8 +11,9 @@
|
|
|
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.
|
|
14
|
+
export declare const VERSION: "1.8.0";
|
|
15
15
|
export type Version = typeof VERSION;
|
|
16
|
+
export * from "./assurance.js";
|
|
16
17
|
export * from "./diff.js";
|
|
17
18
|
export { FrameworkError, RouteConfigError, type RouteConfigErrorCode } from "./errors.js";
|
|
18
19
|
export { FRAMEWORK_NAME, type FrameworkName } from "./internal/brand.js";
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
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,cAAc,gBAAgB,CAAA;AAC9B,cAAc,WAAW,CAAA;AACzB,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,KAAK,oBAAoB,EAAE,MAAM,aAAa,CAAA;AACzF,OAAO,EAAE,cAAc,EAAE,KAAK,aAAa,EAAE,MAAM,qBAAqB,CAAA;AACxE,cAAc,iBAAiB,CAAA;AAC/B,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,oBAAoB,EACzB,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,EACH,KAAK,cAAc,EACnB,cAAc,GACf,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"}
|
package/dist/index.js
CHANGED
|
@@ -11,7 +11,8 @@
|
|
|
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.
|
|
14
|
+
export const VERSION = "1.8.0";
|
|
15
|
+
export * from "./assurance.js";
|
|
15
16
|
export * from "./diff.js";
|
|
16
17
|
export { FrameworkError, RouteConfigError } from "./errors.js";
|
|
17
18
|
export { FRAMEWORK_NAME } from "./internal/brand.js";
|
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,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"}
|
|
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,gBAAgB,CAAA;AAC9B,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,36 @@
|
|
|
1
|
+
import { type Method } from "../router/router.js";
|
|
2
|
+
/** Where enforcement evidence follows Nifra's route-registration semantics. */
|
|
3
|
+
export type AssuranceScope = "global" | "subsequent" | "plugin";
|
|
4
|
+
/** Reflection-safe proof that a named enforcement module covered a route. */
|
|
5
|
+
export interface AssuranceEvidence {
|
|
6
|
+
readonly id: string;
|
|
7
|
+
readonly source: string;
|
|
8
|
+
}
|
|
9
|
+
/** Metadata installed on a middleware/plugin by {@link withRouteAssurance}. */
|
|
10
|
+
export interface AssuranceDeclaration extends AssuranceEvidence {
|
|
11
|
+
readonly scope: AssuranceScope;
|
|
12
|
+
/** Restrict evidence to these HTTP methods. Omit for every method. */
|
|
13
|
+
readonly methods?: readonly Method[];
|
|
14
|
+
/** Restrict evidence to these absolute route globs. Omit for every path. */
|
|
15
|
+
readonly paths?: readonly string[];
|
|
16
|
+
}
|
|
17
|
+
export declare const NIFRA_ASSURANCE_IDS: Readonly<{
|
|
18
|
+
readonly AUTHENTICATED: "nifra.authenticated";
|
|
19
|
+
readonly BODY_BOUNDED: "nifra.body-bounded";
|
|
20
|
+
readonly CSRF: "nifra.csrf";
|
|
21
|
+
readonly IDEMPOTENCY_KEY: "nifra.idempotency-key";
|
|
22
|
+
readonly IP_RESTRICTED: "nifra.ip-restricted";
|
|
23
|
+
readonly RATE_LIMITED: "nifra.rate-limited";
|
|
24
|
+
readonly SECURITY_HEADERS: "nifra.security-headers";
|
|
25
|
+
}>;
|
|
26
|
+
/** Compile an absolute route glob. `*` is one segment; `**` is zero or more segments. */
|
|
27
|
+
export declare function routeGlob(pattern: string): RegExp;
|
|
28
|
+
/** Attach enforcement evidence to the middleware/plugin that installs it. */
|
|
29
|
+
export declare function withRouteAssurance<T extends object>(target: T, declaration: AssuranceDeclaration | readonly AssuranceDeclaration[]): T;
|
|
30
|
+
export declare function assuranceDeclarationsOf(value: object): readonly AssuranceDeclaration[];
|
|
31
|
+
export declare function declarationApplies(declaration: AssuranceDeclaration, method: string, path: string): boolean;
|
|
32
|
+
export declare function assuranceEvidenceFor(declarationsToApply: readonly AssuranceDeclaration[], method: string, path: string): readonly AssuranceEvidence[];
|
|
33
|
+
export declare function validEvidence(value: unknown): value is AssuranceEvidence;
|
|
34
|
+
export declare function validEvidenceId(value: string): boolean;
|
|
35
|
+
export declare function validMethod(value: string): value is Method;
|
|
36
|
+
//# sourceMappingURL=route-assurance.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"route-assurance.d.ts","sourceRoot":"","sources":["../../src/internal/route-assurance.ts"],"names":[],"mappings":"AAAA,OAAO,EAAW,KAAK,MAAM,EAAE,MAAM,qBAAqB,CAAA;AAE1D,+EAA+E;AAC/E,MAAM,MAAM,cAAc,GAAG,QAAQ,GAAG,YAAY,GAAG,QAAQ,CAAA;AAE/D,6EAA6E;AAC7E,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CACxB;AAED,+EAA+E;AAC/E,MAAM,WAAW,oBAAqB,SAAQ,iBAAiB;IAC7D,QAAQ,CAAC,KAAK,EAAE,cAAc,CAAA;IAC9B,sEAAsE;IACtE,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IACpC,4EAA4E;IAC5E,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;CACnC;AAMD,eAAO,MAAM,mBAAmB;;;;;;;;EAQrB,CAAA;AAIX,yFAAyF;AACzF,wBAAgB,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CA6BjD;AAiCD,6EAA6E;AAC7E,wBAAgB,kBAAkB,CAAC,CAAC,SAAS,MAAM,EACjD,MAAM,EAAE,CAAC,EACT,WAAW,EAAE,oBAAoB,GAAG,SAAS,oBAAoB,EAAE,GAClE,CAAC,CASH;AAED,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,oBAAoB,EAAE,CAEtF;AAED,wBAAgB,kBAAkB,CAChC,WAAW,EAAE,oBAAoB,EACjC,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,GACX,OAAO,CAOT;AAED,wBAAgB,oBAAoB,CAClC,mBAAmB,EAAE,SAAS,oBAAoB,EAAE,EACpD,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,GACX,SAAS,iBAAiB,EAAE,CAW9B;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,iBAAiB,CASxE;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAEtD;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,KAAK,IAAI,MAAM,CAE1D"}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { METHODS } from "../router/router.js";
|
|
2
|
+
const EVIDENCE_ID = /^[a-z][a-z0-9]*(?:[.-][a-z0-9]+)*$/;
|
|
3
|
+
const METHOD_SET = new Set(METHODS);
|
|
4
|
+
const declarations = new WeakMap();
|
|
5
|
+
export const NIFRA_ASSURANCE_IDS = Object.freeze({
|
|
6
|
+
AUTHENTICATED: "nifra.authenticated",
|
|
7
|
+
BODY_BOUNDED: "nifra.body-bounded",
|
|
8
|
+
CSRF: "nifra.csrf",
|
|
9
|
+
IDEMPOTENCY_KEY: "nifra.idempotency-key",
|
|
10
|
+
IP_RESTRICTED: "nifra.ip-restricted",
|
|
11
|
+
RATE_LIMITED: "nifra.rate-limited",
|
|
12
|
+
SECURITY_HEADERS: "nifra.security-headers",
|
|
13
|
+
});
|
|
14
|
+
const escapeRegex = (value) => value.replace(/[|\\{}()[\]^$+?.-]/g, "\\$&");
|
|
15
|
+
/** Compile an absolute route glob. `*` is one segment; `**` is zero or more segments. */
|
|
16
|
+
export function routeGlob(pattern) {
|
|
17
|
+
if (!pattern.startsWith("/") || pattern.includes("?") || pattern.includes("#")) {
|
|
18
|
+
throw new Error(`route assurance: path glob must be an absolute path: ${JSON.stringify(pattern)}`);
|
|
19
|
+
}
|
|
20
|
+
if (pattern === "/")
|
|
21
|
+
return /^\/$/;
|
|
22
|
+
const segments = pattern.slice(1).split("/");
|
|
23
|
+
let source = "^";
|
|
24
|
+
for (const [index, segment] of segments.entries()) {
|
|
25
|
+
if (segment === "**") {
|
|
26
|
+
if (index !== segments.length - 1) {
|
|
27
|
+
throw new Error(`route assurance: ** must be the final path segment: ${JSON.stringify(pattern)}`);
|
|
28
|
+
}
|
|
29
|
+
source += "(?:/.*)?";
|
|
30
|
+
}
|
|
31
|
+
else if (segment === "*") {
|
|
32
|
+
source += "/[^/]+";
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
if (segment.includes("*")) {
|
|
36
|
+
throw new Error(`route assurance: * must occupy a whole path segment: ${JSON.stringify(pattern)}`);
|
|
37
|
+
}
|
|
38
|
+
source += `/${escapeRegex(segment)}`;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return new RegExp(`${source}$`);
|
|
42
|
+
}
|
|
43
|
+
function normalizeDeclaration(value) {
|
|
44
|
+
if (!EVIDENCE_ID.test(value.id)) {
|
|
45
|
+
throw new Error(`route assurance: invalid evidence id ${JSON.stringify(value.id)} (use lowercase dot/dash segments)`);
|
|
46
|
+
}
|
|
47
|
+
if (typeof value.source !== "string" || value.source.trim() === "") {
|
|
48
|
+
throw new Error("route assurance: evidence source must be a non-empty string");
|
|
49
|
+
}
|
|
50
|
+
if (value.scope !== "global" && value.scope !== "subsequent" && value.scope !== "plugin") {
|
|
51
|
+
throw new Error(`route assurance: invalid scope ${JSON.stringify(value.scope)}`);
|
|
52
|
+
}
|
|
53
|
+
const methods = value.methods?.map((method) => method.toUpperCase());
|
|
54
|
+
for (const method of methods ?? []) {
|
|
55
|
+
if (!METHOD_SET.has(method)) {
|
|
56
|
+
throw new Error(`route assurance: unsupported HTTP method ${JSON.stringify(method)}`);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
const paths = value.paths?.map((path) => {
|
|
60
|
+
routeGlob(path);
|
|
61
|
+
return path;
|
|
62
|
+
});
|
|
63
|
+
return Object.freeze({
|
|
64
|
+
id: value.id,
|
|
65
|
+
source: value.source.trim(),
|
|
66
|
+
scope: value.scope,
|
|
67
|
+
...(methods !== undefined ? { methods: Object.freeze(methods) } : {}),
|
|
68
|
+
...(paths !== undefined ? { paths: Object.freeze(paths) } : {}),
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
/** Attach enforcement evidence to the middleware/plugin that installs it. */
|
|
72
|
+
export function withRouteAssurance(target, declaration) {
|
|
73
|
+
const values = Array.isArray(declaration) ? declaration : [declaration];
|
|
74
|
+
if (values.length === 0)
|
|
75
|
+
throw new Error("route assurance: at least one declaration is required");
|
|
76
|
+
const previous = declarations.get(target) ?? [];
|
|
77
|
+
declarations.set(target, Object.freeze([...previous, ...values.map((value) => normalizeDeclaration(value))]));
|
|
78
|
+
return target;
|
|
79
|
+
}
|
|
80
|
+
export function assuranceDeclarationsOf(value) {
|
|
81
|
+
return declarations.get(value) ?? [];
|
|
82
|
+
}
|
|
83
|
+
export function declarationApplies(declaration, method, path) {
|
|
84
|
+
if (declaration.methods !== undefined && !declaration.methods.includes(method))
|
|
85
|
+
return false;
|
|
86
|
+
return (declaration.paths === undefined ||
|
|
87
|
+
declaration.paths.some((pattern) => routeGlob(pattern).test(path)));
|
|
88
|
+
}
|
|
89
|
+
export function assuranceEvidenceFor(declarationsToApply, method, path) {
|
|
90
|
+
const seen = new Set();
|
|
91
|
+
const evidence = [];
|
|
92
|
+
for (const declaration of declarationsToApply) {
|
|
93
|
+
if (!declarationApplies(declaration, method, path))
|
|
94
|
+
continue;
|
|
95
|
+
const key = `${declaration.id}\n${declaration.source}`;
|
|
96
|
+
if (seen.has(key))
|
|
97
|
+
continue;
|
|
98
|
+
seen.add(key);
|
|
99
|
+
evidence.push(Object.freeze({ id: declaration.id, source: declaration.source }));
|
|
100
|
+
}
|
|
101
|
+
return Object.freeze(evidence);
|
|
102
|
+
}
|
|
103
|
+
export function validEvidence(value) {
|
|
104
|
+
if (typeof value !== "object" || value === null)
|
|
105
|
+
return false;
|
|
106
|
+
const candidate = value;
|
|
107
|
+
return (typeof candidate.id === "string" &&
|
|
108
|
+
EVIDENCE_ID.test(candidate.id) &&
|
|
109
|
+
typeof candidate.source === "string" &&
|
|
110
|
+
candidate.source.trim() !== "");
|
|
111
|
+
}
|
|
112
|
+
export function validEvidenceId(value) {
|
|
113
|
+
return EVIDENCE_ID.test(value);
|
|
114
|
+
}
|
|
115
|
+
export function validMethod(value) {
|
|
116
|
+
return METHOD_SET.has(value.toUpperCase());
|
|
117
|
+
}
|
|
118
|
+
//# sourceMappingURL=route-assurance.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"route-assurance.js","sourceRoot":"","sources":["../../src/internal/route-assurance.ts"],"names":[],"mappings":"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"}
|
package/dist/reflection.d.ts
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
* `fields` are present only when the value carries inspectable JSON Schema metadata. The implementation
|
|
7
7
|
* recognizes Nifra/TypeBox carriers and raw JSON Schema without depending on a validator package.
|
|
8
8
|
*/
|
|
9
|
+
import { type AssuranceEvidence } from "./internal/route-assurance.js";
|
|
9
10
|
import type { StandardSchemaV1 } from "./schema/standard.js";
|
|
10
11
|
import type { ToolAnnotations } from "./server/server.js";
|
|
11
12
|
/** JSON Schema permits either a schema object or the boolean schemas `true` and `false`. */
|
|
@@ -37,6 +38,7 @@ export interface ReflectedRoute {
|
|
|
37
38
|
readonly method: string;
|
|
38
39
|
readonly path: string;
|
|
39
40
|
readonly schema?: ReflectedRouteSchema;
|
|
41
|
+
readonly assurance?: readonly AssuranceEvidence[];
|
|
40
42
|
readonly tool?: {
|
|
41
43
|
readonly name: string;
|
|
42
44
|
readonly description: string;
|
package/dist/reflection.d.ts.map
CHANGED
|
@@ -1 +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;
|
|
1
|
+
{"version":3,"file":"reflection.d.ts","sourceRoot":"","sources":["../src/reflection.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,KAAK,iBAAiB,EAAiB,MAAM,+BAA+B,CAAA;AACrF,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,SAAS,CAAC,EAAE,SAAS,iBAAiB,EAAE,CAAA;IACjD,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;AAqDD;;;GAGG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,OAAO,GAAG,SAAS,cAAc,EAAE,CAiBxE"}
|
package/dist/reflection.js
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
* `fields` are present only when the value carries inspectable JSON Schema metadata. The implementation
|
|
7
7
|
* recognizes Nifra/TypeBox carriers and raw JSON Schema without depending on a validator package.
|
|
8
8
|
*/
|
|
9
|
+
import { validEvidence } from "./internal/route-assurance.js";
|
|
9
10
|
const recordOf = (value) => value !== null && typeof value === "object"
|
|
10
11
|
? value
|
|
11
12
|
: undefined;
|
|
@@ -53,7 +54,7 @@ const normalizeJsonSchema = (value) => {
|
|
|
53
54
|
// otherwise leak the marker into emitted OpenAPI / mock / form output.
|
|
54
55
|
if (!("~standard" in record))
|
|
55
56
|
return record;
|
|
56
|
-
const {
|
|
57
|
+
const { "~standard": _omitted, ...rest } = record;
|
|
57
58
|
return rest;
|
|
58
59
|
}
|
|
59
60
|
catch {
|
|
@@ -130,6 +131,14 @@ const reflectedTool = (value) => {
|
|
|
130
131
|
: {}),
|
|
131
132
|
};
|
|
132
133
|
};
|
|
134
|
+
const reflectedAssurance = (value) => {
|
|
135
|
+
if (!Array.isArray(value))
|
|
136
|
+
return undefined;
|
|
137
|
+
const evidence = value
|
|
138
|
+
.filter(validEvidence)
|
|
139
|
+
.map((item) => Object.freeze({ id: item.id, source: item.source.trim() }));
|
|
140
|
+
return evidence.length > 0 ? Object.freeze(evidence) : undefined;
|
|
141
|
+
};
|
|
133
142
|
/**
|
|
134
143
|
* Safely enumerate and normalize route descriptors from an app or descriptor array. Invalid entries
|
|
135
144
|
* are ignored; a missing/throwing `routes()` method yields an empty array.
|
|
@@ -142,10 +151,12 @@ export function reflectRoutes(source) {
|
|
|
142
151
|
continue;
|
|
143
152
|
const schema = reflectedRouteSchema(route.schema);
|
|
144
153
|
const tool = reflectedTool(route.tool);
|
|
154
|
+
const assurance = reflectedAssurance(route.assurance);
|
|
145
155
|
reflected.push({
|
|
146
156
|
method: route.method.toUpperCase(),
|
|
147
157
|
path: route.path,
|
|
148
158
|
...(schema !== undefined ? { schema } : {}),
|
|
159
|
+
...(assurance !== undefined ? { assurance } : {}),
|
|
149
160
|
...(tool !== undefined ? { tool } : {}),
|
|
150
161
|
});
|
|
151
162
|
}
|
package/dist/reflection.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reflection.js","sourceRoot":"","sources":["../src/reflection.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;
|
|
1
|
+
{"version":3,"file":"reflection.js","sourceRoot":"","sources":["../src/reflection.ts"],"names":[],"mappings":"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"}
|
|
@@ -55,7 +55,24 @@ export type RouteInfoFor<Path extends string, S extends RouteSchema, Output> = {
|
|
|
55
55
|
};
|
|
56
56
|
/** The client-visible output of a handler: its awaited return, minus raw `Response`. */
|
|
57
57
|
export type OutputOf<H extends (...args: never[]) => unknown> = Exclude<Awaited<ReturnType<H>>, Response>;
|
|
58
|
-
/**
|
|
58
|
+
/**
|
|
59
|
+
* Merge a new route into the registry, combining methods that share a path.
|
|
60
|
+
*
|
|
61
|
+
* SCALING CEILING (measured — see many-routes.test-d.ts and the isolation study below): a single
|
|
62
|
+
* fluent chain hits TS2589 at ~95-100 routes. This intersection is NOT the cause — in isolation it
|
|
63
|
+
* accumulates 1000+ routes cleanly, and heavy per-route `Params<Path>`/schema inference alone
|
|
64
|
+
* reaches 600+. The wall is an INTERACTION unique to the fluent builder: each `.get(path, handler)`
|
|
65
|
+
* both (a) computes the handler's context type from the path (`c.params.id` inferred from `:id`)
|
|
66
|
+
* AND (b) returns `Server<AddRoute<growing-R, …>, Ctx>`. Neither alone strains the compiler; the
|
|
67
|
+
* PRODUCT — recomputing the handler context while re-threading the ever-larger registry at each of
|
|
68
|
+
* N steps — exhausts TypeScript's per-expression instantiation budget around N≈95. It is therefore
|
|
69
|
+
* O(N) and inherent to any builder that infers handler context AND accumulates a typed route
|
|
70
|
+
* registry (Elysia/tRPC/hono's typed clients cap the same way); it is not fixable by reshaping
|
|
71
|
+
* AddRoute. Past ~90 routes, use a path that DOESN'T form the product: split into domain groups and
|
|
72
|
+
* `.merge()` them (each group is a short chain; a merge is one `R & R2` intersection with no
|
|
73
|
+
* per-call context work), or contract-first `implement()` (the registry is one object type declared
|
|
74
|
+
* upfront — no grow-R-per-call, so no ceiling at all).
|
|
75
|
+
*/
|
|
59
76
|
export type AddRoute<R extends Registry, Method extends string, Path extends string, Info extends RouteInfo> = R & {
|
|
60
77
|
[P in Path]: {
|
|
61
78
|
[M in Method]: Info;
|