@nifrajs/core 1.9.1 → 1.11.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.
Files changed (83) hide show
  1. package/dist/assurance.d.ts +18 -0
  2. package/dist/assurance.d.ts.map +1 -1
  3. package/dist/assurance.js +28 -1
  4. package/dist/assurance.js.map +1 -1
  5. package/dist/budget.d.ts +91 -0
  6. package/dist/budget.d.ts.map +1 -0
  7. package/dist/budget.js +172 -0
  8. package/dist/budget.js.map +1 -0
  9. package/dist/capabilities.d.ts +146 -0
  10. package/dist/capabilities.d.ts.map +1 -0
  11. package/dist/capabilities.js +283 -0
  12. package/dist/capabilities.js.map +1 -0
  13. package/dist/classification.d.ts +39 -0
  14. package/dist/classification.d.ts.map +1 -0
  15. package/dist/classification.js +153 -0
  16. package/dist/classification.js.map +1 -0
  17. package/dist/errors.d.ts +1 -1
  18. package/dist/errors.d.ts.map +1 -1
  19. package/dist/errors.js.map +1 -1
  20. package/dist/idempotency.d.ts +137 -0
  21. package/dist/idempotency.d.ts.map +1 -0
  22. package/dist/idempotency.js +306 -0
  23. package/dist/idempotency.js.map +1 -0
  24. package/dist/index.d.ts +8 -1
  25. package/dist/index.d.ts.map +1 -1
  26. package/dist/index.js +8 -1
  27. package/dist/index.js.map +1 -1
  28. package/dist/internal/capability-runtime.d.ts +16 -0
  29. package/dist/internal/capability-runtime.d.ts.map +1 -0
  30. package/dist/internal/capability-runtime.js +27 -0
  31. package/dist/internal/capability-runtime.js.map +1 -0
  32. package/dist/internal/route-assurance.d.ts +1 -0
  33. package/dist/internal/route-assurance.d.ts.map +1 -1
  34. package/dist/internal/route-assurance.js +1 -0
  35. package/dist/internal/route-assurance.js.map +1 -1
  36. package/dist/invariants.d.ts +66 -0
  37. package/dist/invariants.d.ts.map +1 -0
  38. package/dist/invariants.js +483 -0
  39. package/dist/invariants.js.map +1 -0
  40. package/dist/ledger.d.ts +154 -0
  41. package/dist/ledger.d.ts.map +1 -0
  42. package/dist/ledger.js +271 -0
  43. package/dist/ledger.js.map +1 -0
  44. package/dist/manifest.d.ts +81 -0
  45. package/dist/manifest.d.ts.map +1 -0
  46. package/dist/manifest.js +394 -0
  47. package/dist/manifest.js.map +1 -0
  48. package/dist/mount.d.ts +18 -0
  49. package/dist/mount.d.ts.map +1 -0
  50. package/dist/mount.js +11 -0
  51. package/dist/mount.js.map +1 -0
  52. package/dist/reflection.d.ts +4 -0
  53. package/dist/reflection.d.ts.map +1 -1
  54. package/dist/reflection.js +9 -0
  55. package/dist/reflection.js.map +1 -1
  56. package/dist/server/context.d.ts +50 -1
  57. package/dist/server/context.d.ts.map +1 -1
  58. package/dist/server/contract.d.ts +8 -1
  59. package/dist/server/contract.d.ts.map +1 -1
  60. package/dist/server/contract.js +11 -1
  61. package/dist/server/contract.js.map +1 -1
  62. package/dist/server/server.d.ts +56 -2
  63. package/dist/server/server.d.ts.map +1 -1
  64. package/dist/server/server.js +294 -17
  65. package/dist/server/server.js.map +1 -1
  66. package/package.json +36 -4
  67. package/src/assurance.ts +48 -1
  68. package/src/budget.ts +267 -0
  69. package/src/capabilities.ts +486 -0
  70. package/src/classification.ts +189 -0
  71. package/src/errors.ts +2 -0
  72. package/src/idempotency.ts +420 -0
  73. package/src/index.ts +8 -1
  74. package/src/internal/capability-runtime.ts +49 -0
  75. package/src/internal/route-assurance.ts +1 -0
  76. package/src/invariants.ts +600 -0
  77. package/src/ledger.ts +430 -0
  78. package/src/manifest.ts +543 -0
  79. package/src/mount.ts +24 -0
  80. package/src/reflection.ts +18 -0
  81. package/src/server/context.ts +54 -1
  82. package/src/server/contract.ts +19 -2
  83. package/src/server/server.ts +463 -26
@@ -0,0 +1,137 @@
1
+ /**
2
+ * Idempotency primitive. A mutating route can declare `schema.idempotency`; the server then dedupes
3
+ * on an `Idempotency-Key` header: the first request runs and its response is stored, and a retry with
4
+ * the same key replays the stored response byte-for-byte without re-running the handler. A retry that
5
+ * reuses a key with a *different* request body is rejected (409) — a key binds to one request.
6
+ *
7
+ * This module is the runtime-neutral core: the store interface, an in-memory store, the request
8
+ * fingerprint, and response (de)serialization. The server owns the request-path lane that reads the
9
+ * body, consults the store, and captures the response. All logic here is pure/injectable so it is
10
+ * unit-tested without a server. A durable store (cross-restart) implements the same interface.
11
+ */
12
+ /** Whether a route's idempotency is satisfied by an in-process store or a durable (cross-restart) one. */
13
+ export type IdempotencyScope = "request" | "durable";
14
+ /** Default retention for a stored idempotent response: 24 hours. */
15
+ export declare const DEFAULT_IDEMPOTENCY_TTL_MS = 86400000;
16
+ /** Canonical request header carrying the client-chosen idempotency key. */
17
+ export declare const DEFAULT_IDEMPOTENCY_HEADER = "idempotency-key";
18
+ /** Header stamped on a replayed response so clients/proxies can tell a replay from a fresh run. */
19
+ export declare const IDEMPOTENT_REPLAY_HEADER = "x-nifra-idempotent-replay";
20
+ /** A serialized response held by a store. `body` is base64 so binary payloads round-trip intact. */
21
+ export interface StoredResponse {
22
+ readonly status: number;
23
+ readonly headers: readonly (readonly [string, string])[];
24
+ /** Base64-encoded response body; `""` when the response had no body. */
25
+ readonly body: string;
26
+ }
27
+ /**
28
+ * Outcome of reserving a key. `new` → the caller runs the handler and later calls {@link
29
+ * IdempotencyStore.complete}. `replay` → return the stored response, handler never runs. `mismatch`
30
+ * → same key, different request fingerprint (client bug) → 409. `in-flight` → the key is reserved but
31
+ * not yet completed (a concurrent duplicate) → 409 + Retry-After.
32
+ */
33
+ export type IdempotencyBeginResult = {
34
+ readonly state: "new";
35
+ readonly reservation: string;
36
+ } | {
37
+ readonly state: "replay";
38
+ readonly response: StoredResponse;
39
+ } | {
40
+ readonly state: "mismatch";
41
+ } | {
42
+ readonly state: "in-flight";
43
+ } | {
44
+ readonly state: "capacity";
45
+ };
46
+ /** Namespaces isolate the same client key across tenants/subjects without putting identity in a header. */
47
+ export interface IdempotencyEntryKey {
48
+ readonly namespace: string;
49
+ readonly key: string;
50
+ }
51
+ export interface IdempotencyBeginInput extends IdempotencyEntryKey {
52
+ readonly fingerprint: string;
53
+ readonly ttlMs: number;
54
+ }
55
+ export interface IdempotencyCompletionInput extends IdempotencyEntryKey {
56
+ /** Opaque ownership token returned by `begin(state:"new")`. */
57
+ readonly reservation: string;
58
+ readonly response: StoredResponse;
59
+ }
60
+ export interface IdempotencyAbandonInput extends IdempotencyEntryKey {
61
+ /** Opaque ownership token returned by `begin(state:"new")`. */
62
+ readonly reservation: string;
63
+ }
64
+ /**
65
+ * Storage seam for idempotent responses. `begin` MUST be atomic: for one key, exactly one concurrent
66
+ * caller sees `new`; the rest see `in-flight` (or `replay` once completed). The in-memory store gets
67
+ * this free from the single-threaded event loop; a durable store uses an atomic insert.
68
+ */
69
+ export interface IdempotencyStore {
70
+ /**
71
+ * An honest durability marker. Omit/`memory` for process-local stores; a route declaring
72
+ * `scope: "durable"` rejects anything other than `durable` at registration.
73
+ */
74
+ readonly durability?: "memory" | "durable";
75
+ /** Reserve one namespaced key. Exactly one concurrent caller may receive `new`. */
76
+ begin(input: IdempotencyBeginInput): IdempotencyBeginResult | Promise<IdempotencyBeginResult>;
77
+ /**
78
+ * Persist the final response only when `reservation` still owns the key. Returns false for a stale
79
+ * completion (for example after expiry + re-reservation), which prevents an older request from
80
+ * overwriting a newer result.
81
+ */
82
+ complete(input: IdempotencyCompletionInput): boolean | Promise<boolean>;
83
+ /** Release only the pending reservation owned by `reservation`. */
84
+ abandon(input: IdempotencyAbandonInput): boolean | Promise<boolean>;
85
+ }
86
+ /** A key must be a non-empty, bounded, control-char-free token. Fail closed on anything else. */
87
+ export declare function validIdempotencyKey(key: string): boolean;
88
+ /** Namespace values are server-resolved, bounded opaque tokens (normally a tenant/subject hash). */
89
+ export declare function validIdempotencyNamespace(namespace: string): boolean;
90
+ /**
91
+ * SHA-256 fingerprint binding a key to one request: method, path (+ query), and the raw body bytes.
92
+ * A collision-resistant hash matters — a weak hash would let a crafted body replay another's response.
93
+ */
94
+ export declare function computeIdempotencyFingerprint(method: string, path: string, body: Uint8Array, contentType?: string): Promise<string>;
95
+ /** Canonicalize JSON bodies so whitespace/property-order retries bind to the same semantic request. */
96
+ export declare function canonicalizeIdempotencyBody(body: Uint8Array, contentType: string | null): Uint8Array;
97
+ export declare class IdempotencyResponseTooLargeError extends Error {
98
+ readonly maxBytes: number;
99
+ constructor(maxBytes: number);
100
+ }
101
+ /** Buffer a response into a storable form. Clones first so the live response body stays intact. */
102
+ export declare function serializeResponse(response: Response, options?: {
103
+ readonly maxBytes?: number;
104
+ }): Promise<StoredResponse>;
105
+ /** Rebuild a live response from storage, stamping the replay marker header. */
106
+ export declare function responseFromStored(stored: StoredResponse, options?: {
107
+ readonly maxBytes?: number;
108
+ }): Response;
109
+ export interface MemoryIdempotencyStoreOptions {
110
+ /** Injectable clock (epoch ms) for deterministic TTL tests. Default `Date.now`. */
111
+ readonly now?: () => number;
112
+ /** Hard memory bound. At capacity new keys fail closed; completed/pending entries are never evicted early. */
113
+ readonly maxEntries?: number;
114
+ }
115
+ /**
116
+ * In-process idempotency store. Reservation is atomic by construction — `begin` never awaits, so the
117
+ * single-threaded event loop serializes concurrent callers for one key. Expired entries are treated
118
+ * as absent (lazy eviction on access); a periodic {@link MemoryIdempotencyStore.sweep} bounds memory.
119
+ */
120
+ export declare class MemoryIdempotencyStore implements IdempotencyStore {
121
+ readonly durability: "memory";
122
+ private readonly entries;
123
+ private readonly now;
124
+ private readonly maxEntries;
125
+ constructor(options?: MemoryIdempotencyStoreOptions);
126
+ begin(input: IdempotencyBeginInput): IdempotencyBeginResult;
127
+ complete(input: IdempotencyCompletionInput): boolean;
128
+ abandon(input: IdempotencyAbandonInput): boolean;
129
+ /** Evict expired entries. Callers may run this on an interval; access-time eviction covers the rest. */
130
+ sweep(): void;
131
+ /** Live entry count (post-sweep semantics are the caller's; this is a raw size for tests/metrics). */
132
+ get size(): number;
133
+ private storageKey;
134
+ }
135
+ /** Convenience factory mirroring the other core primitives' `create*` style. */
136
+ export declare function createMemoryIdempotencyStore(options?: MemoryIdempotencyStoreOptions): MemoryIdempotencyStore;
137
+ //# sourceMappingURL=idempotency.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"idempotency.d.ts","sourceRoot":"","sources":["../src/idempotency.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,306 @@
1
+ /**
2
+ * Idempotency primitive. A mutating route can declare `schema.idempotency`; the server then dedupes
3
+ * on an `Idempotency-Key` header: the first request runs and its response is stored, and a retry with
4
+ * the same key replays the stored response byte-for-byte without re-running the handler. A retry that
5
+ * reuses a key with a *different* request body is rejected (409) — a key binds to one request.
6
+ *
7
+ * This module is the runtime-neutral core: the store interface, an in-memory store, the request
8
+ * fingerprint, and response (de)serialization. The server owns the request-path lane that reads the
9
+ * body, consults the store, and captures the response. All logic here is pure/injectable so it is
10
+ * unit-tested without a server. A durable store (cross-restart) implements the same interface.
11
+ */
12
+ /** Default retention for a stored idempotent response: 24 hours. */
13
+ export const DEFAULT_IDEMPOTENCY_TTL_MS = 86_400_000;
14
+ /** Canonical request header carrying the client-chosen idempotency key. */
15
+ export const DEFAULT_IDEMPOTENCY_HEADER = "idempotency-key";
16
+ /** Header stamped on a replayed response so clients/proxies can tell a replay from a fresh run. */
17
+ export const IDEMPOTENT_REPLAY_HEADER = "x-nifra-idempotent-replay";
18
+ const KEY_MAX_LENGTH = 255;
19
+ // A replay is a new HTTP exchange, not a byte-for-byte resurrection of connection state. Session
20
+ // setters and hop-by-hop headers belong only to the winning response. Filter on both write and read:
21
+ // durable stores may still contain records created by an older Nifra version.
22
+ const REPLAY_UNSAFE_RESPONSE_HEADERS = new Set([
23
+ "authentication-info",
24
+ "connection",
25
+ "keep-alive",
26
+ "proxy-authenticate",
27
+ "proxy-authentication-info",
28
+ "proxy-authorization",
29
+ "set-cookie",
30
+ "te",
31
+ "trailer",
32
+ "transfer-encoding",
33
+ "upgrade",
34
+ ]);
35
+ function replaySafeHeaders(headers) {
36
+ const safe = [];
37
+ for (const [name, value] of headers) {
38
+ if (!REPLAY_UNSAFE_RESPONSE_HEADERS.has(name.toLowerCase()))
39
+ safe.push([name, value]);
40
+ }
41
+ return safe;
42
+ }
43
+ /** A key must be a non-empty, bounded, control-char-free token. Fail closed on anything else. */
44
+ export function validIdempotencyKey(key) {
45
+ if (typeof key !== "string" || key.length === 0 || key.length > KEY_MAX_LENGTH)
46
+ return false;
47
+ for (let i = 0; i < key.length; i++) {
48
+ const code = key.charCodeAt(i);
49
+ if (code < 33 || code > 126)
50
+ return false;
51
+ }
52
+ return true;
53
+ }
54
+ /** Namespace values are server-resolved, bounded opaque tokens (normally a tenant/subject hash). */
55
+ export function validIdempotencyNamespace(namespace) {
56
+ return validIdempotencyKey(namespace);
57
+ }
58
+ const encoder = new TextEncoder();
59
+ /**
60
+ * SHA-256 fingerprint binding a key to one request: method, path (+ query), and the raw body bytes.
61
+ * A collision-resistant hash matters — a weak hash would let a crafted body replay another's response.
62
+ */
63
+ export async function computeIdempotencyFingerprint(method, path, body, contentType = "") {
64
+ const mediaType = contentType.split(";", 1)[0]?.trim().toLowerCase() ?? "";
65
+ const head = encoder.encode(`${method.toUpperCase()}\n${path}\n${mediaType}\n`);
66
+ const material = new Uint8Array(head.length + body.length);
67
+ material.set(head, 0);
68
+ material.set(body, head.length);
69
+ const digest = await crypto.subtle.digest("SHA-256", material);
70
+ const bytes = new Uint8Array(digest);
71
+ let hex = "";
72
+ for (let i = 0; i < bytes.length; i++)
73
+ hex += bytes[i].toString(16).padStart(2, "0");
74
+ return hex;
75
+ }
76
+ function canonicalJson(value) {
77
+ if (value === null || typeof value === "boolean" || typeof value === "string") {
78
+ return JSON.stringify(value);
79
+ }
80
+ if (typeof value === "number") {
81
+ if (!Number.isFinite(value))
82
+ throw new TypeError("non-finite JSON number");
83
+ return JSON.stringify(value);
84
+ }
85
+ if (Array.isArray(value))
86
+ return `[${value.map((item) => canonicalJson(item)).join(",")}]`;
87
+ if (typeof value === "object") {
88
+ const record = value;
89
+ const entries = Object.keys(record)
90
+ .sort()
91
+ .map((key) => `${JSON.stringify(key)}:${canonicalJson(record[key])}`);
92
+ return `{${entries.join(",")}}`;
93
+ }
94
+ throw new TypeError("unsupported JSON value");
95
+ }
96
+ /** Canonicalize JSON bodies so whitespace/property-order retries bind to the same semantic request. */
97
+ export function canonicalizeIdempotencyBody(body, contentType) {
98
+ const mediaType = contentType?.split(";", 1)[0]?.trim().toLowerCase() ?? "";
99
+ if (mediaType !== "application/json" && !mediaType.endsWith("+json"))
100
+ return body;
101
+ try {
102
+ return encoder.encode(canonicalJson(JSON.parse(new TextDecoder().decode(body))));
103
+ }
104
+ catch {
105
+ // Invalid JSON is rejected by the validation/body lane. Preserve its raw bytes for a stable
106
+ // fingerprint until that rejection releases the reservation.
107
+ return body;
108
+ }
109
+ }
110
+ const BASE64_CHUNK = 0x8000;
111
+ function bytesToBase64(bytes) {
112
+ let binary = "";
113
+ for (let i = 0; i < bytes.length; i += BASE64_CHUNK) {
114
+ binary += String.fromCharCode(...bytes.subarray(i, i + BASE64_CHUNK));
115
+ }
116
+ return btoa(binary);
117
+ }
118
+ function base64ToBytes(value) {
119
+ const binary = atob(value);
120
+ const bytes = new Uint8Array(binary.length);
121
+ for (let i = 0; i < binary.length; i++)
122
+ bytes[i] = binary.charCodeAt(i);
123
+ return bytes;
124
+ }
125
+ function base64DecodedLength(value) {
126
+ if (value === "")
127
+ return 0;
128
+ if (value.length % 4 !== 0 || !/^[A-Za-z0-9+/]*={0,2}$/.test(value)) {
129
+ throw new TypeError("idempotency: corrupt stored response body");
130
+ }
131
+ const padding = value.endsWith("==") ? 2 : value.endsWith("=") ? 1 : 0;
132
+ return (value.length / 4) * 3 - padding;
133
+ }
134
+ export class IdempotencyResponseTooLargeError extends Error {
135
+ maxBytes;
136
+ constructor(maxBytes) {
137
+ super(`idempotency response exceeds the ${maxBytes}-byte storage bound`);
138
+ this.maxBytes = maxBytes;
139
+ this.name = "IdempotencyResponseTooLargeError";
140
+ }
141
+ }
142
+ async function boundedResponseBytes(response, maxBytes) {
143
+ const contentLength = response.headers.get("content-length");
144
+ if (contentLength !== null && /^\d+$/.test(contentLength) && Number(contentLength) > maxBytes) {
145
+ throw new IdempotencyResponseTooLargeError(maxBytes);
146
+ }
147
+ const body = response.clone().body;
148
+ if (body === null)
149
+ return new Uint8Array();
150
+ const reader = body.getReader();
151
+ const chunks = [];
152
+ let total = 0;
153
+ try {
154
+ for (;;) {
155
+ const { done, value } = await reader.read();
156
+ if (done)
157
+ break;
158
+ total += value.byteLength;
159
+ if (total > maxBytes) {
160
+ await reader.cancel();
161
+ throw new IdempotencyResponseTooLargeError(maxBytes);
162
+ }
163
+ chunks.push(value);
164
+ }
165
+ }
166
+ finally {
167
+ reader.releaseLock();
168
+ }
169
+ const bytes = new Uint8Array(total);
170
+ let offset = 0;
171
+ for (const chunk of chunks) {
172
+ bytes.set(chunk, offset);
173
+ offset += chunk.byteLength;
174
+ }
175
+ return bytes;
176
+ }
177
+ /** Buffer a response into a storable form. Clones first so the live response body stays intact. */
178
+ export async function serializeResponse(response, options = {}) {
179
+ const maxBytes = options.maxBytes;
180
+ if (maxBytes !== undefined && (!Number.isInteger(maxBytes) || maxBytes < 0)) {
181
+ throw new RangeError("idempotency: max response bytes must be a non-negative integer");
182
+ }
183
+ const bytes = maxBytes === undefined
184
+ ? new Uint8Array(await response.clone().arrayBuffer())
185
+ : await boundedResponseBytes(response, maxBytes);
186
+ return {
187
+ status: response.status,
188
+ headers: replaySafeHeaders(response.headers),
189
+ body: bytes.length > 0 ? bytesToBase64(bytes) : "",
190
+ };
191
+ }
192
+ /** Rebuild a live response from storage, stamping the replay marker header. */
193
+ export function responseFromStored(stored, options = {}) {
194
+ if (!Number.isInteger(stored.status) || stored.status < 200 || stored.status > 599) {
195
+ throw new TypeError("idempotency: corrupt stored response status");
196
+ }
197
+ const decodedLength = base64DecodedLength(stored.body);
198
+ if (options.maxBytes !== undefined) {
199
+ if (!Number.isSafeInteger(options.maxBytes) || options.maxBytes < 0) {
200
+ throw new RangeError("idempotency: max response bytes must be a non-negative safe integer");
201
+ }
202
+ if (decodedLength > options.maxBytes) {
203
+ throw new IdempotencyResponseTooLargeError(options.maxBytes);
204
+ }
205
+ }
206
+ const headers = new Headers(replaySafeHeaders(stored.headers));
207
+ headers.set(IDEMPOTENT_REPLAY_HEADER, "1");
208
+ // Reference the Response body type structurally: `BodyInit` isn't a named type under every lib config,
209
+ // but a fresh `Uint8Array` is a valid body — the cast bridges the `ArrayBufferLike` generic variance.
210
+ const body = (stored.body === "" ? null : base64ToBytes(stored.body));
211
+ return new Response(body, { status: stored.status, headers });
212
+ }
213
+ /**
214
+ * In-process idempotency store. Reservation is atomic by construction — `begin` never awaits, so the
215
+ * single-threaded event loop serializes concurrent callers for one key. Expired entries are treated
216
+ * as absent (lazy eviction on access); a periodic {@link MemoryIdempotencyStore.sweep} bounds memory.
217
+ */
218
+ export class MemoryIdempotencyStore {
219
+ durability = "memory";
220
+ entries = new Map();
221
+ now;
222
+ maxEntries;
223
+ constructor(options = {}) {
224
+ this.now = options.now ?? Date.now;
225
+ this.maxEntries = options.maxEntries ?? 10_000;
226
+ if (!Number.isInteger(this.maxEntries) || this.maxEntries < 1) {
227
+ throw new RangeError("idempotency: maxEntries must be a positive integer");
228
+ }
229
+ }
230
+ begin(input) {
231
+ const storageKey = this.storageKey(input);
232
+ const existing = this.entries.get(storageKey);
233
+ if (existing !== undefined && existing.expiresAt > this.now()) {
234
+ if (existing.fingerprint !== input.fingerprint)
235
+ return { state: "mismatch" };
236
+ if (existing.response !== undefined)
237
+ return { state: "replay", response: existing.response };
238
+ return { state: "in-flight" };
239
+ }
240
+ if (existing !== undefined)
241
+ this.entries.delete(storageKey);
242
+ if (this.entries.size >= this.maxEntries) {
243
+ this.sweep();
244
+ if (this.entries.size >= this.maxEntries)
245
+ return { state: "capacity" };
246
+ }
247
+ const reservation = crypto.randomUUID();
248
+ this.entries.set(storageKey, {
249
+ fingerprint: input.fingerprint,
250
+ reservation,
251
+ ttlMs: input.ttlMs,
252
+ expiresAt: this.now() + input.ttlMs,
253
+ response: undefined,
254
+ });
255
+ return { state: "new", reservation };
256
+ }
257
+ complete(input) {
258
+ const key = this.storageKey(input);
259
+ const entry = this.entries.get(key);
260
+ if (entry === undefined || entry.reservation !== input.reservation)
261
+ return false;
262
+ if (entry.expiresAt <= this.now()) {
263
+ this.entries.delete(key);
264
+ return false;
265
+ }
266
+ entry.response = input.response;
267
+ entry.expiresAt = this.now() + entry.ttlMs;
268
+ return true;
269
+ }
270
+ abandon(input) {
271
+ const key = this.storageKey(input);
272
+ const entry = this.entries.get(key);
273
+ if (entry !== undefined && entry.expiresAt <= this.now()) {
274
+ this.entries.delete(key);
275
+ return false;
276
+ }
277
+ // Only drop a still-pending reservation; never evict a completed (replayable) response.
278
+ if (entry !== undefined &&
279
+ entry.response === undefined &&
280
+ entry.reservation === input.reservation) {
281
+ this.entries.delete(key);
282
+ return true;
283
+ }
284
+ return false;
285
+ }
286
+ /** Evict expired entries. Callers may run this on an interval; access-time eviction covers the rest. */
287
+ sweep() {
288
+ const now = this.now();
289
+ for (const [key, entry] of this.entries) {
290
+ if (entry.expiresAt <= now)
291
+ this.entries.delete(key);
292
+ }
293
+ }
294
+ /** Live entry count (post-sweep semantics are the caller's; this is a raw size for tests/metrics). */
295
+ get size() {
296
+ return this.entries.size;
297
+ }
298
+ storageKey(input) {
299
+ return `${input.namespace.length}:${input.namespace}${input.key}`;
300
+ }
301
+ }
302
+ /** Convenience factory mirroring the other core primitives' `create*` style. */
303
+ export function createMemoryIdempotencyStore(options) {
304
+ return new MemoryIdempotencyStore(options);
305
+ }
306
+ //# sourceMappingURL=idempotency.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"idempotency.js","sourceRoot":"","sources":["../src/idempotency.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -11,12 +11,19 @@
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.9.1";
14
+ export declare const VERSION: "1.11.0";
15
15
  export type Version = typeof VERSION;
16
16
  export * from "./assurance.js";
17
+ export * from "./capabilities.js";
18
+ export * from "./classification.js";
17
19
  export * from "./diff.js";
18
20
  export { FrameworkError, RouteConfigError, type RouteConfigErrorCode } from "./errors.js";
21
+ export * from "./idempotency.js";
19
22
  export { FRAMEWORK_NAME, type FrameworkName } from "./internal/brand.js";
23
+ export * from "./invariants.js";
24
+ export * from "./ledger.js";
25
+ export * from "./manifest.js";
26
+ export * from "./mount.js";
20
27
  export * from "./reflection.js";
21
28
  export { METHODS, type Method, Router, type RouterMatch } from "./router/router.js";
22
29
  export type { InferInput, InferOutput, StandardIssue, StandardResult, StandardSchemaV1, StandardTypes, ValidationOutcome, } from "./schema/standard.js";
@@ -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,QAAiB,CAAA;AAExC,MAAM,MAAM,OAAO,GAAG,OAAO,OAAO,CAAA;AAEpC,cAAc,gBAAgB,CAAA;AAC9B,cAAc,mBAAmB,CAAA;AACjC,cAAc,qBAAqB,CAAA;AACnC,cAAc,WAAW,CAAA;AACzB,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,KAAK,oBAAoB,EAAE,MAAM,aAAa,CAAA;AACzF,cAAc,kBAAkB,CAAA;AAChC,OAAO,EAAE,cAAc,EAAE,KAAK,aAAa,EAAE,MAAM,qBAAqB,CAAA;AACxE,cAAc,iBAAiB,CAAA;AAC/B,cAAc,aAAa,CAAA;AAC3B,cAAc,eAAe,CAAA;AAC7B,cAAc,YAAY,CAAA;AAC1B,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,mBAAmB,EACxB,KAAK,iBAAiB,EACtB,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,11 +11,18 @@
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.9.1";
14
+ export const VERSION = "1.11.0";
15
15
  export * from "./assurance.js";
16
+ export * from "./capabilities.js";
17
+ export * from "./classification.js";
16
18
  export * from "./diff.js";
17
19
  export { FrameworkError, RouteConfigError } from "./errors.js";
20
+ export * from "./idempotency.js";
18
21
  export { FRAMEWORK_NAME } from "./internal/brand.js";
22
+ export * from "./invariants.js";
23
+ export * from "./ledger.js";
24
+ export * from "./manifest.js";
25
+ export * from "./mount.js";
19
26
  export * from "./reflection.js";
20
27
  export { METHODS, Router } from "./router/router.js";
21
28
  export { validateStandard } from "./schema/standard.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,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,EAKL,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,QAAiB,CAAA;AAIxC,cAAc,gBAAgB,CAAA;AAC9B,cAAc,mBAAmB,CAAA;AACjC,cAAc,qBAAqB,CAAA;AACnC,cAAc,WAAW,CAAA;AACzB,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAA6B,MAAM,aAAa,CAAA;AACzF,cAAc,kBAAkB,CAAA;AAChC,OAAO,EAAE,cAAc,EAAsB,MAAM,qBAAqB,CAAA;AACxE,cAAc,iBAAiB,CAAA;AAC/B,cAAc,aAAa,CAAA;AAC3B,cAAc,eAAe,CAAA;AAC7B,cAAc,YAAY,CAAA;AAC1B,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,EAKL,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,16 @@
1
+ export declare const CAPABILITY_GUARD: unique symbol;
2
+ export declare function validCapabilityId(value: string): boolean;
3
+ export interface CapabilityUseEvent {
4
+ readonly capability: string;
5
+ readonly method: string;
6
+ readonly path: string;
7
+ }
8
+ export interface CapabilityGuard {
9
+ readonly allowed: readonly string[];
10
+ readonly method: string;
11
+ readonly path: string;
12
+ readonly onUse?: (event: CapabilityUseEvent) => void;
13
+ }
14
+ export declare function normalizeRouteCapabilities(values: readonly string[] | undefined): readonly string[];
15
+ export declare function createCapabilityGuard(allowed: readonly string[], method: string, path: string, onUse: ((event: CapabilityUseEvent) => void) | undefined): CapabilityGuard;
16
+ //# sourceMappingURL=capability-runtime.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capability-runtime.d.ts","sourceRoot":"","sources":["../../src/internal/capability-runtime.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,gBAAgB,eAAmC,CAAA;AAGhE,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAExD;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC3B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CACtB;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAA;IACnC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,kBAAkB,KAAK,IAAI,CAAA;CACrD;AAED,wBAAgB,0BAA0B,CACxC,MAAM,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,GACpC,SAAS,MAAM,EAAE,CAiBnB;AAED,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,SAAS,MAAM,EAAE,EAC1B,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,kBAAkB,KAAK,IAAI,CAAC,GAAG,SAAS,GACvD,eAAe,CAEjB"}
@@ -0,0 +1,27 @@
1
+ export const CAPABILITY_GUARD = Symbol("nifra.capability.guard");
2
+ const CAPABILITY_ID = /^[a-z][a-z0-9]*(?:[.-][a-z0-9]+)*$/;
3
+ export function validCapabilityId(value) {
4
+ return CAPABILITY_ID.test(value);
5
+ }
6
+ export function normalizeRouteCapabilities(values) {
7
+ if (values === undefined)
8
+ return Object.freeze([]);
9
+ if (!Array.isArray(values))
10
+ throw new TypeError("route capabilities must be an array");
11
+ const out = [];
12
+ const seen = new Set();
13
+ for (const value of values) {
14
+ if (typeof value !== "string" || !validCapabilityId(value)) {
15
+ throw new Error(`route capabilities: invalid capability id ${JSON.stringify(value)} (use lowercase dot/dash segments)`);
16
+ }
17
+ if (!seen.has(value)) {
18
+ seen.add(value);
19
+ out.push(value);
20
+ }
21
+ }
22
+ return Object.freeze(out);
23
+ }
24
+ export function createCapabilityGuard(allowed, method, path, onUse) {
25
+ return Object.freeze({ allowed, method, path, ...(onUse !== undefined ? { onUse } : {}) });
26
+ }
27
+ //# sourceMappingURL=capability-runtime.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capability-runtime.js","sourceRoot":"","sources":["../../src/internal/capability-runtime.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,gBAAgB,GAAG,MAAM,CAAC,wBAAwB,CAAC,CAAA;AAChE,MAAM,aAAa,GAAG,oCAAoC,CAAA;AAE1D,MAAM,UAAU,iBAAiB,CAAC,KAAa;IAC7C,OAAO,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;AAClC,CAAC;AAeD,MAAM,UAAU,0BAA0B,CACxC,MAAqC;IAErC,IAAI,MAAM,KAAK,SAAS;QAAE,OAAO,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAA;IAClD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC;QAAE,MAAM,IAAI,SAAS,CAAC,qCAAqC,CAAC,CAAA;IACtF,MAAM,GAAG,GAAa,EAAE,CAAA;IACxB,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAA;IAC9B,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,iBAAiB,CAAC,KAAK,CAAC,EAAE,CAAC;YAC3D,MAAM,IAAI,KAAK,CACb,6CAA6C,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,oCAAoC,CACvG,CAAA;QACH,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,MAAM,UAAU,qBAAqB,CACnC,OAA0B,EAC1B,MAAc,EACd,IAAY,EACZ,KAAwD;IAExD,OAAO,MAAM,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAA;AAC5F,CAAC"}
@@ -18,6 +18,7 @@ export declare const NIFRA_ASSURANCE_IDS: Readonly<{
18
18
  readonly AUTHENTICATED: "nifra.authenticated";
19
19
  readonly BODY_BOUNDED: "nifra.body-bounded";
20
20
  readonly CSRF: "nifra.csrf";
21
+ readonly DURABLE_COMMAND: "nifra.durable-command";
21
22
  readonly IDEMPOTENCY_KEY: "nifra.idempotency-key";
22
23
  readonly IP_RESTRICTED: "nifra.ip-restricted";
23
24
  readonly RATE_LIMITED: "nifra.rate-limited";
@@ -1 +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"}
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;;;;;;;;;EASrB,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"}
@@ -6,6 +6,7 @@ export const NIFRA_ASSURANCE_IDS = Object.freeze({
6
6
  AUTHENTICATED: "nifra.authenticated",
7
7
  BODY_BOUNDED: "nifra.body-bounded",
8
8
  CSRF: "nifra.csrf",
9
+ DURABLE_COMMAND: "nifra.durable-command",
9
10
  IDEMPOTENCY_KEY: "nifra.idempotency-key",
10
11
  IP_RESTRICTED: "nifra.ip-restricted",
11
12
  RATE_LIMITED: "nifra.rate-limited",