@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,32 @@
1
+ /**
2
+ * Projects a converted {@link RegistryWorkflowEntry} into the
3
+ * `core/contract` {@link WorkflowContract} shape {@link buildRegistrySnapshot}
4
+ * feeds to `buildWorkflowRevisionManifest`.
5
+ *
6
+ * Split out of `core/registry-snapshot.ts` specifically to stay under the
7
+ * repository's implementation-file-size ceiling once WFT-6's workflow-scoped
8
+ * activity folding (`buildRegistrySnapshot` reading
9
+ * `Engine.listWorkflowActivityDefinitions`) was added there.
10
+ *
11
+ * @module core/registry-workflow-contract-draft
12
+ */
13
+ import type { WorkflowActivityContract, WorkflowContract } from './contract/index.ts';
14
+ import type { RegistryWorkflowEntry } from './registry-snapshot.ts';
15
+ /**
16
+ * Project a converted {@link RegistryWorkflowEntry} (schemas already turned
17
+ * into JSON Schema by `buildWorkflowEntry`) into the `core/contract`
18
+ * {@link WorkflowContract} shape `buildWorkflowRevisionManifest` consumes.
19
+ * Deliberately does not re-run schema conversion — `entry`'s schemas are
20
+ * already `Record<string, unknown>` JSON Schema, structurally identical to
21
+ * what `WorkflowContract` expects, so re-converting through
22
+ * `buildWorkflowContract` (which expects raw `DefinitionSchema`) would
23
+ * double-convert and risk a different error shape for the same failure.
24
+ *
25
+ * `workflowScopedActivities`, when non-empty, becomes the draft's
26
+ * `activities` — the workflow's own `.activities({...})` registrations
27
+ * (`Engine.listWorkflowActivityDefinitions`), never the flat,
28
+ * workflow-independent `RegistrySnapshot.activities` catalog. Omitted
29
+ * (rather than `{}`) when empty, matching this module's "absent fields
30
+ * omitted" convention.
31
+ */
32
+ export declare function toWorkflowContractDraft(workflowType: string, workflowVersion: string, entry: RegistryWorkflowEntry, workflowScopedActivities: Readonly<Record<string, WorkflowActivityContract>>): WorkflowContract;
@@ -0,0 +1,28 @@
1
+ function applyDraftSchemas(draft, entry) {
2
+ if (entry.description !== void 0)
3
+ draft.description = entry.description;
4
+ if (entry.tags !== void 0 && entry.tags.length > 0)
5
+ draft.tags = entry.tags;
6
+ if (entry.inputSchema !== void 0)
7
+ draft.inputSchema = entry.inputSchema;
8
+ if (entry.outputSchema !== void 0)
9
+ draft.outputSchema = entry.outputSchema;
10
+ }
11
+ function applyDraftMessages(draft, entry) {
12
+ if (entry.signals !== void 0 && Object.keys(entry.signals).length > 0)
13
+ draft.signals = entry.signals;
14
+ if (entry.updates !== void 0 && Object.keys(entry.updates).length > 0)
15
+ draft.updates = entry.updates;
16
+ if (entry.queries !== void 0 && Object.keys(entry.queries).length > 0)
17
+ draft.queries = entry.queries;
18
+ }
19
+ export function toWorkflowContractDraft(workflowType, workflowVersion, entry, workflowScopedActivities) {
20
+ const draft = { name: workflowType, workflowVersion };
21
+ applyDraftSchemas(draft, entry);
22
+ applyDraftMessages(draft, entry);
23
+ if (entry.finalizer !== void 0)
24
+ draft.finalizer = entry.finalizer;
25
+ if (Object.keys(workflowScopedActivities).length > 0)
26
+ draft.activities = workflowScopedActivities;
27
+ return draft;
28
+ }
@@ -0,0 +1,122 @@
1
+ /**
2
+ * Build one registered workflow's {@link WorkflowRevisionManifest} — the
3
+ * per-workflow entry/message/scoped-activity conversion `buildRegistrySnapshot`
4
+ * (`registry-snapshot.ts`) folds into every manifest in a full snapshot, and
5
+ * that {@link buildWorkflowManifestForType} exposes standalone for a caller
6
+ * that wants one or a few workflows' manifests without reading, hashing, or
7
+ * being bounded by the rest of the engine's registrations.
8
+ *
9
+ * Split out of `registry-snapshot.ts` specifically so `buildWorkerManifestFromRegistry`
10
+ * (`worker/manifest/registry-contract-builder.ts`) can depend on
11
+ * {@link buildWorkflowManifestForType} without also inheriting
12
+ * `buildRegistrySnapshot`'s full-snapshot `RegistryWorkflowCountLimitError`
13
+ * aggregate check, or an *unrelated* registered workflow's own
14
+ * {@link RegistryManifestLimitError} — neither is the right contract for a
15
+ * caller that only ever looks up the handful of workflows it names.
16
+ *
17
+ * @module core/registry-workflow-manifest
18
+ */
19
+ import type { ActivityMetadata } from './activity-registry.ts';
20
+ import { type WorkflowRevisionManifest } from './contract/index.ts';
21
+ import type { Engine } from './engine.ts';
22
+ import type { RegisteredWorkflowDefinition } from './types/workflow-registry.ts';
23
+ import { WeftError } from './weft-error.ts';
24
+ /** Schema metadata reported for a statically registered workflow message. */
25
+ export type RegistryMessageEntry = {
26
+ inputSchema?: Record<string, unknown>;
27
+ outputSchema?: Record<string, unknown>;
28
+ };
29
+ /** Metadata reported per workflow in a registry snapshot. */
30
+ export type RegistryWorkflowEntry = {
31
+ inputSchema?: Record<string, unknown>;
32
+ outputSchema?: Record<string, unknown>;
33
+ description?: string;
34
+ tags?: ReadonlyArray<string>;
35
+ signals?: Record<string, RegistryMessageEntry>;
36
+ updates?: Record<string, RegistryMessageEntry>;
37
+ queries?: Record<string, RegistryMessageEntry>;
38
+ /** Schema metadata for the workflow's definition-level finalizer activity, when registered. */
39
+ finalizer?: RegistryMessageEntry;
40
+ };
41
+ /**
42
+ * Thrown when a registered workflow's contract cannot be published as a
43
+ * {@link WorkflowRevisionManifest} because it exceeds one of the WFT-5
44
+ * hostile-input limits (`core/contract/limits.ts`) — an identifier over
45
+ * `MAX_CONTRACT_IDENTIFIER_BYTES`, too many signal/update/query/activity
46
+ * entries, a schema nested past `MAX_CONTRACT_SCHEMA_DEPTH`, or a
47
+ * normalized contract over `MAX_NORMALIZED_CONTRACT_BYTES`. Nothing in
48
+ * engine registration enforces those bounds (`name-grammar.ts` has no
49
+ * length cap; `description`/`tags`/`version`/schema depth are unbounded at
50
+ * registration time), so a registration the engine happily accepts can
51
+ * still fail here, at manifest-build time. Mirrors
52
+ * `RegistrySchemaConversionError`'s masked-500 handling in
53
+ * `server/operations/get-registry.ts`: the wire response stays a generic
54
+ * `500 / Internal server error`, and `workflowType` plus the underlying
55
+ * limit reason reach server-side logs only.
56
+ */
57
+ export declare class RegistryManifestLimitError extends WeftError<'RegistryManifestLimitError'> {
58
+ readonly workflowType: string;
59
+ constructor(workflowType: string, cause: unknown);
60
+ }
61
+ /**
62
+ * Build one workflow definition's {@link WorkflowRevisionManifest} from its
63
+ * already-resolved scoped activity metadata, folding in its
64
+ * `.activities({...})`-scoped registrations (WFT-6). This is the shared
65
+ * normalization core both {@link buildOneWorkflowManifest} (the eager
66
+ * `engine.register()` drain path, which looks `activityDefinitions` up from
67
+ * the engine's registry) and the dynamic workflow-source loader path
68
+ * (WFT-13/14, `core/source/validate.ts`, which has no committed `Engine`
69
+ * registration to look up from) route through — so a workflow registered
70
+ * both eagerly and lazily from logically identical content always produces
71
+ * byte-identical manifests, never two independently-derived contracts that
72
+ * could disagree.
73
+ *
74
+ * Throws {@link RegistryManifestLimitError} if `definition`'s contract
75
+ * exceeds a WFT-5 hostile-input limit.
76
+ *
77
+ * @example
78
+ * ```ts
79
+ * import { Engine } from '@lostgradient/weft';
80
+ *
81
+ * declare const engine: Engine;
82
+ * const definition = engine.getWorkflowDefinition('checkout');
83
+ * void definition;
84
+ * ```
85
+ */
86
+ export declare function buildWorkflowManifestFromDefinition(definition: RegisteredWorkflowDefinition, activityDefinitions: readonly ActivityMetadata[]): Promise<WorkflowRevisionManifest>;
87
+ /**
88
+ * Build one registered workflow's {@link WorkflowRevisionManifest}, folding
89
+ * in its `.activities({...})`-scoped registrations (WFT-6). Shared by
90
+ * `buildRegistrySnapshot`'s per-workflow `Promise.all` and
91
+ * {@link buildWorkflowManifestForType}'s single-workflow lookup, so the two
92
+ * call paths can never disagree on what one workflow's manifest contains.
93
+ * A thin wrapper around {@link buildWorkflowManifestFromDefinition} that
94
+ * resolves `activityDefinitions` from `engine`'s own registry.
95
+ *
96
+ * Throws {@link RegistryManifestLimitError} if `definition`'s contract
97
+ * exceeds a WFT-5 hostile-input limit.
98
+ */
99
+ export declare function buildOneWorkflowManifest(engine: Engine, definition: RegisteredWorkflowDefinition): Promise<WorkflowRevisionManifest>;
100
+ /**
101
+ * Build a single registered workflow's {@link WorkflowRevisionManifest} —
102
+ * the scoped counterpart to `buildRegistrySnapshot` for a caller that wants
103
+ * one or a few workflows' manifests without reading, hashing, or being
104
+ * bounded by the rest of the engine's registrations.
105
+ * `buildWorkerManifestFromRegistry` (`worker/manifest/registry-contract-builder.ts`)
106
+ * is exactly that caller: it resolves only the workflows its own
107
+ * caller-declared `options.workflows` names, so neither
108
+ * `RegistryWorkflowCountLimitError` (an aggregate, whole-snapshot concern)
109
+ * nor an unrelated registration's own {@link RegistryManifestLimitError}
110
+ * should ever block it from producing an otherwise-valid,
111
+ * independently-bounded worker manifest for the workflows it actually
112
+ * asked for.
113
+ *
114
+ * Returns `undefined` if `workflowType` is not registered on `engine` — the
115
+ * caller decides how to report that (`buildWorkerManifestFromRegistry`
116
+ * throws `WorkerManifestBuildError`, naming the type).
117
+ *
118
+ * Throws a schema-conversion error if the registered schema fails JSON
119
+ * Schema conversion, or {@link RegistryManifestLimitError} if the contract
120
+ * exceeds a WFT-5 hostile-input limit.
121
+ */
122
+ export declare function buildWorkflowManifestForType(engine: Engine, workflowType: string): Promise<WorkflowRevisionManifest | undefined>;
@@ -0,0 +1,92 @@
1
+ import { compareCodepoint } from "./compare-codepoint.js";
2
+ import {
3
+ buildWorkflowRevisionManifest
4
+ } from "./contract/index.js";
5
+ import { convertSchema } from "./registry-schema-conversion.js";
6
+ import { toWorkflowContractDraft } from "./registry-workflow-contract-draft.js";
7
+ import { WeftError } from "./weft-error.js";
8
+
9
+ export class RegistryManifestLimitError extends WeftError {
10
+ workflowType;
11
+ constructor(workflowType, cause) {
12
+ const causeMessage = cause instanceof Error ? cause.message : String(cause);
13
+ super("RegistryManifestLimitError", `Registered workflow "${workflowType}" cannot be published to the registry: ${causeMessage}`, { cause });
14
+ this.workflowType = workflowType;
15
+ }
16
+ }
17
+ function buildWorkflowScopedActivityContracts(activityDefinitions, workflowType) {
18
+ const activities = Object.create(null), scoped = [...activityDefinitions].toSorted((a, b) => compareCodepoint(a.name, b.name));
19
+ for (const metadata of scoped) {
20
+ const entityName = `${workflowType}.activities.${metadata.name}`, contract = {};
21
+ if (metadata.inputSchema !== void 0)
22
+ contract.inputSchema = convertSchema("activity", entityName, "inputSchema", metadata.inputSchema);
23
+ if (metadata.outputSchema !== void 0)
24
+ contract.outputSchema = convertSchema("activity", entityName, "outputSchema", metadata.outputSchema);
25
+ activities[metadata.name] = contract;
26
+ }
27
+ return activities;
28
+ }
29
+ function buildWorkflowEntry(definition) {
30
+ const entry = {};
31
+ if (definition.inputSchema !== void 0)
32
+ entry.inputSchema = convertSchema("workflow", definition.type, "inputSchema", definition.inputSchema);
33
+ if (definition.outputSchema !== void 0)
34
+ entry.outputSchema = convertSchema("workflow", definition.type, "outputSchema", definition.outputSchema);
35
+ if (definition.description !== void 0)
36
+ entry.description = definition.description;
37
+ if (definition.tags.length > 0)
38
+ entry.tags = [...definition.tags];
39
+ addWorkflowMessageEntries(entry, definition);
40
+ addFinalizerEntry(entry, definition);
41
+ return entry;
42
+ }
43
+ function addFinalizerEntry(entry, definition) {
44
+ if (definition.finalizer === void 0)
45
+ return;
46
+ const entityName = `${definition.type}.finalizer`, finalizerEntry = {};
47
+ if (definition.finalizer.inputSchema !== void 0)
48
+ finalizerEntry.inputSchema = convertSchema("workflow", entityName, "inputSchema", definition.finalizer.inputSchema);
49
+ if (definition.finalizer.outputSchema !== void 0)
50
+ finalizerEntry.outputSchema = convertSchema("workflow", entityName, "outputSchema", definition.finalizer.outputSchema);
51
+ entry.finalizer = finalizerEntry;
52
+ }
53
+ function addWorkflowMessageEntries(entry, definition) {
54
+ if (definition.signals !== void 0 && Object.keys(definition.signals).length > 0)
55
+ entry.signals = buildMessageEntries(definition.type, "signal", definition.signals);
56
+ if (definition.updates !== void 0 && Object.keys(definition.updates).length > 0)
57
+ entry.updates = buildMessageEntries(definition.type, "update", definition.updates);
58
+ if (definition.queries !== void 0 && Object.keys(definition.queries).length > 0)
59
+ entry.queries = buildMessageEntries(definition.type, "query", definition.queries);
60
+ }
61
+ function buildMessageEntries(workflowType, messageKind, definitions) {
62
+ const entries = Object.create(null);
63
+ for (const name of Object.keys(definitions).toSorted()) {
64
+ const definition = definitions[name];
65
+ if (definition === void 0)
66
+ continue;
67
+ const entry = {}, entityName = `${workflowType}.${messageKind}.${name}`;
68
+ if (definition.inputSchema !== void 0)
69
+ entry.inputSchema = convertSchema("workflow", entityName, "inputSchema", definition.inputSchema);
70
+ if (definition.outputSchema !== void 0)
71
+ entry.outputSchema = convertSchema("workflow", entityName, "outputSchema", definition.outputSchema);
72
+ entries[name] = entry;
73
+ }
74
+ return entries;
75
+ }
76
+ export async function buildWorkflowManifestFromDefinition(definition, activityDefinitions) {
77
+ const entry = buildWorkflowEntry(definition), workflowScopedActivities = buildWorkflowScopedActivityContracts(activityDefinitions, definition.type), contract = toWorkflowContractDraft(definition.type, definition.version, entry, workflowScopedActivities);
78
+ try {
79
+ return await buildWorkflowRevisionManifest(contract);
80
+ } catch (cause) {
81
+ throw new RegistryManifestLimitError(definition.type, cause);
82
+ }
83
+ }
84
+ export async function buildOneWorkflowManifest(engine, definition) {
85
+ return buildWorkflowManifestFromDefinition(definition, engine.listWorkflowActivityDefinitions(definition.type));
86
+ }
87
+ export async function buildWorkflowManifestForType(engine, workflowType) {
88
+ const definition = engine.getWorkflowDefinition(workflowType);
89
+ if (definition === void 0)
90
+ return;
91
+ return buildOneWorkflowManifest(engine, definition);
92
+ }
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Rejection vocabulary and the public error thrown by dynamic workflow
3
+ * source validation (WFT-13/14).
4
+ *
5
+ * @module core/source/errors
6
+ */
7
+ import type { WorkflowCompatibilityReason } from '../contract/compatibility.ts';
8
+ import { WeftError } from '../weft-error.ts';
9
+ /**
10
+ * One bounded, machine-readable reason a resolved workflow source was
11
+ * rejected — either a structural problem discovered before a manifest could
12
+ * even be built (`unregistered-source-kind`, `missing-export`,
13
+ * `ambiguous-export`, `invalid-definition`, `manifest-build-failed`), or one
14
+ * of {@link WorkflowCompatibilityReason}'s five reasons, reused verbatim once
15
+ * a manifest was built successfully and compared against the descriptor's
16
+ * expectations.
17
+ *
18
+ * @example
19
+ * ```ts
20
+ * import type { WorkflowSourceRejectionReason } from '@lostgradient/weft';
21
+ *
22
+ * const reasons: WorkflowSourceRejectionReason[] = ['missing-export', 'name-mismatch'];
23
+ * console.log(reasons.join(', '));
24
+ * ```
25
+ */
26
+ export type WorkflowSourceRejectionReason = 'unregistered-source-kind' | 'missing-export' | 'ambiguous-export' | 'invalid-definition' | 'manifest-build-failed' | WorkflowCompatibilityReason;
27
+ /**
28
+ * Thrown by `resolveWorkflowSource()` when a loaded workflow source fails
29
+ * validation: a structural problem (missing/ambiguous export, an
30
+ * export that is not a builder-produced `WorkflowDefinition`, a contract
31
+ * exceeding a hostile-input limit) or a `checkWorkflowCompatibility`
32
+ * mismatch against the descriptor's expected `name`/`revision`/
33
+ * `workflowVersion`/`contractHash`. Carries every applicable
34
+ * {@link WorkflowSourceRejectionReason}, never just the first one found.
35
+ *
36
+ * @example
37
+ * ```ts
38
+ * import { Engine, WorkflowSourceValidationError } from '@lostgradient/weft';
39
+ *
40
+ * declare const engine: Engine;
41
+ * try {
42
+ * await engine.resolveWorkflowSource('checkout', 'r1');
43
+ * } catch (error) {
44
+ * if (error instanceof WorkflowSourceValidationError) {
45
+ * console.error(error.workflowName, error.revision, error.reasons);
46
+ * }
47
+ * }
48
+ * ```
49
+ */
50
+ export declare class WorkflowSourceValidationError extends WeftError<'WorkflowSourceValidationError'> {
51
+ readonly workflowName: string;
52
+ readonly revision: string;
53
+ readonly reasons: readonly WorkflowSourceRejectionReason[];
54
+ constructor(workflowName: string, revision: string, reasons: readonly WorkflowSourceRejectionReason[]);
55
+ }
@@ -0,0 +1,13 @@
1
+ import { WeftError } from "../weft-error.js";
2
+
3
+ export class WorkflowSourceValidationError extends WeftError {
4
+ workflowName;
5
+ revision;
6
+ reasons;
7
+ constructor(workflowName, revision, reasons) {
8
+ super("WorkflowSourceValidationError", `Dynamic workflow source "${workflowName}" revision "${revision}" failed validation: ` + reasons.join(", "));
9
+ this.workflowName = workflowName;
10
+ this.revision = revision;
11
+ this.reasons = reasons;
12
+ }
13
+ }
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Dynamic workflow sources (WFT-13/14): a typed `workflowSource()` factory,
3
+ * the `WorkflowSourceDescriptor`/`WorkflowSourceHandle` types, source-kind
4
+ * resolution, and validation — re-exported both for the package root
5
+ * (`src/index.ts`) and for `core/engine/source-registration.ts` /
6
+ * `core/engine/source-resolution.ts`, which cannot import `internals.ts`
7
+ * (the only import-restricted module in this package) but need everything
8
+ * else here.
9
+ *
10
+ * @module core/source
11
+ */
12
+ export type { WorkflowSourceDescriptor, WorkflowSourceDescriptorInput, WorkflowSourceHandle, WorkflowSourceKind, } from './types.ts';
13
+ export { workflowSource } from './workflow-source.ts';
14
+ export { WorkflowSourceValidationError } from './errors.ts';
15
+ export type { WorkflowSourceRejectionReason } from './errors.ts';
16
+ export { resolveSourceModule } from './resolvers.ts';
17
+ export type { ResolveSourceModuleResult } from './resolvers.ts';
18
+ export { buildExpectedManifest, validateResolvedWorkflowSource } from './validate.ts';
19
+ export type { WorkflowSourceValidationOutcome } from './validate.ts';
@@ -0,0 +1,4 @@
1
+ export { workflowSource } from "./workflow-source.js";
2
+ export { WorkflowSourceValidationError } from "./errors.js";
3
+ export { resolveSourceModule } from "./resolvers.js";
4
+ export { buildExpectedManifest, validateResolvedWorkflowSource } from "./validate.js";
@@ -0,0 +1,45 @@
1
+ /**
2
+ * The `kind -> resolver` registry for dynamic workflow sources. A resolver's
3
+ * only job is to turn a {@link WorkflowSourceHandle} into the raw `unknown`
4
+ * module value its `load()` capability produces — everything downstream
5
+ * (export lookup, definition validation, manifest building) lives in
6
+ * `validate.ts` and is identical regardless of source kind.
7
+ *
8
+ * @module core/source/resolvers
9
+ */
10
+ import type { WorkflowSourceDescriptor, WorkflowSourceHandle } from './types.ts';
11
+ /** The outcome of {@link resolveSourceModule}: either the raw loaded module value, or a short-circuit rejection reason. */
12
+ export type ResolveSourceModuleResult = {
13
+ readonly ok: true;
14
+ readonly moduleValue: unknown;
15
+ } | {
16
+ readonly ok: false;
17
+ readonly reason: 'unregistered-source-kind';
18
+ };
19
+ /**
20
+ * Look up the resolver registered for `descriptor.kind` and invoke it
21
+ * against `handle` to produce the raw, untrusted module value. Returns
22
+ * `{ ok: false, reason: 'unregistered-source-kind' }` when no resolver is
23
+ * registered for that kind — unreachable through `workflowSource()`'s own
24
+ * typed surface today (`WorkflowSourceKind` is the single literal
25
+ * `'module'`), but a manually-constructed handle can still name an
26
+ * unsupported kind, so this stays a checked, structured rejection rather
27
+ * than an unhandled throw — the same "unreachable through the type-safe
28
+ * surface, exists for hostile/manually-constructed input" precedent as
29
+ * `manifest-version-unsupported` in `core/contract/compatibility.ts`.
30
+ *
31
+ * @example
32
+ * ```ts
33
+ * import { workflowSource } from '@lostgradient/weft';
34
+ *
35
+ * declare const loadCheckout: () => Promise<{
36
+ * checkout: import('@lostgradient/weft').WorkflowDefinition<unknown, unknown, 'checkout'>;
37
+ * }>;
38
+ * const source = workflowSource(
39
+ * { name: 'checkout', location: './checkout.ts', exportName: 'checkout', revision: 'r1' },
40
+ * loadCheckout,
41
+ * );
42
+ * console.log(source.descriptor.kind);
43
+ * ```
44
+ */
45
+ export declare function resolveSourceModule(descriptor: WorkflowSourceDescriptor, handle: WorkflowSourceHandle): Promise<ResolveSourceModuleResult>;
@@ -0,0 +1,9 @@
1
+ const SOURCE_RESOLVERS = Object.freeze({
2
+ module: async (handle) => handle.load()
3
+ });
4
+ export async function resolveSourceModule(descriptor, handle) {
5
+ const resolver = Object.hasOwn(SOURCE_RESOLVERS, descriptor.kind) ? SOURCE_RESOLVERS[descriptor.kind] : void 0;
6
+ if (resolver === void 0)
7
+ return { ok: !1, reason: "unregistered-source-kind" };
8
+ return { ok: !0, moduleValue: await resolver(handle) };
9
+ }
@@ -0,0 +1,211 @@
1
+ /**
2
+ * Types for dynamic workflow sources (WFT-13/14): a typed, serializable
3
+ * {@link WorkflowSourceDescriptor} paired with a host-side loader capability
4
+ * that is never serialized, plus the pure type-extractor helpers
5
+ * {@link workflowSource} uses to preserve a literal `() => import('./x.ts')`
6
+ * import's exact `TInput`/`TOutput`/`TServices` inference through to the
7
+ * returned {@link WorkflowSourceHandle}.
8
+ *
9
+ * @module core/source/types
10
+ */
11
+ import type { WorkflowDefinition } from '../types.ts';
12
+ /**
13
+ * The kind of location a {@link WorkflowSourceDescriptor} names. `'module'`
14
+ * is the only kind today — a literal ES module import resolved by a host
15
+ * loader. The union is a single literal rather than `string` so a future
16
+ * source kind (a bundle registry entry, a remote fetch) can be added without
17
+ * a breaking change to this type.
18
+ *
19
+ * @example
20
+ * ```ts
21
+ * import type { WorkflowSourceKind } from '@lostgradient/weft';
22
+ *
23
+ * const kind: WorkflowSourceKind = 'module';
24
+ * console.log(kind);
25
+ * ```
26
+ */
27
+ export type WorkflowSourceKind = 'module';
28
+ /**
29
+ * Plain, serializable metadata identifying one dynamic workflow source:
30
+ * where a workflow's code lives (`location`), which named export holds the
31
+ * workflow definition (`exportName`), and the exact revision the caller
32
+ * expects (`revision`), plus optional pinned `workflowVersion`/`contractHash`
33
+ * expectations. Deliberately carries no function reference — the loader
34
+ * capability that actually resolves `location` into a module value is a
35
+ * separate, never-serialized field on {@link WorkflowSourceHandle}. A
36
+ * descriptor is safe to log, persist, or send over the wire; nothing here
37
+ * can execute code.
38
+ *
39
+ * `TName` is a phantom convenience for callers that want to brand a
40
+ * descriptor with a specific workflow name at the type level (for example
41
+ * a lookup table keyed by name); {@link WorkflowSourceHandle} itself always
42
+ * carries the unparameterized (`TName = string`) shape, since the
43
+ * descriptor's `name` field holds whatever string the caller supplied and
44
+ * is only checked against the loaded module's actual name at resolve time
45
+ * — see `resolveWorkflowSource`'s `name-mismatch` rejection reason.
46
+ *
47
+ * @example
48
+ * ```ts
49
+ * import type { WorkflowSourceDescriptor } from '@lostgradient/weft';
50
+ *
51
+ * const descriptor: WorkflowSourceDescriptor = {
52
+ * kind: 'module',
53
+ * name: 'checkout',
54
+ * location: './workflows/checkout.ts',
55
+ * exportName: 'checkout',
56
+ * revision: 'checkout-2026.09.01',
57
+ * };
58
+ * console.log(descriptor.kind);
59
+ * ```
60
+ */
61
+ export interface WorkflowSourceDescriptor<TName extends string = string> {
62
+ /** Which resolver (`core/source/resolvers.ts`) loads this source. */
63
+ readonly kind: WorkflowSourceKind;
64
+ /** The workflow name this source is expected to resolve to. */
65
+ readonly name: TName;
66
+ /**
67
+ * Host-meaningful location string (a module specifier for `kind: 'module'`).
68
+ * Carried verbatim — never parsed, concatenated, or used to construct an
69
+ * import specifier by this package; the loader capability alone is
70
+ * responsible for turning `location` into a loaded module.
71
+ */
72
+ readonly location: string;
73
+ /** The named export within the loaded module that holds the workflow definition. */
74
+ readonly exportName: string;
75
+ /** The caller's expected content-derived revision; compared against the revision actually derived from the loaded contract. */
76
+ readonly revision: string;
77
+ /** Optional pinned workflow version; compared for exact string equality via `checkWorkflowCompatibility` (`checkVersionCompatibility()`'s entire contract is `storedVersion === registeredVersion` — there is no semver-range matching) when set. */
78
+ readonly workflowVersion?: string;
79
+ /** Optional pinned contract hash; compared for exact equality when set. */
80
+ readonly contractHash?: string;
81
+ }
82
+ /**
83
+ * The loose input shape {@link workflowSource} accepts before `kind`
84
+ * defaults to `'module'` — every {@link WorkflowSourceDescriptor} field
85
+ * except `kind`, which callers may omit for the only kind that exists today.
86
+ *
87
+ * @example
88
+ * ```ts
89
+ * import type { WorkflowSourceDescriptorInput } from '@lostgradient/weft';
90
+ *
91
+ * const input: WorkflowSourceDescriptorInput<'checkout'> = {
92
+ * name: 'checkout',
93
+ * location: './workflows/checkout.ts',
94
+ * exportName: 'checkout',
95
+ * revision: 'checkout-2026.09.01',
96
+ * };
97
+ * console.log(input.exportName);
98
+ * ```
99
+ */
100
+ export type WorkflowSourceDescriptorInput<TExportName extends string> = {
101
+ readonly kind?: WorkflowSourceKind;
102
+ readonly name: string;
103
+ readonly location: string;
104
+ readonly exportName: TExportName;
105
+ readonly revision: string;
106
+ readonly workflowVersion?: string;
107
+ readonly contractHash?: string;
108
+ };
109
+ /**
110
+ * A typed handle pairing a serializable {@link WorkflowSourceDescriptor}
111
+ * with the host-side loader capability that resolves it — the value
112
+ * `workflowSource()` returns. `load` is a plain `() => Promise<unknown>`
113
+ * at the type level; when built from a literal `() => import('./x.ts')`
114
+ * import, `TInput`/`TOutput`/`TName`/`TServices` are inferred from the
115
+ * named export the descriptor points at, so `engine.registerSource(handle)`
116
+ * and a later `resolveWorkflowSource` can carry that inference through
117
+ * without a cast. `TInput`/`TOutput`/`TName`/`TServices` are phantom —
118
+ * carried only as optional, never-populated marker fields — mirroring
119
+ * `BuiltWorkflowDefinition`'s own phantom-marker convention
120
+ * (`core/types/workflow-builder.ts`).
121
+ *
122
+ * @example
123
+ * ```ts
124
+ * import { workflowSource } from '@lostgradient/weft';
125
+ * import type { WorkflowSourceHandle } from '@lostgradient/weft';
126
+ *
127
+ * declare const loadCheckout: () => Promise<{
128
+ * checkout: import('@lostgradient/weft').WorkflowDefinition<{ orderId: string }, { shipped: boolean }, 'checkout'>;
129
+ * }>;
130
+ * const source: WorkflowSourceHandle = workflowSource(
131
+ * { name: 'checkout', location: './workflows/checkout.ts', exportName: 'checkout', revision: 'r1' },
132
+ * loadCheckout,
133
+ * );
134
+ * console.log(source.descriptor.name);
135
+ * ```
136
+ */
137
+ export interface WorkflowSourceHandle<TInput = unknown, TOutput = unknown, TName extends string = string, TServices = unknown> {
138
+ /** Plain, serializable source metadata. Never carries a function reference. */
139
+ readonly descriptor: WorkflowSourceDescriptor;
140
+ /**
141
+ * Host-side loader capability. Never serialized; concurrent
142
+ * `resolveWorkflowSource()` calls for the same `(name, revision)` share
143
+ * exactly one in-flight invocation (single-flight), so it is invoked at
144
+ * most once per key PER ATTEMPT. It is not limited to one invocation for
145
+ * the key's entire lifetime: `getOrCreateSharedSourceLoad()` removes the
146
+ * shared promise once it settles, so if that attempt's load, validation,
147
+ * or catalog install fails, a later `resolveWorkflowSource()` call for the
148
+ * same `(name, revision)` starts a fresh attempt and invokes the loader
149
+ * again. A successful attempt is cached — see `resolveWorkflowSource`.
150
+ */
151
+ readonly load: () => Promise<unknown>;
152
+ /** Phantom marker for the resolved workflow's input type. Not present at runtime. */
153
+ readonly _input?: TInput;
154
+ /** Phantom marker for the resolved workflow's output type. Not present at runtime. */
155
+ readonly _output?: TOutput;
156
+ /** Phantom marker for the resolved workflow's literal name type. Not present at runtime. */
157
+ readonly _name?: TName;
158
+ /** Phantom marker for the resolved workflow's per-run services type. Not present at runtime. */
159
+ readonly _services?: TServices;
160
+ }
161
+ /**
162
+ * `true` when `T` is exactly `any` — used to reject a `workflowSource()`
163
+ * call whose loader's module type could not be inferred (a dynamic
164
+ * `import(pathVariable)`, which TypeScript types as `Promise<any>`).
165
+ * Distinguishing `any` from a genuine `Record<string, unknown>` requires
166
+ * this "does `T` accept both `0` and `1`" trick rather than `T extends
167
+ * Record<string, unknown>` — `any` would trivially satisfy that constraint
168
+ * too, silently defeating the whole point of requiring a literal import.
169
+ *
170
+ * @example
171
+ * ```ts
172
+ * import type { IsAny } from './types.ts';
173
+ *
174
+ * type CheckConcrete = IsAny<{ a: 1 }>;
175
+ * const concrete: CheckConcrete = false;
176
+ * console.log(concrete);
177
+ * ```
178
+ */
179
+ export type IsAny<T> = 0 extends 1 & T ? true : false;
180
+ /**
181
+ * Resolve the exact export type at `TExportName` on `TModule`, narrowed to
182
+ * `WorkflowDefinition` — or `never` when that export is not one. Feeding
183
+ * `never` into {@link InputOf} / {@link OutputOf} / {@link NameOf} /
184
+ * {@link ServicesOf} collapses each to `never` too (conditional types
185
+ * distribute over `never`, TypeScript's "empty union" case), which is how a
186
+ * `workflowSource()` call pointed at a non-workflow export compiles at the
187
+ * call site but produces a handle whose type parameters are unusable —
188
+ * misuse fails at first *use* of the handle rather than at the
189
+ * `workflowSource()` call itself. See `workflow-source.test-d.ts` for the
190
+ * regression pin.
191
+ *
192
+ * @example
193
+ * ```ts
194
+ * import type { ModuleWorkflowDefinition } from './types.ts';
195
+ * import type { WorkflowDefinition } from '@lostgradient/weft';
196
+ *
197
+ * type Module = { checkout: WorkflowDefinition<{ orderId: string }, { shipped: boolean }, 'checkout'> };
198
+ * type Resolved = ModuleWorkflowDefinition<Module, 'checkout'>;
199
+ * declare const resolved: Resolved;
200
+ * console.log(resolved.name);
201
+ * ```
202
+ */
203
+ export type ModuleWorkflowDefinition<TModule extends Record<string, unknown>, TExportName extends keyof TModule & string> = TModule[TExportName] extends WorkflowDefinition<infer _TInput, infer _TOutput, infer _TName, infer _TServices> ? TModule[TExportName] : never;
204
+ /** Extract `TInput` from a `WorkflowDefinition`-shaped type, or `never`. */
205
+ export type InputOf<T> = T extends WorkflowDefinition<infer TInput, infer _TOutput, infer _TName, infer _TServices> ? TInput : never;
206
+ /** Extract `TOutput` from a `WorkflowDefinition`-shaped type, or `never`. */
207
+ export type OutputOf<T> = T extends WorkflowDefinition<infer _TInput, infer TOutput, infer _TName, infer _TServices> ? TOutput : never;
208
+ /** Extract the literal `TName` from a `WorkflowDefinition`-shaped type, or `never`. */
209
+ export type NameOf<T> = T extends WorkflowDefinition<infer _TInput, infer _TOutput, infer TName, infer _TServices> ? TName : never;
210
+ /** Extract `TServices` from a `WorkflowDefinition`-shaped type, or `never`. */
211
+ export type ServicesOf<T> = T extends WorkflowDefinition<infer _TInput, infer _TOutput, infer _TName, infer TServices> ? TServices : never;
File without changes