@workflow/web-shared 5.0.0-beta.4 → 5.0.0-beta.5
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/components/new-trace-viewer/components/event-list.js +2 -2
- package/dist/components/new-trace-viewer/components/event-list.js.map +1 -1
- package/dist/components/new-trace-viewer/components/middle-truncate/middle-truncate.js +1 -1
- package/dist/components/new-trace-viewer/components/middle-truncate/middle-truncate.js.map +1 -1
- package/dist/components/new-trace-viewer/trace-viewer.js +10 -4
- package/dist/components/new-trace-viewer/trace-viewer.js.map +1 -1
- package/dist/components/sidebar/attribute-panel.d.ts.map +1 -1
- package/dist/components/sidebar/attribute-panel.js +6 -0
- package/dist/components/sidebar/attribute-panel.js.map +1 -1
- package/dist/components/ui/error-stack-block.d.ts.map +1 -1
- package/dist/components/ui/error-stack-block.js +24 -2
- package/dist/components/ui/error-stack-block.js.map +1 -1
- package/dist/components/workflow-trace-view.js +1 -1
- package/dist/components/workflow-trace-view.js.map +1 -1
- package/dist/components/workflow-traces/trace-span-construction.js +1 -1
- package/dist/components/workflow-traces/trace-span-construction.js.map +1 -1
- package/dist/lib/hydration.d.ts +6 -0
- package/dist/lib/hydration.d.ts.map +1 -1
- package/dist/lib/hydration.js +124 -1
- package/dist/lib/hydration.js.map +1 -1
- package/package.json +5 -4
- package/src/components/new-trace-viewer/components/event-list.tsx +9 -9
- package/src/components/new-trace-viewer/components/middle-truncate/middle-truncate.tsx +6 -6
- package/src/components/new-trace-viewer/trace-viewer.tsx +54 -46
- package/src/components/sidebar/attribute-panel.tsx +5 -0
- package/src/components/ui/error-stack-block.tsx +32 -4
- package/src/components/workflow-trace-view.tsx +1 -1
- package/src/components/workflow-traces/trace-span-construction.ts +1 -1
- package/src/lib/hydration.ts +132 -1
package/src/lib/hydration.ts
CHANGED
|
@@ -58,12 +58,60 @@ function base64ToArrayBuffer(base64: string): ArrayBuffer {
|
|
|
58
58
|
// Web revivers (browser-safe, no Buffer dependency)
|
|
59
59
|
// ---------------------------------------------------------------------------
|
|
60
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
|
+
|
|
61
103
|
/**
|
|
62
104
|
* Get the web-specific revivers for hydrating serialized data.
|
|
63
105
|
*
|
|
64
106
|
* Uses `atob()` for base64 decoding (no Node.js Buffer dependency).
|
|
65
107
|
* All types are revived as real instances (Date, Map, Set, URL,
|
|
66
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.
|
|
67
115
|
*/
|
|
68
116
|
export function getWebRevivers(): Revivers {
|
|
69
117
|
function reviveArrayBuffer(value: string): ArrayBuffer {
|
|
@@ -83,10 +131,93 @@ export function getWebRevivers(): Revivers {
|
|
|
83
131
|
BigUint64Array: (value: string) =>
|
|
84
132
|
new BigUint64Array(reviveArrayBuffer(value)),
|
|
85
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".
|
|
86
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
|
+
}
|
|
87
215
|
const error = new Error(value.message);
|
|
88
216
|
error.name = value.name;
|
|
89
|
-
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
|
+
}
|
|
90
221
|
return error;
|
|
91
222
|
},
|
|
92
223
|
Float32Array: (value: string) => new Float32Array(reviveArrayBuffer(value)),
|