@lostgradient/weft 0.23.1 → 0.24.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +72 -4
- package/dist/cli/codegen-emit-dedup.d.ts +81 -0
- package/dist/cli/codegen-emit-dedup.js +45 -0
- package/dist/cli/codegen-emit-registry.d.ts +90 -0
- package/dist/cli/codegen-emit-registry.js +50 -0
- package/dist/cli/codegen-emit.d.ts +26 -39
- package/dist/cli/codegen-emit.js +4 -27
- package/dist/cli/codegen-validate.d.ts +49 -0
- package/dist/cli/codegen-validate.js +186 -0
- package/dist/cli/codegen.js +6 -87
- package/dist/cli/generated/operation-catalog.snapshot.json +287 -3
- package/dist/cli/generated/operation-client.generated.d.ts +324 -10
- package/dist/cli/generated/operation-client.generated.js +12 -0
- package/dist/cli/output.js +1 -1
- package/dist/cli/storage-factory.js +2 -0
- package/dist/cli/workflow-commands.js +2 -0
- package/dist/cli-main.js +1 -1
- package/dist/core/application-payload-digest.d.ts +42 -0
- package/dist/core/application-payload-digest.js +76 -0
- package/dist/core/application-primitive-abort.d.ts +50 -0
- package/dist/core/application-primitive-abort.js +40 -0
- package/dist/core/application-primitive-attempt-registry.d.ts +74 -0
- package/dist/core/application-primitive-attempt-registry.js +73 -0
- package/dist/core/application-primitive-codec.d.ts +36 -0
- package/dist/core/application-primitive-codec.js +56 -0
- package/dist/core/application-primitive-commit.d.ts +67 -0
- package/dist/core/application-primitive-commit.js +66 -0
- package/dist/core/application-primitive-guards.d.ts +62 -0
- package/dist/core/application-primitive-guards.js +89 -0
- package/dist/core/application-primitive-payload.d.ts +29 -0
- package/dist/core/application-primitive-payload.js +65 -0
- package/dist/core/application-primitive-timing.d.ts +18 -0
- package/dist/core/application-primitive-timing.js +22 -0
- package/dist/core/atomic-state.js +2 -0
- package/dist/core/catalog/codec.d.ts +40 -0
- package/dist/core/catalog/codec.js +45 -0
- package/dist/core/catalog/errors.d.ts +104 -0
- package/dist/core/catalog/errors.js +41 -0
- package/dist/core/catalog/index.d.ts +25 -0
- package/dist/core/catalog/index.js +15 -0
- package/dist/core/catalog/reference-counts.d.ts +105 -0
- package/dist/core/catalog/reference-counts.js +28 -0
- package/dist/core/catalog/removal.d.ts +52 -0
- package/dist/core/catalog/removal.js +14 -0
- package/dist/core/catalog/storage-io.d.ts +78 -0
- package/dist/core/catalog/storage-io.js +106 -0
- package/dist/core/catalog/types.d.ts +108 -0
- package/dist/core/catalog/types.js +0 -0
- package/dist/core/catalog/workflow-catalog.d.ts +165 -0
- package/dist/core/catalog/workflow-catalog.js +198 -0
- package/dist/core/compare-codepoint.d.ts +13 -0
- package/dist/core/compare-codepoint.js +7 -0
- package/dist/core/compression.js +2 -0
- package/dist/core/context/attributes.d.ts +1 -1
- package/dist/core/context/durable-operations.d.ts +2 -2
- package/dist/core/context/index.js +5 -3
- package/dist/core/context/state-namespace.d.ts +1 -1
- package/dist/core/contract/build.d.ts +64 -0
- package/dist/core/contract/build.js +99 -0
- package/dist/core/contract/compatibility.d.ts +187 -0
- package/dist/core/contract/compatibility.js +37 -0
- package/dist/core/contract/failure.d.ts +64 -0
- package/dist/core/contract/failure.js +4 -0
- package/dist/core/contract/hash.d.ts +92 -0
- package/dist/core/contract/hash.js +34 -0
- package/dist/core/contract/index.d.ts +21 -0
- package/dist/core/contract/index.js +22 -0
- package/dist/core/contract/limits.d.ts +74 -0
- package/dist/core/contract/limits.js +1 -0
- package/dist/core/contract/manifest-parse-schema.d.ts +37 -0
- package/dist/core/contract/manifest-parse-schema.js +106 -0
- package/dist/core/contract/manifest-parse.d.ts +76 -0
- package/dist/core/contract/manifest-parse.js +189 -0
- package/dist/core/contract/manifest.d.ts +56 -0
- package/dist/core/contract/manifest.js +31 -0
- package/dist/core/contract/normalize.d.ts +97 -0
- package/dist/core/contract/normalize.js +127 -0
- package/dist/core/contract/revision.d.ts +29 -0
- package/dist/core/contract/revision.js +5 -0
- package/dist/core/contract/types.d.ts +274 -0
- package/dist/core/contract/types.js +1 -0
- package/dist/core/engine/catalog-activation.d.ts +40 -0
- package/dist/core/engine/catalog-activation.js +17 -0
- package/dist/core/engine/catalog-events.d.ts +36 -0
- package/dist/core/engine/catalog-events.js +15 -0
- package/dist/core/engine/catalog-readiness.d.ts +49 -0
- package/dist/core/engine/catalog-readiness.js +59 -0
- package/dist/core/engine/catalog-removal.d.ts +132 -0
- package/dist/core/engine/catalog-removal.js +70 -0
- package/dist/core/engine/construction.d.ts +1 -1
- package/dist/core/engine/construction.js +4 -2
- package/dist/core/engine/disposal.js +9 -0
- package/dist/core/engine/engine-workflows-namespace.d.ts +130 -0
- package/dist/core/engine/engine-workflows-namespace.js +49 -0
- package/dist/core/engine/finalizer-metadata.d.ts +22 -0
- package/dist/core/engine/finalizer-metadata.js +12 -0
- package/dist/core/engine/handle-result.js +2 -0
- package/dist/core/engine/index.d.ts +83 -0
- package/dist/core/engine/index.js +61 -0
- package/dist/core/engine/internals.d.ts +44 -1
- package/dist/core/engine/internals.js +6 -0
- package/dist/core/engine/lifecycle/start.js +3 -0
- package/dist/core/engine/registration.d.ts +76 -0
- package/dist/core/engine/registration.js +12 -6
- package/dist/core/engine/source-registration.d.ts +42 -0
- package/dist/core/engine/source-registration.js +36 -0
- package/dist/core/engine/source-resolution.d.ts +85 -0
- package/dist/core/engine/source-resolution.js +119 -0
- package/dist/core/engine/validation.js +2 -2
- package/dist/core/events/catalog-events.d.ts +117 -0
- package/dist/core/events/catalog-events.js +62 -0
- package/dist/core/events/event-map.d.ts +6 -0
- package/dist/core/events/index.d.ts +1 -0
- package/dist/core/events/index.js +1 -0
- package/dist/core/mailbox-admission.d.ts +26 -0
- package/dist/core/mailbox-admission.js +130 -0
- package/dist/core/mailbox-claims.d.ts +251 -0
- package/dist/core/mailbox-claims.js +0 -0
- package/dist/core/mailbox-codec.d.ts +32 -0
- package/dist/core/mailbox-codec.js +221 -0
- package/dist/core/mailbox-contract.d.ts +290 -0
- package/dist/core/mailbox-contract.js +0 -0
- package/dist/core/mailbox-delivery.d.ts +37 -0
- package/dist/core/mailbox-delivery.js +193 -0
- package/dist/core/mailbox-guards.d.ts +78 -0
- package/dist/core/mailbox-guards.js +58 -0
- package/dist/core/mailbox-index-codec.d.ts +41 -0
- package/dist/core/mailbox-index-codec.js +71 -0
- package/dist/core/mailbox-internals.d.ts +156 -0
- package/dist/core/mailbox-internals.js +154 -0
- package/dist/core/mailbox-maintenance.d.ts +29 -0
- package/dist/core/mailbox-maintenance.js +196 -0
- package/dist/core/mailbox-settlement.d.ts +69 -0
- package/dist/core/mailbox-settlement.js +206 -0
- package/dist/core/mailbox-storage.d.ts +117 -0
- package/dist/core/mailbox-storage.js +115 -0
- package/dist/core/mailbox-transition-helpers.d.ts +70 -0
- package/dist/core/mailbox-transition-helpers.js +43 -0
- package/dist/core/mailbox-transitions-recovery.d.ts +28 -0
- package/dist/core/mailbox-transitions-recovery.js +64 -0
- package/dist/core/mailbox-transitions.d.ts +138 -0
- package/dist/core/mailbox-transitions.js +180 -0
- package/dist/core/mailbox-types.d.ts +406 -0
- package/dist/core/mailbox-types.js +16 -0
- package/dist/core/mailbox-validation.d.ts +65 -0
- package/dist/core/mailbox-validation.js +73 -0
- package/dist/core/mailbox-waits.d.ts +50 -0
- package/dist/core/mailbox-waits.js +97 -0
- package/dist/core/mailbox.d.ts +163 -0
- package/dist/core/mailbox.js +211 -0
- package/dist/core/outbox-claims.d.ts +307 -0
- package/dist/core/outbox-claims.js +0 -0
- package/dist/core/outbox-codec.d.ts +24 -0
- package/dist/core/outbox-codec.js +257 -0
- package/dist/core/outbox-contract.d.ts +346 -0
- package/dist/core/outbox-contract.js +0 -0
- package/dist/core/outbox-delivery.d.ts +34 -0
- package/dist/core/outbox-delivery.js +149 -0
- package/dist/core/outbox-drain.d.ts +29 -0
- package/dist/core/outbox-drain.js +158 -0
- package/dist/core/outbox-enqueue.d.ts +24 -0
- package/dist/core/outbox-enqueue.js +115 -0
- package/dist/core/outbox-guards.d.ts +76 -0
- package/dist/core/outbox-guards.js +60 -0
- package/dist/core/outbox-index-codec.d.ts +33 -0
- package/dist/core/outbox-index-codec.js +71 -0
- package/dist/core/outbox-internals.d.ts +99 -0
- package/dist/core/outbox-internals.js +159 -0
- package/dist/core/outbox-listing.d.ts +12 -0
- package/dist/core/outbox-listing.js +38 -0
- package/dist/core/outbox-maintenance.d.ts +28 -0
- package/dist/core/outbox-maintenance.js +191 -0
- package/dist/core/outbox-operations.d.ts +18 -0
- package/dist/core/outbox-operations.js +46 -0
- package/dist/core/outbox-runner.d.ts +30 -0
- package/dist/core/outbox-runner.js +217 -0
- package/dist/core/outbox-settlement.d.ts +57 -0
- package/dist/core/outbox-settlement.js +183 -0
- package/dist/core/outbox-storage.d.ts +107 -0
- package/dist/core/outbox-storage.js +127 -0
- package/dist/core/outbox-transition-helpers.d.ts +83 -0
- package/dist/core/outbox-transition-helpers.js +63 -0
- package/dist/core/outbox-transitions-recovery.d.ts +30 -0
- package/dist/core/outbox-transitions-recovery.js +42 -0
- package/dist/core/outbox-transitions.d.ts +145 -0
- package/dist/core/outbox-transitions.js +236 -0
- package/dist/core/outbox-types.d.ts +400 -0
- package/dist/core/outbox-types.js +20 -0
- package/dist/core/outbox-validation.d.ts +101 -0
- package/dist/core/outbox-validation.js +127 -0
- package/dist/core/outbox-waits.d.ts +39 -0
- package/dist/core/outbox-waits.js +88 -0
- package/dist/core/outbox.d.ts +156 -0
- package/dist/core/outbox.js +234 -0
- package/dist/core/registry-limits.d.ts +49 -0
- package/dist/core/registry-limits.js +10 -0
- package/dist/core/registry-schema-conversion.d.ts +20 -0
- package/dist/core/registry-schema-conversion.js +22 -0
- package/dist/core/registry-snapshot.d.ts +91 -42
- package/dist/core/registry-snapshot.js +39 -77
- package/dist/core/registry-workflow-contract-draft.d.ts +32 -0
- package/dist/core/registry-workflow-contract-draft.js +28 -0
- package/dist/core/registry-workflow-manifest.d.ts +122 -0
- package/dist/core/registry-workflow-manifest.js +92 -0
- package/dist/core/source/errors.d.ts +55 -0
- package/dist/core/source/errors.js +13 -0
- package/dist/core/source/index.d.ts +19 -0
- package/dist/core/source/index.js +4 -0
- package/dist/core/source/resolvers.d.ts +45 -0
- package/dist/core/source/resolvers.js +9 -0
- package/dist/core/source/types.d.ts +211 -0
- package/dist/core/source/types.js +0 -0
- package/dist/core/source/validate.d.ts +91 -0
- package/dist/core/source/validate.js +62 -0
- package/dist/core/source/workflow-source.d.ts +43 -0
- package/dist/core/source/workflow-source.js +16 -0
- package/dist/core/types/workflow-registries.d.ts +7 -0
- package/dist/core/types/workflow-registry.d.ts +12 -0
- package/dist/core/versioning.js +2 -0
- package/dist/core/weft-error.d.ts +1 -1
- package/dist/core/weft-error.js +9 -1
- package/dist/http.js +2 -2
- package/dist/index.d.ts +23 -2
- package/dist/index.js +50 -0
- package/dist/indexeddb.js +1 -1
- package/dist/json-schema.js +3 -3
- package/dist/mcp/resources.js +2 -0
- package/dist/runtime/portable.d.ts +9 -1
- package/dist/server/fault-to-json-rpc.js +3 -1
- package/dist/server/handler/auth-context-principal.js +4 -0
- package/dist/server/json-rpc-http.js +2 -0
- package/dist/server/json-rpc-websocket.js +6 -4
- package/dist/server/operation-catalog/index.d.ts +1 -1
- package/dist/server/operation-catalog/pipeline-helpers.js +2 -0
- package/dist/server/operation-catalog/types.d.ts +17 -0
- package/dist/server/operation-fault.d.ts +3 -0
- package/dist/server/operation-fault.js +3 -1
- package/dist/server/operations/activate-workflow-revision.d.ts +30 -0
- package/dist/server/operations/activate-workflow-revision.js +69 -0
- package/dist/server/operations/fleet-events-subscription.js +1 -1
- package/dist/server/operations/fork-workflow.js +1 -1
- package/dist/server/operations/get-active-workflow-revision.d.ts +32 -0
- package/dist/server/operations/get-active-workflow-revision.js +46 -0
- package/dist/server/operations/get-catalog-diagnostics.d.ts +85 -0
- package/dist/server/operations/get-catalog-diagnostics.js +57 -0
- package/dist/server/operations/get-registry.js +17 -4
- package/dist/server/operations/get-workflow-revision.d.ts +25 -0
- package/dist/server/operations/get-workflow-revision.js +50 -0
- package/dist/server/operations/install-workflow-revision.d.ts +27 -0
- package/dist/server/operations/install-workflow-revision.js +46 -0
- package/dist/server/operations/list-workflow-revisions.d.ts +20 -0
- package/dist/server/operations/list-workflow-revisions.js +40 -0
- package/dist/server/operations/start-or-signal-workflow.js +1 -1
- package/dist/server/operations/start-workflow.js +1 -1
- package/dist/server/operations/static-registrations.js +36 -0
- package/dist/server/operations/storage.js +2 -2
- package/dist/server/operations/submit-review-decision.js +1 -1
- package/dist/server/operations/workflow-catalog-operation-helpers.d.ts +59 -0
- package/dist/server/operations/workflow-catalog-operation-helpers.js +135 -0
- package/dist/server/runtime/websocket-upgrade.js +2 -0
- package/dist/storage/bun-sql.js +49 -6
- package/dist/storage/catalog-keys.d.ts +45 -0
- package/dist/storage/catalog-keys.js +6 -0
- package/dist/storage/compressed-storage.js +1 -1
- package/dist/storage/derived-operations.js +1 -1
- package/dist/storage/index.d.ts +26 -1
- package/dist/storage/interface.d.ts +26 -1
- package/dist/storage/interface.js +1 -1
- package/dist/storage/key-encoding.d.ts +15 -0
- package/dist/storage/key-encoding.js +3 -0
- package/dist/storage/key-prefixes.d.ts +1 -1
- package/dist/storage/key-prefixes.js +15 -0
- package/dist/storage/lmdb.d.ts +26 -1
- package/dist/storage/lmdb.js +1 -1
- package/dist/storage/mailbox-keys.d.ts +80 -0
- package/dist/storage/mailbox-keys.js +14 -0
- package/dist/storage/memory.js +1 -1
- package/dist/storage/neon.js +2 -2
- package/dist/storage/node-sqlite-loader.d.ts +1 -1
- package/dist/storage/node-sqlite.js +49 -6
- package/dist/storage/outbox-keys.d.ts +77 -0
- package/dist/storage/outbox-keys.js +14 -0
- package/dist/storage/postgres.js +2 -2
- package/dist/storage/resolve.js +1 -1
- package/dist/storage/scoped-storage.js +1 -1
- package/dist/storage/storage-configuration.d.ts +6 -0
- package/dist/storage/testing.js +1 -1
- package/dist/storage/turso.js +2 -2
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/web-extension.js +1 -1
- package/dist/worker/manifest/registry-contract-builder.d.ts +21 -3
- package/dist/worker/manifest/registry-contract-builder.js +40 -31
- package/package.json +1 -1
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The sync/async boundary glue between `engine.register()` (synchronous,
|
|
3
|
+
* cannot itself build a manifest — that requires `crypto.subtle`) and the
|
|
4
|
+
* durable workflow catalog (async, WFT-9/WFT-10).
|
|
5
|
+
*
|
|
6
|
+
* `register()` stays byte-for-byte synchronous; `commitWorkflowDefinition`
|
|
7
|
+
* (`registration.ts`) only pushes the workflow's name onto
|
|
8
|
+
* `EngineInternals.pendingCatalogInstalls`. {@link ensureWorkflowCatalogReady}
|
|
9
|
+
* is the memoized function that, on first call, restores the catalog from
|
|
10
|
+
* storage, then drains `pendingCatalogInstalls` — building each pending
|
|
11
|
+
* workflow's manifest via the already-existing
|
|
12
|
+
* `buildWorkflowManifestForType` (`registry-workflow-manifest.ts`, reused
|
|
13
|
+
* rather than reimplemented) and unconditionally activating it via
|
|
14
|
+
* `WorkflowCatalog.activateRegistered`.
|
|
15
|
+
*
|
|
16
|
+
* Awaited at every entry point that can observe catalog state — see the
|
|
17
|
+
* call sites in `index.ts` — so "restore catalog state before recovery or
|
|
18
|
+
* any new start" holds.
|
|
19
|
+
*
|
|
20
|
+
* @module core/engine/catalog-readiness
|
|
21
|
+
*/
|
|
22
|
+
import type { Engine } from './index.ts';
|
|
23
|
+
export { getWorkflowCatalog } from './internals.ts';
|
|
24
|
+
/**
|
|
25
|
+
* Synchronous fast-path check: `true` once the catalog is restored and
|
|
26
|
+
* nothing is pending, `false` when {@link ensureWorkflowCatalogReady} would
|
|
27
|
+
* need to do real work. Every `ensureWorkflowCatalogReady` call site in
|
|
28
|
+
* `index.ts` guards its `await` with this check first — `await`ing an
|
|
29
|
+
* `async` function always costs one microtask tick even when the function's
|
|
30
|
+
* own body takes the fast path internally (JS's `await` semantics, not an
|
|
31
|
+
* implementation detail), so skipping the call entirely on an already-warm
|
|
32
|
+
* engine is what "avoid promise-machinery overhead on the hot path" (the
|
|
33
|
+
* WFT-9/WFT-10 design) actually requires — not just an early return inside
|
|
34
|
+
* the async function.
|
|
35
|
+
*/
|
|
36
|
+
export declare function isWorkflowCatalogReady(engine: Engine): boolean;
|
|
37
|
+
/**
|
|
38
|
+
* Restore the workflow catalog from storage (once per engine instance) and
|
|
39
|
+
* drain any workflow names `engine.register()` has queued since the last
|
|
40
|
+
* drain. Memoized: concurrent callers await the same in-flight promise, and
|
|
41
|
+
* a call after a prior drain resolved with newly queued names starts a
|
|
42
|
+
* fresh drain rather than re-scanning storage.
|
|
43
|
+
*
|
|
44
|
+
* Also checks the {@link isWorkflowCatalogReady} fast path itself, so a
|
|
45
|
+
* direct call (bypassing a call site's own guard — as in
|
|
46
|
+
* `buildRegistrySnapshot`, or any future caller) is still cheap and correct
|
|
47
|
+
* without relying on every caller remembering to pre-check.
|
|
48
|
+
*/
|
|
49
|
+
export declare function ensureWorkflowCatalogReady(engine: Engine): Promise<void>;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { restoreWorkflowCatalog, WorkflowCatalog } from "../catalog/index.js";
|
|
2
|
+
import { buildWorkflowManifestForType } from "../registry-workflow-manifest.js";
|
|
3
|
+
import { dispatchCatalogInstallAndActivatedEvents } from "./catalog-events.js";
|
|
4
|
+
import { EngineDisposedError } from "./errors.js";
|
|
5
|
+
import { getInternals } from "./internals.js";
|
|
6
|
+
export { getWorkflowCatalog } from "./internals.js";
|
|
7
|
+
async function drainPendingCatalogInstalls(engine) {
|
|
8
|
+
const internals = getInternals(engine), catalog = internals.workflowCatalog, pending = internals.pendingCatalogInstalls;
|
|
9
|
+
internals.pendingCatalogInstalls = [];
|
|
10
|
+
for (let index = 0;index < pending.length; index += 1) {
|
|
11
|
+
const name = pending[index];
|
|
12
|
+
try {
|
|
13
|
+
const manifest = await buildWorkflowManifestForType(engine, name);
|
|
14
|
+
if (manifest === void 0)
|
|
15
|
+
continue;
|
|
16
|
+
const definition = engine.getWorkflowDefinition(name);
|
|
17
|
+
if (definition === void 0)
|
|
18
|
+
continue;
|
|
19
|
+
const preExisting = await catalog.hasInstalled(name, manifest.revision), pointerBefore = await catalog.resolveActiveDurable(name) ?? null, pointerAfter = await catalog.activateRegistered(name, manifest, definition);
|
|
20
|
+
internals.registeredCatalogRevisions.set(name, manifest.revision);
|
|
21
|
+
dispatchCatalogInstallAndActivatedEvents(engine, name, manifest.revision, preExisting, pointerBefore, pointerAfter);
|
|
22
|
+
} catch (error) {
|
|
23
|
+
internals.pendingCatalogInstalls = [
|
|
24
|
+
...pending.slice(index),
|
|
25
|
+
...internals.pendingCatalogInstalls
|
|
26
|
+
];
|
|
27
|
+
throw error;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
export function isWorkflowCatalogReady(engine) {
|
|
32
|
+
const internals = getInternals(engine);
|
|
33
|
+
return internals.catalogRestored && internals.pendingCatalogInstalls.length === 0;
|
|
34
|
+
}
|
|
35
|
+
export async function ensureWorkflowCatalogReady(engine) {
|
|
36
|
+
const internals = getInternals(engine);
|
|
37
|
+
if (isWorkflowCatalogReady(engine))
|
|
38
|
+
return;
|
|
39
|
+
if (internals.catalogDrainPromise !== null) {
|
|
40
|
+
await internals.catalogDrainPromise;
|
|
41
|
+
return ensureWorkflowCatalogReady(engine);
|
|
42
|
+
}
|
|
43
|
+
const drainPromise = (async () => {
|
|
44
|
+
if (internals.disposed)
|
|
45
|
+
throw new EngineDisposedError;
|
|
46
|
+
if (!internals.catalogRestored) {
|
|
47
|
+
internals.workflowCatalog = new WorkflowCatalog(internals.storage, await restoreWorkflowCatalog(internals.storage));
|
|
48
|
+
internals.catalogRestored = !0;
|
|
49
|
+
}
|
|
50
|
+
await drainPendingCatalogInstalls(engine);
|
|
51
|
+
})();
|
|
52
|
+
internals.catalogDrainPromise = drainPromise;
|
|
53
|
+
try {
|
|
54
|
+
await drainPromise;
|
|
55
|
+
} finally {
|
|
56
|
+
if (internals.catalogDrainPromise === drainPromise)
|
|
57
|
+
internals.catalogDrainPromise = null;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reference accounting and removal for the durable workflow catalog
|
|
3
|
+
* (WFT-12): counts in-process references to a `(name, revision)`,
|
|
4
|
+
* decides whether removal is safe, and performs the removal itself —
|
|
5
|
+
* dispatching `WorkflowRevisionRemovedEvent` on success.
|
|
6
|
+
*
|
|
7
|
+
* Also owns the two `EngineInternals.inFlightStartsByRevision` accessors
|
|
8
|
+
* ({@link reserveInFlightStart}/{@link releaseInFlightStart}) that
|
|
9
|
+
* `lifecycle/start.ts` rides alongside its existing `pendingStarts`
|
|
10
|
+
* reservation try/finally, kept here rather than inline in `start.ts` to
|
|
11
|
+
* stay well under that file's line-count ceiling.
|
|
12
|
+
*
|
|
13
|
+
* @module core/engine/catalog-removal
|
|
14
|
+
*/
|
|
15
|
+
import { type WorkflowRevisionReferenceCounts } from '../catalog/index.ts';
|
|
16
|
+
import type { Engine } from './index.ts';
|
|
17
|
+
import { type EngineInternals } from './internals.ts';
|
|
18
|
+
/**
|
|
19
|
+
* Reserve one in-flight-start slot against `type`'s currently active
|
|
20
|
+
* revision (if any), returning the revision reserved (or `undefined` when
|
|
21
|
+
* `type` has no active revision yet — a start under a still-warming
|
|
22
|
+
* catalog, which `Engine.start()`'s own `ensureWorkflowCatalogReady` await
|
|
23
|
+
* prevents in practice). Called once, synchronously, before
|
|
24
|
+
* `startWorkflow`'s `try` block; the returned value is captured by the
|
|
25
|
+
* caller and passed back to {@link releaseInFlightStart} in its `finally` —
|
|
26
|
+
* never re-resolved, so a concurrent activation moving the pointer
|
|
27
|
+
* mid-start cannot decrement a different revision than was incremented.
|
|
28
|
+
*/
|
|
29
|
+
export declare function reserveInFlightStart(internals: EngineInternals, type: string): string | undefined;
|
|
30
|
+
/** Release the slot {@link reserveInFlightStart} reserved; a no-op when `revision` is `undefined`. */
|
|
31
|
+
export declare function releaseInFlightStart(internals: EngineInternals, type: string, revision: string | undefined): void;
|
|
32
|
+
/**
|
|
33
|
+
* Count every in-process reference this batch wires to a real signal
|
|
34
|
+
* against `(name, revision)`. `registeredDefinitions` and `inFlightStarts`
|
|
35
|
+
* are real; the other five fields of {@link WorkflowRevisionReferenceCounts}
|
|
36
|
+
* stay `0` until WFT-17 (see that type's own field-level docs).
|
|
37
|
+
*/
|
|
38
|
+
export declare function countWorkflowRevisionReferences(engine: Engine, name: string, revision: string): Promise<WorkflowRevisionReferenceCounts>;
|
|
39
|
+
/**
|
|
40
|
+
* Outcome of {@link removeWorkflowRevision}.
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* ```ts
|
|
44
|
+
* import type { WorkflowCatalogRemovalResult } from '@lostgradient/weft';
|
|
45
|
+
*
|
|
46
|
+
* function describe(result: WorkflowCatalogRemovalResult): string {
|
|
47
|
+
* return result.removed ? 'removed' : `kept: ${result.reason}`;
|
|
48
|
+
* }
|
|
49
|
+
* void describe;
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
export type WorkflowCatalogRemovalResult = Readonly<{
|
|
53
|
+
removed: true;
|
|
54
|
+
}> | Readonly<{
|
|
55
|
+
removed: false;
|
|
56
|
+
reason: 'not-found';
|
|
57
|
+
}> | Readonly<{
|
|
58
|
+
removed: false;
|
|
59
|
+
reason: 'active';
|
|
60
|
+
activeRevision: string;
|
|
61
|
+
}> | Readonly<{
|
|
62
|
+
removed: false;
|
|
63
|
+
reason: 'referenced';
|
|
64
|
+
references: WorkflowRevisionReferenceCounts;
|
|
65
|
+
}> | Readonly<{
|
|
66
|
+
removed: false;
|
|
67
|
+
reason: 'conflict';
|
|
68
|
+
}>;
|
|
69
|
+
/**
|
|
70
|
+
* Remove `(name, revision)` from the durable workflow catalog. Refuses when
|
|
71
|
+
* the revision is not installed (`'not-found'`), is the currently active
|
|
72
|
+
* revision (`'active'`), or is referenced by any nonzero count in
|
|
73
|
+
* {@link countWorkflowRevisionReferences} (`'referenced'`, carrying the
|
|
74
|
+
* full breakdown so a caller can report exactly what is still holding the
|
|
75
|
+
* revision). Refuses with `'conflict'` when the durable delete's own
|
|
76
|
+
* compare-and-swap loses to a concurrent writer — the caller may re-read
|
|
77
|
+
* and retry. Dispatches `catalog:revision-removed` on success.
|
|
78
|
+
*
|
|
79
|
+
* @example
|
|
80
|
+
* ```ts
|
|
81
|
+
* import { Engine, removeWorkflowRevision, workflow } from '@lostgradient/weft';
|
|
82
|
+
*
|
|
83
|
+
* const engine = new Engine();
|
|
84
|
+
* engine.register(workflow({ name: 'checkout', version: '1.0.0' }).execute(
|
|
85
|
+
* async function* () { return 'ok'; },
|
|
86
|
+
* ));
|
|
87
|
+
* const result = await removeWorkflowRevision(engine, 'checkout', 'some-old-revision');
|
|
88
|
+
* if (!result.removed) console.log('kept:', result.reason);
|
|
89
|
+
* ```
|
|
90
|
+
*/
|
|
91
|
+
export declare function removeWorkflowRevision(engine: Engine, name: string, revision: string): Promise<WorkflowCatalogRemovalResult>;
|
|
92
|
+
/**
|
|
93
|
+
* Bounded diagnostics projection for one `(name, revision)`, backing
|
|
94
|
+
* `weft.catalog.diagnostics` and `removeWorkflowRevision`'s own pre-check.
|
|
95
|
+
*
|
|
96
|
+
* @example
|
|
97
|
+
* ```ts
|
|
98
|
+
* import type { WorkflowRevisionDiagnostics } from '@lostgradient/weft';
|
|
99
|
+
*
|
|
100
|
+
* function isSafeToRemove(diagnostics: WorkflowRevisionDiagnostics): boolean {
|
|
101
|
+
* return diagnostics.removable;
|
|
102
|
+
* }
|
|
103
|
+
* void isSafeToRemove;
|
|
104
|
+
* ```
|
|
105
|
+
*/
|
|
106
|
+
export type WorkflowRevisionDiagnostics = Readonly<{
|
|
107
|
+
name: string;
|
|
108
|
+
revision: string;
|
|
109
|
+
installed: boolean;
|
|
110
|
+
active: boolean;
|
|
111
|
+
activeRevision?: string;
|
|
112
|
+
references: WorkflowRevisionReferenceCounts;
|
|
113
|
+
removable: boolean;
|
|
114
|
+
}>;
|
|
115
|
+
/**
|
|
116
|
+
* Bounded diagnostics for one `(name, revision)`: whether it is installed,
|
|
117
|
+
* whether it is the currently active revision (and what the active
|
|
118
|
+
* revision is, when different), its full reference-count breakdown, and
|
|
119
|
+
* whether {@link removeWorkflowRevision} would currently succeed against
|
|
120
|
+
* it (`removable`). Never returns raw manifest or contract content — only
|
|
121
|
+
* identity and counts.
|
|
122
|
+
*
|
|
123
|
+
* @example
|
|
124
|
+
* ```ts
|
|
125
|
+
* import { Engine, getWorkflowRevisionDiagnostics } from '@lostgradient/weft';
|
|
126
|
+
*
|
|
127
|
+
* const engine = new Engine();
|
|
128
|
+
* const diagnostics = await getWorkflowRevisionDiagnostics(engine, 'checkout', 'some-revision');
|
|
129
|
+
* console.log(diagnostics.installed, diagnostics.removable);
|
|
130
|
+
* ```
|
|
131
|
+
*/
|
|
132
|
+
export declare function getWorkflowRevisionDiagnostics(engine: Engine, name: string, revision: string): Promise<WorkflowRevisionDiagnostics>;
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import {
|
|
2
|
+
decrementNestedRevisionCount,
|
|
3
|
+
incrementNestedRevisionCount,
|
|
4
|
+
readNestedRevisionCount,
|
|
5
|
+
totalWorkflowRevisionReferences
|
|
6
|
+
} from "../catalog/index.js";
|
|
7
|
+
import { WorkflowRevisionRemovedEvent } from "../events/catalog-events.js";
|
|
8
|
+
import { ensureWorkflowCatalogReady, getWorkflowCatalog } from "./catalog-readiness.js";
|
|
9
|
+
import { getInternals } from "./internals.js";
|
|
10
|
+
export function reserveInFlightStart(internals, type) {
|
|
11
|
+
const revision = internals.workflowCatalog?.resolveActive(type)?.revision;
|
|
12
|
+
if (revision !== void 0)
|
|
13
|
+
incrementNestedRevisionCount(internals.inFlightStartsByRevision, type, revision);
|
|
14
|
+
return revision;
|
|
15
|
+
}
|
|
16
|
+
export function releaseInFlightStart(internals, type, revision) {
|
|
17
|
+
if (revision !== void 0)
|
|
18
|
+
decrementNestedRevisionCount(internals.inFlightStartsByRevision, type, revision);
|
|
19
|
+
}
|
|
20
|
+
export async function countWorkflowRevisionReferences(engine, name, revision) {
|
|
21
|
+
const internals = getInternals(engine);
|
|
22
|
+
return {
|
|
23
|
+
registeredDefinitions: internals.registeredCatalogRevisions.get(name) === revision ? 1 : 0,
|
|
24
|
+
inFlightStarts: readNestedRevisionCount(internals.inFlightStartsByRevision, name, revision),
|
|
25
|
+
nonTerminalRuns: 0,
|
|
26
|
+
pinnedSchedules: 0,
|
|
27
|
+
pendingDispatches: 0,
|
|
28
|
+
activeExecutionRealms: 0,
|
|
29
|
+
retainedRecoveryRecords: 0
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
export async function removeWorkflowRevision(engine, name, revision) {
|
|
33
|
+
await ensureWorkflowCatalogReady(engine);
|
|
34
|
+
const catalog = getWorkflowCatalog(engine);
|
|
35
|
+
if (!await catalog.hasInstalled(name, revision))
|
|
36
|
+
return { removed: !1, reason: "not-found" };
|
|
37
|
+
const active = await catalog.resolveActiveDurable(name);
|
|
38
|
+
if (active !== void 0 && active.revision === revision)
|
|
39
|
+
return { removed: !1, reason: "active", activeRevision: active.revision };
|
|
40
|
+
const references = await countWorkflowRevisionReferences(engine, name, revision);
|
|
41
|
+
if (totalWorkflowRevisionReferences(references) > 0)
|
|
42
|
+
return { removed: !1, reason: "referenced", references };
|
|
43
|
+
const result = await catalog.remove(name, revision);
|
|
44
|
+
switch (result.outcome) {
|
|
45
|
+
case "removed":
|
|
46
|
+
engine.dispatchEvent(new WorkflowRevisionRemovedEvent(name, revision));
|
|
47
|
+
return { removed: !0 };
|
|
48
|
+
case "not-found":
|
|
49
|
+
return { removed: !1, reason: "not-found" };
|
|
50
|
+
case "active":
|
|
51
|
+
return { removed: !1, reason: "active", activeRevision: result.activeRevision };
|
|
52
|
+
case "conflict":
|
|
53
|
+
return { removed: !1, reason: "conflict" };
|
|
54
|
+
default:
|
|
55
|
+
throw Error(`Unknown workflow catalog removal outcome: ${String(result)}`);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
export async function getWorkflowRevisionDiagnostics(engine, name, revision) {
|
|
59
|
+
await ensureWorkflowCatalogReady(engine);
|
|
60
|
+
const catalog = getWorkflowCatalog(engine), installed = await catalog.hasInstalled(name, revision), activePointer = await catalog.resolveActiveDurable(name), active = activePointer !== void 0 && activePointer.revision === revision, references = await countWorkflowRevisionReferences(engine, name, revision), removable = installed && !active && totalWorkflowRevisionReferences(references) === 0;
|
|
61
|
+
return {
|
|
62
|
+
name,
|
|
63
|
+
revision,
|
|
64
|
+
installed,
|
|
65
|
+
active,
|
|
66
|
+
...activePointer !== void 0 ? { activeRevision: activePointer.revision } : {},
|
|
67
|
+
references,
|
|
68
|
+
removable
|
|
69
|
+
};
|
|
70
|
+
}
|
|
@@ -32,7 +32,7 @@ export type NormalizedWorkerExecutionConfiguration = {
|
|
|
32
32
|
discardOnCancel: true;
|
|
33
33
|
};
|
|
34
34
|
export declare function definitionEntries<TDefinition extends object>(definitions: Record<string, TDefinition> | undefined): Array<[string, TDefinition]>;
|
|
35
|
-
export declare function typedEngineView
|
|
35
|
+
export declare function typedEngineView(engine: object): never;
|
|
36
36
|
export declare function readEnvironmentVariableFromSources(name: string, sources: {
|
|
37
37
|
bunEnv?: Record<string, string | undefined> | undefined;
|
|
38
38
|
processEnv?: Record<string, string | undefined> | undefined;
|
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
DEFAULT_WORKER_TURN_TIMEOUT_MS,
|
|
16
16
|
MIN_WORKER_PROTOCOL_MESSAGE_BYTES
|
|
17
17
|
} from "../worker-protocol.js";
|
|
18
|
+
import { copyFinalizerMetadata } from "./finalizer-metadata.js";
|
|
18
19
|
import { resolveBackgroundTaskMode, resolveOwnershipFields } from "./ownership-options.js";
|
|
19
20
|
import {
|
|
20
21
|
normalizeHistoryPolicy,
|
|
@@ -25,7 +26,7 @@ import {
|
|
|
25
26
|
export function definitionEntries(definitions) {
|
|
26
27
|
return Object.entries(definitions ?? {});
|
|
27
28
|
}
|
|
28
|
-
export function typedEngineView(engine
|
|
29
|
+
export function typedEngineView(engine) {
|
|
29
30
|
return engine;
|
|
30
31
|
}
|
|
31
32
|
let didWarnOnMemoryStorageFallback = !1;
|
|
@@ -76,7 +77,8 @@ export function copyWorkflowDefinition(type, registration) {
|
|
|
76
77
|
...registration.updates === void 0 ? {} : { updates: { ...registration.updates } },
|
|
77
78
|
...registration.queries === void 0 ? {} : { queries: { ...registration.queries } },
|
|
78
79
|
...registration.searchAttributes === void 0 ? {} : { searchAttributes: registration.searchAttributes },
|
|
79
|
-
...registration.concurrency === void 0 ? {} : { concurrency: registration.concurrency }
|
|
80
|
+
...registration.concurrency === void 0 ? {} : { concurrency: registration.concurrency },
|
|
81
|
+
...copyFinalizerMetadata(registration.finalizer)
|
|
80
82
|
};
|
|
81
83
|
}
|
|
82
84
|
function resolveRetentionFields(options) {
|
|
@@ -13,6 +13,14 @@ function clearPendingResultPollTimers(internals) {
|
|
|
13
13
|
clearTimeout(timer);
|
|
14
14
|
internals.pendingResultPollTimers.clear();
|
|
15
15
|
}
|
|
16
|
+
function disposeSourceResolutionState(internals) {
|
|
17
|
+
for (const controller of internals.sourceResolutionWaiterControllers)
|
|
18
|
+
controller.abort(new EngineDisposedError);
|
|
19
|
+
internals.sourceResolutionWaiterControllers.clear();
|
|
20
|
+
internals.sourceResolutionsInFlight.clear();
|
|
21
|
+
internals.workflowSourcesByName.clear();
|
|
22
|
+
internals.resolvedWorkflowSources.clear();
|
|
23
|
+
}
|
|
16
24
|
export function disposeEngine(internals) {
|
|
17
25
|
internals.disposed = !0;
|
|
18
26
|
internals.alertManager?.[Symbol.dispose]();
|
|
@@ -57,6 +65,7 @@ export function disposeEngine(internals) {
|
|
|
57
65
|
for (const controller of internals.pendingWebhooks)
|
|
58
66
|
controller.abort();
|
|
59
67
|
internals.pendingWebhooks.clear();
|
|
68
|
+
disposeSourceResolutionState(internals);
|
|
60
69
|
clearPendingResultPollTimers(internals);
|
|
61
70
|
internals.sleepResolvers.clear();
|
|
62
71
|
internals.sleepResolversByWorkflow.clear();
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public promotion of the durable workflow catalog (WFT-9/WFT-10) to
|
|
3
|
+
* `engine.workflows` (WFT-11).
|
|
4
|
+
*
|
|
5
|
+
* This namespace is catalog bookkeeping and promotion control ONLY —
|
|
6
|
+
* `install()`/`activate()` change what {@link import('../registry-snapshot.ts').RegistrySnapshot}
|
|
7
|
+
* reports as the active revision, never which in-process handler
|
|
8
|
+
* `engine.start()` dispatches to. Execution routing resolves purely via
|
|
9
|
+
* `internals.registrations` (the workflow the process actually has code
|
|
10
|
+
* for), a concern dynamic module loading (WFT-13+) will connect to catalog
|
|
11
|
+
* activation. Until then, activating a different installed revision is
|
|
12
|
+
* observable only through this namespace, `getActive()`, and
|
|
13
|
+
* `buildRegistrySnapshot()` — starting a new run of `name` still executes
|
|
14
|
+
* whatever `engine.register()` last registered in this process.
|
|
15
|
+
*
|
|
16
|
+
* A later `engine.register()` call (or the restart-drain path that replays
|
|
17
|
+
* `pendingCatalogInstalls`) can silently revert a manual `activate()` here —
|
|
18
|
+
* `WorkflowCatalog.activateRegistered` is unconditional by design (see its
|
|
19
|
+
* own JSDoc) and does not consult or preserve a prior candidate activation.
|
|
20
|
+
* Reconciling loader-driven and registration-driven activation is WFT-13's
|
|
21
|
+
* job; this namespace does not attempt it.
|
|
22
|
+
*
|
|
23
|
+
* Every method awaits {@link ensureWorkflowCatalogReady} first (skipping the
|
|
24
|
+
* `await` entirely when {@link isWorkflowCatalogReady} already reports warm,
|
|
25
|
+
* matching every other catalog-observing entry point in `index.ts`), so the
|
|
26
|
+
* catalog is always restored from storage and every pending
|
|
27
|
+
* `engine.register()` install is drained before this namespace reads or
|
|
28
|
+
* writes it.
|
|
29
|
+
*
|
|
30
|
+
* @module core/engine/engine-workflows-namespace
|
|
31
|
+
*/
|
|
32
|
+
import { type WorkflowCatalogActivationResult, type WorkflowCatalogActivePointer, type WorkflowRevisionRecord } from '../catalog/index.ts';
|
|
33
|
+
import type { WorkflowCompatibilityPolicy } from '../contract/compatibility.ts';
|
|
34
|
+
import type { WorkflowRevisionManifest } from '../contract/types.ts';
|
|
35
|
+
import type { Engine } from './index.ts';
|
|
36
|
+
/**
|
|
37
|
+
* Options accepted by {@link EngineWorkflowsNamespace.activate}.
|
|
38
|
+
*
|
|
39
|
+
* @example
|
|
40
|
+
* ```ts
|
|
41
|
+
* import { Engine } from '@lostgradient/weft';
|
|
42
|
+
* import type { ActivateWorkflowRevisionOptions } from '@lostgradient/weft';
|
|
43
|
+
*
|
|
44
|
+
* const engine = new Engine();
|
|
45
|
+
* const active = await engine.workflows.getActive('checkout');
|
|
46
|
+
* const options: ActivateWorkflowRevisionOptions = {
|
|
47
|
+
* ...(active === null ? {} : { expectedGeneration: active.generation }),
|
|
48
|
+
* policy: { requireExactRevision: false },
|
|
49
|
+
* };
|
|
50
|
+
* console.log(options.expectedGeneration);
|
|
51
|
+
* ```
|
|
52
|
+
*/
|
|
53
|
+
export type ActivateWorkflowRevisionOptions = {
|
|
54
|
+
/**
|
|
55
|
+
* The generation this caller last observed. Required once `name` has an
|
|
56
|
+
* active pointer — an omitted value there refuses with
|
|
57
|
+
* `expected-generation-required` rather than silently activating, which
|
|
58
|
+
* is what prevents two refreshers from racing to last-write-win. Omit (or
|
|
59
|
+
* pass `0`) for the very first activation of a name, which has no prior
|
|
60
|
+
* generation to name.
|
|
61
|
+
*/
|
|
62
|
+
expectedGeneration?: number;
|
|
63
|
+
/** Compatibility policy; defaults to `DEFAULT_WORKFLOW_COMPATIBILITY_POLICY`. */
|
|
64
|
+
policy?: WorkflowCompatibilityPolicy;
|
|
65
|
+
};
|
|
66
|
+
/**
|
|
67
|
+
* Admin-facing surface over the durable workflow catalog: install a
|
|
68
|
+
* revision's manifest, activate an installed revision as the advertised
|
|
69
|
+
* active one, and read back installed/active state. Workflow code never
|
|
70
|
+
* touches this — it is an external maintenance and deployment-tooling
|
|
71
|
+
* surface, the same audience `engine.state.*` serves.
|
|
72
|
+
*
|
|
73
|
+
* @example
|
|
74
|
+
* ```ts
|
|
75
|
+
* import { Engine, buildWorkflowContract, buildWorkflowRevisionManifest } from '@lostgradient/weft';
|
|
76
|
+
* import { workflow, type WorkflowContext } from '@lostgradient/weft';
|
|
77
|
+
* import type { EngineWorkflowsNamespace } from '@lostgradient/weft';
|
|
78
|
+
*
|
|
79
|
+
* const checkout = workflow({ name: 'checkout', version: '1.0.0' }).execute(
|
|
80
|
+
* async function* (_ctx: WorkflowContext, input: string) {
|
|
81
|
+
* return input;
|
|
82
|
+
* },
|
|
83
|
+
* );
|
|
84
|
+
*
|
|
85
|
+
* const engine = new Engine();
|
|
86
|
+
* engine.register(checkout);
|
|
87
|
+
* const workflows: EngineWorkflowsNamespace = engine.workflows;
|
|
88
|
+
*
|
|
89
|
+
* const contract = buildWorkflowContract({ name: 'checkout', version: '1.0.0' });
|
|
90
|
+
* const manifest = await buildWorkflowRevisionManifest(contract);
|
|
91
|
+
* const record = await workflows.install(manifest);
|
|
92
|
+
* const result = await workflows.activate('checkout', record.manifest.revision);
|
|
93
|
+
* console.log(result.applied);
|
|
94
|
+
* ```
|
|
95
|
+
*/
|
|
96
|
+
export interface EngineWorkflowsNamespace {
|
|
97
|
+
/**
|
|
98
|
+
* Install `manifest` for durable tracking. Requires
|
|
99
|
+
* `engine.getWorkflowDefinition(manifest.name)` to already resolve
|
|
100
|
+
* in-process — this namespace installs bookkeeping for a definition the
|
|
101
|
+
* engine already has, it does not load one (that is WFT-13+'s job).
|
|
102
|
+
* Idempotent on a byte-identical reinstall; throws
|
|
103
|
+
* {@link WorkflowCatalogConflictError} when `(manifest.name, manifest.revision)`
|
|
104
|
+
* is already installed with different contract content, and
|
|
105
|
+
* {@link WorkflowNotRegisteredError} when no in-process definition exists.
|
|
106
|
+
*/
|
|
107
|
+
install(manifest: WorkflowRevisionManifest): Promise<WorkflowRevisionRecord>;
|
|
108
|
+
/**
|
|
109
|
+
* Activate an already-installed `(name, revision)` as the durably
|
|
110
|
+
* advertised active revision. Throws
|
|
111
|
+
* {@link WorkflowRevisionNotInstalledError} when that revision was never
|
|
112
|
+
* installed; otherwise delegates to the catalog's guarded
|
|
113
|
+
* `activateCandidate` and returns its structured result verbatim,
|
|
114
|
+
* including every `applied: false` refusal variant.
|
|
115
|
+
*/
|
|
116
|
+
activate(name: string, revision: string, options?: ActivateWorkflowRevisionOptions): Promise<WorkflowCatalogActivationResult>;
|
|
117
|
+
/**
|
|
118
|
+
* The current active pointer for `name`, or `null` when never activated.
|
|
119
|
+
* In-memory only, matching {@link import('../registry-snapshot.ts').RegistrySnapshot}'s
|
|
120
|
+
* `activeRevisions` staleness contract exactly — the property that makes
|
|
121
|
+
* "operations and the registry snapshot agree" true by construction.
|
|
122
|
+
*/
|
|
123
|
+
getActive(name: string): Promise<WorkflowCatalogActivePointer | null>;
|
|
124
|
+
/** One installed `(name, revision)` record, or `null` when not installed. */
|
|
125
|
+
getRevision(name: string, revision: string): Promise<WorkflowRevisionRecord | null>;
|
|
126
|
+
/** Every installed revision of `name`, sorted deterministically by revision. */
|
|
127
|
+
listRevisions(name: string): Promise<readonly WorkflowRevisionRecord[]>;
|
|
128
|
+
}
|
|
129
|
+
/** Build the `engine.workflows` namespace object for `engine`. */
|
|
130
|
+
export declare function createEngineWorkflowsNamespace(engine: Engine): EngineWorkflowsNamespace;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import {
|
|
2
|
+
WorkflowRevisionNotInstalledError
|
|
3
|
+
} from "../catalog/index.js";
|
|
4
|
+
import { activateCatalogRevisionCandidate } from "./catalog-activation.js";
|
|
5
|
+
import {
|
|
6
|
+
ensureWorkflowCatalogReady,
|
|
7
|
+
getWorkflowCatalog,
|
|
8
|
+
isWorkflowCatalogReady
|
|
9
|
+
} from "./catalog-readiness.js";
|
|
10
|
+
import { WorkflowNotRegisteredError } from "./errors.js";
|
|
11
|
+
async function ensureCatalogReady(engine) {
|
|
12
|
+
if (!isWorkflowCatalogReady(engine))
|
|
13
|
+
await ensureWorkflowCatalogReady(engine);
|
|
14
|
+
}
|
|
15
|
+
async function installWorkflowRevision(engine, manifest) {
|
|
16
|
+
await ensureCatalogReady(engine);
|
|
17
|
+
if (engine.getWorkflowDefinition(manifest.name) === void 0)
|
|
18
|
+
throw new WorkflowNotRegisteredError(manifest.name);
|
|
19
|
+
const entry = await getWorkflowCatalog(engine).install(manifest);
|
|
20
|
+
return { manifest: entry.manifest, installedAt: entry.installedAt };
|
|
21
|
+
}
|
|
22
|
+
async function activateWorkflowRevision(engine, name, revision, options) {
|
|
23
|
+
await ensureCatalogReady(engine);
|
|
24
|
+
const entry = await getWorkflowCatalog(engine).resolveEntry(name, revision);
|
|
25
|
+
if (entry === void 0)
|
|
26
|
+
throw new WorkflowRevisionNotInstalledError(name, revision);
|
|
27
|
+
return activateCatalogRevisionCandidate(engine, name, entry.manifest, options);
|
|
28
|
+
}
|
|
29
|
+
async function getActiveWorkflowRevision(engine, name) {
|
|
30
|
+
await ensureCatalogReady(engine);
|
|
31
|
+
return getWorkflowCatalog(engine).resolveActive(name) ?? null;
|
|
32
|
+
}
|
|
33
|
+
async function getInstalledWorkflowRevision(engine, name, revision) {
|
|
34
|
+
await ensureCatalogReady(engine);
|
|
35
|
+
return await getWorkflowCatalog(engine).resolveEntry(name, revision) ?? null;
|
|
36
|
+
}
|
|
37
|
+
async function listInstalledWorkflowRevisions(engine, name) {
|
|
38
|
+
await ensureCatalogReady(engine);
|
|
39
|
+
return getWorkflowCatalog(engine).listInstalledRevisions(name);
|
|
40
|
+
}
|
|
41
|
+
export function createEngineWorkflowsNamespace(engine) {
|
|
42
|
+
return {
|
|
43
|
+
install: (manifest) => installWorkflowRevision(engine, manifest),
|
|
44
|
+
activate: (name, revision, options) => activateWorkflowRevision(engine, name, revision, options),
|
|
45
|
+
getActive: (name) => getActiveWorkflowRevision(engine, name),
|
|
46
|
+
getRevision: (name, revision) => getInstalledWorkflowRevision(engine, name, revision),
|
|
47
|
+
listRevisions: (name) => listInstalledWorkflowRevisions(engine, name)
|
|
48
|
+
};
|
|
49
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Project a registration's stored definition-level finalizer onto the
|
|
3
|
+
* public, schema-only shape {@link RegisteredWorkflowDefinition.finalizer}
|
|
4
|
+
* exposes — split out of `construction.ts` so `copyWorkflowDefinition` stays
|
|
5
|
+
* under the repository's per-function complexity ceiling.
|
|
6
|
+
*
|
|
7
|
+
* @module core/engine/finalizer-metadata
|
|
8
|
+
*/
|
|
9
|
+
import type { AnyActivityDefinition } from '../types.ts';
|
|
10
|
+
import type { RegisteredWorkflowDefinition } from '../types/workflow-registry.ts';
|
|
11
|
+
/**
|
|
12
|
+
* Convert a stored `RegistrationEntry.finalizer` (when present) to a
|
|
13
|
+
* directly spreadable `{ finalizer: {...} } | {}` carrying the narrower
|
|
14
|
+
* schema-only shape `RegisteredWorkflowDefinition.finalizer` exposes — never
|
|
15
|
+
* the finalizer's `execute` handler, matching this interface's read-only
|
|
16
|
+
* introspection contract (the workflow's own handler is likewise never
|
|
17
|
+
* exposed). Returning the already-branched spread target (rather than
|
|
18
|
+
* `finalizer | undefined`, which would push a `=== undefined` ternary back
|
|
19
|
+
* onto the caller) keeps `copyWorkflowDefinition` under the repository's
|
|
20
|
+
* per-function complexity ceiling.
|
|
21
|
+
*/
|
|
22
|
+
export declare function copyFinalizerMetadata(finalizer: AnyActivityDefinition | undefined): Partial<Pick<RegisteredWorkflowDefinition, 'finalizer'>>;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export function copyFinalizerMetadata(finalizer) {
|
|
2
|
+
if (finalizer === void 0)
|
|
3
|
+
return {};
|
|
4
|
+
const source = finalizer;
|
|
5
|
+
return {
|
|
6
|
+
finalizer: {
|
|
7
|
+
name: source.name,
|
|
8
|
+
...source.inputSchema === void 0 ? {} : { inputSchema: source.inputSchema },
|
|
9
|
+
...source.outputSchema === void 0 ? {} : { outputSchema: source.outputSchema }
|
|
10
|
+
}
|
|
11
|
+
};
|
|
12
|
+
}
|
|
@@ -34,9 +34,11 @@ function fenceResultOnParentGeneration(internals, parentWorkflowId, promise) {
|
|
|
34
34
|
promise.then(async (value) => {
|
|
35
35
|
if (await parentStillOwnsGeneration(internals, parentWorkflowId))
|
|
36
36
|
gate.resolve(value);
|
|
37
|
+
return;
|
|
37
38
|
}, async (error) => {
|
|
38
39
|
if (await parentStillOwnsGeneration(internals, parentWorkflowId))
|
|
39
40
|
gate.reject(error);
|
|
41
|
+
return;
|
|
40
42
|
});
|
|
41
43
|
return gate.promise;
|
|
42
44
|
}
|