@lostgradient/weft 0.13.0 → 0.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (114) hide show
  1. package/README.md +3 -8
  2. package/dist/cli/generated/operation-catalog.snapshot.json +977 -77
  3. package/dist/cli/generated/operation-client.generated.d.ts +14 -21
  4. package/dist/cli/help-text.d.ts +3 -3
  5. package/dist/cli/help-text.js +4 -4
  6. package/dist/cli/operation-catalog-snapshot.d.ts +1 -1
  7. package/dist/cli/schedule.js +1 -3
  8. package/dist/cli/serve-registrations.d.ts +3 -3
  9. package/dist/cli/serve-registrations.js +2 -2
  10. package/dist/cli/shutdown.d.ts +11 -0
  11. package/dist/cli/shutdown.js +25 -0
  12. package/dist/cli/validate.d.ts +1 -1
  13. package/dist/cli/version-check.d.ts +1 -1
  14. package/dist/cli/version-check.js +1 -1
  15. package/dist/cli-main.js +10 -29
  16. package/dist/client/http-client-storage.js +7 -35
  17. package/dist/client/http-request.d.ts +8 -9
  18. package/dist/client/http-request.js +3 -25
  19. package/dist/core/aggregate-validation.d.ts +2 -5
  20. package/dist/core/aggregate-validation.js +2 -10
  21. package/dist/core/atomic-state.js +21 -24
  22. package/dist/core/context/parallel-operations.d.ts +0 -2
  23. package/dist/core/context/parallel-operations.js +0 -7
  24. package/dist/core/engine/callback-checkpoint-persistence.d.ts +2 -0
  25. package/dist/core/engine/callback-checkpoint-persistence.js +6 -3
  26. package/dist/core/engine/callback-creators.js +4 -22
  27. package/dist/core/engine/checkpoint-io.d.ts +1 -1
  28. package/dist/core/engine/operations-coordination.js +1 -1
  29. package/dist/core/engine/parallel-dispatch.d.ts +1 -1
  30. package/dist/core/engine/parallel-dispatch.js +1 -1
  31. package/dist/core/engine/review-list-entries.d.ts +1 -1
  32. package/dist/core/engine/review-list-entries.js +6 -30
  33. package/dist/core/engine/schedules.js +4 -1
  34. package/dist/core/engine/timeline-coordinator-detail.d.ts +1 -1
  35. package/dist/core/inline-execution-strategy.js +8 -46
  36. package/dist/core/list-filter-validation.d.ts +2 -5
  37. package/dist/core/list-filter-validation.js +2 -10
  38. package/dist/core/review/index.d.ts +87 -0
  39. package/dist/core/review/index.js +29 -0
  40. package/dist/core/types/schedules.d.ts +13 -31
  41. package/dist/core/validation-issues.d.ts +13 -0
  42. package/dist/core/validation-issues.js +9 -0
  43. package/dist/diagnostics/validate.d.ts +9 -30
  44. package/dist/diagnostics/validate.js +83 -21
  45. package/dist/diagnostics/version-check.d.ts +2 -2
  46. package/dist/http.js +2 -2
  47. package/dist/indexeddb.js +1 -1
  48. package/dist/mcp/session.js +2 -10
  49. package/dist/mcp/tools.js +2 -10
  50. package/dist/mcp/tuple-list-equality.d.ts +1 -0
  51. package/dist/mcp/tuple-list-equality.js +12 -0
  52. package/dist/server/openapi-error-responses.js +0 -14
  53. package/dist/server/operation-catalog/index.d.ts +1 -1
  54. package/dist/server/operation-catalog/raise-fault.d.ts +2 -1
  55. package/dist/server/operation-catalog/types.d.ts +3 -2
  56. package/dist/server/operation-fault.d.ts +1 -4
  57. package/dist/server/operation-fault.js +1 -1
  58. package/dist/server/operation-registry.d.ts +2 -31
  59. package/dist/server/operations/bulk-filter-helpers.d.ts +17 -17
  60. package/dist/server/operations/bulk-filter-helpers.js +16 -37
  61. package/dist/server/operations/bulk-mutate-workflow-tags.d.ts +27 -27
  62. package/dist/server/operations/bulk-signal-workflows.d.ts +26 -26
  63. package/dist/server/operations/create-schedule.js +7 -19
  64. package/dist/server/operations/event-stream-contracts.d.ts +20 -0
  65. package/dist/server/operations/event-stream-contracts.js +67 -0
  66. package/dist/server/operations/fleet-events-sse.js +21 -50
  67. package/dist/server/operations/fleet-events-subscription.js +8 -12
  68. package/dist/server/operations/list-reviews.js +2 -19
  69. package/dist/server/operations/list-workflows.d.ts +43 -43
  70. package/dist/server/operations/list-workflows.js +9 -30
  71. package/dist/server/operations/purge-workflows.d.ts +11 -11
  72. package/dist/server/operations/recover-all.js +1 -10
  73. package/dist/server/operations/schedule-rest-body.d.ts +11 -0
  74. package/dist/server/operations/schedule-rest-body.js +28 -0
  75. package/dist/server/operations/single-workflow-control-operation.d.ts +2 -1
  76. package/dist/server/operations/update-schedule.js +7 -19
  77. package/dist/server/operations/workflow-events-sse.js +29 -67
  78. package/dist/server/operations/workflow-events-subscription.js +9 -27
  79. package/dist/server/runtime/task-polling.js +3 -5
  80. package/dist/server/task-state.d.ts +2 -8
  81. package/dist/server/task-state.js +10 -7
  82. package/dist/storage/bounded-ndjson-response.d.ts +5 -0
  83. package/dist/storage/bounded-ndjson-response.js +33 -0
  84. package/dist/storage/bun-sql.js +52 -49
  85. package/dist/storage/conditional-batch-body.d.ts +7 -0
  86. package/dist/storage/conditional-batch-body.js +14 -0
  87. package/dist/storage/http.js +5 -37
  88. package/dist/storage/lmdb.js +1 -1
  89. package/dist/storage/memory.js +1 -1
  90. package/dist/storage/neon.d.ts +3 -16
  91. package/dist/storage/neon.js +2 -2
  92. package/dist/storage/node-sqlite-loader.d.ts +2 -2
  93. package/dist/storage/node-sqlite.js +32 -17
  94. package/dist/storage/postgres.js +1 -1
  95. package/dist/storage/resolve.js +1 -1
  96. package/dist/storage/scoped-storage.js +1 -1
  97. package/dist/storage/turso.js +1 -1
  98. package/dist/version.d.ts +1 -1
  99. package/dist/version.js +1 -1
  100. package/dist/web-extension.js +1 -1
  101. package/dist/worker/execute-with-interceptors.d.ts +1 -1
  102. package/dist/worker/execute-with-interceptors.js +2 -2
  103. package/dist/worker/index.js +5 -5
  104. package/dist/worker/long-poll.js +3 -4
  105. package/dist/worker/protocol-messages.d.ts +11 -19
  106. package/dist/worker/protocol-schemas.d.ts +8 -8
  107. package/dist/worker/protocol-schemas.js +4 -4
  108. package/dist/worker/protocol-task-result.d.ts +1 -0
  109. package/dist/worker/protocol-task-result.js +1 -3
  110. package/dist/worker/protocol.js +1 -1
  111. package/dist/worker/registry/types.d.ts +2 -7
  112. package/dist/worker/registry.d.ts +3 -9
  113. package/dist/worker/registry.js +2 -5
  114. package/package.json +1 -1
@@ -6,13 +6,6 @@ import {
6
6
  isParallelOperationCacheEntry
7
7
  } from "./parallel-cache-entry.js";
8
8
  import { captureCallerStack } from "./validation.js";
9
-
10
- export {
11
- assertValidParallelOperationCacheEntry,
12
- BranchTopologyChangedError,
13
- createParallelOperationCacheEntry,
14
- isParallelOperationCacheEntry
15
- };
16
9
  function reconstructAllResult(entry) {
17
10
  return entry.branches.map((slot) => {
18
11
  if (slot.status !== "fulfilled")
@@ -1,3 +1,5 @@
1
1
  import type { ContextOperationRequest } from '../context.ts';
2
+ import { type PersistCheckpointCallbacks } from './checkpoint-io.ts';
2
3
  import type { Engine } from './index.ts';
4
+ export declare function createCheckpointPersistenceCallbacks<TWorkflows extends object, TActivities extends object>(engine: Engine<TWorkflows, TActivities>): PersistCheckpointCallbacks;
3
5
  export declare function persistCheckpointForDataOperation<TWorkflows extends object, TActivities extends object>(engine: Engine<TWorkflows, TActivities>, workflowId: string, operation: ContextOperationRequest): Promise<void>;
@@ -9,8 +9,8 @@ import {
9
9
  import { getInternals } from "./internals.js";
10
10
  import { swallowPromiseRejection } from "./strategy-helpers.js";
11
11
  import { terminateWorkflow } from "./termination.js";
12
- export function persistCheckpointForDataOperation(engine, workflowId, operation) {
13
- return persistCheckpoint(getInternals(engine), workflowId, operation, void 0, {
12
+ export function createCheckpointPersistenceCallbacks(engine) {
13
+ return {
14
14
  appendTimelineBatchOperations: (id, checkpointOperation, step, timestamp, operations) => appendTimelineBatchOperations(getInternals(engine), id, checkpointOperation, step, timestamp, operations),
15
15
  swallowPromiseRejection: (promise) => {
16
16
  swallowPromiseRejection(promise);
@@ -21,5 +21,8 @@ export function persistCheckpointForDataOperation(engine, workflowId, operation)
21
21
  engine.dispatchEvent(event);
22
22
  },
23
23
  enforceHistoryCircuitBreaker: (id) => terminateWorkflow(getInternals(engine), id, "timed-out", createTerminationCallbacks(engine), HISTORY_CIRCUIT_BREAKER_REASON)
24
- }, { timeline: "preserve-pending" });
24
+ };
25
+ }
26
+ export function persistCheckpointForDataOperation(engine, workflowId, operation) {
27
+ return persistCheckpoint(getInternals(engine), workflowId, operation, void 0, createCheckpointPersistenceCallbacks(engine), { timeline: "preserve-pending" });
25
28
  }
@@ -1,6 +1,5 @@
1
1
  import { KEYS } from "../../storage/interface.js";
2
- import { HISTORY_CIRCUIT_BREAKER_REASON } from "../types.js";
3
- import { validateAttributeValueSizes } from "./attributes-tags.js";
2
+ import { createCheckpointPersistenceCallbacks } from "./callback-checkpoint-persistence.js";
4
3
  import {
5
4
  createConstraintCallbacks,
6
5
  createLifecycleCallbacks,
@@ -8,12 +7,7 @@ import {
8
7
  registerEnsureRetentionSweepInterval
9
8
  } from "./callback-creators-core.js";
10
9
  import { createOperationRouterCallbacks } from "./callback-creators-router.js";
11
- import {
12
- appendTimelineBatchOperations,
13
- persistCheckpoint,
14
- pruneCheckpointHistory,
15
- validateDevelopmentCheckpoint
16
- } from "./checkpoint-io.js";
10
+ import { persistCheckpoint, validateDevelopmentCheckpoint } from "./checkpoint-io.js";
17
11
  import { evaluateConstraints } from "./constraints.js";
18
12
  import {
19
13
  getParkedWorkflowResumeDisposition,
@@ -30,8 +24,7 @@ import {
30
24
  } from "./retention.js";
31
25
  import { hasBufferedSignal } from "./signals.js";
32
26
  import { loadWorkflowState, runSerializedWorkflowStateWrite } from "./storage-io.js";
33
- import { swallowPromiseRejection } from "./strategy-helpers.js";
34
- import { cleanupWaiters, terminateWorkflow } from "./termination.js";
27
+ import { cleanupWaiters } from "./termination.js";
35
28
  export { createUpdateCallbacks } from "./callback-creators-bundles.js";
36
29
  export {
37
30
  createBroadcastCallbacks,
@@ -64,18 +57,7 @@ export function createInlineParkingCallbacks(engine) {
64
57
  };
65
58
  }
66
59
  export function persistCheckpointForEngine(engine, workflowId, operation, workerCheckpointBytes) {
67
- return persistCheckpoint(getInternals(engine), workflowId, operation, workerCheckpointBytes, {
68
- appendTimelineBatchOperations: (id, checkpointOperation, step, timestamp, operations) => appendTimelineBatchOperations(getInternals(engine), id, checkpointOperation, step, timestamp, operations),
69
- swallowPromiseRejection: (promise) => {
70
- swallowPromiseRejection(promise);
71
- },
72
- validateAttributeValueSizes,
73
- pruneCheckpointHistory: (id, step) => pruneCheckpointHistory(getInternals(engine), id, step),
74
- dispatchEvent: (event) => {
75
- engine.dispatchEvent(event);
76
- },
77
- enforceHistoryCircuitBreaker: (id) => terminateWorkflow(getInternals(engine), id, "timed-out", createTerminationCallbacks(engine), HISTORY_CIRCUIT_BREAKER_REASON)
78
- });
60
+ return persistCheckpoint(getInternals(engine), workflowId, operation, workerCheckpointBytes, createCheckpointPersistenceCallbacks(engine));
79
61
  }
80
62
  function ensureRetentionSweepIntervalForEngine(engine) {
81
63
  ensureRetentionSweepInterval(getInternals(engine), {
@@ -9,7 +9,7 @@ type PendingTimelineEntryValue = {
9
9
  export type PersistCheckpointOptions = {
10
10
  timeline?: 'record-operation' | 'preserve-pending';
11
11
  };
12
- type PersistCheckpointCallbacks = {
12
+ export type PersistCheckpointCallbacks = {
13
13
  appendTimelineBatchOperations: (workflowId: string, operation: ContextOperationRequest, step: number, timestamp: number, operations: BatchOperation[]) => PendingTimelineEntryValue;
14
14
  swallowPromiseRejection: (promise: Promise<void>) => void;
15
15
  validateAttributeValueSizes: (attributes: Record<string, SearchAttributeValue>) => void;
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  isParallelOperationCacheEntry
3
- } from "../context/parallel-operations.js";
3
+ } from "../context/parallel-cache-entry.js";
4
4
  import {
5
5
  executeRunAllBranches,
6
6
  executeRunAllBranchesSettled
@@ -25,7 +25,7 @@
25
25
  * checkpoint-write machinery — see the `parallel-execution.md` guide
26
26
  * for the precise durability contract.
27
27
  */
28
- import type { ParallelBranchSlot, ParallelOperationCacheEntry } from '../context/parallel-operations.ts';
28
+ import type { ParallelBranchSlot, ParallelOperationCacheEntry } from '../context/parallel-cache-entry.ts';
29
29
  export type ParallelDispatchResult = {
30
30
  /** Final slot table — every entry is `fulfilled` or `rejected`. */
31
31
  slots: ParallelBranchSlot[];
@@ -1,4 +1,4 @@
1
- import { createParallelOperationCacheEntry } from "../context/parallel-operations.js";
1
+ import { createParallelOperationCacheEntry } from "../context/parallel-cache-entry.js";
2
2
  export function createFirstRejectionCapture() {
3
3
  return { hasFirstError: !1, firstError: void 0 };
4
4
  }
@@ -1,4 +1,4 @@
1
- import type { HumanReviewResult, ReviewRequest } from '../review/index.ts';
1
+ import { type HumanReviewResult, type ReviewRequest } from '../review/index.ts';
2
2
  import type { CompletedReviewEntry, PendingReviewEntry } from '../types.ts';
3
3
  export declare function toPendingReviewEntry(review: ReviewRequest): PendingReviewEntry;
4
4
  export declare function parseStoredReviewRequest(value: Uint8Array): ReviewRequest | null;
@@ -1,32 +1,8 @@
1
- import { z } from "zod";
2
1
  import { decode } from "../codec.js";
3
- const storedReviewRequestSchema = z.object({
4
- reviewId: z.string(),
5
- workflowId: z.string(),
6
- artifact: z.unknown().nonoptional(),
7
- reviewType: z.string(),
8
- reviewers: z.array(z.string()),
9
- allowPartial: z.boolean(),
10
- timeout: z.number().optional(),
11
- webhookUrl: z.string().optional(),
12
- createdAt: z.number()
13
- }), persistedCompletedReviewEntrySchema = z.object({
14
- status: z.literal("completed"),
15
- reviewId: z.string(),
16
- workflowId: z.string(),
17
- artifact: z.unknown().nonoptional(),
18
- reviewType: z.string(),
19
- reviewers: z.array(z.string()),
20
- allowPartial: z.boolean(),
21
- timeout: z.number().optional(),
22
- webhookUrl: z.string().optional(),
23
- createdAt: z.number(),
24
- decision: z.enum(["approved", "rejected", "needs-changes"]),
25
- reviewer: z.string(),
26
- feedback: z.string().optional(),
27
- sectionDecisions: z.record(z.string(), z.enum(["approved", "rejected"])).optional(),
28
- timestamp: z.number()
29
- });
2
+ import {
3
+ completedReviewEntrySchema,
4
+ reviewRequestSchema
5
+ } from "../review/index.js";
30
6
  function assignWhenDefined(target, key, value) {
31
7
  if (value !== void 0)
32
8
  target[key] = value;
@@ -58,7 +34,7 @@ export function parseStoredReviewRequest(value) {
58
34
  } catch {
59
35
  return null;
60
36
  }
61
- const parsedReview = storedReviewRequestSchema.safeParse(decodedValue);
37
+ const parsedReview = reviewRequestSchema.safeParse(decodedValue);
62
38
  if (!parsedReview.success)
63
39
  return null;
64
40
  return normalizeStoredReviewRequest(parsedReview.data);
@@ -110,7 +86,7 @@ export function parseCompletedReviewEntry(value) {
110
86
  } catch {
111
87
  return null;
112
88
  }
113
- const parsedReview = persistedCompletedReviewEntrySchema.safeParse(decodedValue);
89
+ const parsedReview = completedReviewEntrySchema.safeParse(decodedValue);
114
90
  if (!parsedReview.success)
115
91
  return null;
116
92
  return normalizeCompletedReviewEntry(parsedReview.data);
@@ -100,7 +100,10 @@ async function hasCurrentScheduleTimer(internals, state) {
100
100
  }
101
101
  export function toScheduleSummary(state) {
102
102
  const { input: _input, ...summary } = state;
103
- return { ...summary, queuedRuns: summary.queuedRuns.map((queuedRun) => ({ ...queuedRun })) };
103
+ return {
104
+ ...summary,
105
+ queuedRuns: summary.queuedRuns.map((queuedRun) => ({ ...queuedRun }))
106
+ };
104
107
  }
105
108
  export async function pauseSchedule(internals, scheduleId) {
106
109
  const normalizedScheduleId = coerceScheduleId(scheduleId, "scheduleId"), state = await requireScheduleState(internals, normalizedScheduleId);
@@ -1,5 +1,5 @@
1
1
  import type { ContextOperationRequest } from '../context.ts';
2
- import type { ParallelBranchSlot } from '../context/parallel-operations.ts';
2
+ import type { ParallelBranchSlot } from '../context/parallel-cache-entry.ts';
3
3
  import type { WorkflowTimelineOperationDetail } from '../types.ts';
4
4
  import type { EngineInternals } from './internals.ts';
5
5
  export declare function operationTimelineDetail(operation: ContextOperationRequest, index: number, outcome: WorkflowTimelineOperationDetail['outcome'], options?: {
@@ -128,11 +128,17 @@ export class InlineExecutionStrategy {
128
128
  this[Symbol.dispose]();
129
129
  }
130
130
  #driveGenerator(workflowId, generator, lastResult) {
131
+ return this.#advanceGenerator(workflowId, () => generator.next(lastResult), void 0);
132
+ }
133
+ #throwIntoGenerator(workflowId, generator, error, operationFailureCategory) {
134
+ return this.#advanceGenerator(workflowId, () => generator.throw(error), operationFailureCategory);
135
+ }
136
+ #advanceGenerator(workflowId, advance, fallbackFailureCategory) {
131
137
  return this.#trackWorkflowAdvance(workflowId, (async () => {
132
138
  try {
133
139
  if (this.#abortControllers.get(workflowId)?.signal.aborted)
134
140
  return;
135
- const iterationResult = await generator.next(lastResult);
141
+ const iterationResult = await advance();
136
142
  if (iterationResult.done) {
137
143
  this.#cleanup(workflowId, {
138
144
  preserveTrackedAdvance: !0,
@@ -161,7 +167,7 @@ export class InlineExecutionStrategy {
161
167
  type: "failed",
162
168
  workflowId,
163
169
  error: error instanceof Error ? error.message : String(error),
164
- failureCategory: classifyErrorAsFailureCategory(error, {
170
+ failureCategory: fallbackFailureCategory ?? classifyErrorAsFailureCategory(error, {
165
171
  defaultErrorCategory: "application"
166
172
  })
167
173
  };
@@ -171,50 +177,6 @@ export class InlineExecutionStrategy {
171
177
  }
172
178
  })());
173
179
  }
174
- #throwIntoGenerator(workflowId, generator, error, operationFailureCategory) {
175
- return this.#trackWorkflowAdvance(workflowId, (async () => {
176
- try {
177
- if (this.#abortControllers.get(workflowId)?.signal.aborted)
178
- return;
179
- const iterationResult = await generator.throw(error);
180
- if (iterationResult.done) {
181
- this.#cleanup(workflowId, {
182
- preserveTrackedAdvance: !0,
183
- preserveTrackedTurn: !0
184
- });
185
- this.#emit({
186
- type: "completed",
187
- workflowId,
188
- result: iterationResult.value
189
- });
190
- return;
191
- }
192
- const operation = iterationResult.value;
193
- this.#emit({
194
- type: "checkpoint",
195
- workflowId,
196
- checkpoint: new ArrayBuffer(0),
197
- operationRequest: operation
198
- });
199
- } catch (innerError) {
200
- this.#cleanup(workflowId, {
201
- preserveTrackedAdvance: !0,
202
- preserveTrackedTurn: !0
203
- });
204
- const failedMessage = {
205
- type: "failed",
206
- workflowId,
207
- error: innerError instanceof Error ? innerError.message : String(innerError),
208
- failureCategory: operationFailureCategory ?? classifyErrorAsFailureCategory(innerError, {
209
- defaultErrorCategory: "application"
210
- })
211
- };
212
- if (innerError instanceof Error && innerError.stack !== void 0)
213
- failedMessage.errorStack = innerError.stack;
214
- this.#emit(failedMessage);
215
- }
216
- })());
217
- }
218
180
  #trackWorkflowAdvance(workflowId, pendingAdvance) {
219
181
  const trackedAdvance = pendingAdvance.finally(() => {
220
182
  if (this.#workflowAdvances.get(workflowId) === trackedAdvance)
@@ -12,6 +12,7 @@ import { z } from 'zod';
12
12
  import { isFailureCategory } from './failure-categories.ts';
13
13
  import type { FailureCategory, WorkflowStatus } from './types/identity.ts';
14
14
  import type { ListFilter } from './types/list-options.ts';
15
+ import { type ValidationIssue } from './validation-issues.ts';
15
16
  import { WeftError } from './weft-error.ts';
16
17
  /**
17
18
  * Concrete object schema for {@link ListFilter}. Supports `.omit()` and
@@ -56,11 +57,7 @@ export declare const listFilterObjectSchema: z.ZodObject<{
56
57
  failureCategory: z.ZodOptional<z.ZodUnion<readonly [z.ZodType<FailureCategory, unknown, z.core.$ZodTypeInternals<FailureCategory, unknown>>, z.ZodArray<z.ZodType<FailureCategory, unknown, z.core.$ZodTypeInternals<FailureCategory, unknown>>>]>>;
57
58
  }, z.core.$strict>;
58
59
  /** A flattened Zod issue suitable for cross-transport serialization. */
59
- export type FilterValidationIssue = {
60
- readonly path: ReadonlyArray<string | number>;
61
- readonly message: string;
62
- readonly code: string;
63
- };
60
+ export type FilterValidationIssue = ValidationIssue;
64
61
  /**
65
62
  * Thrown by {@link normalizeListFilter} when the input fails validation.
66
63
  * Carries flattened Zod issues so transport adapters can map directly to the
@@ -1,5 +1,6 @@
1
1
  import { z } from "zod";
2
2
  import { FAILURE_CATEGORIES, isFailureCategory } from "./failure-categories.js";
3
+ import { flattenZodIssue } from "./validation-issues.js";
3
4
  import { WeftError } from "./weft-error.js";
4
5
  const WORKFLOW_STATUSES = [
5
6
  "pending",
@@ -48,15 +49,6 @@ export const listFilterObjectSchema = z.object({
48
49
  executionDeadline: timeRangeSchema.optional(),
49
50
  failureCategory: z.union([failureCategorySchema, z.array(failureCategorySchema).min(1)]).optional()
50
51
  }).strict();
51
- function flattenIssue(issue) {
52
- const path = [];
53
- for (const segment of issue.path)
54
- if (typeof segment === "string" || typeof segment === "number")
55
- path.push(segment);
56
- else
57
- path.push(String(segment));
58
- return { path, message: issue.message, code: issue.code };
59
- }
60
52
 
61
53
  export class ListFilterValidationError extends WeftError {
62
54
  issues;
@@ -72,7 +64,7 @@ export class ListFilterValidationError extends WeftError {
72
64
  export function normalizeListFilter(input) {
73
65
  const result = listFilterObjectSchema.safeParse(input ?? {});
74
66
  if (!result.success)
75
- throw new ListFilterValidationError(result.error.issues.map(flattenIssue));
67
+ throw new ListFilterValidationError(result.error.issues.map(flattenZodIssue));
76
68
  if (result.data.parentWorkflowExecutionToken !== void 0 && result.data.parentWorkflowId === void 0)
77
69
  throw new ListFilterValidationError([
78
70
  {
@@ -6,6 +6,7 @@
6
6
  *
7
7
  * @module human-review
8
8
  */
9
+ import { z } from 'zod';
9
10
  import type { BatchOperation, Storage } from '../../storage/interface.ts';
10
11
  import { WeftError } from '../weft-error.ts';
11
12
  /**
@@ -51,6 +52,92 @@ export interface ReviewDecisionRecord {
51
52
  sectionDecisions?: Record<string, 'approved' | 'rejected'>;
52
53
  timestamp: number;
53
54
  }
55
+ /** Canonical schema for a persisted review request without its storage envelope. */
56
+ export declare const reviewRequestSchema: z.ZodObject<{
57
+ reviewId: z.ZodString;
58
+ workflowId: z.ZodString;
59
+ artifact: z.ZodNonOptional<z.ZodUnknown>;
60
+ reviewType: z.ZodString;
61
+ reviewers: z.ZodArray<z.ZodString>;
62
+ allowPartial: z.ZodBoolean;
63
+ timeout: z.ZodOptional<z.ZodNumber>;
64
+ webhookUrl: z.ZodOptional<z.ZodString>;
65
+ createdAt: z.ZodNumber;
66
+ }, z.core.$strip>;
67
+ /** Canonical schema for a pending review entry returned by review list surfaces. */
68
+ export declare const pendingReviewEntrySchema: z.ZodObject<{
69
+ reviewId: z.ZodString;
70
+ workflowId: z.ZodString;
71
+ artifact: z.ZodNonOptional<z.ZodUnknown>;
72
+ reviewType: z.ZodString;
73
+ reviewers: z.ZodArray<z.ZodString>;
74
+ allowPartial: z.ZodBoolean;
75
+ timeout: z.ZodOptional<z.ZodNumber>;
76
+ webhookUrl: z.ZodOptional<z.ZodString>;
77
+ createdAt: z.ZodNumber;
78
+ status: z.ZodLiteral<"pending">;
79
+ }, z.core.$strip>;
80
+ /** Canonical schema for a completed review entry returned by review list surfaces. */
81
+ export declare const completedReviewEntrySchema: z.ZodObject<{
82
+ decision: z.ZodEnum<{
83
+ approved: "approved";
84
+ rejected: "rejected";
85
+ "needs-changes": "needs-changes";
86
+ }>;
87
+ reviewer: z.ZodString;
88
+ feedback: z.ZodOptional<z.ZodString>;
89
+ sectionDecisions: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodEnum<{
90
+ approved: "approved";
91
+ rejected: "rejected";
92
+ }>>>;
93
+ timestamp: z.ZodNumber;
94
+ reviewId: z.ZodString;
95
+ workflowId: z.ZodString;
96
+ artifact: z.ZodNonOptional<z.ZodUnknown>;
97
+ reviewType: z.ZodString;
98
+ reviewers: z.ZodArray<z.ZodString>;
99
+ allowPartial: z.ZodBoolean;
100
+ timeout: z.ZodOptional<z.ZodNumber>;
101
+ webhookUrl: z.ZodOptional<z.ZodString>;
102
+ createdAt: z.ZodNumber;
103
+ status: z.ZodLiteral<"completed">;
104
+ }, z.core.$strip>;
105
+ /** Canonical schema for the discriminated review list-entry union. */
106
+ export declare const reviewListEntrySchema: z.ZodUnion<readonly [z.ZodObject<{
107
+ reviewId: z.ZodString;
108
+ workflowId: z.ZodString;
109
+ artifact: z.ZodNonOptional<z.ZodUnknown>;
110
+ reviewType: z.ZodString;
111
+ reviewers: z.ZodArray<z.ZodString>;
112
+ allowPartial: z.ZodBoolean;
113
+ timeout: z.ZodOptional<z.ZodNumber>;
114
+ webhookUrl: z.ZodOptional<z.ZodString>;
115
+ createdAt: z.ZodNumber;
116
+ status: z.ZodLiteral<"pending">;
117
+ }, z.core.$strip>, z.ZodObject<{
118
+ decision: z.ZodEnum<{
119
+ approved: "approved";
120
+ rejected: "rejected";
121
+ "needs-changes": "needs-changes";
122
+ }>;
123
+ reviewer: z.ZodString;
124
+ feedback: z.ZodOptional<z.ZodString>;
125
+ sectionDecisions: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodEnum<{
126
+ approved: "approved";
127
+ rejected: "rejected";
128
+ }>>>;
129
+ timestamp: z.ZodNumber;
130
+ reviewId: z.ZodString;
131
+ workflowId: z.ZodString;
132
+ artifact: z.ZodNonOptional<z.ZodUnknown>;
133
+ reviewType: z.ZodString;
134
+ reviewers: z.ZodArray<z.ZodString>;
135
+ allowPartial: z.ZodBoolean;
136
+ timeout: z.ZodOptional<z.ZodNumber>;
137
+ webhookUrl: z.ZodOptional<z.ZodString>;
138
+ createdAt: z.ZodNumber;
139
+ status: z.ZodLiteral<"completed">;
140
+ }, z.core.$strip>]>;
54
141
  /**
55
142
  * One step in a {@link ReviewOptions.escalation} chain. Either reassigns the
56
143
  * pending review to a new owner (`to`) or auto-decides it (`action`) after
@@ -1,7 +1,36 @@
1
+ import { z } from "zod";
1
2
  import { KEYS } from "../../storage/interface.js";
2
3
  import { decode, encode } from "../codec.js";
3
4
  import { WeftError } from "../weft-error.js";
4
5
  import { ReviewRequestedEvent } from "./events.js";
6
+ const reviewRequestFields = {
7
+ reviewId: z.string(),
8
+ workflowId: z.string(),
9
+ artifact: z.unknown().nonoptional(),
10
+ reviewType: z.string(),
11
+ reviewers: z.array(z.string()),
12
+ allowPartial: z.boolean(),
13
+ timeout: z.number().optional(),
14
+ webhookUrl: z.string().optional(),
15
+ createdAt: z.number()
16
+ }, reviewDecisionFields = {
17
+ decision: z.enum(["approved", "rejected", "needs-changes"]),
18
+ reviewer: z.string(),
19
+ feedback: z.string().optional(),
20
+ sectionDecisions: z.record(z.string(), z.enum(["approved", "rejected"])).optional(),
21
+ timestamp: z.number()
22
+ };
23
+ export const reviewRequestSchema = z.object(reviewRequestFields), pendingReviewEntrySchema = z.object({
24
+ status: z.literal("pending"),
25
+ ...reviewRequestFields
26
+ }), completedReviewEntrySchema = z.object({
27
+ status: z.literal("completed"),
28
+ ...reviewRequestFields,
29
+ ...reviewDecisionFields
30
+ }), reviewListEntrySchema = z.union([
31
+ pendingReviewEntrySchema,
32
+ completedReviewEntrySchema
33
+ ]);
5
34
 
6
35
  export class ReviewTimeoutError extends WeftError {
7
36
  reviewId;
@@ -181,14 +181,13 @@ export type ScheduleDefinition<TInput = unknown> = ScheduleSpec & {
181
181
  */
182
182
  export declare function schedule<TInput>(definition: ScheduleDefinition<TInput>): ScheduleDefinition<TInput>;
183
183
  /**
184
- * Full persisted state of a recurring schedule. Returned by `engine.getSchedule(id)`.
185
- * Use {@link ScheduleSummary} (returned by list operations and `engine.getSchedule()`)
186
- * for the lightweight variant it omits `input` to keep payloads small.
184
+ * Metadata shared by persisted schedule state and lightweight schedule summaries.
185
+ * Persisted state and summaries extend this contract so metadata cannot drift
186
+ * between durable records and public lightweight responses.
187
187
  */
188
- export interface ScheduleState {
188
+ export interface ScheduleMetadata {
189
189
  id: string;
190
190
  workflowType: string;
191
- input: unknown;
192
191
  /** Human-readable operator description stored with this schedule. */
193
192
  description?: string;
194
193
  /**
@@ -220,38 +219,21 @@ export interface ScheduleState {
220
219
  /** Ordered durable occurrences waiting behind `currentWorkflowId`. */
221
220
  queuedRuns: ScheduleQueuedRun[];
222
221
  }
222
+ /**
223
+ * Full persisted state of a recurring schedule. Returned by `engine.getSchedule(id)`.
224
+ * Use {@link ScheduleSummary} (returned by list operations and `engine.getSchedule()`)
225
+ * for the lightweight variant — it omits `input` to keep payloads small.
226
+ */
227
+ export interface ScheduleState extends ScheduleMetadata {
228
+ input: unknown;
229
+ }
223
230
  /**
224
231
  * Lightweight summary of a recurring schedule returned by list operations.
225
232
  * Contains cron expression, status, timing metadata, and the ID of the
226
233
  * currently running workflow (if any). For the full record including the
227
234
  * `input`, use {@link ScheduleState}.
228
235
  */
229
- export interface ScheduleSummary {
230
- id: string;
231
- workflowType: string;
232
- /** Human-readable operator description stored with this schedule. */
233
- description?: string;
234
- /** Cron expression for cron-based schedules; absent for interval schedules. */
235
- cronExpression?: string;
236
- /** Interval period in milliseconds for interval-based schedules; absent for cron schedules. */
237
- intervalMs?: number;
238
- status: ScheduleStatus;
239
- overlap: ScheduleOverlapPolicy;
240
- backfill: boolean;
241
- /** Normalized deterministic jitter window in milliseconds. */
242
- jitterMs?: number;
243
- createdAt: number;
244
- updatedAt: number;
245
- /** Most recent occurrence that started a scheduled workflow. */
246
- lastFireAt?: number;
247
- /** Most recent occurrence skipped because a non-backfill timer was late. */
248
- lastMissedFireAt?: number;
249
- /** Lifetime count of occurrences skipped because a non-backfill timer was late. */
250
- missedFireCount: number;
251
- nextFireAt: number | null;
252
- currentWorkflowId?: string;
253
- /** Ordered durable occurrences waiting behind `currentWorkflowId`. */
254
- queuedRuns: ScheduleQueuedRun[];
236
+ export interface ScheduleSummary extends ScheduleMetadata {
255
237
  }
256
238
  /**
257
239
  * Filter criteria for `engine.listSchedules`. All fields are optional.
@@ -0,0 +1,13 @@
1
+ import type { ZodIssue } from 'zod';
2
+ /** A flattened Zod issue suitable for cross-transport serialization. */
3
+ export type ValidationIssue = {
4
+ readonly path: ReadonlyArray<string | number>;
5
+ readonly message: string;
6
+ readonly code: string;
7
+ };
8
+ /**
9
+ * Convert a Zod issue into the stable diagnostic shape used by core validators.
10
+ * Path segments outside the JSON-friendly string and number forms are rendered
11
+ * with their string representation, preserving the original issue order.
12
+ */
13
+ export declare function flattenZodIssue(issue: ZodIssue): ValidationIssue;
@@ -0,0 +1,9 @@
1
+ export function flattenZodIssue(issue) {
2
+ const path = [];
3
+ for (const segment of issue.path)
4
+ if (typeof segment === "string" || typeof segment === "number")
5
+ path.push(segment);
6
+ else
7
+ path.push(String(segment));
8
+ return { path, message: issue.message, code: issue.code };
9
+ }
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Design-time workflow validation for `weft validate`.
3
3
  *
4
- * Analyses workflow registrations for common anti-patterns:
4
+ * Analyses workflow definitions for common anti-patterns:
5
5
  *
6
6
  * 1. **Unbounded retry policy** — an activity whose `retry.maxAttempts` is
7
7
  * `Infinity` (or the workflow registration specifies `retry.maxAttempts`
@@ -21,27 +21,7 @@
21
21
  *
22
22
  * @module diagnostics/validate
23
23
  */
24
- import type { ConstraintDefinition } from '../core/constraint.ts';
25
- import type { ActivityDefinition, DefinitionSchema, RetentionPolicy, SearchAttributeSchema, WorkflowFunction } from '../core/types.ts';
26
- /**
27
- * Loosely-typed workflow registration shape used only by the `weft validate`
28
- * and `weft schedule` CLIs when loading workflow modules from disk. This is
29
- * intentionally separate from the public `WorkflowDefinition` type because
30
- * loaded modules historically export bare `{ handler, ... }` objects that
31
- * do not carry a `name` field — the registration key comes from the export
32
- * key, not the object itself.
33
- */
34
- export interface WorkflowRegistration<TInput = unknown, TOutput = unknown> {
35
- version?: string;
36
- description?: string;
37
- tags?: ReadonlyArray<string>;
38
- inputSchema?: DefinitionSchema<unknown, TInput>;
39
- outputSchema?: DefinitionSchema<unknown, TOutput>;
40
- handler: WorkflowFunction<TInput, TOutput>;
41
- searchAttributes?: SearchAttributeSchema;
42
- retention?: RetentionPolicy;
43
- constraints?: ConstraintDefinition[];
44
- }
24
+ import type { ActivityDefinition, WorkflowDefinition } from '../core/types.ts';
45
25
  export type ValidationIssueSeverity = 'error' | 'warning';
46
26
  export type ValidationIssueCode = 'unbounded-retry' | 'stateful-without-compensator' | 'non-serializable-input';
47
27
  export interface ValidationIssue {
@@ -52,7 +32,7 @@ export interface ValidationIssue {
52
32
  message: string;
53
33
  }
54
34
  export interface ValidationReport {
55
- /** Total number of workflow registrations scanned. */
35
+ /** Total number of workflow definitions scanned. */
56
36
  workflowCount: number;
57
37
  /** All detected issues across all registrations. */
58
38
  issues: ValidationIssue[];
@@ -60,16 +40,15 @@ export interface ValidationReport {
60
40
  valid: boolean;
61
41
  }
62
42
  /**
63
- * Validate a collection of workflow registrations for common anti-patterns.
43
+ * Validate a collection of workflow definitions for common anti-patterns.
64
44
  *
65
- * @param registrations A record of workflow type name WorkflowRegistration.
66
- * @param activities Optional list of ActivityDefinition objects to check.
67
- * Activities are not reachable from WorkflowRegistration
68
- * alone, so pass them explicitly when available.
45
+ * @param registrations A record of workflow type name to WorkflowDefinition.
46
+ * @param activities Optional standalone ActivityDefinition objects to check
47
+ * in addition to activities embedded in workflow definitions.
69
48
  */
70
- export declare function validateRegistrations(registrations: Record<string, WorkflowRegistration>, activities?: ActivityDefinition[]): ValidationReport;
49
+ export declare function validateRegistrations(registrations: Record<string, WorkflowDefinition>, activities?: ActivityDefinition[]): ValidationReport;
71
50
  export declare function loadRegistrationsFromModule(modulePath: string): Promise<{
72
- registrations: Record<string, WorkflowRegistration>;
51
+ registrations: Record<string, WorkflowDefinition>;
73
52
  activities: ActivityDefinition[];
74
53
  }>;
75
54
  /**