@lostgradient/weft 0.11.0 → 0.13.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 +1 -1
- package/dist/cli/api.d.ts +2 -0
- package/dist/cli/api.js +3 -4
- package/dist/cli/generated/operation-catalog.snapshot.json +5167 -0
- package/dist/cli/generated/operation-client.generated.d.ts +119 -10
- package/dist/cli/generated/operation-client.generated.js +74 -1
- package/dist/cli/index.js +1 -0
- package/dist/cli/operation-catalog-snapshot.d.ts +11 -2
- package/dist/cli/operation-catalog-snapshot.js +14 -5
- package/dist/cli/operation-client-runtime.d.ts +29 -0
- package/dist/cli-main.js +227 -401
- package/dist/client/client-storage.d.ts +24 -0
- package/dist/client/client-storage.js +14 -0
- package/dist/client/handle-delegation.d.ts +3 -3
- package/dist/client/handle-delegation.js +2 -2
- package/dist/client/http-client-requests.d.ts +5 -3
- package/dist/client/http-client-requests.js +20 -2
- package/dist/client/http-client-storage.d.ts +3 -0
- package/dist/client/http-client-storage.js +110 -0
- package/dist/client/http-client.d.ts +9 -6
- package/dist/client/http-client.js +13 -18
- package/dist/client/http-operations.d.ts +3 -1
- package/dist/client/http-operations.js +84 -2
- package/dist/client/http-request.d.ts +35 -6
- package/dist/client/http-request.js +31 -10
- package/dist/client/in-process-operations.d.ts +2 -2
- package/dist/client/in-process-operations.js +2 -2
- package/dist/client/index.d.ts +6 -0
- package/dist/client/index.js +18 -0
- package/dist/client/interface.d.ts +26 -26
- package/dist/client/local.d.ts +9 -6
- package/dist/client/local.js +9 -4
- package/dist/client/search-params.js +10 -6
- package/dist/client/start-body.d.ts +3 -1
- package/dist/client/start-body.js +9 -0
- package/dist/connection.d.ts +8 -0
- package/dist/connection.js +41 -17
- package/dist/core/bulk-workflow-filter.d.ts +2 -1
- package/dist/core/bulk-workflow-filter.js +5 -1
- package/dist/core/engine/async-activity-records.d.ts +12 -1
- package/dist/core/engine/async-activity-records.js +81 -2
- package/dist/core/engine/bulk-operations-purge.js +16 -1
- package/dist/core/engine/bulk-operations-shared.js +2 -0
- package/dist/core/engine/callback-creators-core.js +2 -1
- package/dist/core/engine/callback-creators-schedule.d.ts +2 -1
- package/dist/core/engine/callback-creators-schedule.js +3 -3
- package/dist/core/engine/checkpoint-reads.js +11 -1
- package/dist/core/engine/child-workflow.js +15 -6
- package/dist/core/engine/construction.js +3 -0
- package/dist/core/engine/disposal.js +2 -0
- package/dist/core/engine/engine-internal-types.d.ts +4 -1
- package/dist/core/engine/fenced-write.d.ts +5 -3
- package/dist/core/engine/finalizer-status.d.ts +10 -0
- package/dist/core/engine/finalizer-status.js +82 -0
- package/dist/core/engine/index.d.ts +69 -2
- package/dist/core/engine/index.js +71 -8
- package/dist/core/engine/internals.d.ts +3 -0
- package/dist/core/engine/lease-health.d.ts +64 -0
- package/dist/core/engine/lease-health.js +0 -0
- package/dist/core/engine/lease-manager.d.ts +4 -2
- package/dist/core/engine/lease-manager.js +32 -4
- package/dist/core/engine/lifecycle/recovered-services.js +0 -2
- package/dist/core/engine/lifecycle/shared.d.ts +28 -0
- package/dist/core/engine/lifecycle/start-batch.js +12 -0
- package/dist/core/engine/lifecycle/start.d.ts +1 -1
- package/dist/core/engine/lifecycle/start.js +34 -5
- package/dist/core/engine/lifecycle/transition.js +19 -9
- package/dist/core/engine/operations-coordination.d.ts +1 -12
- package/dist/core/engine/operations-coordination.js +57 -10
- package/dist/core/engine/operations-speculate.d.ts +1 -1
- package/dist/core/engine/operations-speculate.js +19 -5
- package/dist/core/engine/registration.js +14 -0
- package/dist/core/engine/schedule-handle.d.ts +4 -4
- package/dist/core/engine/schedule-handle.js +2 -2
- package/dist/core/engine/schedule-overlap.d.ts +11 -0
- package/dist/core/engine/schedule-overlap.js +50 -0
- package/dist/core/engine/schedule-run.d.ts +11 -3
- package/dist/core/engine/schedule-run.js +27 -4
- package/dist/core/engine/schedule-timer.js +10 -1
- package/dist/core/engine/schedules.d.ts +5 -4
- package/dist/core/engine/schedules.js +62 -56
- package/dist/core/engine/state-utilities.js +1 -1
- package/dist/core/engine/storage-io.d.ts +12 -0
- package/dist/core/engine/storage-io.js +49 -10
- package/dist/core/engine/termination/finalizer-claim.d.ts +8 -6
- package/dist/core/engine/termination/finalizer-claim.js +2 -1
- package/dist/core/engine/termination/finalizer.js +10 -14
- package/dist/core/engine/timeline-coordinator-constants.d.ts +3 -0
- package/dist/core/engine/timeline-coordinator-constants.js +1 -0
- package/dist/core/engine/timeline-coordinator-detail.d.ts +13 -0
- package/dist/core/engine/timeline-coordinator-detail.js +76 -0
- package/dist/core/engine/validation/schedule-options.d.ts +8 -1
- package/dist/core/engine/validation/schedule-options.js +18 -0
- package/dist/core/engine/validation/schedule.d.ts +1 -1
- package/dist/core/engine/validation/schedule.js +27 -3
- package/dist/core/engine/validation.js +66 -2
- package/dist/core/engine/workflow-state-stream.d.ts +5 -1
- package/dist/core/engine/workflow-state-stream.js +37 -14
- package/dist/core/events/schedule-events.d.ts +3 -4
- package/dist/core/events/workflow-events.d.ts +2 -1
- package/dist/core/list-filter-validation.d.ts +3 -0
- package/dist/core/list-filter-validation.js +11 -0
- package/dist/core/registry-snapshot.d.ts +32 -0
- package/dist/core/registry-snapshot.js +28 -0
- package/dist/core/review/index.d.ts +4 -4
- package/dist/core/types/activity.d.ts +52 -5
- package/dist/core/types/bulk.d.ts +1 -0
- package/dist/core/types/definition-schema-to-json.d.ts +11 -0
- package/dist/core/types/definition-schema-to-json.js +11 -2
- package/dist/core/types/list-options.d.ts +6 -0
- package/dist/core/types/options.d.ts +6 -5
- package/dist/core/types/reviews.d.ts +2 -2
- package/dist/core/types/schedules.d.ts +45 -2
- package/dist/core/types/services-resolution.d.ts +5 -5
- package/dist/core/types/state.d.ts +64 -0
- package/dist/core/types/workflow-log.d.ts +3 -2
- package/dist/core/types/workflow-observability.d.ts +50 -0
- package/dist/core/types/workflow-observability.js +0 -0
- package/dist/core/types/workflow-registry.d.ts +7 -0
- package/dist/core/types.d.ts +1 -0
- package/dist/core/types.js +1 -0
- package/dist/http.js +2 -0
- package/dist/index.d.ts +4 -3
- package/dist/indexeddb.js +1 -0
- package/dist/json-schema.js +3 -3
- package/dist/mcp/cli.js +63 -61
- package/dist/mcp/http.d.ts +7 -2
- package/dist/mcp/session.d.ts +3 -3
- package/dist/mcp/session.js +3 -2
- package/dist/mcp/stdio.d.ts +7 -2
- package/dist/observability/index.js +2 -2
- package/dist/runtime/portable.d.ts +33 -0
- package/dist/runtime/portable.js +17 -6
- package/dist/server/access-policy-metadata.d.ts +92 -0
- package/dist/server/access-policy-metadata.js +78 -0
- package/dist/server/engine-event-feed-backend.d.ts +22 -3
- package/dist/server/fault-to-http.d.ts +3 -7
- package/dist/server/fault-to-http.js +2 -34
- package/dist/server/fleet-event-feed.d.ts +65 -0
- package/dist/server/handler/index.d.ts +11 -2
- package/dist/server/handler/index.js +8 -1
- package/dist/server/handler/route-dispatch.d.ts +10 -3
- package/dist/server/handler/route-dispatch.js +19 -4
- package/dist/server/handler.js +1 -56
- package/dist/server/index.d.ts +13 -2
- package/dist/server/index.js +88 -64
- package/dist/server/interactive-operations.js +2 -0
- package/dist/server/openapi-error-responses.js +55 -4
- package/dist/server/openapi.d.ts +3 -1
- package/dist/server/openapi.js +4 -0
- package/dist/server/openrpc-document-schema.d.ts +64 -0
- package/dist/server/openrpc-document-schema.js +6 -26
- package/dist/server/openrpc.d.ts +4 -0
- package/dist/server/openrpc.js +9 -33
- package/dist/server/operation-fault.d.ts +24 -7
- package/dist/server/operation-fault.js +65 -13
- package/dist/server/operations/aggregate-workflows.d.ts +6 -0
- package/dist/server/operations/aggregate-workflows.js +3 -2
- package/dist/server/operations/async-activity.d.ts +14 -0
- package/dist/server/operations/async-activity.js +88 -4
- package/dist/server/operations/bulk-filter-helpers.d.ts +3 -0
- package/dist/server/operations/bulk-filter-helpers.js +27 -3
- package/dist/server/operations/bulk-mutate-workflow-tags.d.ts +6 -0
- package/dist/server/operations/bulk-signal-workflows.d.ts +6 -0
- package/dist/server/operations/get-stream-chunks.js +2 -7
- package/dist/server/operations/get-system-lease.d.ts +19 -0
- package/dist/server/operations/get-system-lease.js +48 -0
- package/dist/server/operations/get-workflow-observability.d.ts +24 -0
- package/dist/server/operations/get-workflow-observability.js +80 -0
- package/dist/server/operations/get-workflow-result.js +2 -2
- package/dist/server/operations/get-workflow.d.ts +2 -2
- package/dist/server/operations/list-filter-query-extractor.js +15 -0
- package/dist/server/operations/list-workflows.d.ts +6 -0
- package/dist/server/operations/list-workflows.js +12 -3
- package/dist/server/operations/operation-helpers.d.ts +9 -18
- package/dist/server/operations/operation-helpers.js +5 -23
- package/dist/server/operations/purge-workflows.d.ts +3 -0
- package/dist/server/operations/recover-all.js +2 -1
- package/dist/server/operations/single-workflow-tag-mutation.js +2 -2
- package/dist/server/operations/sse-stream.js +2 -7
- package/dist/server/operations/storage-capabilities.d.ts +34 -0
- package/dist/server/operations/storage-capabilities.js +38 -0
- package/dist/server/operations/storage.js +8 -17
- package/dist/server/operations/stream-workflow-sse.js +3 -9
- package/dist/server/operations/submit-review-decision.d.ts +2 -0
- package/dist/server/operations/submit-review-decision.js +19 -2
- package/dist/server/operations/update-schedule.d.ts +8 -0
- package/dist/server/operations/update-schedule.js +70 -7
- package/dist/server/operations/workflow-events-sse.js +2 -2
- package/dist/server/replay-live-feed-internals.d.ts +19 -0
- package/dist/server/replay-live-feed-internals.js +76 -0
- package/dist/server/rest-binding.d.ts +7 -6
- package/dist/server/rest-bindings.d.ts +2 -13
- package/dist/server/rest-bindings.js +19 -10
- package/dist/server/runtime/authentication-bridge.d.ts +2 -2
- package/dist/server/serve-internals.js +3 -3
- package/dist/server/task-queue.d.ts +7 -5
- package/dist/server/workflow-event-feed.d.ts +100 -11
- package/dist/server/workflow-event-feed.js +1 -140
- package/dist/service-worker/index.d.ts +8 -2
- package/dist/service-worker/index.js +37 -56
- package/dist/service-worker/setup.d.ts +6 -2
- package/dist/storage/auto.js +1 -1
- package/dist/storage/bun-sql.js +3 -3
- package/dist/storage/capabilities.d.ts +1 -1
- package/dist/storage/cloudflare-durable-object-sql.d.ts +75 -0
- package/dist/storage/cloudflare-durable-object-sql.js +0 -0
- package/dist/storage/cloudflare-value-codec.d.ts +67 -0
- package/dist/storage/cloudflare-value-codec.js +46 -0
- package/dist/storage/cloudflare.d.ts +140 -0
- package/dist/storage/cloudflare.js +127 -0
- package/dist/storage/compressed-storage.js +1 -1
- package/dist/storage/http.js +200 -2
- package/dist/storage/index.d.ts +8 -1
- package/dist/storage/indexeddb.js +311 -1
- package/dist/storage/interface.d.ts +16 -4
- package/dist/storage/interface.js +1 -1
- package/dist/storage/key-prefixes.d.ts +1 -1
- package/dist/storage/key-prefixes.js +4 -0
- package/dist/storage/lmdb.js +1 -1
- package/dist/storage/memory.js +1 -1
- package/dist/storage/neon.js +4 -4
- package/dist/storage/node-sqlite.js +3 -3
- package/dist/storage/postgres-key-value-queries.d.ts +6 -0
- package/dist/storage/postgres-key-value-queries.js +2 -3
- package/dist/storage/postgres.js +4 -4
- package/dist/storage/resolve.js +1 -1
- package/dist/storage/scoped-storage.js +1 -1
- package/dist/storage/sql-identifier.d.ts +35 -0
- package/dist/storage/sql-identifier.js +5 -0
- package/dist/storage/sqlite-key-value-queries.d.ts +11 -6
- package/dist/storage/sqlite-key-value-queries.js +3 -3
- package/dist/storage/testing.js +1 -1
- package/dist/storage/turso.js +2 -2
- package/dist/storage/typed-storage.js +138 -2
- package/dist/storage/web-extension.js +298 -1
- package/dist/testing/index.js +21 -60
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/web-extension.js +1 -0
- package/dist/worker/protocol.js +1 -1
- package/package.json +8 -3
|
@@ -2,8 +2,8 @@ import { KEYS, encodeStorageKeyComponent } from "../../storage/interface.js";
|
|
|
2
2
|
import { decode, encode } from "../codec.js";
|
|
3
3
|
import { ActivityAsyncPendingEvent } from "../events.js";
|
|
4
4
|
import { commitFencedEngineWrite } from "./fenced-write.js";
|
|
5
|
-
const ASYNC_ACTIVITY_TOKEN_PREFIX = "async-act:v1";
|
|
6
|
-
export const ASYNC_ACTIVITY_KEY_PREFIX = "async-act:v1:";
|
|
5
|
+
const ASYNC_ACTIVITY_TOKEN_PREFIX = "async-act:v1", PENDING_ASYNC_ACTIVITY_CURSOR_PREFIX = "pending-async:v1:";
|
|
6
|
+
export const DEFAULT_PENDING_ASYNC_ACTIVITY_LIMIT = 50, MAX_PENDING_ASYNC_ACTIVITY_LIMIT = 200, MAX_PENDING_ASYNC_ACTIVITY_CURSOR_LENGTH = 8192, ASYNC_ACTIVITY_KEY_PREFIX = "async-act:v1:";
|
|
7
7
|
export function asyncActivityWorkflowPrefix(workflowId) {
|
|
8
8
|
return `${ASYNC_ACTIVITY_KEY_PREFIX}${encodeStorageKeyComponent(workflowId)}:`;
|
|
9
9
|
}
|
|
@@ -13,6 +13,85 @@ function isPersistedAsyncActivity(value) {
|
|
|
13
13
|
const record = value;
|
|
14
14
|
return record.version === 1 && typeof record.token === "string" && typeof record.workflowId === "string" && typeof record.activityName === "string" && typeof record.operationId === "string" && typeof record.step === "number" && typeof record.attempt === "number" && typeof record.createdAt === "number";
|
|
15
15
|
}
|
|
16
|
+
function decodePendingAsyncActivityCursor(cursor) {
|
|
17
|
+
if (cursor.length > MAX_PENDING_ASYNC_ACTIVITY_CURSOR_LENGTH || !cursor.startsWith(PENDING_ASYNC_ACTIVITY_CURSOR_PREFIX))
|
|
18
|
+
return null;
|
|
19
|
+
try {
|
|
20
|
+
const suffix = decodeURIComponent(cursor.slice(PENDING_ASYNC_ACTIVITY_CURSOR_PREFIX.length));
|
|
21
|
+
return suffix.length > 0 ? suffix : null;
|
|
22
|
+
} catch {
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
export function isPendingAsyncActivityCursor(cursor) {
|
|
27
|
+
return decodePendingAsyncActivityCursor(cursor) !== null;
|
|
28
|
+
}
|
|
29
|
+
export function isPendingAsyncActivityCursorForWorkflow(cursor, workflowId) {
|
|
30
|
+
const key = decodePendingAsyncActivityCursor(cursor), prefix = asyncActivityWorkflowPrefix(workflowId);
|
|
31
|
+
return key !== null && key.startsWith(prefix) && key.length > prefix.length;
|
|
32
|
+
}
|
|
33
|
+
function encodePendingAsyncActivityCursor(key) {
|
|
34
|
+
return `${PENDING_ASYNC_ACTIVITY_CURSOR_PREFIX}${encodeURIComponent(key)}`;
|
|
35
|
+
}
|
|
36
|
+
function resolvePendingAsyncActivityLimit(limit) {
|
|
37
|
+
const resolved = limit ?? DEFAULT_PENDING_ASYNC_ACTIVITY_LIMIT;
|
|
38
|
+
if (!Number.isSafeInteger(resolved) || resolved < 1 || resolved > MAX_PENDING_ASYNC_ACTIVITY_LIMIT)
|
|
39
|
+
throw RangeError(`Pending async activity limit must be an integer between 1 and ${MAX_PENDING_ASYNC_ACTIVITY_LIMIT}.`);
|
|
40
|
+
return resolved;
|
|
41
|
+
}
|
|
42
|
+
function toPendingAsyncActivityInfo(value, key, workflowId) {
|
|
43
|
+
if (!isPersistedAsyncActivity(value))
|
|
44
|
+
return null;
|
|
45
|
+
if (value.workflowId !== workflowId || key !== KEYS.asyncActivity(workflowId, value.token))
|
|
46
|
+
return null;
|
|
47
|
+
if (!Number.isSafeInteger(value.step) || value.step < 0 || !Number.isSafeInteger(value.attempt) || value.attempt < 1 || !Number.isFinite(value.createdAt))
|
|
48
|
+
return null;
|
|
49
|
+
return {
|
|
50
|
+
token: value.token,
|
|
51
|
+
operationId: value.operationId,
|
|
52
|
+
activityName: value.activityName,
|
|
53
|
+
step: value.step,
|
|
54
|
+
attempt: value.attempt,
|
|
55
|
+
createdAt: value.createdAt
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
function resolvePendingAsyncActivityAfterKey(cursor, workflowId) {
|
|
59
|
+
if (cursor === void 0)
|
|
60
|
+
return;
|
|
61
|
+
const key = decodePendingAsyncActivityCursor(cursor);
|
|
62
|
+
if (key === null || !isPendingAsyncActivityCursorForWorkflow(cursor, workflowId))
|
|
63
|
+
throw TypeError("Invalid pending async activity cursor.");
|
|
64
|
+
return key;
|
|
65
|
+
}
|
|
66
|
+
function decodePendingAsyncActivityInfo(bytes, key, workflowId) {
|
|
67
|
+
try {
|
|
68
|
+
return toPendingAsyncActivityInfo(decode(bytes), key, workflowId);
|
|
69
|
+
} catch {
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
function pendingAsyncActivityPage(scanned, limit, workflowId) {
|
|
74
|
+
const pageEntries = scanned.slice(0, limit), items = pageEntries.flatMap(([key, bytes]) => {
|
|
75
|
+
const item = decodePendingAsyncActivityInfo(bytes, key, workflowId);
|
|
76
|
+
return item === null ? [] : [item];
|
|
77
|
+
}), cursorKey = pageEntries.at(-1)?.[0];
|
|
78
|
+
return {
|
|
79
|
+
items,
|
|
80
|
+
...scanned.length > limit && cursorKey !== void 0 ? { nextCursor: encodePendingAsyncActivityCursor(cursorKey) } : {}
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
export async function listPendingAsyncActivities(internals, workflowId, options = {}) {
|
|
84
|
+
const limit = resolvePendingAsyncActivityLimit(options.limit), prefix = asyncActivityWorkflowPrefix(workflowId), afterKey = resolvePendingAsyncActivityAfterKey(options.cursor, workflowId), scanned = [];
|
|
85
|
+
for await (const entry of internals.storage.scan(prefix, {
|
|
86
|
+
limit: limit + 1,
|
|
87
|
+
...afterKey === void 0 ? {} : { gt: afterKey }
|
|
88
|
+
})) {
|
|
89
|
+
scanned.push(entry);
|
|
90
|
+
if (scanned.length >= limit + 1)
|
|
91
|
+
break;
|
|
92
|
+
}
|
|
93
|
+
return pendingAsyncActivityPage(scanned, limit, workflowId);
|
|
94
|
+
}
|
|
16
95
|
function isPersistedOperationOutcome(value) {
|
|
17
96
|
if (typeof value !== "object" || value === null)
|
|
18
97
|
return !1;
|
|
@@ -12,6 +12,7 @@ import { asyncActivityWorkflowPrefix } from "./async-activity-records.js";
|
|
|
12
12
|
import { forgetCommittedCheckpointBytes } from "./checkpoint-commit-snapshots.js";
|
|
13
13
|
import { commitFencedEngineWrite } from "./fenced-write.js";
|
|
14
14
|
import { streamWorkflowStates } from "./listing.js";
|
|
15
|
+
import { decodeScheduleRunMetadata } from "./schedule-run-metadata.js";
|
|
15
16
|
import { createTerminalCleanupTimerId } from "./state-utilities.js";
|
|
16
17
|
import {
|
|
17
18
|
decodeWorkflowState,
|
|
@@ -181,12 +182,22 @@ async function collectWorkflowPurgeDeleteKeys(internals, state) {
|
|
|
181
182
|
const workflowId = state.id, deleteKeys = buildBaseWorkflowDeleteKeys(state);
|
|
182
183
|
addExecutionDeadlineDeleteKeys(deleteKeys, state);
|
|
183
184
|
addTerminalCleanupDeleteKey(deleteKeys, state);
|
|
185
|
+
await addScheduleRunHistoryDeleteKeys(internals.storage, deleteKeys, workflowId);
|
|
184
186
|
await addUpdateRequestDeleteKeys(internals.storage, deleteKeys, workflowId);
|
|
185
187
|
await addWorkflowPrefixDeleteKeys(internals.storage, deleteKeys, workflowId);
|
|
186
188
|
return deleteKeys;
|
|
187
189
|
}
|
|
190
|
+
async function addScheduleRunHistoryDeleteKeys(storage, deleteKeys, workflowId) {
|
|
191
|
+
const linkKey = KEYS.scheduleRunLink(workflowId), linkBytes = await storage.get(linkKey);
|
|
192
|
+
deleteKeys.add(linkKey);
|
|
193
|
+
if (linkBytes === null)
|
|
194
|
+
return;
|
|
195
|
+
const metadata = decodeScheduleRunMetadata(linkBytes);
|
|
196
|
+
if (metadata !== null)
|
|
197
|
+
deleteKeys.add(KEYS.scheduleRunBySchedule(metadata.id, workflowId));
|
|
198
|
+
}
|
|
188
199
|
function buildBaseWorkflowDeleteKeys(state) {
|
|
189
|
-
|
|
200
|
+
const keys = new Set([
|
|
190
201
|
KEYS.workflow(state.id),
|
|
191
202
|
KEYS.checkpoint(state.id),
|
|
192
203
|
KEYS.workflowHeaders(state.id),
|
|
@@ -196,9 +207,13 @@ function buildBaseWorkflowDeleteKeys(state) {
|
|
|
196
207
|
KEYS.workflowHasServices(state.id),
|
|
197
208
|
KEYS.finalizerState(state.id),
|
|
198
209
|
KEYS.teardownOwed(state.id),
|
|
210
|
+
KEYS.teardownSucceeded(state.id),
|
|
199
211
|
KEYS.attribute(state.id),
|
|
200
212
|
KEYS.terminalWorkflow(state.updatedAt, state.id)
|
|
201
213
|
]);
|
|
214
|
+
if (state.parentWorkflowId !== void 0)
|
|
215
|
+
keys.add(KEYS.childWorkflowByParent(state.parentWorkflowId, state.parentWorkflowExecutionToken, state.id));
|
|
216
|
+
return keys;
|
|
202
217
|
}
|
|
203
218
|
function addExecutionDeadlineDeleteKeys(deleteKeys, state) {
|
|
204
219
|
if (state.executionDeadline === void 0)
|
|
@@ -63,6 +63,8 @@ function summarizeBulkFilter(filter) {
|
|
|
63
63
|
summary.status = Array.isArray(filter.status) ? uniqueSorted(filter.status) : filter.status;
|
|
64
64
|
if (filter.type !== void 0)
|
|
65
65
|
summary.type = filter.type;
|
|
66
|
+
if (filter.scheduleId !== void 0)
|
|
67
|
+
summary.scheduleId = filter.scheduleId;
|
|
66
68
|
const normalizedTags = normalizeWorkflowTags(filter.tags);
|
|
67
69
|
if (normalizedTags !== void 0)
|
|
68
70
|
summary.tags = normalizedTags;
|
|
@@ -77,7 +77,8 @@ export function createLifecycleCallbacks(engine) {
|
|
|
77
77
|
enforceHistoryCircuitBreaker: (workflowId) => terminateWorkflow(getInternals(engine), workflowId, "timed-out", createTerminationCallbacks(engine), HISTORY_CIRCUIT_BREAKER_REASON),
|
|
78
78
|
failWorkflowForUnavailableServices: (workflowId, error) => failWorkflow(getInternals(engine), workflowId, error, createTerminationCallbacks(engine), "system"),
|
|
79
79
|
failWorkflowForRecoveryHook: (workflowId, error) => failWorkflow(getInternals(engine), workflowId, error, createTerminationCallbacks(engine), "system"),
|
|
80
|
-
failWorkflowForCheckpointDecodeError: (workflowId, error) => failWorkflow(getInternals(engine), workflowId, error, createTerminationCallbacks(engine), "system")
|
|
80
|
+
failWorkflowForCheckpointDecodeError: (workflowId, error) => failWorkflow(getInternals(engine), workflowId, error, createTerminationCallbacks(engine), "system"),
|
|
81
|
+
failWorkflowForVersionMismatch: (workflowId, error) => failWorkflow(getInternals(engine), workflowId, error, createTerminationCallbacks(engine), "system")
|
|
81
82
|
};
|
|
82
83
|
}
|
|
83
84
|
export function createTerminationCallbacksWith(engine, handleScheduledWorkflowTerminal) {
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import type { ScheduleState, TimerEntry } from '../types.ts';
|
|
2
2
|
import type { Engine } from './index.ts';
|
|
3
3
|
import type { ReviewOperationCallbacks, SubmitReviewCallbacks } from './reviews.ts';
|
|
4
|
+
import type { ScheduledRunStartOptions } from './schedule-run.ts';
|
|
4
5
|
import { type RefreshedScheduleState, type ScheduleCallbacks } from './schedules.ts';
|
|
5
6
|
export declare function createScheduleCallbacks<TWorkflows extends object, TActivities extends object>(engine: Engine<TWorkflows, TActivities>): ScheduleCallbacks;
|
|
6
7
|
export declare function createReviewOperationCallbacks<TWorkflows extends object, TActivities extends object>(engine: Engine<TWorkflows, TActivities>): ReviewOperationCallbacks;
|
|
7
8
|
export declare function createSubmitReviewCallbacks<TWorkflows extends object, TActivities extends object>(engine: Engine<TWorkflows, TActivities>): SubmitReviewCallbacks;
|
|
8
9
|
export declare function refreshScheduledWorkflowStateForEngine<TWorkflows extends object, TActivities extends object>(engine: Engine<TWorkflows, TActivities>, state: ScheduleState): Promise<RefreshedScheduleState>;
|
|
9
|
-
export declare function startScheduledRunForEngine<TWorkflows extends object, TActivities extends object>(engine: Engine<TWorkflows, TActivities>, state: ScheduleState,
|
|
10
|
+
export declare function startScheduledRunForEngine<TWorkflows extends object, TActivities extends object>(engine: Engine<TWorkflows, TActivities>, state: ScheduleState, options?: ScheduledRunStartOptions): Promise<string>;
|
|
10
11
|
export declare function applyScheduleOccurrenceForEngine<TWorkflows extends object, TActivities extends object>(engine: Engine<TWorkflows, TActivities>, state: ScheduleState, occurrence?: number): Promise<ScheduleState>;
|
|
11
12
|
export declare function settleBackfillScheduleStateForEngine<TWorkflows extends object, TActivities extends object>(engine: Engine<TWorkflows, TActivities>, state: ScheduleState): Promise<ScheduleState>;
|
|
12
13
|
export declare function handleScheduleTimerForEngine<TWorkflows extends object, TActivities extends object>(engine: Engine<TWorkflows, TActivities>, entry: TimerEntry): Promise<void>;
|
|
@@ -27,7 +27,7 @@ export function createScheduleCallbacks(engine) {
|
|
|
27
27
|
cancelWorkflow: (workflowId) => engine.cancel(workflowId),
|
|
28
28
|
getWorkflowResult: (workflowId) => engine.getHandle(workflowId).result(),
|
|
29
29
|
refreshScheduledWorkflowState: (state) => refreshScheduledWorkflowStateForEngine(engine, state),
|
|
30
|
-
startScheduledRun: (state,
|
|
30
|
+
startScheduledRun: (state, options) => startScheduledRunForEngine(engine, state, options),
|
|
31
31
|
applyScheduleOccurrence: (state, occurrence) => applyScheduleOccurrenceForEngine(engine, state, occurrence),
|
|
32
32
|
settleBackfillScheduleState: (state) => settleBackfillScheduleStateForEngine(engine, state),
|
|
33
33
|
flushQueuedInlineWorkflowStartsDirectly: () => flushQueuedInlineWorkflowStartsDirectly(getInternals(engine), createInlineLaunchQueueCallbacks(engine)),
|
|
@@ -51,8 +51,8 @@ export function createSubmitReviewCallbacks(engine) {
|
|
|
51
51
|
export async function refreshScheduledWorkflowStateForEngine(engine, state) {
|
|
52
52
|
return refreshScheduledWorkflowState(getInternals(engine), state, createScheduleCallbacks(engine));
|
|
53
53
|
}
|
|
54
|
-
export async function startScheduledRunForEngine(engine, state,
|
|
55
|
-
return startScheduledRun(getInternals(engine), state, createScheduleCallbacks(engine),
|
|
54
|
+
export async function startScheduledRunForEngine(engine, state, options) {
|
|
55
|
+
return startScheduledRun(getInternals(engine), state, createScheduleCallbacks(engine), options);
|
|
56
56
|
}
|
|
57
57
|
export async function applyScheduleOccurrenceForEngine(engine, state, occurrence) {
|
|
58
58
|
return applyScheduleOccurrence(getInternals(engine), state, createScheduleCallbacks(engine), occurrence);
|
|
@@ -66,12 +66,22 @@ export async function getTimeline(internals, workflowId) {
|
|
|
66
66
|
inputSummary: sanitizeTimelineSummary(decoded.inputSummary) ?? decoded.inputSummary,
|
|
67
67
|
...decoded.outputSummary !== void 0 ? {
|
|
68
68
|
outputSummary: sanitizeTimelineSummary(decoded.outputSummary) ?? decoded.outputSummary
|
|
69
|
-
} : {}
|
|
69
|
+
} : {},
|
|
70
|
+
...decoded.branches === void 0 ? {} : { branches: decoded.branches.map(sanitizeTimelineOperationDetail) },
|
|
71
|
+
...decoded.children === void 0 ? {} : { children: decoded.children.map(sanitizeTimelineOperationDetail) }
|
|
70
72
|
});
|
|
71
73
|
}
|
|
72
74
|
timeline.sort((left, right) => left.step - right.step);
|
|
73
75
|
return timeline;
|
|
74
76
|
}
|
|
77
|
+
function sanitizeTimelineOperationDetail(detail) {
|
|
78
|
+
if (detail.errorSummary === void 0)
|
|
79
|
+
return detail;
|
|
80
|
+
return {
|
|
81
|
+
...detail,
|
|
82
|
+
errorSummary: sanitizeTimelineSummary(detail.errorSummary) ?? detail.errorSummary
|
|
83
|
+
};
|
|
84
|
+
}
|
|
75
85
|
export async function replayTo(internals, workflowId, step) {
|
|
76
86
|
const bytes = await internals.storage.get(KEYS.checkpointHistory(workflowId, step));
|
|
77
87
|
if (!bytes)
|
|
@@ -22,6 +22,8 @@ function applyPendingChildExecutionContext(internals, context) {
|
|
|
22
22
|
internals.pendingNestingDepth = context.pendingNestingDepth;
|
|
23
23
|
internals.pendingParentHeaders = context.pendingParentHeaders;
|
|
24
24
|
internals.pendingExecutionStateOwnerId = context.pendingExecutionStateOwnerId;
|
|
25
|
+
internals.pendingParentWorkflowId = context.pendingParentWorkflowId;
|
|
26
|
+
internals.pendingParentWorkflowExecutionToken = context.pendingParentWorkflowExecutionToken;
|
|
25
27
|
}
|
|
26
28
|
function clearPendingChildExecutionContext(internals, context) {
|
|
27
29
|
if (internals.pendingNestingDepth === context.pendingNestingDepth)
|
|
@@ -30,15 +32,20 @@ function clearPendingChildExecutionContext(internals, context) {
|
|
|
30
32
|
internals.pendingParentHeaders = void 0;
|
|
31
33
|
if (internals.pendingExecutionStateOwnerId === context.pendingExecutionStateOwnerId)
|
|
32
34
|
internals.pendingExecutionStateOwnerId = void 0;
|
|
35
|
+
if (internals.pendingParentWorkflowId === context.pendingParentWorkflowId)
|
|
36
|
+
internals.pendingParentWorkflowId = void 0;
|
|
37
|
+
if (internals.pendingParentWorkflowExecutionToken === context.pendingParentWorkflowExecutionToken)
|
|
38
|
+
internals.pendingParentWorkflowExecutionToken = void 0;
|
|
33
39
|
}
|
|
34
|
-
function existingChildMatchesRequest(existingState, operation, executionStateOwnerId) {
|
|
35
|
-
|
|
40
|
+
function existingChildMatchesRequest(existingState, operation, executionStateOwnerId, parentWorkflowId, parentWorkflowExecutionToken) {
|
|
41
|
+
const lineageMatches = existingState.parentWorkflowId === void 0 && existingState.parentWorkflowExecutionToken === void 0 || existingState.parentWorkflowId === parentWorkflowId && existingState.parentWorkflowExecutionToken === parentWorkflowExecutionToken;
|
|
42
|
+
return existingState.type === operation.workflowType && encodedValuesEqual(existingState.input, operation.input) && existingState.executionStateOwnerId === executionStateOwnerId && lineageMatches;
|
|
36
43
|
}
|
|
37
|
-
async function resolveCollisionChildHandle(childWorkflowId, operation, executionStateOwnerId, collisionError, callbacks) {
|
|
44
|
+
async function resolveCollisionChildHandle(childWorkflowId, operation, executionStateOwnerId, parentWorkflowId, parentWorkflowExecutionToken, collisionError, callbacks) {
|
|
38
45
|
const existingState = await callbacks.loadWorkflowState(childWorkflowId);
|
|
39
46
|
if (!existingState)
|
|
40
47
|
throw collisionError;
|
|
41
|
-
if (!existingChildMatchesRequest(existingState, operation, executionStateOwnerId))
|
|
48
|
+
if (!existingChildMatchesRequest(existingState, operation, executionStateOwnerId, parentWorkflowId, parentWorkflowExecutionToken))
|
|
42
49
|
throw Error(`Child workflow id collision for "${childWorkflowId}" does not match the requested child workflow`, { cause: collisionError });
|
|
43
50
|
return callbacks.getHandle(childWorkflowId);
|
|
44
51
|
}
|
|
@@ -52,7 +59,7 @@ async function dispatchChildWorkflowStart(internals, childWorkflowId, operation,
|
|
|
52
59
|
} catch (error) {
|
|
53
60
|
if (!(error instanceof WorkflowAlreadyExistsError))
|
|
54
61
|
throw error;
|
|
55
|
-
return resolveCollisionChildHandle(childWorkflowId, operation, context.pendingExecutionStateOwnerId ?? void 0, error, callbacks);
|
|
62
|
+
return resolveCollisionChildHandle(childWorkflowId, operation, context.pendingExecutionStateOwnerId ?? void 0, context.pendingParentWorkflowId, context.pendingParentWorkflowExecutionToken, error, callbacks);
|
|
56
63
|
} finally {
|
|
57
64
|
clearPendingChildExecutionContext(internals, context);
|
|
58
65
|
}
|
|
@@ -62,7 +69,9 @@ export async function executeChildWorkflow(internals, workflowId, operation, cur
|
|
|
62
69
|
const context = {
|
|
63
70
|
pendingNestingDepth: currentDepth + 1,
|
|
64
71
|
pendingParentHeaders: internals.workflowHeaders.get(workflowId),
|
|
65
|
-
pendingExecutionStateOwnerId: executionStateOwnerId
|
|
72
|
+
pendingExecutionStateOwnerId: executionStateOwnerId,
|
|
73
|
+
pendingParentWorkflowId: workflowId,
|
|
74
|
+
pendingParentWorkflowExecutionToken: parentState?.workflowExecutionToken
|
|
66
75
|
}, childHandle = await dispatchChildWorkflowStart(internals, childWorkflowId, operation, context, callbacks);
|
|
67
76
|
if (parentClosePolicy === "abandon")
|
|
68
77
|
return createChildWorkflowHandleReference(childHandle.id);
|
|
@@ -72,6 +72,9 @@ export function copyWorkflowDefinition(type, registration) {
|
|
|
72
72
|
...registration.description === void 0 ? {} : { description: registration.description },
|
|
73
73
|
...registration.inputSchema === void 0 ? {} : { inputSchema: registration.inputSchema },
|
|
74
74
|
...registration.outputSchema === void 0 ? {} : { outputSchema: registration.outputSchema },
|
|
75
|
+
...registration.signals === void 0 ? {} : { signals: { ...registration.signals } },
|
|
76
|
+
...registration.updates === void 0 ? {} : { updates: { ...registration.updates } },
|
|
77
|
+
...registration.queries === void 0 ? {} : { queries: { ...registration.queries } },
|
|
75
78
|
...registration.searchAttributes === void 0 ? {} : { searchAttributes: registration.searchAttributes },
|
|
76
79
|
...registration.concurrency === void 0 ? {} : { concurrency: registration.concurrency }
|
|
77
80
|
};
|
|
@@ -53,6 +53,8 @@ export function disposeEngine(internals) {
|
|
|
53
53
|
internals.sleepTimersFiredWithoutResolver.clear();
|
|
54
54
|
internals.checkpoints.clear();
|
|
55
55
|
internals.pendingExecutionStateOwnerId = void 0;
|
|
56
|
+
internals.pendingParentWorkflowId = void 0;
|
|
57
|
+
internals.pendingParentWorkflowExecutionToken = void 0;
|
|
56
58
|
internals.workflowNestingDepths.clear();
|
|
57
59
|
internals.workflowServices.clear();
|
|
58
60
|
internals.workflowHeaders.clear();
|
|
@@ -2,7 +2,7 @@ import type { Storage as WeftStorage } from '../../storage/interface.ts';
|
|
|
2
2
|
import type { ConstraintDefinition } from '../constraint.ts';
|
|
3
3
|
import type { ExecutionStrategy } from '../execution-strategy.ts';
|
|
4
4
|
import type { InlineExecutionStrategy } from '../inline-execution-strategy.ts';
|
|
5
|
-
import type { AnyActivityDefinition, ArchiveAdapter, Checkpoint, DefinitionSchema, EngineOptions, NormalizedHistoryPolicy, NormalizedPayloadSizePolicy, NormalizedRetentionPolicy, SearchAttributeSchema, WorkflowConcurrencyOptions, WorkflowFunction, WorkflowTimelineEntry } from '../types.ts';
|
|
5
|
+
import type { AnyActivityDefinition, ArchiveAdapter, Checkpoint, DefinitionSchema, EngineOptions, NormalizedHistoryPolicy, NormalizedPayloadSizePolicy, NormalizedRetentionPolicy, QueryDefinition, SearchAttributeSchema, SignalDefinition, UpdateDefinition, WorkflowConcurrencyOptions, WorkflowFunction, WorkflowTimelineEntry } from '../types.ts';
|
|
6
6
|
export interface RegistrationEntry {
|
|
7
7
|
handler: WorkflowFunction;
|
|
8
8
|
version: string;
|
|
@@ -10,6 +10,9 @@ export interface RegistrationEntry {
|
|
|
10
10
|
tags?: ReadonlyArray<string>;
|
|
11
11
|
inputSchema?: DefinitionSchema;
|
|
12
12
|
outputSchema?: DefinitionSchema;
|
|
13
|
+
signals?: Readonly<Record<string, Readonly<SignalDefinition<unknown>>>>;
|
|
14
|
+
updates?: Readonly<Record<string, Readonly<UpdateDefinition<unknown>>>>;
|
|
15
|
+
queries?: Readonly<Record<string, Readonly<QueryDefinition<unknown>>>>;
|
|
13
16
|
searchAttributes?: SearchAttributeSchema;
|
|
14
17
|
retention?: NormalizedRetentionPolicy;
|
|
15
18
|
concurrency?: WorkflowConcurrencyOptions;
|
|
@@ -27,9 +27,11 @@ import type { EngineInternals } from './internals.ts';
|
|
|
27
27
|
* work before `recoverAll()` would otherwise durably write workflow state without
|
|
28
28
|
* single-writer ownership and without having recovered existing runs. Placed at
|
|
29
29
|
* each public awaited entry so the caller gets a clean {@link EngineLeaseNotHeldError}
|
|
30
|
-
* — without this, fork
|
|
31
|
-
*
|
|
32
|
-
*
|
|
30
|
+
* — without this, fork, resume, and the schedule mutators (`schedule`,
|
|
31
|
+
* `pauseSchedule`, `resumeSchedule`, `cancelSchedule`, and `updateSchedule`) would
|
|
32
|
+
* reach `resolveFenceEpochOrHalt` with no held epoch and be misreported as a
|
|
33
|
+
* deposition (warn + teardown) rather than the true "lease not held yet"
|
|
34
|
+
* condition. A no-op under `ownership: 'none'`.
|
|
33
35
|
*/
|
|
34
36
|
export declare function assertLeaseHeldForEngineWork(internals: EngineInternals): void;
|
|
35
37
|
/**
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type BatchOperation } from '../../storage/interface.ts';
|
|
2
|
+
import type { WorkflowFinalizerStatus, WorkflowState } from '../types.ts';
|
|
3
|
+
import type { EngineInternals } from './internals.ts';
|
|
4
|
+
export interface TeardownSucceededRecord {
|
|
5
|
+
attempts: number;
|
|
6
|
+
completedAt: number;
|
|
7
|
+
workflowExecutionToken?: string;
|
|
8
|
+
}
|
|
9
|
+
export declare function buildTeardownSuccessOperations(workflowId: string, attempts: number, completedAt: number, workflowExecutionToken: string | undefined): BatchOperation[];
|
|
10
|
+
export declare function getFinalizerStatus(internals: EngineInternals, workflowId: string, state: WorkflowState | null): Promise<WorkflowFinalizerStatus | null>;
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { KEYS } from "../../storage/interface.js";
|
|
2
|
+
import { decode, encode } from "../codec.js";
|
|
3
|
+
import { isRecord } from "../debug-output.js";
|
|
4
|
+
import { isTeardownClaim } from "./state-utilities.js";
|
|
5
|
+
export function buildTeardownSuccessOperations(workflowId, attempts, completedAt, workflowExecutionToken) {
|
|
6
|
+
const outcome = {
|
|
7
|
+
attempts,
|
|
8
|
+
completedAt,
|
|
9
|
+
...workflowExecutionToken === void 0 ? {} : { workflowExecutionToken }
|
|
10
|
+
};
|
|
11
|
+
return [
|
|
12
|
+
{ type: "delete", key: KEYS.teardownOwed(workflowId) },
|
|
13
|
+
{ type: "delete", key: KEYS.finalizerState(workflowId) },
|
|
14
|
+
{ type: "put", key: KEYS.teardownSucceeded(workflowId), value: encode(outcome) }
|
|
15
|
+
];
|
|
16
|
+
}
|
|
17
|
+
function decodeUnknown(bytes) {
|
|
18
|
+
try {
|
|
19
|
+
return decode(bytes);
|
|
20
|
+
} catch {
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
function isNonNegativeSafeInteger(value) {
|
|
25
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
|
|
26
|
+
}
|
|
27
|
+
function isNonNegativeFiniteNumber(value) {
|
|
28
|
+
return typeof value === "number" && Number.isFinite(value) && value >= 0;
|
|
29
|
+
}
|
|
30
|
+
function recordBelongsToRun(record, state) {
|
|
31
|
+
const recordToken = record.workflowExecutionToken;
|
|
32
|
+
if (recordToken !== void 0 && typeof recordToken !== "string")
|
|
33
|
+
return !1;
|
|
34
|
+
if (state === null)
|
|
35
|
+
return !0;
|
|
36
|
+
return recordToken === state.workflowExecutionToken;
|
|
37
|
+
}
|
|
38
|
+
export async function getFinalizerStatus(internals, workflowId, state) {
|
|
39
|
+
const claimBytes = await internals.storage.get(KEYS.teardownOwed(workflowId)), claimStatus = decodeClaimStatus(claimBytes);
|
|
40
|
+
if (claimStatus !== null)
|
|
41
|
+
return claimStatus;
|
|
42
|
+
const deadLetterBytes = await internals.storage.get(KEYS.teardownDeadLetter(workflowId)), failedStatus = decodeFailedStatus(deadLetterBytes, state);
|
|
43
|
+
if (failedStatus !== null)
|
|
44
|
+
return failedStatus;
|
|
45
|
+
const succeededBytes = await internals.storage.get(KEYS.teardownSucceeded(workflowId));
|
|
46
|
+
return decodeSucceededStatus(succeededBytes, state);
|
|
47
|
+
}
|
|
48
|
+
function decodeClaimStatus(bytes) {
|
|
49
|
+
if (bytes === null)
|
|
50
|
+
return null;
|
|
51
|
+
const claim = decodeUnknown(bytes);
|
|
52
|
+
if (!isTeardownClaim(claim))
|
|
53
|
+
return null;
|
|
54
|
+
if (claim.status === "running" && claim.claimedAt !== void 0)
|
|
55
|
+
return { status: "running", attempts: claim.attempts + 1, startedAt: claim.claimedAt };
|
|
56
|
+
return { status: "pending", attempts: claim.attempts };
|
|
57
|
+
}
|
|
58
|
+
function decodeFailedStatus(bytes, state) {
|
|
59
|
+
if (bytes === null)
|
|
60
|
+
return null;
|
|
61
|
+
const record = decodeUnknown(bytes);
|
|
62
|
+
if (!isRecord(record) || !recordBelongsToRun(record, state) || typeof record.lastError !== "string" || !isNonNegativeSafeInteger(record.attempts) || !isNonNegativeFiniteNumber(record.deadLetteredAt))
|
|
63
|
+
return null;
|
|
64
|
+
return {
|
|
65
|
+
status: "failed",
|
|
66
|
+
attempts: record.attempts,
|
|
67
|
+
failedAt: record.deadLetteredAt,
|
|
68
|
+
error: record.lastError
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
function decodeSucceededStatus(bytes, state) {
|
|
72
|
+
if (bytes === null)
|
|
73
|
+
return null;
|
|
74
|
+
const record = decodeUnknown(bytes);
|
|
75
|
+
if (!isRecord(record) || !recordBelongsToRun(record, state) || !isNonNegativeSafeInteger(record.attempts) || !isNonNegativeFiniteNumber(record.completedAt))
|
|
76
|
+
return null;
|
|
77
|
+
return {
|
|
78
|
+
status: "succeeded",
|
|
79
|
+
attempts: record.attempts,
|
|
80
|
+
completedAt: record.completedAt
|
|
81
|
+
};
|
|
82
|
+
}
|
|
@@ -5,7 +5,7 @@ import type { TypedEventTarget, WeftEventMap } from '../events.ts';
|
|
|
5
5
|
import type { Interceptor } from '../interceptor.ts';
|
|
6
6
|
import { type ReviewRequest } from '../review/index.ts';
|
|
7
7
|
import { Scheduler } from '../scheduler.ts';
|
|
8
|
-
import { type AnyActivityDefinition, type AnyWorkflowDefinition, type AttributeFilterKey, type BulkCancelResult, type BulkDeleteResult, type BulkOperationCommitOptions, type BulkOperationDryRunOptions, type BulkOperationDryRunResult, type BulkRetryFailedResult, type BulkSignalAllCommitOptions, type BulkSignalAllDryRunOptions, type BulkSignalResult, type BulkTagResult, type CheckpointState, type CheckpointSummary, type CoordinatedUpdateResult, type DefaultActivityTypes, type DefaultWorkflowRegistry, type ForkOptions, type InferActivityEntries, type InferActivityEntry, type InferWorkflowEntries, type InferWorkflowEntry, type ListFilter, type ListOptions, type PaginatedResult, type PurgeResult, type QueryDefinition, type RegisteredWorkflowDefinition, type RetentionOverview, type ReviewListEntry, type ReviewListFilter, type ScheduleDefinition, type ScheduleFilter, type ScheduleOptions, type ScheduleSpec, type ScheduleSummary, type SearchAttributeValue, type SignalDefinition, type SignalDeliveryOptions, type StartOrSignalOptions, type StartOrSignalSignal, type StartWorkflowOptions, type SubmitReviewOptions, type TypedListFilter, type UpdateDefinition, type WorkflowEvent, type WorkflowInput, type WorkflowOutput, type WorkflowReplay, type WorkflowServices, type WorkflowServicesUnion, type WorkflowState, type WorkflowSummary, type WorkflowTimelineEntry } from '../types.ts';
|
|
8
|
+
import { type AnyActivityDefinition, type AnyWorkflowDefinition, type AttributeFilterKey, type BulkCancelResult, type BulkDeleteResult, type BulkOperationCommitOptions, type BulkOperationDryRunOptions, type BulkOperationDryRunResult, type BulkRetryFailedResult, type BulkSignalAllCommitOptions, type BulkSignalAllDryRunOptions, type BulkSignalResult, type BulkTagResult, type CheckpointState, type CheckpointSummary, type CoordinatedUpdateResult, type DefaultActivityTypes, type DefaultWorkflowRegistry, type ForkOptions, type InferActivityEntries, type InferActivityEntry, type InferWorkflowEntries, type InferWorkflowEntry, type ListFilter, type ListOptions, type PaginatedResult, type PendingAsyncActivityListOptions, type PendingAsyncActivityPage, type PurgeResult, type QueryDefinition, type RegisteredWorkflowDefinition, type RetentionOverview, type ReviewListEntry, type ReviewListFilter, type ScheduleDefinition, type ScheduleFilter, type ScheduleOptions, type ScheduleSpec, type ScheduleSummary, type ScheduleUpdateOptions, type SearchAttributeValue, type SignalDefinition, type SignalDeliveryOptions, type StartOrSignalOptions, type StartOrSignalSignal, type StartWorkflowOptions, type SubmitReviewOptions, type TypedListFilter, type UpdateDefinition, type WorkflowEvent, type WorkflowFinalizerStatus, type WorkflowInput, type WorkflowOutput, type WorkflowReplay, type WorkflowScheduleProvenance, type WorkflowServices, type WorkflowServicesUnion, type WorkflowState, type WorkflowSummary, type WorkflowTimelineEntry } from '../types.ts';
|
|
9
9
|
import type { TimerEntry } from '../types/checkpoint.ts';
|
|
10
10
|
import type { WorkflowAlreadyRegistered } from '../types/workflow-builder.ts';
|
|
11
11
|
import { type AggregateOptions, type AggregateResult } from './aggregate.ts';
|
|
@@ -15,6 +15,7 @@ import type { EngineConstructorOptions } from './engine-internal-types.ts';
|
|
|
15
15
|
import type { EngineStateNamespace } from './engine-state-namespace.ts';
|
|
16
16
|
import { HANDLE_RESULT_PROMISE, WorkflowHandle } from './handles.ts';
|
|
17
17
|
import { ENGINE_LEASE_LOST_WARNING_NAME } from './lease-deposition.ts';
|
|
18
|
+
import type { EngineLeaseHealth } from './lease-health.ts';
|
|
18
19
|
import { type RecoverAllOptions, type StartOrSignalResult } from './lifecycle.ts';
|
|
19
20
|
import { assertCompatiblePersistedDataVersion } from './persisted-data-version.ts';
|
|
20
21
|
import { ScheduleHandle } from './schedule-handle.ts';
|
|
@@ -26,6 +27,7 @@ export type { PendingTimelineEntry, RegistrationEntry, ResolvedOptions, TrackedW
|
|
|
26
27
|
export { ActivityResolutionError, BulkDeleteRequiresTerminalWorkflowsError, BulkOperationConfirmationError, EngineCreateNameMismatchError, EngineDisposedError, IdempotencyKeyPurgedError, PersistedDataIncompatibleError, StartOrSignalConflictError, WorkflowAlreadyExistsError, WorkflowConcurrencyLimitExceededError, WorkflowNotFoundError, WorkflowNotRegisteredError, WorkflowSuspendNotSupportedError, WorkflowTeardownPendingError, WorkflowTypeNotRegisteredForRecoveryError, } from './errors.ts';
|
|
27
28
|
export { HANDLE_RESULT_PROMISE, WorkflowHandle } from './handles.ts';
|
|
28
29
|
export { EngineLeaseAcquisitionTimeoutError, EngineLeaseCorruptedError, EngineLeaseNotHeldError, } from './lease-errors.ts';
|
|
30
|
+
export type { EngineLeaseHealth, LeaseLostReason } from './lease-health.ts';
|
|
29
31
|
export type { RecoverAllOptions, RecoveredWorkflowInfo } from './lifecycle.ts';
|
|
30
32
|
export { ScheduleHandle } from './schedule-handle.ts';
|
|
31
33
|
export type { WorkflowFeedListener, WorkflowFeedRecord, WorkflowFeedSelector, } from './workflow-feed.ts';
|
|
@@ -304,7 +306,7 @@ export declare class Engine<TWorkflows extends object = DefaultWorkflowRegistry,
|
|
|
304
306
|
pauseSchedule(scheduleId: string): Promise<void>;
|
|
305
307
|
resumeSchedule(scheduleId: string): Promise<void>;
|
|
306
308
|
cancelSchedule(scheduleId: string): Promise<void>;
|
|
307
|
-
updateSchedule(scheduleId: string, newSpec: string | ScheduleSpec): Promise<void>;
|
|
309
|
+
updateSchedule(scheduleId: string, newSpec: string | ScheduleSpec, options?: ScheduleUpdateOptions): Promise<void>;
|
|
308
310
|
[HANDLE_RESULT_PROMISE](workflowId: string): Promise<unknown>;
|
|
309
311
|
[ENGINE_PARKED_WORKFLOW_COUNT_FOR_TESTING](): number;
|
|
310
312
|
[ENGINE_SIGNAL_WAITER_COUNT_FOR_TESTING](): number;
|
|
@@ -371,6 +373,12 @@ export declare class Engine<TWorkflows extends object = DefaultWorkflowRegistry,
|
|
|
371
373
|
* deploys or explicit operator storage repair.
|
|
372
374
|
* When set, unknown workflow types are skipped and reported through
|
|
373
375
|
* {@link WorkflowRecoverySkippedEvent}.
|
|
376
|
+
*
|
|
377
|
+
* A recovered workflow whose persisted version metadata no longer matches
|
|
378
|
+
* its registered `WorkflowDefinition.version` is isolated per
|
|
379
|
+
* {@link RecoverAllOptions.versionMismatchPolicy} (default `'fail-run'`):
|
|
380
|
+
* only that workflow fails, and `recoverAll()` continues recovering its
|
|
381
|
+
* siblings in the same call.
|
|
374
382
|
*/
|
|
375
383
|
recoverAll(options?: RecoverAllOptions): Promise<WorkflowHandle[]>;
|
|
376
384
|
/**
|
|
@@ -388,6 +396,13 @@ export declare class Engine<TWorkflows extends object = DefaultWorkflowRegistry,
|
|
|
388
396
|
* the token (unknown, or already completed/failed — tokens are single-use).
|
|
389
397
|
*/
|
|
390
398
|
completeAsyncActivity(token: string, result: unknown): Promise<void>;
|
|
399
|
+
/**
|
|
400
|
+
* List a bounded page of durable async activities awaiting out-of-band
|
|
401
|
+
* completion for one workflow. This reads storage directly, so callers can
|
|
402
|
+
* recover tokens after a process restart before `recoverAll()` repopulates
|
|
403
|
+
* the in-memory completion map.
|
|
404
|
+
*/
|
|
405
|
+
listPendingAsyncActivities(workflowId: string, options?: PendingAsyncActivityListOptions): Promise<PendingAsyncActivityPage>;
|
|
391
406
|
/**
|
|
392
407
|
* Fail a deferred activity out-of-band with `error`. The error is thrown into
|
|
393
408
|
* the workflow generator at the parked step — identical to an inline activity
|
|
@@ -419,6 +434,21 @@ export declare class Engine<TWorkflows extends object = DefaultWorkflowRegistry,
|
|
|
419
434
|
suspend(workflowId: string): Promise<void>;
|
|
420
435
|
timeout(workflowId: string): Promise<void>;
|
|
421
436
|
get(workflowId: string): Promise<WorkflowState | null>;
|
|
437
|
+
/** Return the schedule occurrence that launched a workflow, when applicable. */
|
|
438
|
+
getScheduleProvenance(workflowId: string): Promise<WorkflowScheduleProvenance | null>;
|
|
439
|
+
/** Return durable post-terminal finalizer progress or outcome, when applicable. */
|
|
440
|
+
getFinalizerStatus(workflowId: string): Promise<WorkflowFinalizerStatus | null>;
|
|
441
|
+
/**
|
|
442
|
+
* Return this process's last-known ownership-lease health.
|
|
443
|
+
*
|
|
444
|
+
* This is a synchronous diagnostic snapshot: it never performs a storage read
|
|
445
|
+
* and therefore remains available to operator transports after a confirmed
|
|
446
|
+
* deposition has detached the lease manager. Holder identifiers and timestamps
|
|
447
|
+
* are present only while the manager still has its own last-written holder
|
|
448
|
+
* record; a detached deposed engine reports the confirmed loss without
|
|
449
|
+
* inventing successor details.
|
|
450
|
+
*/
|
|
451
|
+
getLeaseHealth(): EngineLeaseHealth;
|
|
422
452
|
getCurrentCheckpointStep(workflowId: string): Promise<number | null>;
|
|
423
453
|
getAttributes(workflowId: string): Promise<Record<string, SearchAttributeValue> | null>;
|
|
424
454
|
setAttributes(workflowId: string, attributes: Record<string, SearchAttributeValue>): Promise<void>;
|
|
@@ -490,3 +520,40 @@ export declare class Engine<TWorkflows extends object = DefaultWorkflowRegistry,
|
|
|
490
520
|
*/
|
|
491
521
|
fireTimer(entry: TimerEntry): Promise<void>;
|
|
492
522
|
}
|
|
523
|
+
/**
|
|
524
|
+
* `Engine` with its two chained-builder registration methods removed —
|
|
525
|
+
* `register` and `registerWorkflows`, whose return type is itself
|
|
526
|
+
* `Engine<NarrowedRegistry>` (see `register()`'s JSDoc: registering returns
|
|
527
|
+
* "this same engine with the definition added to its phantom type
|
|
528
|
+
* registry"). That self-reference is what makes `Engine` invariant in its
|
|
529
|
+
* registry generics: a concretely narrowed `Engine<Concrete>` (e.g. from
|
|
530
|
+
* `Engine.create({ workflows })`) is not structurally assignable to the
|
|
531
|
+
* plain default `Engine<DefaultWorkflowRegistry>`, even though every other
|
|
532
|
+
* member — including `start` and `startOrSignal`, whose *parameter* types
|
|
533
|
+
* (not return types) reference `TWorkflows` but never produce another
|
|
534
|
+
* `Engine<T>` — is not part of that recursive comparison.
|
|
535
|
+
*
|
|
536
|
+
* `start` and `startOrSignal` are deliberately KEPT (not omitted): hosted
|
|
537
|
+
* transports genuinely call them at runtime (REST/JSON-RPC workflow starts,
|
|
538
|
+
* MCP tool invocations) via `runtimeWorkflowEngine()`'s registry-erased
|
|
539
|
+
* dynamic-name overload, so a value satisfying this type must still provide
|
|
540
|
+
* them — a duck-typed engine substitute lacking `start` correctly fails to
|
|
541
|
+
* satisfy `RegistryAgnosticEngine` (see this type's `.test-d.ts` coverage).
|
|
542
|
+
*
|
|
543
|
+
* Host-facing options that accept an already-constructed `Engine` without
|
|
544
|
+
* needing the two chained-builder registration methods — `serve({ engine })`,
|
|
545
|
+
* the Service Worker helpers, the MCP session/HTTP/stdio surfaces — use this
|
|
546
|
+
* type instead of the bare default `Engine`, so both `new Engine({ storage })`
|
|
547
|
+
* and `Engine.create({ workflows })` are accepted without a call-site cast.
|
|
548
|
+
* See #708.
|
|
549
|
+
*
|
|
550
|
+
* (`Engine<object, object>` looks like the obvious fix — the widest legal
|
|
551
|
+
* instantiation of the registry generics — but TypeScript's structural check
|
|
552
|
+
* on `register()`'s self-referential return type does not reliably resolve
|
|
553
|
+
* that relationship: it can pass or fail for the identical `Engine<A>` /
|
|
554
|
+
* `Engine<B>` pair depending on unrelated compilation context, such as other
|
|
555
|
+
* files in the same program. Removing the registry-typed members entirely,
|
|
556
|
+
* rather than widening their generic arguments, avoids the recursive
|
|
557
|
+
* comparison altogether.)
|
|
558
|
+
*/
|
|
559
|
+
export type RegistryAgnosticEngine = Omit<Engine, 'register' | 'registerWorkflows'>;
|