@lostgradient/weft 0.23.0 → 0.24.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 (295) hide show
  1. package/README.md +72 -4
  2. package/dist/cli/codegen-emit-dedup.d.ts +81 -0
  3. package/dist/cli/codegen-emit-dedup.js +45 -0
  4. package/dist/cli/codegen-emit-registry.d.ts +90 -0
  5. package/dist/cli/codegen-emit-registry.js +50 -0
  6. package/dist/cli/codegen-emit.d.ts +26 -39
  7. package/dist/cli/codegen-emit.js +4 -27
  8. package/dist/cli/codegen-validate.d.ts +49 -0
  9. package/dist/cli/codegen-validate.js +186 -0
  10. package/dist/cli/codegen.js +6 -87
  11. package/dist/cli/generated/operation-catalog.snapshot.json +287 -3
  12. package/dist/cli/generated/operation-client.generated.d.ts +324 -10
  13. package/dist/cli/generated/operation-client.generated.js +12 -0
  14. package/dist/cli/output.js +1 -1
  15. package/dist/cli/storage-factory.js +2 -0
  16. package/dist/cli/workflow-commands.js +2 -0
  17. package/dist/cli-main.js +1 -1
  18. package/dist/core/application-payload-digest.d.ts +42 -0
  19. package/dist/core/application-payload-digest.js +76 -0
  20. package/dist/core/application-primitive-abort.d.ts +50 -0
  21. package/dist/core/application-primitive-abort.js +40 -0
  22. package/dist/core/application-primitive-attempt-registry.d.ts +74 -0
  23. package/dist/core/application-primitive-attempt-registry.js +73 -0
  24. package/dist/core/application-primitive-codec.d.ts +36 -0
  25. package/dist/core/application-primitive-codec.js +56 -0
  26. package/dist/core/application-primitive-commit.d.ts +67 -0
  27. package/dist/core/application-primitive-commit.js +66 -0
  28. package/dist/core/application-primitive-guards.d.ts +62 -0
  29. package/dist/core/application-primitive-guards.js +89 -0
  30. package/dist/core/application-primitive-payload.d.ts +29 -0
  31. package/dist/core/application-primitive-payload.js +65 -0
  32. package/dist/core/application-primitive-timing.d.ts +18 -0
  33. package/dist/core/application-primitive-timing.js +22 -0
  34. package/dist/core/atomic-state.js +2 -0
  35. package/dist/core/catalog/codec.d.ts +40 -0
  36. package/dist/core/catalog/codec.js +45 -0
  37. package/dist/core/catalog/errors.d.ts +104 -0
  38. package/dist/core/catalog/errors.js +41 -0
  39. package/dist/core/catalog/index.d.ts +25 -0
  40. package/dist/core/catalog/index.js +15 -0
  41. package/dist/core/catalog/reference-counts.d.ts +105 -0
  42. package/dist/core/catalog/reference-counts.js +28 -0
  43. package/dist/core/catalog/removal.d.ts +52 -0
  44. package/dist/core/catalog/removal.js +14 -0
  45. package/dist/core/catalog/storage-io.d.ts +78 -0
  46. package/dist/core/catalog/storage-io.js +106 -0
  47. package/dist/core/catalog/types.d.ts +108 -0
  48. package/dist/core/catalog/types.js +0 -0
  49. package/dist/core/catalog/workflow-catalog.d.ts +165 -0
  50. package/dist/core/catalog/workflow-catalog.js +198 -0
  51. package/dist/core/compare-codepoint.d.ts +13 -0
  52. package/dist/core/compare-codepoint.js +7 -0
  53. package/dist/core/compression.js +2 -0
  54. package/dist/core/context/attributes.d.ts +1 -1
  55. package/dist/core/context/durable-operations.d.ts +2 -2
  56. package/dist/core/context/index.js +5 -3
  57. package/dist/core/context/state-namespace.d.ts +1 -1
  58. package/dist/core/contract/build.d.ts +64 -0
  59. package/dist/core/contract/build.js +99 -0
  60. package/dist/core/contract/compatibility.d.ts +187 -0
  61. package/dist/core/contract/compatibility.js +37 -0
  62. package/dist/core/contract/failure.d.ts +64 -0
  63. package/dist/core/contract/failure.js +4 -0
  64. package/dist/core/contract/hash.d.ts +92 -0
  65. package/dist/core/contract/hash.js +34 -0
  66. package/dist/core/contract/index.d.ts +21 -0
  67. package/dist/core/contract/index.js +22 -0
  68. package/dist/core/contract/limits.d.ts +74 -0
  69. package/dist/core/contract/limits.js +1 -0
  70. package/dist/core/contract/manifest-parse-schema.d.ts +37 -0
  71. package/dist/core/contract/manifest-parse-schema.js +106 -0
  72. package/dist/core/contract/manifest-parse.d.ts +76 -0
  73. package/dist/core/contract/manifest-parse.js +189 -0
  74. package/dist/core/contract/manifest.d.ts +56 -0
  75. package/dist/core/contract/manifest.js +31 -0
  76. package/dist/core/contract/normalize.d.ts +97 -0
  77. package/dist/core/contract/normalize.js +127 -0
  78. package/dist/core/contract/revision.d.ts +29 -0
  79. package/dist/core/contract/revision.js +5 -0
  80. package/dist/core/contract/types.d.ts +274 -0
  81. package/dist/core/contract/types.js +1 -0
  82. package/dist/core/engine/catalog-activation.d.ts +40 -0
  83. package/dist/core/engine/catalog-activation.js +17 -0
  84. package/dist/core/engine/catalog-events.d.ts +36 -0
  85. package/dist/core/engine/catalog-events.js +15 -0
  86. package/dist/core/engine/catalog-readiness.d.ts +49 -0
  87. package/dist/core/engine/catalog-readiness.js +59 -0
  88. package/dist/core/engine/catalog-removal.d.ts +132 -0
  89. package/dist/core/engine/catalog-removal.js +70 -0
  90. package/dist/core/engine/construction.d.ts +1 -1
  91. package/dist/core/engine/construction.js +4 -2
  92. package/dist/core/engine/disposal.js +9 -0
  93. package/dist/core/engine/engine-workflows-namespace.d.ts +130 -0
  94. package/dist/core/engine/engine-workflows-namespace.js +49 -0
  95. package/dist/core/engine/finalizer-metadata.d.ts +22 -0
  96. package/dist/core/engine/finalizer-metadata.js +12 -0
  97. package/dist/core/engine/handle-result.js +2 -0
  98. package/dist/core/engine/index.d.ts +83 -0
  99. package/dist/core/engine/index.js +61 -0
  100. package/dist/core/engine/internals.d.ts +44 -1
  101. package/dist/core/engine/internals.js +6 -0
  102. package/dist/core/engine/lifecycle/start.js +3 -0
  103. package/dist/core/engine/registration.d.ts +76 -0
  104. package/dist/core/engine/registration.js +12 -6
  105. package/dist/core/engine/source-registration.d.ts +42 -0
  106. package/dist/core/engine/source-registration.js +36 -0
  107. package/dist/core/engine/source-resolution.d.ts +85 -0
  108. package/dist/core/engine/source-resolution.js +119 -0
  109. package/dist/core/engine/validation.js +2 -2
  110. package/dist/core/events/catalog-events.d.ts +117 -0
  111. package/dist/core/events/catalog-events.js +62 -0
  112. package/dist/core/events/event-map.d.ts +6 -0
  113. package/dist/core/events/index.d.ts +1 -0
  114. package/dist/core/events/index.js +1 -0
  115. package/dist/core/mailbox-admission.d.ts +26 -0
  116. package/dist/core/mailbox-admission.js +130 -0
  117. package/dist/core/mailbox-claims.d.ts +251 -0
  118. package/dist/core/mailbox-claims.js +0 -0
  119. package/dist/core/mailbox-codec.d.ts +32 -0
  120. package/dist/core/mailbox-codec.js +221 -0
  121. package/dist/core/mailbox-contract.d.ts +290 -0
  122. package/dist/core/mailbox-contract.js +0 -0
  123. package/dist/core/mailbox-delivery.d.ts +37 -0
  124. package/dist/core/mailbox-delivery.js +193 -0
  125. package/dist/core/mailbox-guards.d.ts +78 -0
  126. package/dist/core/mailbox-guards.js +58 -0
  127. package/dist/core/mailbox-index-codec.d.ts +41 -0
  128. package/dist/core/mailbox-index-codec.js +71 -0
  129. package/dist/core/mailbox-internals.d.ts +156 -0
  130. package/dist/core/mailbox-internals.js +154 -0
  131. package/dist/core/mailbox-maintenance.d.ts +29 -0
  132. package/dist/core/mailbox-maintenance.js +196 -0
  133. package/dist/core/mailbox-settlement.d.ts +69 -0
  134. package/dist/core/mailbox-settlement.js +206 -0
  135. package/dist/core/mailbox-storage.d.ts +117 -0
  136. package/dist/core/mailbox-storage.js +115 -0
  137. package/dist/core/mailbox-transition-helpers.d.ts +70 -0
  138. package/dist/core/mailbox-transition-helpers.js +43 -0
  139. package/dist/core/mailbox-transitions-recovery.d.ts +28 -0
  140. package/dist/core/mailbox-transitions-recovery.js +64 -0
  141. package/dist/core/mailbox-transitions.d.ts +138 -0
  142. package/dist/core/mailbox-transitions.js +180 -0
  143. package/dist/core/mailbox-types.d.ts +406 -0
  144. package/dist/core/mailbox-types.js +16 -0
  145. package/dist/core/mailbox-validation.d.ts +65 -0
  146. package/dist/core/mailbox-validation.js +73 -0
  147. package/dist/core/mailbox-waits.d.ts +50 -0
  148. package/dist/core/mailbox-waits.js +97 -0
  149. package/dist/core/mailbox.d.ts +163 -0
  150. package/dist/core/mailbox.js +211 -0
  151. package/dist/core/outbox-claims.d.ts +307 -0
  152. package/dist/core/outbox-claims.js +0 -0
  153. package/dist/core/outbox-codec.d.ts +24 -0
  154. package/dist/core/outbox-codec.js +257 -0
  155. package/dist/core/outbox-contract.d.ts +346 -0
  156. package/dist/core/outbox-contract.js +0 -0
  157. package/dist/core/outbox-delivery.d.ts +34 -0
  158. package/dist/core/outbox-delivery.js +149 -0
  159. package/dist/core/outbox-drain.d.ts +29 -0
  160. package/dist/core/outbox-drain.js +158 -0
  161. package/dist/core/outbox-enqueue.d.ts +24 -0
  162. package/dist/core/outbox-enqueue.js +115 -0
  163. package/dist/core/outbox-guards.d.ts +76 -0
  164. package/dist/core/outbox-guards.js +60 -0
  165. package/dist/core/outbox-index-codec.d.ts +33 -0
  166. package/dist/core/outbox-index-codec.js +71 -0
  167. package/dist/core/outbox-internals.d.ts +99 -0
  168. package/dist/core/outbox-internals.js +159 -0
  169. package/dist/core/outbox-listing.d.ts +12 -0
  170. package/dist/core/outbox-listing.js +38 -0
  171. package/dist/core/outbox-maintenance.d.ts +28 -0
  172. package/dist/core/outbox-maintenance.js +191 -0
  173. package/dist/core/outbox-operations.d.ts +18 -0
  174. package/dist/core/outbox-operations.js +46 -0
  175. package/dist/core/outbox-runner.d.ts +30 -0
  176. package/dist/core/outbox-runner.js +217 -0
  177. package/dist/core/outbox-settlement.d.ts +57 -0
  178. package/dist/core/outbox-settlement.js +183 -0
  179. package/dist/core/outbox-storage.d.ts +107 -0
  180. package/dist/core/outbox-storage.js +127 -0
  181. package/dist/core/outbox-transition-helpers.d.ts +83 -0
  182. package/dist/core/outbox-transition-helpers.js +63 -0
  183. package/dist/core/outbox-transitions-recovery.d.ts +30 -0
  184. package/dist/core/outbox-transitions-recovery.js +42 -0
  185. package/dist/core/outbox-transitions.d.ts +145 -0
  186. package/dist/core/outbox-transitions.js +236 -0
  187. package/dist/core/outbox-types.d.ts +400 -0
  188. package/dist/core/outbox-types.js +20 -0
  189. package/dist/core/outbox-validation.d.ts +101 -0
  190. package/dist/core/outbox-validation.js +127 -0
  191. package/dist/core/outbox-waits.d.ts +39 -0
  192. package/dist/core/outbox-waits.js +88 -0
  193. package/dist/core/outbox.d.ts +156 -0
  194. package/dist/core/outbox.js +234 -0
  195. package/dist/core/registry-limits.d.ts +49 -0
  196. package/dist/core/registry-limits.js +10 -0
  197. package/dist/core/registry-schema-conversion.d.ts +20 -0
  198. package/dist/core/registry-schema-conversion.js +22 -0
  199. package/dist/core/registry-snapshot.d.ts +91 -42
  200. package/dist/core/registry-snapshot.js +39 -77
  201. package/dist/core/registry-workflow-contract-draft.d.ts +32 -0
  202. package/dist/core/registry-workflow-contract-draft.js +28 -0
  203. package/dist/core/registry-workflow-manifest.d.ts +122 -0
  204. package/dist/core/registry-workflow-manifest.js +92 -0
  205. package/dist/core/source/errors.d.ts +55 -0
  206. package/dist/core/source/errors.js +13 -0
  207. package/dist/core/source/index.d.ts +19 -0
  208. package/dist/core/source/index.js +4 -0
  209. package/dist/core/source/resolvers.d.ts +45 -0
  210. package/dist/core/source/resolvers.js +9 -0
  211. package/dist/core/source/types.d.ts +211 -0
  212. package/dist/core/source/types.js +0 -0
  213. package/dist/core/source/validate.d.ts +91 -0
  214. package/dist/core/source/validate.js +62 -0
  215. package/dist/core/source/workflow-source.d.ts +43 -0
  216. package/dist/core/source/workflow-source.js +16 -0
  217. package/dist/core/types/workflow-registries.d.ts +7 -0
  218. package/dist/core/types/workflow-registry.d.ts +12 -0
  219. package/dist/core/versioning.js +2 -0
  220. package/dist/core/weft-error.d.ts +1 -1
  221. package/dist/core/weft-error.js +9 -1
  222. package/dist/http.js +2 -2
  223. package/dist/index.d.ts +23 -2
  224. package/dist/index.js +50 -0
  225. package/dist/indexeddb.js +1 -1
  226. package/dist/json-schema.js +3 -3
  227. package/dist/mcp/resources.js +2 -0
  228. package/dist/runtime/portable.d.ts +9 -1
  229. package/dist/server/fault-to-json-rpc.js +3 -1
  230. package/dist/server/handler/auth-context-principal.js +4 -0
  231. package/dist/server/json-rpc-http.js +2 -0
  232. package/dist/server/json-rpc-websocket.js +6 -4
  233. package/dist/server/operation-catalog/index.d.ts +1 -1
  234. package/dist/server/operation-catalog/pipeline-helpers.js +2 -0
  235. package/dist/server/operation-catalog/types.d.ts +17 -0
  236. package/dist/server/operation-fault.d.ts +3 -0
  237. package/dist/server/operation-fault.js +3 -1
  238. package/dist/server/operations/activate-workflow-revision.d.ts +30 -0
  239. package/dist/server/operations/activate-workflow-revision.js +69 -0
  240. package/dist/server/operations/fleet-events-subscription.js +1 -1
  241. package/dist/server/operations/fork-workflow.js +1 -1
  242. package/dist/server/operations/get-active-workflow-revision.d.ts +32 -0
  243. package/dist/server/operations/get-active-workflow-revision.js +46 -0
  244. package/dist/server/operations/get-catalog-diagnostics.d.ts +85 -0
  245. package/dist/server/operations/get-catalog-diagnostics.js +57 -0
  246. package/dist/server/operations/get-registry.js +17 -4
  247. package/dist/server/operations/get-workflow-revision.d.ts +25 -0
  248. package/dist/server/operations/get-workflow-revision.js +50 -0
  249. package/dist/server/operations/install-workflow-revision.d.ts +27 -0
  250. package/dist/server/operations/install-workflow-revision.js +46 -0
  251. package/dist/server/operations/list-workflow-revisions.d.ts +20 -0
  252. package/dist/server/operations/list-workflow-revisions.js +40 -0
  253. package/dist/server/operations/start-or-signal-workflow.js +1 -1
  254. package/dist/server/operations/start-workflow.js +1 -1
  255. package/dist/server/operations/static-registrations.js +36 -0
  256. package/dist/server/operations/storage.js +2 -2
  257. package/dist/server/operations/submit-review-decision.js +1 -1
  258. package/dist/server/operations/workflow-catalog-operation-helpers.d.ts +59 -0
  259. package/dist/server/operations/workflow-catalog-operation-helpers.js +135 -0
  260. package/dist/server/runtime/websocket-upgrade.js +2 -0
  261. package/dist/storage/bun-sql.js +49 -6
  262. package/dist/storage/catalog-keys.d.ts +45 -0
  263. package/dist/storage/catalog-keys.js +6 -0
  264. package/dist/storage/compressed-storage.js +1 -1
  265. package/dist/storage/derived-operations.js +1 -1
  266. package/dist/storage/index.d.ts +26 -1
  267. package/dist/storage/interface.d.ts +26 -1
  268. package/dist/storage/interface.js +1 -1
  269. package/dist/storage/key-encoding.d.ts +15 -0
  270. package/dist/storage/key-encoding.js +3 -0
  271. package/dist/storage/key-prefixes.d.ts +1 -1
  272. package/dist/storage/key-prefixes.js +15 -0
  273. package/dist/storage/lmdb.d.ts +26 -1
  274. package/dist/storage/lmdb.js +1 -1
  275. package/dist/storage/mailbox-keys.d.ts +80 -0
  276. package/dist/storage/mailbox-keys.js +14 -0
  277. package/dist/storage/memory.js +1 -1
  278. package/dist/storage/neon.js +2 -2
  279. package/dist/storage/node-sqlite-loader.d.ts +1 -1
  280. package/dist/storage/node-sqlite-loader.js +2 -2
  281. package/dist/storage/node-sqlite.js +51 -8
  282. package/dist/storage/outbox-keys.d.ts +77 -0
  283. package/dist/storage/outbox-keys.js +14 -0
  284. package/dist/storage/postgres.js +2 -2
  285. package/dist/storage/resolve.js +1 -1
  286. package/dist/storage/scoped-storage.js +1 -1
  287. package/dist/storage/storage-configuration.d.ts +6 -0
  288. package/dist/storage/testing.js +1 -1
  289. package/dist/storage/turso.js +2 -2
  290. package/dist/version.d.ts +1 -1
  291. package/dist/version.js +1 -1
  292. package/dist/web-extension.js +1 -1
  293. package/dist/worker/manifest/registry-contract-builder.d.ts +21 -3
  294. package/dist/worker/manifest/registry-contract-builder.js +40 -31
  295. package/package.json +1 -1
@@ -0,0 +1,251 @@
1
+ /**
2
+ * Claim, settlement, cancellation, and maintenance result types for the durable
3
+ * application command mailbox (WFT-84).
4
+ *
5
+ * Split from `mailbox-contract.ts` only to keep both files under
6
+ * this repository's file-size ceiling; every type here is re-exported from
7
+ * there, so callers still have one import path.
8
+ *
9
+ * The same two rules shape these signatures. Expected outcomes are
10
+ * discriminated results rather than exceptions — a stale attempt token, an
11
+ * already-terminal command, and an unknown command id are all ordinary control
12
+ * flow. And no read here consumes delivery: a snapshot never claims or starts
13
+ * work.
14
+ *
15
+ * @module core/mailbox-claims
16
+ */
17
+ import type { ApplicationCommandReceipt } from './mailbox-contract.ts';
18
+ /**
19
+ * A payload handed to a claimant.
20
+ *
21
+ * For an inline payload the mailbox recomputes the digest at claim time and
22
+ * fails closed on a mismatch, so `verified` is `true`. For a reference payload
23
+ * Weft holds only the locator and the caller-supplied digest and never
24
+ * dereferences either, so `verified` is `false` and verification is the
25
+ * consumer's job.
26
+ *
27
+ * @example
28
+ * ```ts
29
+ * import type { ApplicationCommandClaimedPayload } from '@lostgradient/weft';
30
+ *
31
+ * declare const payload: ApplicationCommandClaimedPayload;
32
+ * if (payload.form === 'inline') console.log(payload.verified); // true
33
+ * ```
34
+ */
35
+ export type ApplicationCommandClaimedPayload = {
36
+ readonly form: 'inline';
37
+ readonly value: unknown;
38
+ readonly digest: string;
39
+ readonly verified: true;
40
+ } | {
41
+ readonly form: 'reference';
42
+ readonly reference: string;
43
+ readonly digest: string;
44
+ readonly byteLength?: number | undefined;
45
+ readonly verified: false;
46
+ };
47
+ /**
48
+ * An open lease on one command.
49
+ *
50
+ * `signal` aborts when cancellation is requested in this process, when the
51
+ * lease is released, or when the mailbox is disposed. It is process-local: a
52
+ * claimant in another process learns about cancellation from
53
+ * `renew()`'s `cancellationRequested` flag instead.
54
+ *
55
+ * @example
56
+ * ```ts
57
+ * import type { ApplicationCommandClaim } from '@lostgradient/weft';
58
+ *
59
+ * declare const claim: ApplicationCommandClaim;
60
+ * console.log(claim.attemptToken, claim.signal.aborted);
61
+ * ```
62
+ */
63
+ export type ApplicationCommandClaim = Readonly<{
64
+ receipt: ApplicationCommandReceipt;
65
+ payload: ApplicationCommandClaimedPayload;
66
+ /** Opaque fencing token. Every later mutation from this attempt must present it. */
67
+ attemptToken: string;
68
+ attempt: number;
69
+ visibilityExpiresAt: number;
70
+ absoluteDeadlineAt: number;
71
+ /** Attempt-scoped abort signal for an in-process claimant. */
72
+ signal: AbortSignal;
73
+ }>;
74
+ /**
75
+ * The outcome of asking for work.
76
+ *
77
+ * `held` means the FIFO head exists but is not due yet. This mailbox preserves
78
+ * strict FIFO order, so a later command never overtakes a delayed head.
79
+ *
80
+ * @example
81
+ * ```ts
82
+ * import type { MailboxClaimResult } from '@lostgradient/weft';
83
+ *
84
+ * declare const result: MailboxClaimResult;
85
+ * if (result.status === 'claimed') console.log(result.claim.attemptToken);
86
+ * ```
87
+ */
88
+ export type MailboxClaimResult = {
89
+ readonly status: 'claimed';
90
+ readonly claim: ApplicationCommandClaim;
91
+ } | {
92
+ readonly status: 'empty';
93
+ } | {
94
+ readonly status: 'held';
95
+ readonly availableAt: number;
96
+ };
97
+ /** Result of renewing a lease and reporting liveness.
98
+ *
99
+ * @example
100
+ * ```ts
101
+ * import type { ApplicationCommandRenewalResult } from '@lostgradient/weft';
102
+ *
103
+ * declare const result: ApplicationCommandRenewalResult;
104
+ * if (result.status === 'renewed' && result.cancellationRequested) console.log('wind down');
105
+ * ```
106
+ */
107
+ export type ApplicationCommandRenewalResult = {
108
+ readonly status: 'renewed';
109
+ readonly visibilityExpiresAt: number;
110
+ /** True once cancellation is durably requested — the cross-process cancellation channel. */
111
+ readonly cancellationRequested: boolean;
112
+ readonly receipt: ApplicationCommandReceipt;
113
+ } | {
114
+ readonly status: 'stale';
115
+ readonly receipt: ApplicationCommandReceipt;
116
+ } | {
117
+ /** The absolute command deadline passed; no attempt may extend or settle it. */
118
+ readonly status: 'deadline-exceeded';
119
+ readonly receipt: ApplicationCommandReceipt;
120
+ } | {
121
+ readonly status: 'unknown';
122
+ };
123
+ /**
124
+ * Result of settling a claimed command.
125
+ *
126
+ * `deadline-exceeded` is reported separately from `stale` on purpose: `stale`
127
+ * means another attempt owns the command and this one should stop, while
128
+ * `deadline-exceeded` means the command itself is over and no attempt will
129
+ * settle it. Maintenance dead-letters the record.
130
+ *
131
+ * @example
132
+ * ```ts
133
+ * import type { ApplicationCommandSettleResult } from '@lostgradient/weft';
134
+ *
135
+ * declare const result: ApplicationCommandSettleResult;
136
+ * if (result.status === 'settled') console.log(result.receipt.state);
137
+ * ```
138
+ */
139
+ export type ApplicationCommandSettleResult = {
140
+ readonly status: 'settled';
141
+ readonly receipt: ApplicationCommandReceipt;
142
+ } | {
143
+ readonly status: 'retrying';
144
+ readonly receipt: ApplicationCommandReceipt;
145
+ } | {
146
+ readonly status: 'stale';
147
+ readonly receipt: ApplicationCommandReceipt;
148
+ } | {
149
+ readonly status: 'deadline-exceeded';
150
+ readonly receipt: ApplicationCommandReceipt;
151
+ } | {
152
+ readonly status: 'unknown';
153
+ };
154
+ /**
155
+ * The outcome of requesting cancellation.
156
+ *
157
+ * The four dispositions are distinct on purpose: an unclaimed command cancels
158
+ * immediately with nothing to clean up, a claimed one records the request and
159
+ * leaves the lease alone, an already-terminal one is reported as such without
160
+ * being rewritten, and an unknown command id is never confused with any of
161
+ * those.
162
+ *
163
+ * @example
164
+ * ```ts
165
+ * import type { ApplicationCommandCancellationResult } from '@lostgradient/weft';
166
+ *
167
+ * declare const result: ApplicationCommandCancellationResult;
168
+ * if (result.status === 'requested') console.log(result.cleanupPending); // true
169
+ * ```
170
+ */
171
+ export type ApplicationCommandCancellationResult = {
172
+ readonly status: 'cancelled';
173
+ readonly receipt: ApplicationCommandReceipt;
174
+ } | {
175
+ readonly status: 'requested';
176
+ readonly receipt: ApplicationCommandReceipt;
177
+ /** Always true: an attempt still holds the command and has not settled. */
178
+ readonly cleanupPending: true;
179
+ } | {
180
+ readonly status: 'already-terminal';
181
+ readonly receipt: ApplicationCommandReceipt;
182
+ } | {
183
+ readonly status: 'unknown';
184
+ };
185
+ /**
186
+ * The bounded outcome of waiting for a cancelled command's claimant to finish.
187
+ *
188
+ * A `pending` status means the mailbox stopped waiting — never that the handler
189
+ * stopped.
190
+ *
191
+ * @example
192
+ * ```ts
193
+ * import type { ApplicationCommandCleanupResult } from '@lostgradient/weft';
194
+ *
195
+ * declare const cleanup: ApplicationCommandCleanupResult;
196
+ * console.log(cleanup.status === 'pending'); // the mailbox stopped waiting
197
+ * ```
198
+ */
199
+ export type ApplicationCommandCleanupResult = {
200
+ readonly status: 'settled';
201
+ readonly receipt: ApplicationCommandReceipt;
202
+ } | {
203
+ readonly status: 'pending';
204
+ readonly receipt: ApplicationCommandReceipt;
205
+ } | {
206
+ readonly status: 'unknown';
207
+ };
208
+ /**
209
+ * What one maintenance pass did. Counts only — deliberately low-cardinality.
210
+ *
211
+ * @example
212
+ * ```ts
213
+ * import type { MailboxMaintenanceReport } from '@lostgradient/weft';
214
+ *
215
+ * declare const report: MailboxMaintenanceReport;
216
+ * console.log(report.released, report.reclaimed, report.deadLettered);
217
+ * ```
218
+ */
219
+ export type MailboxMaintenanceReport = Readonly<{
220
+ /** `accepted` records whose `availableAt` passed and are now `available`. */
221
+ released: number;
222
+ /** Expired leases returned to the delivery index at their original FIFO position. */
223
+ reclaimed: number;
224
+ /** Commands terminalized for exhausted attempts or a passed absolute deadline. */
225
+ deadLettered: number;
226
+ /** Cancelled commands whose abandoned lease expired. */
227
+ cancelled: number;
228
+ /** Terminal receipts deleted by the retention sweep. */
229
+ retired: number;
230
+ }>;
231
+ /**
232
+ * Options for the abortable wait for new available work.
233
+ *
234
+ * `timeoutMs` defaults to `0`: with no options the wait checks once and returns
235
+ * immediately instead of blocking.
236
+ *
237
+ * @example
238
+ * ```ts
239
+ * import type { MailboxWaitOptions } from '@lostgradient/weft';
240
+ *
241
+ * const options: MailboxWaitOptions = { timeoutMs: 5_000, pollIntervalMs: 50 };
242
+ * console.log(options.timeoutMs); // 5000
243
+ * ```
244
+ */
245
+ export type MailboxWaitOptions = {
246
+ readonly signal?: AbortSignal | undefined;
247
+ /** How long to keep polling. Default `0` — one check, no wait. */
248
+ readonly timeoutMs?: number | undefined;
249
+ /** Gap between durable polls. Default 50. */
250
+ readonly pollIntervalMs?: number | undefined;
251
+ };
File without changes
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Encoding and fail-closed decoding for the durable application mailbox's
3
+ * command records (WFT-84). Index records live in
4
+ * `mailbox-index-codec.ts`; shared readers in
5
+ * `mailbox-codec-primitives.ts`.
6
+ *
7
+ * Decoding is deliberately paranoid. A mailbox record is the authority for
8
+ * delivery, fencing, and terminal disposition, so a truncated, hand-edited, or
9
+ * cross-version record must raise `PersistedDataCorruptError` rather than be
10
+ * coerced into a plausible-looking state — silently treating a corrupt record
11
+ * as `available` would redeliver work that already applied.
12
+ *
13
+ * @module core/mailbox-codec
14
+ */
15
+ import type { ApplicationCommandRecord } from './mailbox-types.ts';
16
+ import { isApplicationCommandLeased } from './mailbox-types.ts';
17
+ /**
18
+ * Decode one persisted command record, failing closed on anything unexpected.
19
+ *
20
+ * @throws {PersistedDataCorruptError} When the stored bytes are not a
21
+ * well-formed current-version command record.
22
+ */
23
+ export declare function decodeApplicationCommandRecord(bytes: Uint8Array, key: string): ApplicationCommandRecord;
24
+ /**
25
+ * Encode a command record for storage.
26
+ */
27
+ export declare function encodeApplicationCommandRecord(record: ApplicationCommandRecord): Uint8Array;
28
+ /**
29
+ * Whether a decoded record still holds an attempt lease. Re-exported here so
30
+ * storage callers need only one import.
31
+ */
32
+ export { isApplicationCommandLeased };
@@ -0,0 +1,221 @@
1
+ import { KEYS } from "../storage/interface.js";
2
+ import {
3
+ fail,
4
+ isRecordObject,
5
+ ownKey,
6
+ readIdentifier,
7
+ readInteger,
8
+ readOptionalInteger,
9
+ readOptionalString,
10
+ readPositiveInteger,
11
+ readString,
12
+ readVersion
13
+ } from "./application-primitive-codec.js";
14
+ import { decode, encode } from "./codec.js";
15
+ import { isJSONValue } from "./json.js";
16
+ import {
17
+ MAILBOX_RECORD_VERSION,
18
+ isApplicationCommandLeased,
19
+ isApplicationCommandTerminalState
20
+ } from "./mailbox-types.js";
21
+ const COMMAND_STATES = new Set([
22
+ "accepted",
23
+ "available",
24
+ "claimed",
25
+ "cancellation-requested",
26
+ "applied",
27
+ "rejected",
28
+ "cancelled",
29
+ "dead-lettered"
30
+ ]), FAILURE_REASONS = new Set([
31
+ "application",
32
+ "attempts-exhausted",
33
+ "deadline-exceeded",
34
+ "cancelled"
35
+ ]), PERSISTED_HEX_DIGEST = /^[0-9a-f]{64}$/;
36
+ function readPayloadFields(source, key) {
37
+ const payload = readPayload(source, key), payloadDigest = readString(source, "payloadDigest", key);
38
+ if (payload.form === "reference" && payload.digest !== payloadDigest)
39
+ fail(key);
40
+ return { payload, payloadDigest };
41
+ }
42
+ function readPayload(source, key) {
43
+ const payload = source.payload;
44
+ if (!isRecordObject(payload))
45
+ fail(key);
46
+ if (payload.form === "inline") {
47
+ if (!("value" in payload))
48
+ fail(key);
49
+ return { form: "inline", value: payload.value };
50
+ }
51
+ if (payload.form !== "reference")
52
+ fail(key);
53
+ const reference = readString(payload, "reference", key), digest = readString(payload, "digest", key);
54
+ if (!PERSISTED_HEX_DIGEST.test(digest))
55
+ fail(key);
56
+ const byteLength = readOptionalInteger(payload, "byteLength", key);
57
+ return byteLength === void 0 ? { form: "reference", reference, digest } : { form: "reference", reference, digest, byteLength };
58
+ }
59
+ function readCausation(source, key) {
60
+ const causation = source.causation;
61
+ if (causation === void 0)
62
+ return;
63
+ if (!isRecordObject(causation))
64
+ fail(key);
65
+ return {
66
+ correlationId: readOptionalString(causation, "correlationId", key),
67
+ causationId: readOptionalString(causation, "causationId", key),
68
+ traceparent: readOptionalString(causation, "traceparent", key)
69
+ };
70
+ }
71
+ function readFailure(source, key) {
72
+ const failure = source.failure;
73
+ if (failure === void 0)
74
+ return;
75
+ if (!isRecordObject(failure))
76
+ fail(key);
77
+ const reason = readString(failure, "reason", key);
78
+ if (!FAILURE_REASONS.has(reason))
79
+ fail(key);
80
+ return {
81
+ reason,
82
+ message: readOptionalString(failure, "message", key),
83
+ details: readOptionalJSONValue(failure, "details", key)
84
+ };
85
+ }
86
+ function readBase(source, key) {
87
+ return {
88
+ recordVersion: MAILBOX_RECORD_VERSION,
89
+ namespace: readString(source, "namespace", key),
90
+ resourceId: readString(source, "resourceId", key),
91
+ commandId: readString(source, "commandId", key),
92
+ sequence: readInteger(source, "sequence", key),
93
+ idempotencyKey: source.idempotencyKey === void 0 ? void 0 : readIdentifier(source.idempotencyKey, key),
94
+ caller: readString(source, "caller", key),
95
+ target: readString(source, "target", key),
96
+ kind: readString(source, "kind", key),
97
+ ...readPayloadFields(source, key),
98
+ payloadMediaType: readOptionalString(source, "payloadMediaType", key),
99
+ payloadSchema: readOptionalString(source, "payloadSchema", key),
100
+ causation: readCausation(source, key),
101
+ acceptedAt: readInteger(source, "acceptedAt", key),
102
+ availableAt: readInteger(source, "availableAt", key),
103
+ absoluteDeadlineAt: readInteger(source, "absoluteDeadlineAt", key),
104
+ maxAttempts: readPositiveInteger(source, "maxAttempts", key),
105
+ visibilityTimeoutMs: readPositiveInteger(source, "visibilityTimeoutMs", key),
106
+ generation: readInteger(source, "generation", key),
107
+ attempt: readInteger(source, "attempt", key),
108
+ retryCount: readInteger(source, "retryCount", key),
109
+ firstClaimedAt: readOptionalInteger(source, "firstClaimedAt", key)
110
+ };
111
+ }
112
+ function readOptionalJSONValue(source, field, key) {
113
+ const value = source[field];
114
+ if (value === void 0)
115
+ return;
116
+ if (!isJSONValue(value))
117
+ fail(key);
118
+ return value;
119
+ }
120
+ function readLeasedBase(source, key) {
121
+ const base = readBase(source, key);
122
+ if (base.attempt < 1 || base.attempt > base.maxAttempts)
123
+ fail(key);
124
+ const lease = readLease(source, key), expected = Math.min(lease.lastActivityAt + base.visibilityTimeoutMs, base.absoluteDeadlineAt);
125
+ if (lease.visibilityExpiresAt !== expected)
126
+ fail(key);
127
+ return { ...base, ...lease };
128
+ }
129
+ function readLease(source, key) {
130
+ return {
131
+ attemptToken: readString(source, "attemptToken", key),
132
+ claimedAt: readInteger(source, "claimedAt", key),
133
+ visibilityExpiresAt: readInteger(source, "visibilityExpiresAt", key),
134
+ lastActivityAt: readInteger(source, "lastActivityAt", key),
135
+ progress: readOptionalJSONValue(source, "progress", key)
136
+ };
137
+ }
138
+ function failureMatchesState(state, reason) {
139
+ switch (state) {
140
+ case "applied":
141
+ return reason === void 0;
142
+ case "rejected":
143
+ return reason === "application";
144
+ case "cancelled":
145
+ return reason === "cancelled";
146
+ default:
147
+ return reason === "attempts-exhausted" || reason === "deadline-exceeded";
148
+ }
149
+ }
150
+ function decodeTerminalRecord(decoded, key, state) {
151
+ const cleanupPending = decoded.cleanupPending;
152
+ if (cleanupPending !== void 0 && typeof cleanupPending !== "boolean")
153
+ fail(key);
154
+ const failure = readFailure(decoded, key);
155
+ if (!failureMatchesState(state, failure?.reason))
156
+ fail(key);
157
+ const abandoned = readOptionalString(decoded, "abandonedAttemptToken", key);
158
+ if (!cleanupFieldsMatchState(state, cleanupPending === !0, abandoned))
159
+ fail(key);
160
+ return {
161
+ ...readBase(decoded, key),
162
+ state,
163
+ terminalAt: readInteger(decoded, "terminalAt", key),
164
+ outcome: readOptionalJSONValue(decoded, "outcome", key),
165
+ failure,
166
+ cancellationRequestedAt: readOptionalInteger(decoded, "cancellationRequestedAt", key),
167
+ cancellationReason: readOptionalString(decoded, "cancellationReason", key),
168
+ cleanupPending,
169
+ abandonedAttemptToken: abandoned
170
+ };
171
+ }
172
+ function cleanupFieldsMatchState(state, cleanupPending, abandonedAttemptToken) {
173
+ if (cleanupPending !== (abandonedAttemptToken !== void 0))
174
+ return !1;
175
+ return !cleanupPending || state === "cancelled" || state === "dead-lettered";
176
+ }
177
+ function assertIdentityMatchesKey(decoded, key) {
178
+ const namespace = readString(decoded, "namespace", key), resourceId = readString(decoded, "resourceId", key), commandId = readString(decoded, "commandId", key);
179
+ if (ownKey(() => KEYS.applicationCommand(namespace, resourceId, commandId), key) !== key)
180
+ fail(key);
181
+ }
182
+ function readWaitingRecord(decoded, key, state) {
183
+ const base = readBase(decoded, key);
184
+ if (base.attempt >= base.maxAttempts)
185
+ fail(key);
186
+ return { ...base, state };
187
+ }
188
+ export function decodeApplicationCommandRecord(bytes, key) {
189
+ let decoded;
190
+ try {
191
+ decoded = decode(bytes);
192
+ } catch {
193
+ fail(key);
194
+ }
195
+ if (!isRecordObject(decoded))
196
+ fail(key);
197
+ readVersion(decoded, key);
198
+ assertIdentityMatchesKey(decoded, key);
199
+ const state = decoded.state;
200
+ if (typeof state !== "string" || !COMMAND_STATES.has(state))
201
+ fail(key);
202
+ if (state === "accepted" || state === "available")
203
+ return readWaitingRecord(decoded, key, state);
204
+ if (state === "claimed")
205
+ return { ...readLeasedBase(decoded, key), state };
206
+ if (state === "cancellation-requested")
207
+ return {
208
+ ...readLeasedBase(decoded, key),
209
+ state,
210
+ cancellationRequestedAt: readInteger(decoded, "cancellationRequestedAt", key),
211
+ cancellationReason: readOptionalString(decoded, "cancellationReason", key)
212
+ };
213
+ if (!isApplicationCommandTerminalState(state))
214
+ fail(key);
215
+ return decodeTerminalRecord(decoded, key, state);
216
+ }
217
+ export function encodeApplicationCommandRecord(record) {
218
+ return encode(record);
219
+ }
220
+
221
+ export { isApplicationCommandLeased };