@workflow/web-shared 5.0.0-beta.0 → 5.0.0-beta.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/components/error-boundary.js +1 -1
- package/dist/components/event-list-view.d.ts +18 -1
- package/dist/components/event-list-view.d.ts.map +1 -1
- package/dist/components/event-list-view.js +242 -142
- package/dist/components/hook-actions.js +1 -1
- package/dist/components/index.d.ts +4 -1
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/index.js +5 -2
- package/dist/components/new-trace-viewer/components/copy-button.d.ts +9 -0
- package/dist/components/new-trace-viewer/components/copy-button.d.ts.map +1 -0
- package/dist/components/new-trace-viewer/components/copy-button.js +27 -0
- package/dist/components/new-trace-viewer/components/event-list.d.ts +10 -0
- package/dist/components/new-trace-viewer/components/event-list.d.ts.map +1 -0
- package/dist/components/new-trace-viewer/components/event-list.js +39 -0
- package/dist/components/new-trace-viewer/components/middle-truncate/copy-selection.d.ts +18 -0
- package/dist/components/new-trace-viewer/components/middle-truncate/copy-selection.d.ts.map +1 -0
- package/dist/components/new-trace-viewer/components/middle-truncate/copy-selection.js +54 -0
- package/dist/components/new-trace-viewer/components/middle-truncate/middle-truncate.d.ts +20 -0
- package/dist/components/new-trace-viewer/components/middle-truncate/middle-truncate.d.ts.map +1 -0
- package/dist/components/new-trace-viewer/components/middle-truncate/middle-truncate.js +81 -0
- package/dist/components/new-trace-viewer/components/middle-truncate/truncate.d.ts +25 -0
- package/dist/components/new-trace-viewer/components/middle-truncate/truncate.d.ts.map +1 -0
- package/dist/components/new-trace-viewer/components/middle-truncate/truncate.js +101 -0
- package/dist/components/new-trace-viewer/components/middle-truncate/use-middle-truncate.d.ts +20 -0
- package/dist/components/new-trace-viewer/components/middle-truncate/use-middle-truncate.d.ts.map +1 -0
- package/dist/components/new-trace-viewer/components/middle-truncate/use-middle-truncate.js +114 -0
- package/dist/components/new-trace-viewer/components/split-pane.d.ts +14 -0
- package/dist/components/new-trace-viewer/components/split-pane.d.ts.map +1 -0
- package/dist/components/new-trace-viewer/components/split-pane.js +99 -0
- package/dist/components/new-trace-viewer/components/timeline.d.ts +34 -0
- package/dist/components/new-trace-viewer/components/timeline.d.ts.map +1 -0
- package/dist/components/new-trace-viewer/components/timeline.js +223 -0
- package/dist/components/new-trace-viewer/context.d.ts +15 -0
- package/dist/components/new-trace-viewer/context.d.ts.map +1 -0
- package/dist/components/new-trace-viewer/context.js +47 -0
- package/dist/components/new-trace-viewer/detail-panel.d.ts +10 -0
- package/dist/components/new-trace-viewer/detail-panel.d.ts.map +1 -0
- package/dist/components/new-trace-viewer/detail-panel.js +13 -0
- package/dist/components/new-trace-viewer/icons.d.ts +6 -0
- package/dist/components/new-trace-viewer/icons.d.ts.map +1 -0
- package/dist/components/new-trace-viewer/icons.js +15 -0
- package/dist/components/new-trace-viewer/search.d.ts +19 -0
- package/dist/components/new-trace-viewer/search.d.ts.map +1 -0
- package/dist/components/new-trace-viewer/search.js +134 -0
- package/dist/components/new-trace-viewer/trace-viewer.d.ts +8 -0
- package/dist/components/new-trace-viewer/trace-viewer.d.ts.map +1 -0
- package/dist/components/new-trace-viewer/trace-viewer.js +387 -0
- package/dist/components/new-trace-viewer/types.d.ts +1 -0
- package/dist/components/new-trace-viewer/types.d.ts.map +1 -0
- package/dist/components/new-trace-viewer/types.js +2 -0
- package/dist/components/new-trace-viewer/util/constants.d.ts +1 -0
- package/dist/components/new-trace-viewer/util/constants.d.ts.map +1 -0
- package/dist/components/new-trace-viewer/util/constants.js +2 -0
- package/dist/components/new-trace-viewer/utils.d.ts +46 -0
- package/dist/components/new-trace-viewer/utils.d.ts.map +1 -0
- package/dist/components/new-trace-viewer/utils.js +330 -0
- package/dist/components/run-trace-view.d.ts +2 -1
- package/dist/components/run-trace-view.d.ts.map +1 -1
- package/dist/components/run-trace-view.js +3 -3
- package/dist/components/sidebar/attribute-panel.d.ts +7 -1
- package/dist/components/sidebar/attribute-panel.d.ts.map +1 -1
- package/dist/components/sidebar/attribute-panel.js +131 -70
- package/dist/components/sidebar/conversation-view.js +1 -1
- package/dist/components/sidebar/copyable-data-block.d.ts +1 -0
- package/dist/components/sidebar/copyable-data-block.d.ts.map +1 -1
- package/dist/components/sidebar/copyable-data-block.js +16 -15
- package/dist/components/sidebar/detail-card.d.ts +5 -6
- package/dist/components/sidebar/detail-card.d.ts.map +1 -1
- package/dist/components/sidebar/detail-card.js +32 -16
- package/dist/components/sidebar/entity-detail-panel.d.ts +3 -1
- package/dist/components/sidebar/entity-detail-panel.d.ts.map +1 -1
- package/dist/components/sidebar/entity-detail-panel.js +20 -37
- package/dist/components/sidebar/events-list.d.ts +1 -1
- package/dist/components/sidebar/events-list.d.ts.map +1 -1
- package/dist/components/sidebar/events-list.js +46 -32
- package/dist/components/sidebar/resolve-hook-modal.js +1 -1
- package/dist/components/sidebar/sidebar-data-context.d.ts +29 -0
- package/dist/components/sidebar/sidebar-data-context.d.ts.map +1 -0
- package/dist/components/sidebar/sidebar-data-context.js +19 -0
- package/dist/components/stream-viewer.d.ts +1 -1
- package/dist/components/stream-viewer.d.ts.map +1 -1
- package/dist/components/stream-viewer.js +3 -27
- package/dist/components/trace-viewer/components/map.js +1 -1
- package/dist/components/trace-viewer/components/markers.js +1 -1
- package/dist/components/trace-viewer/components/node.js +1 -1
- package/dist/components/trace-viewer/components/search-input.js +1 -1
- package/dist/components/trace-viewer/components/search.js +1 -1
- package/dist/components/trace-viewer/components/span-content.js +1 -1
- package/dist/components/trace-viewer/components/span-detail-panel.js +1 -1
- package/dist/components/trace-viewer/components/span-segments.js +1 -1
- package/dist/components/trace-viewer/components/span-strategies.js +1 -1
- package/dist/components/trace-viewer/components/ui.js +1 -1
- package/dist/components/trace-viewer/components/zoom-button.js +1 -1
- package/dist/components/trace-viewer/components/zoom-icons.js +1 -1
- package/dist/components/trace-viewer/context.js +1 -1
- package/dist/components/trace-viewer/index.js +1 -1
- package/dist/components/trace-viewer/trace-viewer.js +1 -1
- package/dist/components/trace-viewer/types.js +1 -1
- package/dist/components/trace-viewer/util/constants.js +1 -1
- package/dist/components/trace-viewer/util/scrollbar-width.js +1 -1
- package/dist/components/trace-viewer/util/timing.d.ts +1 -1
- package/dist/components/trace-viewer/util/timing.d.ts.map +1 -1
- package/dist/components/trace-viewer/util/timing.js +6 -9
- package/dist/components/trace-viewer/util/tree.js +1 -1
- package/dist/components/trace-viewer/util/use-immediate-style.js +1 -1
- package/dist/components/trace-viewer/util/use-streaming-spans.js +1 -1
- package/dist/components/trace-viewer/util/use-trackpad-zoom.js +1 -1
- package/dist/components/trace-viewer/worker.js +1 -1
- package/dist/components/trace-viewer-new.d.ts +10 -0
- package/dist/components/trace-viewer-new.d.ts.map +1 -0
- package/dist/components/trace-viewer-new.js +23 -0
- package/dist/components/ui/alert.js +1 -1
- package/dist/components/ui/button.d.ts +10 -0
- package/dist/components/ui/button.d.ts.map +1 -0
- package/dist/components/ui/button.js +46 -0
- package/dist/components/ui/card.js +1 -1
- package/dist/components/ui/data-inspector.d.ts +39 -1
- package/dist/components/ui/data-inspector.d.ts.map +1 -1
- package/dist/components/ui/data-inspector.js +207 -22
- package/dist/components/ui/decrypt-button.js +1 -1
- package/dist/components/ui/error-card.js +1 -1
- package/dist/components/ui/error-stack-block.d.ts.map +1 -1
- package/dist/components/ui/error-stack-block.js +27 -19
- package/dist/components/ui/icon-button.d.ts +13 -0
- package/dist/components/ui/icon-button.d.ts.map +1 -0
- package/dist/components/ui/icon-button.js +29 -0
- package/dist/components/ui/inspector-theme.d.ts +9 -10
- package/dist/components/ui/inspector-theme.d.ts.map +1 -1
- package/dist/components/ui/inspector-theme.js +39 -72
- package/dist/components/ui/load-more-button.js +1 -1
- package/dist/components/ui/menu-dropdown.js +1 -1
- package/dist/components/ui/skeleton.js +1 -1
- package/dist/components/ui/spinner.js +1 -1
- package/dist/components/ui/timestamp-tooltip.js +1 -1
- package/dist/components/workflow-trace-view.d.ts +3 -1
- package/dist/components/workflow-trace-view.d.ts.map +1 -1
- package/dist/components/workflow-trace-view.js +10 -5
- package/dist/components/workflow-traces/event-colors.js +1 -1
- package/dist/components/workflow-traces/trace-colors.js +1 -1
- package/dist/components/workflow-traces/trace-span-construction.d.ts +2 -2
- package/dist/components/workflow-traces/trace-span-construction.d.ts.map +1 -1
- package/dist/components/workflow-traces/trace-span-construction.js +19 -6
- package/dist/components/workflow-traces/trace-time-utils.js +1 -1
- package/dist/hooks/use-dark-mode.js +1 -1
- package/dist/hooks/use-reduced-motion.d.ts +10 -0
- package/dist/hooks/use-reduced-motion.d.ts.map +1 -0
- package/dist/hooks/use-reduced-motion.js +29 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -2
- package/dist/lib/event-analysis.js +1 -1
- package/dist/lib/event-materialization.js +1 -1
- package/dist/lib/exact-event-search-id.d.ts +25 -0
- package/dist/lib/exact-event-search-id.d.ts.map +1 -0
- package/dist/lib/exact-event-search-id.js +39 -0
- package/dist/lib/hydration.d.ts +15 -2
- package/dist/lib/hydration.d.ts.map +1 -1
- package/dist/lib/hydration.js +168 -16
- package/dist/lib/stream-display.d.ts +18 -0
- package/dist/lib/stream-display.d.ts.map +1 -0
- package/dist/lib/stream-display.js +30 -0
- package/dist/lib/toast.js +1 -1
- package/dist/lib/trace-builder.d.ts.map +1 -1
- package/dist/lib/trace-builder.js +3 -2
- package/dist/lib/utils.d.ts +9 -9
- package/dist/lib/utils.d.ts.map +1 -1
- package/dist/lib/utils.js +27 -32
- package/dist/styles.css +475 -1
- package/package.json +6 -4
- package/src/components/event-list-view.tsx +447 -282
- package/src/components/index.ts +12 -1
- package/src/components/new-trace-viewer/components/copy-button.tsx +68 -0
- package/src/components/new-trace-viewer/components/event-list.tsx +127 -0
- package/src/components/new-trace-viewer/components/middle-truncate/copy-selection.ts +114 -0
- package/src/components/new-trace-viewer/components/middle-truncate/middle-truncate.tsx +157 -0
- package/src/components/new-trace-viewer/components/middle-truncate/truncate.ts +132 -0
- package/src/components/new-trace-viewer/components/middle-truncate/use-middle-truncate.ts +167 -0
- package/src/components/new-trace-viewer/components/split-pane.tsx +185 -0
- package/src/components/new-trace-viewer/components/timeline.tsx +552 -0
- package/src/components/new-trace-viewer/context.tsx +92 -0
- package/src/components/new-trace-viewer/detail-panel.tsx +55 -0
- package/src/components/new-trace-viewer/icons.tsx +79 -0
- package/src/components/new-trace-viewer/search.ts +178 -0
- package/src/components/new-trace-viewer/trace-viewer.tsx +694 -0
- package/src/components/new-trace-viewer/types.ts +0 -0
- package/src/components/new-trace-viewer/util/constants.ts +0 -0
- package/src/components/new-trace-viewer/utils.ts +482 -0
- package/src/components/run-trace-view.tsx +3 -0
- package/src/components/sidebar/attribute-panel.tsx +240 -196
- package/src/components/sidebar/copyable-data-block.tsx +49 -27
- package/src/components/sidebar/detail-card.tsx +119 -59
- package/src/components/sidebar/entity-detail-panel.tsx +92 -148
- package/src/components/sidebar/events-list.tsx +93 -108
- package/src/components/sidebar/sidebar-data-context.tsx +62 -0
- package/src/components/stream-viewer.tsx +18 -40
- package/src/components/trace-viewer/util/timing.ts +5 -9
- package/src/components/trace-viewer-new.tsx +49 -0
- package/src/components/ui/button.tsx +68 -0
- package/src/components/ui/data-inspector.tsx +427 -31
- package/src/components/ui/error-stack-block.tsx +39 -30
- package/src/components/ui/icon-button.tsx +57 -0
- package/src/components/ui/inspector-theme.ts +39 -81
- package/src/components/workflow-trace-view.tsx +12 -2
- package/src/components/workflow-traces/trace-span-construction.ts +24 -6
- package/src/hooks/use-reduced-motion.ts +34 -0
- package/src/index.ts +9 -0
- package/src/lib/exact-event-search-id.ts +67 -0
- package/src/lib/hydration.ts +182 -14
- package/src/lib/stream-display.ts +48 -0
- package/src/lib/trace-builder.ts +2 -1
- package/src/lib/utils.ts +27 -32
- package/src/styles.css +475 -1
- package/dist/components/error-boundary.js.map +0 -1
- package/dist/components/event-list-view.js.map +0 -1
- package/dist/components/hook-actions.js.map +0 -1
- package/dist/components/index.js.map +0 -1
- package/dist/components/run-trace-view.js.map +0 -1
- package/dist/components/sidebar/attribute-panel.js.map +0 -1
- package/dist/components/sidebar/conversation-view.js.map +0 -1
- package/dist/components/sidebar/copyable-data-block.js.map +0 -1
- package/dist/components/sidebar/detail-card.js.map +0 -1
- package/dist/components/sidebar/entity-detail-panel.js.map +0 -1
- package/dist/components/sidebar/events-list.js.map +0 -1
- package/dist/components/sidebar/resolve-hook-modal.js.map +0 -1
- package/dist/components/stream-viewer.js.map +0 -1
- package/dist/components/trace-viewer/components/map.js.map +0 -1
- package/dist/components/trace-viewer/components/markers.js.map +0 -1
- package/dist/components/trace-viewer/components/node.js.map +0 -1
- package/dist/components/trace-viewer/components/search-input.js.map +0 -1
- package/dist/components/trace-viewer/components/search.js.map +0 -1
- package/dist/components/trace-viewer/components/span-content.js.map +0 -1
- package/dist/components/trace-viewer/components/span-detail-panel.js.map +0 -1
- package/dist/components/trace-viewer/components/span-segments.js.map +0 -1
- package/dist/components/trace-viewer/components/span-strategies.js.map +0 -1
- package/dist/components/trace-viewer/components/ui.js.map +0 -1
- package/dist/components/trace-viewer/components/zoom-button.js.map +0 -1
- package/dist/components/trace-viewer/components/zoom-icons.js.map +0 -1
- package/dist/components/trace-viewer/context.js.map +0 -1
- package/dist/components/trace-viewer/index.js.map +0 -1
- package/dist/components/trace-viewer/trace-viewer.js.map +0 -1
- package/dist/components/trace-viewer/types.js.map +0 -1
- package/dist/components/trace-viewer/util/constants.js.map +0 -1
- package/dist/components/trace-viewer/util/scrollbar-width.js.map +0 -1
- package/dist/components/trace-viewer/util/timing.js.map +0 -1
- package/dist/components/trace-viewer/util/tree.js.map +0 -1
- package/dist/components/trace-viewer/util/use-immediate-style.js.map +0 -1
- package/dist/components/trace-viewer/util/use-streaming-spans.js.map +0 -1
- package/dist/components/trace-viewer/util/use-trackpad-zoom.js.map +0 -1
- package/dist/components/trace-viewer/worker.js.map +0 -1
- package/dist/components/ui/alert.js.map +0 -1
- package/dist/components/ui/card.js.map +0 -1
- package/dist/components/ui/data-inspector.js.map +0 -1
- package/dist/components/ui/decrypt-button.js.map +0 -1
- package/dist/components/ui/error-card.js.map +0 -1
- package/dist/components/ui/error-stack-block.js.map +0 -1
- package/dist/components/ui/inspector-theme.js.map +0 -1
- package/dist/components/ui/load-more-button.js.map +0 -1
- package/dist/components/ui/menu-dropdown.js.map +0 -1
- package/dist/components/ui/skeleton.js.map +0 -1
- package/dist/components/ui/spinner.js.map +0 -1
- package/dist/components/ui/timestamp-tooltip.js.map +0 -1
- package/dist/components/workflow-trace-view.js.map +0 -1
- package/dist/components/workflow-traces/event-colors.js.map +0 -1
- package/dist/components/workflow-traces/trace-colors.js.map +0 -1
- package/dist/components/workflow-traces/trace-span-construction.js.map +0 -1
- package/dist/components/workflow-traces/trace-time-utils.js.map +0 -1
- package/dist/hooks/use-dark-mode.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/lib/event-analysis.js.map +0 -1
- package/dist/lib/event-materialization.js.map +0 -1
- package/dist/lib/hydration.js.map +0 -1
- package/dist/lib/toast.js.map +0 -1
- package/dist/lib/trace-builder.js.map +0 -1
- package/dist/lib/utils.js.map +0 -1
package/src/lib/hydration.ts
CHANGED
|
@@ -11,9 +11,12 @@ import {
|
|
|
11
11
|
hydrateResourceIO as hydrateResourceIOGeneric,
|
|
12
12
|
isEncryptedData,
|
|
13
13
|
isExpiredStub,
|
|
14
|
+
isRunRef,
|
|
14
15
|
observabilityRevivers,
|
|
15
16
|
type Revivers,
|
|
17
|
+
serializedInstanceToRef,
|
|
16
18
|
} from '@workflow/core/serialization-format';
|
|
19
|
+
import { EVENT_DATA_REF_FIELDS } from '@workflow/world';
|
|
17
20
|
|
|
18
21
|
// Re-export types and utilities that consumers need
|
|
19
22
|
export {
|
|
@@ -23,11 +26,15 @@ export {
|
|
|
23
26
|
extractStreamIds,
|
|
24
27
|
isClassInstanceRef,
|
|
25
28
|
isEncryptedData,
|
|
29
|
+
isRunRef,
|
|
26
30
|
isStreamId,
|
|
27
31
|
isStreamRef,
|
|
28
32
|
type Revivers,
|
|
33
|
+
RUN_REF_TYPE,
|
|
34
|
+
type RunRef,
|
|
29
35
|
STREAM_REF_TYPE,
|
|
30
36
|
type StreamRef,
|
|
37
|
+
serializedInstanceToRef,
|
|
31
38
|
truncateId,
|
|
32
39
|
} from '@workflow/core/serialization-format';
|
|
33
40
|
|
|
@@ -51,12 +58,60 @@ function base64ToArrayBuffer(base64: string): ArrayBuffer {
|
|
|
51
58
|
// Web revivers (browser-safe, no Buffer dependency)
|
|
52
59
|
// ---------------------------------------------------------------------------
|
|
53
60
|
|
|
61
|
+
/**
|
|
62
|
+
* Build a reviver for one of the built-in `Error` subclasses (e.g.
|
|
63
|
+
* `TypeError`, `RangeError`). The constructor for the named subclass is
|
|
64
|
+
* resolved off `globalThis` at call time so the produced instance has the
|
|
65
|
+
* correct prototype chain in the consumer realm. Falls back to a generic
|
|
66
|
+
* `Error` (with `name` set) if the global isn't available, which keeps the
|
|
67
|
+
* o11y UI rendering even on exotic browsers.
|
|
68
|
+
*
|
|
69
|
+
* `cause` is passed through `ErrorOptions` to the constructor when present,
|
|
70
|
+
* matching `getCommonRevivers` in `@workflow/core` so the resulting `cause`
|
|
71
|
+
* property has the same semantics (non-enumerable, set by the engine) as a
|
|
72
|
+
* freshly thrown Error in the consumer realm. The `'cause' in value` check
|
|
73
|
+
* preserves the distinction between "no cause" and "cause is undefined".
|
|
74
|
+
*/
|
|
75
|
+
function makeWebErrorSubclassReviver(
|
|
76
|
+
name:
|
|
77
|
+
| 'EvalError'
|
|
78
|
+
| 'RangeError'
|
|
79
|
+
| 'ReferenceError'
|
|
80
|
+
| 'SyntaxError'
|
|
81
|
+
| 'TypeError'
|
|
82
|
+
| 'URIError'
|
|
83
|
+
) {
|
|
84
|
+
return (value: { message: string; stack?: string; cause?: unknown }) => {
|
|
85
|
+
const opts = 'cause' in value ? { cause: value.cause } : undefined;
|
|
86
|
+
const Ctor = (globalThis as Record<string, any>)[name] as
|
|
87
|
+
| ErrorConstructor
|
|
88
|
+
| undefined;
|
|
89
|
+
let error: Error;
|
|
90
|
+
if (typeof Ctor === 'function') {
|
|
91
|
+
error = new Ctor(value.message, opts);
|
|
92
|
+
} else {
|
|
93
|
+
// Fallback path: no built-in subclass available (exotic env). Construct
|
|
94
|
+
// a plain Error with the right `name` and copy `cause` manually since
|
|
95
|
+
// the base Error constructor is what we actually called.
|
|
96
|
+
error = Object.assign(new Error(value.message, opts), { name });
|
|
97
|
+
}
|
|
98
|
+
if (value.stack !== undefined) error.stack = value.stack;
|
|
99
|
+
return error;
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
|
|
54
103
|
/**
|
|
55
104
|
* Get the web-specific revivers for hydrating serialized data.
|
|
56
105
|
*
|
|
57
106
|
* Uses `atob()` for base64 decoding (no Node.js Buffer dependency).
|
|
58
107
|
* All types are revived as real instances (Date, Map, Set, URL,
|
|
59
108
|
* URLSearchParams, Headers, Error, etc.).
|
|
109
|
+
*
|
|
110
|
+
* NOTE: this set must mirror the keys in `SerializableSpecial` (see
|
|
111
|
+
* `@workflow/core/serialization/types`). Any reducer key added on the
|
|
112
|
+
* serialization side that isn't covered here will cause `devalue.unflatten`
|
|
113
|
+
* to throw `Unknown type X`, which `hydrateResourceIO` swallows and
|
|
114
|
+
* surfaces as a "Failed to load resource details" banner in the o11y UI.
|
|
60
115
|
*/
|
|
61
116
|
export function getWebRevivers(): Revivers {
|
|
62
117
|
function reviveArrayBuffer(value: string): ArrayBuffer {
|
|
@@ -76,10 +131,93 @@ export function getWebRevivers(): Revivers {
|
|
|
76
131
|
BigUint64Array: (value: string) =>
|
|
77
132
|
new BigUint64Array(reviveArrayBuffer(value)),
|
|
78
133
|
Date: (value) => new Date(value),
|
|
134
|
+
|
|
135
|
+
// Error family. The reducer side (see
|
|
136
|
+
// `packages/core/src/serialization/reducers/common.ts`) emits a tagged
|
|
137
|
+
// entry for each built-in Error subclass plus the workflow-specific
|
|
138
|
+
// `FatalError` / `RetryableError` and `AggregateError`. Without
|
|
139
|
+
// matching revivers here, `devalue.unflatten` throws "Unknown type X"
|
|
140
|
+
// — which surfaces in the web o11y UI as "Failed to load resource
|
|
141
|
+
// details: Unknown type FatalError".
|
|
79
142
|
Error: (value) => {
|
|
143
|
+
const opts = 'cause' in value ? { cause: value.cause } : undefined;
|
|
144
|
+
const error = new Error(value.message, opts);
|
|
145
|
+
error.name = value.name;
|
|
146
|
+
if (value.stack !== undefined) error.stack = value.stack;
|
|
147
|
+
return error;
|
|
148
|
+
},
|
|
149
|
+
EvalError: makeWebErrorSubclassReviver('EvalError'),
|
|
150
|
+
RangeError: makeWebErrorSubclassReviver('RangeError'),
|
|
151
|
+
ReferenceError: makeWebErrorSubclassReviver('ReferenceError'),
|
|
152
|
+
SyntaxError: makeWebErrorSubclassReviver('SyntaxError'),
|
|
153
|
+
TypeError: makeWebErrorSubclassReviver('TypeError'),
|
|
154
|
+
URIError: makeWebErrorSubclassReviver('URIError'),
|
|
155
|
+
AggregateError: (value) => {
|
|
156
|
+
const opts = 'cause' in value ? { cause: value.cause } : undefined;
|
|
157
|
+
const Ctor = (
|
|
158
|
+
globalThis as { AggregateError?: AggregateErrorConstructor }
|
|
159
|
+
).AggregateError;
|
|
160
|
+
const error =
|
|
161
|
+
typeof Ctor === 'function'
|
|
162
|
+
? new Ctor(value.errors, value.message, opts)
|
|
163
|
+
: Object.assign(new Error(value.message, opts), {
|
|
164
|
+
name: 'AggregateError',
|
|
165
|
+
errors: value.errors,
|
|
166
|
+
});
|
|
167
|
+
if (value.stack !== undefined) error.stack = value.stack;
|
|
168
|
+
return error;
|
|
169
|
+
},
|
|
170
|
+
// `FatalError` and `RetryableError` are not built-in browser globals,
|
|
171
|
+
// so we can't resolve a constructor from globalThis. The web o11y UI
|
|
172
|
+
// doesn't need `instanceof FatalError` to pass (no user code runs
|
|
173
|
+
// here) — it just needs `name`, `message`, `stack`, and any extra
|
|
174
|
+
// enumerable fields to render. Construct a plain `Error` with `name`
|
|
175
|
+
// set; ObjectInspector reads `constructor.name` for the displayed
|
|
176
|
+
// class label, but we don't have the real class, so we emit a tagged
|
|
177
|
+
// Error whose `name` field carries the class identity. This matches
|
|
178
|
+
// how the existing base `Error` reviver presents unknown subclasses.
|
|
179
|
+
FatalError: (value) => {
|
|
180
|
+
const opts = 'cause' in value ? { cause: value.cause } : undefined;
|
|
181
|
+
const error = new Error(value.message, opts);
|
|
182
|
+
error.name = 'FatalError';
|
|
183
|
+
if (value.stack !== undefined) error.stack = value.stack;
|
|
184
|
+
return error;
|
|
185
|
+
},
|
|
186
|
+
RetryableError: (value) => {
|
|
187
|
+
const opts = 'cause' in value ? { cause: value.cause } : undefined;
|
|
188
|
+
const error = new Error(value.message, opts) as Error & {
|
|
189
|
+
retryAfter?: Date;
|
|
190
|
+
};
|
|
191
|
+
error.name = 'RetryableError';
|
|
192
|
+
if (value.stack !== undefined) error.stack = value.stack;
|
|
193
|
+
// `retryAfter` is serialized as an epoch ms number (see the runtime
|
|
194
|
+
// RetryableError reducer for the rationale around realm-safety).
|
|
195
|
+
// Rehydrate as a Date so o11y consumers can render it directly.
|
|
196
|
+
// Guard against payloads from older runtime versions that predate
|
|
197
|
+
// the field — without this check, `new Date(undefined)` would
|
|
198
|
+
// produce an Invalid Date rather than omitting the property.
|
|
199
|
+
if (value.retryAfter != null) {
|
|
200
|
+
error.retryAfter = new Date(value.retryAfter);
|
|
201
|
+
}
|
|
202
|
+
return error;
|
|
203
|
+
},
|
|
204
|
+
DOMException: (value) => {
|
|
205
|
+
// Modern browsers and Node 18+ expose `DOMException` on globalThis.
|
|
206
|
+
// `AbortController.abort()` with no argument synthesizes one as the
|
|
207
|
+
// signal's reason, so this is a common payload for any aborted step.
|
|
208
|
+
const G = globalThis as { DOMException?: typeof DOMException };
|
|
209
|
+
if (typeof G.DOMException === 'function') {
|
|
210
|
+
const e = new G.DOMException(value.message, value.name);
|
|
211
|
+
if (value.stack !== undefined) e.stack = value.stack;
|
|
212
|
+
if ('cause' in value) (e as { cause?: unknown }).cause = value.cause;
|
|
213
|
+
return e;
|
|
214
|
+
}
|
|
80
215
|
const error = new Error(value.message);
|
|
81
216
|
error.name = value.name;
|
|
82
|
-
error.stack = value.stack;
|
|
217
|
+
if (value.stack !== undefined) error.stack = value.stack;
|
|
218
|
+
if ('cause' in value) {
|
|
219
|
+
(error as Error & { cause?: unknown }).cause = value.cause;
|
|
220
|
+
}
|
|
83
221
|
return error;
|
|
84
222
|
},
|
|
85
223
|
Float32Array: (value: string) => new Float32Array(reviveArrayBuffer(value)),
|
|
@@ -136,6 +274,11 @@ export function getWebRevivers(): Revivers {
|
|
|
136
274
|
// react-inspector shows the class name (it reads constructor.name).
|
|
137
275
|
Class: (value) => `<class:${extractClassName(value.classId)}>`,
|
|
138
276
|
Instance: (value) => {
|
|
277
|
+
// Run instances are rendered as clickable RunRef badges
|
|
278
|
+
const runRef = serializedInstanceToRef(value);
|
|
279
|
+
if (isRunRef(runRef)) {
|
|
280
|
+
return runRef;
|
|
281
|
+
}
|
|
139
282
|
const className = extractClassName(value.classId);
|
|
140
283
|
const data = value.data;
|
|
141
284
|
const props =
|
|
@@ -274,9 +417,14 @@ function replaceEncryptedAndExpiredWithMarkers<T>(resource: T): T {
|
|
|
274
417
|
}
|
|
275
418
|
|
|
276
419
|
if (result.eventData && typeof result.eventData === 'object') {
|
|
420
|
+
const eventType =
|
|
421
|
+
typeof result.eventType === 'string' ? result.eventType : '';
|
|
422
|
+
const refKeys = EVENT_DATA_REF_FIELDS[eventType] ?? [];
|
|
277
423
|
const ed = { ...(result.eventData as Record<string, unknown>) };
|
|
278
|
-
for (const key of
|
|
279
|
-
|
|
424
|
+
for (const key of refKeys) {
|
|
425
|
+
if (key in ed) {
|
|
426
|
+
ed[key] = toDisplayMarker(ed[key]);
|
|
427
|
+
}
|
|
280
428
|
}
|
|
281
429
|
result.eventData = ed;
|
|
282
430
|
}
|
|
@@ -284,15 +432,6 @@ function replaceEncryptedAndExpiredWithMarkers<T>(resource: T): T {
|
|
|
284
432
|
return result as T;
|
|
285
433
|
}
|
|
286
434
|
|
|
287
|
-
/** Known serialized subfields within eventData, matching hydrateEventData in core */
|
|
288
|
-
const EVENT_DATA_SERIALIZED_FIELDS = [
|
|
289
|
-
'result',
|
|
290
|
-
'input',
|
|
291
|
-
'output',
|
|
292
|
-
'metadata',
|
|
293
|
-
'payload',
|
|
294
|
-
];
|
|
295
|
-
|
|
296
435
|
/**
|
|
297
436
|
* Hydrate resource data with decryption support.
|
|
298
437
|
*
|
|
@@ -300,7 +439,7 @@ const EVENT_DATA_SERIALIZED_FIELDS = [
|
|
|
300
439
|
* This is the async version used when the user clicks "Decrypt" in the web UI.
|
|
301
440
|
*
|
|
302
441
|
* Handles both top-level fields (input, output, metadata) and nested
|
|
303
|
-
* eventData subfields
|
|
442
|
+
* eventData subfields per `EVENT_DATA_REF_FIELDS` from `@workflow/world` for that event type.
|
|
304
443
|
*/
|
|
305
444
|
export async function hydrateResourceIOWithKey<T>(
|
|
306
445
|
resource: T,
|
|
@@ -344,8 +483,11 @@ export async function hydrateResourceIOWithKey<T>(
|
|
|
344
483
|
|
|
345
484
|
// Decrypt + hydrate eventData subfields (events)
|
|
346
485
|
if (result.eventData && typeof result.eventData === 'object') {
|
|
486
|
+
const eventType =
|
|
487
|
+
typeof result.eventType === 'string' ? result.eventType : '';
|
|
488
|
+
const refKeys = EVENT_DATA_REF_FIELDS[eventType] ?? [];
|
|
347
489
|
const eventData = { ...(result.eventData as Record<string, unknown>) };
|
|
348
|
-
for (const field of
|
|
490
|
+
for (const field of refKeys) {
|
|
349
491
|
if (field in eventData) {
|
|
350
492
|
eventData[field] = await decryptField(
|
|
351
493
|
eventData[field],
|
|
@@ -359,3 +501,29 @@ export async function hydrateResourceIOWithKey<T>(
|
|
|
359
501
|
|
|
360
502
|
return result as T;
|
|
361
503
|
}
|
|
504
|
+
|
|
505
|
+
/**
|
|
506
|
+
* Check whether a hydrated resource (event, step, run, etc.) contains any
|
|
507
|
+
* encrypted display markers. Inspects the standard top-level fields
|
|
508
|
+
* (`input`, `output`, `error`, `metadata`) as well as the event-type-specific
|
|
509
|
+
* `eventData` ref fields.
|
|
510
|
+
*/
|
|
511
|
+
export function hasEncryptedFields(resource: unknown): boolean {
|
|
512
|
+
if (!resource || typeof resource !== 'object') return false;
|
|
513
|
+
const r = resource as Record<string, unknown>;
|
|
514
|
+
|
|
515
|
+
for (const key of ['input', 'output', 'metadata', 'error']) {
|
|
516
|
+
if (isEncryptedMarker(r[key])) return true;
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
if (r.eventData && typeof r.eventData === 'object') {
|
|
520
|
+
const eventType = typeof r.eventType === 'string' ? r.eventType : '';
|
|
521
|
+
const refKeys = EVENT_DATA_REF_FIELDS[eventType] ?? [];
|
|
522
|
+
const ed = r.eventData as Record<string, unknown>;
|
|
523
|
+
for (const key of refKeys) {
|
|
524
|
+
if (key in ed && isEncryptedMarker(ed[key])) return true;
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
return false;
|
|
529
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
export interface DecodedStreamChunkSource {
|
|
2
|
+
type: string;
|
|
3
|
+
encoding: 'utf-8';
|
|
4
|
+
rawSummary: string;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export interface FormattedStreamChunkDisplay {
|
|
8
|
+
text: string;
|
|
9
|
+
decodedFrom?: DecodedStreamChunkSource;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function summarizeArrayBufferView(value: ArrayBufferView): string {
|
|
13
|
+
const ta = value as unknown as {
|
|
14
|
+
length: number;
|
|
15
|
+
constructor: { name: string };
|
|
16
|
+
} & ArrayLike<number>;
|
|
17
|
+
const name = ta.constructor.name;
|
|
18
|
+
const preview = Array.from(
|
|
19
|
+
{ length: Math.min(ta.length, 8) },
|
|
20
|
+
(_, i) => ta[i]
|
|
21
|
+
);
|
|
22
|
+
const suffix = ta.length > 8 ? ', …' : '';
|
|
23
|
+
return `${name}(${ta.length}) [${preview.join(', ')}${suffix}]`;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Decode a typed array as UTF-8 text when valid, otherwise return a compact
|
|
28
|
+
* raw-byte summary. Used by `DataInspector`'s `collapseRefs` pipeline so
|
|
29
|
+
* hydrated `Uint8Array` chunks (e.g. AI SDK text deltas) render as readable
|
|
30
|
+
* text while still exposing the underlying byte layout.
|
|
31
|
+
*/
|
|
32
|
+
export function formatArrayBufferViewForDisplay(
|
|
33
|
+
value: ArrayBufferView
|
|
34
|
+
): FormattedStreamChunkDisplay {
|
|
35
|
+
try {
|
|
36
|
+
const text = new TextDecoder('utf-8', { fatal: true }).decode(value);
|
|
37
|
+
return {
|
|
38
|
+
text,
|
|
39
|
+
decodedFrom: {
|
|
40
|
+
type: value.constructor.name,
|
|
41
|
+
encoding: 'utf-8',
|
|
42
|
+
rawSummary: summarizeArrayBufferView(value),
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
} catch {
|
|
46
|
+
return { text: summarizeArrayBufferView(value) };
|
|
47
|
+
}
|
|
48
|
+
}
|
package/src/lib/trace-builder.ts
CHANGED
|
@@ -117,6 +117,7 @@ function buildSpans(
|
|
|
117
117
|
// unknown territory. Even when the run is completed, we may not have loaded
|
|
118
118
|
// all events yet, so always use the latest event we've actually seen.
|
|
119
119
|
const childMaxEnd = latestKnownTime;
|
|
120
|
+
const runMaxEnd = run.completedAt ?? now;
|
|
120
121
|
|
|
121
122
|
const stepSpans = Array.from(groupedEvents.eventsByStepId.values())
|
|
122
123
|
.map((events) => stepToSpan(events, childMaxEnd))
|
|
@@ -127,7 +128,7 @@ function buildSpans(
|
|
|
127
128
|
.filter((span): span is Span => span !== null);
|
|
128
129
|
|
|
129
130
|
const waitSpans = Array.from(groupedEvents.timerEvents.values())
|
|
130
|
-
.map((events) => waitToSpan(events, childMaxEnd))
|
|
131
|
+
.map((events) => waitToSpan(events, childMaxEnd, runMaxEnd))
|
|
131
132
|
.filter((span): span is Span => span !== null);
|
|
132
133
|
|
|
133
134
|
return {
|
package/src/lib/utils.ts
CHANGED
|
@@ -7,10 +7,6 @@ export function cn(...inputs: ClassValue[]) {
|
|
|
7
7
|
return twMerge(clsx(inputs));
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
-
const durationFormatter = new Intl.NumberFormat(undefined, {
|
|
11
|
-
maximumFractionDigits: 2,
|
|
12
|
-
});
|
|
13
|
-
|
|
14
10
|
const MS_IN_SECOND = 1000;
|
|
15
11
|
const MS_IN_MINUTE = 60 * MS_IN_SECOND;
|
|
16
12
|
const MS_IN_HOUR = 60 * MS_IN_MINUTE;
|
|
@@ -20,52 +16,53 @@ const MS_IN_DAY = 24 * MS_IN_HOUR;
|
|
|
20
16
|
* Formats a duration in milliseconds to a human-readable string.
|
|
21
17
|
*
|
|
22
18
|
* @param ms - Duration in milliseconds
|
|
23
|
-
* @param compact - If true, returns a
|
|
24
|
-
* If false (default), returns multi-part format (e.g., "
|
|
19
|
+
* @param compact - If true, returns a compact format (e.g., "380ms", "2m 30s").
|
|
20
|
+
* If false (default), returns multi-part format (e.g., "1m 13s", "2d 5h 3m 12s").
|
|
25
21
|
*
|
|
26
|
-
* Compact format:
|
|
27
|
-
* - < 1s: shows milliseconds (e.g., "
|
|
22
|
+
* Compact format (timeline markers):
|
|
23
|
+
* - < 1s: shows milliseconds (e.g., "380ms")
|
|
28
24
|
* - < 1m: shows seconds (e.g., "45s")
|
|
29
|
-
* - < 1h: shows minutes (e.g., "
|
|
30
|
-
* - >= 1h: shows hours (e.g., "
|
|
25
|
+
* - < 1h: shows minutes and seconds (e.g., "2m 30s")
|
|
26
|
+
* - >= 1h: shows hours and minutes (e.g., "2h 30m")
|
|
31
27
|
*
|
|
32
28
|
* Full format:
|
|
33
|
-
* - < 1s: shows milliseconds (e.g., "
|
|
34
|
-
* - < 1m: shows seconds (e.g., "
|
|
35
|
-
* - >= 1m: shows
|
|
29
|
+
* - < 1s: shows milliseconds (e.g., "380ms")
|
|
30
|
+
* - < 1m: shows seconds (e.g., "45s")
|
|
31
|
+
* - >= 1m: shows decomposed format with whole seconds (e.g., "1m 13s", "2m 13s")
|
|
36
32
|
*/
|
|
37
33
|
export function formatDuration(ms: number, compact = false): string {
|
|
38
34
|
if (ms === 0) {
|
|
39
|
-
return '
|
|
35
|
+
return '0s';
|
|
40
36
|
}
|
|
41
37
|
|
|
42
|
-
// For durations less than 1 second, show milliseconds
|
|
43
38
|
if (ms < MS_IN_SECOND) {
|
|
44
|
-
|
|
39
|
+
const roundedMs = Math.round(ms);
|
|
40
|
+
return roundedMs < MS_IN_SECOND ? `${roundedMs}ms` : '1s';
|
|
45
41
|
}
|
|
46
42
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
43
|
+
const roundedMs = Math.round(ms / MS_IN_SECOND) * MS_IN_SECOND;
|
|
44
|
+
|
|
45
|
+
if (roundedMs < MS_IN_MINUTE) {
|
|
46
|
+
return `${Math.floor(roundedMs / MS_IN_SECOND)}s`;
|
|
50
47
|
}
|
|
51
48
|
|
|
52
49
|
// Compact format: multi-unit without decimals (e.g. "8m 20s", "2h 30m")
|
|
53
50
|
if (compact) {
|
|
54
|
-
if (
|
|
55
|
-
const m = Math.floor(
|
|
56
|
-
const s = Math.floor((
|
|
51
|
+
if (roundedMs < MS_IN_HOUR) {
|
|
52
|
+
const m = Math.floor(roundedMs / MS_IN_MINUTE);
|
|
53
|
+
const s = Math.floor((roundedMs % MS_IN_MINUTE) / MS_IN_SECOND);
|
|
57
54
|
return s > 0 ? `${m}m ${s}s` : `${m}m`;
|
|
58
55
|
}
|
|
59
|
-
const h = Math.floor(
|
|
60
|
-
const m = Math.floor((
|
|
56
|
+
const h = Math.floor(roundedMs / MS_IN_HOUR);
|
|
57
|
+
const m = Math.floor((roundedMs % MS_IN_HOUR) / MS_IN_MINUTE);
|
|
61
58
|
return m > 0 ? `${h}h ${m}m` : `${h}h`;
|
|
62
59
|
}
|
|
63
60
|
|
|
64
|
-
// Full format:
|
|
65
|
-
const days = Math.floor(
|
|
66
|
-
const hours = Math.floor((
|
|
67
|
-
const minutes = Math.floor((
|
|
68
|
-
const seconds = Math.floor((
|
|
61
|
+
// Full format: decompose into larger units + whole seconds.
|
|
62
|
+
const days = Math.floor(roundedMs / MS_IN_DAY);
|
|
63
|
+
const hours = Math.floor((roundedMs % MS_IN_DAY) / MS_IN_HOUR);
|
|
64
|
+
const minutes = Math.floor((roundedMs % MS_IN_HOUR) / MS_IN_MINUTE);
|
|
65
|
+
const seconds = Math.floor((roundedMs % MS_IN_MINUTE) / MS_IN_SECOND);
|
|
69
66
|
|
|
70
67
|
const parts: string[] = [];
|
|
71
68
|
|
|
@@ -78,9 +75,7 @@ export function formatDuration(ms: number, compact = false): string {
|
|
|
78
75
|
if (minutes > 0) {
|
|
79
76
|
parts.push(`${minutes}m`);
|
|
80
77
|
}
|
|
81
|
-
|
|
82
|
-
parts.push(`${seconds}s`);
|
|
83
|
-
}
|
|
78
|
+
parts.push(`${seconds}s`);
|
|
84
79
|
|
|
85
80
|
return parts.join(' ');
|
|
86
81
|
}
|