@orkestrel/workflow 0.0.11 → 0.0.13

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.
@@ -155,6 +155,159 @@ function isWorkflowError(value) {
155
155
  }
156
156
  }
157
157
  //#endregion
158
+ //#region src/core/validators.ts
159
+ /** Test the workflow lifecycle vocabulary. */
160
+ function isLifecycleStatus(value) {
161
+ return value === "pending" || value === "running" || value === "completed" || value === "failed" || value === "skipped" || value === "stopped";
162
+ }
163
+ /** Test a normalized persisted task failure. */
164
+ function isTaskFailure(value) {
165
+ try {
166
+ return (0, _orkestrel_contract.isRecord)(value) && Object.keys(value).every((key) => key === "origin" || key === "message") && (value.origin === "handler" || value.origin === "timeout" || value.origin === "recovery") && (0, _orkestrel_contract.isNonEmptyString)(value.message);
167
+ } catch {
168
+ return false;
169
+ }
170
+ }
171
+ /**
172
+ * Validate a safe owned JSON graph as a coherent workflow snapshot.
173
+ *
174
+ * @remarks
175
+ * Callers at hostile boundaries use {@link isWorkflowSnapshot}, which owns the
176
+ * graph first so this semantic pass never observes accessors or prototypes.
177
+ */
178
+ function isOwnedWorkflowSnapshot(value) {
179
+ try {
180
+ if (!(0, _orkestrel_contract.isRecord)(value) || !Object.keys(value).every((key) => key === "id" || key === "name" || key === "description" || key === "status" || key === "override" || key === "bail" || key === "phases" || key === "created" || key === "updated") || !(0, _orkestrel_contract.isNonEmptyString)(value.id) || !(0, _orkestrel_contract.isNonEmptyString)(value.name) || value.description !== void 0 && typeof value.description !== "string" || !isLifecycleStatus(value.status) || value.override !== void 0 && value.override !== "completed" && value.override !== "skipped" && value.override !== "stopped" || !(0, _orkestrel_contract.isBoolean)(value.bail) || !(0, _orkestrel_contract.isArray)(value.phases) || !(0, _orkestrel_contract.isFiniteNumber)(value.created) || value.created < 0 || !(0, _orkestrel_contract.isFiniteNumber)(value.updated) || value.updated < value.created) return false;
181
+ const phaseIds = /* @__PURE__ */ new Set();
182
+ const derivations = [];
183
+ let frontier = false;
184
+ let running = false;
185
+ let vacuous = true;
186
+ for (const phase of value.phases) {
187
+ if (!(0, _orkestrel_contract.isRecord)(phase) || !Object.keys(phase).every((key) => key === "id" || key === "name" || key === "description" || key === "status" || key === "override" || key === "bail" || key === "concurrency" || key === "tasks") || !(0, _orkestrel_contract.isNonEmptyString)(phase.id) || phaseIds.has(phase.id) || !(0, _orkestrel_contract.isNonEmptyString)(phase.name) || phase.description !== void 0 && typeof phase.description !== "string" || !isLifecycleStatus(phase.status) || phase.override !== void 0 && phase.override !== "skipped" && phase.override !== "stopped" || !(0, _orkestrel_contract.isBoolean)(phase.bail) || phase.concurrency !== void 0 && (!(0, _orkestrel_contract.isInteger)(phase.concurrency) || phase.concurrency < 1) || !(0, _orkestrel_contract.isArray)(phase.tasks)) return false;
188
+ const forced = phase.override === "skipped" || phase.override === "stopped";
189
+ const started = phase.status === "running" || phase.status === "completed" || phase.status === "failed";
190
+ if (!forced && frontier && started || phase.status === "running" && running) return false;
191
+ if (phase.status === "running") running = true;
192
+ if (!forced && (phase.status === "pending" || phase.status === "running" || phase.status === "failed" && phase.bail)) frontier = true;
193
+ phaseIds.add(phase.id);
194
+ const taskIds = /* @__PURE__ */ new Set();
195
+ const statuses = [];
196
+ if (phase.tasks.length > 0) vacuous = false;
197
+ for (const task of phase.tasks) {
198
+ if (!(0, _orkestrel_contract.isRecord)(task) || !Object.keys(task).every((key) => key === "id" || key === "name" || key === "description" || key === "status" || key === "result" || key === "metadata" || key === "attempts" || key === "run" || key === "retries" || key === "timeout" || key === "activity") || !(0, _orkestrel_contract.isNonEmptyString)(task.id) || taskIds.has(task.id) || !(0, _orkestrel_contract.isNonEmptyString)(task.name) || task.description !== void 0 && typeof task.description !== "string" || !isLifecycleStatus(task.status) || !(0, _orkestrel_contract.isRecord)(task.metadata) || !(0, _orkestrel_contract.isJSONValue)(task.metadata) || !(0, _orkestrel_contract.isInteger)(task.attempts) || task.attempts < 0 || task.run !== void 0 && !(0, _orkestrel_contract.isNonEmptyString)(task.run) || task.retries !== void 0 && (!(0, _orkestrel_contract.isInteger)(task.retries) || task.retries < 0) || task.timeout !== void 0 && (!(0, _orkestrel_contract.isInteger)(task.timeout) || task.timeout < 0 || task.timeout > 2147483647)) return false;
199
+ const budget = (task.retries ?? 0) + 1;
200
+ if (task.attempts > budget || task.status === "pending" && task.attempts >= budget) return false;
201
+ if (!(task.activity === void 0 || isTaskActivity(task.activity))) return false;
202
+ if (task.status === "running" || task.status === "completed" || task.status === "failed") {
203
+ if (task.attempts < 1 || task.activity === void 0) return false;
204
+ }
205
+ if (task.status === "pending" && task.activity !== void 0) return false;
206
+ if (task.status === "completed" || task.status === "failed") {
207
+ if (!isTaskResult(task.result, value, phase, task)) return false;
208
+ } else if (task.result !== void 0) return false;
209
+ taskIds.add(task.id);
210
+ statuses.push(task.status);
211
+ }
212
+ const derived = derivePhaseStatus(statuses);
213
+ if (phase.status !== (phase.override ?? derived) || phase.override !== void 0 && phase.status !== phase.override) return false;
214
+ derivations.push({
215
+ status: phase.status,
216
+ bail: phase.bail
217
+ });
218
+ }
219
+ const derived = deriveWorkflowStatus(derivations);
220
+ if (value.override === "completed") return value.status === "completed" && derived === "pending" && vacuous;
221
+ return value.status === (value.override ?? derived);
222
+ } catch {
223
+ return false;
224
+ }
225
+ }
226
+ /** Total hostile-boundary workflow snapshot guard. */
227
+ function isWorkflowSnapshot(value) {
228
+ const cloned = (0, _orkestrel_contract.attempt)(() => (0, _orkestrel_contract.cloneJSONValue)(value));
229
+ return cloned.success && isOwnedWorkflowSnapshot(cloned.value);
230
+ }
231
+ /**
232
+ * Test whether an unknown value is a valid whole-frame activity report.
233
+ */
234
+ function isTaskActivityInput(value) {
235
+ try {
236
+ if (!(0, _orkestrel_contract.isRecord)(value)) return false;
237
+ const prototype = Object.getPrototypeOf(value);
238
+ if (prototype !== Object.prototype && prototype !== null || !Object.keys(value).every((key) => key === "note" || key === "progress" || key === "operations" || key === "constraints")) return false;
239
+ const note = value.note;
240
+ const progress = value.progress;
241
+ const operations = value.operations;
242
+ const constraints = value.constraints;
243
+ if (note !== void 0 && !(0, _orkestrel_contract.isNonEmptyString)(note)) return false;
244
+ if (progress !== void 0) {
245
+ if (!(0, _orkestrel_contract.isRecord)(progress)) return false;
246
+ const progressPrototype = Object.getPrototypeOf(progress);
247
+ if (progressPrototype !== Object.prototype && progressPrototype !== null || !Object.keys(progress).every((key) => key === "current" || key === "total" || key === "unit")) return false;
248
+ const current = progress.current;
249
+ const total = progress.total;
250
+ const unit = progress.unit;
251
+ if (!(0, _orkestrel_contract.isFiniteNumber)(current) || current < 0 || total !== void 0 && (!(0, _orkestrel_contract.isFiniteNumber)(total) || total < current) || unit !== void 0 && !(0, _orkestrel_contract.isNonEmptyString)(unit)) return false;
252
+ }
253
+ if (operations !== void 0) {
254
+ if (!(0, _orkestrel_contract.isArray)(operations)) return false;
255
+ const ids = /* @__PURE__ */ new Set();
256
+ for (const operation of operations) {
257
+ if (!(0, _orkestrel_contract.isRecord)(operation)) return false;
258
+ const operationPrototype = Object.getPrototypeOf(operation);
259
+ if (operationPrototype !== Object.prototype && operationPrototype !== null || !Object.keys(operation).every((key) => key === "id" || key === "name" || key === "started")) return false;
260
+ const id = operation.id;
261
+ const name = operation.name;
262
+ const started = operation.started;
263
+ if (!(0, _orkestrel_contract.isNonEmptyString)(id) || !(0, _orkestrel_contract.isNonEmptyString)(name) || !(0, _orkestrel_contract.isFiniteNumber)(started) || started < 0 || ids.has(id)) return false;
264
+ ids.add(id);
265
+ }
266
+ }
267
+ if (constraints !== void 0) {
268
+ if (!(0, _orkestrel_contract.isArray)(constraints)) return false;
269
+ const ids = /* @__PURE__ */ new Set();
270
+ for (const constraint of constraints) {
271
+ if (!(0, _orkestrel_contract.isRecord)(constraint)) return false;
272
+ const constraintPrototype = Object.getPrototypeOf(constraint);
273
+ if (constraintPrototype !== Object.prototype && constraintPrototype !== null || !Object.keys(constraint).every((key) => key === "id" || key === "name" || key === "started")) return false;
274
+ const id = constraint.id;
275
+ const name = constraint.name;
276
+ const started = constraint.started;
277
+ if (!(0, _orkestrel_contract.isNonEmptyString)(id) || !(0, _orkestrel_contract.isNonEmptyString)(name) || !(0, _orkestrel_contract.isFiniteNumber)(started) || started < 0 || ids.has(id)) return false;
278
+ ids.add(id);
279
+ }
280
+ }
281
+ return true;
282
+ } catch {
283
+ return false;
284
+ }
285
+ }
286
+ /**
287
+ * Test whether an unknown value is valid persisted task activity.
288
+ */
289
+ function isTaskActivity(value) {
290
+ try {
291
+ if (!(0, _orkestrel_contract.isRecord)(value)) return false;
292
+ const prototype = Object.getPrototypeOf(value);
293
+ if (prototype !== Object.prototype && prototype !== null || !Object.keys(value).every((key) => key === "note" || key === "progress" || key === "operations" || key === "constraints" || key === "updated")) return false;
294
+ const note = value.note;
295
+ const progress = value.progress;
296
+ const operations = value.operations;
297
+ const constraints = value.constraints;
298
+ const updated = value.updated;
299
+ if (operations === void 0 || constraints === void 0 || !(0, _orkestrel_contract.isFiniteNumber)(updated) || updated < 0) return false;
300
+ return isTaskActivityInput({
301
+ ...note === void 0 ? {} : { note },
302
+ ...progress === void 0 ? {} : { progress },
303
+ operations,
304
+ constraints
305
+ });
306
+ } catch {
307
+ return false;
308
+ }
309
+ }
310
+ //#endregion
158
311
  //#region src/core/helpers.ts
159
312
  /**
160
313
  * Capture every top-level {@link WorkflowOptions} value exactly once into an owned plain bag.
@@ -628,6 +781,53 @@ function recoverWorkflowSnapshot(snapshot) {
628
781
  updated: now
629
782
  };
630
783
  }
784
+ /** Compare two optional description values. */
785
+ function matchesDescription(left, right) {
786
+ return left === right && (left === void 0 || typeof left === "string");
787
+ }
788
+ /** Test a result's lineage against its containing snapshot nodes. */
789
+ function isTaskResult(value, workflow, phase, task) {
790
+ try {
791
+ if (!(0, _orkestrel_contract.isRecord)(value) || !(0, _orkestrel_contract.isRecord)(workflow) || !(0, _orkestrel_contract.isRecord)(phase) || !(0, _orkestrel_contract.isRecord)(task) || !Object.keys(value).every((key) => key === "task" || key === "phase" || key === "workflow" || key === "status" || key === "result" || key === "timestamp") || !isLifecycleStatus(value.status) || value.status !== task.status || !(0, _orkestrel_contract.isFiniteNumber)(value.timestamp) || value.timestamp < 0 || !(0, _orkestrel_contract.isRecord)(value.task) || !(0, _orkestrel_contract.isRecord)(value.phase) || !(0, _orkestrel_contract.isRecord)(value.workflow) || !Object.keys(value.workflow).every((key) => key === "id" || key === "name" || key === "description") || !Object.keys(value.phase).every((key) => key === "id" || key === "name" || key === "description" || key === "workflow") || !Object.keys(value.task).every((key) => key === "id" || key === "name" || key === "description" || key === "phase")) return false;
792
+ if (value.task.id !== task.id || value.task.name !== task.name || !matchesDescription(value.task.description, task.description) || value.phase.id !== phase.id || value.phase.name !== phase.name || !matchesDescription(value.phase.description, phase.description) || value.workflow.id !== workflow.id || value.workflow.name !== workflow.name || !matchesDescription(value.workflow.description, workflow.description)) return false;
793
+ if (!(0, _orkestrel_contract.isRecord)(value.task.phase) || !(0, _orkestrel_contract.isRecord)(value.task.phase.workflow) || !(0, _orkestrel_contract.isRecord)(value.phase.workflow) || !Object.keys(value.task.phase).every((key) => key === "id" || key === "name" || key === "description" || key === "workflow") || !Object.keys(value.task.phase.workflow).every((key) => key === "id" || key === "name" || key === "description") || !Object.keys(value.phase.workflow).every((key) => key === "id" || key === "name" || key === "description")) return false;
794
+ if (value.task.phase.id !== phase.id || value.task.phase.name !== phase.name || !matchesDescription(value.task.phase.description, phase.description) || value.phase.workflow.id !== workflow.id || value.phase.workflow.name !== workflow.name || !matchesDescription(value.phase.workflow.description, workflow.description) || value.task.phase.workflow.id !== workflow.id || value.task.phase.workflow.name !== workflow.name || !matchesDescription(value.task.phase.workflow.description, workflow.description)) return false;
795
+ if (value.status === "completed") return (0, _orkestrel_contract.isRecord)(value.result) && value.result.success === true && Object.keys(value.result).every((key) => key === "success" || key === "value") && (0, _orkestrel_contract.isJSONValue)(value.result.value);
796
+ if (value.status === "failed") return (0, _orkestrel_contract.isRecord)(value.result) && value.result.success === false && Object.keys(value.result).every((key) => key === "success" || key === "error") && isTaskFailure(value.result.error);
797
+ return false;
798
+ } catch {
799
+ return false;
800
+ }
801
+ }
802
+ function hasWorkflowHandlers(workflow, functions) {
803
+ if ("destroyed" in workflow) {
804
+ for (const phase of workflow.phases.phases()) for (const task of phase.tasks.tasks()) if (task.run !== void 0 && !(0, _orkestrel_contract.isFunction)(task.handler)) return false;
805
+ return true;
806
+ }
807
+ const runs = /* @__PURE__ */ new Set();
808
+ for (const phase of workflow.phases) for (const task of phase.tasks) {
809
+ if (task.run === void 0 || runs.has(task.run)) continue;
810
+ runs.add(task.run);
811
+ if (!(0, _orkestrel_contract.isFunction)(functions?.[task.run])) return false;
812
+ }
813
+ return true;
814
+ }
815
+ /** Locate the nearest identifiable node for an inconsistent owned snapshot. */
816
+ function workflowSnapshotContext(value) {
817
+ if (!(0, _orkestrel_contract.isRecord)(value) || !(0, _orkestrel_contract.isArray)(value.phases)) return void 0;
818
+ for (const phase of value.phases) {
819
+ if (!(0, _orkestrel_contract.isRecord)(phase)) continue;
820
+ const phaseContext = (0, _orkestrel_contract.isNonEmptyString)(phase.id) ? { phase: phase.id } : void 0;
821
+ if (!(0, _orkestrel_contract.isBoolean)(phase.bail) || phase.concurrency !== void 0 && (!(0, _orkestrel_contract.isInteger)(phase.concurrency) || phase.concurrency < 1) || !(0, _orkestrel_contract.isArray)(phase.tasks)) return phaseContext;
822
+ for (const task of phase.tasks) {
823
+ if (!(0, _orkestrel_contract.isRecord)(task)) continue;
824
+ if (task.run !== void 0 && !(0, _orkestrel_contract.isNonEmptyString)(task.run) || task.retries !== void 0 && (!(0, _orkestrel_contract.isInteger)(task.retries) || task.retries < 0) || task.timeout !== void 0 && (!(0, _orkestrel_contract.isInteger)(task.timeout) || task.timeout < 0 || task.timeout > 2147483647) || !(0, _orkestrel_contract.isInteger)(task.attempts) || task.attempts < 0) return {
825
+ ...phaseContext ?? {},
826
+ ...(0, _orkestrel_contract.isNonEmptyString)(task.id) ? { task: task.id } : {}
827
+ };
828
+ }
829
+ }
830
+ }
631
831
  /**
632
832
  * Flatten a nested list of per-phase {@link TaskResult} lists into one positional list
633
833
  * — the workflow tier of the result tree, built from each phase's `results()`.
@@ -872,206 +1072,6 @@ var Scheduler = class {
872
1072
  }
873
1073
  };
874
1074
  //#endregion
875
- //#region src/core/validators.ts
876
- /** Test the workflow lifecycle vocabulary. */
877
- function isLifecycleStatus(value) {
878
- return value === "pending" || value === "running" || value === "completed" || value === "failed" || value === "skipped" || value === "stopped";
879
- }
880
- /** Test a normalized persisted task failure. */
881
- function isTaskFailure(value) {
882
- try {
883
- return (0, _orkestrel_contract.isRecord)(value) && Object.keys(value).every((key) => key === "origin" || key === "message") && (value.origin === "handler" || value.origin === "timeout" || value.origin === "recovery") && (0, _orkestrel_contract.isNonEmptyString)(value.message);
884
- } catch {
885
- return false;
886
- }
887
- }
888
- /** Compare two optional description values. */
889
- function matchesDescription(left, right) {
890
- return left === right && (left === void 0 || typeof left === "string");
891
- }
892
- /** Test a result's lineage against its containing snapshot nodes. */
893
- function isTaskResult(value, workflow, phase, task) {
894
- try {
895
- if (!(0, _orkestrel_contract.isRecord)(value) || !(0, _orkestrel_contract.isRecord)(workflow) || !(0, _orkestrel_contract.isRecord)(phase) || !(0, _orkestrel_contract.isRecord)(task) || !Object.keys(value).every((key) => key === "task" || key === "phase" || key === "workflow" || key === "status" || key === "result" || key === "timestamp") || !isLifecycleStatus(value.status) || value.status !== task.status || !(0, _orkestrel_contract.isFiniteNumber)(value.timestamp) || value.timestamp < 0 || !(0, _orkestrel_contract.isRecord)(value.task) || !(0, _orkestrel_contract.isRecord)(value.phase) || !(0, _orkestrel_contract.isRecord)(value.workflow) || !Object.keys(value.workflow).every((key) => key === "id" || key === "name" || key === "description") || !Object.keys(value.phase).every((key) => key === "id" || key === "name" || key === "description" || key === "workflow") || !Object.keys(value.task).every((key) => key === "id" || key === "name" || key === "description" || key === "phase")) return false;
896
- if (value.task.id !== task.id || value.task.name !== task.name || !matchesDescription(value.task.description, task.description) || value.phase.id !== phase.id || value.phase.name !== phase.name || !matchesDescription(value.phase.description, phase.description) || value.workflow.id !== workflow.id || value.workflow.name !== workflow.name || !matchesDescription(value.workflow.description, workflow.description)) return false;
897
- if (!(0, _orkestrel_contract.isRecord)(value.task.phase) || !(0, _orkestrel_contract.isRecord)(value.task.phase.workflow) || !(0, _orkestrel_contract.isRecord)(value.phase.workflow) || !Object.keys(value.task.phase).every((key) => key === "id" || key === "name" || key === "description" || key === "workflow") || !Object.keys(value.task.phase.workflow).every((key) => key === "id" || key === "name" || key === "description") || !Object.keys(value.phase.workflow).every((key) => key === "id" || key === "name" || key === "description")) return false;
898
- if (value.task.phase.id !== phase.id || value.task.phase.name !== phase.name || !matchesDescription(value.task.phase.description, phase.description) || value.phase.workflow.id !== workflow.id || value.phase.workflow.name !== workflow.name || !matchesDescription(value.phase.workflow.description, workflow.description) || value.task.phase.workflow.id !== workflow.id || value.task.phase.workflow.name !== workflow.name || !matchesDescription(value.task.phase.workflow.description, workflow.description)) return false;
899
- if (value.status === "completed") return (0, _orkestrel_contract.isRecord)(value.result) && value.result.success === true && Object.keys(value.result).every((key) => key === "success" || key === "value") && (0, _orkestrel_contract.isJSONValue)(value.result.value);
900
- if (value.status === "failed") return (0, _orkestrel_contract.isRecord)(value.result) && value.result.success === false && Object.keys(value.result).every((key) => key === "success" || key === "error") && isTaskFailure(value.result.error);
901
- return false;
902
- } catch {
903
- return false;
904
- }
905
- }
906
- /**
907
- * Validate a safe owned JSON graph as a coherent workflow snapshot.
908
- *
909
- * @remarks
910
- * Callers at hostile boundaries use {@link isWorkflowSnapshot}, which owns the
911
- * graph first so this semantic pass never observes accessors or prototypes.
912
- */
913
- function isOwnedWorkflowSnapshot(value) {
914
- try {
915
- if (!(0, _orkestrel_contract.isRecord)(value) || !Object.keys(value).every((key) => key === "id" || key === "name" || key === "description" || key === "status" || key === "override" || key === "bail" || key === "phases" || key === "created" || key === "updated") || !(0, _orkestrel_contract.isNonEmptyString)(value.id) || !(0, _orkestrel_contract.isNonEmptyString)(value.name) || value.description !== void 0 && typeof value.description !== "string" || !isLifecycleStatus(value.status) || value.override !== void 0 && value.override !== "completed" && value.override !== "skipped" && value.override !== "stopped" || !(0, _orkestrel_contract.isBoolean)(value.bail) || !(0, _orkestrel_contract.isArray)(value.phases) || !(0, _orkestrel_contract.isFiniteNumber)(value.created) || value.created < 0 || !(0, _orkestrel_contract.isFiniteNumber)(value.updated) || value.updated < value.created) return false;
916
- const phaseIds = /* @__PURE__ */ new Set();
917
- const derivations = [];
918
- let frontier = false;
919
- let running = false;
920
- let vacuous = true;
921
- for (const phase of value.phases) {
922
- if (!(0, _orkestrel_contract.isRecord)(phase) || !Object.keys(phase).every((key) => key === "id" || key === "name" || key === "description" || key === "status" || key === "override" || key === "bail" || key === "concurrency" || key === "tasks") || !(0, _orkestrel_contract.isNonEmptyString)(phase.id) || phaseIds.has(phase.id) || !(0, _orkestrel_contract.isNonEmptyString)(phase.name) || phase.description !== void 0 && typeof phase.description !== "string" || !isLifecycleStatus(phase.status) || phase.override !== void 0 && phase.override !== "skipped" && phase.override !== "stopped" || !(0, _orkestrel_contract.isBoolean)(phase.bail) || phase.concurrency !== void 0 && (!(0, _orkestrel_contract.isInteger)(phase.concurrency) || phase.concurrency < 1) || !(0, _orkestrel_contract.isArray)(phase.tasks)) return false;
923
- const forced = phase.override === "skipped" || phase.override === "stopped";
924
- const started = phase.status === "running" || phase.status === "completed" || phase.status === "failed";
925
- if (!forced && frontier && started || phase.status === "running" && running) return false;
926
- if (phase.status === "running") running = true;
927
- if (!forced && (phase.status === "pending" || phase.status === "running" || phase.status === "failed" && phase.bail)) frontier = true;
928
- phaseIds.add(phase.id);
929
- const taskIds = /* @__PURE__ */ new Set();
930
- const statuses = [];
931
- if (phase.tasks.length > 0) vacuous = false;
932
- for (const task of phase.tasks) {
933
- if (!(0, _orkestrel_contract.isRecord)(task) || !Object.keys(task).every((key) => key === "id" || key === "name" || key === "description" || key === "status" || key === "result" || key === "metadata" || key === "attempts" || key === "run" || key === "retries" || key === "timeout" || key === "activity") || !(0, _orkestrel_contract.isNonEmptyString)(task.id) || taskIds.has(task.id) || !(0, _orkestrel_contract.isNonEmptyString)(task.name) || task.description !== void 0 && typeof task.description !== "string" || !isLifecycleStatus(task.status) || !(0, _orkestrel_contract.isRecord)(task.metadata) || !(0, _orkestrel_contract.isJSONValue)(task.metadata) || !(0, _orkestrel_contract.isInteger)(task.attempts) || task.attempts < 0 || task.run !== void 0 && !(0, _orkestrel_contract.isNonEmptyString)(task.run) || task.retries !== void 0 && (!(0, _orkestrel_contract.isInteger)(task.retries) || task.retries < 0) || task.timeout !== void 0 && (!(0, _orkestrel_contract.isInteger)(task.timeout) || task.timeout < 0 || task.timeout > 2147483647)) return false;
934
- const budget = (task.retries ?? 0) + 1;
935
- if (task.attempts > budget || task.status === "pending" && task.attempts >= budget) return false;
936
- if (!(task.activity === void 0 || isTaskActivity(task.activity))) return false;
937
- if (task.status === "running" || task.status === "completed" || task.status === "failed") {
938
- if (task.attempts < 1 || task.activity === void 0) return false;
939
- }
940
- if (task.status === "pending" && task.activity !== void 0) return false;
941
- if (task.status === "completed" || task.status === "failed") {
942
- if (!isTaskResult(task.result, value, phase, task)) return false;
943
- } else if (task.result !== void 0) return false;
944
- taskIds.add(task.id);
945
- statuses.push(task.status);
946
- }
947
- const derived = derivePhaseStatus(statuses);
948
- if (phase.status !== (phase.override ?? derived) || phase.override !== void 0 && phase.status !== phase.override) return false;
949
- derivations.push({
950
- status: phase.status,
951
- bail: phase.bail
952
- });
953
- }
954
- const derived = deriveWorkflowStatus(derivations);
955
- if (value.override === "completed") return value.status === "completed" && derived === "pending" && vacuous;
956
- return value.status === (value.override ?? derived);
957
- } catch {
958
- return false;
959
- }
960
- }
961
- /** Total hostile-boundary workflow snapshot guard. */
962
- function isWorkflowSnapshot(value) {
963
- const cloned = (0, _orkestrel_contract.attempt)(() => (0, _orkestrel_contract.cloneJSONValue)(value));
964
- return cloned.success && isOwnedWorkflowSnapshot(cloned.value);
965
- }
966
- function hasWorkflowHandlers(workflow, functions) {
967
- if ("destroyed" in workflow) {
968
- for (const phase of workflow.phases.phases()) for (const task of phase.tasks.tasks()) if (task.run !== void 0 && !(0, _orkestrel_contract.isFunction)(task.handler)) return false;
969
- return true;
970
- }
971
- const runs = /* @__PURE__ */ new Set();
972
- for (const phase of workflow.phases) for (const task of phase.tasks) {
973
- if (task.run === void 0 || runs.has(task.run)) continue;
974
- runs.add(task.run);
975
- if (!(0, _orkestrel_contract.isFunction)(functions?.[task.run])) return false;
976
- }
977
- return true;
978
- }
979
- /** Locate the nearest identifiable node for an inconsistent owned snapshot. */
980
- function workflowSnapshotContext(value) {
981
- if (!(0, _orkestrel_contract.isRecord)(value) || !(0, _orkestrel_contract.isArray)(value.phases)) return void 0;
982
- for (const phase of value.phases) {
983
- if (!(0, _orkestrel_contract.isRecord)(phase)) continue;
984
- const phaseContext = (0, _orkestrel_contract.isNonEmptyString)(phase.id) ? { phase: phase.id } : void 0;
985
- if (!(0, _orkestrel_contract.isBoolean)(phase.bail) || phase.concurrency !== void 0 && (!(0, _orkestrel_contract.isInteger)(phase.concurrency) || phase.concurrency < 1) || !(0, _orkestrel_contract.isArray)(phase.tasks)) return phaseContext;
986
- for (const task of phase.tasks) {
987
- if (!(0, _orkestrel_contract.isRecord)(task)) continue;
988
- if (task.run !== void 0 && !(0, _orkestrel_contract.isNonEmptyString)(task.run) || task.retries !== void 0 && (!(0, _orkestrel_contract.isInteger)(task.retries) || task.retries < 0) || task.timeout !== void 0 && (!(0, _orkestrel_contract.isInteger)(task.timeout) || task.timeout < 0 || task.timeout > 2147483647) || !(0, _orkestrel_contract.isInteger)(task.attempts) || task.attempts < 0) return {
989
- ...phaseContext ?? {},
990
- ...(0, _orkestrel_contract.isNonEmptyString)(task.id) ? { task: task.id } : {}
991
- };
992
- }
993
- }
994
- }
995
- /**
996
- * Test whether an unknown value is a valid whole-frame activity report.
997
- */
998
- function isTaskActivityInput(value) {
999
- try {
1000
- if (!(0, _orkestrel_contract.isRecord)(value)) return false;
1001
- const prototype = Object.getPrototypeOf(value);
1002
- if (prototype !== Object.prototype && prototype !== null || !Object.keys(value).every((key) => key === "note" || key === "progress" || key === "operations" || key === "constraints")) return false;
1003
- const note = value.note;
1004
- const progress = value.progress;
1005
- const operations = value.operations;
1006
- const constraints = value.constraints;
1007
- if (note !== void 0 && !(0, _orkestrel_contract.isNonEmptyString)(note)) return false;
1008
- if (progress !== void 0) {
1009
- if (!(0, _orkestrel_contract.isRecord)(progress)) return false;
1010
- const progressPrototype = Object.getPrototypeOf(progress);
1011
- if (progressPrototype !== Object.prototype && progressPrototype !== null || !Object.keys(progress).every((key) => key === "current" || key === "total" || key === "unit")) return false;
1012
- const current = progress.current;
1013
- const total = progress.total;
1014
- const unit = progress.unit;
1015
- if (!(0, _orkestrel_contract.isFiniteNumber)(current) || current < 0 || total !== void 0 && (!(0, _orkestrel_contract.isFiniteNumber)(total) || total < current) || unit !== void 0 && !(0, _orkestrel_contract.isNonEmptyString)(unit)) return false;
1016
- }
1017
- if (operations !== void 0) {
1018
- if (!(0, _orkestrel_contract.isArray)(operations)) return false;
1019
- const ids = /* @__PURE__ */ new Set();
1020
- for (const operation of operations) {
1021
- if (!(0, _orkestrel_contract.isRecord)(operation)) return false;
1022
- const operationPrototype = Object.getPrototypeOf(operation);
1023
- if (operationPrototype !== Object.prototype && operationPrototype !== null || !Object.keys(operation).every((key) => key === "id" || key === "name" || key === "started")) return false;
1024
- const id = operation.id;
1025
- const name = operation.name;
1026
- const started = operation.started;
1027
- if (!(0, _orkestrel_contract.isNonEmptyString)(id) || !(0, _orkestrel_contract.isNonEmptyString)(name) || !(0, _orkestrel_contract.isFiniteNumber)(started) || started < 0 || ids.has(id)) return false;
1028
- ids.add(id);
1029
- }
1030
- }
1031
- if (constraints !== void 0) {
1032
- if (!(0, _orkestrel_contract.isArray)(constraints)) return false;
1033
- const ids = /* @__PURE__ */ new Set();
1034
- for (const constraint of constraints) {
1035
- if (!(0, _orkestrel_contract.isRecord)(constraint)) return false;
1036
- const constraintPrototype = Object.getPrototypeOf(constraint);
1037
- if (constraintPrototype !== Object.prototype && constraintPrototype !== null || !Object.keys(constraint).every((key) => key === "id" || key === "name" || key === "started")) return false;
1038
- const id = constraint.id;
1039
- const name = constraint.name;
1040
- const started = constraint.started;
1041
- if (!(0, _orkestrel_contract.isNonEmptyString)(id) || !(0, _orkestrel_contract.isNonEmptyString)(name) || !(0, _orkestrel_contract.isFiniteNumber)(started) || started < 0 || ids.has(id)) return false;
1042
- ids.add(id);
1043
- }
1044
- }
1045
- return true;
1046
- } catch {
1047
- return false;
1048
- }
1049
- }
1050
- /**
1051
- * Test whether an unknown value is valid persisted task activity.
1052
- */
1053
- function isTaskActivity(value) {
1054
- try {
1055
- if (!(0, _orkestrel_contract.isRecord)(value)) return false;
1056
- const prototype = Object.getPrototypeOf(value);
1057
- if (prototype !== Object.prototype && prototype !== null || !Object.keys(value).every((key) => key === "note" || key === "progress" || key === "operations" || key === "constraints" || key === "updated")) return false;
1058
- const note = value.note;
1059
- const progress = value.progress;
1060
- const operations = value.operations;
1061
- const constraints = value.constraints;
1062
- const updated = value.updated;
1063
- if (operations === void 0 || constraints === void 0 || !(0, _orkestrel_contract.isFiniteNumber)(updated) || updated < 0) return false;
1064
- return isTaskActivityInput({
1065
- ...note === void 0 ? {} : { note },
1066
- ...progress === void 0 ? {} : { progress },
1067
- operations,
1068
- constraints
1069
- });
1070
- } catch {
1071
- return false;
1072
- }
1073
- }
1074
- //#endregion
1075
1075
  //#region src/core/cloners.ts
1076
1076
  /**
1077
1077
  * Validate and own a workflow snapshot before live construction.
@@ -1328,18 +1328,18 @@ var phaseUpdateShape = (0, _orkestrel_contract.objectShape)({
1328
1328
  * idle-TTL / eviction — a persisted run-state is durable orchestration state that lives until an
1329
1329
  * explicit `delete`. The public surface is EXACTLY `get` / `set` / `delete` — no extra members (the
1330
1330
  * §22 method bijection with {@link WorkflowStoreInterface}). Restore stays a caller concern: read a
1331
- * snapshot back and rebuild the live tree with {@link import('../factories.js').restoreWorkflow}.
1331
+ * snapshot back and rebuild the live tree with {@link import('../factories.js').createRestoredWorkflow}.
1332
1332
  *
1333
1333
  * @example
1334
1334
  * ```ts
1335
1335
  * import { createMemoryDriver } from '@orkestrel/database'
1336
- * import { createDatabaseWorkflowStore, createWorkflow, restoreWorkflow } from '@orkestrel/workflow'
1336
+ * import { createDatabaseWorkflowStore, createWorkflow, createRestoredWorkflow } from '@orkestrel/workflow'
1337
1337
  *
1338
1338
  * const store = createDatabaseWorkflowStore(createMemoryDriver()) // a durable driver swaps in here
1339
1339
  * const workflow = createWorkflow(definition)
1340
1340
  * await store.set(workflow.snapshot()) // persist the run state (one JSON column)
1341
1341
  * const snapshot = await store.get(definition.id)
1342
- * const restored = snapshot && restoreWorkflow(snapshot) // an identical live tree
1342
+ * const restored = snapshot && createRestoredWorkflow(snapshot) // an identical live tree
1343
1343
  * await store.delete(definition.id) // drop it
1344
1344
  * ```
1345
1345
  */
@@ -1399,17 +1399,17 @@ var DatabaseWorkflowStore = class {
1399
1399
  *
1400
1400
  * The public surface is EXACTLY `get` / `set` / `delete` — no extra members (the §22 method
1401
1401
  * bijection with {@link WorkflowStoreInterface}). Restore is a caller concern: read a snapshot
1402
- * back and rebuild the live tree with {@link import('../factories.js').restoreWorkflow}.
1402
+ * back and rebuild the live tree with {@link import('../factories.js').createRestoredWorkflow}.
1403
1403
  *
1404
1404
  * @example
1405
1405
  * ```ts
1406
- * import { createMemoryWorkflowStore, createWorkflow, restoreWorkflow } from '@orkestrel/workflow'
1406
+ * import { createMemoryWorkflowStore, createWorkflow, createRestoredWorkflow } from '@orkestrel/workflow'
1407
1407
  *
1408
1408
  * const store = createMemoryWorkflowStore()
1409
1409
  * const workflow = createWorkflow(definition)
1410
1410
  * await store.set(workflow.snapshot()) // persist the run state
1411
1411
  * const snapshot = await store.get(definition.id)
1412
- * const restored = snapshot && restoreWorkflow(snapshot) // an identical live tree
1412
+ * const restored = snapshot && createRestoredWorkflow(snapshot) // an identical live tree
1413
1413
  * await store.delete(definition.id) // drop it
1414
1414
  * ```
1415
1415
  */
@@ -2251,7 +2251,7 @@ var PhaseManager = class {
2251
2251
  * @remarks
2252
2252
  * - **Construction.** Built from a {@link WorkflowSnapshot} (the unified input —
2253
2253
  * {@link import('./factories.js').createWorkflow} seeds an initial snapshot from a
2254
- * {@link import('./types.js').WorkflowDefinition}, {@link import('./factories.js').restoreWorkflow}
2254
+ * {@link import('./types.js').WorkflowDefinition}, {@link import('./factories.js').createRestoredWorkflow}
2255
2255
  * passes a persisted one). Each child {@link Phase} is wired to escalate to `#recompute`.
2256
2256
  * - **Derived status.** `status` is `#override` when forced, else
2257
2257
  * {@link deriveWorkflowStatus} over the live phases' statuses feeding `bail`. `failed` is
@@ -2266,7 +2266,7 @@ var PhaseManager = class {
2266
2266
  * workflow tier; `phase(id)` + each `phase.task(id)` navigate DOWN, a task's `phase` / `workflow`
2267
2267
  * navigate UP.
2268
2268
  * - **Snapshot.** `snapshot()` serializes the whole live tree to a {@link WorkflowSnapshot} (pure
2269
- * JSON); {@link import('./factories.js').restoreWorkflow} rebuilds an equivalent live tree.
2269
+ * JSON); {@link import('./factories.js').createRestoredWorkflow} rebuilds an equivalent live tree.
2270
2270
  * - **Observable (AGENTS §13).** The owned {@link emitter} ({@link WorkflowEventMap}) fires
2271
2271
  * `start` / `complete` / `fail` / `pause` / `resume` / `skip` / `stop` after the
2272
2272
  * corresponding status or runtime-gate change; the emitter isolates a listener throw and
@@ -2670,7 +2670,7 @@ var WorkflowManager = class {
2670
2670
  if (!this.#owns(id, mutation, generation)) return this.#resolve(id, generation);
2671
2671
  let workflow;
2672
2672
  try {
2673
- workflow = restoreWorkflow(owned, { ...this.#functions === void 0 ? {} : { functions: this.#functions } });
2673
+ workflow = createRestoredWorkflow(owned, { ...this.#functions === void 0 ? {} : { functions: this.#functions } });
2674
2674
  } catch (error) {
2675
2675
  if (!this.#owns(id, mutation, generation)) return this.#resolve(id, generation);
2676
2676
  throw error;
@@ -3979,12 +3979,12 @@ function createWorkflow(definition, options) {
3979
3979
  return new Workflow(definitionToSnapshot(definition, captured.bail ?? definition.bail ?? false), captured);
3980
3980
  }
3981
3981
  /**
3982
- * Rebuild an equivalent live W-b entity tree from a {@link WorkflowSnapshot} — the
3982
+ * Build an equivalent live W-b entity tree from a {@link WorkflowSnapshot} — the
3983
3983
  * inverse of {@link WorkflowInterface.snapshot}, restoring structure + each node's status
3984
3984
  * + recorded results + positional order + the persisted `#override`.
3985
3985
  *
3986
3986
  * @remarks
3987
- * Round-trip fidelity is paramount: a `snapshot()` → `restoreWorkflow()` reproduces the
3987
+ * Round-trip fidelity is paramount: a `snapshot()` → `createRestoredWorkflow()` reproduces the
3988
3988
  * same status at every node (each `#override` restored DIRECTLY from the snapshot's own
3989
3989
  * `override` field, not guessed from a status divergence), the same recorded
3990
3990
  * {@link import('./types.js').TaskResult}s, and the same positional order (an interior
@@ -4004,18 +4004,18 @@ function createWorkflow(definition, options) {
4004
4004
  *
4005
4005
  * @example
4006
4006
  * ```ts
4007
- * import { restoreWorkflow } from '@orkestrel/workflow'
4007
+ * import { createRestoredWorkflow } from '@orkestrel/workflow'
4008
4008
  *
4009
- * const restored = restoreWorkflow(workflow.snapshot()) // bail comes from the snapshot
4009
+ * const restored = createRestoredWorkflow(workflow.snapshot()) // bail comes from the snapshot
4010
4010
  * restored.status === workflow.status // true
4011
4011
  * ```
4012
4012
  */
4013
- function restoreWorkflow(snapshot, options) {
4013
+ function createRestoredWorkflow(snapshot, options) {
4014
4014
  const captured = captureWorkflowOptions(options);
4015
4015
  return new Workflow(cloneWorkflowSnapshot(snapshot), captured);
4016
4016
  }
4017
4017
  /**
4018
- * Rebuild an interrupted workflow at its remaining retry budget.
4018
+ * Build an interrupted workflow back to life at its remaining retry budget.
4019
4019
  *
4020
4020
  * @remarks
4021
4021
  * Each phase captures every unique initial `run` binding once before constructing tasks. Recovery
@@ -4024,9 +4024,17 @@ function restoreWorkflow(snapshot, options) {
4024
4024
  *
4025
4025
  * @param snapshot - The hostile persisted snapshot
4026
4026
  * @param options - Runtime handlers and entity options
4027
- * @returns A recoverable live workflow
4027
+ * @returns A recoverable live {@link WorkflowInterface} root
4028
+ *
4029
+ * @example
4030
+ * ```ts
4031
+ * import { createRecoveredWorkflow } from '@orkestrel/workflow'
4032
+ *
4033
+ * const recovered = createRecoveredWorkflow(snapshot, { functions })
4034
+ * recovered.status // 'pending' — interrupted running work returned to its remaining budget
4035
+ * ```
4028
4036
  */
4029
- function recoverWorkflow(snapshot, options) {
4037
+ function createRecoveredWorkflow(snapshot, options) {
4030
4038
  const captured = captureWorkflowOptions(options);
4031
4039
  const owned = cloneWorkflowSnapshot(snapshot);
4032
4040
  if (owned.override !== void 0 || owned.phases.some((phase) => phase.override !== void 0)) throw new WorkflowError("RESTORE", `workflow '${owned.id}' has a terminal override`, { workflow: owned.id });
@@ -4035,29 +4043,6 @@ function recoverWorkflow(snapshot, options) {
4035
4043
  return workflow;
4036
4044
  }
4037
4045
  /**
4038
- * Assert that a {@link WorkflowSnapshot} carries a `boolean` `bail` — at the workflow tier AND
4039
- * on every phase — and that its every node's status (and its `override`, when present) is drawn
4040
- * from the lifecycle vocabulary, throwing a `RESTORE` {@link WorkflowError} otherwise.
4041
- *
4042
- * @remarks
4043
- * The boundary-narrowing guard (AGENTS §14) for {@link restoreWorkflow}: a snapshot is
4044
- * untrusted JSON, so a status (or an override) outside
4045
- * {@link import('./constants.js').WORKFLOW_STATUSES} /
4046
- * {@link import('./constants.js').PHASE_STATUSES} / {@link import('./constants.js').TASK_STATUSES},
4047
- * a non-boolean `bail` (the workflow's OR any phase's — both are REQUIRED persisted policy), a
4048
- * present-but-invalid phase `concurrency` (not a positive integer), or a present-but-invalid task
4049
- * `run` (an empty string) / `retries` / `timeout` (not a non-negative integer),
4050
- * is rejected loudly (naming the offending node) rather than silently producing a broken tree.
4051
- * The `override` / `concurrency` / `run` / `retries` / `timeout` are optional, so each is only
4052
- * checked WHEN present. Structural shape beyond these fields is the contract's concern; this
4053
- * guards exactly the fields the live state machine reads back.
4054
- *
4055
- * @param snapshot - The snapshot to validate
4056
- */
4057
- function assertSnapshot(snapshot) {
4058
- cloneWorkflowSnapshot(snapshot);
4059
- }
4060
- /**
4061
4046
  * Create the in-memory durable {@link WorkflowStoreInterface} — a process-lifetime
4062
4047
  * {@link MemoryWorkflowStore} persisting {@link WorkflowSnapshot}s by workflow id, the DEFAULT
4063
4048
  * backend behind the W-d persistence seam.
@@ -4070,19 +4055,19 @@ function assertSnapshot(snapshot) {
4070
4055
  * {@link createDatabaseWorkflowStore} (the snapshot as one opaque JSON column over a `databases`
4071
4056
  * table) — for a DURABLE store (run-state surviving a restart) pass it a JSON / SQLite / IndexedDB
4072
4057
  * driver, and it swaps in WITHOUT touching the runner or the entity tree. Restore stays a caller
4073
- * concern: read a snapshot back and rebuild the live tree with {@link restoreWorkflow}.
4058
+ * concern: read a snapshot back and rebuild the live tree with {@link createRestoredWorkflow}.
4074
4059
  *
4075
4060
  * @returns A memory-backed {@link WorkflowStoreInterface}
4076
4061
  *
4077
4062
  * @example
4078
4063
  * ```ts
4079
- * import { createMemoryWorkflowStore, createWorkflow, restoreWorkflow } from '@orkestrel/workflow'
4064
+ * import { createMemoryWorkflowStore, createWorkflow, createRestoredWorkflow } from '@orkestrel/workflow'
4080
4065
  *
4081
4066
  * const store = createMemoryWorkflowStore()
4082
4067
  * const workflow = createWorkflow(definition)
4083
4068
  * await store.set(workflow.snapshot()) // persist the run state
4084
4069
  * const snapshot = await store.get(definition.id)
4085
- * const restored = snapshot && restoreWorkflow(snapshot) // an identical live tree
4070
+ * const restored = snapshot && createRestoredWorkflow(snapshot) // an identical live tree
4086
4071
  * ```
4087
4072
  */
4088
4073
  function createMemoryWorkflowStore() {
@@ -4113,13 +4098,13 @@ function createMemoryWorkflowStore() {
4113
4098
  * @example
4114
4099
  * ```ts
4115
4100
  * import { createMemoryDriver } from '@orkestrel/database'
4116
- * import { createDatabaseWorkflowStore, createWorkflow, restoreWorkflow } from '@orkestrel/workflow'
4101
+ * import { createDatabaseWorkflowStore, createWorkflow, createRestoredWorkflow } from '@orkestrel/workflow'
4117
4102
  *
4118
4103
  * const store = createDatabaseWorkflowStore(createMemoryDriver()) // a durable driver swaps in here
4119
4104
  * const workflow = createWorkflow(definition)
4120
4105
  * await store.set(workflow.snapshot()) // persist the run state (one JSON column)
4121
4106
  * const snapshot = await store.get(definition.id)
4122
- * const restored = snapshot && restoreWorkflow(snapshot) // an identical live tree
4107
+ * const restored = snapshot && createRestoredWorkflow(snapshot) // an identical live tree
4123
4108
  * ```
4124
4109
  */
4125
4110
  function createDatabaseWorkflowStore(driver = (0, _orkestrel_database.createMemoryDriver)()) {
@@ -4188,11 +4173,11 @@ function createWorkflowRunner(options) {
4188
4173
  * @remarks
4189
4174
  * `options.functions` flows into every workflow the manager mints (`add`, via
4190
4175
  * {@link createWorkflow}) or hydrates (`open`'s registry-miss path, via
4191
- * {@link restoreWorkflow}), so a hydrated workflow is RUNNABLE rather than a dead snapshot
4176
+ * {@link createRestoredWorkflow}), so a hydrated workflow is RUNNABLE rather than a dead snapshot
4192
4177
  * mirror. `options.store` is the EXACT analogue of the twins' `store` seam — omitted ⇒ the
4193
4178
  * manager is registry-only (`open` resolves only what is registered, `save` is a no-op). This
4194
4179
  * is PURELY ADDITIVE: direct {@link WorkflowStoreInterface} use and
4195
- * {@link restoreWorkflow} remain valid — the manager is one more caller-driven persistence
4180
+ * {@link createRestoredWorkflow} remain valid — the manager is one more caller-driven persistence
4196
4181
  * seam, not a replacement.
4197
4182
  *
4198
4183
  * @param options - The optional `store` seam and the `functions` registry threaded into every mint/hydrate
@@ -4331,7 +4316,6 @@ exports.WorkflowError = WorkflowError;
4331
4316
  exports.WorkflowManager = WorkflowManager;
4332
4317
  exports.WorkflowPersistence = WorkflowPersistence;
4333
4318
  exports.WorkflowRunner = WorkflowRunner;
4334
- exports.assertSnapshot = assertSnapshot;
4335
4319
  exports.buildPhaseContext = buildPhaseContext;
4336
4320
  exports.buildTaskContext = buildTaskContext;
4337
4321
  exports.buildWorkflowContext = buildWorkflowContext;
@@ -4343,6 +4327,8 @@ exports.collectResults = collectResults;
4343
4327
  exports.createDatabaseWorkflowStore = createDatabaseWorkflowStore;
4344
4328
  exports.createDeferred = createDeferred;
4345
4329
  exports.createMemoryWorkflowStore = createMemoryWorkflowStore;
4330
+ exports.createRecoveredWorkflow = createRecoveredWorkflow;
4331
+ exports.createRestoredWorkflow = createRestoredWorkflow;
4346
4332
  exports.createRunner = createRunner;
4347
4333
  exports.createScheduler = createScheduler;
4348
4334
  exports.createWorkflow = createWorkflow;
@@ -4373,10 +4359,8 @@ exports.parkSignal = parkSignal;
4373
4359
  exports.phaseDefinitionToSnapshot = phaseDefinitionToSnapshot;
4374
4360
  exports.phaseShape = phaseShape;
4375
4361
  exports.phaseUpdateShape = phaseUpdateShape;
4376
- exports.recoverWorkflow = recoverWorkflow;
4377
4362
  exports.recoverWorkflowSnapshot = recoverWorkflowSnapshot;
4378
4363
  exports.resolveTaskSilence = resolveTaskSilence;
4379
- exports.restoreWorkflow = restoreWorkflow;
4380
4364
  exports.scheduleHost = scheduleHost;
4381
4365
  exports.success = success;
4382
4366
  exports.taskDefinitionToSnapshot = taskDefinitionToSnapshot;