@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,307 @@
1
+ /**
2
+ * Claim, settlement, cancellation, operator, maintenance, wait, and drain
3
+ * result types for the durable application delivery outbox (WFT-85).
4
+ *
5
+ * Split from `outbox-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
+ * @module core/outbox-claims
10
+ */
11
+ import type { ApplicationDeliveryReceipt, OutboxCapacity } from './outbox-contract.ts';
12
+ /**
13
+ * A payload handed to a claimant: digest-verified when inline, unverified when
14
+ * a reference Weft never dereferences.
15
+ *
16
+ * @example
17
+ * ```ts
18
+ * import type { ApplicationDeliveryClaimedPayload } from '@lostgradient/weft';
19
+ *
20
+ * declare const payload: ApplicationDeliveryClaimedPayload;
21
+ * if (payload.form === 'inline') console.log(payload.verified); // true
22
+ * ```
23
+ */
24
+ export type ApplicationDeliveryClaimedPayload = {
25
+ readonly form: 'inline';
26
+ readonly value: unknown;
27
+ readonly digest: string;
28
+ readonly verified: true;
29
+ } | {
30
+ readonly form: 'reference';
31
+ readonly reference: string;
32
+ readonly digest: string;
33
+ readonly byteLength?: number | undefined;
34
+ readonly verified: false;
35
+ };
36
+ /**
37
+ * An open lease on one delivery.
38
+ *
39
+ * `signal` aborts when cancellation is requested in this process, when the
40
+ * attempt is released or refused, and when the outbox is disposed. It is
41
+ * process-local. The attempt deadline does not arm a timer on it: a host that
42
+ * drives claims itself learns the deadline has passed from `heartbeat()` or
43
+ * `settle()` returning `deadline-exceeded`, and `deliverNext()` stops waiting
44
+ * for the adapter at the deadline and aborts the signal as it releases the
45
+ * attempt.
46
+ *
47
+ * @example
48
+ * ```ts
49
+ * import type { ApplicationDeliveryClaim } from '@lostgradient/weft';
50
+ *
51
+ * declare const claim: ApplicationDeliveryClaim;
52
+ * console.log(claim.attemptToken, claim.signal.aborted);
53
+ * ```
54
+ */
55
+ export type ApplicationDeliveryClaim = Readonly<{
56
+ receipt: ApplicationDeliveryReceipt;
57
+ payload: ApplicationDeliveryClaimedPayload;
58
+ /** Present only to the claimant; never on a receipt. */
59
+ credentialRef?: string | undefined;
60
+ attemptToken: string;
61
+ attempt: number;
62
+ visibilityExpiresAt: number;
63
+ attemptDeadlineAt: number;
64
+ signal: AbortSignal;
65
+ }>;
66
+ /**
67
+ * The outcome of asking for work. `held` means deliveries exist but none is
68
+ * due yet; `availableAt` is the earliest.
69
+ *
70
+ * @example
71
+ * ```ts
72
+ * import type { OutboxClaimResult } from '@lostgradient/weft';
73
+ *
74
+ * declare const result: OutboxClaimResult;
75
+ * if (result.status === 'claimed') console.log(result.claim.attemptToken);
76
+ * ```
77
+ */
78
+ export type OutboxClaimResult = {
79
+ readonly status: 'claimed';
80
+ readonly claim: ApplicationDeliveryClaim;
81
+ } | {
82
+ readonly status: 'empty';
83
+ } | {
84
+ readonly status: 'held';
85
+ readonly availableAt: number;
86
+ };
87
+ /**
88
+ * Result of a heartbeat: liveness recorded and visibility extended, clamped to
89
+ * the fixed attempt deadline.
90
+ *
91
+ * @example
92
+ * ```ts
93
+ * import type { ApplicationDeliveryHeartbeatResult } from '@lostgradient/weft';
94
+ *
95
+ * declare const result: ApplicationDeliveryHeartbeatResult;
96
+ * if (result.status === 'renewed' && result.cancellationRequested) console.log('stop sending');
97
+ * ```
98
+ */
99
+ export type ApplicationDeliveryHeartbeatResult = {
100
+ readonly status: 'renewed';
101
+ readonly visibilityExpiresAt: number;
102
+ readonly attemptDeadlineAt: number;
103
+ readonly cancellationRequested: boolean;
104
+ readonly receipt: ApplicationDeliveryReceipt;
105
+ } | {
106
+ readonly status: 'stale';
107
+ readonly receipt: ApplicationDeliveryReceipt;
108
+ } | {
109
+ readonly status: 'deadline-exceeded';
110
+ readonly receipt: ApplicationDeliveryReceipt;
111
+ } | {
112
+ readonly status: 'unknown';
113
+ };
114
+ /**
115
+ * Result of marking an attempt as begun, or of settling it.
116
+ *
117
+ * `deadline-exceeded` is distinct from `stale`: the attempt itself is over and
118
+ * maintenance recovers the delivery, while `stale` means another attempt owns
119
+ * it.
120
+ *
121
+ * @example
122
+ * ```ts
123
+ * import type { ApplicationDeliverySettleResult } from '@lostgradient/weft';
124
+ *
125
+ * declare const result: ApplicationDeliverySettleResult;
126
+ * if (result.status === 'settled') console.log(result.receipt.state);
127
+ * ```
128
+ */
129
+ export type ApplicationDeliverySettleResult = {
130
+ readonly status: 'settled';
131
+ readonly receipt: ApplicationDeliveryReceipt;
132
+ } | {
133
+ readonly status: 'retrying';
134
+ readonly receipt: ApplicationDeliveryReceipt;
135
+ } | {
136
+ readonly status: 'stale';
137
+ readonly receipt: ApplicationDeliveryReceipt;
138
+ } | {
139
+ readonly status: 'deadline-exceeded';
140
+ readonly receipt: ApplicationDeliveryReceipt;
141
+ } | {
142
+ readonly status: 'unknown';
143
+ };
144
+ /**
145
+ * Result of `deliverNext()`: one delivery run through the adapter and settled,
146
+ * or nothing to do.
147
+ *
148
+ * @example
149
+ * ```ts
150
+ * import type { OutboxDeliverResult } from '@lostgradient/weft';
151
+ *
152
+ * declare const result: OutboxDeliverResult;
153
+ * if (result.status === 'settled') console.log(result.receipt.state);
154
+ * ```
155
+ */
156
+ export type OutboxDeliverResult = {
157
+ readonly status: 'settled';
158
+ readonly receipt: ApplicationDeliveryReceipt;
159
+ /**
160
+ * Whether this call committed the receipt's disposition. `false` when
161
+ * another actor moved the delivery first (a cancellation or recovery that
162
+ * refused this runner's begin or settlement), when the caller aborted
163
+ * before the send began, or when the outbox was disposed mid-send and the
164
+ * lease was left for maintenance; the receipt is then the current durable
165
+ * state, not this runner's work.
166
+ */
167
+ readonly committed: boolean;
168
+ } | {
169
+ readonly status: 'empty';
170
+ } | {
171
+ readonly status: 'held';
172
+ readonly availableAt: number;
173
+ };
174
+ /**
175
+ * The outcome of requesting cancellation.
176
+ *
177
+ * @example
178
+ * ```ts
179
+ * import type { ApplicationDeliveryCancellationResult } from '@lostgradient/weft';
180
+ *
181
+ * declare const result: ApplicationDeliveryCancellationResult;
182
+ * if (result.status === 'requested') console.log(result.cleanupPending); // true
183
+ * ```
184
+ */
185
+ export type ApplicationDeliveryCancellationResult = {
186
+ readonly status: 'cancelled';
187
+ readonly receipt: ApplicationDeliveryReceipt;
188
+ } | {
189
+ readonly status: 'requested';
190
+ readonly receipt: ApplicationDeliveryReceipt;
191
+ readonly cleanupPending: true;
192
+ } | {
193
+ readonly status: 'already-terminal';
194
+ readonly receipt: ApplicationDeliveryReceipt;
195
+ } | {
196
+ readonly status: 'unknown';
197
+ };
198
+ /**
199
+ * The bounded outcome of waiting for a cancelled delivery's attempt to settle.
200
+ *
201
+ * @example
202
+ * ```ts
203
+ * import type { ApplicationDeliveryCleanupResult } from '@lostgradient/weft';
204
+ *
205
+ * declare const cleanup: ApplicationDeliveryCleanupResult;
206
+ * console.log(cleanup.status === 'pending'); // the outbox stopped waiting
207
+ * ```
208
+ */
209
+ export type ApplicationDeliveryCleanupResult = {
210
+ readonly status: 'settled';
211
+ readonly receipt: ApplicationDeliveryReceipt;
212
+ } | {
213
+ readonly status: 'pending';
214
+ readonly receipt: ApplicationDeliveryReceipt;
215
+ } | {
216
+ readonly status: 'unknown';
217
+ };
218
+ /**
219
+ * The outcome of an operator `retry()` or `deadLetter()`.
220
+ *
221
+ * @example
222
+ * ```ts
223
+ * import type { ApplicationDeliveryOperatorResult } from '@lostgradient/weft';
224
+ *
225
+ * declare const result: ApplicationDeliveryOperatorResult;
226
+ * if (result.status === 'applied') console.log(result.receipt.state);
227
+ * ```
228
+ */
229
+ export type ApplicationDeliveryOperatorResult = {
230
+ readonly status: 'applied';
231
+ readonly receipt: ApplicationDeliveryReceipt;
232
+ } | {
233
+ readonly status: 'not-applicable';
234
+ readonly receipt: ApplicationDeliveryReceipt;
235
+ } | {
236
+ /** Reopening would exceed `maxBacklog`; nothing was written. */
237
+ readonly status: 'rejected';
238
+ readonly reason: 'backlog-full';
239
+ readonly capacity: OutboxCapacity;
240
+ } | {
241
+ readonly status: 'unknown';
242
+ };
243
+ /**
244
+ * What one maintenance pass did. Counts only.
245
+ *
246
+ * @example
247
+ * ```ts
248
+ * import type { OutboxMaintenanceReport } from '@lostgradient/weft';
249
+ *
250
+ * declare const report: OutboxMaintenanceReport;
251
+ * console.log(report.rescheduled, report.parked, report.retired);
252
+ * ```
253
+ */
254
+ export type OutboxMaintenanceReport = Readonly<{
255
+ /** Expired `claimed` leases returned to the due index. */
256
+ rescheduled: number;
257
+ /** Expired `attempting` leases parked as `unknown-outcome`. */
258
+ parked: number;
259
+ /** Deliveries terminalized as `dead-lettered`. */
260
+ deadLettered: number;
261
+ /** Terminal receipts deleted by the retention sweep. */
262
+ retired: number;
263
+ }>;
264
+ /** Options for the abortable wait for due work. `timeoutMs` defaults to `0`.
265
+ *
266
+ * @example
267
+ * ```ts
268
+ * import type { OutboxWaitOptions } from '@lostgradient/weft';
269
+ *
270
+ * const options: OutboxWaitOptions = { timeoutMs: 5_000 };
271
+ * console.log(options.timeoutMs); // 5000
272
+ * ```
273
+ */
274
+ export type OutboxWaitOptions = {
275
+ readonly signal?: AbortSignal | undefined;
276
+ readonly timeoutMs?: number | undefined;
277
+ readonly pollIntervalMs?: number | undefined;
278
+ };
279
+ /**
280
+ * What a bounded drain did. `pending` is what remained open when the drain
281
+ * stopped; every other count is a durable disposition the drain committed.
282
+ *
283
+ * @example
284
+ * ```ts
285
+ * import type { OutboxDrainReport } from '@lostgradient/weft';
286
+ *
287
+ * declare const report: OutboxDrainReport;
288
+ * console.log(report.acknowledged, report.pending);
289
+ * ```
290
+ */
291
+ export type OutboxDrainReport = Readonly<{
292
+ acknowledged: number;
293
+ rejected: number;
294
+ retryScheduled: number;
295
+ deadLettered: number;
296
+ cancelled: number;
297
+ unknown: number;
298
+ /**
299
+ * Deliveries still open when the drain stopped, as durable storage last
300
+ * reported it, kept current with the dispositions this drain committed.
301
+ * `null` when the drain stopped before storage ever answered its first
302
+ * header read: nothing was observed, so nothing is claimed.
303
+ */
304
+ pending: number | null;
305
+ /** Whether the drain stopped because nothing was left to do, rather than budget or abort. */
306
+ drained: boolean;
307
+ }>;
File without changes
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Encoding and fail-closed decoding for the durable application outbox's
3
+ * delivery records (WFT-85). Index records live in
4
+ * `outbox-index-codec.ts`.
5
+ *
6
+ * Decoding is deliberately paranoid, as the mailbox's is. A delivery record is
7
+ * the authority for fencing, disposition, and whether an effect may already
8
+ * have happened, so a truncated, hand-edited, or cross-version record must
9
+ * raise `PersistedDataCorruptError` rather than be coerced into a plausible
10
+ * state — silently treating a corrupt record as `queued` would resend work
11
+ * that already reached its destination.
12
+ *
13
+ * @module core/outbox-codec
14
+ */
15
+ import type { ApplicationDeliveryRecord } from './outbox-types.ts';
16
+ /**
17
+ * Decode one persisted delivery record, failing closed on anything unexpected.
18
+ *
19
+ * @throws {PersistedDataCorruptError} When the stored bytes are not a
20
+ * well-formed current-version delivery record.
21
+ */
22
+ export declare function decodeApplicationDeliveryRecord(bytes: Uint8Array, key: string): ApplicationDeliveryRecord;
23
+ /** Encode a delivery record for storage. */
24
+ export declare function encodeApplicationDeliveryRecord(record: ApplicationDeliveryRecord): Uint8Array;
@@ -0,0 +1,257 @@
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 { OUTBOX_RECORD_VERSION, isApplicationDeliveryTerminalState } from "./outbox-types.js";
17
+ const DELIVERY_STATES = new Set([
18
+ "queued",
19
+ "retry-scheduled",
20
+ "claimed",
21
+ "attempting",
22
+ "cancellation-requested",
23
+ "acknowledged",
24
+ "rejected",
25
+ "cancelled",
26
+ "unknown-outcome",
27
+ "dead-lettered"
28
+ ]), FAILURE_REASONS = new Set([
29
+ "application",
30
+ "retryable",
31
+ "attempts-exhausted",
32
+ "unknown-outcome",
33
+ "cancelled"
34
+ ]), POLICIES = new Set([
35
+ "park",
36
+ "dead-letter",
37
+ "retry-with-idempotency"
38
+ ]), PERSISTED_HEX_DIGEST = /^[0-9a-f]{64}$/;
39
+ function readPayloadFields(source, key) {
40
+ const payload = readPayload(source, key), payloadDigest = readString(source, "payloadDigest", key);
41
+ if (payload.form === "reference" && payload.digest !== payloadDigest)
42
+ fail(key);
43
+ return { payload, payloadDigest };
44
+ }
45
+ function readPayload(source, key) {
46
+ const payload = source.payload;
47
+ if (!isRecordObject(payload))
48
+ fail(key);
49
+ if (payload.form === "inline") {
50
+ if (!("value" in payload))
51
+ fail(key);
52
+ return { form: "inline", value: payload.value };
53
+ }
54
+ if (payload.form !== "reference")
55
+ fail(key);
56
+ const reference = readString(payload, "reference", key), digest = readString(payload, "digest", key);
57
+ if (!PERSISTED_HEX_DIGEST.test(digest))
58
+ fail(key);
59
+ const byteLength = readOptionalInteger(payload, "byteLength", key);
60
+ return byteLength === void 0 ? { form: "reference", reference, digest } : { form: "reference", reference, digest, byteLength };
61
+ }
62
+ function readCausation(source, key) {
63
+ const causation = source.causation;
64
+ if (causation === void 0)
65
+ return;
66
+ if (!isRecordObject(causation))
67
+ fail(key);
68
+ return {
69
+ correlationId: readOptionalString(causation, "correlationId", key),
70
+ causationId: readOptionalString(causation, "causationId", key),
71
+ traceparent: readOptionalString(causation, "traceparent", key)
72
+ };
73
+ }
74
+ function readFailure(source, field, key) {
75
+ const failure = source[field];
76
+ if (failure === void 0)
77
+ return;
78
+ if (!isRecordObject(failure))
79
+ fail(key);
80
+ const reason = readString(failure, "reason", key);
81
+ if (!FAILURE_REASONS.has(reason))
82
+ fail(key);
83
+ return {
84
+ reason,
85
+ message: readOptionalString(failure, "message", key),
86
+ details: readOptionalJSONValue(failure, "details", key)
87
+ };
88
+ }
89
+ function readPolicy(source, key) {
90
+ const policy = readString(source, "unknownOutcomePolicy", key);
91
+ if (!POLICIES.has(policy))
92
+ fail(key);
93
+ return policy;
94
+ }
95
+ function readOptionalIdentifier(source, field, key) {
96
+ return source[field] === void 0 ? void 0 : readIdentifier(source[field], key);
97
+ }
98
+ function readBase(source, key) {
99
+ const externalIdempotencyKey = readOptionalIdentifier(source, "externalIdempotencyKey", key), unknownOutcomePolicy = readPolicy(source, key);
100
+ if (unknownOutcomePolicy === "retry-with-idempotency" && externalIdempotencyKey === void 0)
101
+ fail(key);
102
+ return {
103
+ recordVersion: OUTBOX_RECORD_VERSION,
104
+ namespace: readString(source, "namespace", key),
105
+ ownerId: readString(source, "ownerId", key),
106
+ deliveryId: readString(source, "deliveryId", key),
107
+ sequence: readInteger(source, "sequence", key),
108
+ idempotencyKey: readOptionalIdentifier(source, "idempotencyKey", key),
109
+ destinationRef: readString(source, "destinationRef", key),
110
+ credentialRef: readOptionalString(source, "credentialRef", key),
111
+ kind: readString(source, "kind", key),
112
+ ...readPayloadFields(source, key),
113
+ payloadMediaType: readOptionalString(source, "payloadMediaType", key),
114
+ payloadSchema: readOptionalString(source, "payloadSchema", key),
115
+ causation: readCausation(source, key),
116
+ externalIdempotencyKey,
117
+ unknownOutcomePolicy,
118
+ enqueuedAt: readInteger(source, "enqueuedAt", key),
119
+ availableAt: readInteger(source, "availableAt", key),
120
+ maxAttempts: readPositiveInteger(source, "maxAttempts", key),
121
+ visibilityTimeoutMs: readPositiveInteger(source, "visibilityTimeoutMs", key),
122
+ attemptTimeoutMs: readPositiveInteger(source, "attemptTimeoutMs", key),
123
+ generation: readInteger(source, "generation", key),
124
+ attempt: readInteger(source, "attempt", key),
125
+ retryCount: readInteger(source, "retryCount", key),
126
+ firstClaimedAt: readOptionalInteger(source, "firstClaimedAt", key)
127
+ };
128
+ }
129
+ function readOptionalJSONValue(source, field, key) {
130
+ const value = source[field];
131
+ if (value === void 0)
132
+ return;
133
+ if (!isJSONValue(value))
134
+ fail(key);
135
+ return value;
136
+ }
137
+ function readLeasedBase(source, key) {
138
+ const base = readBase(source, key);
139
+ if (base.attempt < 1 || base.attempt > base.maxAttempts)
140
+ fail(key);
141
+ const lease = {
142
+ attemptToken: readString(source, "attemptToken", key),
143
+ claimedAt: readInteger(source, "claimedAt", key),
144
+ visibilityExpiresAt: readInteger(source, "visibilityExpiresAt", key),
145
+ attemptDeadlineAt: readInteger(source, "attemptDeadlineAt", key),
146
+ lastActivityAt: readInteger(source, "lastActivityAt", key),
147
+ transportActivity: readOptionalJSONValue(source, "transportActivity", key)
148
+ };
149
+ if (lease.attemptDeadlineAt !== lease.claimedAt + base.attemptTimeoutMs)
150
+ fail(key);
151
+ const expected = Math.min(lease.lastActivityAt + base.visibilityTimeoutMs, lease.attemptDeadlineAt);
152
+ if (lease.visibilityExpiresAt !== expected)
153
+ fail(key);
154
+ return { ...base, ...lease };
155
+ }
156
+ function failureMatchesState(state, reason) {
157
+ switch (state) {
158
+ case "acknowledged":
159
+ return reason === void 0;
160
+ case "rejected":
161
+ return reason === "application";
162
+ case "cancelled":
163
+ return reason === "cancelled";
164
+ case "unknown-outcome":
165
+ return reason === "unknown-outcome";
166
+ default:
167
+ return reason === "attempts-exhausted" || reason === "unknown-outcome";
168
+ }
169
+ }
170
+ function cleanupFieldsMatchState(state, cleanupPending, abandonedAttemptToken) {
171
+ if (cleanupPending !== (abandonedAttemptToken !== void 0))
172
+ return !1;
173
+ return !cleanupPending || state === "unknown-outcome" || state === "dead-lettered";
174
+ }
175
+ function decodeTerminalRecord(decoded, key, state) {
176
+ const cleanupPending = decoded.cleanupPending;
177
+ if (cleanupPending !== void 0 && typeof cleanupPending !== "boolean")
178
+ fail(key);
179
+ const failure = readFailure(decoded, "failure", key);
180
+ if (!failureMatchesState(state, failure?.reason))
181
+ fail(key);
182
+ const abandoned = readOptionalString(decoded, "abandonedAttemptToken", key);
183
+ if (!cleanupFieldsMatchState(state, cleanupPending === !0, abandoned))
184
+ fail(key);
185
+ return {
186
+ ...readBase(decoded, key),
187
+ state,
188
+ terminalAt: readInteger(decoded, "terminalAt", key),
189
+ evidence: readOptionalJSONValue(decoded, "evidence", key),
190
+ failure,
191
+ cancellationRequestedAt: readOptionalInteger(decoded, "cancellationRequestedAt", key),
192
+ cancellationReason: readOptionalString(decoded, "cancellationReason", key),
193
+ cleanupPending,
194
+ abandonedAttemptToken: abandoned
195
+ };
196
+ }
197
+ function assertIdentityMatchesKey(decoded, key) {
198
+ const namespace = readString(decoded, "namespace", key), ownerId = readString(decoded, "ownerId", key), deliveryId = readString(decoded, "deliveryId", key);
199
+ if (ownKey(() => KEYS.applicationDelivery(namespace, ownerId, deliveryId), key) !== key)
200
+ fail(key);
201
+ }
202
+ function readWaitingRecord(decoded, key, state) {
203
+ const base = readBase(decoded, key);
204
+ if (base.attempt >= base.maxAttempts)
205
+ fail(key);
206
+ if (state === "queued")
207
+ return { ...base, state };
208
+ const lastFailure = readFailure(decoded, "lastFailure", key);
209
+ if (lastFailure === void 0 || lastFailure.reason !== "retryable" && lastFailure.reason !== "unknown-outcome")
210
+ fail(key);
211
+ return { ...base, state, lastFailure };
212
+ }
213
+ function readEnvelope(bytes, key) {
214
+ let decoded;
215
+ try {
216
+ decoded = decode(bytes);
217
+ } catch {
218
+ fail(key);
219
+ }
220
+ if (!isRecordObject(decoded))
221
+ fail(key);
222
+ readVersion(decoded, key, OUTBOX_RECORD_VERSION);
223
+ return decoded;
224
+ }
225
+ export function decodeApplicationDeliveryRecord(bytes, key) {
226
+ const decoded = readEnvelope(bytes, key);
227
+ assertIdentityMatchesKey(decoded, key);
228
+ const state = decoded.state;
229
+ if (!isDeliveryState(state))
230
+ fail(key);
231
+ if (state === "queued" || state === "retry-scheduled")
232
+ return readWaitingRecord(decoded, key, state);
233
+ if (isApplicationDeliveryTerminalState(state))
234
+ return decodeTerminalRecord(decoded, key, state);
235
+ return decodeLeasedRecord(decoded, key, state);
236
+ }
237
+ function isDeliveryState(state) {
238
+ return typeof state === "string" && DELIVERY_STATES.has(state);
239
+ }
240
+ function decodeLeasedRecord(decoded, key, state) {
241
+ const base = readLeasedBase(decoded, key);
242
+ if (state === "claimed")
243
+ return { ...base, state };
244
+ const attemptStartedAt = readInteger(decoded, "attemptStartedAt", key);
245
+ if (state === "attempting")
246
+ return { ...base, state, attemptStartedAt };
247
+ return {
248
+ ...base,
249
+ state,
250
+ attemptStartedAt,
251
+ cancellationRequestedAt: readInteger(decoded, "cancellationRequestedAt", key),
252
+ cancellationReason: readOptionalString(decoded, "cancellationReason", key)
253
+ };
254
+ }
255
+ export function encodeApplicationDeliveryRecord(record) {
256
+ return encode(record);
257
+ }