@nifrajs/core 2.14.1 → 3.2.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 (226) hide show
  1. package/README.md +25 -0
  2. package/dist/assurance.d.ts +16 -8
  3. package/dist/assurance.d.ts.map +1 -1
  4. package/dist/assurance.js +33 -0
  5. package/dist/assurance.js.map +1 -1
  6. package/dist/durable-adapters.d.ts.map +1 -1
  7. package/dist/durable-adapters.js +26 -3
  8. package/dist/durable-adapters.js.map +1 -1
  9. package/dist/durable-approval.d.ts +56 -0
  10. package/dist/durable-approval.d.ts.map +1 -0
  11. package/dist/durable-approval.js +233 -0
  12. package/dist/durable-approval.js.map +1 -0
  13. package/dist/durable-effect.d.ts +42 -0
  14. package/dist/durable-effect.d.ts.map +1 -0
  15. package/dist/durable-effect.js +234 -0
  16. package/dist/durable-effect.js.map +1 -0
  17. package/dist/durable-execution.d.ts +8 -346
  18. package/dist/durable-execution.d.ts.map +1 -1
  19. package/dist/durable-execution.js +7 -1150
  20. package/dist/durable-execution.js.map +1 -1
  21. package/dist/durable-saga.d.ts +94 -0
  22. package/dist/durable-saga.d.ts.map +1 -0
  23. package/dist/durable-saga.js +550 -0
  24. package/dist/durable-saga.js.map +1 -0
  25. package/dist/edge-kit.d.ts +27 -0
  26. package/dist/edge-kit.d.ts.map +1 -0
  27. package/dist/edge-kit.js +24 -0
  28. package/dist/edge-kit.js.map +1 -0
  29. package/dist/errors.d.ts +1 -1
  30. package/dist/errors.d.ts.map +1 -1
  31. package/dist/errors.js.map +1 -1
  32. package/dist/index.d.ts +23 -2
  33. package/dist/index.d.ts.map +1 -1
  34. package/dist/index.js +18 -2
  35. package/dist/index.js.map +1 -1
  36. package/dist/internal/durable-approval-protocol.d.ts +1 -1
  37. package/dist/internal/durable-approval-protocol.d.ts.map +1 -1
  38. package/dist/internal/durable-effect-protocol.d.ts +1 -1
  39. package/dist/internal/durable-effect-protocol.d.ts.map +1 -1
  40. package/dist/internal/durable-saga-protocol.d.ts +1 -1
  41. package/dist/internal/durable-saga-protocol.d.ts.map +1 -1
  42. package/dist/internal/durable-shared.d.ts +26 -0
  43. package/dist/internal/durable-shared.d.ts.map +1 -0
  44. package/dist/internal/durable-shared.js +131 -0
  45. package/dist/internal/durable-shared.js.map +1 -0
  46. package/dist/internal/durable-types.d.ts +159 -0
  47. package/dist/internal/durable-types.d.ts.map +1 -0
  48. package/dist/internal/durable-types.js +2 -0
  49. package/dist/internal/durable-types.js.map +1 -0
  50. package/dist/internal/route-compiler.d.ts +61 -0
  51. package/dist/internal/route-compiler.d.ts.map +1 -0
  52. package/dist/internal/route-compiler.js +121 -0
  53. package/dist/internal/route-compiler.js.map +1 -0
  54. package/dist/internal/route-execution.d.ts +17 -9
  55. package/dist/internal/route-execution.d.ts.map +1 -1
  56. package/dist/internal/route-execution.js +4 -18
  57. package/dist/internal/route-execution.js.map +1 -1
  58. package/dist/internal/route-lanes.d.ts +35 -0
  59. package/dist/internal/route-lanes.d.ts.map +1 -0
  60. package/dist/internal/route-lanes.js +150 -0
  61. package/dist/internal/route-lanes.js.map +1 -0
  62. package/dist/internal/route-program.d.ts +67 -0
  63. package/dist/internal/route-program.d.ts.map +1 -0
  64. package/dist/internal/route-program.js +199 -0
  65. package/dist/internal/route-program.js.map +1 -0
  66. package/dist/response-observer.d.ts +25 -0
  67. package/dist/response-observer.d.ts.map +1 -0
  68. package/dist/response-observer.js +40 -0
  69. package/dist/response-observer.js.map +1 -0
  70. package/dist/security/baseline.d.ts +68 -0
  71. package/dist/security/baseline.d.ts.map +1 -0
  72. package/dist/security/baseline.js +118 -0
  73. package/dist/security/baseline.js.map +1 -0
  74. package/dist/server/bare-error-lane.d.ts +26 -0
  75. package/dist/server/bare-error-lane.d.ts.map +1 -0
  76. package/dist/server/bare-error-lane.js +60 -0
  77. package/dist/server/bare-error-lane.js.map +1 -0
  78. package/dist/server/body-lane.d.ts +13 -0
  79. package/dist/server/body-lane.d.ts.map +1 -0
  80. package/dist/server/body-lane.js +134 -0
  81. package/dist/server/body-lane.js.map +1 -0
  82. package/dist/server/body.d.ts +7 -0
  83. package/dist/server/body.d.ts.map +1 -1
  84. package/dist/server/body.js +7 -0
  85. package/dist/server/body.js.map +1 -1
  86. package/dist/server/bridge-markers.d.ts +25 -0
  87. package/dist/server/bridge-markers.d.ts.map +1 -0
  88. package/dist/server/bridge-markers.js +25 -0
  89. package/dist/server/bridge-markers.js.map +1 -0
  90. package/dist/server/context.d.ts +6 -1
  91. package/dist/server/context.d.ts.map +1 -1
  92. package/dist/server/contract.d.ts +40 -14
  93. package/dist/server/contract.d.ts.map +1 -1
  94. package/dist/server/contract.js +7 -0
  95. package/dist/server/contract.js.map +1 -1
  96. package/dist/server/cookies.d.ts.map +1 -1
  97. package/dist/server/cookies.js +16 -2
  98. package/dist/server/cookies.js.map +1 -1
  99. package/dist/server/header-case.d.ts.map +1 -1
  100. package/dist/server/header-case.js +2 -1
  101. package/dist/server/header-case.js.map +1 -1
  102. package/dist/server/http.d.ts +36 -3
  103. package/dist/server/http.d.ts.map +1 -1
  104. package/dist/server/http.js +49 -3
  105. package/dist/server/http.js.map +1 -1
  106. package/dist/server/install.d.ts +6 -8
  107. package/dist/server/install.d.ts.map +1 -1
  108. package/dist/server/install.js +7 -0
  109. package/dist/server/install.js.map +1 -1
  110. package/dist/server/node-outcome-hook.d.ts +2 -1
  111. package/dist/server/node-outcome-hook.d.ts.map +1 -1
  112. package/dist/server/node-outcome-hook.js.map +1 -1
  113. package/dist/server/node-outcome.d.ts +17 -2
  114. package/dist/server/node-outcome.d.ts.map +1 -1
  115. package/dist/server/node-outcome.js +37 -3
  116. package/dist/server/node-outcome.js.map +1 -1
  117. package/dist/server/plugin.d.ts +2 -2
  118. package/dist/server/plugin.d.ts.map +1 -1
  119. package/dist/server/plugin.js +6 -1
  120. package/dist/server/plugin.js.map +1 -1
  121. package/dist/server/query.d.ts +7 -1
  122. package/dist/server/query.d.ts.map +1 -1
  123. package/dist/server/query.js +8 -3
  124. package/dist/server/query.js.map +1 -1
  125. package/dist/server/registry.d.ts +40 -12
  126. package/dist/server/registry.d.ts.map +1 -1
  127. package/dist/server/request-context.d.ts +2 -13
  128. package/dist/server/request-context.d.ts.map +1 -1
  129. package/dist/server/request-context.js +18 -159
  130. package/dist/server/request-context.js.map +1 -1
  131. package/dist/server/respond.d.ts.map +1 -1
  132. package/dist/server/respond.js +58 -4
  133. package/dist/server/respond.js.map +1 -1
  134. package/dist/server/response-contract-lane.d.ts.map +1 -1
  135. package/dist/server/response-contract-lane.js +5 -2
  136. package/dist/server/response-contract-lane.js.map +1 -1
  137. package/dist/server/response-observer-runtime.d.ts +20 -0
  138. package/dist/server/response-observer-runtime.d.ts.map +1 -0
  139. package/dist/server/response-observer-runtime.js +95 -0
  140. package/dist/server/response-observer-runtime.js.map +1 -0
  141. package/dist/server/runtime-core.d.ts +76 -0
  142. package/dist/server/runtime-core.d.ts.map +1 -1
  143. package/dist/server/runtime-core.js +42 -1
  144. package/dist/server/runtime-core.js.map +1 -1
  145. package/dist/server/server-types.d.ts +6 -1
  146. package/dist/server/server-types.d.ts.map +1 -1
  147. package/dist/server/server.d.ts +158 -116
  148. package/dist/server/server.d.ts.map +1 -1
  149. package/dist/server/server.js +707 -844
  150. package/dist/server/server.js.map +1 -1
  151. package/dist/server/validation.d.ts +5 -0
  152. package/dist/server/validation.d.ts.map +1 -0
  153. package/dist/server/validation.js +13 -0
  154. package/dist/server/validation.js.map +1 -0
  155. package/dist/server/websocket.d.ts +20 -4
  156. package/dist/server/websocket.d.ts.map +1 -1
  157. package/dist/server/websocket.js +81 -11
  158. package/dist/server/websocket.js.map +1 -1
  159. package/dist/server/ws-bun.d.ts +12 -4
  160. package/dist/server/ws-bun.d.ts.map +1 -1
  161. package/dist/server/ws-bun.js +50 -16
  162. package/dist/server/ws-bun.js.map +1 -1
  163. package/dist/server/ws-hook.d.ts +3 -2
  164. package/dist/server/ws-hook.d.ts.map +1 -1
  165. package/dist/server.d.ts +3 -2
  166. package/dist/server.d.ts.map +1 -1
  167. package/dist/server.js +2 -1
  168. package/dist/server.js.map +1 -1
  169. package/dist/single-copy-register.d.ts +2 -0
  170. package/dist/single-copy-register.d.ts.map +1 -0
  171. package/dist/single-copy-register.js +24 -0
  172. package/dist/single-copy-register.js.map +1 -0
  173. package/dist/single-copy.d.ts +156 -0
  174. package/dist/single-copy.d.ts.map +1 -0
  175. package/dist/single-copy.js +472 -0
  176. package/dist/single-copy.js.map +1 -0
  177. package/package.json +28 -3
  178. package/src/assurance.ts +58 -1
  179. package/src/durable-adapters.ts +20 -0
  180. package/src/durable-approval.ts +281 -0
  181. package/src/durable-effect.ts +300 -0
  182. package/src/durable-execution.ts +8 -1627
  183. package/src/durable-saga.ts +744 -0
  184. package/src/edge-kit.ts +27 -0
  185. package/src/errors.ts +1 -0
  186. package/src/index.ts +129 -2
  187. package/src/internal/durable-approval-protocol.ts +1 -1
  188. package/src/internal/durable-effect-protocol.ts +1 -1
  189. package/src/internal/durable-saga-protocol.ts +1 -1
  190. package/src/internal/durable-shared.ts +157 -0
  191. package/src/internal/durable-types.ts +194 -0
  192. package/src/internal/route-compiler.ts +234 -0
  193. package/src/internal/route-execution.ts +53 -96
  194. package/src/internal/route-lanes.ts +221 -0
  195. package/src/internal/route-program.ts +404 -0
  196. package/src/response-observer.ts +64 -0
  197. package/src/security/baseline.ts +172 -0
  198. package/src/server/bare-error-lane.ts +77 -0
  199. package/src/server/body-lane.ts +203 -0
  200. package/src/server/body.ts +8 -0
  201. package/src/server/bridge-markers.ts +24 -0
  202. package/src/server/context.ts +6 -1
  203. package/src/server/contract.ts +70 -20
  204. package/src/server/cookies.ts +16 -2
  205. package/src/server/header-case.ts +3 -1
  206. package/src/server/http.ts +53 -3
  207. package/src/server/install.ts +14 -0
  208. package/src/server/node-outcome-hook.ts +2 -1
  209. package/src/server/node-outcome.ts +44 -3
  210. package/src/server/plugin.ts +11 -5
  211. package/src/server/query.ts +10 -4
  212. package/src/server/registry.ts +71 -16
  213. package/src/server/request-context.ts +13 -216
  214. package/src/server/respond.ts +71 -3
  215. package/src/server/response-contract-lane.ts +6 -2
  216. package/src/server/response-observer-runtime.ts +135 -0
  217. package/src/server/runtime-core.ts +124 -1
  218. package/src/server/server-types.ts +6 -1
  219. package/src/server/server.ts +1446 -1485
  220. package/src/server/validation.ts +19 -0
  221. package/src/server/websocket.ts +127 -17
  222. package/src/server/ws-bun.ts +67 -15
  223. package/src/server/ws-hook.ts +3 -2
  224. package/src/server.ts +8 -2
  225. package/src/single-copy-register.ts +24 -0
  226. package/src/single-copy.ts +526 -0
@@ -0,0 +1,56 @@
1
+ import type { CapabilityApprovalGate } from "./internal/capability-runtime.js";
2
+ import type { ApprovalConsumeResult, ApprovalRecord, ApprovalStore } from "./internal/durable-types.js";
3
+ export declare class ApprovalRequiredError extends Error {
4
+ readonly approvalId: string;
5
+ readonly effectId: string;
6
+ readonly resumeToken: string;
7
+ readonly expiresAt: number;
8
+ constructor(approvalId: string, effectId: string, resumeToken: string, expiresAt: number);
9
+ }
10
+ export declare class ApprovalTokenInvalidError extends Error {
11
+ constructor();
12
+ }
13
+ export declare class ApprovalTokenExpiredError extends Error {
14
+ constructor();
15
+ }
16
+ export declare class ApprovalTokenReplayError extends Error {
17
+ constructor();
18
+ }
19
+ export declare class ApprovalBindingError extends Error {
20
+ constructor();
21
+ }
22
+ export declare class ApprovalPendingError extends Error {
23
+ constructor();
24
+ }
25
+ export declare class ApprovalDeniedError extends Error {
26
+ constructor();
27
+ }
28
+ export interface ApprovalCoordinator extends CapabilityApprovalGate {
29
+ decide(input: {
30
+ readonly approvalId: string;
31
+ readonly tenantId: string;
32
+ readonly decision: "approved" | "denied";
33
+ readonly decidedBy: string;
34
+ }): Promise<void>;
35
+ get(approvalId: string): Promise<ApprovalRecord | undefined>;
36
+ }
37
+ export interface ApprovalCoordinatorOptions {
38
+ readonly store: ApprovalStore;
39
+ /** At least 32 random bytes, kept separately from the approval store. */
40
+ readonly secret: Uint8Array;
41
+ readonly ttlMs?: number;
42
+ readonly now?: () => number;
43
+ /** Tests/local development only. Production approval records require a durable store. */
44
+ readonly allowMemoryStore?: boolean;
45
+ }
46
+ export declare function createApprovalCoordinator(options: ApprovalCoordinatorOptions): ApprovalCoordinator;
47
+ export declare class MemoryApprovalStore implements ApprovalStore {
48
+ readonly durability: "memory";
49
+ private readonly records;
50
+ create(record: ApprovalRecord): boolean;
51
+ get(approvalId: string): ApprovalRecord | undefined;
52
+ decide(input: Parameters<ApprovalStore["decide"]>[0]): boolean;
53
+ consume(input: Parameters<ApprovalStore["consume"]>[0]): ApprovalConsumeResult;
54
+ list(): readonly ApprovalRecord[];
55
+ }
56
+ //# sourceMappingURL=durable-approval.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"durable-approval.d.ts","sourceRoot":"","sources":["../src/durable-approval.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,kCAAkC,CAAA;AAY9E,OAAO,KAAK,EACV,qBAAqB,EACrB,cAAc,EACd,aAAa,EACd,MAAM,6BAA6B,CAAA;AAoBpC,qBAAa,qBAAsB,SAAQ,KAAK;IAC9C,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC3B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,WAAW,EAAG,MAAM,CAAA;IAC7B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;gBAEd,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM;CAazF;AAED,qBAAa,yBAA0B,SAAQ,KAAK;;CAKnD;AACD,qBAAa,yBAA0B,SAAQ,KAAK;;CAKnD;AACD,qBAAa,wBAAyB,SAAQ,KAAK;;CAKlD;AACD,qBAAa,oBAAqB,SAAQ,KAAK;;CAK9C;AACD,qBAAa,oBAAqB,SAAQ,KAAK;;CAK9C;AACD,qBAAa,mBAAoB,SAAQ,KAAK;;CAK7C;AASD,MAAM,WAAW,mBAAoB,SAAQ,sBAAsB;IACjE,MAAM,CAAC,KAAK,EAAE;QACZ,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;QAC3B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;QACzB,QAAQ,CAAC,QAAQ,EAAE,UAAU,GAAG,QAAQ,CAAA;QACxC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;KAC3B,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACjB,GAAG,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,GAAG,SAAS,CAAC,CAAA;CAC7D;AAED,MAAM,WAAW,0BAA0B;IACzC,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAA;IAC7B,yEAAyE;IACzE,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAA;IAC3B,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAA;IAC3B,yFAAyF;IACzF,QAAQ,CAAC,gBAAgB,CAAC,EAAE,OAAO,CAAA;CACpC;AAED,wBAAgB,yBAAyB,CACvC,OAAO,EAAE,0BAA0B,GAClC,mBAAmB,CAyHrB;AAED,qBAAa,mBAAoB,YAAW,aAAa;IACvD,QAAQ,CAAC,UAAU,EAAG,QAAQ,CAAS;IACvC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAoC;IAE5D,MAAM,CAAC,MAAM,EAAE,cAAc,GAAG,OAAO;IAKvC,GAAG,CAAC,UAAU,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS;IAInD,MAAM,CAAC,KAAK,EAAE,UAAU,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,OAAO;IAO9D,OAAO,CAAC,KAAK,EAAE,UAAU,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,qBAAqB;IAO9E,IAAI,IAAI,SAAS,cAAc,EAAE;CAKlC"}
@@ -0,0 +1,233 @@
1
+ import { durableApprovalProtocol } from "./internal/durable-approval-protocol.js";
2
+ import { addDuration, assertPositiveMs, assertToken, bytesToBase64Url, cloneValue, encoder, readClock, sha256, } from "./internal/durable-shared.js";
3
+ const decoder = new TextDecoder();
4
+ function base64UrlToBytes(value) {
5
+ if (!/^[A-Za-z0-9_-]+$/u.test(value))
6
+ throw new ApprovalTokenInvalidError();
7
+ const padded = value
8
+ .replaceAll("-", "+")
9
+ .replaceAll("_", "/")
10
+ .padEnd(Math.ceil(value.length / 4) * 4, "=");
11
+ let binary;
12
+ try {
13
+ binary = atob(padded);
14
+ }
15
+ catch {
16
+ throw new ApprovalTokenInvalidError();
17
+ }
18
+ return Uint8Array.from(binary, (character) => character.charCodeAt(0));
19
+ }
20
+ // Durable human approval with signed, single-use resume tokens
21
+ export class ApprovalRequiredError extends Error {
22
+ approvalId;
23
+ effectId;
24
+ resumeToken;
25
+ expiresAt;
26
+ constructor(approvalId, effectId, resumeToken, expiresAt) {
27
+ super("capability approval is required");
28
+ this.approvalId = approvalId;
29
+ this.effectId = effectId;
30
+ this.expiresAt = expiresAt;
31
+ Object.defineProperty(this, "resumeToken", {
32
+ value: resumeToken,
33
+ enumerable: false,
34
+ configurable: false,
35
+ writable: false,
36
+ });
37
+ this.name = "ApprovalRequiredError";
38
+ }
39
+ }
40
+ export class ApprovalTokenInvalidError extends Error {
41
+ constructor() {
42
+ super("approval resume token is invalid");
43
+ this.name = "ApprovalTokenInvalidError";
44
+ }
45
+ }
46
+ export class ApprovalTokenExpiredError extends Error {
47
+ constructor() {
48
+ super("approval resume token has expired");
49
+ this.name = "ApprovalTokenExpiredError";
50
+ }
51
+ }
52
+ export class ApprovalTokenReplayError extends Error {
53
+ constructor() {
54
+ super("approval resume token has already been consumed");
55
+ this.name = "ApprovalTokenReplayError";
56
+ }
57
+ }
58
+ export class ApprovalBindingError extends Error {
59
+ constructor() {
60
+ super("approval resume token is bound to another tenant or principal");
61
+ this.name = "ApprovalBindingError";
62
+ }
63
+ }
64
+ export class ApprovalPendingError extends Error {
65
+ constructor() {
66
+ super("capability approval is still pending");
67
+ this.name = "ApprovalPendingError";
68
+ }
69
+ }
70
+ export class ApprovalDeniedError extends Error {
71
+ constructor() {
72
+ super("capability approval was denied");
73
+ this.name = "ApprovalDeniedError";
74
+ }
75
+ }
76
+ export function createApprovalCoordinator(options) {
77
+ if (options.store.durability !== "durable" && options.allowMemoryStore !== true) {
78
+ throw new TypeError('approval coordinator requires store.durability === "durable"');
79
+ }
80
+ if (!(options.secret instanceof Uint8Array) || options.secret.byteLength < 32) {
81
+ throw new TypeError("approval secret must contain at least 32 random bytes");
82
+ }
83
+ const secret = new Uint8Array(options.secret);
84
+ const ttlMs = options.ttlMs ?? 15 * 60_000;
85
+ assertPositiveMs(ttlMs, "approval ttlMs");
86
+ const clock = options.now ?? Date.now;
87
+ const now = () => readClock(clock, "approval clock");
88
+ const key = crypto.subtle.importKey("raw", secret, { name: "HMAC", hash: "SHA-256" }, false, [
89
+ "sign",
90
+ "verify",
91
+ ]);
92
+ const sign = async (claims) => {
93
+ const payload = bytesToBase64Url(encoder.encode(JSON.stringify(claims)));
94
+ const signature = new Uint8Array(await crypto.subtle.sign("HMAC", await key, encoder.encode(payload)));
95
+ return `v1.${payload}.${bytesToBase64Url(signature)}`;
96
+ };
97
+ const verify = async (token) => {
98
+ if (typeof token !== "string" || token.length > 2048)
99
+ throw new ApprovalTokenInvalidError();
100
+ const parts = token.split(".");
101
+ if (parts.length !== 3 || parts[0] !== "v1")
102
+ throw new ApprovalTokenInvalidError();
103
+ const payload = parts[1];
104
+ const valid = await crypto.subtle.verify("HMAC", await key, base64UrlToBytes(parts[2]).buffer, encoder.encode(payload));
105
+ if (!valid)
106
+ throw new ApprovalTokenInvalidError();
107
+ let claims;
108
+ try {
109
+ claims = JSON.parse(decoder.decode(base64UrlToBytes(payload)));
110
+ }
111
+ catch {
112
+ throw new ApprovalTokenInvalidError();
113
+ }
114
+ if (typeof claims !== "object" || claims === null)
115
+ throw new ApprovalTokenInvalidError();
116
+ const candidate = claims;
117
+ if (candidate.v !== 1 ||
118
+ typeof candidate.id !== "string" ||
119
+ typeof candidate.nonce !== "string" ||
120
+ !Number.isSafeInteger(candidate.exp)) {
121
+ throw new ApprovalTokenInvalidError();
122
+ }
123
+ assertToken(candidate.id, "approval id", 128);
124
+ assertToken(candidate.nonce, "approval nonce", 128);
125
+ if (candidate.exp <= now())
126
+ throw new ApprovalTokenExpiredError();
127
+ return candidate;
128
+ };
129
+ const coordinator = {
130
+ async authorize(input) {
131
+ if (input.signal.aborted)
132
+ throw input.signal.reason;
133
+ assertToken(input.identity.tenantId, "approval tenantId");
134
+ assertToken(input.identity.principalId, "approval principalId");
135
+ if (input.resumeToken === undefined) {
136
+ const approvalId = crypto.randomUUID();
137
+ const nonce = bytesToBase64Url(crypto.getRandomValues(new Uint8Array(18)));
138
+ const issuedAt = now();
139
+ const expiresAt = addDuration(issuedAt, ttlMs, "approval expiry");
140
+ const resumeToken = await sign({ v: 1, id: approvalId, nonce, exp: expiresAt });
141
+ const accepted = await options.store.create(Object.freeze({
142
+ approvalId,
143
+ effectId: input.effectId,
144
+ capability: input.capability,
145
+ ...(input.target === undefined ? {} : { target: input.target }),
146
+ ...(input.digest === undefined ? {} : { digest: input.digest }),
147
+ tenantId: input.identity.tenantId,
148
+ principalId: input.identity.principalId,
149
+ tokenHash: await sha256(resumeToken),
150
+ state: "pending",
151
+ createdAt: issuedAt,
152
+ expiresAt,
153
+ updatedAt: issuedAt,
154
+ version: 1,
155
+ }));
156
+ if (!accepted)
157
+ throw new Error("approval store rejected a unique approval id");
158
+ throw new ApprovalRequiredError(approvalId, input.effectId, resumeToken, expiresAt);
159
+ }
160
+ const claims = await verify(input.resumeToken);
161
+ const consumed = await options.store.consume({
162
+ approvalId: claims.id,
163
+ tenantId: input.identity.tenantId,
164
+ principalId: input.identity.principalId,
165
+ capability: input.capability,
166
+ ...(input.target === undefined ? {} : { target: input.target }),
167
+ ...(input.digest === undefined ? {} : { digest: input.digest }),
168
+ tokenHash: await sha256(input.resumeToken),
169
+ now: now(),
170
+ });
171
+ if (consumed.state === "consumed")
172
+ return;
173
+ if (consumed.state === "replay")
174
+ throw new ApprovalTokenReplayError();
175
+ if (consumed.state === "binding")
176
+ throw new ApprovalBindingError();
177
+ if (consumed.state === "expired")
178
+ throw new ApprovalTokenExpiredError();
179
+ if (consumed.state === "pending")
180
+ throw new ApprovalPendingError();
181
+ if (consumed.state === "denied")
182
+ throw new ApprovalDeniedError();
183
+ throw new ApprovalTokenInvalidError();
184
+ },
185
+ async decide(input) {
186
+ assertToken(input.approvalId, "approval id", 128);
187
+ assertToken(input.tenantId, "approval tenantId");
188
+ assertToken(input.decidedBy, "approval decidedBy");
189
+ const accepted = await options.store.decide({ ...input, now: now() });
190
+ if (!accepted)
191
+ throw new Error("approval decision rejected");
192
+ },
193
+ async get(approvalId) {
194
+ assertToken(approvalId, "approval id", 128);
195
+ return await options.store.get(approvalId);
196
+ },
197
+ };
198
+ return Object.freeze(coordinator);
199
+ }
200
+ export class MemoryApprovalStore {
201
+ durability = "memory";
202
+ records = new Map();
203
+ create(record) {
204
+ if (this.records.has(record.approvalId))
205
+ return false;
206
+ this.records.set(record.approvalId, Object.freeze(cloneValue(record)));
207
+ return true;
208
+ }
209
+ get(approvalId) {
210
+ const record = this.records.get(approvalId);
211
+ return record === undefined ? undefined : Object.freeze(cloneValue(record));
212
+ }
213
+ decide(input) {
214
+ const record = this.records.get(input.approvalId);
215
+ const next = durableApprovalProtocol.decide(record, input);
216
+ if (next === undefined)
217
+ return false;
218
+ this.records.set(input.approvalId, Object.freeze(next));
219
+ return true;
220
+ }
221
+ consume(input) {
222
+ const record = this.records.get(input.approvalId);
223
+ const transition = durableApprovalProtocol.consume(record, input);
224
+ if (transition.next !== undefined)
225
+ this.records.set(input.approvalId, Object.freeze(transition.next));
226
+ return transition.result;
227
+ }
228
+ list() {
229
+ return Object.freeze([...this.records.values()].map((record) => Object.freeze(cloneValue(record))));
230
+ }
231
+ }
232
+ // -------------------------------------------------------------------------------------------------
233
+ //# sourceMappingURL=durable-approval.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"durable-approval.js","sourceRoot":"","sources":["../src/durable-approval.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,42 @@
1
+ import { type EffectLifecycleObserver } from "./effect-lifecycle.js";
2
+ import type { CapabilityExecutionJournal } from "./internal/capability-runtime.js";
3
+ import type { DurableEffectRecord, DurableEffectState, DurableEffectStore, ReconciliationPage, ReconciliationScanOptions, ReconciliationScanPage } from "./internal/durable-types.js";
4
+ export declare class DurableEffectTransitionError extends Error {
5
+ readonly effectId: string;
6
+ readonly transition: string;
7
+ constructor(effectId: string, transition: string);
8
+ }
9
+ export interface DurableEffectJournalOptions {
10
+ readonly store: DurableEffectStore;
11
+ readonly now?: () => number;
12
+ /** Tests/local development only. Production journals require `store.durability === "durable"`. */
13
+ readonly allowMemoryStore?: boolean;
14
+ }
15
+ export declare function createDurableEffectJournal(options: DurableEffectJournalOptions): CapabilityExecutionJournal;
16
+ export declare class MemoryDurableEffectStore implements DurableEffectStore {
17
+ readonly durability: "memory";
18
+ private readonly records;
19
+ private readonly byState;
20
+ create(record: DurableEffectRecord): boolean;
21
+ get(effectId: string): DurableEffectRecord | undefined;
22
+ transition(input: Parameters<DurableEffectStore["transition"]>[0]): boolean;
23
+ list(): readonly DurableEffectRecord[];
24
+ scan(input: ReconciliationScanOptions<DurableEffectState>): ReconciliationScanPage<DurableEffectRecord>;
25
+ }
26
+ export interface EffectReconciliationFinding {
27
+ readonly effectId: string;
28
+ readonly capability: string;
29
+ readonly state: "incomplete" | "ambiguous";
30
+ readonly updatedAt: number;
31
+ }
32
+ export declare function reconcileEffectsPage(store: DurableEffectStore, options: {
33
+ readonly staleBefore: number;
34
+ readonly observer?: EffectLifecycleObserver;
35
+ readonly cursor?: string;
36
+ readonly limit?: number;
37
+ }): Promise<ReconciliationPage<EffectReconciliationFinding>>;
38
+ export declare function reconcileEffects(store: DurableEffectStore, options: {
39
+ readonly staleBefore: number;
40
+ readonly observer?: EffectLifecycleObserver;
41
+ }): Promise<readonly EffectReconciliationFinding[]>;
42
+ //# sourceMappingURL=durable-effect.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"durable-effect.d.ts","sourceRoot":"","sources":["../src/durable-effect.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,uBAAuB,EAAuB,MAAM,uBAAuB,CAAA;AACzF,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,kCAAkC,CAAA;AAgBlF,OAAO,KAAK,EACV,mBAAmB,EACnB,kBAAkB,EAClB,kBAAkB,EAClB,kBAAkB,EAClB,yBAAyB,EACzB,sBAAsB,EACvB,MAAM,6BAA6B,CAAA;AAGpC,qBAAa,4BAA6B,SAAQ,KAAK;aAEnC,QAAQ,EAAE,MAAM;aAChB,UAAU,EAAE,MAAM;gBADlB,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM;CAKrC;AAED,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,CAAC,KAAK,EAAE,kBAAkB,CAAA;IAClC,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAA;IAC3B,kGAAkG;IAClG,QAAQ,CAAC,gBAAgB,CAAC,EAAE,OAAO,CAAA;CACpC;AAED,wBAAgB,0BAA0B,CACxC,OAAO,EAAE,2BAA2B,GACnC,0BAA0B,CA+H5B;AAED,qBAAa,wBAAyB,YAAW,kBAAkB;IACjE,QAAQ,CAAC,UAAU,EAAG,QAAQ,CAAS;IACvC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAyC;IAGjE,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA6C;IAErE,MAAM,CAAC,MAAM,EAAE,mBAAmB,GAAG,OAAO;IAO5C,GAAG,CAAC,QAAQ,EAAE,MAAM,GAAG,mBAAmB,GAAG,SAAS;IAKtD,UAAU,CAAC,KAAK,EAAE,UAAU,CAAC,kBAAkB,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,OAAO;IAU3E,IAAI,IAAI,SAAS,mBAAmB,EAAE;IAMtC,IAAI,CACF,KAAK,EAAE,yBAAyB,CAAC,kBAAkB,CAAC,GACnD,sBAAsB,CAAC,mBAAmB,CAAC;CAG/C;AAED,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC3B,QAAQ,CAAC,KAAK,EAAE,YAAY,GAAG,WAAW,CAAA;IAC1C,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;CAC3B;AAWD,wBAAsB,oBAAoB,CACxC,KAAK,EAAE,kBAAkB,EACzB,OAAO,EAAE;IACP,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,QAAQ,CAAC,QAAQ,CAAC,EAAE,uBAAuB,CAAA;IAC3C,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CACxB,GACA,OAAO,CAAC,kBAAkB,CAAC,2BAA2B,CAAC,CAAC,CAwC1D;AAED,wBAAsB,gBAAgB,CACpC,KAAK,EAAE,kBAAkB,EACzB,OAAO,EAAE;IAAE,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,uBAAuB,CAAA;CAAE,GACrF,OAAO,CAAC,SAAS,2BAA2B,EAAE,CAAC,CAWjD"}
@@ -0,0 +1,234 @@
1
+ import { emitEffectLifecycle } from "./effect-lifecycle.js";
2
+ import { validCapabilityId } from "./internal/capability-runtime.js";
3
+ import { durableEffectProtocol } from "./internal/durable-effect-protocol.js";
4
+ import { assertTimestamp, assertToken, bucketAdd, bucketMove, cloneValue, ERROR_CODE, indexedScan, MAX_RECONCILIATION_LIMIT, memoryScan, readClock, reconciliationLimit, } from "./internal/durable-shared.js";
5
+ // Durable effect journal + reconciliation
6
+ export class DurableEffectTransitionError extends Error {
7
+ effectId;
8
+ transition;
9
+ constructor(effectId, transition) {
10
+ super(`durable effect ${effectId}: ${transition} transition was rejected`);
11
+ this.effectId = effectId;
12
+ this.transition = transition;
13
+ this.name = "DurableEffectTransitionError";
14
+ }
15
+ }
16
+ export function createDurableEffectJournal(options) {
17
+ if (options.store.durability !== "durable" && options.allowMemoryStore !== true) {
18
+ throw new TypeError('durable effect journal requires store.durability === "durable"');
19
+ }
20
+ const clock = options.now ?? Date.now;
21
+ const now = () => readClock(clock, "durable effect clock");
22
+ const current = async (effectId) => {
23
+ assertToken(effectId, "durable effect id", 64);
24
+ const record = await options.store.get(effectId);
25
+ if (record === undefined)
26
+ throw new DurableEffectTransitionError(effectId, "missing");
27
+ if (record.effectId !== effectId ||
28
+ !validCapabilityId(record.capability) ||
29
+ !["admission", "executing", "committed", "failed", "unknown"].includes(record.state) ||
30
+ !Number.isSafeInteger(record.version) ||
31
+ record.version < 1) {
32
+ throw new TypeError(`durable effect ${effectId}: store returned an invalid record`);
33
+ }
34
+ assertTimestamp(record.createdAt, "durable effect createdAt");
35
+ assertTimestamp(record.updatedAt, "durable effect updatedAt");
36
+ if (record.createdAt > record.updatedAt)
37
+ throw new TypeError(`durable effect ${effectId}: updatedAt precedes createdAt`);
38
+ if (record.target !== undefined)
39
+ assertToken(record.target, "stored durable effect target", 128);
40
+ if (record.digest !== undefined && !/^[0-9a-f]{64}$/u.test(record.digest))
41
+ throw new TypeError(`durable effect ${effectId}: store returned an invalid digest`);
42
+ if (record.tenantId !== undefined)
43
+ assertToken(record.tenantId, "stored durable effect tenantId");
44
+ if (record.principalId !== undefined)
45
+ assertToken(record.principalId, "stored durable effect principalId");
46
+ if ((record.tenantId === undefined) !== (record.principalId === undefined))
47
+ throw new TypeError(`durable effect ${effectId}: store returned a partial identity`);
48
+ if (record.errorCode !== undefined && !ERROR_CODE.test(record.errorCode))
49
+ throw new TypeError(`durable effect ${effectId}: store returned an invalid error code`);
50
+ return record;
51
+ };
52
+ const transition = async (effectId, from, to, errorCode) => {
53
+ const record = await current(effectId);
54
+ const next = durableEffectProtocol.transition(record, {
55
+ effectId,
56
+ version: record.version,
57
+ from,
58
+ to,
59
+ updatedAt: now(),
60
+ ...(errorCode === undefined ? {} : { errorCode }),
61
+ });
62
+ if (next === undefined)
63
+ throw new DurableEffectTransitionError(effectId, `${from}->${to}`);
64
+ const accepted = await options.store.transition({
65
+ effectId,
66
+ version: record.version,
67
+ from,
68
+ to,
69
+ updatedAt: next.updatedAt,
70
+ ...(errorCode === undefined ? {} : { errorCode }),
71
+ });
72
+ if (!accepted)
73
+ throw new DurableEffectTransitionError(effectId, `${from}->${to}`);
74
+ };
75
+ const journal = {
76
+ async intent(input) {
77
+ assertToken(input.effectId, "durable effect id", 64);
78
+ if (!validCapabilityId(input.capability))
79
+ throw new TypeError("durable effect capability is invalid");
80
+ if (input.target !== undefined)
81
+ assertToken(input.target, "durable effect target", 128);
82
+ if (input.digest !== undefined && !/^[0-9a-f]{64}$/u.test(input.digest))
83
+ throw new TypeError("durable effect digest is invalid");
84
+ if (input.identity !== undefined) {
85
+ assertToken(input.identity.tenantId, "durable effect tenantId");
86
+ assertToken(input.identity.principalId, "durable effect principalId");
87
+ }
88
+ const at = now();
89
+ const accepted = await options.store.create(Object.freeze({
90
+ effectId: input.effectId,
91
+ capability: input.capability,
92
+ ...(input.target === undefined ? {} : { target: input.target }),
93
+ ...(input.digest === undefined ? {} : { digest: input.digest }),
94
+ ...(input.identity === undefined
95
+ ? {}
96
+ : { tenantId: input.identity.tenantId, principalId: input.identity.principalId }),
97
+ state: "admission",
98
+ createdAt: at,
99
+ updatedAt: at,
100
+ version: 1,
101
+ }));
102
+ if (!accepted)
103
+ throw new DurableEffectTransitionError(input.effectId, "create");
104
+ },
105
+ async executing(effectId) {
106
+ await transition(effectId, "admission", "executing");
107
+ },
108
+ async committed(effectId) {
109
+ await transition(effectId, "executing", "committed");
110
+ },
111
+ async failed(effectId, input) {
112
+ if (!ERROR_CODE.test(input.errorCode))
113
+ throw new TypeError("durable effect errorCode is invalid");
114
+ const record = await current(effectId);
115
+ const to = input.began ? "unknown" : "failed";
116
+ const next = durableEffectProtocol.transition(record, {
117
+ effectId,
118
+ version: record.version,
119
+ from: record.state,
120
+ to,
121
+ updatedAt: now(),
122
+ errorCode: input.errorCode,
123
+ });
124
+ if (next === undefined)
125
+ throw new DurableEffectTransitionError(effectId, `${record.state}->${to}`);
126
+ const accepted = await options.store.transition({
127
+ effectId,
128
+ version: record.version,
129
+ from: record.state,
130
+ to,
131
+ updatedAt: next.updatedAt,
132
+ errorCode: input.errorCode,
133
+ });
134
+ if (!accepted)
135
+ throw new DurableEffectTransitionError(effectId, `${record.state}->${to}`);
136
+ },
137
+ };
138
+ return Object.freeze(journal);
139
+ }
140
+ export class MemoryDurableEffectStore {
141
+ durability = "memory";
142
+ records = new Map();
143
+ // Secondary index: effectIds grouped by state, so reconciliation scans only the requested (few,
144
+ // non-terminal) states instead of walking every retained record. See {@link indexedScan}.
145
+ byState = new Map();
146
+ create(record) {
147
+ if (this.records.has(record.effectId))
148
+ return false;
149
+ this.records.set(record.effectId, Object.freeze(cloneValue(record)));
150
+ bucketAdd(this.byState, record.state, record.effectId);
151
+ return true;
152
+ }
153
+ get(effectId) {
154
+ const record = this.records.get(effectId);
155
+ return record === undefined ? undefined : Object.freeze(cloneValue(record));
156
+ }
157
+ transition(input) {
158
+ const current = this.records.get(input.effectId);
159
+ const next = durableEffectProtocol.transition(current, input);
160
+ if (next === undefined)
161
+ return false;
162
+ if (current === undefined)
163
+ return false;
164
+ this.records.set(input.effectId, Object.freeze(next));
165
+ bucketMove(this.byState, current.state, input.to, input.effectId);
166
+ return true;
167
+ }
168
+ list() {
169
+ return Object.freeze([...this.records.values()].map((record) => Object.freeze(cloneValue(record))));
170
+ }
171
+ scan(input) {
172
+ return indexedScan(this.byState, (id) => this.records.get(id), input);
173
+ }
174
+ }
175
+ async function scanEffectRecords(store, input) {
176
+ if (store.scan !== undefined)
177
+ return await store.scan(input);
178
+ if (store.list === undefined)
179
+ throw new TypeError("effect store does not support reconciliation");
180
+ return memoryScan(await store.list(), input);
181
+ }
182
+ export async function reconcileEffectsPage(store, options) {
183
+ const findings = [];
184
+ const page = await scanEffectRecords(store, {
185
+ states: ["admission", "executing", "unknown"],
186
+ updatedBefore: options.staleBefore,
187
+ ...(options.cursor === undefined ? {} : { cursor: options.cursor }),
188
+ limit: reconciliationLimit(options.limit),
189
+ });
190
+ for (const record of page.records) {
191
+ if (!validCapabilityId(record.capability) || !/^[!-~]{1,64}$/u.test(record.effectId))
192
+ continue;
193
+ if (record.updatedAt > options.staleBefore)
194
+ continue;
195
+ const state = record.state === "admission"
196
+ ? "incomplete"
197
+ : record.state === "executing" || record.state === "unknown"
198
+ ? "ambiguous"
199
+ : undefined;
200
+ if (state === undefined)
201
+ continue;
202
+ findings.push(Object.freeze({
203
+ effectId: record.effectId,
204
+ capability: record.capability,
205
+ state,
206
+ updatedAt: record.updatedAt,
207
+ }));
208
+ if (options.observer !== undefined) {
209
+ emitEffectLifecycle([options.observer], {
210
+ effectId: record.effectId,
211
+ capability: record.capability,
212
+ stage: "reconciliation",
213
+ phase: state === "ambiguous" ? "ambiguous" : "failed",
214
+ errorCode: state === "ambiguous" ? "effect_ambiguous" : "effect_incomplete",
215
+ });
216
+ }
217
+ }
218
+ return Object.freeze({
219
+ findings: Object.freeze(findings),
220
+ ...(page.cursor === undefined ? {} : { cursor: page.cursor }),
221
+ });
222
+ }
223
+ export async function reconcileEffects(store, options) {
224
+ const page = await reconcileEffectsPage(store, {
225
+ ...options,
226
+ limit: MAX_RECONCILIATION_LIMIT,
227
+ });
228
+ if (page.cursor !== undefined) {
229
+ throw new RangeError(`effect reconciliation exceeds ${MAX_RECONCILIATION_LIMIT} records; use reconcileEffectsPage()`);
230
+ }
231
+ return page.findings;
232
+ }
233
+ // -------------------------------------------------------------------------------------------------
234
+ //# sourceMappingURL=durable-effect.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"durable-effect.js","sourceRoot":"","sources":["../src/durable-effect.ts"],"names":[],"mappings":"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"}