@workflow/web-shared 5.0.0-beta.3 → 5.0.0-beta.31
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 +2 -10
- package/dist/components/error-boundary.js +1 -1
- package/dist/components/event-list-view.d.ts +46 -1
- package/dist/components/event-list-view.d.ts.map +1 -1
- package/dist/components/event-list-view.js +228 -90
- package/dist/components/hook-actions.js +1 -1
- package/dist/components/index.d.ts +6 -2
- 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.js +3 -3
- package/dist/components/new-trace-viewer/components/detail-panel-width.d.ts +34 -0
- package/dist/components/new-trace-viewer/components/detail-panel-width.d.ts.map +1 -0
- package/dist/components/new-trace-viewer/components/detail-panel-width.js +67 -0
- package/dist/components/new-trace-viewer/components/detail-panel.d.ts +14 -0
- package/dist/components/new-trace-viewer/components/detail-panel.d.ts.map +1 -0
- package/dist/components/new-trace-viewer/components/detail-panel.js +122 -0
- package/dist/components/new-trace-viewer/components/draggable-border.d.ts +31 -0
- package/dist/components/new-trace-viewer/components/draggable-border.d.ts.map +1 -0
- package/dist/components/new-trace-viewer/components/draggable-border.js +140 -0
- package/dist/components/new-trace-viewer/components/event-list.d.ts +4 -2
- package/dist/components/new-trace-viewer/components/event-list.d.ts.map +1 -1
- package/dist/components/new-trace-viewer/components/event-list.js +22 -13
- 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/minimap.d.ts +14 -0
- package/dist/components/new-trace-viewer/components/minimap.d.ts.map +1 -0
- package/dist/components/new-trace-viewer/components/minimap.js +337 -0
- package/dist/components/new-trace-viewer/components/pane-constants.d.ts +14 -0
- package/dist/components/new-trace-viewer/components/pane-constants.d.ts.map +1 -0
- package/dist/components/new-trace-viewer/components/pane-constants.js +16 -0
- package/dist/components/new-trace-viewer/components/span-markers.d.ts +46 -0
- package/dist/components/new-trace-viewer/components/span-markers.d.ts.map +1 -0
- package/dist/components/new-trace-viewer/components/span-markers.js +85 -0
- package/dist/components/new-trace-viewer/components/split-pane.d.ts +3 -7
- package/dist/components/new-trace-viewer/components/split-pane.d.ts.map +1 -1
- package/dist/components/new-trace-viewer/components/split-pane.js +25 -84
- package/dist/components/new-trace-viewer/components/timeline.d.ts +19 -15
- package/dist/components/new-trace-viewer/components/timeline.d.ts.map +1 -1
- package/dist/components/new-trace-viewer/components/timeline.js +229 -111
- package/dist/components/new-trace-viewer/components/timeline.module.css +46 -0
- package/dist/components/new-trace-viewer/components/trace-shortcut-helper.d.ts +5 -0
- package/dist/components/new-trace-viewer/components/trace-shortcut-helper.d.ts.map +1 -0
- package/dist/components/new-trace-viewer/components/trace-shortcut-helper.js +55 -0
- package/dist/components/new-trace-viewer/components/trace-shortcut-helper.module.css +20 -0
- package/dist/components/new-trace-viewer/components/trace-viewer-skeleton.d.ts +2 -0
- package/dist/components/new-trace-viewer/components/trace-viewer-skeleton.d.ts.map +1 -0
- package/dist/components/new-trace-viewer/components/trace-viewer-skeleton.js +26 -0
- package/dist/components/new-trace-viewer/components/use-element-width.d.ts +8 -0
- package/dist/components/new-trace-viewer/components/use-element-width.d.ts.map +1 -0
- package/dist/components/new-trace-viewer/components/use-element-width.js +25 -0
- package/dist/components/new-trace-viewer/components/use-row-window.d.ts +34 -0
- package/dist/components/new-trace-viewer/components/use-row-window.d.ts.map +1 -0
- package/dist/components/new-trace-viewer/components/use-row-window.js +107 -0
- package/dist/components/new-trace-viewer/context.d.ts +3 -1
- package/dist/components/new-trace-viewer/context.d.ts.map +1 -1
- package/dist/components/new-trace-viewer/context.js +9 -10
- package/dist/components/new-trace-viewer/icons.js +3 -3
- 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 +6 -3
- package/dist/components/new-trace-viewer/trace-viewer.d.ts.map +1 -1
- package/dist/components/new-trace-viewer/trace-viewer.js +167 -162
- package/dist/components/new-trace-viewer/types.d.ts +2 -0
- package/dist/components/new-trace-viewer/types.d.ts.map +1 -1
- package/dist/components/new-trace-viewer/types.js +2 -2
- package/dist/components/new-trace-viewer/utils.d.ts +48 -13
- package/dist/components/new-trace-viewer/utils.d.ts.map +1 -1
- package/dist/components/new-trace-viewer/utils.js +135 -107
- package/dist/components/run-trace-view.d.ts +5 -7
- 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 +4 -1
- package/dist/components/sidebar/attribute-panel.d.ts.map +1 -1
- package/dist/components/sidebar/attribute-panel.js +133 -113
- package/dist/components/sidebar/attributes-block.d.ts +40 -0
- package/dist/components/sidebar/attributes-block.d.ts.map +1 -0
- package/dist/components/sidebar/attributes-block.js +140 -0
- package/dist/components/sidebar/conversation-view.js +1 -1
- package/dist/components/sidebar/copyable-data-block.d.ts +2 -0
- package/dist/components/sidebar/copyable-data-block.d.ts.map +1 -1
- package/dist/components/sidebar/copyable-data-block.js +17 -16
- package/dist/components/sidebar/entity-detail-panel.d.ts +11 -11
- package/dist/components/sidebar/entity-detail-panel.d.ts.map +1 -1
- package/dist/components/sidebar/entity-detail-panel.js +35 -69
- package/dist/components/sidebar/events-list.d.ts +6 -2
- package/dist/components/sidebar/events-list.d.ts.map +1 -1
- package/dist/components/sidebar/events-list.js +76 -62
- package/dist/components/sidebar/resolve-hook-modal.js +1 -1
- package/dist/components/sidebar/sidebar-data-context.d.ts +10 -7
- package/dist/components/sidebar/sidebar-data-context.d.ts.map +1 -1
- package/dist/components/sidebar/sidebar-data-context.js +1 -1
- package/dist/components/sidebar/span-detail-merge.d.ts +31 -0
- package/dist/components/sidebar/span-detail-merge.d.ts.map +1 -0
- package/dist/components/sidebar/span-detail-merge.js +92 -0
- package/dist/components/sidebar/use-selected-span-detail.d.ts +16 -0
- package/dist/components/sidebar/use-selected-span-detail.d.ts.map +1 -0
- package/dist/components/sidebar/use-selected-span-detail.js +93 -0
- package/dist/components/stream-viewer.js +1 -1
- package/dist/components/trace-viewer/components/map.d.ts +2 -2
- package/dist/components/trace-viewer/components/map.d.ts.map +1 -1
- 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.d.ts +7 -7
- package/dist/components/trace-viewer/components/node.d.ts.map +1 -1
- package/dist/components/trace-viewer/components/node.js +2 -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/trace-viewer.module.css +4 -4
- 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 +3 -3
- package/dist/components/trace-viewer/util/timing.d.ts.map +1 -1
- package/dist/components/trace-viewer/util/timing.js +8 -11
- 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 +5 -1
- package/dist/components/trace-viewer-new.d.ts.map +1 -1
- package/dist/components/trace-viewer-new.js +8 -10
- package/dist/components/ui/alert.js +2 -2
- 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 +2 -2
- package/dist/components/ui/collapsible.d.ts +46 -0
- package/dist/components/ui/collapsible.d.ts.map +1 -0
- package/dist/components/ui/collapsible.js +66 -0
- package/dist/components/ui/context-card.d.ts +47 -0
- package/dist/components/ui/context-card.d.ts.map +1 -0
- package/dist/components/ui/context-card.js +471 -0
- package/dist/components/ui/data-inspector.d.ts +7 -6
- package/dist/components/ui/data-inspector.d.ts.map +1 -1
- package/dist/components/ui/data-inspector.js +232 -99
- package/dist/components/ui/data-inspector.styles.d.ts +29 -0
- package/dist/components/ui/data-inspector.styles.d.ts.map +1 -0
- package/dist/components/ui/data-inspector.styles.js +95 -0
- package/dist/components/ui/decrypt-button.js +1 -1
- package/dist/components/ui/error-card.js +2 -2
- package/dist/components/ui/error-stack-block.d.ts +17 -10
- package/dist/components/ui/error-stack-block.d.ts.map +1 -1
- package/dist/components/ui/error-stack-block.js +49 -30
- package/dist/components/ui/icon-button.d.ts +19 -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/kbd.d.ts +10 -0
- package/dist/components/ui/kbd.d.ts.map +1 -0
- package/dist/components/ui/kbd.js +25 -0
- 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 +2 -2
- package/dist/components/ui/spinner.js +1 -1
- package/dist/components/ui/timestamp-tooltip.d.ts +34 -1
- package/dist/components/ui/timestamp-tooltip.d.ts.map +1 -1
- package/dist/components/ui/timestamp-tooltip.js +80 -132
- package/dist/components/ui/tooltip.d.ts +10 -0
- package/dist/components/ui/tooltip.d.ts.map +1 -0
- package/dist/components/ui/tooltip.js +12 -0
- package/dist/components/workflow-trace-view.d.ts +7 -8
- package/dist/components/workflow-trace-view.d.ts.map +1 -1
- package/dist/components/workflow-trace-view.js +11 -16
- package/dist/components/workflow-traces/event-colors.d.ts +2 -1
- package/dist/components/workflow-traces/event-colors.d.ts.map +1 -1
- package/dist/components/workflow-traces/event-colors.js +15 -7
- package/dist/components/workflow-traces/trace-colors.d.ts.map +1 -1
- package/dist/components/workflow-traces/trace-colors.js +3 -4
- package/dist/components/workflow-traces/trace-span-construction.d.ts +7 -4
- package/dist/components/workflow-traces/trace-span-construction.d.ts.map +1 -1
- package/dist/components/workflow-traces/trace-span-construction.js +87 -33
- package/dist/components/workflow-traces/trace-time-utils.js +1 -1
- package/dist/hooks/use-dark-mode.js +1 -1
- package/dist/hooks/use-intersection-observer.d.ts +17 -0
- package/dist/hooks/use-intersection-observer.d.ts.map +1 -0
- package/dist/hooks/use-intersection-observer.js +29 -0
- package/dist/hooks/use-load-more-on-scroll.d.ts +21 -0
- package/dist/hooks/use-load-more-on-scroll.d.ts.map +1 -0
- package/dist/hooks/use-load-more-on-scroll.js +28 -0
- 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 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -3
- package/dist/lib/cn.d.ts +10 -0
- package/dist/lib/cn.d.ts.map +1 -0
- package/dist/lib/cn.js +83 -0
- package/dist/lib/event-analysis.d.ts +1 -1
- package/dist/lib/event-analysis.d.ts.map +1 -1
- package/dist/lib/event-analysis.js +3 -2
- package/dist/lib/event-materialization.d.ts +1 -1
- package/dist/lib/event-materialization.d.ts.map +1 -1
- package/dist/lib/event-materialization.js +29 -21
- 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 +17 -2
- package/dist/lib/hydration.d.ts.map +1 -1
- package/dist/lib/hydration.js +185 -22
- package/dist/lib/stream-display.js +1 -1
- package/dist/lib/toast.js +1 -1
- package/dist/lib/trace-builder.d.ts +16 -4
- package/dist/lib/trace-builder.d.ts.map +1 -1
- package/dist/lib/trace-builder.js +34 -15
- package/dist/lib/utils.d.ts +23 -9
- package/dist/lib/utils.d.ts.map +1 -1
- package/dist/lib/utils.js +73 -33
- package/dist/lib/zstd-browser-decoder.d.ts +7 -0
- package/dist/lib/zstd-browser-decoder.d.ts.map +1 -0
- package/dist/lib/zstd-browser-decoder.js +41 -0
- package/dist/styles.css +14 -0
- package/package.json +10 -7
- package/src/components/event-list-view.tsx +375 -116
- package/src/components/index.ts +12 -5
- package/src/components/new-trace-viewer/components/copy-button.tsx +2 -2
- package/src/components/new-trace-viewer/components/detail-panel-width.test.ts +123 -0
- package/src/components/new-trace-viewer/components/detail-panel-width.ts +76 -0
- package/src/components/new-trace-viewer/components/detail-panel.tsx +273 -0
- package/src/components/new-trace-viewer/components/draggable-border.tsx +216 -0
- package/src/components/new-trace-viewer/components/event-list.tsx +57 -32
- 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/minimap.tsx +559 -0
- package/src/components/new-trace-viewer/components/pane-constants.ts +19 -0
- package/src/components/new-trace-viewer/components/span-markers.tsx +173 -0
- package/src/components/new-trace-viewer/components/split-pane.tsx +80 -135
- package/src/components/new-trace-viewer/components/timeline.module.css +46 -0
- package/src/components/new-trace-viewer/components/timeline.tsx +603 -239
- package/src/components/new-trace-viewer/components/trace-shortcut-helper.module.css +20 -0
- package/src/components/new-trace-viewer/components/trace-shortcut-helper.tsx +116 -0
- package/src/components/new-trace-viewer/components/trace-viewer-skeleton.tsx +114 -0
- package/src/components/new-trace-viewer/components/use-element-width.ts +29 -0
- package/src/components/new-trace-viewer/components/use-row-window.ts +140 -0
- package/src/components/new-trace-viewer/context.tsx +13 -14
- package/src/components/new-trace-viewer/icons.tsx +2 -2
- package/src/components/new-trace-viewer/search.ts +178 -0
- package/src/components/new-trace-viewer/trace-viewer.tsx +336 -293
- package/src/components/new-trace-viewer/types.ts +2 -0
- package/src/components/new-trace-viewer/utils.test.ts +247 -0
- package/src/components/new-trace-viewer/utils.ts +203 -134
- package/src/components/run-trace-view.tsx +10 -14
- package/src/components/sidebar/attribute-panel.tsx +276 -275
- package/src/components/sidebar/attributes-block.tsx +326 -0
- package/src/components/sidebar/copyable-data-block.tsx +50 -28
- package/src/components/sidebar/entity-detail-panel.tsx +89 -123
- package/src/components/sidebar/events-list.tsx +196 -178
- package/src/components/sidebar/sidebar-data-context.tsx +11 -11
- package/src/components/sidebar/span-detail-merge.ts +134 -0
- package/src/components/sidebar/use-selected-span-detail.ts +146 -0
- package/src/components/trace-viewer/components/node.tsx +3 -2
- package/src/components/trace-viewer/trace-viewer.module.css +4 -4
- package/src/components/trace-viewer/util/timing.ts +7 -11
- package/src/components/trace-viewer-new.tsx +21 -15
- package/src/components/ui/alert.tsx +1 -1
- package/src/components/ui/button.tsx +68 -0
- package/src/components/ui/card.tsx +1 -1
- package/src/components/ui/collapsible.tsx +219 -0
- package/src/components/ui/context-card.tsx +784 -0
- package/src/components/ui/data-inspector.styles.ts +96 -0
- package/src/components/ui/data-inspector.tsx +501 -204
- package/src/components/ui/error-card.tsx +1 -1
- package/src/components/ui/error-stack-block.tsx +84 -55
- package/src/components/ui/icon-button.tsx +53 -0
- package/src/components/ui/kbd.tsx +43 -0
- package/src/components/ui/skeleton.tsx +1 -1
- package/src/components/ui/timestamp-tooltip.tsx +132 -194
- package/src/components/ui/tooltip.tsx +47 -0
- package/src/components/workflow-trace-view.tsx +31 -36
- package/src/components/workflow-traces/event-colors.ts +15 -11
- package/src/components/workflow-traces/trace-colors.ts +6 -6
- package/src/components/workflow-traces/trace-span-construction.test.ts +85 -0
- package/src/components/workflow-traces/trace-span-construction.ts +118 -35
- package/src/hooks/use-intersection-observer.ts +57 -0
- package/src/hooks/use-load-more-on-scroll.ts +49 -0
- package/src/hooks/use-reduced-motion.ts +34 -0
- package/src/index.ts +9 -0
- package/src/lib/cn.ts +93 -0
- package/src/lib/event-analysis.ts +6 -4
- package/src/lib/event-materialization.ts +35 -21
- package/src/lib/exact-event-search-id.ts +67 -0
- package/src/lib/hydration.ts +203 -29
- package/src/lib/trace-builder.ts +44 -19
- package/src/lib/utils.test.ts +33 -0
- package/src/lib/utils.ts +82 -35
- package/src/lib/zstd-browser-decoder.ts +42 -0
- package/src/styles.css +14 -0
- 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/new-trace-viewer/components/copy-button.js.map +0 -1
- package/dist/components/new-trace-viewer/components/event-list.js.map +0 -1
- package/dist/components/new-trace-viewer/components/split-pane.js.map +0 -1
- package/dist/components/new-trace-viewer/components/timeline.js.map +0 -1
- package/dist/components/new-trace-viewer/context.js.map +0 -1
- package/dist/components/new-trace-viewer/detail-panel.d.ts +0 -10
- package/dist/components/new-trace-viewer/detail-panel.d.ts.map +0 -1
- package/dist/components/new-trace-viewer/detail-panel.js +0 -11
- package/dist/components/new-trace-viewer/detail-panel.js.map +0 -1
- package/dist/components/new-trace-viewer/icons.js.map +0 -1
- package/dist/components/new-trace-viewer/trace-viewer.js.map +0 -1
- package/dist/components/new-trace-viewer/types.js.map +0 -1
- package/dist/components/new-trace-viewer/util/constants.d.ts +0 -1
- package/dist/components/new-trace-viewer/util/constants.d.ts.map +0 -1
- package/dist/components/new-trace-viewer/util/constants.js +0 -2
- package/dist/components/new-trace-viewer/util/constants.js.map +0 -1
- package/dist/components/new-trace-viewer/utils.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.d.ts +0 -14
- package/dist/components/sidebar/detail-card.d.ts.map +0 -1
- package/dist/components/sidebar/detail-card.js +0 -20
- 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/sidebar/sidebar-data-context.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/trace-viewer-new.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.d.ts +0 -95
- package/dist/components/ui/inspector-theme.d.ts.map +0 -1
- package/dist/components/ui/inspector-theme.js +0 -82
- 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/stream-display.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/components/new-trace-viewer/detail-panel.tsx +0 -57
- package/src/components/new-trace-viewer/util/constants.ts +0 -0
- package/src/components/sidebar/detail-card.tsx +0 -65
- package/src/components/ui/inspector-theme.ts +0 -110
|
@@ -10,7 +10,13 @@
|
|
|
10
10
|
* of making separate API calls for each entity type.
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
-
import
|
|
13
|
+
import {
|
|
14
|
+
type Event,
|
|
15
|
+
isHookLifecycleEventType,
|
|
16
|
+
isStepEventType,
|
|
17
|
+
isWaitEventType,
|
|
18
|
+
type StepStatus,
|
|
19
|
+
} from '@workflow/world';
|
|
14
20
|
|
|
15
21
|
// ---------------------------------------------------------------------------
|
|
16
22
|
// Materialized entity types
|
|
@@ -60,18 +66,18 @@ export interface MaterializedEntities {
|
|
|
60
66
|
}
|
|
61
67
|
|
|
62
68
|
// ---------------------------------------------------------------------------
|
|
63
|
-
// Helper: group events by correlationId
|
|
69
|
+
// Helper: group events by correlationId
|
|
64
70
|
// ---------------------------------------------------------------------------
|
|
65
71
|
|
|
66
72
|
function groupByCorrelationId(
|
|
67
73
|
events: Event[],
|
|
68
|
-
|
|
74
|
+
matchesEventType: (eventType: string) => boolean
|
|
69
75
|
): Map<string, Event[]> {
|
|
70
76
|
const groups = new Map<string, Event[]>();
|
|
71
77
|
for (const event of events) {
|
|
72
78
|
const cid = event.correlationId;
|
|
73
79
|
if (!cid) continue;
|
|
74
|
-
if (!
|
|
80
|
+
if (!matchesEventType(event.eventType)) continue;
|
|
75
81
|
const existing = groups.get(cid);
|
|
76
82
|
if (existing) {
|
|
77
83
|
existing.push(event);
|
|
@@ -82,6 +88,14 @@ function groupByCorrelationId(
|
|
|
82
88
|
return groups;
|
|
83
89
|
}
|
|
84
90
|
|
|
91
|
+
function getEventTimestamp(event: Event | undefined): Date | undefined {
|
|
92
|
+
const value = event?.occurredAt ?? event?.createdAt;
|
|
93
|
+
if (!value) return undefined;
|
|
94
|
+
|
|
95
|
+
const date = value instanceof Date ? value : new Date(value);
|
|
96
|
+
return Number.isNaN(date.getTime()) ? undefined : date;
|
|
97
|
+
}
|
|
98
|
+
|
|
85
99
|
// ---------------------------------------------------------------------------
|
|
86
100
|
// materializeSteps
|
|
87
101
|
// ---------------------------------------------------------------------------
|
|
@@ -93,7 +107,7 @@ function groupByCorrelationId(
|
|
|
93
107
|
* step_created event with no completion yet.
|
|
94
108
|
*/
|
|
95
109
|
export function materializeSteps(events: Event[]): MaterializedStep[] {
|
|
96
|
-
const groups = groupByCorrelationId(events,
|
|
110
|
+
const groups = groupByCorrelationId(events, isStepEventType);
|
|
97
111
|
const steps: MaterializedStep[] = [];
|
|
98
112
|
|
|
99
113
|
for (const [correlationId, stepEvents] of groups) {
|
|
@@ -104,31 +118,31 @@ export function materializeSteps(events: Event[]): MaterializedStep[] {
|
|
|
104
118
|
let attempt = 0;
|
|
105
119
|
let startedAt: Date | undefined;
|
|
106
120
|
let completedAt: Date | undefined;
|
|
107
|
-
let updatedAt = created.createdAt;
|
|
121
|
+
let updatedAt = getEventTimestamp(created) ?? created.createdAt;
|
|
108
122
|
|
|
109
123
|
for (const e of stepEvents) {
|
|
110
124
|
switch (e.eventType) {
|
|
111
125
|
case 'step_started':
|
|
112
126
|
status = 'running';
|
|
113
127
|
attempt += 1;
|
|
114
|
-
if (!startedAt) startedAt = e.createdAt;
|
|
128
|
+
if (!startedAt) startedAt = getEventTimestamp(e) ?? e.createdAt;
|
|
115
129
|
completedAt = undefined;
|
|
116
|
-
updatedAt = e.createdAt;
|
|
130
|
+
updatedAt = getEventTimestamp(e) ?? e.createdAt;
|
|
117
131
|
break;
|
|
118
132
|
case 'step_completed':
|
|
119
133
|
status = 'completed';
|
|
120
|
-
completedAt = e.createdAt;
|
|
121
|
-
updatedAt = e.createdAt;
|
|
134
|
+
completedAt = getEventTimestamp(e) ?? e.createdAt;
|
|
135
|
+
updatedAt = getEventTimestamp(e) ?? e.createdAt;
|
|
122
136
|
break;
|
|
123
137
|
case 'step_failed':
|
|
124
138
|
status = 'failed';
|
|
125
|
-
completedAt = e.createdAt;
|
|
126
|
-
updatedAt = e.createdAt;
|
|
139
|
+
completedAt = getEventTimestamp(e) ?? e.createdAt;
|
|
140
|
+
updatedAt = getEventTimestamp(e) ?? e.createdAt;
|
|
127
141
|
break;
|
|
128
142
|
case 'step_retrying':
|
|
129
143
|
status = 'pending';
|
|
130
144
|
completedAt = undefined;
|
|
131
|
-
updatedAt = e.createdAt;
|
|
145
|
+
updatedAt = getEventTimestamp(e) ?? e.createdAt;
|
|
132
146
|
break;
|
|
133
147
|
}
|
|
134
148
|
}
|
|
@@ -142,7 +156,7 @@ export function materializeSteps(events: Event[]): MaterializedStep[] {
|
|
|
142
156
|
: correlationId,
|
|
143
157
|
status,
|
|
144
158
|
attempt,
|
|
145
|
-
createdAt: created.createdAt,
|
|
159
|
+
createdAt: getEventTimestamp(created) ?? created.createdAt,
|
|
146
160
|
startedAt,
|
|
147
161
|
completedAt,
|
|
148
162
|
updatedAt,
|
|
@@ -161,7 +175,7 @@ export function materializeSteps(events: Event[]): MaterializedStep[] {
|
|
|
161
175
|
* Group hook_* events by correlationId and build Hook-like entities.
|
|
162
176
|
*/
|
|
163
177
|
export function materializeHooks(events: Event[]): MaterializedHook[] {
|
|
164
|
-
const groups = groupByCorrelationId(events,
|
|
178
|
+
const groups = groupByCorrelationId(events, isHookLifecycleEventType);
|
|
165
179
|
const hooks: MaterializedHook[] = [];
|
|
166
180
|
|
|
167
181
|
for (const [correlationId, hookEvents] of groups) {
|
|
@@ -181,10 +195,10 @@ export function materializeHooks(events: Event[]): MaterializedHook[] {
|
|
|
181
195
|
created.eventType === 'hook_created'
|
|
182
196
|
? created.eventData?.token
|
|
183
197
|
: undefined,
|
|
184
|
-
createdAt: created.createdAt,
|
|
198
|
+
createdAt: getEventTimestamp(created) ?? created.createdAt,
|
|
185
199
|
receivedCount: receivedEvents.length,
|
|
186
|
-
lastReceivedAt: lastReceived
|
|
187
|
-
disposedAt: disposed
|
|
200
|
+
lastReceivedAt: getEventTimestamp(lastReceived),
|
|
201
|
+
disposedAt: getEventTimestamp(disposed),
|
|
188
202
|
events: hookEvents,
|
|
189
203
|
});
|
|
190
204
|
}
|
|
@@ -200,7 +214,7 @@ export function materializeHooks(events: Event[]): MaterializedHook[] {
|
|
|
200
214
|
* Group wait_* events by correlationId and build Wait-like entities.
|
|
201
215
|
*/
|
|
202
216
|
export function materializeWaits(events: Event[]): MaterializedWait[] {
|
|
203
|
-
const groups = groupByCorrelationId(events,
|
|
217
|
+
const groups = groupByCorrelationId(events, isWaitEventType);
|
|
204
218
|
const waits: MaterializedWait[] = [];
|
|
205
219
|
|
|
206
220
|
for (const [correlationId, waitEvents] of groups) {
|
|
@@ -213,12 +227,12 @@ export function materializeWaits(events: Event[]): MaterializedWait[] {
|
|
|
213
227
|
waitId: correlationId,
|
|
214
228
|
runId: created.runId,
|
|
215
229
|
status: completed ? 'completed' : 'waiting',
|
|
216
|
-
createdAt: created.createdAt,
|
|
230
|
+
createdAt: getEventTimestamp(created) ?? created.createdAt,
|
|
217
231
|
resumeAt:
|
|
218
232
|
created.eventType === 'wait_created'
|
|
219
233
|
? created.eventData?.resumeAt
|
|
220
234
|
: undefined,
|
|
221
|
-
completedAt: completed
|
|
235
|
+
completedAt: getEventTimestamp(completed),
|
|
222
236
|
events: waitEvents,
|
|
223
237
|
});
|
|
224
238
|
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import type { Event } from '@workflow/world';
|
|
2
|
+
|
|
3
|
+
const WORKFLOW_ULID_BODY = '[0123456789ABCDEFGHJKMNPQRSTVWXYZ]{26}';
|
|
4
|
+
|
|
5
|
+
const STEP_ID_PATTERN = new RegExp(`^step_(${WORKFLOW_ULID_BODY})$`, 'i');
|
|
6
|
+
const WAIT_ID_PATTERN = new RegExp(`^wait_(${WORKFLOW_ULID_BODY})$`, 'i');
|
|
7
|
+
const HOOK_ID_PATTERN = new RegExp(`^hook_(${WORKFLOW_ULID_BODY})$`, 'i');
|
|
8
|
+
const EVENT_ID_PATTERN = new RegExp(`^evnt_(${WORKFLOW_ULID_BODY})$`, 'i');
|
|
9
|
+
|
|
10
|
+
const WORKFLOW_ID_PREFIX_PATTERN = /^(step_|wait_|hook_|evnt_|wrun_)/i;
|
|
11
|
+
|
|
12
|
+
export type ExactWorkflowSearchIdKind = 'step' | 'wait' | 'hook' | 'event';
|
|
13
|
+
|
|
14
|
+
export type ExactWorkflowSearchId = {
|
|
15
|
+
kind: ExactWorkflowSearchIdKind;
|
|
16
|
+
id: string;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export type ExactIdSearchResult =
|
|
20
|
+
| { status: 'ok'; events: Event[]; truncated?: boolean }
|
|
21
|
+
| { status: 'not_found' }
|
|
22
|
+
| { status: 'error'; message: string };
|
|
23
|
+
|
|
24
|
+
function matchPrefixedId(
|
|
25
|
+
pattern: RegExp,
|
|
26
|
+
prefix: 'step' | 'wait' | 'hook' | 'evnt',
|
|
27
|
+
kind: ExactWorkflowSearchIdKind,
|
|
28
|
+
query: string
|
|
29
|
+
): ExactWorkflowSearchId | null {
|
|
30
|
+
const match = query.match(pattern);
|
|
31
|
+
if (!match) {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
return { kind, id: `${prefix}_${match[1].toUpperCase()}` };
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Returns a parsed workflow ID when `query` is a full step, wait, hook, or event ID.
|
|
39
|
+
* Partial IDs and run IDs (`wrun_`) are ignored. ULID bodies are matched case-insensitively
|
|
40
|
+
* and normalized to uppercase in the returned ID.
|
|
41
|
+
*/
|
|
42
|
+
export function parseExactWorkflowSearchId(
|
|
43
|
+
query: string
|
|
44
|
+
): ExactWorkflowSearchId | null {
|
|
45
|
+
const trimmed = query.trim();
|
|
46
|
+
if (!trimmed) {
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return (
|
|
51
|
+
matchPrefixedId(STEP_ID_PATTERN, 'step', 'step', trimmed) ??
|
|
52
|
+
matchPrefixedId(WAIT_ID_PATTERN, 'wait', 'wait', trimmed) ??
|
|
53
|
+
matchPrefixedId(HOOK_ID_PATTERN, 'hook', 'hook', trimmed) ??
|
|
54
|
+
matchPrefixedId(EVENT_ID_PATTERN, 'evnt', 'event', trimmed)
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/** True when input looks like the user is attempting an ID search (including partial). */
|
|
59
|
+
export function looksLikeWorkflowIdSearchInput(query: string): boolean {
|
|
60
|
+
const trimmed = query.trim();
|
|
61
|
+
if (!WORKFLOW_ID_PREFIX_PATTERN.test(trimmed)) {
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
// Distinguish IDs (contain digits) from event-type strings like step_started.
|
|
65
|
+
// Assumes workflow event types do not include digits in their names.
|
|
66
|
+
return /\d/.test(trimmed);
|
|
67
|
+
}
|
package/src/lib/hydration.ts
CHANGED
|
@@ -16,7 +16,7 @@ import {
|
|
|
16
16
|
type Revivers,
|
|
17
17
|
serializedInstanceToRef,
|
|
18
18
|
} from '@workflow/core/serialization-format';
|
|
19
|
-
import {
|
|
19
|
+
import { getEventDataRefFields } from '@workflow/world';
|
|
20
20
|
|
|
21
21
|
// Re-export types and utilities that consumers need
|
|
22
22
|
export {
|
|
@@ -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,120 @@ 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` / `HookConflictError` /
|
|
139
|
+
// `RuntimeDecryptionError` and `AggregateError`. Without
|
|
140
|
+
// matching revivers here, `devalue.unflatten` throws "Unknown type X"
|
|
141
|
+
// — which surfaces in the web o11y UI as "Failed to load resource
|
|
142
|
+
// details: Unknown type FatalError".
|
|
86
143
|
Error: (value) => {
|
|
144
|
+
const opts = 'cause' in value ? { cause: value.cause } : undefined;
|
|
145
|
+
const error = new Error(value.message, opts);
|
|
146
|
+
error.name = value.name;
|
|
147
|
+
if (value.stack !== undefined) error.stack = value.stack;
|
|
148
|
+
return error;
|
|
149
|
+
},
|
|
150
|
+
EvalError: makeWebErrorSubclassReviver('EvalError'),
|
|
151
|
+
RangeError: makeWebErrorSubclassReviver('RangeError'),
|
|
152
|
+
ReferenceError: makeWebErrorSubclassReviver('ReferenceError'),
|
|
153
|
+
SyntaxError: makeWebErrorSubclassReviver('SyntaxError'),
|
|
154
|
+
TypeError: makeWebErrorSubclassReviver('TypeError'),
|
|
155
|
+
URIError: makeWebErrorSubclassReviver('URIError'),
|
|
156
|
+
AggregateError: (value) => {
|
|
157
|
+
const opts = 'cause' in value ? { cause: value.cause } : undefined;
|
|
158
|
+
const Ctor = (
|
|
159
|
+
globalThis as { AggregateError?: AggregateErrorConstructor }
|
|
160
|
+
).AggregateError;
|
|
161
|
+
const error =
|
|
162
|
+
typeof Ctor === 'function'
|
|
163
|
+
? new Ctor(value.errors, value.message, opts)
|
|
164
|
+
: Object.assign(new Error(value.message, opts), {
|
|
165
|
+
name: 'AggregateError',
|
|
166
|
+
errors: value.errors,
|
|
167
|
+
});
|
|
168
|
+
if (value.stack !== undefined) error.stack = value.stack;
|
|
169
|
+
return error;
|
|
170
|
+
},
|
|
171
|
+
// `FatalError` and `RetryableError` are not built-in browser globals,
|
|
172
|
+
// so we can't resolve a constructor from globalThis. The web o11y UI
|
|
173
|
+
// doesn't need `instanceof FatalError` to pass (no user code runs
|
|
174
|
+
// here) — it just needs `name`, `message`, `stack`, and any extra
|
|
175
|
+
// enumerable fields to render. Construct a plain `Error` with `name`
|
|
176
|
+
// set; ObjectInspector reads `constructor.name` for the displayed
|
|
177
|
+
// class label, but we don't have the real class, so we emit a tagged
|
|
178
|
+
// Error whose `name` field carries the class identity. This matches
|
|
179
|
+
// how the existing base `Error` reviver presents unknown subclasses.
|
|
180
|
+
FatalError: (value) => {
|
|
181
|
+
const opts = 'cause' in value ? { cause: value.cause } : undefined;
|
|
182
|
+
const error = new Error(value.message, opts);
|
|
183
|
+
error.name = 'FatalError';
|
|
184
|
+
if (value.stack !== undefined) error.stack = value.stack;
|
|
185
|
+
return error;
|
|
186
|
+
},
|
|
187
|
+
HookConflictError: (value) => {
|
|
188
|
+
const opts = 'cause' in value ? { cause: value.cause } : undefined;
|
|
189
|
+
const error = new Error(value.message, opts) as Error & {
|
|
190
|
+
token?: string;
|
|
191
|
+
conflictingRunId?: string;
|
|
192
|
+
};
|
|
193
|
+
error.name = 'HookConflictError';
|
|
194
|
+
error.token = value.token;
|
|
195
|
+
if (value.conflictingRunId !== undefined) {
|
|
196
|
+
error.conflictingRunId = value.conflictingRunId;
|
|
197
|
+
}
|
|
198
|
+
if (value.stack !== undefined) error.stack = value.stack;
|
|
199
|
+
return error;
|
|
200
|
+
},
|
|
201
|
+
RetryableError: (value) => {
|
|
202
|
+
const opts = 'cause' in value ? { cause: value.cause } : undefined;
|
|
203
|
+
const error = new Error(value.message, opts) as Error & {
|
|
204
|
+
retryAfter?: Date;
|
|
205
|
+
};
|
|
206
|
+
error.name = 'RetryableError';
|
|
207
|
+
if (value.stack !== undefined) error.stack = value.stack;
|
|
208
|
+
// `retryAfter` is serialized as an epoch ms number (see the runtime
|
|
209
|
+
// RetryableError reducer for the rationale around realm-safety).
|
|
210
|
+
// Rehydrate as a Date so o11y consumers can render it directly.
|
|
211
|
+
// Guard against payloads from older runtime versions that predate
|
|
212
|
+
// the field — without this check, `new Date(undefined)` would
|
|
213
|
+
// produce an Invalid Date rather than omitting the property.
|
|
214
|
+
if (value.retryAfter != null) {
|
|
215
|
+
error.retryAfter = new Date(value.retryAfter);
|
|
216
|
+
}
|
|
217
|
+
return error;
|
|
218
|
+
},
|
|
219
|
+
RuntimeDecryptionError: (value) => {
|
|
220
|
+
const opts = 'cause' in value ? { cause: value.cause } : undefined;
|
|
221
|
+
const error = new Error(value.message, opts) as Error & {
|
|
222
|
+
context?: unknown;
|
|
223
|
+
};
|
|
224
|
+
error.name = 'RuntimeDecryptionError';
|
|
225
|
+
if (value.context !== undefined) {
|
|
226
|
+
error.context = value.context;
|
|
227
|
+
}
|
|
228
|
+
if (value.stack !== undefined) error.stack = value.stack;
|
|
229
|
+
return error;
|
|
230
|
+
},
|
|
231
|
+
DOMException: (value) => {
|
|
232
|
+
// Modern browsers and Node 18+ expose `DOMException` on globalThis.
|
|
233
|
+
// `AbortController.abort()` with no argument synthesizes one as the
|
|
234
|
+
// signal's reason, so this is a common payload for any aborted step.
|
|
235
|
+
const G = globalThis as { DOMException?: typeof DOMException };
|
|
236
|
+
if (typeof G.DOMException === 'function') {
|
|
237
|
+
const e = new G.DOMException(value.message, value.name);
|
|
238
|
+
if (value.stack !== undefined) e.stack = value.stack;
|
|
239
|
+
if ('cause' in value) (e as { cause?: unknown }).cause = value.cause;
|
|
240
|
+
return e;
|
|
241
|
+
}
|
|
87
242
|
const error = new Error(value.message);
|
|
88
243
|
error.name = value.name;
|
|
89
|
-
error.stack = value.stack;
|
|
244
|
+
if (value.stack !== undefined) error.stack = value.stack;
|
|
245
|
+
if ('cause' in value) {
|
|
246
|
+
(error as Error & { cause?: unknown }).cause = value.cause;
|
|
247
|
+
}
|
|
90
248
|
return error;
|
|
91
249
|
},
|
|
92
250
|
Float32Array: (value: string) => new Float32Array(reviveArrayBuffer(value)),
|
|
@@ -140,7 +298,7 @@ export function getWebRevivers(): Revivers {
|
|
|
140
298
|
|
|
141
299
|
// Web-specific overrides for class instances.
|
|
142
300
|
// Create objects with a dynamically-named constructor so that
|
|
143
|
-
//
|
|
301
|
+
// the data inspector shows the class name (it reads constructor.name).
|
|
144
302
|
Class: (value) => `<class:${extractClassName(value.classId)}>`,
|
|
145
303
|
Instance: (value) => {
|
|
146
304
|
// Run instances are rendered as clickable RunRef badges
|
|
@@ -153,7 +311,7 @@ export function getWebRevivers(): Revivers {
|
|
|
153
311
|
const props =
|
|
154
312
|
data && typeof data === 'object' ? { ...data } : { value: data };
|
|
155
313
|
// Create a constructor with the right name using computed property
|
|
156
|
-
// so
|
|
314
|
+
// so the data inspector's `object.constructor.name` shows the class name.
|
|
157
315
|
// Must use `function` (not arrow) because arrow functions have no .prototype.
|
|
158
316
|
// biome-ignore lint/complexity/useArrowFunction: arrow functions have no .prototype
|
|
159
317
|
const ctor = { [className]: function () {} }[className]!;
|
|
@@ -288,7 +446,7 @@ function replaceEncryptedAndExpiredWithMarkers<T>(resource: T): T {
|
|
|
288
446
|
if (result.eventData && typeof result.eventData === 'object') {
|
|
289
447
|
const eventType =
|
|
290
448
|
typeof result.eventType === 'string' ? result.eventType : '';
|
|
291
|
-
const refKeys =
|
|
449
|
+
const refKeys = getEventDataRefFields(eventType);
|
|
292
450
|
const ed = { ...(result.eventData as Record<string, unknown>) };
|
|
293
451
|
for (const key of refKeys) {
|
|
294
452
|
if (key in ed) {
|
|
@@ -307,36 +465,56 @@ function replaceEncryptedAndExpiredWithMarkers<T>(resource: T): T {
|
|
|
307
465
|
* When a key is provided, encrypted fields are decrypted before hydration.
|
|
308
466
|
* This is the async version used when the user clicks "Decrypt" in the web UI.
|
|
309
467
|
*
|
|
310
|
-
* Handles both top-level fields (input, output, metadata) and nested
|
|
311
|
-
*
|
|
468
|
+
* Handles both top-level fields (input, output, metadata) and nested eventData
|
|
469
|
+
* payload fields for that event type.
|
|
312
470
|
*/
|
|
313
471
|
export async function hydrateResourceIOWithKey<T>(
|
|
314
472
|
resource: T,
|
|
315
473
|
key: Uint8Array
|
|
474
|
+
): Promise<T> {
|
|
475
|
+
return hydrateResourceIOAsync(resource, key);
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
/**
|
|
479
|
+
* Async hydration for web display.
|
|
480
|
+
*
|
|
481
|
+
* This follows the same resource-field mapping as {@link hydrateResourceIO},
|
|
482
|
+
* but can also inflate compressed browser payloads through the registered
|
|
483
|
+
* zstd WASM decoder. When a key is provided, encrypted fields are decrypted
|
|
484
|
+
* first and then inflated/hydrated.
|
|
485
|
+
*/
|
|
486
|
+
export async function hydrateResourceIOAsync<T>(
|
|
487
|
+
resource: T,
|
|
488
|
+
key?: Uint8Array
|
|
316
489
|
): Promise<T> {
|
|
317
490
|
const { hydrateDataWithKey } = await import(
|
|
318
491
|
'@workflow/core/serialization-format'
|
|
319
492
|
);
|
|
320
|
-
|
|
321
|
-
|
|
493
|
+
// Payloads may be zstd-compressed (the Web DecompressionStream has no zstd);
|
|
494
|
+
// register the WASM-backed browser decoder before hydrating. Idempotent and
|
|
495
|
+
// lazy — the WASM is only compiled when a zstd payload is actually decoded.
|
|
496
|
+
const { ensureZstdDecoderRegistered } = await import(
|
|
497
|
+
'./zstd-browser-decoder.js'
|
|
498
|
+
);
|
|
499
|
+
ensureZstdDecoderRegistered();
|
|
500
|
+
const cryptoKey = key
|
|
501
|
+
? await import('@workflow/core/encryption').then(({ importKey }) =>
|
|
502
|
+
importKey(key)
|
|
503
|
+
)
|
|
504
|
+
: undefined;
|
|
322
505
|
const revivers = getRevivers();
|
|
323
506
|
|
|
324
|
-
|
|
325
|
-
async function decryptField(
|
|
326
|
-
value: unknown,
|
|
327
|
-
rev: Revivers,
|
|
328
|
-
k: Awaited<ReturnType<typeof importKey>>
|
|
329
|
-
): Promise<unknown> {
|
|
507
|
+
async function hydrateField(value: unknown): Promise<unknown> {
|
|
330
508
|
// Already-hydrated: encrypted marker with stored bytes
|
|
331
509
|
if (isEncryptedMarker(value)) {
|
|
332
510
|
const raw = (value as any).__encryptedData as Uint8Array;
|
|
333
|
-
return hydrateDataWithKey(raw,
|
|
511
|
+
return cryptoKey ? hydrateDataWithKey(raw, revivers, cryptoKey) : value;
|
|
334
512
|
}
|
|
335
|
-
// Raw encrypted
|
|
513
|
+
// Raw Uint8Array: may be encrypted, compressed, or plain devalue.
|
|
336
514
|
if (value instanceof Uint8Array) {
|
|
337
|
-
return hydrateDataWithKey(value,
|
|
515
|
+
return hydrateDataWithKey(value, revivers, cryptoKey);
|
|
338
516
|
}
|
|
339
|
-
// Not
|
|
517
|
+
// Not serialized — return as-is.
|
|
340
518
|
return value;
|
|
341
519
|
}
|
|
342
520
|
|
|
@@ -346,29 +524,25 @@ export async function hydrateResourceIOWithKey<T>(
|
|
|
346
524
|
// Decrypt + hydrate top-level serialized fields (runs, steps, hooks)
|
|
347
525
|
for (const field of ['input', 'output', 'metadata', 'error']) {
|
|
348
526
|
if (field in result) {
|
|
349
|
-
result[field] = await
|
|
527
|
+
result[field] = await hydrateField(result[field]);
|
|
350
528
|
}
|
|
351
529
|
}
|
|
352
530
|
|
|
353
|
-
//
|
|
531
|
+
// Hydrate eventData subfields (events)
|
|
354
532
|
if (result.eventData && typeof result.eventData === 'object') {
|
|
355
533
|
const eventType =
|
|
356
534
|
typeof result.eventType === 'string' ? result.eventType : '';
|
|
357
|
-
const refKeys =
|
|
535
|
+
const refKeys = getEventDataRefFields(eventType);
|
|
358
536
|
const eventData = { ...(result.eventData as Record<string, unknown>) };
|
|
359
537
|
for (const field of refKeys) {
|
|
360
538
|
if (field in eventData) {
|
|
361
|
-
eventData[field] = await
|
|
362
|
-
eventData[field],
|
|
363
|
-
revivers,
|
|
364
|
-
cryptoKey
|
|
365
|
-
);
|
|
539
|
+
eventData[field] = await hydrateField(eventData[field]);
|
|
366
540
|
}
|
|
367
541
|
}
|
|
368
542
|
result.eventData = eventData;
|
|
369
543
|
}
|
|
370
544
|
|
|
371
|
-
return result as T;
|
|
545
|
+
return replaceEncryptedAndExpiredWithMarkers(result as T);
|
|
372
546
|
}
|
|
373
547
|
|
|
374
548
|
/**
|
|
@@ -387,7 +561,7 @@ export function hasEncryptedFields(resource: unknown): boolean {
|
|
|
387
561
|
|
|
388
562
|
if (r.eventData && typeof r.eventData === 'object') {
|
|
389
563
|
const eventType = typeof r.eventType === 'string' ? r.eventType : '';
|
|
390
|
-
const refKeys =
|
|
564
|
+
const refKeys = getEventDataRefFields(eventType);
|
|
391
565
|
const ed = r.eventData as Record<string, unknown>;
|
|
392
566
|
for (const key of refKeys) {
|
|
393
567
|
if (key in ed && isEncryptedMarker(ed[key])) return true;
|
package/src/lib/trace-builder.ts
CHANGED
|
@@ -6,30 +6,54 @@
|
|
|
6
6
|
* a fully-formed Trace ready for the trace viewer.
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
import
|
|
9
|
+
import {
|
|
10
|
+
type Event,
|
|
11
|
+
isHookLifecycleEventType,
|
|
12
|
+
isStepEventType,
|
|
13
|
+
isWaitEventType,
|
|
14
|
+
type WorkflowRun,
|
|
15
|
+
} from '@workflow/world';
|
|
10
16
|
import type { Span } from '../components/trace-viewer/types';
|
|
11
17
|
import {
|
|
18
|
+
getEventTimestamp,
|
|
12
19
|
hookToSpan,
|
|
13
20
|
runToSpan,
|
|
14
21
|
stepToSpan,
|
|
15
|
-
waitToSpan,
|
|
16
22
|
WORKFLOW_LIBRARY,
|
|
23
|
+
waitToSpan,
|
|
17
24
|
} from '../components/workflow-traces/trace-span-construction';
|
|
18
25
|
import { otelTimeToMs } from '../components/workflow-traces/trace-time-utils';
|
|
19
26
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
27
|
+
/**
|
|
28
|
+
* Events that belong to the run root span rather than a child entity span.
|
|
29
|
+
* Mirrors the fallthrough logic in {@link groupEventsByCorrelation}: events
|
|
30
|
+
* without a correlationId (run lifecycle) plus correlated events that aren't
|
|
31
|
+
* step/timer/hook events (e.g. `attr_set`, whose correlationId is a dedup
|
|
32
|
+
* token rather than a child entity ID).
|
|
33
|
+
*/
|
|
34
|
+
export const isRunLevelEvent = (event: Event): boolean =>
|
|
35
|
+
!event.correlationId ||
|
|
36
|
+
(!isWaitEventType(event.eventType) &&
|
|
37
|
+
!isHookLifecycleEventType(event.eventType) &&
|
|
38
|
+
!isStepEventType(event.eventType));
|
|
28
39
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
40
|
+
/**
|
|
41
|
+
* Filter the raw event list down to the events for a selected span.
|
|
42
|
+
* For the run root span this returns run-level events (see
|
|
43
|
+
* {@link isRunLevelEvent}); for child spans it returns the events
|
|
44
|
+
* correlated to that span's ID.
|
|
45
|
+
*/
|
|
46
|
+
export function filterSpanRawEvents(
|
|
47
|
+
events: Event[],
|
|
48
|
+
resource: string | undefined,
|
|
49
|
+
spanId: string | undefined
|
|
50
|
+
): Event[] {
|
|
51
|
+
if (resource === 'run') {
|
|
52
|
+
return events.filter(isRunLevelEvent);
|
|
53
|
+
}
|
|
54
|
+
if (!spanId) return [];
|
|
55
|
+
return events.filter((e) => e.correlationId === spanId);
|
|
56
|
+
}
|
|
33
57
|
|
|
34
58
|
// ---------------------------------------------------------------------------
|
|
35
59
|
// Event grouping
|
|
@@ -68,17 +92,17 @@ export function groupEventsByCorrelation(events: Event[]): GroupedEvents {
|
|
|
68
92
|
continue;
|
|
69
93
|
}
|
|
70
94
|
|
|
71
|
-
if (
|
|
95
|
+
if (isWaitEventType(event.eventType)) {
|
|
72
96
|
pushEvent(timerEvents, correlationId, event);
|
|
73
97
|
continue;
|
|
74
98
|
}
|
|
75
99
|
|
|
76
|
-
if (
|
|
100
|
+
if (isHookLifecycleEventType(event.eventType)) {
|
|
77
101
|
pushEvent(hookEvents, correlationId, event);
|
|
78
102
|
continue;
|
|
79
103
|
}
|
|
80
104
|
|
|
81
|
-
if (
|
|
105
|
+
if (isStepEventType(event.eventType)) {
|
|
82
106
|
pushEvent(eventsByStepId, correlationId, event);
|
|
83
107
|
continue;
|
|
84
108
|
}
|
|
@@ -101,7 +125,7 @@ export function groupEventsByCorrelation(events: Event[]): GroupedEvents {
|
|
|
101
125
|
function computeLatestKnownTime(events: Event[], run: WorkflowRun): Date {
|
|
102
126
|
let latest = new Date(run.createdAt).getTime();
|
|
103
127
|
for (const event of events) {
|
|
104
|
-
const t = new Date(event.createdAt).getTime();
|
|
128
|
+
const t = (getEventTimestamp(event) ?? new Date(event.createdAt)).getTime();
|
|
105
129
|
if (t > latest) latest = t;
|
|
106
130
|
}
|
|
107
131
|
return new Date(latest);
|
|
@@ -117,6 +141,7 @@ function buildSpans(
|
|
|
117
141
|
// unknown territory. Even when the run is completed, we may not have loaded
|
|
118
142
|
// all events yet, so always use the latest event we've actually seen.
|
|
119
143
|
const childMaxEnd = latestKnownTime;
|
|
144
|
+
const runMaxEnd = run.completedAt ?? now;
|
|
120
145
|
|
|
121
146
|
const stepSpans = Array.from(groupedEvents.eventsByStepId.values())
|
|
122
147
|
.map((events) => stepToSpan(events, childMaxEnd))
|
|
@@ -127,7 +152,7 @@ function buildSpans(
|
|
|
127
152
|
.filter((span): span is Span => span !== null);
|
|
128
153
|
|
|
129
154
|
const waitSpans = Array.from(groupedEvents.timerEvents.values())
|
|
130
|
-
.map((events) => waitToSpan(events, childMaxEnd))
|
|
155
|
+
.map((events) => waitToSpan(events, childMaxEnd, runMaxEnd))
|
|
131
156
|
.filter((span): span is Span => span !== null);
|
|
132
157
|
|
|
133
158
|
return {
|