@nifrajs/core 1.10.0 → 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 (63) hide show
  1. package/dist/assurance.d.ts +13 -0
  2. package/dist/assurance.d.ts.map +1 -1
  3. package/dist/assurance.js +20 -0
  4. package/dist/assurance.js.map +1 -1
  5. package/dist/capabilities.d.ts +30 -1
  6. package/dist/capabilities.d.ts.map +1 -1
  7. package/dist/capabilities.js +32 -6
  8. package/dist/capabilities.js.map +1 -1
  9. package/dist/classification.d.ts +20 -0
  10. package/dist/classification.d.ts.map +1 -1
  11. package/dist/classification.js +120 -0
  12. package/dist/classification.js.map +1 -1
  13. package/dist/errors.d.ts +1 -1
  14. package/dist/errors.d.ts.map +1 -1
  15. package/dist/errors.js.map +1 -1
  16. package/dist/idempotency.d.ts +59 -12
  17. package/dist/idempotency.d.ts.map +1 -1
  18. package/dist/idempotency.js +191 -20
  19. package/dist/idempotency.js.map +1 -1
  20. package/dist/index.d.ts +5 -1
  21. package/dist/index.d.ts.map +1 -1
  22. package/dist/index.js +5 -1
  23. package/dist/index.js.map +1 -1
  24. package/dist/invariants.d.ts +66 -0
  25. package/dist/invariants.d.ts.map +1 -0
  26. package/dist/invariants.js +483 -0
  27. package/dist/invariants.js.map +1 -0
  28. package/dist/ledger.d.ts +154 -0
  29. package/dist/ledger.d.ts.map +1 -0
  30. package/dist/ledger.js +271 -0
  31. package/dist/ledger.js.map +1 -0
  32. package/dist/manifest.d.ts +81 -0
  33. package/dist/manifest.d.ts.map +1 -0
  34. package/dist/manifest.js +394 -0
  35. package/dist/manifest.js.map +1 -0
  36. package/dist/mount.d.ts +18 -0
  37. package/dist/mount.d.ts.map +1 -0
  38. package/dist/mount.js +11 -0
  39. package/dist/mount.js.map +1 -0
  40. package/dist/reflection.d.ts +3 -3
  41. package/dist/reflection.d.ts.map +1 -1
  42. package/dist/reflection.js +5 -5
  43. package/dist/reflection.js.map +1 -1
  44. package/dist/server/context.d.ts +17 -1
  45. package/dist/server/context.d.ts.map +1 -1
  46. package/dist/server/server.d.ts +23 -2
  47. package/dist/server/server.d.ts.map +1 -1
  48. package/dist/server/server.js +179 -26
  49. package/dist/server/server.js.map +1 -1
  50. package/package.json +26 -1
  51. package/src/assurance.ts +33 -0
  52. package/src/capabilities.ts +60 -4
  53. package/src/classification.ts +145 -0
  54. package/src/errors.ts +1 -0
  55. package/src/idempotency.ts +245 -30
  56. package/src/index.ts +5 -1
  57. package/src/invariants.ts +600 -0
  58. package/src/ledger.ts +430 -0
  59. package/src/manifest.ts +543 -0
  60. package/src/mount.ts +24 -0
  61. package/src/reflection.ts +11 -7
  62. package/src/server/context.ts +20 -1
  63. package/src/server/server.ts +254 -30
@@ -32,6 +32,7 @@ export interface StoredResponse {
32
32
  */
33
33
  export type IdempotencyBeginResult = {
34
34
  readonly state: "new";
35
+ readonly reservation: string;
35
36
  } | {
36
37
  readonly state: "replay";
37
38
  readonly response: StoredResponse;
@@ -39,34 +40,77 @@ export type IdempotencyBeginResult = {
39
40
  readonly state: "mismatch";
40
41
  } | {
41
42
  readonly state: "in-flight";
43
+ } | {
44
+ readonly state: "capacity";
42
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
+ }
43
64
  /**
44
65
  * Storage seam for idempotent responses. `begin` MUST be atomic: for one key, exactly one concurrent
45
66
  * caller sees `new`; the rest see `in-flight` (or `replay` once completed). The in-memory store gets
46
67
  * this free from the single-threaded event loop; a durable store uses an atomic insert.
47
68
  */
48
69
  export interface IdempotencyStore {
49
- /** Reserve `key` for `fingerprint`, retaining any stored response for `ttlMs`. */
50
- begin(key: string, fingerprint: string, ttlMs: number): IdempotencyBeginResult | Promise<IdempotencyBeginResult>;
51
- /** Persist the final response for a reserved key so later retries replay it. */
52
- complete(key: string, response: StoredResponse): void | Promise<void>;
53
- /** Release a reservation that produced no cacheable response, so the client may retry. */
54
- abandon(key: string): void | Promise<void>;
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>;
55
85
  }
56
86
  /** A key must be a non-empty, bounded, control-char-free token. Fail closed on anything else. */
57
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;
58
90
  /**
59
91
  * SHA-256 fingerprint binding a key to one request: method, path (+ query), and the raw body bytes.
60
92
  * A collision-resistant hash matters — a weak hash would let a crafted body replay another's response.
61
93
  */
62
- export declare function computeIdempotencyFingerprint(method: string, path: string, body: Uint8Array): Promise<string>;
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
+ }
63
101
  /** Buffer a response into a storable form. Clones first so the live response body stays intact. */
64
- export declare function serializeResponse(response: Response): Promise<StoredResponse>;
102
+ export declare function serializeResponse(response: Response, options?: {
103
+ readonly maxBytes?: number;
104
+ }): Promise<StoredResponse>;
65
105
  /** Rebuild a live response from storage, stamping the replay marker header. */
66
- export declare function responseFromStored(stored: StoredResponse): Response;
106
+ export declare function responseFromStored(stored: StoredResponse, options?: {
107
+ readonly maxBytes?: number;
108
+ }): Response;
67
109
  export interface MemoryIdempotencyStoreOptions {
68
110
  /** Injectable clock (epoch ms) for deterministic TTL tests. Default `Date.now`. */
69
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;
70
114
  }
71
115
  /**
72
116
  * In-process idempotency store. Reservation is atomic by construction — `begin` never awaits, so the
@@ -74,16 +118,19 @@ export interface MemoryIdempotencyStoreOptions {
74
118
  * as absent (lazy eviction on access); a periodic {@link MemoryIdempotencyStore.sweep} bounds memory.
75
119
  */
76
120
  export declare class MemoryIdempotencyStore implements IdempotencyStore {
121
+ readonly durability: "memory";
77
122
  private readonly entries;
78
123
  private readonly now;
124
+ private readonly maxEntries;
79
125
  constructor(options?: MemoryIdempotencyStoreOptions);
80
- begin(key: string, fingerprint: string, ttlMs: number): IdempotencyBeginResult;
81
- complete(key: string, response: StoredResponse): void;
82
- abandon(key: string): void;
126
+ begin(input: IdempotencyBeginInput): IdempotencyBeginResult;
127
+ complete(input: IdempotencyCompletionInput): boolean;
128
+ abandon(input: IdempotencyAbandonInput): boolean;
83
129
  /** Evict expired entries. Callers may run this on an interval; access-time eviction covers the rest. */
84
130
  sweep(): void;
85
131
  /** Live entry count (post-sweep semantics are the caller's; this is a raw size for tests/metrics). */
86
132
  get size(): number;
133
+ private storageKey;
87
134
  }
88
135
  /** Convenience factory mirroring the other core primitives' `create*` style. */
89
136
  export declare function createMemoryIdempotencyStore(options?: MemoryIdempotencyStoreOptions): MemoryIdempotencyStore;
@@ -1 +1 @@
1
- {"version":3,"file":"idempotency.d.ts","sourceRoot":"","sources":["../src/idempotency.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,0GAA0G;AAC1G,MAAM,MAAM,gBAAgB,GAAG,SAAS,GAAG,SAAS,CAAA;AAEpD,oEAAoE;AACpE,eAAO,MAAM,0BAA0B,WAAa,CAAA;AAEpD,2EAA2E;AAC3E,eAAO,MAAM,0BAA0B,oBAAoB,CAAA;AAE3D,mGAAmG;AACnG,eAAO,MAAM,wBAAwB,8BAA8B,CAAA;AAInE,oGAAoG;AACpG,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,OAAO,EAAE,SAAS,CAAC,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,EAAE,CAAA;IACxD,wEAAwE;IACxE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CACtB;AAED;;;;;GAKG;AACH,MAAM,MAAM,sBAAsB,GAC9B;IAAE,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAA;CAAE,GACzB;IAAE,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,cAAc,CAAA;CAAE,GAC/D;IAAE,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAA;CAAE,GAC9B;IAAE,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAA;CAAE,CAAA;AAEnC;;;;GAIG;AACH,MAAM,WAAW,gBAAgB;IAC/B,kFAAkF;IAClF,KAAK,CACH,GAAG,EAAE,MAAM,EACX,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,MAAM,GACZ,sBAAsB,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAAA;IAC3D,gFAAgF;IAChF,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,cAAc,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACrE,0FAA0F;IAC1F,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;CAC3C;AAED,iGAAiG;AACjG,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAOxD;AAID;;;GAGG;AACH,wBAAsB,6BAA6B,CACjD,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,UAAU,GACf,OAAO,CAAC,MAAM,CAAC,CAUjB;AAmBD,mGAAmG;AACnG,wBAAsB,iBAAiB,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,cAAc,CAAC,CAOnF;AAED,+EAA+E;AAC/E,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,cAAc,GAAG,QAAQ,CASnE;AAQD,MAAM,WAAW,6BAA6B;IAC5C,mFAAmF;IACnF,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAA;CAC5B;AAED;;;;GAIG;AACH,qBAAa,sBAAuB,YAAW,gBAAgB;IAC7D,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAiC;IACzD,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAc;gBAEtB,OAAO,GAAE,6BAAkC;IAIvD,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,sBAAsB;IAe9E,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,cAAc,GAAG,IAAI;IAKrD,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAM1B,wGAAwG;IACxG,KAAK,IAAI,IAAI;IAOb,sGAAsG;IACtG,IAAI,IAAI,IAAI,MAAM,CAEjB;CACF;AAED,gFAAgF;AAChF,wBAAgB,4BAA4B,CAC1C,OAAO,CAAC,EAAE,6BAA6B,GACtC,sBAAsB,CAExB"}
1
+ {"version":3,"file":"idempotency.d.ts","sourceRoot":"","sources":["../src/idempotency.ts"],"names":[],"mappings":"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"}
@@ -16,24 +16,53 @@ export const DEFAULT_IDEMPOTENCY_HEADER = "idempotency-key";
16
16
  /** Header stamped on a replayed response so clients/proxies can tell a replay from a fresh run. */
17
17
  export const IDEMPOTENT_REPLAY_HEADER = "x-nifra-idempotent-replay";
18
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
+ }
19
43
  /** A key must be a non-empty, bounded, control-char-free token. Fail closed on anything else. */
20
44
  export function validIdempotencyKey(key) {
21
45
  if (typeof key !== "string" || key.length === 0 || key.length > KEY_MAX_LENGTH)
22
46
  return false;
23
47
  for (let i = 0; i < key.length; i++) {
24
48
  const code = key.charCodeAt(i);
25
- if (code <= 31 || code === 127)
49
+ if (code < 33 || code > 126)
26
50
  return false;
27
51
  }
28
52
  return true;
29
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
+ }
30
58
  const encoder = new TextEncoder();
31
59
  /**
32
60
  * SHA-256 fingerprint binding a key to one request: method, path (+ query), and the raw body bytes.
33
61
  * A collision-resistant hash matters — a weak hash would let a crafted body replay another's response.
34
62
  */
35
- export async function computeIdempotencyFingerprint(method, path, body) {
36
- const head = encoder.encode(`${method.toUpperCase()}\n${path}\n`);
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`);
37
66
  const material = new Uint8Array(head.length + body.length);
38
67
  material.set(head, 0);
39
68
  material.set(body, head.length);
@@ -44,6 +73,40 @@ export async function computeIdempotencyFingerprint(method, path, body) {
44
73
  hex += bytes[i].toString(16).padStart(2, "0");
45
74
  return hex;
46
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
+ }
47
110
  const BASE64_CHUNK = 0x8000;
48
111
  function bytesToBase64(bytes) {
49
112
  let binary = "";
@@ -59,18 +122,88 @@ function base64ToBytes(value) {
59
122
  bytes[i] = binary.charCodeAt(i);
60
123
  return bytes;
61
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
+ }
62
177
  /** Buffer a response into a storable form. Clones first so the live response body stays intact. */
63
- export async function serializeResponse(response) {
64
- const bytes = new Uint8Array(await response.clone().arrayBuffer());
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);
65
186
  return {
66
187
  status: response.status,
67
- headers: [...response.headers],
188
+ headers: replaySafeHeaders(response.headers),
68
189
  body: bytes.length > 0 ? bytesToBase64(bytes) : "",
69
190
  };
70
191
  }
71
192
  /** Rebuild a live response from storage, stamping the replay marker header. */
72
- export function responseFromStored(stored) {
73
- const headers = new Headers(stored.headers);
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));
74
207
  headers.set(IDEMPOTENT_REPLAY_HEADER, "1");
75
208
  // Reference the Response body type structurally: `BodyInit` isn't a named type under every lib config,
76
209
  // but a fresh `Uint8Array` is a valid body — the cast bridges the `ArrayBufferLike` generic variance.
@@ -83,37 +216,72 @@ export function responseFromStored(stored) {
83
216
  * as absent (lazy eviction on access); a periodic {@link MemoryIdempotencyStore.sweep} bounds memory.
84
217
  */
85
218
  export class MemoryIdempotencyStore {
219
+ durability = "memory";
86
220
  entries = new Map();
87
221
  now;
222
+ maxEntries;
88
223
  constructor(options = {}) {
89
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
+ }
90
229
  }
91
- begin(key, fingerprint, ttlMs) {
92
- const existing = this.entries.get(key);
230
+ begin(input) {
231
+ const storageKey = this.storageKey(input);
232
+ const existing = this.entries.get(storageKey);
93
233
  if (existing !== undefined && existing.expiresAt > this.now()) {
94
- if (existing.fingerprint !== fingerprint)
234
+ if (existing.fingerprint !== input.fingerprint)
95
235
  return { state: "mismatch" };
96
236
  if (existing.response !== undefined)
97
237
  return { state: "replay", response: existing.response };
98
238
  return { state: "in-flight" };
99
239
  }
100
- this.entries.set(key, {
101
- fingerprint,
102
- expiresAt: this.now() + ttlMs,
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,
103
253
  response: undefined,
104
254
  });
105
- return { state: "new" };
255
+ return { state: "new", reservation };
106
256
  }
107
- complete(key, response) {
257
+ complete(input) {
258
+ const key = this.storageKey(input);
108
259
  const entry = this.entries.get(key);
109
- if (entry !== undefined)
110
- entry.response = response;
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;
111
269
  }
112
- abandon(key) {
270
+ abandon(input) {
271
+ const key = this.storageKey(input);
113
272
  const entry = this.entries.get(key);
273
+ if (entry !== undefined && entry.expiresAt <= this.now()) {
274
+ this.entries.delete(key);
275
+ return false;
276
+ }
114
277
  // Only drop a still-pending reservation; never evict a completed (replayable) response.
115
- if (entry !== undefined && entry.response === undefined)
278
+ if (entry !== undefined &&
279
+ entry.response === undefined &&
280
+ entry.reservation === input.reservation) {
116
281
  this.entries.delete(key);
282
+ return true;
283
+ }
284
+ return false;
117
285
  }
118
286
  /** Evict expired entries. Callers may run this on an interval; access-time eviction covers the rest. */
119
287
  sweep() {
@@ -127,6 +295,9 @@ export class MemoryIdempotencyStore {
127
295
  get size() {
128
296
  return this.entries.size;
129
297
  }
298
+ storageKey(input) {
299
+ return `${input.namespace.length}:${input.namespace}${input.key}`;
300
+ }
130
301
  }
131
302
  /** Convenience factory mirroring the other core primitives' `create*` style. */
132
303
  export function createMemoryIdempotencyStore(options) {
@@ -1 +1 @@
1
- {"version":3,"file":"idempotency.js","sourceRoot":"","sources":["../src/idempotency.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"idempotency.js","sourceRoot":"","sources":["../src/idempotency.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -11,7 +11,7 @@
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.10.0";
14
+ export declare const VERSION: "1.11.0";
15
15
  export type Version = typeof VERSION;
16
16
  export * from "./assurance.js";
17
17
  export * from "./capabilities.js";
@@ -20,6 +20,10 @@ export * from "./diff.js";
20
20
  export { FrameworkError, RouteConfigError, type RouteConfigErrorCode } from "./errors.js";
21
21
  export * from "./idempotency.js";
22
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";
23
27
  export * from "./reflection.js";
24
28
  export { METHODS, type Method, Router, type RouterMatch } from "./router/router.js";
25
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":"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"}
package/dist/index.js CHANGED
@@ -11,7 +11,7 @@
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.10.0";
14
+ export const VERSION = "1.11.0";
15
15
  export * from "./assurance.js";
16
16
  export * from "./capabilities.js";
17
17
  export * from "./classification.js";
@@ -19,6 +19,10 @@ export * from "./diff.js";
19
19
  export { FrameworkError, RouteConfigError } from "./errors.js";
20
20
  export * from "./idempotency.js";
21
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";
22
26
  export * from "./reflection.js";
23
27
  export { METHODS, Router } from "./router/router.js";
24
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,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,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,66 @@
1
+ /**
2
+ * Contract-generated invariant tests: the declared contract *is* the test suite.
3
+ *
4
+ * `runContractInvariants(app)` reads each route's reflected contract (schemas, classification) and
5
+ * verifies, with deterministic seeded fuzzing, the properties the contract already promises:
6
+ *
7
+ * 1. **Classification consistency** (static) — a route whose response fields are tagged more
8
+ * sensitive than its declared route-level classification is understating what it emits.
9
+ * 2. **Valid input never crashes** (dynamic) — schema-generated valid requests must not produce 5xx.
10
+ * 3. **Response conformance** (dynamic) — a 2xx response body must validate against the declared
11
+ * response schema; an undeclared response shape is exactly where sensitive data leaks.
12
+ * 4. **Validation fails closed** (dynamic) — schema-violating bodies must be rejected (4xx), never
13
+ * accepted (2xx) and never crash (5xx).
14
+ *
15
+ * Everything is deterministic: a seeded PRNG (no ambient randomness, no wall clock), so a failing
16
+ * case reproduces from its seed. Routes whose inputs cannot be generated from their JSON Schema are
17
+ * reported in `skipped` — never silently dropped.
18
+ */
19
+ export type InvariantFindingCode = "classification-understated" | "server-error-on-valid-input" | "response-schema-violation" | "validation-bypass" | "server-error-on-invalid-input";
20
+ export interface InvariantFinding {
21
+ readonly code: InvariantFindingCode;
22
+ readonly method: string;
23
+ readonly path: string;
24
+ /** The case's deterministic seed — rerun with it to reproduce the exact request. */
25
+ readonly seed?: number;
26
+ readonly message: string;
27
+ }
28
+ export interface SkippedRoute {
29
+ readonly method: string;
30
+ readonly path: string;
31
+ readonly reason: string;
32
+ }
33
+ export interface InvariantReport {
34
+ readonly ok: boolean;
35
+ /** Routes exercised dynamically. */
36
+ readonly tested: readonly {
37
+ readonly method: string;
38
+ readonly path: string;
39
+ }[];
40
+ /** Routes that could not be exercised, with the reason — reported, never silently dropped. */
41
+ readonly skipped: readonly SkippedRoute[];
42
+ readonly findings: readonly InvariantFinding[];
43
+ }
44
+ export interface RunInvariantsOptions {
45
+ /** Deterministic seed for the fuzzer. Default 1. */
46
+ readonly seed?: number;
47
+ /** Valid-input cases per route. Default 8. */
48
+ readonly casesPerRoute?: number;
49
+ /** Invalid-input (mutated) cases per route with a body schema. Default 4. */
50
+ readonly invalidCasesPerRoute?: number;
51
+ /**
52
+ * Explicit isolated executor for dynamic cases. It must point at a disposable test app, sandbox,
53
+ * or transaction that is rolled back. The runner never calls `source.fetch()` implicitly: doing so
54
+ * could charge cards, send mail, or mutate production state merely by running a verification tool.
55
+ */
56
+ readonly executor?: InvariantExecutor;
57
+ }
58
+ export type InvariantExecutor = (request: Request) => Response | Promise<Response>;
59
+ /** Opaque route-reflection source. The runner never invokes an app's live fetch method implicitly. */
60
+ type ReflectableApp = object;
61
+ /** Deterministic PRNG (mulberry32). Ambient randomness would make failures unreproducible. */
62
+ export declare function createSeededRandom(seed: number): () => number;
63
+ /** Run the contract-derived invariant suite against a reflectable app. Pure; no ambient state. */
64
+ export declare function runContractInvariants(app: ReflectableApp, options?: RunInvariantsOptions): Promise<InvariantReport>;
65
+ export {};
66
+ //# sourceMappingURL=invariants.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"invariants.d.ts","sourceRoot":"","sources":["../src/invariants.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAWH,MAAM,MAAM,oBAAoB,GAC5B,4BAA4B,GAC5B,6BAA6B,GAC7B,2BAA2B,GAC3B,mBAAmB,GACnB,+BAA+B,CAAA;AAEnC,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,oFAAoF;IACpF,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAA;IACtB,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,MAAM,EAAE,MAAM,CAAA;CACxB;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,EAAE,EAAE,OAAO,CAAA;IACpB,oCAAoC;IACpC,QAAQ,CAAC,MAAM,EAAE,SAAS;QAAE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;IAC9E,8FAA8F;IAC9F,QAAQ,CAAC,OAAO,EAAE,SAAS,YAAY,EAAE,CAAA;IACzC,QAAQ,CAAC,QAAQ,EAAE,SAAS,gBAAgB,EAAE,CAAA;CAC/C;AAED,MAAM,WAAW,oBAAoB;IACnC,oDAAoD;IACpD,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAA;IACtB,8CAA8C;IAC9C,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAA;IAC/B,6EAA6E;IAC7E,QAAQ,CAAC,oBAAoB,CAAC,EAAE,MAAM,CAAA;IACtC;;;;OAIG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,iBAAiB,CAAA;CACtC;AAED,MAAM,MAAM,iBAAiB,GAAG,CAAC,OAAO,EAAE,OAAO,KAAK,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAA;AAElF,sGAAsG;AACtG,KAAK,cAAc,GAAG,MAAM,CAAA;AA0B5B,8FAA8F;AAC9F,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,MAAM,CAS7D;AA8ND,kGAAkG;AAClG,wBAAsB,qBAAqB,CACzC,GAAG,EAAE,cAAc,EACnB,OAAO,GAAE,oBAAyB,GACjC,OAAO,CAAC,eAAe,CAAC,CAmG1B"}