@stepflowjs/client-ts 0.0.1

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.
@@ -0,0 +1,366 @@
1
+ type RealtimeStrategy = "sse" | "websocket" | "auto";
2
+ interface RealtimeEvent {
3
+ type: string;
4
+ data: unknown;
5
+ }
6
+ interface RealtimeConnectionConfig {
7
+ /**
8
+ * Connection strategy
9
+ * @default 'auto'
10
+ */
11
+ strategy?: RealtimeStrategy;
12
+ /**
13
+ * SSE endpoint URL
14
+ */
15
+ sseUrl: string;
16
+ /**
17
+ * WebSocket endpoint URL (optional, derived from sseUrl if not provided)
18
+ */
19
+ wsUrl?: string;
20
+ /**
21
+ * HTTP headers for SSE connection
22
+ */
23
+ headers?: Record<string, string>;
24
+ /**
25
+ * Number of reconnection attempts
26
+ * @default 3
27
+ */
28
+ reconnectAttempts?: number;
29
+ /**
30
+ * Delay between reconnection attempts in milliseconds
31
+ * @default 1000
32
+ */
33
+ reconnectDelayMs?: number;
34
+ /**
35
+ * Called when connection is established
36
+ */
37
+ onConnect?: () => void;
38
+ /**
39
+ * Called when connection is closed
40
+ */
41
+ onDisconnect?: () => void;
42
+ /**
43
+ * Called when an error occurs
44
+ */
45
+ onError?: (error: Error) => void;
46
+ /**
47
+ * Called when a message is received
48
+ */
49
+ onMessage?: (event: RealtimeEvent) => void;
50
+ }
51
+ declare class RealtimeConnection {
52
+ private config;
53
+ private eventSource;
54
+ private webSocket;
55
+ private activeStrategy;
56
+ private reconnectCount;
57
+ private reconnectTimeout;
58
+ private connectionTimeout;
59
+ private isManualDisconnect;
60
+ constructor(config: RealtimeConnectionConfig);
61
+ /**
62
+ * Connect using the configured strategy
63
+ */
64
+ connect(): Promise<void>;
65
+ /**
66
+ * Disconnect from the active connection
67
+ */
68
+ disconnect(): void;
69
+ /**
70
+ * Check if currently connected
71
+ */
72
+ isConnected(): boolean;
73
+ /**
74
+ * Get the currently active strategy
75
+ */
76
+ getActiveStrategy(): "sse" | "websocket" | null;
77
+ private connectAuto;
78
+ private connectSSE;
79
+ private setupSSEEventListeners;
80
+ private connectWebSocket;
81
+ private handleMessage;
82
+ private handleDisconnect;
83
+ private attemptReconnect;
84
+ private closeConnections;
85
+ private closeSSE;
86
+ private closeWebSocket;
87
+ private clearTimeouts;
88
+ private deriveWebSocketUrl;
89
+ }
90
+
91
+ /**
92
+ * Storage interface for tokens
93
+ */
94
+ interface TokenStorage {
95
+ get(key: string): Promise<string | null>;
96
+ set(key: string, value: string): Promise<void>;
97
+ remove(key: string): Promise<void>;
98
+ }
99
+ /**
100
+ * Token manager configuration
101
+ */
102
+ interface TokenManagerConfig {
103
+ /**
104
+ * Storage implementation
105
+ * @default MemoryTokenStorage
106
+ */
107
+ storage?: TokenStorage;
108
+ /**
109
+ * Prefix for storage keys
110
+ * @default 'stepflow_token_'
111
+ */
112
+ storageKeyPrefix?: string;
113
+ /**
114
+ * Refresh threshold in milliseconds before expiry
115
+ * @default 300000 (5 minutes)
116
+ */
117
+ refreshThresholdMs?: number;
118
+ /**
119
+ * Callback when token is refreshed
120
+ */
121
+ onTokenRefresh?: (runId: string, newToken: string) => void;
122
+ /**
123
+ * Callback when token expires
124
+ */
125
+ onTokenExpired?: (runId: string) => void;
126
+ }
127
+ /**
128
+ * In-memory token storage (default for SSR/testing)
129
+ */
130
+ declare class MemoryTokenStorage implements TokenStorage {
131
+ private store;
132
+ get(key: string): Promise<string | null>;
133
+ set(key: string, value: string): Promise<void>;
134
+ remove(key: string): Promise<void>;
135
+ }
136
+ /**
137
+ * Browser localStorage wrapper
138
+ */
139
+ declare class LocalStorageTokenStorage implements TokenStorage {
140
+ get(key: string): Promise<string | null>;
141
+ set(key: string, value: string): Promise<void>;
142
+ remove(key: string): Promise<void>;
143
+ }
144
+ /**
145
+ * Manages API tokens with storage and auto-refresh
146
+ */
147
+ declare class TokenManager {
148
+ private storage;
149
+ private storageKeyPrefix;
150
+ private refreshThresholdMs;
151
+ private onTokenRefresh?;
152
+ private onTokenExpired?;
153
+ private refreshTimers;
154
+ constructor(config?: TokenManagerConfig);
155
+ /**
156
+ * Store a token with expiry
157
+ */
158
+ storeToken(runId: string, token: string, expiresAt: Date): Promise<void>;
159
+ /**
160
+ * Get a token if it's still valid
161
+ * @returns Token string or null if expired/not found
162
+ */
163
+ getToken(runId: string): Promise<string | null>;
164
+ /**
165
+ * Remove a token from storage
166
+ */
167
+ removeToken(runId: string): Promise<void>;
168
+ /**
169
+ * Check if a token is valid (exists and not expired)
170
+ */
171
+ isTokenValid(runId: string): Promise<boolean>;
172
+ /**
173
+ * Get token expiry date
174
+ * @returns Expiry date or null if not found
175
+ */
176
+ getTokenExpiry(runId: string): Promise<Date | null>;
177
+ /**
178
+ * Start auto-refresh for a token
179
+ */
180
+ startAutoRefresh(runId: string, refreshFn: () => Promise<{
181
+ token: string;
182
+ expiresAt: Date;
183
+ }>): void;
184
+ /**
185
+ * Stop auto-refresh for a specific token
186
+ */
187
+ stopAutoRefresh(runId: string): void;
188
+ /**
189
+ * Stop all auto-refresh timers
190
+ */
191
+ stopAllAutoRefresh(): void;
192
+ /**
193
+ * Schedule a refresh based on token expiry
194
+ */
195
+ private scheduleRefresh;
196
+ /**
197
+ * Get storage key for a run ID
198
+ */
199
+ private getStorageKey;
200
+ }
201
+
202
+ interface StepflowClientConfig {
203
+ /**
204
+ * Base URL of the Stepflow API
205
+ */
206
+ baseUrl: string;
207
+ /**
208
+ * API key for server-side requests
209
+ */
210
+ apiKey?: string;
211
+ /**
212
+ * Public API key for client-side requests
213
+ */
214
+ publicApiKey?: string;
215
+ /**
216
+ * WebSocket URL for real-time updates
217
+ */
218
+ wsUrl?: string;
219
+ }
220
+ type ExecutionStatus = "pending" | "running" | "completed" | "failed" | "waiting" | "sleeping" | "cancelled";
221
+ interface Execution<TPayload = unknown, TResult = unknown> {
222
+ id: string;
223
+ runId: string;
224
+ workflowId: string;
225
+ eventName: string;
226
+ payload: TPayload;
227
+ status: ExecutionStatus;
228
+ result?: TResult;
229
+ error?: ExecutionError;
230
+ steps: StepExecution[];
231
+ metadata: Record<string, unknown>;
232
+ attempt: number;
233
+ startedAt: Date;
234
+ completedAt?: Date;
235
+ }
236
+ interface ExecutionError {
237
+ name: string;
238
+ message: string;
239
+ stack?: string;
240
+ code?: string;
241
+ }
242
+ interface StepExecution {
243
+ name: string;
244
+ status: "pending" | "running" | "completed" | "failed" | "cached";
245
+ result?: unknown;
246
+ error?: ExecutionError;
247
+ startedAt?: Date;
248
+ completedAt?: Date;
249
+ durationMs?: number;
250
+ }
251
+ interface TriggerResult {
252
+ runId: string;
253
+ executionId: string;
254
+ publicAccessToken: string;
255
+ }
256
+ interface NotifyResult {
257
+ waiters: number;
258
+ executions: string[];
259
+ }
260
+ interface TriggerOptions {
261
+ runId?: string;
262
+ metadata?: Record<string, unknown>;
263
+ delay?: number;
264
+ }
265
+ interface SubscribeOptions<TPayload = unknown, TResult = unknown> {
266
+ accessToken?: string;
267
+ throttleMs?: number;
268
+ strategy?: RealtimeStrategy;
269
+ onUpdate?: (run: Execution<TPayload, TResult>) => void;
270
+ onStepComplete?: (step: StepExecution) => void;
271
+ onComplete?: (result: TResult) => void;
272
+ onError?: (error: Error) => void;
273
+ onConnect?: () => void;
274
+ onDisconnect?: () => void;
275
+ }
276
+ interface StreamOptions {
277
+ signal?: AbortSignal;
278
+ }
279
+ interface StreamEvent {
280
+ type: string;
281
+ data: unknown;
282
+ stepName?: string;
283
+ }
284
+ interface ListRunsOptions {
285
+ workflowId?: string;
286
+ status?: ExecutionStatus;
287
+ limit?: number;
288
+ offset?: number;
289
+ }
290
+ interface PaginatedResult<T> {
291
+ data: T[];
292
+ total: number;
293
+ limit: number;
294
+ offset: number;
295
+ }
296
+ type Unsubscribe = () => void;
297
+ declare class StepflowError extends Error {
298
+ readonly code?: string | undefined;
299
+ readonly status?: number | undefined;
300
+ constructor(message: string, code?: string | undefined, status?: number | undefined);
301
+ }
302
+ declare class StepflowClient {
303
+ private config;
304
+ constructor(config: StepflowClientConfig);
305
+ /**
306
+ * Trigger a workflow execution
307
+ */
308
+ trigger<TPayload = unknown>(workflowId: string, payload: TPayload, options?: TriggerOptions): Promise<TriggerResult>;
309
+ /**
310
+ * Subscribe to a run's real-time updates via SSE or WebSocket
311
+ */
312
+ subscribeToRun<TPayload = unknown, TResult = unknown>(runId: string, options: SubscribeOptions<TPayload, TResult>): Unsubscribe;
313
+ /**
314
+ * Subscribe using RealtimeConnection with SSE/WebSocket fallback
315
+ */
316
+ private subscribeWithRealtimeConnection;
317
+ /**
318
+ * Derive WebSocket URL from HTTP URL
319
+ */
320
+ private deriveWebSocketUrl;
321
+ /**
322
+ * Stream a workflow execution (trigger + stream events)
323
+ */
324
+ stream<TPayload = unknown, TResult = unknown>(workflowId: string, payload: TPayload, options?: StreamOptions): AsyncGenerator<StreamEvent, void, unknown>;
325
+ /**
326
+ * Get a run by ID
327
+ */
328
+ getRun<TPayload = unknown, TResult = unknown>(runId: string, options?: {
329
+ accessToken?: string;
330
+ }): Promise<Execution<TPayload, TResult> | null>;
331
+ /**
332
+ * Get execution by ID
333
+ */
334
+ getExecution<TPayload = unknown, TResult = unknown>(executionId: string): Promise<Execution<TPayload, TResult> | null>;
335
+ /**
336
+ * List runs with optional filters
337
+ */
338
+ listRuns(options?: ListRunsOptions): Promise<PaginatedResult<Execution>>;
339
+ /**
340
+ * Notify an event (for waitForEvent)
341
+ */
342
+ notify(eventId: string, data: unknown): Promise<NotifyResult>;
343
+ /**
344
+ * Create a public access token for a run
345
+ */
346
+ createAccessToken(runId: string): Promise<{
347
+ token: string;
348
+ expiresAt: Date;
349
+ }>;
350
+ /**
351
+ * Health check
352
+ */
353
+ health(): Promise<{
354
+ ok: boolean;
355
+ }>;
356
+ /**
357
+ * Internal fetch helper
358
+ */
359
+ private fetch;
360
+ /**
361
+ * Get auth headers
362
+ */
363
+ private getAuthHeaders;
364
+ }
365
+
366
+ export { type Execution, type ExecutionError, type ExecutionStatus, type ListRunsOptions, LocalStorageTokenStorage, MemoryTokenStorage, type NotifyResult, type PaginatedResult, RealtimeConnection, type RealtimeConnectionConfig, type RealtimeEvent, type RealtimeStrategy, type StepExecution, StepflowClient, type StepflowClientConfig, StepflowError, type StreamEvent, type StreamOptions, type SubscribeOptions, TokenManager, type TokenManagerConfig, type TokenStorage, type TriggerOptions, type TriggerResult, type Unsubscribe, StepflowClient as default };
package/dist/index.js ADDED
@@ -0,0 +1,746 @@
1
+ // src/index.ts
2
+ import { EventSourcePolyfill as EventSourcePolyfill2 } from "event-source-polyfill";
3
+
4
+ // src/realtime.ts
5
+ import { EventSourcePolyfill } from "event-source-polyfill";
6
+ var RealtimeConnection = class {
7
+ config;
8
+ eventSource = null;
9
+ webSocket = null;
10
+ activeStrategy = null;
11
+ reconnectCount = 0;
12
+ reconnectTimeout = null;
13
+ connectionTimeout = null;
14
+ isManualDisconnect = false;
15
+ constructor(config) {
16
+ this.config = {
17
+ strategy: config.strategy ?? "auto",
18
+ sseUrl: config.sseUrl,
19
+ wsUrl: config.wsUrl,
20
+ headers: config.headers,
21
+ reconnectAttempts: config.reconnectAttempts ?? 3,
22
+ reconnectDelayMs: config.reconnectDelayMs ?? 1e3,
23
+ onConnect: config.onConnect,
24
+ onDisconnect: config.onDisconnect,
25
+ onError: config.onError,
26
+ onMessage: config.onMessage
27
+ };
28
+ }
29
+ /**
30
+ * Connect using the configured strategy
31
+ */
32
+ async connect() {
33
+ this.isManualDisconnect = false;
34
+ this.reconnectCount = 0;
35
+ const strategy = this.config.strategy;
36
+ if (strategy === "sse") {
37
+ await this.connectSSE();
38
+ } else if (strategy === "websocket") {
39
+ await this.connectWebSocket();
40
+ } else {
41
+ await this.connectAuto();
42
+ }
43
+ }
44
+ /**
45
+ * Disconnect from the active connection
46
+ */
47
+ disconnect() {
48
+ this.isManualDisconnect = true;
49
+ this.clearTimeouts();
50
+ this.closeConnections();
51
+ this.activeStrategy = null;
52
+ }
53
+ /**
54
+ * Check if currently connected
55
+ */
56
+ isConnected() {
57
+ if (this.activeStrategy === "sse") {
58
+ return this.eventSource !== null && this.eventSource.readyState === EventSourcePolyfill.OPEN;
59
+ } else if (this.activeStrategy === "websocket") {
60
+ return this.webSocket !== null && this.webSocket.readyState === WebSocket.OPEN;
61
+ }
62
+ return false;
63
+ }
64
+ /**
65
+ * Get the currently active strategy
66
+ */
67
+ getActiveStrategy() {
68
+ return this.activeStrategy;
69
+ }
70
+ // ============================================================================
71
+ // Private Methods - Connection Strategies
72
+ // ============================================================================
73
+ async connectAuto() {
74
+ return new Promise((resolve, reject) => {
75
+ let sseResolved = false;
76
+ let sseError = null;
77
+ this.connectionTimeout = setTimeout(() => {
78
+ if (!sseResolved) {
79
+ sseResolved = true;
80
+ this.closeSSE();
81
+ this.connectWebSocket().then(resolve).catch(reject);
82
+ }
83
+ }, 5e3);
84
+ this.connectSSE().then(() => {
85
+ if (!sseResolved) {
86
+ sseResolved = true;
87
+ if (this.connectionTimeout) {
88
+ clearTimeout(this.connectionTimeout);
89
+ this.connectionTimeout = null;
90
+ }
91
+ resolve();
92
+ }
93
+ }).catch((error) => {
94
+ sseError = error;
95
+ if (!sseResolved) {
96
+ sseResolved = true;
97
+ if (this.connectionTimeout) {
98
+ clearTimeout(this.connectionTimeout);
99
+ this.connectionTimeout = null;
100
+ }
101
+ this.connectWebSocket().then(resolve).catch((wsError) => {
102
+ const combinedError = new Error(
103
+ `Failed to connect via SSE (${sseError?.message}) and WebSocket (${wsError.message})`
104
+ );
105
+ this.config.onError?.(combinedError);
106
+ reject(combinedError);
107
+ });
108
+ }
109
+ });
110
+ });
111
+ }
112
+ async connectSSE() {
113
+ return new Promise((resolve, reject) => {
114
+ try {
115
+ const eventSource = new EventSourcePolyfill(this.config.sseUrl, {
116
+ headers: this.config.headers ?? {}
117
+ });
118
+ eventSource.onopen = () => {
119
+ this.activeStrategy = "sse";
120
+ this.reconnectCount = 0;
121
+ this.config.onConnect?.();
122
+ resolve();
123
+ };
124
+ eventSource.onerror = () => {
125
+ if (this.activeStrategy === null) {
126
+ this.closeSSE();
127
+ reject(new Error("SSE connection failed"));
128
+ } else {
129
+ this.handleDisconnect();
130
+ }
131
+ };
132
+ eventSource.onmessage = (event) => {
133
+ this.handleMessage(event);
134
+ };
135
+ this.setupSSEEventListeners(eventSource);
136
+ this.eventSource = eventSource;
137
+ } catch (error) {
138
+ reject(error);
139
+ }
140
+ });
141
+ }
142
+ setupSSEEventListeners(eventSource) {
143
+ const originalAddEventListener = eventSource.addEventListener.bind(eventSource);
144
+ const eventTypes = [
145
+ "update",
146
+ "step:complete",
147
+ "execution:complete",
148
+ "execution:failed"
149
+ ];
150
+ eventTypes.forEach((type) => {
151
+ originalAddEventListener(type, (event) => {
152
+ this.handleMessage(event);
153
+ });
154
+ });
155
+ }
156
+ async connectWebSocket() {
157
+ return new Promise((resolve, reject) => {
158
+ try {
159
+ const wsUrl = this.config.wsUrl ?? this.deriveWebSocketUrl(this.config.sseUrl);
160
+ const webSocket = new WebSocket(wsUrl);
161
+ webSocket.onopen = () => {
162
+ this.activeStrategy = "websocket";
163
+ this.reconnectCount = 0;
164
+ this.config.onConnect?.();
165
+ resolve();
166
+ };
167
+ webSocket.onerror = () => {
168
+ if (this.activeStrategy === null) {
169
+ this.closeWebSocket();
170
+ reject(new Error("WebSocket connection failed"));
171
+ }
172
+ };
173
+ webSocket.onclose = () => {
174
+ this.handleDisconnect();
175
+ };
176
+ webSocket.onmessage = (event) => {
177
+ try {
178
+ const data = JSON.parse(event.data);
179
+ this.config.onMessage?.({
180
+ type: data.type ?? "message",
181
+ data: data.data ?? data
182
+ });
183
+ } catch (error) {
184
+ this.config.onError?.(
185
+ new Error(
186
+ `Failed to parse WebSocket message: ${error.message}`
187
+ )
188
+ );
189
+ }
190
+ };
191
+ this.webSocket = webSocket;
192
+ } catch (error) {
193
+ reject(error);
194
+ }
195
+ });
196
+ }
197
+ // ============================================================================
198
+ // Private Methods - Event Handling
199
+ // ============================================================================
200
+ handleMessage(event) {
201
+ try {
202
+ const data = typeof event.data === "string" ? JSON.parse(event.data) : event.data;
203
+ this.config.onMessage?.({
204
+ type: event.type ?? "message",
205
+ data
206
+ });
207
+ } catch (error) {
208
+ this.config.onError?.(
209
+ new Error(`Failed to parse message: ${error.message}`)
210
+ );
211
+ }
212
+ }
213
+ handleDisconnect() {
214
+ this.config.onDisconnect?.();
215
+ if (!this.isManualDisconnect && this.reconnectCount < this.config.reconnectAttempts) {
216
+ this.attemptReconnect();
217
+ } else if (!this.isManualDisconnect) {
218
+ this.config.onError?.(new Error("Max reconnection attempts reached"));
219
+ }
220
+ }
221
+ attemptReconnect() {
222
+ this.reconnectCount++;
223
+ const delay = this.config.reconnectDelayMs * Math.pow(2, this.reconnectCount - 1);
224
+ this.reconnectTimeout = setTimeout(() => {
225
+ if (this.activeStrategy === "sse") {
226
+ this.closeSSE();
227
+ this.connectSSE().catch(() => {
228
+ this.handleDisconnect();
229
+ });
230
+ } else if (this.activeStrategy === "websocket") {
231
+ this.closeWebSocket();
232
+ this.connectWebSocket().catch(() => {
233
+ this.handleDisconnect();
234
+ });
235
+ }
236
+ }, delay);
237
+ }
238
+ // ============================================================================
239
+ // Private Methods - Cleanup
240
+ // ============================================================================
241
+ closeConnections() {
242
+ this.closeSSE();
243
+ this.closeWebSocket();
244
+ }
245
+ closeSSE() {
246
+ if (this.eventSource) {
247
+ this.eventSource.close();
248
+ this.eventSource = null;
249
+ }
250
+ }
251
+ closeWebSocket() {
252
+ if (this.webSocket) {
253
+ this.webSocket.close();
254
+ this.webSocket = null;
255
+ }
256
+ }
257
+ clearTimeouts() {
258
+ if (this.reconnectTimeout) {
259
+ clearTimeout(this.reconnectTimeout);
260
+ this.reconnectTimeout = null;
261
+ }
262
+ if (this.connectionTimeout) {
263
+ clearTimeout(this.connectionTimeout);
264
+ this.connectionTimeout = null;
265
+ }
266
+ }
267
+ // ============================================================================
268
+ // Private Methods - Utilities
269
+ // ============================================================================
270
+ deriveWebSocketUrl(sseUrl) {
271
+ const url = new URL(sseUrl);
272
+ url.protocol = url.protocol === "https:" ? "wss:" : "ws:";
273
+ return url.toString();
274
+ }
275
+ };
276
+
277
+ // src/token-manager.ts
278
+ var MemoryTokenStorage = class {
279
+ store = /* @__PURE__ */ new Map();
280
+ async get(key) {
281
+ return this.store.get(key) ?? null;
282
+ }
283
+ async set(key, value) {
284
+ this.store.set(key, value);
285
+ }
286
+ async remove(key) {
287
+ this.store.delete(key);
288
+ }
289
+ };
290
+ var LocalStorageTokenStorage = class {
291
+ async get(key) {
292
+ if (typeof window === "undefined" || !window.localStorage) {
293
+ return null;
294
+ }
295
+ return window.localStorage.getItem(key);
296
+ }
297
+ async set(key, value) {
298
+ if (typeof window === "undefined" || !window.localStorage) {
299
+ return;
300
+ }
301
+ window.localStorage.setItem(key, value);
302
+ }
303
+ async remove(key) {
304
+ if (typeof window === "undefined" || !window.localStorage) {
305
+ return;
306
+ }
307
+ window.localStorage.removeItem(key);
308
+ }
309
+ };
310
+ var TokenManager = class {
311
+ storage;
312
+ storageKeyPrefix;
313
+ refreshThresholdMs;
314
+ onTokenRefresh;
315
+ onTokenExpired;
316
+ refreshTimers = /* @__PURE__ */ new Map();
317
+ constructor(config) {
318
+ this.storage = config?.storage ?? new MemoryTokenStorage();
319
+ this.storageKeyPrefix = config?.storageKeyPrefix ?? "stepflow_token_";
320
+ this.refreshThresholdMs = config?.refreshThresholdMs ?? 3e5;
321
+ this.onTokenRefresh = config?.onTokenRefresh;
322
+ this.onTokenExpired = config?.onTokenExpired;
323
+ }
324
+ /**
325
+ * Store a token with expiry
326
+ */
327
+ async storeToken(runId, token, expiresAt) {
328
+ const stored = {
329
+ token,
330
+ expiresAt: expiresAt.getTime()
331
+ };
332
+ const key = this.getStorageKey(runId);
333
+ await this.storage.set(key, JSON.stringify(stored));
334
+ }
335
+ /**
336
+ * Get a token if it's still valid
337
+ * @returns Token string or null if expired/not found
338
+ */
339
+ async getToken(runId) {
340
+ const key = this.getStorageKey(runId);
341
+ const value = await this.storage.get(key);
342
+ if (!value) {
343
+ return null;
344
+ }
345
+ try {
346
+ const stored = JSON.parse(value);
347
+ const now = Date.now();
348
+ if (stored.expiresAt <= now) {
349
+ await this.removeToken(runId);
350
+ return null;
351
+ }
352
+ return stored.token;
353
+ } catch {
354
+ await this.removeToken(runId);
355
+ return null;
356
+ }
357
+ }
358
+ /**
359
+ * Remove a token from storage
360
+ */
361
+ async removeToken(runId) {
362
+ const key = this.getStorageKey(runId);
363
+ await this.storage.remove(key);
364
+ this.stopAutoRefresh(runId);
365
+ }
366
+ /**
367
+ * Check if a token is valid (exists and not expired)
368
+ */
369
+ async isTokenValid(runId) {
370
+ const token = await this.getToken(runId);
371
+ return token !== null;
372
+ }
373
+ /**
374
+ * Get token expiry date
375
+ * @returns Expiry date or null if not found
376
+ */
377
+ async getTokenExpiry(runId) {
378
+ const key = this.getStorageKey(runId);
379
+ const value = await this.storage.get(key);
380
+ if (!value) {
381
+ return null;
382
+ }
383
+ try {
384
+ const stored = JSON.parse(value);
385
+ return new Date(stored.expiresAt);
386
+ } catch {
387
+ return null;
388
+ }
389
+ }
390
+ /**
391
+ * Start auto-refresh for a token
392
+ */
393
+ startAutoRefresh(runId, refreshFn) {
394
+ this.stopAutoRefresh(runId);
395
+ this.scheduleRefresh(runId, refreshFn);
396
+ }
397
+ /**
398
+ * Stop auto-refresh for a specific token
399
+ */
400
+ stopAutoRefresh(runId) {
401
+ const timer = this.refreshTimers.get(runId);
402
+ if (timer) {
403
+ clearTimeout(timer);
404
+ this.refreshTimers.delete(runId);
405
+ }
406
+ }
407
+ /**
408
+ * Stop all auto-refresh timers
409
+ */
410
+ stopAllAutoRefresh() {
411
+ for (const timer of this.refreshTimers.values()) {
412
+ clearTimeout(timer);
413
+ }
414
+ this.refreshTimers.clear();
415
+ }
416
+ /**
417
+ * Schedule a refresh based on token expiry
418
+ */
419
+ async scheduleRefresh(runId, refreshFn) {
420
+ const expiry = await this.getTokenExpiry(runId);
421
+ if (!expiry) {
422
+ return;
423
+ }
424
+ const now = Date.now();
425
+ const expiryTime = expiry.getTime();
426
+ const refreshTime = expiryTime - this.refreshThresholdMs;
427
+ const delay = Math.max(0, refreshTime - now);
428
+ const timer = setTimeout(async () => {
429
+ try {
430
+ const { token, expiresAt } = await refreshFn();
431
+ await this.storeToken(runId, token, expiresAt);
432
+ this.onTokenRefresh?.(runId, token);
433
+ this.scheduleRefresh(runId, refreshFn);
434
+ } catch (error) {
435
+ this.onTokenExpired?.(runId);
436
+ this.stopAutoRefresh(runId);
437
+ }
438
+ }, delay);
439
+ this.refreshTimers.set(runId, timer);
440
+ }
441
+ /**
442
+ * Get storage key for a run ID
443
+ */
444
+ getStorageKey(runId) {
445
+ return `${this.storageKeyPrefix}${runId}`;
446
+ }
447
+ };
448
+
449
+ // src/index.ts
450
+ var StepflowError = class extends Error {
451
+ constructor(message, code, status) {
452
+ super(message);
453
+ this.code = code;
454
+ this.status = status;
455
+ this.name = "StepflowError";
456
+ }
457
+ };
458
+ var StepflowClient = class {
459
+ constructor(config) {
460
+ this.config = config;
461
+ }
462
+ /**
463
+ * Trigger a workflow execution
464
+ */
465
+ async trigger(workflowId, payload, options) {
466
+ const response = await this.fetch(`/workflows/${workflowId}/trigger`, {
467
+ method: "POST",
468
+ body: JSON.stringify({ payload, ...options })
469
+ });
470
+ return await response.json();
471
+ }
472
+ /**
473
+ * Subscribe to a run's real-time updates via SSE or WebSocket
474
+ */
475
+ subscribeToRun(runId, options) {
476
+ const {
477
+ accessToken,
478
+ throttleMs,
479
+ strategy,
480
+ onUpdate,
481
+ onStepComplete,
482
+ onComplete,
483
+ onError,
484
+ onConnect,
485
+ onDisconnect
486
+ } = options;
487
+ if (strategy) {
488
+ return this.subscribeWithRealtimeConnection(runId, {
489
+ accessToken,
490
+ throttleMs,
491
+ strategy,
492
+ onUpdate,
493
+ onStepComplete,
494
+ onComplete,
495
+ onError,
496
+ onConnect,
497
+ onDisconnect
498
+ });
499
+ }
500
+ const url = new URL(`${this.config.baseUrl}/runs/${runId}/stream`);
501
+ if (accessToken) {
502
+ url.searchParams.set("token", accessToken);
503
+ }
504
+ if (throttleMs) {
505
+ url.searchParams.set("throttle", String(throttleMs));
506
+ }
507
+ const headers = {
508
+ Accept: "text/event-stream",
509
+ ...this.getAuthHeaders(accessToken)
510
+ };
511
+ const eventSource = new EventSourcePolyfill2(url.toString(), { headers });
512
+ eventSource.onopen = () => {
513
+ onConnect?.();
514
+ };
515
+ eventSource.onerror = () => {
516
+ onDisconnect?.();
517
+ };
518
+ eventSource.addEventListener("update", (event) => {
519
+ const data = JSON.parse(event.data);
520
+ onUpdate?.(data);
521
+ });
522
+ eventSource.addEventListener("step:complete", (event) => {
523
+ const data = JSON.parse(event.data);
524
+ onStepComplete?.(data);
525
+ });
526
+ eventSource.addEventListener("execution:complete", (event) => {
527
+ const data = JSON.parse(event.data);
528
+ onComplete?.(data.result);
529
+ });
530
+ eventSource.addEventListener("execution:failed", (event) => {
531
+ const data = JSON.parse(event.data);
532
+ onError?.(new Error(data.error.message));
533
+ });
534
+ return () => {
535
+ eventSource.close();
536
+ };
537
+ }
538
+ /**
539
+ * Subscribe using RealtimeConnection with SSE/WebSocket fallback
540
+ */
541
+ subscribeWithRealtimeConnection(runId, options) {
542
+ const {
543
+ accessToken,
544
+ throttleMs,
545
+ strategy,
546
+ onUpdate,
547
+ onStepComplete,
548
+ onComplete,
549
+ onError,
550
+ onConnect,
551
+ onDisconnect
552
+ } = options;
553
+ const url = new URL(`${this.config.baseUrl}/runs/${runId}/stream`);
554
+ if (accessToken) {
555
+ url.searchParams.set("token", accessToken);
556
+ }
557
+ if (throttleMs) {
558
+ url.searchParams.set("throttle", String(throttleMs));
559
+ }
560
+ const headers = {
561
+ Accept: "text/event-stream",
562
+ ...this.getAuthHeaders(accessToken)
563
+ };
564
+ const wsUrl = this.config.wsUrl ?? this.deriveWebSocketUrl(url.toString());
565
+ const connection = new RealtimeConnection({
566
+ strategy,
567
+ sseUrl: url.toString(),
568
+ wsUrl,
569
+ headers,
570
+ onConnect,
571
+ onDisconnect,
572
+ onError,
573
+ onMessage: (event) => {
574
+ if (event.type === "update") {
575
+ onUpdate?.(event.data);
576
+ } else if (event.type === "step:complete") {
577
+ onStepComplete?.(event.data);
578
+ } else if (event.type === "execution:complete") {
579
+ const data = event.data;
580
+ onComplete?.(data.result);
581
+ } else if (event.type === "execution:failed") {
582
+ const data = event.data;
583
+ onError?.(new Error(data.error.message));
584
+ }
585
+ }
586
+ });
587
+ connection.connect().catch((error) => {
588
+ onError?.(error);
589
+ });
590
+ return () => {
591
+ connection.disconnect();
592
+ };
593
+ }
594
+ /**
595
+ * Derive WebSocket URL from HTTP URL
596
+ */
597
+ deriveWebSocketUrl(httpUrl) {
598
+ const url = new URL(httpUrl);
599
+ url.protocol = url.protocol === "https:" ? "wss:" : "ws:";
600
+ return url.toString();
601
+ }
602
+ /**
603
+ * Stream a workflow execution (trigger + stream events)
604
+ */
605
+ async *stream(workflowId, payload, options) {
606
+ const response = await this.fetch(`/workflows/${workflowId}/stream`, {
607
+ method: "POST",
608
+ body: JSON.stringify({ payload }),
609
+ signal: options?.signal
610
+ });
611
+ if (!response.body) {
612
+ throw new StepflowError("No response body");
613
+ }
614
+ const reader = response.body.getReader();
615
+ const decoder = new TextDecoder();
616
+ let buffer = "";
617
+ while (true) {
618
+ const { done, value } = await reader.read();
619
+ if (done) break;
620
+ buffer += decoder.decode(value, { stream: true });
621
+ const lines = buffer.split("\n");
622
+ buffer = lines.pop() || "";
623
+ for (const line of lines) {
624
+ if (line.startsWith("data: ")) {
625
+ try {
626
+ const data = JSON.parse(line.slice(6));
627
+ yield data;
628
+ } catch {
629
+ }
630
+ }
631
+ }
632
+ }
633
+ }
634
+ /**
635
+ * Get a run by ID
636
+ */
637
+ async getRun(runId, options) {
638
+ const response = await this.fetch(`/runs/${runId}`, {
639
+ headers: this.getAuthHeaders(options?.accessToken)
640
+ });
641
+ if (response.status === 404) {
642
+ return null;
643
+ }
644
+ return await response.json();
645
+ }
646
+ /**
647
+ * Get execution by ID
648
+ */
649
+ async getExecution(executionId) {
650
+ const response = await this.fetch(`/executions/${executionId}`);
651
+ if (response.status === 404) {
652
+ return null;
653
+ }
654
+ return await response.json();
655
+ }
656
+ /**
657
+ * List runs with optional filters
658
+ */
659
+ async listRuns(options) {
660
+ const params = new URLSearchParams();
661
+ if (options?.workflowId) params.set("workflowId", options.workflowId);
662
+ if (options?.status) params.set("status", options.status);
663
+ if (options?.limit) params.set("limit", String(options.limit));
664
+ if (options?.offset) params.set("offset", String(options.offset));
665
+ const response = await this.fetch(`/runs?${params}`);
666
+ return await response.json();
667
+ }
668
+ /**
669
+ * Notify an event (for waitForEvent)
670
+ */
671
+ async notify(eventId, data) {
672
+ const response = await this.fetch(`/events/${eventId}/notify`, {
673
+ method: "POST",
674
+ body: JSON.stringify({ data })
675
+ });
676
+ return await response.json();
677
+ }
678
+ /**
679
+ * Create a public access token for a run
680
+ */
681
+ async createAccessToken(runId) {
682
+ const response = await this.fetch(`/runs/${runId}/token`, {
683
+ method: "POST"
684
+ });
685
+ return await response.json();
686
+ }
687
+ /**
688
+ * Health check
689
+ */
690
+ async health() {
691
+ const response = await this.fetch("/health");
692
+ return await response.json();
693
+ }
694
+ /**
695
+ * Internal fetch helper
696
+ */
697
+ async fetch(path, options = {}) {
698
+ const url = `${this.config.baseUrl}${path}`;
699
+ const headers = {
700
+ "Content-Type": "application/json",
701
+ ...this.getAuthHeaders(),
702
+ ...options.headers
703
+ };
704
+ const response = await fetch(url, { ...options, headers });
705
+ if (!response.ok && response.status !== 404) {
706
+ let errorData = {};
707
+ try {
708
+ errorData = await response.json();
709
+ } catch {
710
+ errorData = { message: response.statusText };
711
+ }
712
+ throw new StepflowError(
713
+ errorData.message || "Request failed",
714
+ errorData.code,
715
+ response.status
716
+ );
717
+ }
718
+ return response;
719
+ }
720
+ /**
721
+ * Get auth headers
722
+ */
723
+ getAuthHeaders(accessToken) {
724
+ if (accessToken) {
725
+ return { Authorization: `Bearer ${accessToken}` };
726
+ }
727
+ if (this.config.apiKey) {
728
+ return { "X-API-Key": this.config.apiKey };
729
+ }
730
+ if (this.config.publicApiKey) {
731
+ return { "X-Public-Key": this.config.publicApiKey };
732
+ }
733
+ return {};
734
+ }
735
+ };
736
+ var index_default = StepflowClient;
737
+ export {
738
+ LocalStorageTokenStorage,
739
+ MemoryTokenStorage,
740
+ RealtimeConnection,
741
+ StepflowClient,
742
+ StepflowError,
743
+ TokenManager,
744
+ index_default as default
745
+ };
746
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/realtime.ts","../src/token-manager.ts"],"sourcesContent":["// ============================================================================\n// Stepflow TypeScript Client\n// ============================================================================\n\nimport { EventSourcePolyfill } from \"event-source-polyfill\";\nimport type { RealtimeStrategy } from \"./realtime.js\";\nimport { RealtimeConnection } from \"./realtime.js\";\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface StepflowClientConfig {\n /**\n * Base URL of the Stepflow API\n */\n baseUrl: string;\n\n /**\n * API key for server-side requests\n */\n apiKey?: string;\n\n /**\n * Public API key for client-side requests\n */\n publicApiKey?: string;\n\n /**\n * WebSocket URL for real-time updates\n */\n wsUrl?: string;\n}\n\nexport type ExecutionStatus =\n | \"pending\"\n | \"running\"\n | \"completed\"\n | \"failed\"\n | \"waiting\"\n | \"sleeping\"\n | \"cancelled\";\n\nexport interface Execution<TPayload = unknown, TResult = unknown> {\n id: string;\n runId: string;\n workflowId: string;\n eventName: string;\n payload: TPayload;\n status: ExecutionStatus;\n result?: TResult;\n error?: ExecutionError;\n steps: StepExecution[];\n metadata: Record<string, unknown>;\n attempt: number;\n startedAt: Date;\n completedAt?: Date;\n}\n\nexport interface ExecutionError {\n name: string;\n message: string;\n stack?: string;\n code?: string;\n}\n\nexport interface StepExecution {\n name: string;\n status: \"pending\" | \"running\" | \"completed\" | \"failed\" | \"cached\";\n result?: unknown;\n error?: ExecutionError;\n startedAt?: Date;\n completedAt?: Date;\n durationMs?: number;\n}\n\nexport interface TriggerResult {\n runId: string;\n executionId: string;\n publicAccessToken: string;\n}\n\nexport interface NotifyResult {\n waiters: number;\n executions: string[];\n}\n\nexport interface TriggerOptions {\n runId?: string;\n metadata?: Record<string, unknown>;\n delay?: number;\n}\n\nexport interface SubscribeOptions<TPayload = unknown, TResult = unknown> {\n accessToken?: string;\n throttleMs?: number;\n strategy?: RealtimeStrategy;\n onUpdate?: (run: Execution<TPayload, TResult>) => void;\n onStepComplete?: (step: StepExecution) => void;\n onComplete?: (result: TResult) => void;\n onError?: (error: Error) => void;\n onConnect?: () => void;\n onDisconnect?: () => void;\n}\n\nexport interface StreamOptions {\n signal?: AbortSignal;\n}\n\nexport interface StreamEvent {\n type: string;\n data: unknown;\n stepName?: string;\n}\n\nexport interface ListRunsOptions {\n workflowId?: string;\n status?: ExecutionStatus;\n limit?: number;\n offset?: number;\n}\n\nexport interface PaginatedResult<T> {\n data: T[];\n total: number;\n limit: number;\n offset: number;\n}\n\nexport type Unsubscribe = () => void;\n\n// ============================================================================\n// Client Error\n// ============================================================================\n\nexport class StepflowError extends Error {\n constructor(\n message: string,\n public readonly code?: string,\n public readonly status?: number,\n ) {\n super(message);\n this.name = \"StepflowError\";\n }\n}\n\n// ============================================================================\n// Client Implementation\n// ============================================================================\n\nexport class StepflowClient {\n constructor(private config: StepflowClientConfig) {}\n\n /**\n * Trigger a workflow execution\n */\n async trigger<TPayload = unknown>(\n workflowId: string,\n payload: TPayload,\n options?: TriggerOptions,\n ): Promise<TriggerResult> {\n const response = await this.fetch(`/workflows/${workflowId}/trigger`, {\n method: \"POST\",\n body: JSON.stringify({ payload, ...options }),\n });\n\n return (await response.json()) as TriggerResult;\n }\n\n /**\n * Subscribe to a run's real-time updates via SSE or WebSocket\n */\n subscribeToRun<TPayload = unknown, TResult = unknown>(\n runId: string,\n options: SubscribeOptions<TPayload, TResult>,\n ): Unsubscribe {\n const {\n accessToken,\n throttleMs,\n strategy,\n onUpdate,\n onStepComplete,\n onComplete,\n onError,\n onConnect,\n onDisconnect,\n } = options;\n\n // If strategy is provided, use RealtimeConnection\n if (strategy) {\n return this.subscribeWithRealtimeConnection(runId, {\n accessToken,\n throttleMs,\n strategy,\n onUpdate,\n onStepComplete,\n onComplete,\n onError,\n onConnect,\n onDisconnect,\n });\n }\n\n // Default behavior: use EventSource directly (backward compatibility)\n const url = new URL(`${this.config.baseUrl}/runs/${runId}/stream`);\n if (accessToken) {\n url.searchParams.set(\"token\", accessToken);\n }\n if (throttleMs) {\n url.searchParams.set(\"throttle\", String(throttleMs));\n }\n\n const headers: Record<string, string> = {\n Accept: \"text/event-stream\",\n ...this.getAuthHeaders(accessToken),\n };\n\n const eventSource = new EventSourcePolyfill(url.toString(), { headers });\n\n eventSource.onopen = () => {\n onConnect?.();\n };\n\n eventSource.onerror = () => {\n onDisconnect?.();\n };\n\n // Type-safe event listeners using any to bypass EventSource typing issues\n eventSource.addEventListener(\"update\", (event: any) => {\n const data = JSON.parse(event.data) as Execution<TPayload, TResult>;\n onUpdate?.(data);\n });\n\n eventSource.addEventListener(\"step:complete\", (event: any) => {\n const data = JSON.parse(event.data) as StepExecution;\n onStepComplete?.(data);\n });\n\n eventSource.addEventListener(\"execution:complete\", (event: any) => {\n const data = JSON.parse(event.data) as { result: TResult };\n onComplete?.(data.result);\n });\n\n eventSource.addEventListener(\"execution:failed\", (event: any) => {\n const data = JSON.parse(event.data) as { error: { message: string } };\n onError?.(new Error(data.error.message));\n });\n\n return () => {\n eventSource.close();\n };\n }\n\n /**\n * Subscribe using RealtimeConnection with SSE/WebSocket fallback\n */\n private subscribeWithRealtimeConnection<\n TPayload = unknown,\n TResult = unknown,\n >(\n runId: string,\n options: Required<Pick<SubscribeOptions<TPayload, TResult>, \"strategy\">> &\n SubscribeOptions<TPayload, TResult>,\n ): Unsubscribe {\n const {\n accessToken,\n throttleMs,\n strategy,\n onUpdate,\n onStepComplete,\n onComplete,\n onError,\n onConnect,\n onDisconnect,\n } = options;\n\n const url = new URL(`${this.config.baseUrl}/runs/${runId}/stream`);\n if (accessToken) {\n url.searchParams.set(\"token\", accessToken);\n }\n if (throttleMs) {\n url.searchParams.set(\"throttle\", String(throttleMs));\n }\n\n const headers: Record<string, string> = {\n Accept: \"text/event-stream\",\n ...this.getAuthHeaders(accessToken),\n };\n\n // Derive WebSocket URL from config or SSE URL\n const wsUrl = this.config.wsUrl ?? this.deriveWebSocketUrl(url.toString());\n\n const connection = new RealtimeConnection({\n strategy,\n sseUrl: url.toString(),\n wsUrl,\n headers,\n onConnect,\n onDisconnect,\n onError,\n onMessage: (event) => {\n // Route events to appropriate handlers\n if (event.type === \"update\") {\n onUpdate?.(event.data as Execution<TPayload, TResult>);\n } else if (event.type === \"step:complete\") {\n onStepComplete?.(event.data as StepExecution);\n } else if (event.type === \"execution:complete\") {\n const data = event.data as { result: TResult };\n onComplete?.(data.result);\n } else if (event.type === \"execution:failed\") {\n const data = event.data as { error: { message: string } };\n onError?.(new Error(data.error.message));\n }\n },\n });\n\n // Connect asynchronously\n connection.connect().catch((error) => {\n onError?.(error as Error);\n });\n\n return () => {\n connection.disconnect();\n };\n }\n\n /**\n * Derive WebSocket URL from HTTP URL\n */\n private deriveWebSocketUrl(httpUrl: string): string {\n const url = new URL(httpUrl);\n url.protocol = url.protocol === \"https:\" ? \"wss:\" : \"ws:\";\n return url.toString();\n }\n\n /**\n * Stream a workflow execution (trigger + stream events)\n */\n async *stream<TPayload = unknown, TResult = unknown>(\n workflowId: string,\n payload: TPayload,\n options?: StreamOptions,\n ): AsyncGenerator<StreamEvent, void, unknown> {\n const response = await this.fetch(`/workflows/${workflowId}/stream`, {\n method: \"POST\",\n body: JSON.stringify({ payload }),\n signal: options?.signal,\n });\n\n if (!response.body) {\n throw new StepflowError(\"No response body\");\n }\n\n const reader = response.body.getReader();\n const decoder = new TextDecoder();\n let buffer = \"\";\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split(\"\\n\");\n buffer = lines.pop() || \"\";\n\n for (const line of lines) {\n if (line.startsWith(\"data: \")) {\n try {\n const data = JSON.parse(line.slice(6));\n yield data as StreamEvent;\n } catch {\n // Skip malformed events\n }\n }\n }\n }\n }\n\n /**\n * Get a run by ID\n */\n async getRun<TPayload = unknown, TResult = unknown>(\n runId: string,\n options?: { accessToken?: string },\n ): Promise<Execution<TPayload, TResult> | null> {\n const response = await this.fetch(`/runs/${runId}`, {\n headers: this.getAuthHeaders(options?.accessToken),\n });\n\n if (response.status === 404) {\n return null;\n }\n\n return (await response.json()) as Execution<TPayload, TResult>;\n }\n\n /**\n * Get execution by ID\n */\n async getExecution<TPayload = unknown, TResult = unknown>(\n executionId: string,\n ): Promise<Execution<TPayload, TResult> | null> {\n const response = await this.fetch(`/executions/${executionId}`);\n\n if (response.status === 404) {\n return null;\n }\n\n return (await response.json()) as Execution<TPayload, TResult>;\n }\n\n /**\n * List runs with optional filters\n */\n async listRuns(\n options?: ListRunsOptions,\n ): Promise<PaginatedResult<Execution>> {\n const params = new URLSearchParams();\n if (options?.workflowId) params.set(\"workflowId\", options.workflowId);\n if (options?.status) params.set(\"status\", options.status);\n if (options?.limit) params.set(\"limit\", String(options.limit));\n if (options?.offset) params.set(\"offset\", String(options.offset));\n\n const response = await this.fetch(`/runs?${params}`);\n return (await response.json()) as PaginatedResult<Execution>;\n }\n\n /**\n * Notify an event (for waitForEvent)\n */\n async notify(eventId: string, data: unknown): Promise<NotifyResult> {\n const response = await this.fetch(`/events/${eventId}/notify`, {\n method: \"POST\",\n body: JSON.stringify({ data }),\n });\n return (await response.json()) as NotifyResult;\n }\n\n /**\n * Create a public access token for a run\n */\n async createAccessToken(\n runId: string,\n ): Promise<{ token: string; expiresAt: Date }> {\n const response = await this.fetch(`/runs/${runId}/token`, {\n method: \"POST\",\n });\n return (await response.json()) as { token: string; expiresAt: Date };\n }\n\n /**\n * Health check\n */\n async health(): Promise<{ ok: boolean }> {\n const response = await this.fetch(\"/health\");\n return (await response.json()) as { ok: boolean };\n }\n\n /**\n * Internal fetch helper\n */\n private async fetch(\n path: string,\n options: RequestInit = {},\n ): Promise<Response> {\n const url = `${this.config.baseUrl}${path}`;\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n ...this.getAuthHeaders(),\n ...(options.headers as Record<string, string>),\n };\n\n const response = await fetch(url, { ...options, headers });\n\n if (!response.ok && response.status !== 404) {\n let errorData: { message?: string; code?: string } = {};\n try {\n errorData = (await response.json()) as {\n message?: string;\n code?: string;\n };\n } catch {\n errorData = { message: response.statusText };\n }\n\n throw new StepflowError(\n errorData.message || \"Request failed\",\n errorData.code,\n response.status,\n );\n }\n\n return response;\n }\n\n /**\n * Get auth headers\n */\n private getAuthHeaders(accessToken?: string): Record<string, string> {\n if (accessToken) {\n return { Authorization: `Bearer ${accessToken}` };\n }\n if (this.config.apiKey) {\n return { \"X-API-Key\": this.config.apiKey };\n }\n if (this.config.publicApiKey) {\n return { \"X-Public-Key\": this.config.publicApiKey };\n }\n return {};\n }\n}\n\n// ============================================================================\n// Token Manager Exports\n// ============================================================================\n\nexport {\n TokenManager,\n MemoryTokenStorage,\n LocalStorageTokenStorage,\n} from \"./token-manager.js\";\n\nexport type { TokenStorage, TokenManagerConfig } from \"./token-manager.js\";\n\n// ============================================================================\n// Realtime Connection Exports\n// ============================================================================\n\nexport { RealtimeConnection } from \"./realtime.js\";\n\nexport type {\n RealtimeConnectionConfig,\n RealtimeEvent,\n RealtimeStrategy,\n} from \"./realtime.js\";\n\n// Default export\nexport default StepflowClient;\n","// ============================================================================\n// Realtime Connection - SSE/WebSocket Fallback Strategy\n// ============================================================================\n\nimport { EventSourcePolyfill } from \"event-source-polyfill\";\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport type RealtimeStrategy = \"sse\" | \"websocket\" | \"auto\";\n\nexport interface RealtimeEvent {\n type: string;\n data: unknown;\n}\n\nexport interface RealtimeConnectionConfig {\n /**\n * Connection strategy\n * @default 'auto'\n */\n strategy?: RealtimeStrategy;\n\n /**\n * SSE endpoint URL\n */\n sseUrl: string;\n\n /**\n * WebSocket endpoint URL (optional, derived from sseUrl if not provided)\n */\n wsUrl?: string;\n\n /**\n * HTTP headers for SSE connection\n */\n headers?: Record<string, string>;\n\n /**\n * Number of reconnection attempts\n * @default 3\n */\n reconnectAttempts?: number;\n\n /**\n * Delay between reconnection attempts in milliseconds\n * @default 1000\n */\n reconnectDelayMs?: number;\n\n /**\n * Called when connection is established\n */\n onConnect?: () => void;\n\n /**\n * Called when connection is closed\n */\n onDisconnect?: () => void;\n\n /**\n * Called when an error occurs\n */\n onError?: (error: Error) => void;\n\n /**\n * Called when a message is received\n */\n onMessage?: (event: RealtimeEvent) => void;\n}\n\n// ============================================================================\n// RealtimeConnection Implementation\n// ============================================================================\n\nexport class RealtimeConnection {\n private config: Required<\n Omit<\n RealtimeConnectionConfig,\n | \"wsUrl\"\n | \"headers\"\n | \"onConnect\"\n | \"onDisconnect\"\n | \"onError\"\n | \"onMessage\"\n >\n > &\n Pick<\n RealtimeConnectionConfig,\n | \"wsUrl\"\n | \"headers\"\n | \"onConnect\"\n | \"onDisconnect\"\n | \"onError\"\n | \"onMessage\"\n >;\n\n private eventSource: EventSourcePolyfill | null = null;\n private webSocket: WebSocket | null = null;\n private activeStrategy: \"sse\" | \"websocket\" | null = null;\n private reconnectCount = 0;\n private reconnectTimeout: ReturnType<typeof setTimeout> | null = null;\n private connectionTimeout: ReturnType<typeof setTimeout> | null = null;\n private isManualDisconnect = false;\n\n constructor(config: RealtimeConnectionConfig) {\n this.config = {\n strategy: config.strategy ?? \"auto\",\n sseUrl: config.sseUrl,\n wsUrl: config.wsUrl,\n headers: config.headers,\n reconnectAttempts: config.reconnectAttempts ?? 3,\n reconnectDelayMs: config.reconnectDelayMs ?? 1000,\n onConnect: config.onConnect,\n onDisconnect: config.onDisconnect,\n onError: config.onError,\n onMessage: config.onMessage,\n };\n }\n\n /**\n * Connect using the configured strategy\n */\n async connect(): Promise<void> {\n this.isManualDisconnect = false;\n this.reconnectCount = 0;\n\n const strategy = this.config.strategy;\n\n if (strategy === \"sse\") {\n await this.connectSSE();\n } else if (strategy === \"websocket\") {\n await this.connectWebSocket();\n } else {\n // Auto strategy: try SSE first, fallback to WebSocket\n await this.connectAuto();\n }\n }\n\n /**\n * Disconnect from the active connection\n */\n disconnect(): void {\n this.isManualDisconnect = true;\n this.clearTimeouts();\n this.closeConnections();\n this.activeStrategy = null;\n }\n\n /**\n * Check if currently connected\n */\n isConnected(): boolean {\n if (this.activeStrategy === \"sse\") {\n return (\n this.eventSource !== null &&\n this.eventSource.readyState === EventSourcePolyfill.OPEN\n );\n } else if (this.activeStrategy === \"websocket\") {\n return (\n this.webSocket !== null && this.webSocket.readyState === WebSocket.OPEN\n );\n }\n return false;\n }\n\n /**\n * Get the currently active strategy\n */\n getActiveStrategy(): \"sse\" | \"websocket\" | null {\n return this.activeStrategy;\n }\n\n // ============================================================================\n // Private Methods - Connection Strategies\n // ============================================================================\n\n private async connectAuto(): Promise<void> {\n return new Promise((resolve, reject) => {\n let sseResolved = false;\n let sseError: Error | null = null;\n\n // Set a timeout for SSE connection\n this.connectionTimeout = setTimeout(() => {\n if (!sseResolved) {\n sseResolved = true;\n // SSE failed to connect in time, try WebSocket\n this.closeSSE();\n this.connectWebSocket().then(resolve).catch(reject);\n }\n }, 5000);\n\n // Try SSE first\n this.connectSSE()\n .then(() => {\n if (!sseResolved) {\n sseResolved = true;\n if (this.connectionTimeout) {\n clearTimeout(this.connectionTimeout);\n this.connectionTimeout = null;\n }\n resolve();\n }\n })\n .catch((error) => {\n sseError = error as Error;\n if (!sseResolved) {\n sseResolved = true;\n if (this.connectionTimeout) {\n clearTimeout(this.connectionTimeout);\n this.connectionTimeout = null;\n }\n // SSE failed, try WebSocket\n this.connectWebSocket()\n .then(resolve)\n .catch((wsError) => {\n // Both failed\n const combinedError = new Error(\n `Failed to connect via SSE (${sseError?.message}) and WebSocket (${(wsError as Error).message})`,\n );\n this.config.onError?.(combinedError);\n reject(combinedError);\n });\n }\n });\n });\n }\n\n private async connectSSE(): Promise<void> {\n return new Promise((resolve, reject) => {\n try {\n const eventSource = new EventSourcePolyfill(this.config.sseUrl, {\n headers: this.config.headers ?? {},\n });\n\n eventSource.onopen = () => {\n this.activeStrategy = \"sse\";\n this.reconnectCount = 0;\n this.config.onConnect?.();\n resolve();\n };\n\n eventSource.onerror = () => {\n if (this.activeStrategy === null) {\n // Connection failed before opening\n this.closeSSE();\n reject(new Error(\"SSE connection failed\"));\n } else {\n // Connection was open but now errored\n this.handleDisconnect();\n }\n };\n\n eventSource.onmessage = (event: any) => {\n this.handleMessage(event);\n };\n\n // Listen for custom events\n this.setupSSEEventListeners(eventSource);\n\n this.eventSource = eventSource;\n } catch (error) {\n reject(error);\n }\n });\n }\n\n private setupSSEEventListeners(eventSource: EventSourcePolyfill): void {\n // Generic event listener for all custom events\n const originalAddEventListener =\n eventSource.addEventListener.bind(eventSource);\n\n // Listen for common event types\n const eventTypes = [\n \"update\",\n \"step:complete\",\n \"execution:complete\",\n \"execution:failed\",\n ];\n\n eventTypes.forEach((type) => {\n originalAddEventListener(type, (event: any) => {\n this.handleMessage(event);\n });\n });\n }\n\n private async connectWebSocket(): Promise<void> {\n return new Promise((resolve, reject) => {\n try {\n // Derive WebSocket URL from SSE URL if not provided\n const wsUrl =\n this.config.wsUrl ?? this.deriveWebSocketUrl(this.config.sseUrl);\n\n const webSocket = new WebSocket(wsUrl);\n\n webSocket.onopen = () => {\n this.activeStrategy = \"websocket\";\n this.reconnectCount = 0;\n this.config.onConnect?.();\n resolve();\n };\n\n webSocket.onerror = () => {\n if (this.activeStrategy === null) {\n // Connection failed before opening\n this.closeWebSocket();\n reject(new Error(\"WebSocket connection failed\"));\n }\n };\n\n webSocket.onclose = () => {\n this.handleDisconnect();\n };\n\n webSocket.onmessage = (event) => {\n try {\n const data = JSON.parse(event.data);\n this.config.onMessage?.({\n type: data.type ?? \"message\",\n data: data.data ?? data,\n });\n } catch (error) {\n this.config.onError?.(\n new Error(\n `Failed to parse WebSocket message: ${(error as Error).message}`,\n ),\n );\n }\n };\n\n this.webSocket = webSocket;\n } catch (error) {\n reject(error);\n }\n });\n }\n\n // ============================================================================\n // Private Methods - Event Handling\n // ============================================================================\n\n private handleMessage(event: any): void {\n try {\n const data =\n typeof event.data === \"string\" ? JSON.parse(event.data) : event.data;\n this.config.onMessage?.({\n type: event.type ?? \"message\",\n data,\n });\n } catch (error) {\n this.config.onError?.(\n new Error(`Failed to parse message: ${(error as Error).message}`),\n );\n }\n }\n\n private handleDisconnect(): void {\n this.config.onDisconnect?.();\n\n if (\n !this.isManualDisconnect &&\n this.reconnectCount < this.config.reconnectAttempts\n ) {\n this.attemptReconnect();\n } else if (!this.isManualDisconnect) {\n this.config.onError?.(new Error(\"Max reconnection attempts reached\"));\n }\n }\n\n private attemptReconnect(): void {\n this.reconnectCount++;\n const delay =\n this.config.reconnectDelayMs * Math.pow(2, this.reconnectCount - 1); // Exponential backoff\n\n this.reconnectTimeout = setTimeout(() => {\n if (this.activeStrategy === \"sse\") {\n this.closeSSE();\n this.connectSSE().catch(() => {\n this.handleDisconnect();\n });\n } else if (this.activeStrategy === \"websocket\") {\n this.closeWebSocket();\n this.connectWebSocket().catch(() => {\n this.handleDisconnect();\n });\n }\n }, delay);\n }\n\n // ============================================================================\n // Private Methods - Cleanup\n // ============================================================================\n\n private closeConnections(): void {\n this.closeSSE();\n this.closeWebSocket();\n }\n\n private closeSSE(): void {\n if (this.eventSource) {\n this.eventSource.close();\n this.eventSource = null;\n }\n }\n\n private closeWebSocket(): void {\n if (this.webSocket) {\n this.webSocket.close();\n this.webSocket = null;\n }\n }\n\n private clearTimeouts(): void {\n if (this.reconnectTimeout) {\n clearTimeout(this.reconnectTimeout);\n this.reconnectTimeout = null;\n }\n if (this.connectionTimeout) {\n clearTimeout(this.connectionTimeout);\n this.connectionTimeout = null;\n }\n }\n\n // ============================================================================\n // Private Methods - Utilities\n // ============================================================================\n\n private deriveWebSocketUrl(sseUrl: string): string {\n // Convert HTTP(S) URL to WS(S) URL\n const url = new URL(sseUrl);\n url.protocol = url.protocol === \"https:\" ? \"wss:\" : \"ws:\";\n return url.toString();\n }\n}\n","// ============================================================================\n// Token Manager - Storage and auto-refresh for API tokens\n// ============================================================================\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Storage interface for tokens\n */\nexport interface TokenStorage {\n get(key: string): Promise<string | null>;\n set(key: string, value: string): Promise<void>;\n remove(key: string): Promise<void>;\n}\n\n/**\n * Stored token format\n */\ninterface StoredToken {\n token: string;\n expiresAt: number; // Unix timestamp ms\n}\n\n/**\n * Token manager configuration\n */\nexport interface TokenManagerConfig {\n /**\n * Storage implementation\n * @default MemoryTokenStorage\n */\n storage?: TokenStorage;\n\n /**\n * Prefix for storage keys\n * @default 'stepflow_token_'\n */\n storageKeyPrefix?: string;\n\n /**\n * Refresh threshold in milliseconds before expiry\n * @default 300000 (5 minutes)\n */\n refreshThresholdMs?: number;\n\n /**\n * Callback when token is refreshed\n */\n onTokenRefresh?: (runId: string, newToken: string) => void;\n\n /**\n * Callback when token expires\n */\n onTokenExpired?: (runId: string) => void;\n}\n\n// ============================================================================\n// Storage Implementations\n// ============================================================================\n\n/**\n * In-memory token storage (default for SSR/testing)\n */\nexport class MemoryTokenStorage implements TokenStorage {\n private store = new Map<string, string>();\n\n async get(key: string): Promise<string | null> {\n return this.store.get(key) ?? null;\n }\n\n async set(key: string, value: string): Promise<void> {\n this.store.set(key, value);\n }\n\n async remove(key: string): Promise<void> {\n this.store.delete(key);\n }\n}\n\n/**\n * Browser localStorage wrapper\n */\nexport class LocalStorageTokenStorage implements TokenStorage {\n async get(key: string): Promise<string | null> {\n if (typeof window === \"undefined\" || !window.localStorage) {\n return null;\n }\n return window.localStorage.getItem(key);\n }\n\n async set(key: string, value: string): Promise<void> {\n if (typeof window === \"undefined\" || !window.localStorage) {\n return;\n }\n window.localStorage.setItem(key, value);\n }\n\n async remove(key: string): Promise<void> {\n if (typeof window === \"undefined\" || !window.localStorage) {\n return;\n }\n window.localStorage.removeItem(key);\n }\n}\n\n// ============================================================================\n// Token Manager\n// ============================================================================\n\n/**\n * Manages API tokens with storage and auto-refresh\n */\nexport class TokenManager {\n private storage: TokenStorage;\n private storageKeyPrefix: string;\n private refreshThresholdMs: number;\n private onTokenRefresh?: (runId: string, newToken: string) => void;\n private onTokenExpired?: (runId: string) => void;\n private refreshTimers = new Map<string, NodeJS.Timeout>();\n\n constructor(config?: TokenManagerConfig) {\n this.storage = config?.storage ?? new MemoryTokenStorage();\n this.storageKeyPrefix = config?.storageKeyPrefix ?? \"stepflow_token_\";\n this.refreshThresholdMs = config?.refreshThresholdMs ?? 300000; // 5 minutes\n this.onTokenRefresh = config?.onTokenRefresh;\n this.onTokenExpired = config?.onTokenExpired;\n }\n\n /**\n * Store a token with expiry\n */\n async storeToken(\n runId: string,\n token: string,\n expiresAt: Date,\n ): Promise<void> {\n const stored: StoredToken = {\n token,\n expiresAt: expiresAt.getTime(),\n };\n\n const key = this.getStorageKey(runId);\n await this.storage.set(key, JSON.stringify(stored));\n }\n\n /**\n * Get a token if it's still valid\n * @returns Token string or null if expired/not found\n */\n async getToken(runId: string): Promise<string | null> {\n const key = this.getStorageKey(runId);\n const value = await this.storage.get(key);\n\n if (!value) {\n return null;\n }\n\n try {\n const stored = JSON.parse(value) as StoredToken;\n const now = Date.now();\n\n // Check if expired\n if (stored.expiresAt <= now) {\n await this.removeToken(runId);\n return null;\n }\n\n return stored.token;\n } catch {\n // Invalid format, remove it\n await this.removeToken(runId);\n return null;\n }\n }\n\n /**\n * Remove a token from storage\n */\n async removeToken(runId: string): Promise<void> {\n const key = this.getStorageKey(runId);\n await this.storage.remove(key);\n this.stopAutoRefresh(runId);\n }\n\n /**\n * Check if a token is valid (exists and not expired)\n */\n async isTokenValid(runId: string): Promise<boolean> {\n const token = await this.getToken(runId);\n return token !== null;\n }\n\n /**\n * Get token expiry date\n * @returns Expiry date or null if not found\n */\n async getTokenExpiry(runId: string): Promise<Date | null> {\n const key = this.getStorageKey(runId);\n const value = await this.storage.get(key);\n\n if (!value) {\n return null;\n }\n\n try {\n const stored = JSON.parse(value) as StoredToken;\n return new Date(stored.expiresAt);\n } catch {\n return null;\n }\n }\n\n /**\n * Start auto-refresh for a token\n */\n startAutoRefresh(\n runId: string,\n refreshFn: () => Promise<{ token: string; expiresAt: Date }>,\n ): void {\n // Stop existing refresh if any\n this.stopAutoRefresh(runId);\n\n // Schedule refresh\n this.scheduleRefresh(runId, refreshFn);\n }\n\n /**\n * Stop auto-refresh for a specific token\n */\n stopAutoRefresh(runId: string): void {\n const timer = this.refreshTimers.get(runId);\n if (timer) {\n clearTimeout(timer);\n this.refreshTimers.delete(runId);\n }\n }\n\n /**\n * Stop all auto-refresh timers\n */\n stopAllAutoRefresh(): void {\n for (const timer of this.refreshTimers.values()) {\n clearTimeout(timer);\n }\n this.refreshTimers.clear();\n }\n\n /**\n * Schedule a refresh based on token expiry\n */\n private async scheduleRefresh(\n runId: string,\n refreshFn: () => Promise<{ token: string; expiresAt: Date }>,\n ): Promise<void> {\n const expiry = await this.getTokenExpiry(runId);\n if (!expiry) {\n return;\n }\n\n const now = Date.now();\n const expiryTime = expiry.getTime();\n const refreshTime = expiryTime - this.refreshThresholdMs;\n const delay = Math.max(0, refreshTime - now);\n\n const timer = setTimeout(async () => {\n try {\n // Attempt refresh\n const { token, expiresAt } = await refreshFn();\n\n // Store new token\n await this.storeToken(runId, token, expiresAt);\n\n // Notify callback\n this.onTokenRefresh?.(runId, token);\n\n // Schedule next refresh\n this.scheduleRefresh(runId, refreshFn);\n } catch (error) {\n // Refresh failed, notify expiry\n this.onTokenExpired?.(runId);\n this.stopAutoRefresh(runId);\n }\n }, delay);\n\n this.refreshTimers.set(runId, timer);\n }\n\n /**\n * Get storage key for a run ID\n */\n private getStorageKey(runId: string): string {\n return `${this.storageKeyPrefix}${runId}`;\n }\n}\n"],"mappings":"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","names":["EventSourcePolyfill","EventSourcePolyfill"]}
package/package.json ADDED
@@ -0,0 +1,58 @@
1
+ {
2
+ "name": "@stepflowjs/client-ts",
3
+ "version": "0.0.1",
4
+ "description": "TypeScript client for Stepflow workflow orchestration",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "import": "./dist/index.js",
12
+ "types": "./dist/index.d.ts"
13
+ }
14
+ },
15
+ "files": [
16
+ "dist"
17
+ ],
18
+ "dependencies": {
19
+ "event-source-polyfill": "^1.0.31"
20
+ },
21
+ "devDependencies": {
22
+ "@types/event-source-polyfill": "^1.0.5",
23
+ "tsup": "^8.5.1",
24
+ "vitest": "^4.0.17"
25
+ },
26
+ "peerDependencies": {
27
+ "typescript": "^5.0.0"
28
+ },
29
+ "license": "MIT",
30
+ "author": "Stepflow Contributors",
31
+ "repository": {
32
+ "type": "git",
33
+ "url": "https://stepflow-production.up.railway.app",
34
+ "directory": "packages/client-ts"
35
+ },
36
+ "homepage": "https://stepflow-production.up.railway.app",
37
+ "bugs": {
38
+ "url": "https://stepflow-production.up.railway.app"
39
+ },
40
+ "keywords": [
41
+ "stepflow",
42
+ "workflow",
43
+ "orchestration",
44
+ "client",
45
+ "sdk",
46
+ "typescript"
47
+ ],
48
+ "publishConfig": {
49
+ "access": "public"
50
+ },
51
+ "scripts": {
52
+ "build": "tsup",
53
+ "dev": "tsup --watch",
54
+ "typecheck": "tsc --noEmit",
55
+ "test": "vitest",
56
+ "clean": "rm -rf dist"
57
+ }
58
+ }