@workflow/web-shared 4.0.1-beta.24 → 4.0.1-beta.26
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/dist/api/workflow-api-client.d.ts +40 -5
- package/dist/api/workflow-api-client.d.ts.map +1 -1
- package/dist/api/workflow-api-client.js +280 -196
- package/dist/api/workflow-api-client.js.map +1 -1
- package/dist/api/workflow-server-actions.d.ts +18 -1
- package/dist/api/workflow-server-actions.d.ts.map +1 -1
- package/dist/api/workflow-server-actions.js +173 -93
- package/dist/api/workflow-server-actions.js.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/lib/utils.d.ts +19 -0
- package/dist/lib/utils.d.ts.map +1 -1
- package/dist/lib/utils.js +64 -0
- package/dist/lib/utils.js.map +1 -1
- package/dist/sidebar/attribute-panel.d.ts +6 -2
- package/dist/sidebar/attribute-panel.d.ts.map +1 -1
- package/dist/sidebar/attribute-panel.js +136 -9
- package/dist/sidebar/attribute-panel.js.map +1 -1
- package/dist/sidebar/detail-card.d.ts.map +1 -1
- package/dist/sidebar/detail-card.js +2 -2
- package/dist/sidebar/detail-card.js.map +1 -1
- package/dist/sidebar/events-list.d.ts +2 -1
- package/dist/sidebar/events-list.d.ts.map +1 -1
- package/dist/sidebar/events-list.js +9 -7
- package/dist/sidebar/events-list.js.map +1 -1
- package/dist/sidebar/workflow-detail-panel.d.ts +5 -1
- package/dist/sidebar/workflow-detail-panel.d.ts.map +1 -1
- package/dist/sidebar/workflow-detail-panel.js +2 -2
- package/dist/sidebar/workflow-detail-panel.js.map +1 -1
- package/dist/stream-viewer.d.ts +13 -0
- package/dist/stream-viewer.d.ts.map +1 -0
- package/dist/stream-viewer.js +108 -0
- package/dist/stream-viewer.js.map +1 -0
- package/dist/trace-viewer/components/markers.js +2 -2
- package/dist/trace-viewer/components/markers.js.map +1 -1
- package/dist/trace-viewer/components/span-detail-panel.js +2 -2
- package/dist/trace-viewer/components/span-detail-panel.js.map +1 -1
- package/dist/trace-viewer/trace-viewer.module.css +25 -20
- package/dist/trace-viewer/util/timing.d.ts +7 -1
- package/dist/trace-viewer/util/timing.d.ts.map +1 -1
- package/dist/trace-viewer/util/timing.js +7 -12
- package/dist/trace-viewer/util/timing.js.map +1 -1
- package/dist/workflow-trace-view.d.ts +3 -1
- package/dist/workflow-trace-view.d.ts.map +1 -1
- package/dist/workflow-trace-view.js +2 -2
- package/dist/workflow-trace-view.js.map +1 -1
- package/package.json +4 -3
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
3
3
|
import { getPaginationDisplay } from '../lib/utils';
|
|
4
|
-
import { cancelRun as cancelRunServerAction, fetchEvents, fetchEventsByCorrelationId, fetchHook, fetchHooks, fetchRun, fetchRuns, fetchStep, fetchSteps, readStreamServerAction, recreateRun as recreateRunServerAction, } from './workflow-server-actions';
|
|
4
|
+
import { cancelRun as cancelRunServerAction, fetchEvents, fetchEventsByCorrelationId, fetchHook, fetchHooks, fetchRun, fetchRuns, fetchStep, fetchSteps, fetchStreams, readStreamServerAction, recreateRun as recreateRunServerAction, } from './workflow-server-actions';
|
|
5
5
|
const MAX_ITEMS = 1000;
|
|
6
6
|
const LIVE_POLL_LIMIT = 10;
|
|
7
7
|
const LIVE_STEP_UPDATE_INTERVAL_MS = 2000;
|
|
8
8
|
const LIVE_UPDATE_INTERVAL_MS = 5000;
|
|
9
9
|
/**
|
|
10
|
-
* Helper to convert ServerActionError to
|
|
10
|
+
* Helper to convert ServerActionError to WorkflowWebAPIError
|
|
11
11
|
*/
|
|
12
12
|
function createWorkflowAPIError(serverError) {
|
|
13
|
-
return new
|
|
13
|
+
return new WorkflowWebAPIError(serverError.message, {
|
|
14
14
|
cause: serverError.cause,
|
|
15
15
|
request: serverError.request,
|
|
16
16
|
layer: serverError.layer,
|
|
@@ -18,31 +18,50 @@ function createWorkflowAPIError(serverError) {
|
|
|
18
18
|
}
|
|
19
19
|
/**
|
|
20
20
|
* Gets a user-facing error message from an error object.
|
|
21
|
-
* Handles both
|
|
21
|
+
* Handles both WorkflowWebAPIError and regular Error instances.
|
|
22
22
|
*/
|
|
23
23
|
export const getErrorMessage = (error) => {
|
|
24
24
|
if ('layer' in error && error.layer) {
|
|
25
|
-
if (error instanceof
|
|
25
|
+
if (error instanceof WorkflowWebAPIError) {
|
|
26
26
|
if (error.request?.status === 403) {
|
|
27
27
|
return 'Your current Vercel account does not have access to this data. Please use `vercel login` to log in, or use `vercel switch` to ensure you can access the correct team.';
|
|
28
28
|
}
|
|
29
29
|
}
|
|
30
|
-
//
|
|
30
|
+
// WorkflowWebAPIError already has user-facing messages
|
|
31
31
|
return error.message;
|
|
32
32
|
}
|
|
33
33
|
return error instanceof Error ? error.message : 'An error occurred';
|
|
34
34
|
};
|
|
35
35
|
/**
|
|
36
|
-
* Helper to handle server action results and throw
|
|
36
|
+
* Helper to handle server action results and throw WorkflowWebAPIError on failure
|
|
37
37
|
*/
|
|
38
|
-
function unwrapServerActionResult(
|
|
38
|
+
export async function unwrapServerActionResult(promise) {
|
|
39
|
+
let result;
|
|
40
|
+
try {
|
|
41
|
+
result = await promise;
|
|
42
|
+
}
|
|
43
|
+
catch (error) {
|
|
44
|
+
result = {
|
|
45
|
+
success: false,
|
|
46
|
+
error: error,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
39
49
|
if (!result.success) {
|
|
50
|
+
console.error('[web-api-client] error', result.error);
|
|
40
51
|
if (!result.error) {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
52
|
+
return {
|
|
53
|
+
error: new WorkflowWebAPIError('Unknown error occurred', {
|
|
54
|
+
layer: 'client',
|
|
55
|
+
}),
|
|
56
|
+
result: null,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
return {
|
|
60
|
+
error: createWorkflowAPIError(result.error),
|
|
61
|
+
result: null,
|
|
62
|
+
};
|
|
44
63
|
}
|
|
45
|
-
return result.data;
|
|
64
|
+
return { error: null, result: result.data };
|
|
46
65
|
}
|
|
47
66
|
/**
|
|
48
67
|
* Error instance for API and server-side errors.
|
|
@@ -58,12 +77,12 @@ function unwrapServerActionResult(result) {
|
|
|
58
77
|
* calling the server action, these fields will be populated:
|
|
59
78
|
* - `error.layer` will be 'server'
|
|
60
79
|
*/
|
|
61
|
-
export class
|
|
80
|
+
export class WorkflowWebAPIError extends Error {
|
|
62
81
|
request;
|
|
63
82
|
layer;
|
|
64
83
|
constructor(message, options) {
|
|
65
84
|
super(message, { cause: options?.cause });
|
|
66
|
-
this.name = '
|
|
85
|
+
this.name = 'WorkflowWebAPIError';
|
|
67
86
|
this.request = options?.request;
|
|
68
87
|
this.layer = options?.layer;
|
|
69
88
|
if (options?.cause instanceof Error) {
|
|
@@ -117,42 +136,14 @@ export function useWorkflowRuns(env, params) {
|
|
|
117
136
|
return;
|
|
118
137
|
}
|
|
119
138
|
}
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
const result = unwrapServerActionResult(serverResult);
|
|
129
|
-
// Cache the result
|
|
130
|
-
pageCache.current.set(cacheKey, {
|
|
131
|
-
data: result.data,
|
|
132
|
-
cursor: result.cursor,
|
|
133
|
-
hasMore: result.hasMore,
|
|
134
|
-
});
|
|
135
|
-
setAllPageResults((prev) => {
|
|
136
|
-
const newMap = new Map(prev);
|
|
137
|
-
newMap.set(pageIndex, {
|
|
138
|
-
data: result.data,
|
|
139
|
-
isLoading: false,
|
|
140
|
-
error: null,
|
|
141
|
-
});
|
|
142
|
-
return newMap;
|
|
143
|
-
});
|
|
144
|
-
setCursor(result.cursor);
|
|
145
|
-
setHasMore(result.hasMore);
|
|
146
|
-
}
|
|
147
|
-
catch (err) {
|
|
148
|
-
const error = err instanceof WorkflowAPIError
|
|
149
|
-
? err
|
|
150
|
-
: err instanceof Error
|
|
151
|
-
? new WorkflowAPIError(err.message, {
|
|
152
|
-
cause: err,
|
|
153
|
-
layer: 'client',
|
|
154
|
-
})
|
|
155
|
-
: new WorkflowAPIError(String(err), { layer: 'client' });
|
|
139
|
+
const { error, result } = await unwrapServerActionResult(fetchRuns(env, {
|
|
140
|
+
cursor: pageCursor,
|
|
141
|
+
sortOrder,
|
|
142
|
+
limit: limit,
|
|
143
|
+
workflowName,
|
|
144
|
+
status,
|
|
145
|
+
}));
|
|
146
|
+
if (error) {
|
|
156
147
|
setAllPageResults((prev) => {
|
|
157
148
|
const newMap = new Map(prev);
|
|
158
149
|
newMap.set(pageIndex, {
|
|
@@ -162,7 +153,25 @@ export function useWorkflowRuns(env, params) {
|
|
|
162
153
|
});
|
|
163
154
|
return newMap;
|
|
164
155
|
});
|
|
156
|
+
return;
|
|
165
157
|
}
|
|
158
|
+
// Cache the result
|
|
159
|
+
pageCache.current.set(cacheKey, {
|
|
160
|
+
data: result.data,
|
|
161
|
+
cursor: result.cursor,
|
|
162
|
+
hasMore: result.hasMore,
|
|
163
|
+
});
|
|
164
|
+
setAllPageResults((prev) => {
|
|
165
|
+
const newMap = new Map(prev);
|
|
166
|
+
newMap.set(pageIndex, {
|
|
167
|
+
data: result.data,
|
|
168
|
+
isLoading: false,
|
|
169
|
+
error: null,
|
|
170
|
+
});
|
|
171
|
+
return newMap;
|
|
172
|
+
});
|
|
173
|
+
setCursor(result.cursor);
|
|
174
|
+
setHasMore(result.hasMore);
|
|
166
175
|
}, [env, workflowName, limit, sortOrder, status]);
|
|
167
176
|
// Initial load
|
|
168
177
|
// biome-ignore lint/correctness/useExhaustiveDependencies: Want to refetch first page on param change
|
|
@@ -281,41 +290,13 @@ export function useWorkflowHooks(env, params) {
|
|
|
281
290
|
return;
|
|
282
291
|
}
|
|
283
292
|
}
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
const result = unwrapServerActionResult(serverResult);
|
|
292
|
-
// Cache the result
|
|
293
|
-
pageCache.current.set(cacheKey, {
|
|
294
|
-
data: result.data,
|
|
295
|
-
cursor: result.cursor,
|
|
296
|
-
hasMore: result.hasMore,
|
|
297
|
-
});
|
|
298
|
-
setAllPageResults((prev) => {
|
|
299
|
-
const newMap = new Map(prev);
|
|
300
|
-
newMap.set(pageIndex, {
|
|
301
|
-
data: result.data,
|
|
302
|
-
isLoading: false,
|
|
303
|
-
error: null,
|
|
304
|
-
});
|
|
305
|
-
return newMap;
|
|
306
|
-
});
|
|
307
|
-
setCursor(result.cursor);
|
|
308
|
-
setHasMore(result.hasMore);
|
|
309
|
-
}
|
|
310
|
-
catch (err) {
|
|
311
|
-
const error = err instanceof WorkflowAPIError
|
|
312
|
-
? err
|
|
313
|
-
: err instanceof Error
|
|
314
|
-
? new WorkflowAPIError(err.message, {
|
|
315
|
-
cause: err,
|
|
316
|
-
layer: 'client',
|
|
317
|
-
})
|
|
318
|
-
: new WorkflowAPIError(String(err), { layer: 'client' });
|
|
293
|
+
const { error, result } = await unwrapServerActionResult(fetchHooks(env, {
|
|
294
|
+
runId,
|
|
295
|
+
cursor: pageCursor,
|
|
296
|
+
sortOrder,
|
|
297
|
+
limit: limit,
|
|
298
|
+
}));
|
|
299
|
+
if (error) {
|
|
319
300
|
setAllPageResults((prev) => {
|
|
320
301
|
const newMap = new Map(prev);
|
|
321
302
|
newMap.set(pageIndex, {
|
|
@@ -325,7 +306,25 @@ export function useWorkflowHooks(env, params) {
|
|
|
325
306
|
});
|
|
326
307
|
return newMap;
|
|
327
308
|
});
|
|
309
|
+
return;
|
|
328
310
|
}
|
|
311
|
+
// Cache the result
|
|
312
|
+
pageCache.current.set(cacheKey, {
|
|
313
|
+
data: result.data,
|
|
314
|
+
cursor: result.cursor,
|
|
315
|
+
hasMore: result.hasMore,
|
|
316
|
+
});
|
|
317
|
+
setAllPageResults((prev) => {
|
|
318
|
+
const newMap = new Map(prev);
|
|
319
|
+
newMap.set(pageIndex, {
|
|
320
|
+
data: result.data,
|
|
321
|
+
isLoading: false,
|
|
322
|
+
error: null,
|
|
323
|
+
});
|
|
324
|
+
return newMap;
|
|
325
|
+
});
|
|
326
|
+
setCursor(result.cursor);
|
|
327
|
+
setHasMore(result.hasMore);
|
|
329
328
|
}, [env, runId, limit, sortOrder]);
|
|
330
329
|
// Initial load
|
|
331
330
|
useEffect(() => {
|
|
@@ -402,12 +401,15 @@ async function fetchAllSteps(env, runId) {
|
|
|
402
401
|
let stepsData = [];
|
|
403
402
|
let stepsCursor;
|
|
404
403
|
while (true) {
|
|
405
|
-
const
|
|
404
|
+
const { error, result } = await unwrapServerActionResult(fetchSteps(env, runId, {
|
|
406
405
|
cursor: stepsCursor,
|
|
407
406
|
sortOrder: 'asc',
|
|
408
407
|
limit: 100,
|
|
409
|
-
});
|
|
410
|
-
|
|
408
|
+
}));
|
|
409
|
+
// TODO: We're not handling errors well for infinite fetches
|
|
410
|
+
if (error) {
|
|
411
|
+
break;
|
|
412
|
+
}
|
|
411
413
|
stepsData = [...stepsData, ...result.data];
|
|
412
414
|
if (!result.hasMore || !result.cursor || stepsData.length >= MAX_ITEMS) {
|
|
413
415
|
break;
|
|
@@ -421,13 +423,15 @@ async function fetchAllHooks(env, runId) {
|
|
|
421
423
|
let hooksData = [];
|
|
422
424
|
let hooksCursor;
|
|
423
425
|
while (true) {
|
|
424
|
-
const
|
|
426
|
+
const { error, result } = await unwrapServerActionResult(fetchHooks(env, {
|
|
425
427
|
runId,
|
|
426
428
|
cursor: hooksCursor,
|
|
427
429
|
sortOrder: 'asc',
|
|
428
430
|
limit: 100,
|
|
429
|
-
});
|
|
430
|
-
|
|
431
|
+
}));
|
|
432
|
+
if (error) {
|
|
433
|
+
break;
|
|
434
|
+
}
|
|
431
435
|
hooksData = [...hooksData, ...result.data];
|
|
432
436
|
if (!result.hasMore || !result.cursor || hooksData.length >= MAX_ITEMS) {
|
|
433
437
|
break;
|
|
@@ -441,12 +445,14 @@ async function fetchAllEvents(env, runId) {
|
|
|
441
445
|
let eventsData = [];
|
|
442
446
|
let eventsCursor;
|
|
443
447
|
while (true) {
|
|
444
|
-
const
|
|
448
|
+
const { error, result } = await unwrapServerActionResult(fetchEvents(env, runId, {
|
|
445
449
|
cursor: eventsCursor,
|
|
446
450
|
sortOrder: 'asc',
|
|
447
451
|
limit: 1000,
|
|
448
|
-
});
|
|
449
|
-
|
|
452
|
+
}));
|
|
453
|
+
if (error) {
|
|
454
|
+
break;
|
|
455
|
+
}
|
|
450
456
|
eventsData = [...eventsData, ...result.data];
|
|
451
457
|
if (!result.hasMore || !result.cursor || eventsData.length >= MAX_ITEMS) {
|
|
452
458
|
break;
|
|
@@ -483,11 +489,13 @@ export function useWorkflowTraceViewerData(env, runId, options = {}) {
|
|
|
483
489
|
setAuxiliaryDataLoading(true);
|
|
484
490
|
setError(null);
|
|
485
491
|
const promises = [
|
|
486
|
-
fetchRun(env, runId).then((result) => {
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
492
|
+
unwrapServerActionResult(fetchRun(env, runId)).then(({ error, result }) => {
|
|
493
|
+
if (error) {
|
|
494
|
+
setError(error);
|
|
495
|
+
return;
|
|
496
|
+
}
|
|
497
|
+
setRun(result);
|
|
498
|
+
return result;
|
|
491
499
|
}),
|
|
492
500
|
fetchAllSteps(env, runId).then((result) => {
|
|
493
501
|
setSteps(result.data);
|
|
@@ -502,23 +510,17 @@ export function useWorkflowTraceViewerData(env, runId, options = {}) {
|
|
|
502
510
|
setEventsCursor(result.cursor);
|
|
503
511
|
}),
|
|
504
512
|
];
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
: new WorkflowAPIError(String(err), { layer: 'client' });
|
|
513
|
+
const results = await Promise.allSettled(promises);
|
|
514
|
+
setLoading(false);
|
|
515
|
+
setAuxiliaryDataLoading(false);
|
|
516
|
+
setInitialLoadCompleted(true);
|
|
517
|
+
isFetchingRef.current = false;
|
|
518
|
+
// Just doing the first error, but would be nice to show multiple
|
|
519
|
+
const error = results.find((result) => result.status === 'rejected')
|
|
520
|
+
?.reason;
|
|
521
|
+
if (error) {
|
|
515
522
|
setError(error);
|
|
516
|
-
|
|
517
|
-
finally {
|
|
518
|
-
setLoading(false);
|
|
519
|
-
setAuxiliaryDataLoading(false);
|
|
520
|
-
isFetchingRef.current = false;
|
|
521
|
-
setInitialLoadCompleted(true);
|
|
523
|
+
return;
|
|
522
524
|
}
|
|
523
525
|
}, [env, runId]);
|
|
524
526
|
// Helper to merge steps by ID
|
|
@@ -543,19 +545,25 @@ export function useWorkflowTraceViewerData(env, runId, options = {}) {
|
|
|
543
545
|
if (run?.completedAt) {
|
|
544
546
|
return false;
|
|
545
547
|
}
|
|
546
|
-
const
|
|
547
|
-
|
|
548
|
+
const { error, result } = await unwrapServerActionResult(fetchRun(env, runId));
|
|
549
|
+
if (error) {
|
|
550
|
+
setError(error);
|
|
551
|
+
return false;
|
|
552
|
+
}
|
|
548
553
|
setRun(result);
|
|
549
554
|
return true;
|
|
550
555
|
}, [env, runId, run?.completedAt]);
|
|
551
556
|
// Poll for new steps
|
|
552
557
|
const pollSteps = useCallback(async () => {
|
|
553
|
-
const
|
|
558
|
+
const { error, result } = await unwrapServerActionResult(fetchSteps(env, runId, {
|
|
554
559
|
cursor: stepsCursor,
|
|
555
560
|
sortOrder: 'asc',
|
|
556
561
|
limit: LIVE_POLL_LIMIT,
|
|
557
|
-
});
|
|
558
|
-
|
|
562
|
+
}));
|
|
563
|
+
if (error) {
|
|
564
|
+
setError(error);
|
|
565
|
+
return false;
|
|
566
|
+
}
|
|
559
567
|
if (result.data.length > 0) {
|
|
560
568
|
setSteps((prev) => mergeSteps(prev, result.data));
|
|
561
569
|
if (result.cursor) {
|
|
@@ -567,13 +575,16 @@ export function useWorkflowTraceViewerData(env, runId, options = {}) {
|
|
|
567
575
|
}, [env, runId, stepsCursor, mergeSteps]);
|
|
568
576
|
// Poll for new hooks
|
|
569
577
|
const pollHooks = useCallback(async () => {
|
|
570
|
-
const
|
|
578
|
+
const { error, result } = await unwrapServerActionResult(fetchHooks(env, {
|
|
571
579
|
runId,
|
|
572
580
|
cursor: hooksCursor,
|
|
573
581
|
sortOrder: 'asc',
|
|
574
582
|
limit: LIVE_POLL_LIMIT,
|
|
575
|
-
});
|
|
576
|
-
|
|
583
|
+
}));
|
|
584
|
+
if (error) {
|
|
585
|
+
setError(error);
|
|
586
|
+
return false;
|
|
587
|
+
}
|
|
577
588
|
if (result.data.length > 0) {
|
|
578
589
|
setHooks((prev) => mergeHooks(prev, result.data));
|
|
579
590
|
if (result.cursor) {
|
|
@@ -585,12 +596,15 @@ export function useWorkflowTraceViewerData(env, runId, options = {}) {
|
|
|
585
596
|
}, [env, runId, hooksCursor, mergeHooks]);
|
|
586
597
|
// Poll for new events
|
|
587
598
|
const pollEvents = useCallback(async () => {
|
|
588
|
-
const
|
|
599
|
+
const { error, result } = await unwrapServerActionResult(fetchEvents(env, runId, {
|
|
589
600
|
cursor: eventsCursor,
|
|
590
601
|
sortOrder: 'asc',
|
|
591
602
|
limit: LIVE_POLL_LIMIT,
|
|
592
|
-
});
|
|
593
|
-
|
|
603
|
+
}));
|
|
604
|
+
if (error) {
|
|
605
|
+
setError(error);
|
|
606
|
+
return false;
|
|
607
|
+
}
|
|
594
608
|
if (result.data.length > 0) {
|
|
595
609
|
setEvents((prev) => mergeEvents(prev, result.data));
|
|
596
610
|
if (result.cursor) {
|
|
@@ -657,28 +671,37 @@ async function fetchResourceWithCorrelationId(env, resource, resourceId, options
|
|
|
657
671
|
let correlationId;
|
|
658
672
|
const resolveData = options.resolveData ?? 'all';
|
|
659
673
|
if (resource === 'run') {
|
|
660
|
-
const
|
|
661
|
-
|
|
674
|
+
const { error, result } = await unwrapServerActionResult(fetchRun(env, resourceId, resolveData));
|
|
675
|
+
if (error) {
|
|
676
|
+
throw error;
|
|
677
|
+
}
|
|
678
|
+
resourceData = result;
|
|
662
679
|
correlationId = resourceData.runId;
|
|
663
680
|
}
|
|
664
681
|
else if (resource === 'step') {
|
|
665
682
|
const { runId } = options;
|
|
666
683
|
if (!runId) {
|
|
667
|
-
throw new
|
|
684
|
+
throw new WorkflowWebAPIError('runId is required for step resource', {
|
|
668
685
|
layer: 'client',
|
|
669
686
|
});
|
|
670
687
|
}
|
|
671
|
-
const
|
|
672
|
-
|
|
688
|
+
const { error, result } = await unwrapServerActionResult(fetchStep(env, runId, resourceId, resolveData));
|
|
689
|
+
if (error) {
|
|
690
|
+
throw error;
|
|
691
|
+
}
|
|
692
|
+
resourceData = result;
|
|
673
693
|
correlationId = resourceData.stepId;
|
|
674
694
|
}
|
|
675
695
|
else if (resource === 'hook') {
|
|
676
|
-
const
|
|
677
|
-
|
|
696
|
+
const { error, result } = await unwrapServerActionResult(fetchHook(env, resourceId, resolveData));
|
|
697
|
+
if (error) {
|
|
698
|
+
throw error;
|
|
699
|
+
}
|
|
700
|
+
resourceData = result;
|
|
678
701
|
correlationId = resourceData.hookId;
|
|
679
702
|
}
|
|
680
703
|
else {
|
|
681
|
-
throw new
|
|
704
|
+
throw new WorkflowWebAPIError(`Unknown resource type: ${resource}`, {
|
|
682
705
|
layer: 'client',
|
|
683
706
|
});
|
|
684
707
|
}
|
|
@@ -698,52 +721,53 @@ export function useWorkflowResourceData(env, resource, resourceId, options = {})
|
|
|
698
721
|
setLoading(true);
|
|
699
722
|
setData(null);
|
|
700
723
|
setError(null);
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
const waitStartEvent = eventsData.data.find((event) => event.eventType === 'wait_created');
|
|
710
|
-
if (waitStartEvent) {
|
|
711
|
-
setData({
|
|
712
|
-
waitId: waitStartEvent.correlationId,
|
|
713
|
-
runId: waitStartEvent.runId,
|
|
714
|
-
createdAt: waitStartEvent.createdAt,
|
|
715
|
-
resumeAt: waitStartEvent.eventData.resumeAt,
|
|
716
|
-
});
|
|
717
|
-
}
|
|
724
|
+
if (resource === 'sleep') {
|
|
725
|
+
const { error, result } = await unwrapServerActionResult(fetchEventsByCorrelationId(env, resourceId, {
|
|
726
|
+
sortOrder: 'asc',
|
|
727
|
+
limit: 100,
|
|
728
|
+
withData: true,
|
|
729
|
+
}));
|
|
730
|
+
if (error) {
|
|
731
|
+
setError(error);
|
|
718
732
|
return;
|
|
719
733
|
}
|
|
720
|
-
|
|
734
|
+
const eventsData = result;
|
|
735
|
+
const waitStartEvent = eventsData.data.find((event) => event.eventType === 'wait_created');
|
|
736
|
+
if (waitStartEvent) {
|
|
737
|
+
setData({
|
|
738
|
+
waitId: waitStartEvent.correlationId,
|
|
739
|
+
runId: waitStartEvent.runId,
|
|
740
|
+
createdAt: waitStartEvent.createdAt,
|
|
741
|
+
resumeAt: waitStartEvent.eventData.resumeAt,
|
|
742
|
+
});
|
|
743
|
+
}
|
|
744
|
+
return;
|
|
745
|
+
}
|
|
746
|
+
// Fetch resource with full data
|
|
747
|
+
try {
|
|
721
748
|
const { data: resourceData } = await fetchResourceWithCorrelationId(env, resource, resourceId, {
|
|
722
749
|
runId,
|
|
723
750
|
});
|
|
724
751
|
setData(resourceData);
|
|
725
|
-
if (resource === 'run') {
|
|
726
|
-
setLoading(false);
|
|
727
|
-
return;
|
|
728
|
-
}
|
|
729
|
-
// // Fetch events by correlation ID
|
|
730
|
-
// const eventsData = await fetchAllEventsByCorrelationId(
|
|
731
|
-
// env,
|
|
732
|
-
// correlationId
|
|
733
|
-
// );
|
|
734
|
-
// setEvents(eventsData);
|
|
735
752
|
}
|
|
736
|
-
catch (
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
753
|
+
catch (error) {
|
|
754
|
+
if (error instanceof Error) {
|
|
755
|
+
setError(error);
|
|
756
|
+
}
|
|
757
|
+
else {
|
|
758
|
+
setError(new Error(String(error)));
|
|
759
|
+
}
|
|
760
|
+
return;
|
|
743
761
|
}
|
|
744
762
|
finally {
|
|
745
763
|
setLoading(false);
|
|
746
764
|
}
|
|
765
|
+
// // Fetch events by correlation ID
|
|
766
|
+
// const eventsData = await fetchAllEventsByCorrelationId(
|
|
767
|
+
// env,
|
|
768
|
+
// correlationId
|
|
769
|
+
// );
|
|
770
|
+
// setEvents(eventsData);
|
|
747
771
|
}, [env, resource, resourceId, runId]);
|
|
748
772
|
// Initial load
|
|
749
773
|
useEffect(() => {
|
|
@@ -769,45 +793,105 @@ export function useWorkflowResourceData(env, resource, resourceId, options = {})
|
|
|
769
793
|
* Cancel a workflow run
|
|
770
794
|
*/
|
|
771
795
|
export async function cancelRun(env, runId) {
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
}
|
|
776
|
-
catch (err) {
|
|
777
|
-
console.error('Error canceling run:', err);
|
|
778
|
-
if (err instanceof WorkflowAPIError) {
|
|
779
|
-
throw err;
|
|
780
|
-
}
|
|
781
|
-
throw new WorkflowAPIError(err instanceof Error ? err.message : 'Failed to cancel run', { cause: err, layer: 'client' });
|
|
796
|
+
const { error } = await unwrapServerActionResult(cancelRunServerAction(env, runId));
|
|
797
|
+
if (error) {
|
|
798
|
+
throw error;
|
|
782
799
|
}
|
|
783
800
|
}
|
|
784
801
|
/**
|
|
785
802
|
* Start a new workflow run
|
|
786
803
|
*/
|
|
787
804
|
export async function recreateRun(env, runId) {
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
}
|
|
792
|
-
catch (err) {
|
|
793
|
-
console.error('Error starting run:', err);
|
|
794
|
-
if (err instanceof WorkflowAPIError) {
|
|
795
|
-
throw err;
|
|
796
|
-
}
|
|
797
|
-
throw new WorkflowAPIError(err instanceof Error ? err.message : 'Failed to start run', { cause: err, layer: 'client' });
|
|
805
|
+
const { error, result: resultData } = await unwrapServerActionResult(recreateRunServerAction(env, runId));
|
|
806
|
+
if (error) {
|
|
807
|
+
throw error;
|
|
798
808
|
}
|
|
809
|
+
return resultData;
|
|
810
|
+
}
|
|
811
|
+
function isServerActionError(value) {
|
|
812
|
+
return (typeof value === 'object' &&
|
|
813
|
+
value !== null &&
|
|
814
|
+
'message' in value &&
|
|
815
|
+
'layer' in value &&
|
|
816
|
+
'cause' in value &&
|
|
817
|
+
'request' in value);
|
|
799
818
|
}
|
|
800
819
|
export async function readStream(env, streamId, startIndex) {
|
|
801
820
|
try {
|
|
802
|
-
const
|
|
803
|
-
|
|
821
|
+
const stream = await readStreamServerAction(env, streamId, startIndex);
|
|
822
|
+
if (!stream) {
|
|
823
|
+
throw new WorkflowWebAPIError('Failed to read stream', {
|
|
824
|
+
layer: 'client',
|
|
825
|
+
});
|
|
826
|
+
}
|
|
827
|
+
if (isServerActionError(stream)) {
|
|
828
|
+
throw new WorkflowWebAPIError(stream.message, {
|
|
829
|
+
layer: 'client',
|
|
830
|
+
cause: stream.cause,
|
|
831
|
+
request: stream.request,
|
|
832
|
+
});
|
|
833
|
+
}
|
|
834
|
+
return stream;
|
|
804
835
|
}
|
|
805
|
-
catch (
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
throw err;
|
|
836
|
+
catch (error) {
|
|
837
|
+
if (error instanceof WorkflowWebAPIError) {
|
|
838
|
+
throw error;
|
|
809
839
|
}
|
|
810
|
-
throw new
|
|
840
|
+
throw new WorkflowWebAPIError('Failed to read stream', {
|
|
841
|
+
layer: 'client',
|
|
842
|
+
cause: error,
|
|
843
|
+
});
|
|
844
|
+
}
|
|
845
|
+
}
|
|
846
|
+
/**
|
|
847
|
+
* List all stream IDs for a run
|
|
848
|
+
*/
|
|
849
|
+
export async function listStreams(env, runId) {
|
|
850
|
+
const { error, result } = await unwrapServerActionResult(fetchStreams(env, runId));
|
|
851
|
+
if (error) {
|
|
852
|
+
throw error;
|
|
811
853
|
}
|
|
854
|
+
return result;
|
|
855
|
+
}
|
|
856
|
+
const STREAMS_REFRESH_INTERVAL_MS = 10000;
|
|
857
|
+
/**
|
|
858
|
+
* Hook to fetch and manage stream list for a run
|
|
859
|
+
*/
|
|
860
|
+
export function useWorkflowStreams(env, runId, refreshInterval = STREAMS_REFRESH_INTERVAL_MS) {
|
|
861
|
+
const [streams, setStreams] = useState([]);
|
|
862
|
+
const [loading, setLoading] = useState(true);
|
|
863
|
+
const [error, setError] = useState(null);
|
|
864
|
+
const fetchData = useCallback(async () => {
|
|
865
|
+
setLoading(true);
|
|
866
|
+
setError(null);
|
|
867
|
+
try {
|
|
868
|
+
const result = await listStreams(env, runId);
|
|
869
|
+
setStreams(result);
|
|
870
|
+
}
|
|
871
|
+
catch (err) {
|
|
872
|
+
setError(err instanceof Error ? err : new Error(String(err)));
|
|
873
|
+
}
|
|
874
|
+
finally {
|
|
875
|
+
setLoading(false);
|
|
876
|
+
}
|
|
877
|
+
}, [env, runId]);
|
|
878
|
+
// Initial load
|
|
879
|
+
useEffect(() => {
|
|
880
|
+
fetchData();
|
|
881
|
+
}, [fetchData]);
|
|
882
|
+
// Auto-refresh interval
|
|
883
|
+
useEffect(() => {
|
|
884
|
+
if (!refreshInterval || refreshInterval <= 0) {
|
|
885
|
+
return;
|
|
886
|
+
}
|
|
887
|
+
const interval = setInterval(fetchData, refreshInterval);
|
|
888
|
+
return () => clearInterval(interval);
|
|
889
|
+
}, [refreshInterval, fetchData]);
|
|
890
|
+
return {
|
|
891
|
+
streams,
|
|
892
|
+
loading,
|
|
893
|
+
error,
|
|
894
|
+
refresh: fetchData,
|
|
895
|
+
};
|
|
812
896
|
}
|
|
813
897
|
//# sourceMappingURL=workflow-api-client.js.map
|