@lostgradient/weft 0.23.1 → 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 (294) 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.js +49 -6
  281. package/dist/storage/outbox-keys.d.ts +77 -0
  282. package/dist/storage/outbox-keys.js +14 -0
  283. package/dist/storage/postgres.js +2 -2
  284. package/dist/storage/resolve.js +1 -1
  285. package/dist/storage/scoped-storage.js +1 -1
  286. package/dist/storage/storage-configuration.d.ts +6 -0
  287. package/dist/storage/testing.js +1 -1
  288. package/dist/storage/turso.js +2 -2
  289. package/dist/version.d.ts +1 -1
  290. package/dist/version.js +1 -1
  291. package/dist/web-extension.js +1 -1
  292. package/dist/worker/manifest/registry-contract-builder.d.ts +21 -3
  293. package/dist/worker/manifest/registry-contract-builder.js +40 -31
  294. package/package.json +1 -1
@@ -0,0 +1,127 @@
1
+ import { encodeStorageKeyComponent, KEYS } from "../storage/interface.js";
2
+ import {
3
+ commitApplicationTransition
4
+ } from "./application-primitive-commit.js";
5
+ import {
6
+ decodeApplicationDeliveryRecord,
7
+ encodeApplicationDeliveryRecord
8
+ } from "./outbox-codec.js";
9
+ import {
10
+ decodeApplicationDeliveryEntry,
11
+ decodeApplicationDeliveryIdempotencyRecord,
12
+ decodeOutboxRecord,
13
+ encodeApplicationDeliveryEntry,
14
+ encodeOutboxRecord
15
+ } from "./outbox-index-codec.js";
16
+ import {
17
+ isApplicationDeliveryTerminalState,
18
+ isApplicationDeliveryWaiting,
19
+ OUTBOX_RECORD_VERSION
20
+ } from "./outbox-types.js";
21
+ import { PersistedDataCorruptError } from "./persisted-data-incompatible-error.js";
22
+ export function createOutboxKeys(namespace, ownerId) {
23
+ return {
24
+ header: KEYS.applicationOutbox(namespace, ownerId),
25
+ sinkProbe: (nonce) => KEYS.applicationOutboxSinkProbe(namespace, ownerId, nonce),
26
+ deliveryPrefix: KEYS.applicationDeliveryPrefix(namespace, ownerId),
27
+ delivery: (deliveryId) => KEYS.applicationDelivery(namespace, ownerId, deliveryId),
28
+ duePrefix: KEYS.applicationDeliveryDuePrefix(namespace, ownerId),
29
+ due: (availableAt, deliveryId) => KEYS.applicationDeliveryDue(namespace, ownerId, availableAt, deliveryId),
30
+ bySequencePrefix: KEYS.applicationDeliveryBySequencePrefix(namespace, ownerId),
31
+ bySequence: (sequence) => KEYS.applicationDeliveryBySequence(namespace, ownerId, sequence),
32
+ idempotency: (key) => KEYS.applicationDeliveryIdempotency(namespace, ownerId, key),
33
+ terminalPrefix: KEYS.applicationDeliveryTerminalPrefix(namespace, ownerId),
34
+ terminal: (terminalAt, deliveryId) => KEYS.applicationDeliveryTerminal(namespace, ownerId, terminalAt, deliveryId)
35
+ };
36
+ }
37
+ export function emptyOutboxRecord(namespace, ownerId) {
38
+ return {
39
+ recordVersion: OUTBOX_RECORD_VERSION,
40
+ namespace,
41
+ ownerId,
42
+ nextSequence: 0,
43
+ openCount: 0,
44
+ enqueuedCount: 0
45
+ };
46
+ }
47
+ export async function loadOutboxHeader(storage, keys, namespace, ownerId) {
48
+ const bytes = await storage.get(keys.header);
49
+ if (bytes === null)
50
+ return { record: emptyOutboxRecord(namespace, ownerId), bytes: null };
51
+ return { record: decodeOutboxRecord(bytes, keys.header), bytes };
52
+ }
53
+ export async function loadDelivery(storage, keys, deliveryId) {
54
+ const key = keys.delivery(deliveryId), bytes = await storage.get(key);
55
+ if (bytes === null)
56
+ return null;
57
+ return { record: decodeApplicationDeliveryRecord(bytes, key), bytes };
58
+ }
59
+ export async function loadDeliveryIdempotencyBinding(storage, keys, idempotencyKey) {
60
+ const key = keys.idempotency(idempotencyKey), bytes = await storage.get(key);
61
+ if (bytes === null)
62
+ return null;
63
+ return { record: decodeApplicationDeliveryIdempotencyRecord(bytes, key), bytes };
64
+ }
65
+ export async function loadDueHead(storage, keys, limit) {
66
+ const entries = [];
67
+ for await (const [key, value] of storage.scan(keys.duePrefix, { limit })) {
68
+ const deliveryId = decodeApplicationDeliveryEntry(value, key);
69
+ if (!key.endsWith(`:${encodeStorageKeyComponent(deliveryId)}`))
70
+ throw new PersistedDataCorruptError(key);
71
+ entries.push({ key, bytes: value, deliveryId });
72
+ }
73
+ return entries;
74
+ }
75
+ export function indexOperationsFor(keys, previous, next) {
76
+ return [
77
+ ...dueIndexOperations(keys, previous, next),
78
+ ...terminalIndexOperations(keys, previous, next)
79
+ ];
80
+ }
81
+ function moveIndexEntry(before, after, deliveryId) {
82
+ if (before === after)
83
+ return [];
84
+ const operations = [];
85
+ if (before !== null)
86
+ operations.push({ type: "delete", key: before });
87
+ if (after !== null)
88
+ operations.push({ type: "put", key: after, value: encodeApplicationDeliveryEntry(deliveryId) });
89
+ return operations;
90
+ }
91
+ function dueIndexOperations(keys, previous, next) {
92
+ const before = previous !== null && isApplicationDeliveryWaiting(previous) ? keys.due(previous.availableAt, previous.deliveryId) : null, after = isApplicationDeliveryWaiting(next) ? keys.due(next.availableAt, next.deliveryId) : null;
93
+ return moveIndexEntry(before, after, next.deliveryId);
94
+ }
95
+ function terminalIndexOperations(keys, previous, next) {
96
+ const before = previous !== null && isTerminalRecord(previous) ? keys.terminal(previous.terminalAt, previous.deliveryId) : null, after = isTerminalRecord(next) ? keys.terminal(next.terminalAt, next.deliveryId) : null;
97
+ return moveIndexEntry(before, after, next.deliveryId);
98
+ }
99
+ function isTerminalRecord(record) {
100
+ return isApplicationDeliveryTerminalState(record.state);
101
+ }
102
+ export function commitOutboxTransition(storage, events, plan) {
103
+ return commitApplicationTransition(storage, events, plan, "application outbox");
104
+ }
105
+ export function planDeliveryTransition(keys, options) {
106
+ return {
107
+ sinkProbeKey: keys.sinkProbe(crypto.randomUUID()),
108
+ conditions: [
109
+ { key: keys.delivery(options.next.deliveryId), expectedValue: options.expectedBytes },
110
+ ...options.extraConditions ?? []
111
+ ],
112
+ operations: [
113
+ {
114
+ type: "put",
115
+ key: keys.delivery(options.next.deliveryId),
116
+ value: encodeApplicationDeliveryRecord(options.next)
117
+ },
118
+ ...indexOperationsFor(keys, options.previous, options.next),
119
+ ...options.extraOperations ?? []
120
+ ],
121
+ event: options.event,
122
+ now: options.now
123
+ };
124
+ }
125
+ export function headerOperation(keys, record) {
126
+ return { type: "put", key: keys.header, value: encodeOutboxRecord(record) };
127
+ }
@@ -0,0 +1,83 @@
1
+ /**
2
+ * The primitives every outbox transition shares (WFT-85): the
3
+ * rejection vocabulary, the transition result shape, non-terminal narrowing,
4
+ * identity-field carry-over, and retry scheduling.
5
+ *
6
+ * Extracted so `outbox-transitions.ts` and
7
+ * `outbox-transitions-recovery.ts` can both use them without
8
+ * importing each other.
9
+ *
10
+ * @module core/outbox-transition-helpers
11
+ */
12
+ import { computeRetryBackoffMs } from './application-primitive-timing.ts';
13
+ import type { ApplicationDeliveryFailure, ApplicationDeliveryLeasedRecord, ApplicationDeliveryRecord, ApplicationDeliveryRetryScheduled, ApplicationDeliveryTerminalRecord, ApplicationDeliveryWaitingRecord } from './outbox-types.ts';
14
+ export { computeRetryBackoffMs };
15
+ /**
16
+ * Why a proposed transition is illegal. Stable and low-cardinality, so callers
17
+ * can map each reason onto a discriminated result without string matching.
18
+ */
19
+ export type OutboxTransitionRejection = 'stale-attempt' | 'not-leased' | 'not-waiting' | 'not-due' | 'not-attempting' | 'deadline-exceeded' | 'already-terminal' | 'cancellation-requested' | 'not-applicable';
20
+ /** The outcome of a proposed transition: the record to persist, or why the edge is illegal. */
21
+ export type OutboxTransition<TNext> = {
22
+ readonly ok: true;
23
+ readonly next: TNext;
24
+ } | {
25
+ readonly ok: false;
26
+ readonly reason: OutboxTransitionRejection;
27
+ };
28
+ export declare function rejectedTransition<TNext>(reason: OutboxTransitionRejection): OutboxTransition<TNext>;
29
+ export declare function succeededTransition<TNext>(next: TNext): OutboxTransition<TNext>;
30
+ /** Narrow a record to a terminal disposition. */
31
+ export declare function isTerminalDeliveryRecord(record: ApplicationDeliveryRecord): record is ApplicationDeliveryTerminalRecord;
32
+ /** Narrow a record to the five non-terminal states, or `null`. */
33
+ export declare function nonTerminalDeliveryRecord(record: ApplicationDeliveryRecord): ApplicationDeliveryWaitingRecord | ApplicationDeliveryLeasedRecord | null;
34
+ /** Strip the state-specific fields so a transition rebuilds a record from identity alone. */
35
+ export declare function applicationDeliveryIdentityFields(record: ApplicationDeliveryRecord): {
36
+ readonly recordVersion: 1;
37
+ readonly namespace: string;
38
+ readonly ownerId: string;
39
+ readonly deliveryId: string;
40
+ readonly sequence: number;
41
+ readonly idempotencyKey: string | undefined;
42
+ readonly destinationRef: string;
43
+ readonly credentialRef: string | undefined;
44
+ readonly kind: string;
45
+ readonly payload: import("./mailbox-types.ts").ApplicationCommandPayload;
46
+ readonly payloadDigest: string;
47
+ readonly payloadMediaType: string | undefined;
48
+ readonly payloadSchema: string | undefined;
49
+ readonly causation: Readonly<{
50
+ correlationId?: string | undefined;
51
+ causationId?: string | undefined;
52
+ traceparent?: string | undefined;
53
+ }> | undefined;
54
+ readonly externalIdempotencyKey: string | undefined;
55
+ readonly unknownOutcomePolicy: import("./outbox-types.ts").ApplicationDeliveryUnknownOutcomePolicy;
56
+ readonly enqueuedAt: number;
57
+ readonly maxAttempts: number;
58
+ readonly visibilityTimeoutMs: number;
59
+ readonly attemptTimeoutMs: number;
60
+ readonly generation: number;
61
+ readonly attempt: number;
62
+ readonly retryCount: number;
63
+ readonly firstClaimedAt: number | undefined;
64
+ readonly availableAt: number;
65
+ };
66
+ /** Backoff policy shared by every reschedule. */
67
+ export type RetryPolicy = {
68
+ readonly retryBackoffMs: number;
69
+ readonly maxRetryBackoffMs: number;
70
+ };
71
+ /**
72
+ * Reschedule a leased delivery for another attempt, or dead-letter it when the
73
+ * attempt budget is spent.
74
+ *
75
+ * The delay is the outbox's own backoff or the transport's suggestion,
76
+ * whichever is longer: a transport asking for more time is honoured, one
77
+ * asking for less is not allowed to defeat the configured backoff.
78
+ */
79
+ export declare function rescheduleOrDeadLetter(leased: ApplicationDeliveryLeasedRecord, options: {
80
+ readonly now: number;
81
+ readonly failure: ApplicationDeliveryFailure;
82
+ readonly retryAfterMs?: number | undefined;
83
+ } & RetryPolicy): ApplicationDeliveryRetryScheduled | ApplicationDeliveryTerminalRecord;
@@ -0,0 +1,63 @@
1
+ import { computeRetryBackoffMs } from "./application-primitive-timing.js";
2
+ import { requireDerivedInstant } from "./outbox-guards.js";
3
+ import { OUTBOX_RECORD_VERSION, isApplicationDeliveryTerminalState } from "./outbox-types.js";
4
+
5
+ export { computeRetryBackoffMs };
6
+ export function rejectedTransition(reason) {
7
+ return { ok: !1, reason };
8
+ }
9
+ export function succeededTransition(next) {
10
+ return { ok: !0, next };
11
+ }
12
+ export function isTerminalDeliveryRecord(record) {
13
+ return isApplicationDeliveryTerminalState(record.state);
14
+ }
15
+ export function nonTerminalDeliveryRecord(record) {
16
+ return isTerminalDeliveryRecord(record) ? null : record;
17
+ }
18
+ export function applicationDeliveryIdentityFields(record) {
19
+ return {
20
+ recordVersion: OUTBOX_RECORD_VERSION,
21
+ namespace: record.namespace,
22
+ ownerId: record.ownerId,
23
+ deliveryId: record.deliveryId,
24
+ sequence: record.sequence,
25
+ idempotencyKey: record.idempotencyKey,
26
+ destinationRef: record.destinationRef,
27
+ credentialRef: record.credentialRef,
28
+ kind: record.kind,
29
+ payload: record.payload,
30
+ payloadDigest: record.payloadDigest,
31
+ payloadMediaType: record.payloadMediaType,
32
+ payloadSchema: record.payloadSchema,
33
+ causation: record.causation,
34
+ externalIdempotencyKey: record.externalIdempotencyKey,
35
+ unknownOutcomePolicy: record.unknownOutcomePolicy,
36
+ enqueuedAt: record.enqueuedAt,
37
+ maxAttempts: record.maxAttempts,
38
+ visibilityTimeoutMs: record.visibilityTimeoutMs,
39
+ attemptTimeoutMs: record.attemptTimeoutMs,
40
+ generation: record.generation + 1,
41
+ attempt: record.attempt,
42
+ retryCount: record.retryCount,
43
+ firstClaimedAt: record.firstClaimedAt,
44
+ availableAt: record.availableAt
45
+ };
46
+ }
47
+ export function rescheduleOrDeadLetter(leased, options) {
48
+ if (leased.attempt >= leased.maxAttempts)
49
+ return {
50
+ ...applicationDeliveryIdentityFields(leased),
51
+ state: "dead-lettered",
52
+ terminalAt: options.now,
53
+ failure: { ...options.failure, reason: "attempts-exhausted" }
54
+ };
55
+ const backoff = computeRetryBackoffMs(leased.attempt, options.retryBackoffMs, options.maxRetryBackoffMs);
56
+ return {
57
+ ...applicationDeliveryIdentityFields(leased),
58
+ state: "retry-scheduled",
59
+ retryCount: leased.retryCount + 1,
60
+ availableAt: requireDerivedInstant(options.now + Math.max(backoff, options.retryAfterMs ?? 0), "availableAt"),
61
+ lastFailure: options.failure
62
+ };
63
+ }
@@ -0,0 +1,30 @@
1
+ /**
2
+ * The time-driven recovery transition for the application delivery outbox
3
+ * (WFT-85): what happens to a lease nobody renewed.
4
+ *
5
+ * The state the lease expired in decides everything. A `claimed` lease never
6
+ * called the transport, so the delivery is safe to reschedule (or dead-letter
7
+ * when its attempt budget is spent). An `attempting` or cancellation-requested
8
+ * lease may have sent, so its outcome is unknown and the delivery's own
9
+ * unknown-outcome policy decides — never a blind retry.
10
+ *
11
+ * @module core/outbox-transitions-recovery
12
+ */
13
+ import { type OutboxTransition, type RetryPolicy } from './outbox-transition-helpers.ts';
14
+ import type { ApplicationDeliveryRecord, ApplicationDeliveryRetryScheduled, ApplicationDeliveryTerminalRecord } from './outbox-types.ts';
15
+ /**
16
+ * Whether a leased record's lease has lapsed: its visibility expired or its
17
+ * attempt deadline passed, whichever came first.
18
+ */
19
+ export declare function isDeliveryLeaseExpired(record: ApplicationDeliveryRecord, now: number): boolean;
20
+ /**
21
+ * Recover a delivery whose lease lapsed.
22
+ *
23
+ * `cleanupPending: true` and `abandonedAttemptToken` are written whenever the
24
+ * lease is abandoned rather than settled by its holder, in every disposition:
25
+ * the outbox stopped waiting for that attempt, which is not a claim that the
26
+ * attempt stopped.
27
+ */
28
+ export declare function recoverExpiredDelivery(record: ApplicationDeliveryRecord, options: {
29
+ readonly now: number;
30
+ } & RetryPolicy): OutboxTransition<ApplicationDeliveryRetryScheduled | ApplicationDeliveryTerminalRecord>;
@@ -0,0 +1,42 @@
1
+ import {
2
+ nonTerminalDeliveryRecord,
3
+ rejectedTransition,
4
+ rescheduleOrDeadLetter,
5
+ succeededTransition
6
+ } from "./outbox-transition-helpers.js";
7
+ import { applyUnknownOutcomePolicy } from "./outbox-transitions.js";
8
+ export function isDeliveryLeaseExpired(record, now) {
9
+ if (record.state !== "claimed" && record.state !== "attempting" && record.state !== "cancellation-requested")
10
+ return !1;
11
+ return now >= record.visibilityExpiresAt || now >= record.attemptDeadlineAt;
12
+ }
13
+ export function recoverExpiredDelivery(record, options) {
14
+ const live = nonTerminalDeliveryRecord(record);
15
+ if (live === null)
16
+ return rejectedTransition("already-terminal");
17
+ if (live.state === "queued" || live.state === "retry-scheduled")
18
+ return rejectedTransition("not-leased");
19
+ if (!isDeliveryLeaseExpired(live, options.now))
20
+ return rejectedTransition("not-due");
21
+ if (live.state === "claimed") {
22
+ const next = rescheduleOrDeadLetter(live, {
23
+ ...options,
24
+ failure: { reason: "retryable", message: "The attempt lease expired before the send began." }
25
+ });
26
+ if (next.state === "retry-scheduled")
27
+ return succeededTransition(next);
28
+ return succeededTransition({
29
+ ...next,
30
+ cleanupPending: !0,
31
+ abandonedAttemptToken: live.attemptToken
32
+ });
33
+ }
34
+ return succeededTransition(applyUnknownOutcomePolicy(live, {
35
+ ...options,
36
+ failure: {
37
+ reason: "unknown-outcome",
38
+ message: "The attempt lease expired after the send began; the transport result is unknown."
39
+ },
40
+ abandonedAttemptToken: live.attemptToken
41
+ }));
42
+ }
@@ -0,0 +1,145 @@
1
+ /**
2
+ * Pure conditional-transition functions for the durable application delivery
3
+ * outbox (WFT-85) — one function per legal edge of the outbox state machine.
4
+ *
5
+ * These functions are storage-agnostic. They take the currently decoded
6
+ * {@link ApplicationDeliveryRecord} and proposed inputs and return either the
7
+ * next record to persist or a stable rejection reason. They never read or write
8
+ * storage and never see encoded bytes; the caller that commits a transition
9
+ * keeps the raw bytes it read as the compare-and-swap `expectedValue`.
10
+ *
11
+ * The legal edges are:
12
+ *
13
+ * ```text
14
+ * (none) --enqueue--> queued
15
+ * queued | retry-scheduled --claim(due)--> claimed
16
+ * claimed --begin--> attempting
17
+ * claimed | attempting | cancel-req --heartbeat--> (same state, visibility extended)
18
+ * attempting --settle(acknowledged)--> acknowledged
19
+ * attempting --settle(rejected)--> rejected
20
+ * attempting --settle(retryable)--> retry-scheduled | dead-lettered
21
+ * attempting --settle(unknown)--> unknown-outcome | dead-lettered | retry-scheduled
22
+ * cancellation-requested --settle(ack)--> acknowledged (the effect happened)
23
+ * cancellation-requested --settle(other)--> cancelled | unknown-outcome | dead-lettered
24
+ * queued | retry-scheduled | claimed --cancel--> cancelled
25
+ * attempting --cancel--> cancellation-requested
26
+ * claimed --expire--> retry-scheduled | dead-lettered (recovery)
27
+ * attempting | cancel-req --expire--> unknown-outcome | dead-lettered | retry-scheduled
28
+ * unknown-outcome | dead-lettered | rejected --retry--> queued (operator)
29
+ * unknown-outcome --deadLetter--> dead-lettered (operator)
30
+ * ```
31
+ *
32
+ * @module core/outbox-transitions
33
+ */
34
+ import type { JSONValue } from './json.ts';
35
+ import { type OutboxTransition, type RetryPolicy } from './outbox-transition-helpers.ts';
36
+ import type { ApplicationDeliveryAttempting, ApplicationDeliveryCancelling, ApplicationDeliveryClaimed, ApplicationDeliveryLeasedRecord, ApplicationDeliveryQueued, ApplicationDeliveryRecord, ApplicationDeliveryRetryScheduled, ApplicationDeliveryTerminalRecord } from './outbox-types.ts';
37
+ import type { ValidatedDeliveryInput, ValidatedOutcome } from './outbox-validation.ts';
38
+ export { isTerminalDeliveryRecord, nonTerminalDeliveryRecord, } from './outbox-transition-helpers.ts';
39
+ export type { OutboxTransition, OutboxTransitionRejection } from './outbox-transition-helpers.ts';
40
+ /** Build the record for a freshly enqueued delivery. */
41
+ export declare function createEnqueuedDeliveryRecord(input: ValidatedDeliveryInput, context: {
42
+ readonly namespace: string;
43
+ readonly ownerId: string;
44
+ readonly deliveryId: string;
45
+ readonly sequence: number;
46
+ readonly now: number;
47
+ }): ApplicationDeliveryQueued;
48
+ /**
49
+ * Lease a waiting delivery to one attempt.
50
+ *
51
+ * The attempt deadline is fixed here, at `now + attemptTimeoutMs`, and nothing
52
+ * later moves it. Visibility starts at the lesser of the renewal window and
53
+ * that deadline.
54
+ */
55
+ export declare function claimWaitingDelivery(record: ApplicationDeliveryRecord, options: {
56
+ readonly now: number;
57
+ readonly attemptToken: string;
58
+ }): OutboxTransition<ApplicationDeliveryClaimed>;
59
+ /**
60
+ * Durably mark that the current attempt is about to call the transport.
61
+ *
62
+ * This is the edge that makes recovery honest: a lease that expires in
63
+ * `claimed` provably sent nothing and is safe to retry, while one that expires
64
+ * in `attempting` may have, and follows the unknown-outcome policy.
65
+ */
66
+ export declare function beginDeliveryAttempt(record: ApplicationDeliveryRecord, options: {
67
+ readonly attemptToken: string;
68
+ readonly now: number;
69
+ }): OutboxTransition<ApplicationDeliveryAttempting>;
70
+ /**
71
+ * Record liveness for the current attempt and extend its visibility, clamped
72
+ * to the fixed attempt deadline. `transportActivity` is evidence of transport
73
+ * progress — bytes written, a request id — and is never fencing.
74
+ */
75
+ export declare function heartbeatDeliveryAttempt(record: ApplicationDeliveryRecord, options: {
76
+ readonly attemptToken: string;
77
+ readonly now: number;
78
+ readonly transportActivity?: JSONValue | undefined;
79
+ }): OutboxTransition<ApplicationDeliveryLeasedRecord>;
80
+ /**
81
+ * Apply the unknown-outcome policy to a leased delivery whose transport result
82
+ * is lost. Shared by settlement (adapter reported `unknown`) and recovery (the
83
+ * lease expired in `attempting`).
84
+ *
85
+ * A delivery whose cancellation was requested is never retried: `park` and
86
+ * `retry-with-idempotency` both park it, because a retry would send work the
87
+ * caller asked to stop. `abandonedAttemptToken` is set by recovery only.
88
+ */
89
+ export declare function applyUnknownOutcomePolicy(leased: ApplicationDeliveryLeasedRecord, options: {
90
+ readonly now: number;
91
+ readonly failure: {
92
+ readonly reason: 'unknown-outcome';
93
+ readonly message?: string | undefined;
94
+ };
95
+ readonly abandonedAttemptToken?: string | undefined;
96
+ } & RetryPolicy): ApplicationDeliveryRetryScheduled | ApplicationDeliveryTerminalRecord;
97
+ /**
98
+ * Settle the current attempt on what the transport reported.
99
+ *
100
+ * Only an `attempting` (or cancellation-requested) delivery can settle: a
101
+ * `claimed` one never called the transport, so it has no outcome to record.
102
+ * An acknowledgement always wins, even after cancellation was requested — the
103
+ * effect happened and the receipt must say so. Any other outcome on a
104
+ * cancelling delivery honours the cancellation: `cancelled` when nothing was
105
+ * confirmed, the unknown-outcome policy when the result was lost.
106
+ */
107
+ export declare function settleDeliveryAttempt(record: ApplicationDeliveryRecord, options: {
108
+ readonly attemptToken: string;
109
+ readonly now: number;
110
+ readonly outcome: ValidatedOutcome;
111
+ } & RetryPolicy): OutboxTransition<ApplicationDeliveryRetryScheduled | ApplicationDeliveryTerminalRecord>;
112
+ /**
113
+ * Record a durable cancellation request.
114
+ *
115
+ * A waiting or merely claimed delivery cancels at once: nothing has been sent.
116
+ * (The claimant's `attempting` commit then loses its compare-and-swap and it
117
+ * re-reads a terminal record.) An attempting delivery keeps its lease and moves
118
+ * to `cancellation-requested`, so only the current attempt can settle it.
119
+ * Requesting cancellation twice rejects with `not-leased` against a record
120
+ * already in `cancellation-requested`, which the caller reports as the same
121
+ * outcome.
122
+ */
123
+ export declare function requestDeliveryCancellation(record: ApplicationDeliveryRecord, options: {
124
+ readonly now: number;
125
+ readonly reason?: string | undefined;
126
+ }): OutboxTransition<ApplicationDeliveryCancelling | ApplicationDeliveryTerminalRecord>;
127
+ /**
128
+ * Operator retry: return a parked, dead-lettered, or rejected delivery to the
129
+ * due index with at least one more attempt to spend.
130
+ *
131
+ * A budget the delivery never used up — a permanent rejection on its first
132
+ * attempt of five, say — is kept, so the reopened delivery may retry on its
133
+ * own up to `maxAttempts`; a spent budget is raised to `attempt + 1`, so the
134
+ * delivery can be claimed exactly once more, and a second operator retry
135
+ * grants one more again. The record's provenance (`attempt`, `retryCount`) is
136
+ * preserved.
137
+ */
138
+ export declare function retryDeliveryByOperator(record: ApplicationDeliveryRecord, options: {
139
+ readonly now: number;
140
+ }): OutboxTransition<ApplicationDeliveryQueued>;
141
+ /** Operator dead-letter: close a parked `unknown-outcome` delivery for good. */
142
+ export declare function deadLetterDeliveryByOperator(record: ApplicationDeliveryRecord, options: {
143
+ readonly now: number;
144
+ readonly reason?: string | undefined;
145
+ }): OutboxTransition<ApplicationDeliveryTerminalRecord>;