@wave-av/workflow-sdk 1.0.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/CHANGELOG.md ADDED
@@ -0,0 +1,9 @@
1
+ # Changelog
2
+
3
+ ## 1.0.0 (2026-04-02)
4
+
5
+ - Initial release
6
+ - Workflow builder with fluent API
7
+ - 3 subpath exports: root, `./types`, `./client`
8
+ - Real-time execution events via EventEmitter
9
+ - Zod schema validation
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 WAVE Inc.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,250 @@
1
+ # @wave-av/workflow-sdk
2
+
3
+ Official SDK for building and executing workflows on the WAVE platform.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @wave-av/workflow-sdk
9
+ # or
10
+ yarn add @wave-av/workflow-sdk
11
+ # or
12
+ pnpm add @wave-av/workflow-sdk
13
+ ```
14
+
15
+ ## Quick start
16
+
17
+ ```typescript
18
+ import { WaveWorkflowClient } from '@wave-av/workflow-sdk';
19
+
20
+ // Create a client
21
+ const client = new WaveWorkflowClient({
22
+ apiKey: process.env.WAVE_API_KEY!,
23
+ organizationId: 'org_123',
24
+ });
25
+
26
+ // Execute a workflow
27
+ const execution = await client.execute('my-workflow', {
28
+ input_params: {
29
+ environment: 'production',
30
+ },
31
+ });
32
+
33
+ console.log('Execution started:', execution.id);
34
+
35
+ // Wait for completion
36
+ const result = await client.waitForCompletion(execution.id);
37
+ console.log('Result:', result.status);
38
+ ```
39
+
40
+ ## Building workflows
41
+
42
+ Use the fluent builder API to create workflow definitions:
43
+
44
+ ```typescript
45
+ import { WorkflowBuilder } from '@wave-av/workflow-sdk';
46
+
47
+ const workflow = new WorkflowBuilder('data-pipeline')
48
+ .name('Data Processing Pipeline')
49
+ .description('ETL pipeline for processing analytics data')
50
+ .category('data-processing')
51
+ .version('1.0.0')
52
+ .tags('etl', 'analytics')
53
+ .phase('extract', (phase) =>
54
+ phase
55
+ .description('Extract data from source systems')
56
+ .agent('data-extractor', { source: 'api', endpoint: '/data' })
57
+ )
58
+ .phase('transform', (phase) =>
59
+ phase
60
+ .description('Transform and validate data')
61
+ .agent('data-transformer', { format: 'json' })
62
+ .onFailure('retry')
63
+ )
64
+ .phase('load', (phase) =>
65
+ phase
66
+ .description('Load data to destination')
67
+ .agent('data-loader', { destination: 'database' })
68
+ )
69
+ .timeout(3600)
70
+ .enableCheckpoints()
71
+ .maxRetries(3)
72
+ .build();
73
+
74
+ // Export as JSON
75
+ console.log(JSON.stringify(workflow, null, 2));
76
+ ```
77
+
78
+ ## API reference
79
+
80
+ ### WaveWorkflowClient
81
+
82
+ #### Constructor options
83
+
84
+ ```typescript
85
+ const client = new WaveWorkflowClient({
86
+ apiKey: string; // Required: API key for authentication
87
+ organizationId: string; // Required: Organization ID for tenant isolation
88
+ baseUrl?: string; // Optional: API base URL (default: https://api.wave.online)
89
+ timeout?: number; // Optional: Request timeout in ms (default: 30000)
90
+ debug?: boolean; // Optional: Enable debug logging
91
+ });
92
+ ```
93
+
94
+ #### Methods
95
+
96
+ ##### Workflow definitions
97
+
98
+ ```typescript
99
+ // Get a workflow by slug
100
+ const workflow = await client.getWorkflow('my-workflow');
101
+
102
+ // List all workflows
103
+ const { workflows, total } = await client.listWorkflows({
104
+ category: 'devops',
105
+ status: 'active',
106
+ limit: 10,
107
+ });
108
+ ```
109
+
110
+ ##### Executions
111
+
112
+ ```typescript
113
+ // Execute a workflow
114
+ const execution = await client.execute('my-workflow', {
115
+ input_params: { key: 'value' },
116
+ idempotency_key: 'unique-key',
117
+ });
118
+
119
+ // Get execution status
120
+ const status = await client.getExecution(execution.id);
121
+
122
+ // List executions
123
+ const { executions } = await client.listExecutions({
124
+ workflow_id: 'workflow-id',
125
+ status: 'running',
126
+ limit: 20,
127
+ });
128
+
129
+ // Cancel an execution
130
+ await client.cancelExecution(execution.id);
131
+
132
+ // Pause an execution
133
+ await client.pauseExecution(execution.id);
134
+
135
+ // Resume a paused execution
136
+ await client.resumeExecution(execution.id);
137
+
138
+ // Retry a failed execution
139
+ await client.retryExecution(execution.id, { from_checkpoint: true });
140
+ ```
141
+
142
+ ##### Convenience methods
143
+
144
+ ```typescript
145
+ // Wait for completion with progress callback
146
+ const result = await client.waitForCompletion(execution.id, {
147
+ pollInterval: 2000, // Poll every 2 seconds
148
+ timeout: 3600000, // 1 hour timeout
149
+ onProgress: (exec) => {
150
+ console.log(`Status: ${exec.status}, Phase: ${exec.current_phase}`);
151
+ },
152
+ });
153
+
154
+ // Execute and wait in one call
155
+ const result = await client.executeAndWait('my-workflow', {
156
+ input_params: { key: 'value' },
157
+ });
158
+ ```
159
+
160
+ ##### Logs
161
+
162
+ ```typescript
163
+ // Get execution logs
164
+ const { logs } = await client.getLogs(execution.id, {
165
+ level: 'error',
166
+ limit: 100,
167
+ });
168
+ ```
169
+
170
+ ##### Real-time events
171
+
172
+ ```typescript
173
+ // Subscribe to execution events
174
+ const unsubscribe = client.subscribeToExecution(execution.id);
175
+
176
+ client.on('execution.started', (event) => {
177
+ console.log('Execution started:', event);
178
+ });
179
+
180
+ client.on('phase.completed', (event) => {
181
+ console.log('Phase completed:', event.data.phase_name);
182
+ });
183
+
184
+ client.on('execution.completed', (event) => {
185
+ console.log('Execution completed in', event.data.duration_ms, 'ms');
186
+ unsubscribe();
187
+ });
188
+
189
+ client.on('error', (error) => {
190
+ console.error('Error:', error);
191
+ });
192
+ ```
193
+
194
+ ## Types
195
+
196
+ All TypeScript types are exported from the package:
197
+
198
+ ```typescript
199
+ import type {
200
+ WorkflowDefinition,
201
+ WorkflowPhase,
202
+ WorkflowAgent,
203
+ WorkflowConfig,
204
+ WorkflowExecution,
205
+ ExecutionStatus,
206
+ ExecutionLog,
207
+ AnyWorkflowEvent,
208
+ } from '@wave-av/workflow-sdk';
209
+ ```
210
+
211
+ ## Validation
212
+
213
+ The SDK includes Zod schemas for runtime validation:
214
+
215
+ ```typescript
216
+ import { WorkflowDefinitionSchema } from '@wave-av/workflow-sdk/types';
217
+
218
+ const result = WorkflowDefinitionSchema.safeParse(workflowData);
219
+ if (!result.success) {
220
+ console.error('Validation errors:', result.error.issues);
221
+ }
222
+ ```
223
+
224
+ ## Error handling
225
+
226
+ ```typescript
227
+ try {
228
+ const execution = await client.execute('my-workflow');
229
+ } catch (error) {
230
+ if (error.message.includes('API error (404)')) {
231
+ console.error('Workflow not found');
232
+ } else if (error.message.includes('timeout')) {
233
+ console.error('Request timed out');
234
+ } else {
235
+ console.error('Unknown error:', error);
236
+ }
237
+ }
238
+ ```
239
+
240
+ ## Environment variables
241
+
242
+ | Variable | Description |
243
+ |----------|-------------|
244
+ | `WAVE_API_KEY` | API key for authentication |
245
+ | `WAVE_ORGANIZATION_ID` | Organization ID for tenant isolation |
246
+ | `WAVE_API_URL` | Optional: Custom API base URL |
247
+
248
+ ## License
249
+
250
+ MIT
@@ -0,0 +1,237 @@
1
+ // src/client.ts
2
+ import { EventEmitter } from "eventemitter3";
3
+ var WaveWorkflowClient = class extends EventEmitter {
4
+ config;
5
+ headers;
6
+ constructor(config) {
7
+ super();
8
+ this.config = {
9
+ baseUrl: "https://api.wave.online",
10
+ timeout: 3e4,
11
+ debug: false,
12
+ ...config
13
+ };
14
+ this.headers = {
15
+ "Authorization": `Bearer ${this.config.apiKey}`,
16
+ "Content-Type": "application/json",
17
+ "X-Organization-Id": this.config.organizationId
18
+ };
19
+ }
20
+ // ==========================================================================
21
+ // Workflow Definitions
22
+ // ==========================================================================
23
+ /**
24
+ * Get a workflow definition by slug
25
+ */
26
+ async getWorkflow(slug) {
27
+ return this.request(`/v1/workflows/${slug}`);
28
+ }
29
+ /**
30
+ * List all workflows
31
+ */
32
+ async listWorkflows(options) {
33
+ const params = new URLSearchParams();
34
+ if (options?.category) params.set("category", options.category);
35
+ if (options?.status) params.set("status", options.status);
36
+ if (options?.limit) params.set("limit", String(options.limit));
37
+ if (options?.offset) params.set("offset", String(options.offset));
38
+ return this.request(`/v1/workflows?${params.toString()}`);
39
+ }
40
+ // ==========================================================================
41
+ // Workflow Executions
42
+ // ==========================================================================
43
+ /**
44
+ * Execute a workflow
45
+ */
46
+ async execute(workflowSlug, request) {
47
+ const response = await this.request(
48
+ `/v1/workflows/${workflowSlug}/execute`,
49
+ {
50
+ method: "POST",
51
+ body: JSON.stringify(request || {})
52
+ }
53
+ );
54
+ return response.execution;
55
+ }
56
+ /**
57
+ * Get execution status
58
+ */
59
+ async getExecution(executionId) {
60
+ return this.request(`/v1/executions/${executionId}`);
61
+ }
62
+ /**
63
+ * List executions
64
+ */
65
+ async listExecutions(request) {
66
+ const params = new URLSearchParams();
67
+ if (request?.workflow_id) params.set("workflow_id", request.workflow_id);
68
+ if (request?.status) params.set("status", request.status);
69
+ if (request?.limit) params.set("limit", String(request.limit));
70
+ if (request?.offset) params.set("offset", String(request.offset));
71
+ if (request?.order_by) params.set("order_by", request.order_by);
72
+ if (request?.order) params.set("order", request.order);
73
+ return this.request(`/v1/executions?${params.toString()}`);
74
+ }
75
+ /**
76
+ * Cancel a running execution
77
+ */
78
+ async cancelExecution(executionId) {
79
+ return this.request(
80
+ `/v1/executions/${executionId}/cancel`,
81
+ { method: "POST" }
82
+ );
83
+ }
84
+ /**
85
+ * Pause a running execution
86
+ */
87
+ async pauseExecution(executionId) {
88
+ return this.request(
89
+ `/v1/executions/${executionId}/pause`,
90
+ { method: "POST" }
91
+ );
92
+ }
93
+ /**
94
+ * Resume a paused execution
95
+ */
96
+ async resumeExecution(executionId) {
97
+ return this.request(
98
+ `/v1/executions/${executionId}/resume`,
99
+ { method: "POST" }
100
+ );
101
+ }
102
+ /**
103
+ * Retry a failed execution
104
+ */
105
+ async retryExecution(executionId, options) {
106
+ return this.request(
107
+ `/v1/executions/${executionId}/retry`,
108
+ {
109
+ method: "POST",
110
+ body: JSON.stringify(options || {})
111
+ }
112
+ );
113
+ }
114
+ // ==========================================================================
115
+ // Execution Logs
116
+ // ==========================================================================
117
+ /**
118
+ * Get execution logs
119
+ */
120
+ async getLogs(executionId, options) {
121
+ const params = new URLSearchParams();
122
+ if (options?.level) params.set("level", options.level);
123
+ if (options?.limit) params.set("limit", String(options.limit));
124
+ if (options?.offset) params.set("offset", String(options.offset));
125
+ return this.request(`/v1/executions/${executionId}/logs?${params.toString()}`);
126
+ }
127
+ // ==========================================================================
128
+ // Convenience Methods
129
+ // ==========================================================================
130
+ /**
131
+ * Wait for an execution to complete
132
+ */
133
+ async waitForCompletion(executionId, options) {
134
+ const pollInterval = options?.pollInterval || 2e3;
135
+ const timeout = options?.timeout || 36e5;
136
+ const startTime = Date.now();
137
+ const terminalStatuses = [
138
+ "completed",
139
+ "failed",
140
+ "cancelled",
141
+ "timeout"
142
+ ];
143
+ while (Date.now() - startTime < timeout) {
144
+ const execution = await this.getExecution(executionId);
145
+ if (options?.onProgress) {
146
+ options.onProgress(execution);
147
+ }
148
+ if (terminalStatuses.includes(execution.status)) {
149
+ return execution;
150
+ }
151
+ await this.sleep(pollInterval);
152
+ }
153
+ throw new Error(`Execution ${executionId} timed out after ${timeout}ms`);
154
+ }
155
+ /**
156
+ * Execute a workflow and wait for completion
157
+ */
158
+ async executeAndWait(workflowSlug, request, waitOptions) {
159
+ const execution = await this.execute(workflowSlug, request);
160
+ return this.waitForCompletion(execution.id, waitOptions);
161
+ }
162
+ // ==========================================================================
163
+ // Real-time Events (WebSocket)
164
+ // ==========================================================================
165
+ /**
166
+ * Subscribe to real-time execution events
167
+ */
168
+ subscribeToExecution(executionId) {
169
+ const wsUrl = this.config.baseUrl.replace("https://", "wss://").replace("http://", "ws://");
170
+ const ws = new WebSocket(
171
+ `${wsUrl}/v1/executions/${executionId}/events?token=${this.config.apiKey}`
172
+ );
173
+ ws.onmessage = (event) => {
174
+ try {
175
+ const data = JSON.parse(event.data);
176
+ this.emit(data.type, data);
177
+ } catch (error) {
178
+ this.emit("error", error);
179
+ }
180
+ };
181
+ ws.onerror = (error) => {
182
+ this.emit("error", new Error(`WebSocket error: ${error}`));
183
+ };
184
+ return () => {
185
+ if (ws.readyState === WebSocket.OPEN) {
186
+ ws.close();
187
+ }
188
+ };
189
+ }
190
+ // ==========================================================================
191
+ // Private Helpers
192
+ // ==========================================================================
193
+ async request(path, options) {
194
+ const url = `${this.config.baseUrl}${path}`;
195
+ if (this.config.debug) {
196
+ console.log(`[WaveWorkflowClient] ${options?.method || "GET"} ${url}`);
197
+ }
198
+ const controller = new AbortController();
199
+ const timeoutId = setTimeout(
200
+ () => controller.abort(),
201
+ this.config.timeout
202
+ );
203
+ try {
204
+ const response = await fetch(url, {
205
+ ...options,
206
+ headers: {
207
+ ...this.headers,
208
+ ...options?.headers
209
+ },
210
+ signal: controller.signal
211
+ });
212
+ clearTimeout(timeoutId);
213
+ if (!response.ok) {
214
+ const error = await response.text();
215
+ throw new Error(`API error (${response.status}): ${error}`);
216
+ }
217
+ return response.json();
218
+ } catch (error) {
219
+ clearTimeout(timeoutId);
220
+ if (error instanceof Error && error.name === "AbortError") {
221
+ throw new Error(`Request timeout after ${this.config.timeout}ms`);
222
+ }
223
+ throw error;
224
+ }
225
+ }
226
+ sleep(ms) {
227
+ return new Promise((resolve) => setTimeout(resolve, ms));
228
+ }
229
+ };
230
+ function createClient(config) {
231
+ return new WaveWorkflowClient(config);
232
+ }
233
+
234
+ export {
235
+ WaveWorkflowClient,
236
+ createClient
237
+ };
@@ -0,0 +1,57 @@
1
+ // src/types.ts
2
+ import { z } from "zod";
3
+ var WorkflowAgentSchema = z.object({
4
+ type: z.string().min(1),
5
+ config: z.record(z.unknown()).optional(),
6
+ timeout_seconds: z.number().int().positive().optional(),
7
+ retry_policy: z.object({
8
+ max_attempts: z.number().int().positive(),
9
+ backoff_type: z.enum(["fixed", "exponential"]),
10
+ initial_delay_ms: z.number().int().positive(),
11
+ max_delay_ms: z.number().int().positive().optional()
12
+ }).optional()
13
+ });
14
+ var WorkflowPhaseSchema = z.object({
15
+ name: z.string().min(1).max(100),
16
+ description: z.string().max(500).optional(),
17
+ order: z.number().int().positive(),
18
+ agents: z.array(WorkflowAgentSchema),
19
+ condition: z.object({
20
+ type: z.enum(["expression", "previous_phase_status"]),
21
+ expression: z.string().optional(),
22
+ required_status: z.enum(["completed", "skipped"]).optional()
23
+ }).optional(),
24
+ on_failure: z.enum(["fail", "skip", "retry"]).optional()
25
+ });
26
+ var WorkflowConfigSchema = z.object({
27
+ timeout_seconds: z.number().int().positive().max(86400).optional(),
28
+ max_retries: z.number().int().min(0).max(10).optional(),
29
+ checkpoint_enabled: z.boolean().optional(),
30
+ parallel_phases: z.boolean().optional(),
31
+ fail_fast: z.boolean().optional(),
32
+ notification_channels: z.array(z.string()).optional()
33
+ });
34
+ var WorkflowDefinitionSchema = z.object({
35
+ name: z.string().min(1).max(200),
36
+ slug: z.string().regex(/^[a-z0-9-]+$/).min(1).max(100),
37
+ description: z.string().max(1e3).optional(),
38
+ category: z.string().min(1).max(50),
39
+ version: z.string().regex(/^\d+\.\d+\.\d+$/),
40
+ phases: z.array(WorkflowPhaseSchema).min(1),
41
+ config: WorkflowConfigSchema.optional(),
42
+ tags: z.array(z.string().max(50)).max(10).optional()
43
+ });
44
+ var ExecuteWorkflowRequestSchema = z.object({
45
+ input_params: z.record(z.unknown()).optional(),
46
+ trigger_type: z.enum(["manual", "api"]).optional(),
47
+ idempotency_key: z.string().max(100).optional(),
48
+ checkpoint_id: z.string().uuid().optional()
49
+ });
50
+
51
+ export {
52
+ WorkflowAgentSchema,
53
+ WorkflowPhaseSchema,
54
+ WorkflowConfigSchema,
55
+ WorkflowDefinitionSchema,
56
+ ExecuteWorkflowRequestSchema
57
+ };