@cascade-flow/client 0.1.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 ADDED
@@ -0,0 +1,114 @@
1
+ # @cascadeflow/client
2
+
3
+ Type-safe programmatic client for submitting and managing workflow runs.
4
+
5
+ ## Installation
6
+
7
+ The client requires a backend implementation to persist workflow state. Install the client along with your chosen backend:
8
+
9
+ ### With Filesystem Backend (Recommended for Development)
10
+
11
+ ```bash
12
+ npm install @cascadeflow/client @cascadeflow/backend-filesystem
13
+ ```
14
+
15
+ ### With PostgreSQL Backend (Production)
16
+
17
+ ```bash
18
+ npm install @cascadeflow/client @cascadeflow/backend-postgres
19
+ ```
20
+
21
+ ## Usage
22
+
23
+ ```typescript
24
+ import { WorkflowClient } from "@cascadeflow/client";
25
+ import { FileSystemBackend } from "@cascadeflow/backend-filesystem";
26
+
27
+ const client = new WorkflowClient(new FileSystemBackend("./.runs"));
28
+
29
+ // Submit run
30
+ const { runId } = await client.submit({
31
+ workflow: "my-workflow",
32
+ input: { userId: "123", count: 42 },
33
+ priority: 10,
34
+ timeout: 300000
35
+ });
36
+
37
+ // Wait for completion
38
+ const output = await client.waitForCompletion(runId, {
39
+ timeout: 60000,
40
+ exponentialBackoff: true
41
+ });
42
+
43
+ // Check status
44
+ const info = await client.getRun(runId);
45
+
46
+ // Cancel
47
+ await client.cancel(runId, "reason");
48
+ ```
49
+
50
+ ## Type Safety
51
+
52
+ ```typescript
53
+ interface MyInput { userId: string; count: number; }
54
+ interface MyOutput { results: string[]; }
55
+
56
+ const { runId } = await client.submit<MyInput>({
57
+ workflow: "my-workflow",
58
+ input: { userId: "123", count: 42 } // Type-checked
59
+ });
60
+
61
+ const output = await client.waitForCompletion<MyOutput>(runId);
62
+ console.log(output.results); // Type-safe access
63
+ ```
64
+
65
+ ## Methods
66
+
67
+ ```typescript
68
+ // Submit run
69
+ submit<TInput>(params: {
70
+ workflow: string;
71
+ input?: TInput;
72
+ priority?: number;
73
+ timeout?: number;
74
+ idempotencyKey?: string;
75
+ metadata?: Record<string, unknown>;
76
+ tags?: string[];
77
+ }): Promise<{ runId: string; isNew: boolean }>;
78
+
79
+ // Get status
80
+ getStatus(runId: string): Promise<RunStatus>;
81
+
82
+ // Get detailed info
83
+ getRun(runId: string): Promise<RunState | null>;
84
+
85
+ // Wait for completion
86
+ waitForCompletion<TOutput>(runId: string, options?: {
87
+ interval?: number;
88
+ exponentialBackoff?: boolean;
89
+ maxBackoff?: number;
90
+ timeout?: number;
91
+ }): Promise<TOutput>;
92
+
93
+ // List runs
94
+ listRuns(options?: { status?: RunStatus; limit?: number }): Promise<RunState[]>;
95
+
96
+ // Cancel run
97
+ cancel(runId: string, reason?: string): Promise<void>;
98
+ ```
99
+
100
+ ## Timeouts
101
+
102
+ **3-tier fallback for step execution:**
103
+ 1. Step-level: `defineStep({ timeoutMs })`
104
+ 2. **Submission-level: `submit({ timeout })`** ← This package
105
+ 3. System default: 300000ms (5 min)
106
+
107
+ Submission timeout sets workflow-wide execution limit for steps without their own `timeoutMs`.
108
+
109
+ ## CLI Integration
110
+
111
+ Used internally by:
112
+ - `cf submit` → `client.submit()`
113
+ - `cf status` → `client.getRun()`
114
+ - `cf cancel` → `client.cancel()`
@@ -0,0 +1,613 @@
1
+ import type { Backend, RunState, WorkflowMetadata, AnalyticsOptions, ErrorAnalysis, RetryAnalysis, SchedulingLatency, StepDuration, WorkflowDuration, WorkerStability, Throughput, QueueDepth, QueueDepthByWorkflow, SuccessRate, AnalyticsSummary, StepEvent, StepState, LogEntry } from "@cascade-flow/backend-interface";
2
+ import { type AttemptMetadata } from "@cascade-flow/backend-interface";
3
+ import type { PollOptions, ListRunsOptions, RunInfo } from "./types.ts";
4
+ /**
5
+ * WorkflowClient - submit and manage workflow runs via queue
6
+ *
7
+ * Features:
8
+ * - Type-safe submission with generic input types
9
+ * - Status checking and polling
10
+ * - Wait for completion with timeout
11
+ * - List and filter runs
12
+ * - Cancellation support
13
+ */
14
+ export declare class WorkflowClient {
15
+ private backend;
16
+ constructor(backend: Backend);
17
+ /**
18
+ * Submit a workflow run to the queue
19
+ *
20
+ * Generic type TInput provides type safety for workflow input
21
+ *
22
+ * @example
23
+ * ```typescript
24
+ * import type { WorkflowInput } from './workflows/my-workflow/input-schema';
25
+ *
26
+ * const { runId } = await client.submit<WorkflowInput>({
27
+ * workflow: 'my-workflow',
28
+ * input: { userId: "123", count: 42 } // Fully typed!
29
+ * });
30
+ * ```
31
+ */
32
+ submit<TInput = unknown>(params: {
33
+ workflow: string;
34
+ input?: TInput;
35
+ runId?: string;
36
+ availableAt?: number;
37
+ priority?: number;
38
+ timeout?: number;
39
+ idempotencyKey?: string;
40
+ metadata?: Record<string, unknown>;
41
+ tags?: string[];
42
+ }): Promise<{
43
+ runId: string;
44
+ isNew: boolean;
45
+ }>;
46
+ /**
47
+ * Get the current status of a run
48
+ *
49
+ * @param runId - The run ID to query
50
+ * @returns Run state or null if not found
51
+ */
52
+ getStatus(runId: string): Promise<RunState | null>;
53
+ /**
54
+ * Get detailed run information including output/error
55
+ *
56
+ * @param runId - The run ID to query
57
+ * @returns Extended run info or null if not found
58
+ */
59
+ getRun(runId: string): Promise<RunInfo | null>;
60
+ /**
61
+ * Wait for a run to complete
62
+ *
63
+ * Polls the backend until the run reaches a terminal state (completed/failed/cancelled)
64
+ *
65
+ * @param runId - The run ID to wait for
66
+ * @param options - Polling options
67
+ * @returns Run info when complete
68
+ * @throws Error if timeout or run fails
69
+ */
70
+ waitForCompletion<TOutput = unknown>(runId: string, options?: PollOptions): Promise<TOutput>;
71
+ /**
72
+ * List runs matching filters
73
+ *
74
+ * @param options - Filter options
75
+ * @returns Array of run states
76
+ */
77
+ listRuns(options?: ListRunsOptions): Promise<RunState[]>;
78
+ /**
79
+ * Cancel a run
80
+ *
81
+ * Can cancel runs in pending, claimed, or running status
82
+ *
83
+ * @param runId - The run to cancel
84
+ * @param reason - Optional cancellation reason
85
+ */
86
+ cancel(runId: string, reason?: string): Promise<void>;
87
+ /**
88
+ * Retry a failed workflow
89
+ *
90
+ * Retries all failed steps in the workflow, keeping successful steps from the original run.
91
+ * Step attempt numbers are reset to 1 for each retried step.
92
+ *
93
+ * @param runId - The run ID to retry
94
+ * @param reason - Optional reason for retry
95
+ * @returns Retry information including new workflow attempt number
96
+ * @throws Error if run is not in failed status
97
+ */
98
+ retry(runId: string, reason?: string): Promise<{
99
+ runId: string;
100
+ workflowAttemptNumber: number;
101
+ retriedSteps: string[];
102
+ }>;
103
+ /**
104
+ * List all available workflows
105
+ *
106
+ * @returns Array of workflow metadata
107
+ */
108
+ listWorkflows(): Promise<WorkflowMetadata[]>;
109
+ /**
110
+ * Get metadata for a specific workflow
111
+ *
112
+ * @param workflowSlug - Workflow identifier (directory name)
113
+ * @returns Workflow metadata or null if not found
114
+ */
115
+ getWorkflowMetadata(workflowSlug: string): Promise<WorkflowMetadata | null>;
116
+ /**
117
+ * Get step definitions for a specific workflow
118
+ *
119
+ * @param workflowSlug - Workflow identifier (directory name)
120
+ * @returns Array of step definitions or empty array if workflow not found
121
+ */
122
+ getWorkflowSteps(workflowSlug: string): Promise<any[]>;
123
+ /**
124
+ * Get the JSON Schema for a workflow's input
125
+ *
126
+ * @param workflowSlug - Workflow identifier (directory name)
127
+ * @returns JSON Schema object or null if workflow has no input schema
128
+ */
129
+ getWorkflowSchema(workflowSlug: string): Promise<any | null>;
130
+ /**
131
+ * Helper to sleep
132
+ */
133
+ private sleep;
134
+ /**
135
+ * Get error analysis for workflows and steps
136
+ *
137
+ * Analyzes failure patterns, error types, and common error messages.
138
+ *
139
+ * @param options - Optional filters for time range, workflow, or step
140
+ * @returns Error analysis data
141
+ *
142
+ * @example
143
+ * ```typescript
144
+ * // Get errors for last 24 hours (default)
145
+ * const errors = await client.getErrorAnalysis();
146
+ *
147
+ * // Get errors for specific workflow
148
+ * const errors = await client.getErrorAnalysis({
149
+ * workflowSlug: 'my-workflow',
150
+ * startUs: Date.now() * 1000 - 7 * 24 * 60 * 60 * 1000 * 1000 // Last 7 days
151
+ * });
152
+ * ```
153
+ */
154
+ getErrorAnalysis(options?: AnalyticsOptions): Promise<ErrorAnalysis>;
155
+ /**
156
+ * Get retry analysis metrics
157
+ *
158
+ * Analyzes retry patterns, success rates after retries, and retry effectiveness.
159
+ *
160
+ * @param options - Optional filters for time range, workflow, or step
161
+ * @returns Retry analysis data
162
+ */
163
+ getRetryAnalysis(options?: AnalyticsOptions): Promise<RetryAnalysis>;
164
+ /**
165
+ * Get scheduling latency metrics
166
+ *
167
+ * Measures time between step being scheduled and actually starting execution.
168
+ * High latency indicates worker starvation or queue congestion.
169
+ *
170
+ * @param options - Optional filters for time range, workflow, or step
171
+ * @returns Scheduling latency statistics
172
+ *
173
+ * @example
174
+ * ```typescript
175
+ * const latency = await client.getSchedulingLatency({ workflowSlug: 'my-workflow' });
176
+ * console.log(`Average wait time: ${latency.averageUs / 1000}ms`);
177
+ * console.log(`P95 wait time: ${latency.p95Us / 1000}ms`);
178
+ * ```
179
+ */
180
+ getSchedulingLatency(options?: AnalyticsOptions): Promise<SchedulingLatency>;
181
+ /**
182
+ * Get step duration metrics
183
+ *
184
+ * Analyzes how long steps take to execute.
185
+ *
186
+ * @param options - Optional filters for time range, workflow, or step
187
+ * @returns Step duration statistics
188
+ */
189
+ getStepDuration(options?: AnalyticsOptions): Promise<StepDuration>;
190
+ /**
191
+ * Get workflow duration metrics
192
+ *
193
+ * Analyzes end-to-end workflow execution time (from submission to completion).
194
+ *
195
+ * @param options - Optional filters for time range or workflow
196
+ * @returns Workflow duration statistics
197
+ */
198
+ getWorkflowDuration(options?: AnalyticsOptions): Promise<WorkflowDuration>;
199
+ /**
200
+ * Get worker stability metrics
201
+ *
202
+ * Analyzes worker crashes, reclamations, and stale heartbeats.
203
+ *
204
+ * @param options - Optional filters for time range
205
+ * @returns Worker stability data
206
+ */
207
+ getWorkerStability(options?: AnalyticsOptions): Promise<WorkerStability>;
208
+ /**
209
+ * Get throughput metrics
210
+ *
211
+ * Analyzes how many runs/steps are being completed per unit time.
212
+ *
213
+ * @param options - Optional filters for time range or workflow
214
+ * @returns Throughput data
215
+ */
216
+ getThroughput(options?: AnalyticsOptions): Promise<Throughput>;
217
+ /**
218
+ * Get current queue depth
219
+ *
220
+ * Real-time snapshot of pending/running runs and steps.
221
+ *
222
+ * @param options - Optional filter for workflow
223
+ * @returns Queue depth data
224
+ *
225
+ * @example
226
+ * ```typescript
227
+ * const depth = await client.getQueueDepth();
228
+ * console.log(`Pending runs: ${depth.pendingRuns}`);
229
+ * console.log(`Scheduled steps: ${depth.scheduledSteps}`);
230
+ * ```
231
+ */
232
+ getQueueDepth(options?: Pick<AnalyticsOptions, "workflowSlug">): Promise<QueueDepth>;
233
+ /**
234
+ * Get queue depth broken down by workflow
235
+ *
236
+ * Real-time snapshot showing per-workflow queue statistics.
237
+ * Useful for identifying which workflows have pending work.
238
+ *
239
+ * @returns Array of per-workflow queue depth data
240
+ *
241
+ * @example
242
+ * ```typescript
243
+ * const breakdown = await client.getQueueDepthByWorkflow();
244
+ * for (const workflow of breakdown) {
245
+ * console.log(`${workflow.workflowName}: ${workflow.pendingRuns} pending, ${workflow.scheduledSteps} scheduled`);
246
+ * }
247
+ * ```
248
+ */
249
+ getQueueDepthByWorkflow(): Promise<QueueDepthByWorkflow>;
250
+ /**
251
+ * Get success/failure rate metrics
252
+ *
253
+ * Analyzes overall health of workflows and steps.
254
+ *
255
+ * @param options - Optional filters for time range, workflow, or step
256
+ * @returns Success rate data
257
+ */
258
+ getSuccessRate(options?: AnalyticsOptions): Promise<SuccessRate>;
259
+ /**
260
+ * Get comprehensive analytics summary
261
+ *
262
+ * Combines all analytics metrics into a single response.
263
+ * Useful for dashboard views.
264
+ *
265
+ * @param options - Optional filters for time range or workflow
266
+ * @returns Complete analytics summary
267
+ *
268
+ * @example
269
+ * ```typescript
270
+ * // Get full analytics for last 24 hours
271
+ * const summary = await client.getAnalyticsSummary();
272
+ *
273
+ * // Get analytics for specific workflow over last week
274
+ * const summary = await client.getAnalyticsSummary({
275
+ * workflowSlug: 'my-workflow',
276
+ * startUs: Date.now() * 1000 - 7 * 24 * 60 * 60 * 1000 * 1000
277
+ * });
278
+ * ```
279
+ */
280
+ getAnalyticsSummary(options?: AnalyticsOptions): Promise<AnalyticsSummary>;
281
+ /**
282
+ * Get paginated list of errors grouped by fingerprint
283
+ *
284
+ * @param options - Filtering and pagination options
285
+ * @returns Paginated list of error groups
286
+ *
287
+ * @example
288
+ * ```typescript
289
+ * // Get errors for last 24h
290
+ * const { errors, total } = await client.getErrorsList({
291
+ * timeRange: { start: Date.now() * 1000 - 86400000000, end: Date.now() * 1000 },
292
+ * groupingStrategy: 'exact',
293
+ * limit: 50,
294
+ * offset: 0
295
+ * });
296
+ * ```
297
+ */
298
+ getErrorsList(options?: {
299
+ timeRange?: {
300
+ start: number;
301
+ end: number;
302
+ };
303
+ workflowSlug?: string;
304
+ groupingStrategy?: 'exact' | 'normalized' | 'portable';
305
+ limit?: number;
306
+ offset?: number;
307
+ }): Promise<{
308
+ errors: Array<{
309
+ fingerprint: string;
310
+ errorMessage: string;
311
+ errorName: string;
312
+ sampleStack: string;
313
+ count: number;
314
+ affectedRuns: number;
315
+ firstSeen: number;
316
+ lastSeen: number;
317
+ }>;
318
+ total: number;
319
+ }>;
320
+ /**
321
+ * Get detailed information about a specific error by fingerprint
322
+ *
323
+ * @param fingerprint - Composite fingerprint (nameHash:messageHash:stackHash)
324
+ * @param groupingStrategy - Which stack hash variant to use
325
+ * @param options - Filtering and pagination options
326
+ * @returns Error details with all occurrences
327
+ *
328
+ * @example
329
+ * ```typescript
330
+ * const detail = await client.getErrorDetail(
331
+ * 'abc123:def456:ghi789',
332
+ * 'exact',
333
+ * { limit: 100, offset: 0 }
334
+ * );
335
+ * ```
336
+ */
337
+ getErrorDetail(fingerprint: string, groupingStrategy: 'exact' | 'normalized' | 'portable', options?: {
338
+ timeRange?: {
339
+ start: number;
340
+ end: number;
341
+ };
342
+ limit?: number;
343
+ offset?: number;
344
+ }): Promise<{
345
+ fingerprint: string;
346
+ errorMessage: string;
347
+ errorName: string;
348
+ sampleStack: string;
349
+ totalCount: number;
350
+ affectedRuns: number;
351
+ firstSeen: number;
352
+ lastSeen: number;
353
+ occurrences: Array<{
354
+ workflowSlug: string;
355
+ runId: string;
356
+ stepId: string;
357
+ attemptNumber: number;
358
+ timestampUs: number;
359
+ }>;
360
+ total: number;
361
+ }>;
362
+ /**
363
+ * Get the state of all steps for a run
364
+ * Projects step events to compute current state
365
+ */
366
+ getStepStates(workflowSlug: string, runId: string): Promise<StepState[]>;
367
+ /**
368
+ * Get all events for a specific run (both workflow and step events)
369
+ */
370
+ getRunEvents(workflowSlug: string, runId: string): Promise<({
371
+ eventId: string;
372
+ timestampUs: number;
373
+ workflowSlug: string;
374
+ runId: string;
375
+ category: "step";
376
+ stepId: string;
377
+ type: "StepStarted";
378
+ workerId: string;
379
+ dependencies: string[];
380
+ attemptNumber: number;
381
+ } | {
382
+ eventId: string;
383
+ timestampUs: number;
384
+ workflowSlug: string;
385
+ runId: string;
386
+ category: "step";
387
+ stepId: string;
388
+ type: "StepCompleted";
389
+ output: string;
390
+ durationUs: number;
391
+ attemptNumber: number;
392
+ exportOutput: boolean;
393
+ } | {
394
+ eventId: string;
395
+ timestampUs: number;
396
+ workflowSlug: string;
397
+ runId: string;
398
+ category: "step";
399
+ stepId: string;
400
+ type: "StepFailed";
401
+ error: {
402
+ message: string;
403
+ stack?: string | undefined;
404
+ name?: string | undefined;
405
+ };
406
+ errorFingerprints: {
407
+ nameHash: string;
408
+ messageHash: string;
409
+ stackExactHash: string;
410
+ stackNormalizedHash: string;
411
+ stackPortableHash: string;
412
+ };
413
+ durationUs: number;
414
+ attemptNumber: number;
415
+ terminal: boolean;
416
+ failureReason: "timeout" | "cancelled" | "worker-crash" | "exhausted-retries" | "execution-error";
417
+ nextRetryAtUs?: number | undefined;
418
+ } | {
419
+ eventId: string;
420
+ timestampUs: number;
421
+ workflowSlug: string;
422
+ runId: string;
423
+ category: "step";
424
+ stepId: string;
425
+ type: "LogEntry";
426
+ stream: "stdout" | "stderr";
427
+ message: string;
428
+ attemptNumber: number;
429
+ } | {
430
+ eventId: string;
431
+ timestampUs: number;
432
+ workflowSlug: string;
433
+ runId: string;
434
+ category: "step";
435
+ stepId: string;
436
+ type: "StepRetrying";
437
+ attemptNumber: number;
438
+ nextAttempt: number;
439
+ error: {
440
+ message: string;
441
+ stack?: string | undefined;
442
+ name?: string | undefined;
443
+ };
444
+ maxRetries: number;
445
+ } | {
446
+ eventId: string;
447
+ timestampUs: number;
448
+ workflowSlug: string;
449
+ runId: string;
450
+ category: "step";
451
+ stepId: string;
452
+ type: "StepScheduled";
453
+ availableAtUs: number;
454
+ reason: "retry" | "initial" | "dependency-satisfied";
455
+ attemptNumber: number;
456
+ retryDelayMs?: number | undefined;
457
+ } | {
458
+ eventId: string;
459
+ workflowSlug: string;
460
+ runId: string;
461
+ category: "step";
462
+ stepId: string;
463
+ type: "StepHeartbeat";
464
+ workerId: string;
465
+ timestampUs: number;
466
+ attemptNumber: number;
467
+ } | {
468
+ eventId: string;
469
+ timestampUs: number;
470
+ workflowSlug: string;
471
+ runId: string;
472
+ category: "step";
473
+ stepId: string;
474
+ type: "StepReclaimed";
475
+ originalWorkerId: string;
476
+ reclaimedBy: string;
477
+ lastHeartbeatUs: number;
478
+ staleThresholdUs: number;
479
+ staleDurationUs: number;
480
+ attemptNumber: number;
481
+ } | {
482
+ eventId: string;
483
+ timestampUs: number;
484
+ workflowSlug: string;
485
+ runId: string;
486
+ category: "step";
487
+ stepId: string;
488
+ type: "StepSkipped";
489
+ skipType: "primary" | "cascade";
490
+ reason: string;
491
+ durationUs: number;
492
+ attemptNumber: number;
493
+ metadata?: Record<string, any> | undefined;
494
+ cascadedFrom?: string | undefined;
495
+ } | {
496
+ eventId: string;
497
+ timestampUs: number;
498
+ workflowSlug: string;
499
+ runId: string;
500
+ category: "workflow";
501
+ type: "RunSubmitted";
502
+ availableAtUs: number;
503
+ priority: number;
504
+ hasInputSchema: boolean;
505
+ input?: string | undefined;
506
+ timeoutUs?: number | undefined;
507
+ idempotencyKey?: string | undefined;
508
+ metadata?: Record<string, any> | undefined;
509
+ tags?: string[] | undefined;
510
+ } | {
511
+ eventId: string;
512
+ timestampUs: number;
513
+ workflowSlug: string;
514
+ runId: string;
515
+ category: "workflow";
516
+ type: "WorkflowStarted";
517
+ workflowAttemptNumber: number;
518
+ hasInputSchema: boolean;
519
+ hasInput: boolean;
520
+ } | {
521
+ eventId: string;
522
+ timestampUs: number;
523
+ workflowSlug: string;
524
+ runId: string;
525
+ category: "workflow";
526
+ type: "WorkflowInputValidation";
527
+ workflowAttemptNumber: number;
528
+ hasSchema: boolean;
529
+ success: boolean;
530
+ error?: {
531
+ message: string;
532
+ stack?: string | undefined;
533
+ name?: string | undefined;
534
+ } | undefined;
535
+ validationErrors?: {
536
+ path: string;
537
+ message: string;
538
+ }[] | undefined;
539
+ } | {
540
+ eventId: string;
541
+ timestampUs: number;
542
+ workflowSlug: string;
543
+ runId: string;
544
+ category: "workflow";
545
+ type: "WorkflowCompleted";
546
+ workflowAttemptNumber: number;
547
+ output: string;
548
+ durationUs: number;
549
+ totalSteps: number;
550
+ } | {
551
+ eventId: string;
552
+ timestampUs: number;
553
+ workflowSlug: string;
554
+ runId: string;
555
+ category: "workflow";
556
+ type: "WorkflowFailed";
557
+ workflowAttemptNumber: number;
558
+ error: {
559
+ message: string;
560
+ stack?: string | undefined;
561
+ name?: string | undefined;
562
+ };
563
+ durationUs: number;
564
+ completedSteps: number;
565
+ failureReason: "timeout" | "cancelled" | "worker-crash" | "step-failed";
566
+ failedStep?: string | undefined;
567
+ } | {
568
+ eventId: string;
569
+ timestampUs: number;
570
+ workflowSlug: string;
571
+ runId: string;
572
+ category: "workflow";
573
+ type: "WorkflowResumed";
574
+ originalRunId: string;
575
+ resumedSteps: number;
576
+ pendingSteps: number;
577
+ } | {
578
+ eventId: string;
579
+ timestampUs: number;
580
+ workflowSlug: string;
581
+ runId: string;
582
+ category: "workflow";
583
+ type: "WorkflowCancelled";
584
+ workflowAttemptNumber: number;
585
+ durationUs: number;
586
+ completedSteps: number;
587
+ reason?: string | undefined;
588
+ } | {
589
+ eventId: string;
590
+ timestampUs: number;
591
+ workflowSlug: string;
592
+ runId: string;
593
+ category: "workflow";
594
+ type: "WorkflowRetryStarted";
595
+ workflowAttemptNumber: number;
596
+ previousAttemptNumber: number;
597
+ retriedSteps: string[];
598
+ reason?: string | undefined;
599
+ })[]>;
600
+ /**
601
+ * Get detailed information for a specific step
602
+ * Includes state, events, and logs
603
+ */
604
+ getStepDetail(workflowSlug: string, runId: string, stepName: string): Promise<{
605
+ state: StepState;
606
+ events: StepEvent[];
607
+ logs: LogEntry[];
608
+ attempts: AttemptMetadata[];
609
+ } | null>;
610
+ }
611
+ export type { PollOptions, ListRunsOptions, RunInfo } from "./types.ts";
612
+ export type { AnalyticsOptions, ErrorAnalysis, RetryAnalysis, SchedulingLatency, StepDuration, WorkflowDuration, WorkerStability, Throughput, QueueDepth, QueueDepthByWorkflow, SuccessRate, AnalyticsSummary, } from "@cascade-flow/backend-interface";
613
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,OAAO,EAEP,QAAQ,EACR,gBAAgB,EAChB,gBAAgB,EAChB,aAAa,EACb,aAAa,EACb,iBAAiB,EACjB,YAAY,EACZ,gBAAgB,EAChB,eAAe,EACf,UAAU,EACV,UAAU,EACV,oBAAoB,EACpB,WAAW,EACX,gBAAgB,EAChB,SAAS,EACT,SAAS,EACT,QAAQ,EACT,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAIL,KAAK,eAAe,EACrB,MAAM,iCAAiC,CAAC;AACzC,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAExE;;;;;;;;;GASG;AACH,qBAAa,cAAc;IACb,OAAO,CAAC,OAAO;gBAAP,OAAO,EAAE,OAAO;IAEpC;;;;;;;;;;;;;;OAcG;IACG,MAAM,CAAC,MAAM,GAAG,OAAO,EAAE,MAAM,EAAE;QACrC,QAAQ,EAAE,MAAM,CAAC;QACjB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,cAAc,CAAC,EAAE,MAAM,CAAC;QACxB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QACnC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;KACjB,GAAG,OAAO,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,OAAO,CAAA;KAAE,CAAC;IAgB9C;;;;;OAKG;IACG,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC;IAIxD;;;;;OAKG;IACG,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC;IAgCpD;;;;;;;;;OASG;IACG,iBAAiB,CAAC,OAAO,GAAG,OAAO,EACvC,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,WAAgB,GACxB,OAAO,CAAC,OAAO,CAAC;IAkDnB;;;;;OAKG;IACG,QAAQ,CAAC,OAAO,GAAE,eAAoB,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC;IAiBlE;;;;;;;OAOG;IACG,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAI3D;;;;;;;;;;OAUG;IACG,KAAK,CACT,KAAK,EAAE,MAAM,EACb,MAAM,CAAC,EAAE,MAAM,GACd,OAAO,CAAC;QACT,KAAK,EAAE,MAAM,CAAC;QACd,qBAAqB,EAAE,MAAM,CAAC;QAC9B,YAAY,EAAE,MAAM,EAAE,CAAC;KACxB,CAAC;IAoDF;;;;OAIG;IACG,aAAa,IAAI,OAAO,CAAC,gBAAgB,EAAE,CAAC;IAIlD;;;;;OAKG;IACG,mBAAmB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC;IAIjF;;;;;OAKG;IACG,gBAAgB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;IAI5D;;;;;OAKG;IACG,iBAAiB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,GAAG,IAAI,CAAC;IAKlE;;OAEG;IACH,OAAO,CAAC,KAAK;IAQb;;;;;;;;;;;;;;;;;;;OAmBG;IACG,gBAAgB,CAAC,OAAO,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,aAAa,CAAC;IAI1E;;;;;;;OAOG;IACG,gBAAgB,CAAC,OAAO,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,aAAa,CAAC;IAI1E;;;;;;;;;;;;;;;OAeG;IACG,oBAAoB,CAAC,OAAO,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAIlF;;;;;;;OAOG;IACG,eAAe,CAAC,OAAO,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,YAAY,CAAC;IAIxE;;;;;;;OAOG;IACG,mBAAmB,CAAC,OAAO,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAIhF;;;;;;;OAOG;IACG,kBAAkB,CAAC,OAAO,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,eAAe,CAAC;IAI9E;;;;;;;OAOG;IACG,aAAa,CAAC,OAAO,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,UAAU,CAAC;IAIpE;;;;;;;;;;;;;;OAcG;IACG,aAAa,CAAC,OAAO,CAAC,EAAE,IAAI,CAAC,gBAAgB,EAAE,cAAc,CAAC,GAAG,OAAO,CAAC,UAAU,CAAC;IAI1F;;;;;;;;;;;;;;;OAeG;IACG,uBAAuB,IAAI,OAAO,CAAC,oBAAoB,CAAC;IAI9D;;;;;;;OAOG;IACG,cAAc,CAAC,OAAO,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,WAAW,CAAC;IAItE;;;;;;;;;;;;;;;;;;;;OAoBG;IACG,mBAAmB,CAAC,OAAO,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAIhF;;;;;;;;;;;;;;;;OAgBG;IACG,aAAa,CAAC,OAAO,CAAC,EAAE;QAC5B,SAAS,CAAC,EAAE;YAAE,KAAK,EAAE,MAAM,CAAC;YAAC,GAAG,EAAE,MAAM,CAAA;SAAE,CAAC;QAC3C,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,gBAAgB,CAAC,EAAE,OAAO,GAAG,YAAY,GAAG,UAAU,CAAC;QACvD,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,MAAM,CAAC,EAAE,MAAM,CAAC;KACjB,GAAG,OAAO,CAAC;QACV,MAAM,EAAE,KAAK,CAAC;YACZ,WAAW,EAAE,MAAM,CAAC;YACpB,YAAY,EAAE,MAAM,CAAC;YACrB,SAAS,EAAE,MAAM,CAAC;YAClB,WAAW,EAAE,MAAM,CAAC;YACpB,KAAK,EAAE,MAAM,CAAC;YACd,YAAY,EAAE,MAAM,CAAC;YACrB,SAAS,EAAE,MAAM,CAAC;YAClB,QAAQ,EAAE,MAAM,CAAC;SAClB,CAAC,CAAC;QACH,KAAK,EAAE,MAAM,CAAC;KACf,CAAC;IAIF;;;;;;;;;;;;;;;;OAgBG;IACG,cAAc,CAClB,WAAW,EAAE,MAAM,EACnB,gBAAgB,EAAE,OAAO,GAAG,YAAY,GAAG,UAAU,EACrD,OAAO,CAAC,EAAE;QACR,SAAS,CAAC,EAAE;YAAE,KAAK,EAAE,MAAM,CAAC;YAAC,GAAG,EAAE,MAAM,CAAA;SAAE,CAAC;QAC3C,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,MAAM,CAAC,EAAE,MAAM,CAAC;KACjB,GACA,OAAO,CAAC;QACT,WAAW,EAAE,MAAM,CAAC;QACpB,YAAY,EAAE,MAAM,CAAC;QACrB,SAAS,EAAE,MAAM,CAAC;QAClB,WAAW,EAAE,MAAM,CAAC;QACpB,UAAU,EAAE,MAAM,CAAC;QACnB,YAAY,EAAE,MAAM,CAAC;QACrB,SAAS,EAAE,MAAM,CAAC;QAClB,QAAQ,EAAE,MAAM,CAAC;QACjB,WAAW,EAAE,KAAK,CAAC;YACjB,YAAY,EAAE,MAAM,CAAC;YACrB,KAAK,EAAE,MAAM,CAAC;YACd,MAAM,EAAE,MAAM,CAAC;YACf,aAAa,EAAE,MAAM,CAAC;YACtB,WAAW,EAAE,MAAM,CAAC;SACrB,CAAC,CAAC;QACH,KAAK,EAAE,MAAM,CAAC;KACf,CAAC;IAIF;;;OAGG;IACG,aAAa,CAAC,YAAY,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;IA8B9E;;OAEG;IACG,YAAY,CAAC,YAAY,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAItD;;;OAGG;IACG,aAAa,CACjB,YAAY,EAAE,MAAM,EACpB,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC;QACT,KAAK,EAAE,SAAS,CAAC;QACjB,MAAM,EAAE,SAAS,EAAE,CAAC;QACpB,IAAI,EAAE,QAAQ,EAAE,CAAC;QACjB,QAAQ,EAAE,eAAe,EAAE,CAAC;KAC7B,GAAG,IAAI,CAAC;CA8BV;AAGD,YAAY,EAAE,WAAW,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AACxE,YAAY,EACV,gBAAgB,EAChB,aAAa,EACb,aAAa,EACb,iBAAiB,EACjB,YAAY,EACZ,gBAAgB,EAChB,eAAe,EACf,UAAU,EACV,UAAU,EACV,oBAAoB,EACpB,WAAW,EACX,gBAAgB,GACjB,MAAM,iCAAiC,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,247 @@
1
+ // src/index.ts
2
+ import {
3
+ projectStepState,
4
+ extractLogsFromEvents,
5
+ extractAttemptMetadata
6
+ } from "@cascade-flow/backend-interface";
7
+
8
+ class WorkflowClient {
9
+ backend;
10
+ constructor(backend) {
11
+ this.backend = backend;
12
+ }
13
+ async submit(params) {
14
+ const submission = {
15
+ workflowSlug: params.workflow,
16
+ input: params.input,
17
+ runId: params.runId,
18
+ availableAt: params.availableAt,
19
+ priority: params.priority,
20
+ timeout: params.timeout,
21
+ idempotencyKey: params.idempotencyKey,
22
+ metadata: params.metadata,
23
+ tags: params.tags
24
+ };
25
+ return this.backend.submitRun(submission);
26
+ }
27
+ async getStatus(runId) {
28
+ return this.backend.getRun(runId);
29
+ }
30
+ async getRun(runId) {
31
+ const runState = await this.backend.getRun(runId);
32
+ if (!runState)
33
+ return null;
34
+ const info = { ...runState };
35
+ if (runState.status === "completed" || runState.status === "failed") {
36
+ try {
37
+ const events = await this.backend.loadEvents(runState.workflowSlug, runId, {
38
+ category: "workflow"
39
+ });
40
+ for (const event of events) {
41
+ if (event.category === "workflow") {
42
+ if (event.type === "WorkflowCompleted") {
43
+ info.output = JSON.parse(event.output);
44
+ } else if (event.type === "WorkflowFailed") {
45
+ info.error = event.error;
46
+ }
47
+ }
48
+ }
49
+ } catch (err) {}
50
+ }
51
+ return info;
52
+ }
53
+ async waitForCompletion(runId, options = {}) {
54
+ const {
55
+ interval = 1000,
56
+ maxAttempts = 60,
57
+ timeout,
58
+ exponentialBackoff = false,
59
+ maxBackoff = 1e4
60
+ } = options;
61
+ const startTime = Date.now();
62
+ const effectiveTimeout = timeout || maxAttempts * interval;
63
+ let currentInterval = interval;
64
+ let attempts = 0;
65
+ while (true) {
66
+ attempts++;
67
+ if (Date.now() - startTime > effectiveTimeout) {
68
+ throw new Error(`Timeout waiting for run ${runId} after ${effectiveTimeout}ms`);
69
+ }
70
+ const run = await this.getRun(runId);
71
+ if (!run) {
72
+ throw new Error(`Run ${runId} not found`);
73
+ }
74
+ if (run.status === "completed") {
75
+ return run.output;
76
+ } else if (run.status === "failed") {
77
+ const errorMsg = run.error?.message || "Run failed";
78
+ throw new Error(`Run ${runId} failed: ${errorMsg}`);
79
+ } else if (run.status === "cancelled") {
80
+ throw new Error(`Run ${runId} was cancelled`);
81
+ }
82
+ await this.sleep(currentInterval);
83
+ if (exponentialBackoff) {
84
+ currentInterval = Math.min(currentInterval * 2, maxBackoff);
85
+ }
86
+ }
87
+ }
88
+ async listRuns(options = {}) {
89
+ const { workflowSlug, status, tags, limit } = options;
90
+ let statuses;
91
+ if (status) {
92
+ statuses = Array.isArray(status) ? status : [status];
93
+ }
94
+ return this.backend.listRuns({
95
+ workflowSlug,
96
+ status: statuses,
97
+ tags,
98
+ limit
99
+ });
100
+ }
101
+ async cancel(runId, reason) {
102
+ await this.backend.cancelRun(runId, reason);
103
+ }
104
+ async retry(runId, reason) {
105
+ const runState = await this.backend.getRun(runId);
106
+ if (!runState) {
107
+ throw new Error(`Run ${runId} not found`);
108
+ }
109
+ if (runState.status !== "failed") {
110
+ throw new Error(`Cannot retry run ${runId} - status is ${runState.status}, expected 'failed'`);
111
+ }
112
+ const workflowSlug = runState.workflowSlug;
113
+ const failedSteps = await this.backend.getFailedSteps(workflowSlug, runId);
114
+ if (failedSteps.length === 0) {
115
+ throw new Error(`No failed steps found in run ${runId}`);
116
+ }
117
+ const previousAttemptNumber = runState.workflowAttemptNumber || 1;
118
+ const workflowAttemptNumber = previousAttemptNumber + 1;
119
+ const retriedStepIds = failedSteps.map((s) => s.stepId);
120
+ await this.backend.saveWorkflowRetryStarted(workflowSlug, runId, {
121
+ workflowAttemptNumber,
122
+ previousAttemptNumber,
123
+ retriedSteps: retriedStepIds,
124
+ reason
125
+ });
126
+ const now = Date.now() * 1000;
127
+ for (const step of failedSteps) {
128
+ await this.backend.saveStepScheduled(workflowSlug, runId, step.stepId, {
129
+ availableAt: now,
130
+ reason: "retry",
131
+ attemptNumber: 1,
132
+ retryDelayMs: 0
133
+ });
134
+ }
135
+ return {
136
+ runId,
137
+ workflowAttemptNumber,
138
+ retriedSteps: retriedStepIds
139
+ };
140
+ }
141
+ async listWorkflows() {
142
+ return this.backend.listWorkflowMetadata();
143
+ }
144
+ async getWorkflowMetadata(workflowSlug) {
145
+ return this.backend.getWorkflowMetadata(workflowSlug);
146
+ }
147
+ async getWorkflowSteps(workflowSlug) {
148
+ return this.backend.getWorkflowSteps(workflowSlug);
149
+ }
150
+ async getWorkflowSchema(workflowSlug) {
151
+ const metadata = await this.backend.getWorkflowMetadata(workflowSlug);
152
+ return metadata?.inputSchemaJSON ?? null;
153
+ }
154
+ sleep(ms) {
155
+ return new Promise((resolve) => setTimeout(resolve, ms));
156
+ }
157
+ async getErrorAnalysis(options) {
158
+ return this.backend.getErrorAnalysis(options);
159
+ }
160
+ async getRetryAnalysis(options) {
161
+ return this.backend.getRetryAnalysis(options);
162
+ }
163
+ async getSchedulingLatency(options) {
164
+ return this.backend.getSchedulingLatency(options);
165
+ }
166
+ async getStepDuration(options) {
167
+ return this.backend.getStepDuration(options);
168
+ }
169
+ async getWorkflowDuration(options) {
170
+ return this.backend.getWorkflowDuration(options);
171
+ }
172
+ async getWorkerStability(options) {
173
+ return this.backend.getWorkerStability(options);
174
+ }
175
+ async getThroughput(options) {
176
+ return this.backend.getThroughput(options);
177
+ }
178
+ async getQueueDepth(options) {
179
+ return this.backend.getQueueDepth(options);
180
+ }
181
+ async getQueueDepthByWorkflow() {
182
+ return this.backend.getQueueDepthByWorkflow();
183
+ }
184
+ async getSuccessRate(options) {
185
+ return this.backend.getSuccessRate(options);
186
+ }
187
+ async getAnalyticsSummary(options) {
188
+ return this.backend.getAnalyticsSummary(options);
189
+ }
190
+ async getErrorsList(options) {
191
+ return this.backend.getErrorsList(options);
192
+ }
193
+ async getErrorDetail(fingerprint, groupingStrategy, options) {
194
+ return this.backend.getErrorDetail(fingerprint, groupingStrategy, options);
195
+ }
196
+ async getStepStates(workflowSlug, runId) {
197
+ const events = await this.backend.loadEvents(workflowSlug, runId, {
198
+ category: "step"
199
+ });
200
+ const stepGroups = new Map;
201
+ for (const event of events) {
202
+ if (event.category === "step") {
203
+ if (!stepGroups.has(event.stepId)) {
204
+ stepGroups.set(event.stepId, []);
205
+ }
206
+ stepGroups.get(event.stepId).push(event);
207
+ }
208
+ }
209
+ const states = [];
210
+ for (const [stepId, stepEvents] of stepGroups) {
211
+ try {
212
+ const state = projectStepState(stepEvents, workflowSlug);
213
+ states.push(state);
214
+ } catch (err) {
215
+ console.error(`Failed to project state for step ${stepId}:`, err);
216
+ }
217
+ }
218
+ return states;
219
+ }
220
+ async getRunEvents(workflowSlug, runId) {
221
+ return this.backend.loadEvents(workflowSlug, runId);
222
+ }
223
+ async getStepDetail(workflowSlug, runId, stepName) {
224
+ const events = await this.backend.loadEvents(workflowSlug, runId, {
225
+ category: "step",
226
+ stepId: stepName
227
+ });
228
+ const stepEvents = events.filter((e) => e.category === "step");
229
+ if (stepEvents.length === 0) {
230
+ return null;
231
+ }
232
+ const state = projectStepState(stepEvents, workflowSlug);
233
+ const logs = extractLogsFromEvents(stepEvents);
234
+ const attempts = extractAttemptMetadata(stepEvents);
235
+ return {
236
+ state,
237
+ events: stepEvents,
238
+ logs,
239
+ attempts
240
+ };
241
+ }
242
+ }
243
+ export {
244
+ WorkflowClient
245
+ };
246
+
247
+ //# debugId=092C4E0F5E8FB25364756E2164756E21
@@ -0,0 +1,10 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/index.ts"],
4
+ "sourcesContent": [
5
+ "import type {\n Backend,\n RunSubmission,\n RunState,\n WorkflowMetadata,\n AnalyticsOptions,\n ErrorAnalysis,\n RetryAnalysis,\n SchedulingLatency,\n StepDuration,\n WorkflowDuration,\n WorkerStability,\n Throughput,\n QueueDepth,\n QueueDepthByWorkflow,\n SuccessRate,\n AnalyticsSummary,\n StepEvent,\n StepState,\n LogEntry,\n} from \"@cascade-flow/backend-interface\";\nimport {\n projectStepState,\n extractLogsFromEvents,\n extractAttemptMetadata,\n type AttemptMetadata,\n} from \"@cascade-flow/backend-interface\";\nimport type { PollOptions, ListRunsOptions, RunInfo } from \"./types.ts\";\n\n/**\n * WorkflowClient - submit and manage workflow runs via queue\n *\n * Features:\n * - Type-safe submission with generic input types\n * - Status checking and polling\n * - Wait for completion with timeout\n * - List and filter runs\n * - Cancellation support\n */\nexport class WorkflowClient {\n constructor(private backend: Backend) {}\n\n /**\n * Submit a workflow run to the queue\n *\n * Generic type TInput provides type safety for workflow input\n *\n * @example\n * ```typescript\n * import type { WorkflowInput } from './workflows/my-workflow/input-schema';\n *\n * const { runId } = await client.submit<WorkflowInput>({\n * workflow: 'my-workflow',\n * input: { userId: \"123\", count: 42 } // Fully typed!\n * });\n * ```\n */\n async submit<TInput = unknown>(params: {\n workflow: string;\n input?: TInput;\n runId?: string;\n availableAt?: number;\n priority?: number;\n timeout?: number;\n idempotencyKey?: string;\n metadata?: Record<string, unknown>;\n tags?: string[];\n }): Promise<{ runId: string; isNew: boolean }> {\n const submission: RunSubmission = {\n workflowSlug: params.workflow,\n input: params.input,\n runId: params.runId,\n availableAt: params.availableAt,\n priority: params.priority,\n timeout: params.timeout,\n idempotencyKey: params.idempotencyKey,\n metadata: params.metadata,\n tags: params.tags,\n };\n\n return this.backend.submitRun(submission);\n }\n\n /**\n * Get the current status of a run\n *\n * @param runId - The run ID to query\n * @returns Run state or null if not found\n */\n async getStatus(runId: string): Promise<RunState | null> {\n return this.backend.getRun(runId);\n }\n\n /**\n * Get detailed run information including output/error\n *\n * @param runId - The run ID to query\n * @returns Extended run info or null if not found\n */\n async getRun(runId: string): Promise<RunInfo | null> {\n const runState = await this.backend.getRun(runId);\n if (!runState) return null;\n\n const info: RunInfo = { ...runState };\n\n // Load output or error if run is completed/failed\n if (runState.status === \"completed\" || runState.status === \"failed\") {\n try {\n // Load workflow events to get output/error\n const events = await this.backend.loadEvents(runState.workflowSlug, runId, {\n category: \"workflow\",\n });\n\n // Find WorkflowCompleted or WorkflowFailed event\n for (const event of events) {\n if (event.category === \"workflow\") {\n if (event.type === \"WorkflowCompleted\") {\n info.output = JSON.parse(event.output);\n } else if (event.type === \"WorkflowFailed\") {\n info.error = event.error;\n }\n }\n }\n } catch (err) {\n // Failed to load output/error, return state only\n }\n }\n\n return info;\n }\n\n /**\n * Wait for a run to complete\n *\n * Polls the backend until the run reaches a terminal state (completed/failed/cancelled)\n *\n * @param runId - The run ID to wait for\n * @param options - Polling options\n * @returns Run info when complete\n * @throws Error if timeout or run fails\n */\n async waitForCompletion<TOutput = unknown>(\n runId: string,\n options: PollOptions = {}\n ): Promise<TOutput> {\n const {\n interval = 1000,\n maxAttempts = 60,\n timeout,\n exponentialBackoff = false,\n maxBackoff = 10000,\n } = options;\n\n const startTime = Date.now();\n const effectiveTimeout = timeout || maxAttempts * interval;\n\n let currentInterval = interval;\n let attempts = 0;\n\n while (true) {\n attempts++;\n\n // Check timeout\n if (Date.now() - startTime > effectiveTimeout) {\n throw new Error(`Timeout waiting for run ${runId} after ${effectiveTimeout}ms`);\n }\n\n // Get run status\n const run = await this.getRun(runId);\n\n if (!run) {\n throw new Error(`Run ${runId} not found`);\n }\n\n // Check if run reached terminal state\n if (run.status === \"completed\") {\n return run.output as TOutput;\n } else if (run.status === \"failed\") {\n const errorMsg = run.error?.message || \"Run failed\";\n throw new Error(`Run ${runId} failed: ${errorMsg}`);\n } else if (run.status === \"cancelled\") {\n throw new Error(`Run ${runId} was cancelled`);\n }\n\n // Sleep before next poll\n await this.sleep(currentInterval);\n\n // Apply exponential backoff if enabled\n if (exponentialBackoff) {\n currentInterval = Math.min(currentInterval * 2, maxBackoff);\n }\n }\n }\n\n /**\n * List runs matching filters\n *\n * @param options - Filter options\n * @returns Array of run states\n */\n async listRuns(options: ListRunsOptions = {}): Promise<RunState[]> {\n const { workflowSlug, status, tags, limit } = options;\n\n // Convert status to array for backend (if provided)\n let statuses: RunState[\"status\"][] | undefined;\n if (status) {\n statuses = Array.isArray(status) ? status : [status];\n }\n\n return this.backend.listRuns({\n workflowSlug,\n status: statuses,\n tags,\n limit,\n });\n }\n\n /**\n * Cancel a run\n *\n * Can cancel runs in pending, claimed, or running status\n *\n * @param runId - The run to cancel\n * @param reason - Optional cancellation reason\n */\n async cancel(runId: string, reason?: string): Promise<void> {\n await this.backend.cancelRun(runId, reason);\n }\n\n /**\n * Retry a failed workflow\n *\n * Retries all failed steps in the workflow, keeping successful steps from the original run.\n * Step attempt numbers are reset to 1 for each retried step.\n *\n * @param runId - The run ID to retry\n * @param reason - Optional reason for retry\n * @returns Retry information including new workflow attempt number\n * @throws Error if run is not in failed status\n */\n async retry(\n runId: string,\n reason?: string\n ): Promise<{\n runId: string;\n workflowAttemptNumber: number;\n retriedSteps: string[];\n }> {\n // Get run state\n const runState = await this.backend.getRun(runId);\n if (!runState) {\n throw new Error(`Run ${runId} not found`);\n }\n\n // Verify run is failed\n if (runState.status !== \"failed\") {\n throw new Error(`Cannot retry run ${runId} - status is ${runState.status}, expected 'failed'`);\n }\n\n const workflowSlug = runState.workflowSlug;\n\n // Get failed steps\n const failedSteps = await this.backend.getFailedSteps(workflowSlug, runId);\n if (failedSteps.length === 0) {\n throw new Error(`No failed steps found in run ${runId}`);\n }\n\n // Calculate new workflow attempt number\n const previousAttemptNumber = runState.workflowAttemptNumber || 1;\n const workflowAttemptNumber = previousAttemptNumber + 1;\n\n const retriedStepIds = failedSteps.map((s) => s.stepId);\n\n // Emit WorkflowRetryStarted event\n await this.backend.saveWorkflowRetryStarted(workflowSlug, runId, {\n workflowAttemptNumber,\n previousAttemptNumber,\n retriedSteps: retriedStepIds,\n reason,\n });\n\n // Schedule each failed step for retry with fresh attempt number\n const now = Date.now() * 1000; // Convert to microseconds\n for (const step of failedSteps) {\n await this.backend.saveStepScheduled(workflowSlug, runId, step.stepId, {\n availableAt: now,\n reason: \"retry\",\n attemptNumber: 1, // Reset to 1 for workflow retry\n retryDelayMs: 0,\n });\n }\n\n return {\n runId,\n workflowAttemptNumber,\n retriedSteps: retriedStepIds,\n };\n }\n\n /**\n * List all available workflows\n *\n * @returns Array of workflow metadata\n */\n async listWorkflows(): Promise<WorkflowMetadata[]> {\n return this.backend.listWorkflowMetadata();\n }\n\n /**\n * Get metadata for a specific workflow\n *\n * @param workflowSlug - Workflow identifier (directory name)\n * @returns Workflow metadata or null if not found\n */\n async getWorkflowMetadata(workflowSlug: string): Promise<WorkflowMetadata | null> {\n return this.backend.getWorkflowMetadata(workflowSlug);\n }\n\n /**\n * Get step definitions for a specific workflow\n *\n * @param workflowSlug - Workflow identifier (directory name)\n * @returns Array of step definitions or empty array if workflow not found\n */\n async getWorkflowSteps(workflowSlug: string): Promise<any[]> {\n return this.backend.getWorkflowSteps(workflowSlug);\n }\n\n /**\n * Get the JSON Schema for a workflow's input\n *\n * @param workflowSlug - Workflow identifier (directory name)\n * @returns JSON Schema object or null if workflow has no input schema\n */\n async getWorkflowSchema(workflowSlug: string): Promise<any | null> {\n const metadata = await this.backend.getWorkflowMetadata(workflowSlug);\n return metadata?.inputSchemaJSON ?? null;\n }\n\n /**\n * Helper to sleep\n */\n private sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n\n // ============================================================================\n // Analytics Methods\n // ============================================================================\n\n /**\n * Get error analysis for workflows and steps\n *\n * Analyzes failure patterns, error types, and common error messages.\n *\n * @param options - Optional filters for time range, workflow, or step\n * @returns Error analysis data\n *\n * @example\n * ```typescript\n * // Get errors for last 24 hours (default)\n * const errors = await client.getErrorAnalysis();\n *\n * // Get errors for specific workflow\n * const errors = await client.getErrorAnalysis({\n * workflowSlug: 'my-workflow',\n * startUs: Date.now() * 1000 - 7 * 24 * 60 * 60 * 1000 * 1000 // Last 7 days\n * });\n * ```\n */\n async getErrorAnalysis(options?: AnalyticsOptions): Promise<ErrorAnalysis> {\n return this.backend.getErrorAnalysis(options);\n }\n\n /**\n * Get retry analysis metrics\n *\n * Analyzes retry patterns, success rates after retries, and retry effectiveness.\n *\n * @param options - Optional filters for time range, workflow, or step\n * @returns Retry analysis data\n */\n async getRetryAnalysis(options?: AnalyticsOptions): Promise<RetryAnalysis> {\n return this.backend.getRetryAnalysis(options);\n }\n\n /**\n * Get scheduling latency metrics\n *\n * Measures time between step being scheduled and actually starting execution.\n * High latency indicates worker starvation or queue congestion.\n *\n * @param options - Optional filters for time range, workflow, or step\n * @returns Scheduling latency statistics\n *\n * @example\n * ```typescript\n * const latency = await client.getSchedulingLatency({ workflowSlug: 'my-workflow' });\n * console.log(`Average wait time: ${latency.averageUs / 1000}ms`);\n * console.log(`P95 wait time: ${latency.p95Us / 1000}ms`);\n * ```\n */\n async getSchedulingLatency(options?: AnalyticsOptions): Promise<SchedulingLatency> {\n return this.backend.getSchedulingLatency(options);\n }\n\n /**\n * Get step duration metrics\n *\n * Analyzes how long steps take to execute.\n *\n * @param options - Optional filters for time range, workflow, or step\n * @returns Step duration statistics\n */\n async getStepDuration(options?: AnalyticsOptions): Promise<StepDuration> {\n return this.backend.getStepDuration(options);\n }\n\n /**\n * Get workflow duration metrics\n *\n * Analyzes end-to-end workflow execution time (from submission to completion).\n *\n * @param options - Optional filters for time range or workflow\n * @returns Workflow duration statistics\n */\n async getWorkflowDuration(options?: AnalyticsOptions): Promise<WorkflowDuration> {\n return this.backend.getWorkflowDuration(options);\n }\n\n /**\n * Get worker stability metrics\n *\n * Analyzes worker crashes, reclamations, and stale heartbeats.\n *\n * @param options - Optional filters for time range\n * @returns Worker stability data\n */\n async getWorkerStability(options?: AnalyticsOptions): Promise<WorkerStability> {\n return this.backend.getWorkerStability(options);\n }\n\n /**\n * Get throughput metrics\n *\n * Analyzes how many runs/steps are being completed per unit time.\n *\n * @param options - Optional filters for time range or workflow\n * @returns Throughput data\n */\n async getThroughput(options?: AnalyticsOptions): Promise<Throughput> {\n return this.backend.getThroughput(options);\n }\n\n /**\n * Get current queue depth\n *\n * Real-time snapshot of pending/running runs and steps.\n *\n * @param options - Optional filter for workflow\n * @returns Queue depth data\n *\n * @example\n * ```typescript\n * const depth = await client.getQueueDepth();\n * console.log(`Pending runs: ${depth.pendingRuns}`);\n * console.log(`Scheduled steps: ${depth.scheduledSteps}`);\n * ```\n */\n async getQueueDepth(options?: Pick<AnalyticsOptions, \"workflowSlug\">): Promise<QueueDepth> {\n return this.backend.getQueueDepth(options);\n }\n\n /**\n * Get queue depth broken down by workflow\n *\n * Real-time snapshot showing per-workflow queue statistics.\n * Useful for identifying which workflows have pending work.\n *\n * @returns Array of per-workflow queue depth data\n *\n * @example\n * ```typescript\n * const breakdown = await client.getQueueDepthByWorkflow();\n * for (const workflow of breakdown) {\n * console.log(`${workflow.workflowName}: ${workflow.pendingRuns} pending, ${workflow.scheduledSteps} scheduled`);\n * }\n * ```\n */\n async getQueueDepthByWorkflow(): Promise<QueueDepthByWorkflow> {\n return this.backend.getQueueDepthByWorkflow();\n }\n\n /**\n * Get success/failure rate metrics\n *\n * Analyzes overall health of workflows and steps.\n *\n * @param options - Optional filters for time range, workflow, or step\n * @returns Success rate data\n */\n async getSuccessRate(options?: AnalyticsOptions): Promise<SuccessRate> {\n return this.backend.getSuccessRate(options);\n }\n\n /**\n * Get comprehensive analytics summary\n *\n * Combines all analytics metrics into a single response.\n * Useful for dashboard views.\n *\n * @param options - Optional filters for time range or workflow\n * @returns Complete analytics summary\n *\n * @example\n * ```typescript\n * // Get full analytics for last 24 hours\n * const summary = await client.getAnalyticsSummary();\n *\n * // Get analytics for specific workflow over last week\n * const summary = await client.getAnalyticsSummary({\n * workflowSlug: 'my-workflow',\n * startUs: Date.now() * 1000 - 7 * 24 * 60 * 60 * 1000 * 1000\n * });\n * ```\n */\n async getAnalyticsSummary(options?: AnalyticsOptions): Promise<AnalyticsSummary> {\n return this.backend.getAnalyticsSummary(options);\n }\n\n /**\n * Get paginated list of errors grouped by fingerprint\n *\n * @param options - Filtering and pagination options\n * @returns Paginated list of error groups\n *\n * @example\n * ```typescript\n * // Get errors for last 24h\n * const { errors, total } = await client.getErrorsList({\n * timeRange: { start: Date.now() * 1000 - 86400000000, end: Date.now() * 1000 },\n * groupingStrategy: 'exact',\n * limit: 50,\n * offset: 0\n * });\n * ```\n */\n async getErrorsList(options?: {\n timeRange?: { start: number; end: number };\n workflowSlug?: string;\n groupingStrategy?: 'exact' | 'normalized' | 'portable';\n limit?: number;\n offset?: number;\n }): Promise<{\n errors: Array<{\n fingerprint: string;\n errorMessage: string;\n errorName: string;\n sampleStack: string;\n count: number;\n affectedRuns: number;\n firstSeen: number;\n lastSeen: number;\n }>;\n total: number;\n }> {\n return this.backend.getErrorsList(options);\n }\n\n /**\n * Get detailed information about a specific error by fingerprint\n *\n * @param fingerprint - Composite fingerprint (nameHash:messageHash:stackHash)\n * @param groupingStrategy - Which stack hash variant to use\n * @param options - Filtering and pagination options\n * @returns Error details with all occurrences\n *\n * @example\n * ```typescript\n * const detail = await client.getErrorDetail(\n * 'abc123:def456:ghi789',\n * 'exact',\n * { limit: 100, offset: 0 }\n * );\n * ```\n */\n async getErrorDetail(\n fingerprint: string,\n groupingStrategy: 'exact' | 'normalized' | 'portable',\n options?: {\n timeRange?: { start: number; end: number };\n limit?: number;\n offset?: number;\n }\n ): Promise<{\n fingerprint: string;\n errorMessage: string;\n errorName: string;\n sampleStack: string;\n totalCount: number;\n affectedRuns: number;\n firstSeen: number;\n lastSeen: number;\n occurrences: Array<{\n workflowSlug: string;\n runId: string;\n stepId: string;\n attemptNumber: number;\n timestampUs: number;\n }>;\n total: number;\n }> {\n return this.backend.getErrorDetail(fingerprint, groupingStrategy, options);\n }\n\n /**\n * Get the state of all steps for a run\n * Projects step events to compute current state\n */\n async getStepStates(workflowSlug: string, runId: string): Promise<StepState[]> {\n const events = await this.backend.loadEvents(workflowSlug, runId, {\n category: 'step',\n });\n\n // Group events by step ID\n const stepGroups = new Map<string, StepEvent[]>();\n for (const event of events) {\n if (event.category === 'step') {\n if (!stepGroups.has(event.stepId)) {\n stepGroups.set(event.stepId, []);\n }\n stepGroups.get(event.stepId)!.push(event as StepEvent);\n }\n }\n\n // Project each step's state\n const states: StepState[] = [];\n for (const [stepId, stepEvents] of stepGroups) {\n try {\n const state = projectStepState(stepEvents, workflowSlug);\n states.push(state);\n } catch (err) {\n console.error(`Failed to project state for step ${stepId}:`, err);\n }\n }\n\n return states;\n }\n\n /**\n * Get all events for a specific run (both workflow and step events)\n */\n async getRunEvents(workflowSlug: string, runId: string) {\n return this.backend.loadEvents(workflowSlug, runId);\n }\n\n /**\n * Get detailed information for a specific step\n * Includes state, events, and logs\n */\n async getStepDetail(\n workflowSlug: string,\n runId: string,\n stepName: string\n ): Promise<{\n state: StepState;\n events: StepEvent[];\n logs: LogEntry[];\n attempts: AttemptMetadata[];\n } | null> {\n // Load all events for this specific step\n const events = await this.backend.loadEvents(workflowSlug, runId, {\n category: 'step',\n stepId: stepName,\n });\n\n // Filter to only step events\n const stepEvents = events.filter((e): e is StepEvent => e.category === 'step');\n\n if (stepEvents.length === 0) {\n return null;\n }\n\n // Project events to current state\n const state = projectStepState(stepEvents, workflowSlug);\n\n // Extract logs from events\n const logs = extractLogsFromEvents(stepEvents);\n\n // Extract attempt metadata\n const attempts = extractAttemptMetadata(stepEvents);\n\n return {\n state,\n events: stepEvents,\n logs,\n attempts,\n };\n }\n}\n\n// Export types\nexport type { PollOptions, ListRunsOptions, RunInfo } from \"./types.ts\";\nexport type {\n AnalyticsOptions,\n ErrorAnalysis,\n RetryAnalysis,\n SchedulingLatency,\n StepDuration,\n WorkflowDuration,\n WorkerStability,\n Throughput,\n QueueDepth,\n QueueDepthByWorkflow,\n SuccessRate,\n AnalyticsSummary,\n} from \"@cascade-flow/backend-interface\";\n"
6
+ ],
7
+ "mappings": "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",
8
+ "debugId": "092C4E0F5E8FB25364756E2164756E21",
9
+ "names": []
10
+ }
@@ -0,0 +1,41 @@
1
+ import type { RunState } from "@cascade-flow/backend-interface";
2
+ /**
3
+ * Options for polling and waiting
4
+ */
5
+ export type PollOptions = {
6
+ /** Interval between polls (ms, default: 1000) */
7
+ interval?: number;
8
+ /** Maximum number of poll attempts (default: 60) */
9
+ maxAttempts?: number;
10
+ /** Timeout in milliseconds (overrides maxAttempts if provided) */
11
+ timeout?: number;
12
+ /** Use exponential backoff (default: false) */
13
+ exponentialBackoff?: boolean;
14
+ /** Maximum backoff interval (ms, default: 10000) */
15
+ maxBackoff?: number;
16
+ };
17
+ /**
18
+ * Options for listing runs
19
+ */
20
+ export type ListRunsOptions = {
21
+ /** Filter by workflow slug */
22
+ workflowSlug?: string;
23
+ /** Filter by status (single status or array of statuses) */
24
+ status?: RunState["status"] | RunState["status"][];
25
+ /** Filter by tags (runs must have all tags) */
26
+ tags?: string[];
27
+ /** Limit results */
28
+ limit?: number;
29
+ };
30
+ /**
31
+ * Extended run information with output
32
+ */
33
+ export type RunInfo = RunState & {
34
+ output?: any;
35
+ error?: {
36
+ message: string;
37
+ stack?: string;
38
+ name?: string;
39
+ };
40
+ };
41
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAiB,MAAM,iCAAiC,CAAC;AAE/E;;GAEG;AACH,MAAM,MAAM,WAAW,GAAG;IACxB,iDAAiD;IACjD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB,oDAAoD;IACpD,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB,kEAAkE;IAClE,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB,+CAA+C;IAC/C,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAE7B,oDAAoD;IACpD,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,eAAe,GAAG;IAC5B,8BAA8B;IAC9B,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB,4DAA4D;IAC5D,MAAM,CAAC,EAAE,QAAQ,CAAC,QAAQ,CAAC,GAAG,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;IAEnD,+CAA+C;IAC/C,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAEhB,oBAAoB;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,OAAO,GAAG,QAAQ,GAAG;IAC/B,MAAM,CAAC,EAAE,GAAG,CAAC;IACb,KAAK,CAAC,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CAC5D,CAAC"}
package/package.json ADDED
@@ -0,0 +1,59 @@
1
+ {
2
+ "name": "@cascade-flow/client",
3
+ "version": "0.1.0",
4
+ "main": "./dist/index.js",
5
+ "module": "./dist/index.js",
6
+ "types": "./dist/index.d.ts",
7
+ "type": "module",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js",
12
+ "default": "./dist/index.js"
13
+ }
14
+ },
15
+ "scripts": {
16
+ "build": "rm -rf dist && bun build src/index.ts --outdir dist --target node --sourcemap=external --external=@cascade-flow/* && tsc -p tsconfig.build.json",
17
+ "prepublishOnly": "bun run build",
18
+ "test": "bun test"
19
+ },
20
+ "dependencies": {
21
+ "@cascade-flow/backend-interface": "0.1.0",
22
+ "zod": "^4.1.12"
23
+ },
24
+ "devDependencies": {
25
+ "@types/bun": "latest",
26
+ "typescript": "^5"
27
+ },
28
+ "peerDependencies": {
29
+ "typescript": "^5"
30
+ },
31
+ "peerDependenciesMeta": {
32
+ "@cascadeflow/backend-filesystem": {
33
+ "optional": true
34
+ },
35
+ "@cascadeflow/backend-postgres": {
36
+ "optional": true
37
+ }
38
+ },
39
+ "files": [
40
+ "dist"
41
+ ],
42
+ "publishConfig": {
43
+ "access": "public"
44
+ },
45
+ "repository": {
46
+ "type": "git",
47
+ "url": "https://github.com/cascadeflow/cascadeflow.git",
48
+ "directory": "packages/client"
49
+ },
50
+ "license": "MIT",
51
+ "description": "Type-safe programmatic client for CascadeFlow workflow orchestrator",
52
+ "keywords": [
53
+ "workflow",
54
+ "orchestrator",
55
+ "client",
56
+ "api",
57
+ "typescript"
58
+ ]
59
+ }