@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,36 @@
1
+ import { utf8ByteLength } from "../../worker/manifest/utf8.js";
2
+ import { MAX_CONTRACT_IDENTIFIER_BYTES } from "../contract/limits.js";
3
+ import { validateWorkflowOrActivityName } from "../types/name-grammar.js";
4
+ function assertWellFormedSourceDescriptor(source) {
5
+ const { kind, name, revision } = source.descriptor;
6
+ if (typeof kind !== "string" || kind.length === 0)
7
+ throw TypeError("registerSource(): source.descriptor.kind must be a non-empty string");
8
+ if (typeof name !== "string" || name.length === 0)
9
+ throw TypeError("registerSource(): source.descriptor.name must be a non-empty string");
10
+ if (typeof revision !== "string" || revision.length === 0)
11
+ throw TypeError("registerSource(): source.descriptor.revision must be a non-empty string");
12
+ const revisionBytes = utf8ByteLength(revision);
13
+ if (revisionBytes > MAX_CONTRACT_IDENTIFIER_BYTES)
14
+ throw TypeError(`registerSource(): source.descriptor.revision is ${revisionBytes} bytes, exceeding the maximum identifier size of ${MAX_CONTRACT_IDENTIFIER_BYTES}`);
15
+ }
16
+ export function registerSource(internals, source) {
17
+ assertWellFormedSourceDescriptor(source);
18
+ const { name, revision } = source.descriptor;
19
+ validateWorkflowOrActivityName(name, "workflow");
20
+ Object.freeze(source.descriptor);
21
+ if (internals.registrations.has(name))
22
+ throw Error(`Cannot registerSource("${name}"): "${name}" is already registered as an eager workflow via engine.register(). A workflow name may not be both eagerly registered and a dynamic source.`);
23
+ let byRevision = internals.workflowSourcesByName.get(name);
24
+ if (byRevision === void 0) {
25
+ byRevision = new Map;
26
+ internals.workflowSourcesByName.set(name, byRevision);
27
+ }
28
+ const existing = byRevision.get(revision);
29
+ if (existing === void 0) {
30
+ byRevision.set(revision, source);
31
+ return;
32
+ }
33
+ if (existing === source)
34
+ return;
35
+ throw Error(`Cannot registerSource("${name}", "${revision}"): a different source handle is already registered for this exact (name, revision) key.`);
36
+ }
@@ -0,0 +1,85 @@
1
+ /**
2
+ * `resolveWorkflowSource()` — the async, single-flight entry point that
3
+ * loads, validates, and installs one dynamic workflow source revision
4
+ * (WFT-13/14).
5
+ *
6
+ * Single-flight per `(name, revision)`: the underlying load+validate+install
7
+ * work is shared by every concurrent caller for the same key via
8
+ * `internals.sourceResolutionsInFlight`, but each caller races that shared
9
+ * work against its OWN per-call cancellation interest — a cancelled waiter
10
+ * never aborts a load another waiter still needs, and the shared load
11
+ * itself is never tied to any individual caller's lifetime. Disposal aborts
12
+ * every outstanding waiter (rejecting each pending `resolveWorkflowSource()`
13
+ * call) without touching the shared load, which keeps running to whatever
14
+ * point it naturally settles.
15
+ *
16
+ * @module core/engine/source-resolution
17
+ */
18
+ import type { WorkflowRevisionRecord } from '../catalog/index.ts';
19
+ import type { Engine } from './index.ts';
20
+ /**
21
+ * Options accepted by {@link resolveWorkflowSource}.
22
+ *
23
+ * @example
24
+ * ```ts
25
+ * import { Engine } from '@lostgradient/weft';
26
+ * import type { ResolveWorkflowSourceOptions } from '@lostgradient/weft';
27
+ *
28
+ * declare const engine: Engine;
29
+ * const options: ResolveWorkflowSourceOptions = { signal: AbortSignal.timeout(5_000) };
30
+ * const record = await engine.resolveWorkflowSource('checkout', 'r1', options);
31
+ * console.log(record.manifest.revision);
32
+ * ```
33
+ */
34
+ export type ResolveWorkflowSourceOptions = {
35
+ /** When aborted, this caller's own `resolveWorkflowSource()` call rejects; a load already in flight for other callers is unaffected. */
36
+ signal?: AbortSignal;
37
+ };
38
+ /**
39
+ * Load, validate, and install one dynamic workflow source revision
40
+ * previously recorded via `engine.registerSource()`. Returns the installed
41
+ * {@link WorkflowRevisionRecord} immediately, without invoking the loader
42
+ * at all, when `(name, revision)` is already durably installed — including
43
+ * a revision installed by a different process. When that is the case,
44
+ * `internals.resolvedWorkflowSources` is NOT populated for this key (there
45
+ * is no locally-loaded `WorkflowDefinition` to stash — only the durable
46
+ * manifest was ever read) even though the catalog itself considers the
47
+ * revision installed; a later batch reading `resolvedWorkflowSources` must
48
+ * account for that gap rather than assuming every installed revision has a
49
+ * live definition available in this process. This fast path still requires
50
+ * `registerSource()` to have been called for this exact key first (see
51
+ * {@link resolveCachedOrHandle}), and still validates a pinned
52
+ * `workflowVersion`/`contractHash` against the cached manifest — the ONLY
53
+ * thing it skips is re-invoking the loader and re-running
54
+ * {@link import('../source/index.ts').validateResolvedWorkflowSource}.
55
+ *
56
+ * Single-flight per `(name, revision)` — see the module doc for the full
57
+ * cancellation contract. Throws a plain `Error` when `registerSource()` was
58
+ * never called for this exact key (a programmer error, not untrusted-input
59
+ * rejection); throws {@link WorkflowSourceValidationError} when the loaded
60
+ * module fails validation, OR when a cached manifest contradicts a pinned
61
+ * `workflowVersion`/`contractHash`; throws {@link EngineDisposedError} when
62
+ * the engine is disposed, either already or during the call; propagates
63
+ * {@link import('../catalog/index.ts').WorkflowCatalogConflictError}
64
+ * unwrapped on a genuine content conflict with an already-installed
65
+ * revision.
66
+ *
67
+ * @example
68
+ * ```ts
69
+ * import { Engine, workflowSource } from '@lostgradient/weft';
70
+ *
71
+ * declare const engine: Engine;
72
+ * declare const loadCheckout: () => Promise<{
73
+ * checkout: import('@lostgradient/weft').WorkflowDefinition<unknown, unknown, 'checkout'>;
74
+ * }>;
75
+ * engine.registerSource(
76
+ * workflowSource(
77
+ * { name: 'checkout', location: './checkout.ts', exportName: 'checkout', revision: 'r1' },
78
+ * loadCheckout,
79
+ * ),
80
+ * );
81
+ * const record = await engine.resolveWorkflowSource('checkout', 'r1');
82
+ * console.log(record.manifest.revision);
83
+ * ```
84
+ */
85
+ export declare function resolveWorkflowSource(engine: Engine, name: string, revision: string, options?: ResolveWorkflowSourceOptions): Promise<WorkflowRevisionRecord>;
@@ -0,0 +1,119 @@
1
+ import {
2
+ checkWorkflowCompatibility,
3
+ DEFAULT_WORKFLOW_COMPATIBILITY_POLICY
4
+ } from "../contract/compatibility.js";
5
+ import {
6
+ buildExpectedManifest,
7
+ resolveSourceModule,
8
+ validateResolvedWorkflowSource,
9
+ WorkflowSourceValidationError
10
+ } from "../source/index.js";
11
+ import { ensureWorkflowCatalogReady, isWorkflowCatalogReady } from "./catalog-readiness.js";
12
+ import { EngineDisposedError } from "./errors.js";
13
+ import { getInternals, getWorkflowCatalog } from "./internals.js";
14
+ function toAbortError(signal) {
15
+ const reason = signal.reason;
16
+ return reason instanceof Error ? reason : Error("resolveWorkflowSource() aborted");
17
+ }
18
+ function abortRejection(signal) {
19
+ return new Promise((_resolve, reject) => {
20
+ signal.addEventListener("abort", () => reject(toAbortError(signal)), { once: !0 });
21
+ });
22
+ }
23
+ async function runSharedSourceLoad(engine, internals, name, revision, handle) {
24
+ const resolved = await resolveSourceModule(handle.descriptor, handle);
25
+ if (!resolved.ok)
26
+ throw new WorkflowSourceValidationError(name, revision, [resolved.reason]);
27
+ const outcome = await validateResolvedWorkflowSource(handle.descriptor, resolved.moduleValue);
28
+ if (!outcome.ok)
29
+ throw new WorkflowSourceValidationError(name, revision, outcome.reasons);
30
+ if (internals.disposed)
31
+ throw new EngineDisposedError;
32
+ const installed = await getWorkflowCatalog(engine).install(outcome.manifest, outcome.definition);
33
+ if (!internals.disposed) {
34
+ let resolvedByRevision = internals.resolvedWorkflowSources.get(name);
35
+ if (resolvedByRevision === void 0) {
36
+ resolvedByRevision = new Map;
37
+ internals.resolvedWorkflowSources.set(name, resolvedByRevision);
38
+ }
39
+ resolvedByRevision.set(revision, {
40
+ definition: outcome.loadedDefinition,
41
+ activityRegistry: outcome.activityRegistry
42
+ });
43
+ }
44
+ return { manifest: installed.manifest, installedAt: installed.installedAt };
45
+ }
46
+ function getOrCreateSharedSourceLoad(engine, internals, name, revision, handle) {
47
+ let byRevision = internals.sourceResolutionsInFlight.get(name);
48
+ if (byRevision === void 0) {
49
+ byRevision = new Map;
50
+ internals.sourceResolutionsInFlight.set(name, byRevision);
51
+ }
52
+ const existing = byRevision.get(revision);
53
+ if (existing !== void 0)
54
+ return existing;
55
+ const shared = runSharedSourceLoad(engine, internals, name, revision, handle).finally(() => {
56
+ const currentByRevision = internals.sourceResolutionsInFlight.get(name);
57
+ if (currentByRevision?.get(revision) !== shared)
58
+ return;
59
+ currentByRevision.delete(revision);
60
+ if (currentByRevision.size === 0)
61
+ internals.sourceResolutionsInFlight.delete(name);
62
+ });
63
+ shared.catch(() => {});
64
+ byRevision.set(revision, shared);
65
+ return shared;
66
+ }
67
+ function createWaiterAbort(options) {
68
+ const controller = new AbortController, forwardAbort = () => controller.abort(options?.signal?.reason);
69
+ if (options?.signal?.aborted)
70
+ forwardAbort();
71
+ else
72
+ options?.signal?.addEventListener("abort", forwardAbort, { once: !0 });
73
+ return { controller, detach: () => options?.signal?.removeEventListener("abort", forwardAbort) };
74
+ }
75
+ async function resolveCachedOrHandle(engine, internals, name, revision) {
76
+ const handle = internals.workflowSourcesByName.get(name)?.get(revision);
77
+ if (handle === void 0)
78
+ throw Error(`resolveWorkflowSource("${name}", "${revision}") was called before registerSource() ` + "registered this exact (name, revision) \u2014 call engine.registerSource() first.");
79
+ if (!isWorkflowCatalogReady(engine))
80
+ await ensureWorkflowCatalogReady(engine);
81
+ const existing = await getWorkflowCatalog(engine).resolveEntry(name, revision);
82
+ if (existing !== void 0) {
83
+ const expectedManifest = buildExpectedManifest(handle.descriptor, existing.manifest), verdict = checkWorkflowCompatibility(expectedManifest, existing.manifest, DEFAULT_WORKFLOW_COMPATIBILITY_POLICY);
84
+ if (!verdict.compatible)
85
+ throw new WorkflowSourceValidationError(name, revision, verdict.reasons);
86
+ return { cached: existing };
87
+ }
88
+ return { handle };
89
+ }
90
+ export async function resolveWorkflowSource(engine, name, revision, options) {
91
+ const internals = getInternals(engine), waiter = createWaiterAbort(options);
92
+ if (waiter.controller.signal.aborted) {
93
+ waiter.detach();
94
+ throw toAbortError(waiter.controller.signal);
95
+ }
96
+ if (internals.disposed) {
97
+ waiter.detach();
98
+ throw new EngineDisposedError;
99
+ }
100
+ internals.sourceResolutionWaiterControllers.add(waiter.controller);
101
+ try {
102
+ const cachedOrHandle = resolveCachedOrHandle(engine, internals, name, revision), cachedOrHandleAbort = abortRejection(waiter.controller.signal);
103
+ cachedOrHandleAbort.catch(() => {});
104
+ let outcome;
105
+ try {
106
+ outcome = await Promise.race([cachedOrHandle, cachedOrHandleAbort]);
107
+ } finally {
108
+ cachedOrHandle.catch(() => {});
109
+ }
110
+ if (outcome.cached !== void 0)
111
+ return outcome.cached;
112
+ const shared = getOrCreateSharedSourceLoad(engine, internals, name, revision, outcome.handle), waiterAbort = abortRejection(waiter.controller.signal);
113
+ waiterAbort.catch(() => {});
114
+ return await Promise.race([shared, waiterAbort]);
115
+ } finally {
116
+ waiter.detach();
117
+ internals.sourceResolutionWaiterControllers.delete(waiter.controller);
118
+ }
119
+ }
@@ -121,7 +121,7 @@ export function decodeWorkflowState(bytes) {
121
121
  liftFlatVersionTuple(decodedRecord);
122
122
  const state = decoded;
123
123
  if (!isValidDecodedTags(state.tags)) {
124
- console.warn(`[weft] Decoded workflow state for "${String(state.id)}" has invalid tags; dropping the malformed tag list from the decoded state.`);
124
+ console.warn(`[weft] Decoded workflow state for "${state.id}" has invalid tags; dropping the malformed tag list from the decoded state.`);
125
125
  delete state.tags;
126
126
  }
127
127
  if (state.failureCategory !== void 0 && state.failureCategory !== null) {
@@ -135,7 +135,7 @@ export function decodeWorkflowState(bytes) {
135
135
  try {
136
136
  coerceStartWorkflowId(state.executionStateOwnerId, "executionStateOwnerId");
137
137
  } catch {
138
- console.warn(`[weft] Decoded workflow state for "${String(state.id)}" has an invalid executionStateOwnerId field; falling back to the workflow id as the execution owner. This usually indicates corruption or tampering of the storage record.`);
138
+ console.warn(`[weft] Decoded workflow state for "${state.id}" has an invalid executionStateOwnerId field; falling back to the workflow id as the execution owner. This usually indicates corruption or tampering of the storage record.`);
139
139
  delete state.executionStateOwnerId;
140
140
  }
141
141
  sanitizeDecodedParentLineage(state);
@@ -0,0 +1,117 @@
1
+ import type { WorkflowCompatibilityReason } from '../contract/compatibility.ts';
2
+ /**
3
+ * Fired on the {@link Engine} when a `(name, revision)` is durably installed
4
+ * into the workflow catalog for the first time. Never fired for a
5
+ * byte-identical reinstall of an already-installed revision. Read
6
+ * `e.workflowType` and `e.revision` directly off the event.
7
+ *
8
+ * @example
9
+ * ```ts
10
+ * import { Engine, WorkflowRevisionInstalledEvent, workflow } from '@lostgradient/weft';
11
+ *
12
+ * const engine = new Engine();
13
+ * engine.addEventListener(WorkflowRevisionInstalledEvent.type, (event) => {
14
+ * console.log('installed:', event.workflowType, event.revision);
15
+ * });
16
+ * engine.register(workflow({ name: 'ping' }).execute(async function* () { return 'pong'; }));
17
+ * ```
18
+ */
19
+ export declare class WorkflowRevisionInstalledEvent extends Event {
20
+ static readonly type: "catalog:revision-installed";
21
+ readonly workflowType: string;
22
+ readonly revision: string;
23
+ constructor(workflowType: string, revision: string);
24
+ }
25
+ /**
26
+ * Fired on the {@link Engine} when a `(name, revision)` becomes the active
27
+ * revision for its name — bumping the catalog's per-name `generation`
28
+ * counter. `previousRevision` is `undefined` on a name's first-ever
29
+ * activation, and set to the revision this activation replaced otherwise.
30
+ *
31
+ * @example
32
+ * ```ts
33
+ * import { Engine, WorkflowRevisionActivatedEvent, workflow } from '@lostgradient/weft';
34
+ *
35
+ * const engine = new Engine();
36
+ * engine.addEventListener(WorkflowRevisionActivatedEvent.type, (event) => {
37
+ * console.log('activated:', event.workflowType, event.revision, 'gen', event.generation);
38
+ * });
39
+ * engine.register(workflow({ name: 'ping' }).execute(async function* () { return 'pong'; }));
40
+ * ```
41
+ */
42
+ export declare class WorkflowRevisionActivatedEvent extends Event {
43
+ static readonly type: "catalog:revision-activated";
44
+ readonly workflowType: string;
45
+ readonly revision: string;
46
+ readonly generation: number;
47
+ readonly previousRevision: string | undefined;
48
+ constructor(workflowType: string, revision: string, generation: number, previousRevision: string | undefined);
49
+ }
50
+ /**
51
+ * Fired on the {@link Engine} when a candidate activation
52
+ * (`activateCatalogRevisionCandidate`, the guarded primitive) is refused.
53
+ * `reason` is a closed, low-cardinality union safe to use as a metric label;
54
+ * `incompatibilityReasons` is populated only when `reason === 'incompatible'`,
55
+ * carrying every applicable {@link WorkflowCompatibilityReason} — never the
56
+ * full compatibility verdict object.
57
+ *
58
+ * @example
59
+ * ```ts
60
+ * import { Engine, WorkflowRevisionActivationRejectedEvent } from '@lostgradient/weft';
61
+ *
62
+ * const engine = new Engine();
63
+ * engine.addEventListener(WorkflowRevisionActivationRejectedEvent.type, (event) => {
64
+ * console.log('rejected:', event.workflowType, event.candidateRevision, event.reason);
65
+ * });
66
+ * ```
67
+ */
68
+ export declare class WorkflowRevisionActivationRejectedEvent extends Event {
69
+ static readonly type: "catalog:activation-rejected";
70
+ readonly workflowType: string;
71
+ readonly candidateRevision: string;
72
+ readonly reason: 'incompatible' | 'stale-generation' | 'conflict' | 'expected-generation-required';
73
+ readonly incompatibilityReasons: readonly WorkflowCompatibilityReason[] | undefined;
74
+ constructor(workflowType: string, candidateRevision: string, reason: 'incompatible' | 'stale-generation' | 'conflict' | 'expected-generation-required', incompatibilityReasons?: readonly WorkflowCompatibilityReason[]);
75
+ }
76
+ /**
77
+ * Fired on the {@link Engine} alongside {@link WorkflowRevisionActivatedEvent}
78
+ * when activating a new revision displaces a previously active one for the
79
+ * same name. Never fired on a name's first-ever activation (there is
80
+ * nothing to drain).
81
+ *
82
+ * @example
83
+ * ```ts
84
+ * import { Engine, WorkflowRevisionDrainingEvent } from '@lostgradient/weft';
85
+ *
86
+ * const engine = new Engine();
87
+ * engine.addEventListener(WorkflowRevisionDrainingEvent.type, (event) => {
88
+ * console.log('draining:', event.workflowType, event.revision);
89
+ * });
90
+ * ```
91
+ */
92
+ export declare class WorkflowRevisionDrainingEvent extends Event {
93
+ static readonly type: "catalog:revision-draining";
94
+ readonly workflowType: string;
95
+ readonly revision: string;
96
+ constructor(workflowType: string, revision: string);
97
+ }
98
+ /**
99
+ * Fired on the {@link Engine} when a `(name, revision)` is durably removed
100
+ * from the workflow catalog via `removeWorkflowRevision`.
101
+ *
102
+ * @example
103
+ * ```ts
104
+ * import { Engine, WorkflowRevisionRemovedEvent } from '@lostgradient/weft';
105
+ *
106
+ * const engine = new Engine();
107
+ * engine.addEventListener(WorkflowRevisionRemovedEvent.type, (event) => {
108
+ * console.log('removed:', event.workflowType, event.revision);
109
+ * });
110
+ * ```
111
+ */
112
+ export declare class WorkflowRevisionRemovedEvent extends Event {
113
+ static readonly type: "catalog:revision-removed";
114
+ readonly workflowType: string;
115
+ readonly revision: string;
116
+ constructor(workflowType: string, revision: string);
117
+ }
@@ -0,0 +1,62 @@
1
+ export class WorkflowRevisionInstalledEvent extends Event {
2
+ static type = "catalog:revision-installed";
3
+ workflowType;
4
+ revision;
5
+ constructor(workflowType, revision) {
6
+ super(WorkflowRevisionInstalledEvent.type);
7
+ this.workflowType = workflowType;
8
+ this.revision = revision;
9
+ }
10
+ }
11
+
12
+ export class WorkflowRevisionActivatedEvent extends Event {
13
+ static type = "catalog:revision-activated";
14
+ workflowType;
15
+ revision;
16
+ generation;
17
+ previousRevision;
18
+ constructor(workflowType, revision, generation, previousRevision) {
19
+ super(WorkflowRevisionActivatedEvent.type);
20
+ this.workflowType = workflowType;
21
+ this.revision = revision;
22
+ this.generation = generation;
23
+ this.previousRevision = previousRevision;
24
+ }
25
+ }
26
+
27
+ export class WorkflowRevisionActivationRejectedEvent extends Event {
28
+ static type = "catalog:activation-rejected";
29
+ workflowType;
30
+ candidateRevision;
31
+ reason;
32
+ incompatibilityReasons;
33
+ constructor(workflowType, candidateRevision, reason, incompatibilityReasons) {
34
+ super(WorkflowRevisionActivationRejectedEvent.type);
35
+ this.workflowType = workflowType;
36
+ this.candidateRevision = candidateRevision;
37
+ this.reason = reason;
38
+ this.incompatibilityReasons = incompatibilityReasons;
39
+ }
40
+ }
41
+
42
+ export class WorkflowRevisionDrainingEvent extends Event {
43
+ static type = "catalog:revision-draining";
44
+ workflowType;
45
+ revision;
46
+ constructor(workflowType, revision) {
47
+ super(WorkflowRevisionDrainingEvent.type);
48
+ this.workflowType = workflowType;
49
+ this.revision = revision;
50
+ }
51
+ }
52
+
53
+ export class WorkflowRevisionRemovedEvent extends Event {
54
+ static type = "catalog:revision-removed";
55
+ workflowType;
56
+ revision;
57
+ constructor(workflowType, revision) {
58
+ super(WorkflowRevisionRemovedEvent.type);
59
+ this.workflowType = workflowType;
60
+ this.revision = revision;
61
+ }
62
+ }
@@ -1,6 +1,7 @@
1
1
  import type { ReviewCompletedEvent, ReviewRequestedEvent } from '../review/events.ts';
2
2
  import type { ActivityAsyncPendingEvent, ActivityCompletedEvent, ActivityFailedEvent, ActivityStartedEvent, TaskResultDeadLetteredEvent } from './activity-events.ts';
3
3
  import type { AttributesChangedEvent } from './attribute-events.ts';
4
+ import type { WorkflowRevisionActivatedEvent, WorkflowRevisionActivationRejectedEvent, WorkflowRevisionDrainingEvent, WorkflowRevisionInstalledEvent, WorkflowRevisionRemovedEvent } from './catalog-events.ts';
4
5
  import type { ScheduleFiredEvent, ScheduleMissedFireEvent } from './schedule-events.ts';
5
6
  import type { SignalDeliveredEvent, SignalReceivedEvent } from './signal-events.ts';
6
7
  import type { AlertFiredEvent, AlertResolvedEvent, CheckpointSizeWarningEvent, CleanupWarningEvent, ConstraintViolatedEvent, DevelopmentWarningEvent, StorageSizeReportedEvent, WorkerConnectedEvent, WorkerDisconnectedEvent } from './system-events.ts';
@@ -57,6 +58,11 @@ export type WeftEventMap = {
57
58
  'alert:fired': AlertFiredEvent;
58
59
  'alert:resolved': AlertResolvedEvent;
59
60
  'constraint:violated': ConstraintViolatedEvent;
61
+ 'catalog:revision-installed': WorkflowRevisionInstalledEvent;
62
+ 'catalog:revision-activated': WorkflowRevisionActivatedEvent;
63
+ 'catalog:activation-rejected': WorkflowRevisionActivationRejectedEvent;
64
+ 'catalog:revision-draining': WorkflowRevisionDrainingEvent;
65
+ 'catalog:revision-removed': WorkflowRevisionRemovedEvent;
60
66
  };
61
67
  /**
62
68
  * Typed version of the `EventTarget` interface that constrains
@@ -1,5 +1,6 @@
1
1
  export * from './activity-events.ts';
2
2
  export * from './attribute-events.ts';
3
+ export * from './catalog-events.ts';
3
4
  export * from './event-map.ts';
4
5
  export * from './schedule-events.ts';
5
6
  export * from './signal-events.ts';
@@ -1,5 +1,6 @@
1
1
  export * from "./activity-events.js";
2
2
  export * from "./attribute-events.js";
3
+ export * from "./catalog-events.js";
3
4
  export * from "./event-map.js";
4
5
  export * from "./schedule-events.js";
5
6
  export * from "./signal-events.js";
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Admission for the application command mailbox (WFT-84): validating an offered
3
+ * command, resolving its idempotency identity, enforcing backlog capacity, and
4
+ * committing the record with its indexes and fleet event.
5
+ *
6
+ * Admission is the one transition that also allocates: it advances the mailbox
7
+ * header's FIFO sequence and open count in the same conditional batch as the
8
+ * record itself, so backlog accounting can never drift from the records it
9
+ * describes.
10
+ *
11
+ * @module core/mailbox-admission
12
+ */
13
+ import type { ApplicationCommandAdmission, ApplicationCommandInput, MailboxCapacity } from './mailbox-contract.ts';
14
+ import { type MailboxRuntime } from './mailbox-internals.ts';
15
+ /** Backlog accounting, shared by admission rejection and the public `capacity()`. */
16
+ export declare function capacityOf(runtime: MailboxRuntime, open: number, admitted: number): MailboxCapacity;
17
+ /**
18
+ * Offer a command to the mailbox.
19
+ *
20
+ * An exact retry of the same idempotency identity returns the original
21
+ * receipt without creating a second command. Reusing the key with a different
22
+ * caller, target, kind, or payload digest returns a conflict and leaves the
23
+ * original command untouched. A full backlog is rejected before anything is
24
+ * persisted.
25
+ */
26
+ export declare function admitCommand(runtime: MailboxRuntime, command: ApplicationCommandInput): Promise<ApplicationCommandAdmission>;
@@ -0,0 +1,130 @@
1
+ import { computeIdentityDigest } from "./application-payload-digest.js";
2
+ import {
3
+ encodeApplicationCommandIdempotencyRecord,
4
+ encodeApplicationReadyEntry
5
+ } from "./mailbox-index-codec.js";
6
+ import {
7
+ describeCommandTransition,
8
+ MailboxContentionError,
9
+ MAX_MAILBOX_TRANSITION_ATTEMPTS,
10
+ toApplicationCommandReceipt
11
+ } from "./mailbox-internals.js";
12
+ import {
13
+ commitMailboxTransition,
14
+ headerOperation,
15
+ loadCommand,
16
+ loadIdempotencyBinding,
17
+ loadMailboxHeader,
18
+ planCommandTransition
19
+ } from "./mailbox-storage.js";
20
+ import { createAdmittedCommandRecord } from "./mailbox-transitions.js";
21
+ import { MAILBOX_RECORD_VERSION } from "./mailbox-types.js";
22
+ import {
23
+ ApplicationCommandValidationError,
24
+ requireGeneratedIdentifier,
25
+ validateCommandInput
26
+ } from "./mailbox-validation.js";
27
+ import { PersistedDataCorruptError } from "./persisted-data-incompatible-error.js";
28
+ export function capacityOf(runtime, open, admitted) {
29
+ const limit = runtime.policy.maxBacklog;
30
+ return Object.freeze({ open, limit, remaining: Math.max(0, limit - open), admitted });
31
+ }
32
+ export async function admitCommand(runtime, command) {
33
+ const input = await validateCommandInput(command, runtime.policy), identityDigest = await computeIdentityDigest([
34
+ input.caller,
35
+ input.target,
36
+ input.kind,
37
+ input.payloadDigest
38
+ ]);
39
+ for (let attempt = 1;attempt <= MAX_MAILBOX_TRANSITION_ATTEMPTS; attempt += 1) {
40
+ let expectedBinding = null;
41
+ if (input.idempotencyKey !== void 0) {
42
+ const resolved = await resolveIdempotency(runtime, input.idempotencyKey, identityDigest);
43
+ if (resolved.admission !== null)
44
+ return resolved.admission;
45
+ expectedBinding = resolved.staleBindingBytes;
46
+ }
47
+ const header = await loadMailboxHeader(runtime.storage, runtime.keys, runtime.policy.namespace, runtime.policy.resourceId);
48
+ if (header.record.openCount >= runtime.policy.maxBacklog)
49
+ return {
50
+ status: "rejected",
51
+ reason: "backlog-full",
52
+ capacity: capacityOf(runtime, header.record.openCount, header.record.admittedCount)
53
+ };
54
+ if (header.record.nextSequence >= Number.MAX_SAFE_INTEGER)
55
+ throw new ApplicationCommandValidationError("This mailbox has exhausted its FIFO sequence allocator; no further commands can be admitted under this namespace and resource id.");
56
+ const now = runtime.now(), record = createAdmittedCommandRecord(input, {
57
+ namespace: runtime.policy.namespace,
58
+ resourceId: runtime.policy.resourceId,
59
+ commandId: requireGeneratedIdentifier(runtime.generateId(), "commandId"),
60
+ sequence: header.record.nextSequence,
61
+ now
62
+ });
63
+ if (!await commitMailboxTransition(runtime.storage, runtime.events, planCommandTransition(runtime.keys, {
64
+ previous: null,
65
+ expectedBytes: null,
66
+ next: record,
67
+ event: describeCommandTransition(null, record),
68
+ now,
69
+ extraConditions: [
70
+ { key: runtime.keys.header, expectedValue: header.bytes },
71
+ ...input.idempotencyKey === void 0 ? [] : [
72
+ {
73
+ key: runtime.keys.idempotency(input.idempotencyKey),
74
+ expectedValue: expectedBinding
75
+ }
76
+ ]
77
+ ],
78
+ extraOperations: [
79
+ {
80
+ type: "put",
81
+ key: runtime.keys.bySequence(record.sequence),
82
+ value: encodeApplicationReadyEntry(record.commandId)
83
+ },
84
+ headerOperation(runtime.keys, {
85
+ ...header.record,
86
+ nextSequence: header.record.nextSequence + 1,
87
+ openCount: header.record.openCount + 1,
88
+ admittedCount: header.record.admittedCount + 1
89
+ }),
90
+ ...input.idempotencyKey === void 0 ? [] : [
91
+ {
92
+ type: "put",
93
+ key: runtime.keys.idempotency(input.idempotencyKey),
94
+ value: encodeApplicationCommandIdempotencyRecord({
95
+ recordVersion: MAILBOX_RECORD_VERSION,
96
+ commandId: record.commandId,
97
+ identityDigest
98
+ })
99
+ }
100
+ ]
101
+ ]
102
+ })))
103
+ continue;
104
+ return { status: "admitted", receipt: toApplicationCommandReceipt(record) };
105
+ }
106
+ throw new MailboxContentionError("admit", null);
107
+ }
108
+ async function resolveIdempotency(runtime, idempotencyKey, identityDigest) {
109
+ const binding = await loadIdempotencyBinding(runtime.storage, runtime.keys, idempotencyKey);
110
+ if (binding === null)
111
+ return { admission: null, staleBindingBytes: null };
112
+ const loaded = await loadCommand(runtime.storage, runtime.keys, binding.record.commandId);
113
+ if (loaded === null)
114
+ return { admission: null, staleBindingBytes: binding.bytes };
115
+ const ownDigest = await computeIdentityDigest([
116
+ loaded.record.caller,
117
+ loaded.record.target,
118
+ loaded.record.kind,
119
+ loaded.record.payloadDigest
120
+ ]);
121
+ if (loaded.record.idempotencyKey !== idempotencyKey || ownDigest !== binding.record.identityDigest)
122
+ throw new PersistedDataCorruptError(runtime.keys.idempotency(idempotencyKey));
123
+ const receipt = toApplicationCommandReceipt(loaded.record);
124
+ if (binding.record.identityDigest !== identityDigest)
125
+ return {
126
+ admission: { status: "conflict", receipt, reason: "idempotency-identity-mismatch" },
127
+ staleBindingBytes: null
128
+ };
129
+ return { admission: { status: "duplicate", receipt }, staleBindingBytes: null };
130
+ }