@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,97 @@
1
+ /**
2
+ * Deterministic normalization and canonical serialization for workflow
3
+ * contracts.
4
+ *
5
+ * Two contracts that describe the same workflow must produce byte-identical
6
+ * canonical output regardless of how their object keys were ordered in the
7
+ * source, so `contractHash()` and `deriveWorkflowRevision()` identify the
8
+ * *content* rather than an accident of construction. Serialization walks the
9
+ * declared contract shape explicitly instead of generically stringifying the
10
+ * input, which means an unknown extra property can never leak into the
11
+ * canonical bytes and change a hash.
12
+ *
13
+ * @module core/contract/normalize
14
+ */
15
+ import type { WorkflowContract, WorkflowMessageContract } from './types.ts';
16
+ /**
17
+ * Normalize a workflow contract into its canonical in-memory form.
18
+ *
19
+ * Field order follows the declared shape, every open-ended record is
20
+ * rebuilt with its keys sorted (and omitted entirely when empty), and every
21
+ * schema fragment is deep-cloned onto a null-prototype object. The result is
22
+ * a fresh value; the input is not mutated.
23
+ *
24
+ * @example
25
+ * ```ts
26
+ * import { normalizeWorkflowContract } from '@lostgradient/weft';
27
+ *
28
+ * const normalized = normalizeWorkflowContract({
29
+ * name: 'checkout',
30
+ * workflowVersion: '2.1.0',
31
+ * signals: {
32
+ * zeta: {},
33
+ * alpha: {},
34
+ * },
35
+ * });
36
+ * console.log(Object.keys(normalized.signals ?? {})); // ['alpha', 'zeta']
37
+ * ```
38
+ */
39
+ export declare function normalizeWorkflowContract(contract: WorkflowContract): WorkflowContract;
40
+ /**
41
+ * Serialize one signal/update/query/activity contract's schema pair.
42
+ * Shared between {@link canonicalWorkflowContractJson} (the full-identity
43
+ * form) and `hash.ts`'s payload-only serialization, since both walk the same
44
+ * `{ inputSchema?, outputSchema? }` shape — the only difference between the
45
+ * two identities is which *top-level* fields are included, not how a single
46
+ * message/activity entry serializes.
47
+ *
48
+ * @internal Exported for reuse within `core/contract/*`; not part of the
49
+ * package's public API.
50
+ */
51
+ export declare function canonicalMessageContractJson(entry: WorkflowMessageContract): string;
52
+ /**
53
+ * @internal Exported for reuse within `core/contract/*`; not part of the
54
+ * package's public API.
55
+ */
56
+ export declare function canonicalContractRecordJson(record: Readonly<Record<string, WorkflowMessageContract>>): string;
57
+ /**
58
+ * @internal Exported for reuse within `core/contract/*` (`hash.ts`'s
59
+ * payload-only serialization shares this field-appending logic); not part of
60
+ * the package's public API.
61
+ */
62
+ export declare function appendContractRecordField(fields: string[], label: 'signals' | 'updates' | 'queries' | 'activities', record: Readonly<Record<string, WorkflowMessageContract>> | undefined): void;
63
+ /**
64
+ * @internal Exported for reuse within `core/contract/*`; not part of the
65
+ * package's public API.
66
+ */
67
+ export declare function appendSchemaField(fields: string[], label: 'inputSchema' | 'outputSchema', schema: Record<string, unknown> | undefined): void;
68
+ /**
69
+ * Serialize a workflow contract to its canonical, full-identity JSON string
70
+ * — the digest input {@link deriveWorkflowRevision} uses, and the value
71
+ * returned as `WorkflowRevisionManifestParseSuccess.canonicalJson`.
72
+ *
73
+ * This is a *different* identity from {@link contractHash}'s payload-only
74
+ * serialization: it includes `name`, `workflowVersion`, `description`, and
75
+ * `tags`, so a documentation edit changes this output (and therefore
76
+ * `revision`) without changing `contractHash`. The output is byte-identical
77
+ * for equivalent contracts regardless of source key order, and every field
78
+ * this project cares about changes it.
79
+ *
80
+ * @example
81
+ * ```ts
82
+ * import { canonicalWorkflowContractJson } from '@lostgradient/weft';
83
+ *
84
+ * const left = canonicalWorkflowContractJson({
85
+ * name: 'checkout',
86
+ * workflowVersion: '2.1.0',
87
+ * signals: { alpha: {}, zeta: {} },
88
+ * });
89
+ * const right = canonicalWorkflowContractJson({
90
+ * name: 'checkout',
91
+ * workflowVersion: '2.1.0',
92
+ * signals: { zeta: {}, alpha: {} },
93
+ * });
94
+ * console.log(left === right); // true
95
+ * ```
96
+ */
97
+ export declare function canonicalWorkflowContractJson(contract: WorkflowContract): string;
@@ -0,0 +1,127 @@
1
+ import { canonicalJsonStringify } from "../../worker/manifest/canonical-json.js";
2
+ import { WORKFLOW_CONTRACT_VERSION } from "./types.js";
3
+ function sortedKeys(record) {
4
+ return Object.keys(record).toSorted();
5
+ }
6
+ function cloneSchemaFragment(value) {
7
+ if (value === null || typeof value !== "object")
8
+ return value;
9
+ if (Array.isArray(value))
10
+ return value.map((entry) => cloneSchemaFragment(entry));
11
+ const record = value, cloned = Object.create(null);
12
+ for (const key of Object.keys(record))
13
+ cloned[key] = cloneSchemaFragment(record[key]);
14
+ return cloned;
15
+ }
16
+ function cloneSchemaRecord(value) {
17
+ return value === void 0 ? void 0 : cloneSchemaFragment(value);
18
+ }
19
+ function normalizeMessageContract(entry) {
20
+ const normalized = {}, inputSchema = cloneSchemaRecord(entry.inputSchema);
21
+ if (inputSchema !== void 0)
22
+ normalized.inputSchema = inputSchema;
23
+ const outputSchema = cloneSchemaRecord(entry.outputSchema);
24
+ if (outputSchema !== void 0)
25
+ normalized.outputSchema = outputSchema;
26
+ return normalized;
27
+ }
28
+ function normalizeActivityContract(entry) {
29
+ return normalizeMessageContract(entry);
30
+ }
31
+ function sortedContractRecord(record, normalizeValue) {
32
+ if (record === void 0)
33
+ return;
34
+ const keys = sortedKeys(record);
35
+ if (keys.length === 0)
36
+ return;
37
+ const normalized = Object.create(null);
38
+ for (const key of keys)
39
+ normalized[key] = normalizeValue(record[key]);
40
+ return normalized;
41
+ }
42
+ function applyDescriptionAndTags(draft, contract) {
43
+ if (contract.description !== void 0)
44
+ draft.description = contract.description;
45
+ if (contract.tags !== void 0 && contract.tags.length > 0)
46
+ draft.tags = [...contract.tags].toSorted();
47
+ }
48
+ function applySchemas(draft, contract) {
49
+ const inputSchema = cloneSchemaRecord(contract.inputSchema);
50
+ if (inputSchema !== void 0)
51
+ draft.inputSchema = inputSchema;
52
+ const outputSchema = cloneSchemaRecord(contract.outputSchema);
53
+ if (outputSchema !== void 0)
54
+ draft.outputSchema = outputSchema;
55
+ }
56
+ function applyMessageRecords(draft, contract) {
57
+ const signals = sortedContractRecord(contract.signals, normalizeMessageContract);
58
+ if (signals !== void 0)
59
+ draft.signals = signals;
60
+ const updates = sortedContractRecord(contract.updates, normalizeMessageContract);
61
+ if (updates !== void 0)
62
+ draft.updates = updates;
63
+ const queries = sortedContractRecord(contract.queries, normalizeMessageContract);
64
+ if (queries !== void 0)
65
+ draft.queries = queries;
66
+ }
67
+ export function normalizeWorkflowContract(contract) {
68
+ const draft = {
69
+ name: contract.name,
70
+ workflowVersion: contract.workflowVersion
71
+ };
72
+ applyDescriptionAndTags(draft, contract);
73
+ applySchemas(draft, contract);
74
+ applyMessageRecords(draft, contract);
75
+ const activities = sortedContractRecord(contract.activities, normalizeActivityContract);
76
+ if (activities !== void 0)
77
+ draft.activities = activities;
78
+ if (contract.finalizer !== void 0)
79
+ draft.finalizer = normalizeActivityContract(contract.finalizer);
80
+ return draft;
81
+ }
82
+ export function canonicalMessageContractJson(entry) {
83
+ const fields = [];
84
+ if (entry.inputSchema !== void 0)
85
+ fields.push(`"inputSchema":${canonicalJsonStringify(entry.inputSchema)}`);
86
+ if (entry.outputSchema !== void 0)
87
+ fields.push(`"outputSchema":${canonicalJsonStringify(entry.outputSchema)}`);
88
+ return `{${fields.join(",")}}`;
89
+ }
90
+ export function canonicalContractRecordJson(record) {
91
+ return `{${sortedKeys(record).map((key) => `${JSON.stringify(key)}:${canonicalMessageContractJson(record[key])}`).join(",")}}`;
92
+ }
93
+ export function appendContractRecordField(fields, label, record) {
94
+ if (record === void 0 || Object.keys(record).length === 0)
95
+ return;
96
+ fields.push(`"${label}":${canonicalContractRecordJson(record)}`);
97
+ }
98
+ export function appendSchemaField(fields, label, schema) {
99
+ if (schema === void 0)
100
+ return;
101
+ fields.push(`"${label}":${canonicalJsonStringify(schema)}`);
102
+ }
103
+ function appendTagsField(fields, tags) {
104
+ if (tags === void 0 || tags.length === 0)
105
+ return;
106
+ const sortedTags = [...tags].toSorted().map((tag) => JSON.stringify(tag));
107
+ fields.push(`"tags":[${sortedTags.join(",")}]`);
108
+ }
109
+ export function canonicalWorkflowContractJson(contract) {
110
+ const fields = [
111
+ `"contractVersion":${JSON.stringify(WORKFLOW_CONTRACT_VERSION)}`,
112
+ `"name":${JSON.stringify(contract.name)}`,
113
+ `"workflowVersion":${JSON.stringify(contract.workflowVersion)}`
114
+ ];
115
+ if (contract.description !== void 0)
116
+ fields.push(`"description":${JSON.stringify(contract.description)}`);
117
+ appendTagsField(fields, contract.tags);
118
+ appendSchemaField(fields, "inputSchema", contract.inputSchema);
119
+ appendSchemaField(fields, "outputSchema", contract.outputSchema);
120
+ appendContractRecordField(fields, "signals", contract.signals);
121
+ appendContractRecordField(fields, "updates", contract.updates);
122
+ appendContractRecordField(fields, "queries", contract.queries);
123
+ appendContractRecordField(fields, "activities", contract.activities);
124
+ if (contract.finalizer !== void 0)
125
+ fields.push(`"finalizer":${canonicalMessageContractJson(contract.finalizer)}`);
126
+ return `{${fields.join(",")}}`;
127
+ }
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Content-derived workflow revision identity.
3
+ *
4
+ * `revision` is the broader identity companion to `contractHash`: it hashes
5
+ * the *entire* normalized contract — `name`, `workflowVersion`,
6
+ * `description`, and `tags` included — so it changes whenever anything
7
+ * about the definition changes, including documentation. This is the same
8
+ * formula the (now-refactored) `buildWorkerManifestFromRegistry()` used for
9
+ * its `workflowRevision` field before this module existed.
10
+ *
11
+ * @module core/contract/revision
12
+ */
13
+ import type { WorkflowContract } from './types.ts';
14
+ /**
15
+ * Derive a content-addressed revision identity for a workflow contract.
16
+ *
17
+ * Two calls on an equivalent contract (regardless of source key order)
18
+ * produce the same revision, and any field the full canonical serialization
19
+ * carries — including `description` and `tags` — changes it.
20
+ *
21
+ * @example
22
+ * ```ts
23
+ * import { deriveWorkflowRevision } from '@lostgradient/weft';
24
+ *
25
+ * const revision = await deriveWorkflowRevision({ name: 'checkout', workflowVersion: '2.1.0' });
26
+ * console.log(revision.startsWith('sha256:')); // true
27
+ * ```
28
+ */
29
+ export declare function deriveWorkflowRevision(contract: WorkflowContract): Promise<string>;
@@ -0,0 +1,5 @@
1
+ import { digestCanonicalWorkflowContract } from "./hash.js";
2
+ import { canonicalWorkflowContractJson } from "./normalize.js";
3
+ export async function deriveWorkflowRevision(contract) {
4
+ return digestCanonicalWorkflowContract(canonicalWorkflowContractJson(contract));
5
+ }
@@ -0,0 +1,274 @@
1
+ /**
2
+ * Canonical, normalized workflow contract vocabulary.
3
+ *
4
+ * A `WorkflowContract` is the single normalized representation that feeds
5
+ * both TypeScript code generation (`weft codegen`) and `contractHash()` — the
6
+ * same data, described once, rather than two independent derivations that
7
+ * could silently drift apart. `WorkflowRevisionManifest` pairs that contract
8
+ * with the two identity questions a consumer asks about a workflow revision:
9
+ *
10
+ * | Field | Question answered | Stability |
11
+ * | -------------- | ----------------------------------------------------- | ----------------------------- |
12
+ * | `contractHash` | Which public payload contract does this revision use? | Deterministic, payload-only |
13
+ * | `revision` | Which contract-metadata identity (name, version, docs) is this? | Deterministic or author-set |
14
+ *
15
+ * `contractHash` deliberately excludes `name`, `workflowVersion`,
16
+ * `description`, and `tags` — those identify *which* workflow and *how it is
17
+ * documented*, not *what callers may send and expect back*. `revision` is the
18
+ * broader identity: it changes on a documentation edit even when the payload
19
+ * contract does not, which is what lets a caller detect "the same contract,
20
+ * redeployed" versus "a genuinely different definition was loaded."
21
+ *
22
+ * @module core/contract/types
23
+ */
24
+ import type { DefinitionSchema } from '../types/definition-schema.ts';
25
+ /**
26
+ * Domain separator folded into every `contractHash()`/`deriveWorkflowRevision()`
27
+ * digest. Bumping this constant is how a future normalization change is
28
+ * guaranteed to produce a different hash rather than silently colliding with
29
+ * one computed under the old rules.
30
+ *
31
+ * @example
32
+ * ```ts
33
+ * import { WORKFLOW_CONTRACT_VERSION } from '@lostgradient/weft';
34
+ *
35
+ * console.log(WORKFLOW_CONTRACT_VERSION); // 1
36
+ * ```
37
+ */
38
+ export declare const WORKFLOW_CONTRACT_VERSION = 1;
39
+ /**
40
+ * Normalized JSON Schema pair carried by one workflow signal, update, or
41
+ * query.
42
+ *
43
+ * @example
44
+ * ```ts
45
+ * import type { WorkflowMessageContract } from '@lostgradient/weft';
46
+ *
47
+ * const approval: WorkflowMessageContract = {
48
+ * inputSchema: { type: 'object', properties: { approved: { type: 'boolean' } } },
49
+ * };
50
+ * console.log(approval.inputSchema?.['type']);
51
+ * ```
52
+ */
53
+ export type WorkflowMessageContract = Readonly<{
54
+ /** Normalized JSON Schema describing accepted input, when the message accepts one. */
55
+ inputSchema?: Record<string, unknown>;
56
+ /** Normalized JSON Schema describing the returned value, when the message returns one. */
57
+ outputSchema?: Record<string, unknown>;
58
+ }>;
59
+ /**
60
+ * Normalized JSON Schema pair carried by one activity a workflow contract
61
+ * exposes.
62
+ *
63
+ * @example
64
+ * ```ts
65
+ * import type { WorkflowActivityContract } from '@lostgradient/weft';
66
+ *
67
+ * const charge: WorkflowActivityContract = {
68
+ * inputSchema: { type: 'object', properties: { amount: { type: 'number' } } },
69
+ * outputSchema: { type: 'object', properties: { id: { type: 'string' } } },
70
+ * };
71
+ * console.log(charge.inputSchema?.['type']);
72
+ * ```
73
+ */
74
+ export type WorkflowActivityContract = Readonly<{
75
+ /** Normalized JSON Schema describing accepted input, when the activity accepts one. */
76
+ inputSchema?: Record<string, unknown>;
77
+ /** Normalized JSON Schema describing the returned value, when the activity returns one. */
78
+ outputSchema?: Record<string, unknown>;
79
+ }>;
80
+ /**
81
+ * Canonical, normalized representation of one workflow's public contract —
82
+ * everything callers may send it and expect back, plus enough identity
83
+ * metadata (`name`, `workflowVersion`, `description`, `tags`) to describe
84
+ * which workflow this is. This is the single input to both TypeScript
85
+ * emission and `contractHash()`.
86
+ *
87
+ * Every open-ended record (`signals`, `updates`, `queries`, `activities`) is
88
+ * omitted entirely rather than present-but-empty, matching the registry
89
+ * snapshot's "absent fields omitted, never `null` or `{}`" convention — see
90
+ * {@link normalizeWorkflowContract}.
91
+ *
92
+ * @example
93
+ * ```ts
94
+ * import type { WorkflowContract } from '@lostgradient/weft';
95
+ *
96
+ * const checkout: WorkflowContract = {
97
+ * name: 'checkout',
98
+ * workflowVersion: '2.1.0',
99
+ * inputSchema: { type: 'object', properties: { cartId: { type: 'string' } } },
100
+ * activities: {
101
+ * charge: { inputSchema: { type: 'object', properties: { amount: { type: 'number' } } } },
102
+ * },
103
+ * };
104
+ * console.log(checkout.name);
105
+ * ```
106
+ */
107
+ export type WorkflowContract = Readonly<{
108
+ /** Wire-safe workflow name. */
109
+ name: string;
110
+ /** Semantic replay-compatibility boundary declared by the workflow author. */
111
+ workflowVersion: string;
112
+ /** User-facing description. Excluded from `contractHash()`; included in `revision`. */
113
+ description?: string;
114
+ /** User-facing grouping tags. Excluded from `contractHash()`; included in `revision`. */
115
+ tags?: ReadonlyArray<string>;
116
+ /** Normalized JSON Schema describing accepted workflow input, when declared. */
117
+ inputSchema?: Record<string, unknown>;
118
+ /** Normalized JSON Schema describing the workflow result, when declared. */
119
+ outputSchema?: Record<string, unknown>;
120
+ /** Signal contracts keyed by canonical signal name. */
121
+ signals?: Readonly<Record<string, WorkflowMessageContract>>;
122
+ /** Update contracts keyed by canonical update name. */
123
+ updates?: Readonly<Record<string, WorkflowMessageContract>>;
124
+ /** Query contracts keyed by canonical query name. */
125
+ queries?: Readonly<Record<string, WorkflowMessageContract>>;
126
+ /** Activity contracts keyed by canonical activity name. */
127
+ activities?: Readonly<Record<string, WorkflowActivityContract>>;
128
+ /** Contract of the workflow's definition-level finalizer activity, when declared. */
129
+ finalizer?: WorkflowActivityContract;
130
+ }>;
131
+ /**
132
+ * Structural shape one signal, update, or query source must satisfy for
133
+ * {@link buildWorkflowContract} to convert it. Deliberately narrower than
134
+ * `SignalDefinition`/`UpdateDefinition`/`QueryDefinition` — only the schema
135
+ * metadata those conversions need — so any of the three handle types (and
136
+ * any structurally equivalent value) satisfies it without a cast.
137
+ *
138
+ * @example
139
+ * ```ts
140
+ * import { signal } from '@lostgradient/weft';
141
+ * import type { WorkflowContractMessageSource } from '@lostgradient/weft';
142
+ *
143
+ * const approval = signal('approval');
144
+ * const source: WorkflowContractMessageSource = approval;
145
+ * console.log(source.inputSchema === undefined);
146
+ * ```
147
+ */
148
+ export interface WorkflowContractMessageSource {
149
+ /**
150
+ * The message's own wire name, as recorded by `signal()`/`update()`/`query()`
151
+ * and used by `normalizeMessageDefinitions()` (`core/engine/registration.ts`)
152
+ * to key the registered message — not necessarily the JS object key the
153
+ * caller used in `.signals({...})`/`.updates({...})`/`.queries({...})`,
154
+ * which may alias a different local name. {@link buildWorkflowContract}
155
+ * keys `WorkflowContract.signals`/`updates`/`queries` by this field so the
156
+ * built contract matches what the registry and codegen actually expose.
157
+ */
158
+ readonly name: string;
159
+ readonly inputSchema?: DefinitionSchema;
160
+ readonly outputSchema?: DefinitionSchema;
161
+ }
162
+ /**
163
+ * Structural shape one activity or finalizer source must satisfy for
164
+ * {@link buildWorkflowContract} to convert it. Requires `name` — shared with
165
+ * every real activity source type — specifically so a `WorkflowDefinition`'s
166
+ * `finalizer` field (declared as the narrower `AnyActivityDefinition`, which
167
+ * does not itself declare `inputSchema`/`outputSchema`) remains structurally
168
+ * assignable here: TypeScript's weak-type check requires at least one
169
+ * property in common between source and target when every target property is
170
+ * optional, and `name` is that shared property.
171
+ *
172
+ * @example
173
+ * ```ts
174
+ * import { activity } from '@lostgradient/weft';
175
+ * import type { WorkflowContractActivitySource } from '@lostgradient/weft';
176
+ *
177
+ * const charge = activity({ name: 'charge', execute: async (input: number) => input });
178
+ * const source: WorkflowContractActivitySource = charge;
179
+ * console.log(source.name);
180
+ * ```
181
+ */
182
+ export interface WorkflowContractActivitySource {
183
+ readonly name: string;
184
+ readonly inputSchema?: DefinitionSchema;
185
+ readonly outputSchema?: DefinitionSchema;
186
+ }
187
+ /**
188
+ * Authoring-time input accepted by {@link buildWorkflowContract} — the
189
+ * narrowest structural shape that both `WorkflowDefinition` and
190
+ * `BuiltWorkflowDefinition` already satisfy, so neither type is imported here
191
+ * and no coupling is introduced between this module and the workflow builder.
192
+ *
193
+ * @example
194
+ * ```ts
195
+ * import { workflow } from '@lostgradient/weft';
196
+ * import type { WorkflowContractSource } from '@lostgradient/weft';
197
+ *
198
+ * const greet = workflow({ name: 'greet', version: '1.0.0' }).execute(
199
+ * async function* (_ctx, input: string) {
200
+ * return `hello ${input}`;
201
+ * },
202
+ * );
203
+ * const source: WorkflowContractSource = greet;
204
+ * console.log(source.name);
205
+ * ```
206
+ */
207
+ export interface WorkflowContractSource {
208
+ readonly name: string;
209
+ readonly version?: string;
210
+ readonly description?: string;
211
+ readonly tags?: ReadonlyArray<string>;
212
+ readonly inputSchema?: DefinitionSchema;
213
+ readonly outputSchema?: DefinitionSchema;
214
+ readonly signals?: Readonly<Record<string, WorkflowContractMessageSource>>;
215
+ readonly updates?: Readonly<Record<string, WorkflowContractMessageSource>>;
216
+ readonly queries?: Readonly<Record<string, WorkflowContractMessageSource>>;
217
+ readonly activities?: Readonly<Record<string, WorkflowContractActivitySource>>;
218
+ readonly finalizer?: WorkflowContractActivitySource;
219
+ }
220
+ /**
221
+ * Current workflow revision manifest schema version. An unknown value is
222
+ * rejected by {@link parseWorkflowRevisionManifest} before any other field is
223
+ * read, the same "reject rather than best-effort parse" contract
224
+ * `WORKER_MANIFEST_VERSION` uses.
225
+ *
226
+ * @example
227
+ * ```ts
228
+ * import { WORKFLOW_REVISION_MANIFEST_VERSION } from '@lostgradient/weft';
229
+ *
230
+ * console.log(WORKFLOW_REVISION_MANIFEST_VERSION); // 1
231
+ * ```
232
+ */
233
+ export declare const WORKFLOW_REVISION_MANIFEST_VERSION = 1;
234
+ /**
235
+ * A workflow contract paired with its two identity answers: the
236
+ * payload-only `contractHash` and the broader `revision`.
237
+ *
238
+ * `revision` is an opaque label: content-derived by {@link deriveWorkflowRevision}
239
+ * by default, or explicitly supplied. {@link parseWorkflowRevisionManifest}
240
+ * recomputes and checks `contractHash` on every parse, but never recomputes
241
+ * `revision` — an explicitly supplied revision is a caller assertion, not a
242
+ * value this module can verify.
243
+ *
244
+ * @example
245
+ * ```ts
246
+ * import { WORKFLOW_REVISION_MANIFEST_VERSION, buildWorkflowContract } from '@lostgradient/weft';
247
+ * import type { WorkflowRevisionManifest } from '@lostgradient/weft';
248
+ *
249
+ * const contract = buildWorkflowContract({ name: 'checkout', version: '2.1.0' });
250
+ * const manifest: WorkflowRevisionManifest = {
251
+ * manifestVersion: WORKFLOW_REVISION_MANIFEST_VERSION,
252
+ * name: contract.name,
253
+ * workflowVersion: contract.workflowVersion,
254
+ * revision: 'sha256:placeholder',
255
+ * contractHash: 'sha256:placeholder',
256
+ * contract,
257
+ * };
258
+ * console.log(manifest.name);
259
+ * ```
260
+ */
261
+ export type WorkflowRevisionManifest = Readonly<{
262
+ /** Manifest schema version; unknown values are rejected, not tolerated. */
263
+ manifestVersion: typeof WORKFLOW_REVISION_MANIFEST_VERSION;
264
+ /** Wire-safe workflow name; must equal `contract.name`. */
265
+ name: string;
266
+ /** Semantic replay-compatibility boundary; must equal `contract.workflowVersion`. */
267
+ workflowVersion: string;
268
+ /** Content-derived or explicitly supplied opaque revision identity. */
269
+ revision: string;
270
+ /** Deterministic payload-only contract identity, verified on every parse. */
271
+ contractHash: string;
272
+ /** The normalized workflow contract this manifest describes. */
273
+ contract: WorkflowContract;
274
+ }>;
@@ -0,0 +1 @@
1
+ export const WORKFLOW_CONTRACT_VERSION = 1, WORKFLOW_REVISION_MANIFEST_VERSION = 1;
@@ -0,0 +1,40 @@
1
+ /**
2
+ * `activateCatalogRevisionCandidate` — a thin engine-level wrapper around
3
+ * `WorkflowCatalog.activateCandidate()`, the guarded activation primitive
4
+ * (WFT-9/WFT-10). Awaits catalog readiness, reads pre-activation state,
5
+ * calls the guarded primitive, dispatches the correct catalog event(s), and
6
+ * returns the primitive's own structured result verbatim:
7
+ * the shared installed/activated/draining helper on success, or
8
+ * `WorkflowRevisionActivationRejectedEvent` directly on refusal.
9
+ *
10
+ * `engine.workflows.activate()` (WFT-11,
11
+ * `core/engine/engine-workflows-namespace.ts`) is this wrapper's production
12
+ * caller — the only practical way an external caller reaches the guarded
13
+ * candidate-activation primitive, so routing it through here (rather than
14
+ * calling `WorkflowCatalog.activateCandidate()` directly) is what makes a
15
+ * manual activation dispatch `catalog:revision-installed`/
16
+ * `catalog:revision-activated`/`catalog:revision-draining`/
17
+ * `catalog:activation-rejected` the same way `engine.register()`'s
18
+ * drain path already does.
19
+ *
20
+ * Never imports `./index.ts` as a value (only as a type, matching
21
+ * `catalog-readiness.ts`'s own import-cycle discipline for itself) — the
22
+ * `Engine` class import here is `import type`, erased at build time.
23
+ *
24
+ * @module core/engine/catalog-activation
25
+ */
26
+ import type { ActivateCandidateOptions, WorkflowCatalogActivationResult } from '../catalog/index.ts';
27
+ import type { WorkflowRevisionManifest } from '../contract/types.ts';
28
+ import type { Engine } from './index.ts';
29
+ /**
30
+ * Activate `candidateManifest` for `name` through the catalog's guarded
31
+ * primitive (`checkWorkflowCompatibility`-gated, single-shot CAS), and
32
+ * return its structured result verbatim. On success, dispatches
33
+ * `catalog:revision-installed` (when genuinely new content),
34
+ * `catalog:revision-draining` (when displacing a prior active revision),
35
+ * and `catalog:revision-activated`. On refusal, dispatches
36
+ * `catalog:activation-rejected` carrying only the bounded `reason` code
37
+ * (and, for `'incompatible'`, the bounded `incompatibilityReasons` array) —
38
+ * never the full `WorkflowCompatibilityVerdict` object.
39
+ */
40
+ export declare function activateCatalogRevisionCandidate(engine: Engine, name: string, candidateManifest: WorkflowRevisionManifest, options?: ActivateCandidateOptions): Promise<WorkflowCatalogActivationResult>;
@@ -0,0 +1,17 @@
1
+ import { WorkflowRevisionActivationRejectedEvent } from "../events/catalog-events.js";
2
+ import { dispatchCatalogInstallAndActivatedEvents } from "./catalog-events.js";
3
+ import { ensureWorkflowCatalogReady, getWorkflowCatalog } from "./catalog-readiness.js";
4
+ export async function activateCatalogRevisionCandidate(engine, name, candidateManifest, options) {
5
+ await ensureWorkflowCatalogReady(engine);
6
+ const catalog = getWorkflowCatalog(engine), preExisting = await catalog.hasInstalled(name, candidateManifest.revision), pointerBefore = await catalog.resolveActiveDurable(name) ?? null, result = await catalog.activateCandidate(name, candidateManifest, options);
7
+ if (result.applied) {
8
+ dispatchCatalogInstallAndActivatedEvents(engine, name, candidateManifest.revision, preExisting, pointerBefore, result.pointer);
9
+ return result;
10
+ }
11
+ if (result.reason === "incompatible") {
12
+ engine.dispatchEvent(new WorkflowRevisionActivationRejectedEvent(name, candidateManifest.revision, result.reason, result.verdict.compatible ? void 0 : result.verdict.reasons));
13
+ return result;
14
+ }
15
+ engine.dispatchEvent(new WorkflowRevisionActivationRejectedEvent(name, candidateManifest.revision, result.reason));
16
+ return result;
17
+ }
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Shared installed/activated/draining event-dispatch helper (WFT-12), used
3
+ * by BOTH producers of catalog activation: `catalog-readiness.ts`'s
4
+ * `drainPendingCatalogInstalls` (the `engine.register()`-drain path) and
5
+ * `catalog-activation.ts`'s `activateCatalogRevisionCandidate` (the guarded
6
+ * primitive). The two producers return different result shapes
7
+ * (`activateRegistered` always succeeds and returns a bare pointer;
8
+ * `activateCandidate` returns a union that can also refuse) — this helper
9
+ * takes already-normalized before/after pointer values instead of either
10
+ * raw return type, so it stays agnostic to which producer called it.
11
+ * `activation-rejected` is NOT dispatched here — only `activateCandidate`
12
+ * can refuse, so its one caller dispatches that event itself.
13
+ *
14
+ * @module core/engine/catalog-events
15
+ */
16
+ import type { WorkflowCatalogActivePointer } from '../catalog/index.ts';
17
+ import type { Engine } from './index.ts';
18
+ /**
19
+ * Dispatch `catalog:revision-installed` (only when `preExisting` is
20
+ * `false` — genuinely new content, not a byte-identical reinstall or a
21
+ * cross-process durable adoption of already-present content), then decide
22
+ * activated/draining from how `pointerBefore` and `pointerAfter` compare:
23
+ *
24
+ * - Identical `revision` AND `generation` (a true no-op — nothing was
25
+ * durably written, e.g. `activateRegistered`'s own no-op branch): neither
26
+ * fires.
27
+ * - Same `revision`, different `generation` (a reactivation that still
28
+ * bumped the fencing counter, e.g. `activateCandidate` re-activating the
29
+ * currently active revision): `catalog:revision-activated` fires with
30
+ * `previousRevision: undefined` — nothing was actually displaced, so
31
+ * there is nothing to drain.
32
+ * - Different `revision`: `catalog:revision-draining` for `pointerBefore`
33
+ * (when it existed) followed by `catalog:revision-activated` for
34
+ * `pointerAfter`, `previousRevision` set to the displaced revision.
35
+ */
36
+ export declare function dispatchCatalogInstallAndActivatedEvents(engine: Engine, name: string, revision: string, preExisting: boolean, pointerBefore: WorkflowCatalogActivePointer | null, pointerAfter: WorkflowCatalogActivePointer): void;
@@ -0,0 +1,15 @@
1
+ import {
2
+ WorkflowRevisionActivatedEvent,
3
+ WorkflowRevisionDrainingEvent,
4
+ WorkflowRevisionInstalledEvent
5
+ } from "../events/catalog-events.js";
6
+ export function dispatchCatalogInstallAndActivatedEvents(engine, name, revision, preExisting, pointerBefore, pointerAfter) {
7
+ if (!preExisting)
8
+ engine.dispatchEvent(new WorkflowRevisionInstalledEvent(name, revision));
9
+ if (pointerBefore !== null && pointerBefore.revision === pointerAfter.revision && pointerBefore.generation === pointerAfter.generation)
10
+ return;
11
+ const previousRevision = pointerBefore !== null && pointerBefore.revision !== pointerAfter.revision ? pointerBefore.revision : void 0;
12
+ if (previousRevision !== void 0)
13
+ engine.dispatchEvent(new WorkflowRevisionDrainingEvent(name, previousRevision));
14
+ engine.dispatchEvent(new WorkflowRevisionActivatedEvent(name, pointerAfter.revision, pointerAfter.generation, previousRevision));
15
+ }