@workflow/web-shared 5.0.0-beta.2 → 5.0.0-beta.3
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/index.d.ts +2 -0
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/index.js +2 -0
- package/dist/components/index.js.map +1 -1
- 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/copy-button.js.map +1 -0
- package/dist/components/new-trace-viewer/components/event-list.d.ts +8 -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 +35 -0
- package/dist/components/new-trace-viewer/components/event-list.js.map +1 -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 +100 -0
- package/dist/components/new-trace-viewer/components/split-pane.js.map +1 -0
- package/dist/components/new-trace-viewer/components/timeline.d.ts +32 -0
- package/dist/components/new-trace-viewer/components/timeline.d.ts.map +1 -0
- package/dist/components/new-trace-viewer/components/timeline.js +134 -0
- package/dist/components/new-trace-viewer/components/timeline.js.map +1 -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 +49 -0
- package/dist/components/new-trace-viewer/context.js.map +1 -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 +11 -0
- package/dist/components/new-trace-viewer/detail-panel.js.map +1 -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/icons.js.map +1 -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 +329 -0
- package/dist/components/new-trace-viewer/trace-viewer.js.map +1 -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/types.js.map +1 -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/util/constants.js.map +1 -0
- package/dist/components/new-trace-viewer/utils.d.ts +47 -0
- package/dist/components/new-trace-viewer/utils.d.ts.map +1 -0
- package/dist/components/new-trace-viewer/utils.js +358 -0
- package/dist/components/new-trace-viewer/utils.js.map +1 -0
- package/dist/components/sidebar/attribute-panel.d.ts.map +1 -1
- package/dist/components/sidebar/attribute-panel.js +42 -23
- package/dist/components/sidebar/attribute-panel.js.map +1 -1
- package/dist/components/sidebar/copyable-data-block.js +1 -1
- package/dist/components/sidebar/copyable-data-block.js.map +1 -1
- package/dist/components/sidebar/detail-card.d.ts.map +1 -1
- package/dist/components/sidebar/detail-card.js +1 -1
- package/dist/components/sidebar/detail-card.js.map +1 -1
- package/dist/components/sidebar/entity-detail-panel.d.ts +1 -3
- package/dist/components/sidebar/entity-detail-panel.d.ts.map +1 -1
- package/dist/components/sidebar/entity-detail-panel.js +3 -25
- package/dist/components/sidebar/entity-detail-panel.js.map +1 -1
- package/dist/components/sidebar/events-list.d.ts.map +1 -1
- package/dist/components/sidebar/events-list.js +2 -2
- package/dist/components/sidebar/events-list.js.map +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/sidebar/sidebar-data-context.js.map +1 -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 +2 -26
- package/dist/components/stream-viewer.js.map +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/trace-viewer-new.js.map +1 -0
- package/dist/components/ui/data-inspector.d.ts +21 -0
- package/dist/components/ui/data-inspector.d.ts.map +1 -1
- package/dist/components/ui/data-inspector.js +99 -4
- package/dist/components/ui/data-inspector.js.map +1 -1
- 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 +38 -71
- package/dist/components/ui/inspector-theme.js.map +1 -1
- package/dist/components/workflow-trace-view.d.ts +1 -3
- package/dist/components/workflow-trace-view.d.ts.map +1 -1
- package/dist/components/workflow-trace-view.js +4 -4
- package/dist/components/workflow-trace-view.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- 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/stream-display.js.map +1 -0
- package/dist/lib/utils.d.ts +7 -9
- package/dist/lib/utils.d.ts.map +1 -1
- package/dist/lib/utils.js +17 -22
- package/dist/lib/utils.js.map +1 -1
- package/dist/styles.css +470 -1
- package/package.json +3 -2
- package/src/components/index.ts +5 -0
- package/src/components/new-trace-viewer/components/copy-button.tsx +68 -0
- package/src/components/new-trace-viewer/components/event-list.tsx +109 -0
- package/src/components/new-trace-viewer/components/split-pane.tsx +186 -0
- package/src/components/new-trace-viewer/components/timeline.tsx +378 -0
- package/src/components/new-trace-viewer/context.tsx +94 -0
- package/src/components/new-trace-viewer/detail-panel.tsx +57 -0
- package/src/components/new-trace-viewer/icons.tsx +79 -0
- package/src/components/new-trace-viewer/trace-viewer.tsx +585 -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 +524 -0
- package/src/components/sidebar/attribute-panel.tsx +43 -32
- package/src/components/sidebar/copyable-data-block.tsx +1 -1
- package/src/components/sidebar/detail-card.tsx +1 -19
- package/src/components/sidebar/entity-detail-panel.tsx +0 -71
- package/src/components/sidebar/events-list.tsx +9 -6
- package/src/components/sidebar/sidebar-data-context.tsx +62 -0
- package/src/components/stream-viewer.tsx +18 -40
- package/src/components/trace-viewer-new.tsx +49 -0
- package/src/components/ui/data-inspector.tsx +235 -4
- package/src/components/ui/inspector-theme.ts +39 -81
- package/src/components/workflow-trace-view.tsx +2 -6
- package/src/index.ts +1 -0
- package/src/lib/stream-display.ts +48 -0
- package/src/lib/utils.ts +18 -23
- package/src/styles.css +470 -1
|
@@ -88,7 +88,7 @@ function EventItem({ event, onLoadEventData, encryptionKey, }) {
|
|
|
88
88
|
: undefined, children: [_jsxs("div", { className: "flex flex-col divide-y rounded-md border overflow-hidden", style: {
|
|
89
89
|
borderColor: 'var(--ds-gray-300)',
|
|
90
90
|
backgroundColor: 'var(--ds-gray-100)',
|
|
91
|
-
}, children: [_jsxs("div", { className: "flex min-h-[32px] items-center justify-between gap-4 px-2.5 py-1.5", style: { borderColor: 'var(--ds-gray-300)' }, children: [_jsx("span", { className: "text-[
|
|
91
|
+
}, children: [_jsxs("div", { className: "flex min-h-[32px] items-center justify-between gap-4 px-2.5 py-1.5", style: { borderColor: 'var(--ds-gray-300)' }, children: [_jsx("span", { className: "text-[13px] font-medium", style: { color: 'var(--ds-gray-700)' }, children: "Event ID" }), _jsx("span", { className: "max-w-[70%] truncate text-right text-[13px] font-mono", style: { color: 'var(--ds-gray-1000)' }, title: event.eventId, children: event.eventId })] }), event.correlationId && (_jsxs("div", { className: "flex min-h-[32px] items-center justify-between gap-4 px-2.5 py-1.5", style: { borderColor: 'var(--ds-gray-300)' }, children: [_jsx("span", { className: "text-[13px] font-medium", style: { color: 'var(--ds-gray-700)' }, children: "Correlation ID" }), _jsx("span", { className: "max-w-[70%] truncate text-right text-[13px] font-mono", style: { color: 'var(--ds-gray-1000)' }, title: event.correlationId, children: event.correlationId })] }))] }), isLoading && (_jsxs("div", { className: "mt-2 rounded-md border p-3", style: {
|
|
92
92
|
borderColor: 'var(--ds-gray-300)',
|
|
93
93
|
}, children: [_jsx(Skeleton, { className: "h-4 w-[35%]" }), _jsx(Skeleton, { className: "mt-2 h-4 w-[90%]" }), _jsx(Skeleton, { className: "mt-2 h-4 w-[75%]" })] })), loadError && (_jsx(ErrorCard, { title: "Failed to load event data", details: loadError, className: "mt-2" })), displayPayload != null && (_jsx("div", { className: "mt-2", children: _jsx(EventDataBlock, { eventType: event.eventType, data: displayPayload }) }))] }));
|
|
94
94
|
}
|
|
@@ -145,6 +145,6 @@ function EventDataBlock({ eventType, data, }) {
|
|
|
145
145
|
export function EventsList({ events, isLoading = false, error, onLoadEventData, encryptionKey, }) {
|
|
146
146
|
// Sort by createdAt
|
|
147
147
|
const sortedEvents = useMemo(() => [...events].sort((a, b) => new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime()), [events]);
|
|
148
|
-
return (_jsxs("div", { className: "mt-2", style: { color: 'var(--ds-gray-1000)' }, children: [
|
|
148
|
+
return (_jsxs("div", { className: "mt-2", style: { color: 'var(--ds-gray-1000)' }, children: [_jsx("h3", { className: "text-label-14 font-medium mt-4 mb-2", style: { color: 'var(--ds-gray-1000)' }, children: "Events" }), isLoading ? (_jsxs("div", { className: "flex flex-col gap-4", children: [_jsx(Skeleton, { className: "h-9 w-full rounded-md" }), _jsx(Skeleton, { className: "h-9 w-full rounded-md" }), _jsx(Skeleton, { className: "h-9 w-full rounded-md" })] })) : null, !isLoading && !error && sortedEvents.length === 0 && (_jsx("div", { className: "text-sm", children: "No events found" })), sortedEvents.length > 0 && !error ? (_jsx("div", { className: "flex flex-col gap-4", children: sortedEvents.map((event) => (_jsx(EventItem, { event: event, onLoadEventData: onLoadEventData, encryptionKey: encryptionKey }, event.eventId))) })) : null] }));
|
|
149
149
|
}
|
|
150
150
|
//# sourceMappingURL=events-list.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"events-list.js","sourceRoot":"","sources":["../../../src/components/sidebar/events-list.tsx"],"names":[],"mappings":"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","sourcesContent":["'use client';\n\nimport { EVENT_DATA_REF_FIELDS, type Event } from '@workflow/world';\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport { isExpiredMarker } from '../../lib/hydration';\nimport { ErrorCard } from '../ui/error-card';\nimport {\n ErrorStackBlock,\n isStructuredErrorWithStack,\n} from '../ui/error-stack-block';\nimport { Skeleton } from '../ui/skeleton';\nimport { localMillisecondTime } from './attribute-panel';\nimport { CopyableDataBlock } from './copyable-data-block';\nimport { DetailCard } from './detail-card';\n\n/**\n * Event types whose eventData contains an error field with a StructuredError.\n */\nconst ERROR_EVENT_TYPES = new Set(['step_failed', 'step_retrying']);\n\n/**\n * Event types that carry user-serialized data in their eventData field.\n */\nconst DATA_EVENT_TYPES = new Set([\n 'step_created',\n 'step_completed',\n 'step_failed',\n 'step_retrying',\n 'hook_created',\n 'hook_received',\n 'run_created',\n 'run_completed',\n 'run_failed',\n 'wait_created',\n 'wait_completed',\n]);\n\n/**\n * A single event row that can lazy-load its eventData when expanded.\n */\nfunction EventItem({\n event,\n onLoadEventData,\n encryptionKey,\n}: {\n event: Event;\n onLoadEventData?: (\n correlationId: string,\n eventId: string\n ) => Promise<unknown | null>;\n /** When this changes (e.g., Decrypt was clicked), invalidate cached data */\n encryptionKey?: Uint8Array;\n}) {\n const [loadedData, setLoadedData] = useState<unknown | null>(null);\n const [isLoading, setIsLoading] = useState(false);\n const [loadError, setLoadError] = useState<string | null>(null);\n const wasExpandedRef = useRef(false);\n /** Mirrors whether we have a fetched payload; avoids stale `loadedData` in load closure. */\n const loadedDataRef = useRef<unknown | null>(null);\n\n // Check if the event already has eventData from the store\n const existingData =\n 'eventData' in event && event.eventData != null ? event.eventData : null;\n const mergedDisplay = loadedData ?? existingData;\n const canHaveData = DATA_EVENT_TYPES.has(event.eventType);\n\n const loadEventData = useCallback(\n async (options?: { force?: boolean }) => {\n if (!onLoadEventData || !event.correlationId || !event.eventId) return;\n if (!options?.force && loadedDataRef.current !== null) {\n return;\n }\n\n try {\n setIsLoading(true);\n setLoadError(null);\n const data = await onLoadEventData(event.correlationId, event.eventId);\n loadedDataRef.current = data;\n setLoadedData(data);\n } catch (err) {\n setLoadError(err instanceof Error ? err.message : String(err));\n } finally {\n setIsLoading(false);\n }\n },\n [onLoadEventData, event.correlationId, event.eventId]\n );\n\n const handleExpand = useCallback(async () => {\n if (isLoading) return;\n wasExpandedRef.current = true;\n await loadEventData();\n }, [isLoading, loadEventData]);\n\n // When the encryption key changes and this event was previously expanded,\n // re-load the data so it gets decrypted\n useEffect(() => {\n if (!encryptionKey || !wasExpandedRef.current) return;\n loadedDataRef.current = null;\n setLoadedData(null);\n void loadEventData({ force: true });\n }, [encryptionKey, loadEventData]);\n\n const createdAt = new Date(event.createdAt);\n\n const displayPayload = isLoading ? loadedData : mergedDisplay;\n\n return (\n <DetailCard\n summaryClassName=\"text-base py-2\"\n summary={\n <>\n <span\n className=\"font-medium\"\n style={{ color: 'var(--ds-gray-1000)' }}\n >\n {event.eventType}\n </span>{' '}\n -{' '}\n <span style={{ color: 'var(--ds-gray-700)' }}>\n {localMillisecondTime(createdAt.getTime())}\n </span>\n </>\n }\n onToggle={\n canHaveData\n ? (open) => {\n if (open) handleExpand();\n }\n : undefined\n }\n >\n {/* Event attributes */}\n <div\n className=\"flex flex-col divide-y rounded-md border overflow-hidden\"\n style={{\n borderColor: 'var(--ds-gray-300)',\n backgroundColor: 'var(--ds-gray-100)',\n }}\n >\n <div\n className=\"flex min-h-[32px] items-center justify-between gap-4 px-2.5 py-1.5\"\n style={{ borderColor: 'var(--ds-gray-300)' }}\n >\n <span className=\"text-[14px]\" style={{ color: 'var(--ds-gray-700)' }}>\n eventId\n </span>\n <span\n className=\"max-w-[70%] truncate text-right text-[13px] font-mono\"\n style={{ color: 'var(--ds-gray-1000)' }}\n title={event.eventId}\n >\n {event.eventId}\n </span>\n </div>\n {event.correlationId && (\n <div\n className=\"flex min-h-[32px] items-center justify-between gap-4 px-2.5 py-1.5\"\n style={{ borderColor: 'var(--ds-gray-300)' }}\n >\n <span\n className=\"text-[14px]\"\n style={{ color: 'var(--ds-gray-700)' }}\n >\n correlationId\n </span>\n <span\n className=\"max-w-[70%] truncate text-right text-[13px] font-mono\"\n style={{ color: 'var(--ds-gray-1000)' }}\n title={event.correlationId}\n >\n {event.correlationId}\n </span>\n </div>\n )}\n </div>\n\n {/* Loading state */}\n {isLoading && (\n <div\n className=\"mt-2 rounded-md border p-3\"\n style={{\n borderColor: 'var(--ds-gray-300)',\n }}\n >\n <Skeleton className=\"h-4 w-[35%]\" />\n <Skeleton className=\"mt-2 h-4 w-[90%]\" />\n <Skeleton className=\"mt-2 h-4 w-[75%]\" />\n </div>\n )}\n\n {/* Error state */}\n {loadError && (\n <ErrorCard\n title=\"Failed to load event data\"\n details={loadError}\n className=\"mt-2\"\n />\n )}\n\n {/* Event data */}\n {displayPayload != null && (\n <div className=\"mt-2\">\n <EventDataBlock eventType={event.eventType} data={displayPayload} />\n </div>\n )}\n </DetailCard>\n );\n}\n\n/**\n * Check if an eventData object has only expired marker values in ref/payload\n * fields for this event type (see {@link EVENT_DATA_REF_FIELDS}). Other keys\n * (e.g. `resumeAt`, `stepName`) are ignored.\n */\nfunction hasOnlyExpiredFields(data: unknown, eventType: string): boolean {\n if (data === null || typeof data !== 'object' || Array.isArray(data)) {\n return false;\n }\n const record = data as Record<string, unknown>;\n const refKeys = EVENT_DATA_REF_FIELDS[eventType] ?? [];\n const presentKeys = refKeys.filter((k) => k in record);\n return (\n presentKeys.length > 0 &&\n presentKeys.every((k) => isExpiredMarker(record[k]))\n );\n}\n\n/**\n * Renders event data, using ErrorStackBlock for error events that contain\n * a structured error with a stack trace, and CopyableDataBlock otherwise.\n */\nfunction EventDataBlock({\n eventType,\n data,\n}: {\n eventType: string;\n data: unknown;\n}) {\n // Expired data — show a simple message instead of the raw stub.\n // Check both the top-level eventData and nested sub-fields (result, input, etc.)\n // since the server stubs each ref field independently.\n if (isExpiredMarker(data) || hasOnlyExpiredFields(data, eventType)) {\n return (\n <div\n className=\"flex items-center gap-1.5 rounded-md border px-3 py-2 text-xs\"\n style={{\n borderColor: 'var(--ds-gray-300)',\n backgroundColor: 'var(--ds-gray-100)',\n color: 'var(--ds-gray-700)',\n }}\n >\n <span className=\"font-medium\">Data expired</span>\n </div>\n );\n }\n\n // For error events (step_failed, step_retrying), the eventData has the shape\n // { error: StructuredError, stack?: string, ... }. Check both the top-level\n // value and the nested `error` field for a stack trace.\n if (\n ERROR_EVENT_TYPES.has(eventType) &&\n data != null &&\n typeof data === 'object'\n ) {\n const record = data as Record<string, unknown>;\n\n // Check the nested `error` field first (the StructuredError)\n if (isStructuredErrorWithStack(record.error)) {\n return <ErrorStackBlock value={record.error} />;\n }\n\n // Some error formats put the stack at the top level of eventData\n if (isStructuredErrorWithStack(record)) {\n return <ErrorStackBlock value={record} />;\n }\n }\n\n // For non-error events or errors without a stack, fall back to the\n // generic JSON viewer.\n return <CopyableDataBlock data={data} />;\n}\n\nexport function EventsList({\n events,\n isLoading = false,\n error,\n onLoadEventData,\n encryptionKey,\n}: {\n events: Event[];\n isLoading?: boolean;\n error?: Error | null;\n onLoadEventData?: (\n correlationId: string,\n eventId: string\n ) => Promise<unknown | null>;\n /** When provided, signals that decryption is active (triggers re-load of expanded events) */\n encryptionKey?: Uint8Array;\n}) {\n // Sort by createdAt\n const sortedEvents = useMemo(\n () =>\n [...events].sort(\n (a, b) =>\n new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime()\n ),\n [events]\n );\n\n return (\n <div className=\"mt-2\" style={{ color: 'var(--ds-gray-1000)' }}>\n <h3\n className=\"text-heading-16 font-medium mt-4 mb-2\"\n style={{ color: 'var(--ds-gray-1000)' }}\n >\n Events {!isLoading && `(${sortedEvents.length})`}\n </h3>\n {isLoading ? (\n <div className=\"flex flex-col gap-4\">\n <Skeleton className=\"h-9 w-full rounded-md\" />\n <Skeleton className=\"h-9 w-full rounded-md\" />\n <Skeleton className=\"h-9 w-full rounded-md\" />\n </div>\n ) : null}\n {!isLoading && !error && sortedEvents.length === 0 && (\n <div className=\"text-sm\">No events found</div>\n )}\n {sortedEvents.length > 0 && !error ? (\n <div className=\"flex flex-col gap-4\">\n {sortedEvents.map((event) => (\n <EventItem\n key={event.eventId}\n event={event}\n onLoadEventData={onLoadEventData}\n encryptionKey={encryptionKey}\n />\n ))}\n </div>\n ) : null}\n </div>\n );\n}\n"]}
|
|
1
|
+
{"version":3,"file":"events-list.js","sourceRoot":"","sources":["../../../src/components/sidebar/events-list.tsx"],"names":[],"mappings":"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","sourcesContent":["'use client';\n\nimport { EVENT_DATA_REF_FIELDS, type Event } from '@workflow/world';\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport { isExpiredMarker } from '../../lib/hydration';\nimport { ErrorCard } from '../ui/error-card';\nimport {\n ErrorStackBlock,\n isStructuredErrorWithStack,\n} from '../ui/error-stack-block';\nimport { Skeleton } from '../ui/skeleton';\nimport { localMillisecondTime } from './attribute-panel';\nimport { CopyableDataBlock } from './copyable-data-block';\nimport { DetailCard } from './detail-card';\n\n/**\n * Event types whose eventData contains an error field with a StructuredError.\n */\nconst ERROR_EVENT_TYPES = new Set(['step_failed', 'step_retrying']);\n\n/**\n * Event types that carry user-serialized data in their eventData field.\n */\nconst DATA_EVENT_TYPES = new Set([\n 'step_created',\n 'step_completed',\n 'step_failed',\n 'step_retrying',\n 'hook_created',\n 'hook_received',\n 'run_created',\n 'run_completed',\n 'run_failed',\n 'wait_created',\n 'wait_completed',\n]);\n\n/**\n * A single event row that can lazy-load its eventData when expanded.\n */\nfunction EventItem({\n event,\n onLoadEventData,\n encryptionKey,\n}: {\n event: Event;\n onLoadEventData?: (\n correlationId: string,\n eventId: string\n ) => Promise<unknown | null>;\n /** When this changes (e.g., Decrypt was clicked), invalidate cached data */\n encryptionKey?: Uint8Array;\n}) {\n const [loadedData, setLoadedData] = useState<unknown | null>(null);\n const [isLoading, setIsLoading] = useState(false);\n const [loadError, setLoadError] = useState<string | null>(null);\n const wasExpandedRef = useRef(false);\n /** Mirrors whether we have a fetched payload; avoids stale `loadedData` in load closure. */\n const loadedDataRef = useRef<unknown | null>(null);\n\n // Check if the event already has eventData from the store\n const existingData =\n 'eventData' in event && event.eventData != null ? event.eventData : null;\n const mergedDisplay = loadedData ?? existingData;\n const canHaveData = DATA_EVENT_TYPES.has(event.eventType);\n\n const loadEventData = useCallback(\n async (options?: { force?: boolean }) => {\n if (!onLoadEventData || !event.correlationId || !event.eventId) return;\n if (!options?.force && loadedDataRef.current !== null) {\n return;\n }\n\n try {\n setIsLoading(true);\n setLoadError(null);\n const data = await onLoadEventData(event.correlationId, event.eventId);\n loadedDataRef.current = data;\n setLoadedData(data);\n } catch (err) {\n setLoadError(err instanceof Error ? err.message : String(err));\n } finally {\n setIsLoading(false);\n }\n },\n [onLoadEventData, event.correlationId, event.eventId]\n );\n\n const handleExpand = useCallback(async () => {\n if (isLoading) return;\n wasExpandedRef.current = true;\n await loadEventData();\n }, [isLoading, loadEventData]);\n\n // When the encryption key changes and this event was previously expanded,\n // re-load the data so it gets decrypted\n useEffect(() => {\n if (!encryptionKey || !wasExpandedRef.current) return;\n loadedDataRef.current = null;\n setLoadedData(null);\n void loadEventData({ force: true });\n }, [encryptionKey, loadEventData]);\n\n const createdAt = new Date(event.createdAt);\n\n const displayPayload = isLoading ? loadedData : mergedDisplay;\n\n return (\n <DetailCard\n summaryClassName=\"text-base py-2\"\n summary={\n <>\n <span\n className=\"font-medium\"\n style={{ color: 'var(--ds-gray-1000)' }}\n >\n {event.eventType}\n </span>{' '}\n -{' '}\n <span style={{ color: 'var(--ds-gray-700)' }}>\n {localMillisecondTime(createdAt.getTime())}\n </span>\n </>\n }\n onToggle={\n canHaveData\n ? (open) => {\n if (open) handleExpand();\n }\n : undefined\n }\n >\n {/* Event attributes */}\n <div\n className=\"flex flex-col divide-y rounded-md border overflow-hidden\"\n style={{\n borderColor: 'var(--ds-gray-300)',\n backgroundColor: 'var(--ds-gray-100)',\n }}\n >\n <div\n className=\"flex min-h-[32px] items-center justify-between gap-4 px-2.5 py-1.5\"\n style={{ borderColor: 'var(--ds-gray-300)' }}\n >\n <span\n className=\"text-[13px] font-medium\"\n style={{ color: 'var(--ds-gray-700)' }}\n >\n Event ID\n </span>\n <span\n className=\"max-w-[70%] truncate text-right text-[13px] font-mono\"\n style={{ color: 'var(--ds-gray-1000)' }}\n title={event.eventId}\n >\n {event.eventId}\n </span>\n </div>\n {event.correlationId && (\n <div\n className=\"flex min-h-[32px] items-center justify-between gap-4 px-2.5 py-1.5\"\n style={{ borderColor: 'var(--ds-gray-300)' }}\n >\n <span\n className=\"text-[13px] font-medium\"\n style={{ color: 'var(--ds-gray-700)' }}\n >\n Correlation ID\n </span>\n <span\n className=\"max-w-[70%] truncate text-right text-[13px] font-mono\"\n style={{ color: 'var(--ds-gray-1000)' }}\n title={event.correlationId}\n >\n {event.correlationId}\n </span>\n </div>\n )}\n </div>\n\n {/* Loading state */}\n {isLoading && (\n <div\n className=\"mt-2 rounded-md border p-3\"\n style={{\n borderColor: 'var(--ds-gray-300)',\n }}\n >\n <Skeleton className=\"h-4 w-[35%]\" />\n <Skeleton className=\"mt-2 h-4 w-[90%]\" />\n <Skeleton className=\"mt-2 h-4 w-[75%]\" />\n </div>\n )}\n\n {/* Error state */}\n {loadError && (\n <ErrorCard\n title=\"Failed to load event data\"\n details={loadError}\n className=\"mt-2\"\n />\n )}\n\n {/* Event data */}\n {displayPayload != null && (\n <div className=\"mt-2\">\n <EventDataBlock eventType={event.eventType} data={displayPayload} />\n </div>\n )}\n </DetailCard>\n );\n}\n\n/**\n * Check if an eventData object has only expired marker values in ref/payload\n * fields for this event type (see {@link EVENT_DATA_REF_FIELDS}). Other keys\n * (e.g. `resumeAt`, `stepName`) are ignored.\n */\nfunction hasOnlyExpiredFields(data: unknown, eventType: string): boolean {\n if (data === null || typeof data !== 'object' || Array.isArray(data)) {\n return false;\n }\n const record = data as Record<string, unknown>;\n const refKeys = EVENT_DATA_REF_FIELDS[eventType] ?? [];\n const presentKeys = refKeys.filter((k) => k in record);\n return (\n presentKeys.length > 0 &&\n presentKeys.every((k) => isExpiredMarker(record[k]))\n );\n}\n\n/**\n * Renders event data, using ErrorStackBlock for error events that contain\n * a structured error with a stack trace, and CopyableDataBlock otherwise.\n */\nfunction EventDataBlock({\n eventType,\n data,\n}: {\n eventType: string;\n data: unknown;\n}) {\n // Expired data — show a simple message instead of the raw stub.\n // Check both the top-level eventData and nested sub-fields (result, input, etc.)\n // since the server stubs each ref field independently.\n if (isExpiredMarker(data) || hasOnlyExpiredFields(data, eventType)) {\n return (\n <div\n className=\"flex items-center gap-1.5 rounded-md border px-3 py-2 text-xs\"\n style={{\n borderColor: 'var(--ds-gray-300)',\n backgroundColor: 'var(--ds-gray-100)',\n color: 'var(--ds-gray-700)',\n }}\n >\n <span className=\"font-medium\">Data expired</span>\n </div>\n );\n }\n\n // For error events (step_failed, step_retrying), the eventData has the shape\n // { error: StructuredError, stack?: string, ... }. Check both the top-level\n // value and the nested `error` field for a stack trace.\n if (\n ERROR_EVENT_TYPES.has(eventType) &&\n data != null &&\n typeof data === 'object'\n ) {\n const record = data as Record<string, unknown>;\n\n // Check the nested `error` field first (the StructuredError)\n if (isStructuredErrorWithStack(record.error)) {\n return <ErrorStackBlock value={record.error} />;\n }\n\n // Some error formats put the stack at the top level of eventData\n if (isStructuredErrorWithStack(record)) {\n return <ErrorStackBlock value={record} />;\n }\n }\n\n // For non-error events or errors without a stack, fall back to the\n // generic JSON viewer.\n return <CopyableDataBlock data={data} />;\n}\n\nexport function EventsList({\n events,\n isLoading = false,\n error,\n onLoadEventData,\n encryptionKey,\n}: {\n events: Event[];\n isLoading?: boolean;\n error?: Error | null;\n onLoadEventData?: (\n correlationId: string,\n eventId: string\n ) => Promise<unknown | null>;\n /** When provided, signals that decryption is active (triggers re-load of expanded events) */\n encryptionKey?: Uint8Array;\n}) {\n // Sort by createdAt\n const sortedEvents = useMemo(\n () =>\n [...events].sort(\n (a, b) =>\n new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime()\n ),\n [events]\n );\n\n return (\n <div className=\"mt-2\" style={{ color: 'var(--ds-gray-1000)' }}>\n <h3\n className=\"text-label-14 font-medium mt-4 mb-2\"\n style={{ color: 'var(--ds-gray-1000)' }}\n >\n Events\n </h3>\n {isLoading ? (\n <div className=\"flex flex-col gap-4\">\n <Skeleton className=\"h-9 w-full rounded-md\" />\n <Skeleton className=\"h-9 w-full rounded-md\" />\n <Skeleton className=\"h-9 w-full rounded-md\" />\n </div>\n ) : null}\n {!isLoading && !error && sortedEvents.length === 0 && (\n <div className=\"text-sm\">No events found</div>\n )}\n {sortedEvents.length > 0 && !error ? (\n <div className=\"flex flex-col gap-4\">\n {sortedEvents.map((event) => (\n <EventItem\n key={event.eventId}\n event={event}\n onLoadEventData={onLoadEventData}\n encryptionKey={encryptionKey}\n />\n ))}\n </div>\n ) : null}\n </div>\n );\n}\n"]}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { type ReactNode } from 'react';
|
|
2
|
+
import type { Event, Hook, Step, WorkflowRun } from '@workflow/world';
|
|
3
|
+
import type { SpanSelectionInfo } from './entity-detail-panel';
|
|
4
|
+
export interface SidebarDataContextValue {
|
|
5
|
+
run: WorkflowRun;
|
|
6
|
+
events: Event[];
|
|
7
|
+
spanDetailData: WorkflowRun | Step | Hook | Event | null;
|
|
8
|
+
spanDetailError?: Error | null;
|
|
9
|
+
spanDetailLoading?: boolean;
|
|
10
|
+
onSpanSelect: (info: SpanSelectionInfo) => void;
|
|
11
|
+
onStreamClick?: (streamId: string) => void;
|
|
12
|
+
onRunClick?: (runId: string) => void;
|
|
13
|
+
onWakeUpSleep?: (runId: string, correlationId: string) => Promise<{
|
|
14
|
+
stoppedCount: number;
|
|
15
|
+
}>;
|
|
16
|
+
onLoadEventData?: (correlationId: string, eventId: string) => Promise<unknown | null>;
|
|
17
|
+
onResolveHook?: (hookToken: string, payload: unknown, hook?: Hook) => Promise<void>;
|
|
18
|
+
encryptionKey?: Uint8Array;
|
|
19
|
+
onDecrypt?: () => void;
|
|
20
|
+
isDecrypting?: boolean;
|
|
21
|
+
hasEncryptedData?: boolean;
|
|
22
|
+
}
|
|
23
|
+
export declare function SidebarDataProvider({ value, children, }: {
|
|
24
|
+
value: SidebarDataContextValue;
|
|
25
|
+
children: ReactNode;
|
|
26
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
27
|
+
export declare function useSidebarData(): SidebarDataContextValue;
|
|
28
|
+
export declare function useSidebarDataOptional(): SidebarDataContextValue | null;
|
|
29
|
+
//# sourceMappingURL=sidebar-data-context.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sidebar-data-context.d.ts","sourceRoot":"","sources":["../../../src/components/sidebar/sidebar-data-context.tsx"],"names":[],"mappings":"AAEA,OAAO,EAA6B,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAClE,OAAO,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AACtE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAE/D,MAAM,WAAW,uBAAuB;IACtC,GAAG,EAAE,WAAW,CAAC;IACjB,MAAM,EAAE,KAAK,EAAE,CAAC;IAChB,cAAc,EAAE,WAAW,GAAG,IAAI,GAAG,IAAI,GAAG,KAAK,GAAG,IAAI,CAAC;IACzD,eAAe,CAAC,EAAE,KAAK,GAAG,IAAI,CAAC;IAC/B,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,YAAY,EAAE,CAAC,IAAI,EAAE,iBAAiB,KAAK,IAAI,CAAC;IAChD,aAAa,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IAC3C,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,aAAa,CAAC,EAAE,CACd,KAAK,EAAE,MAAM,EACb,aAAa,EAAE,MAAM,KAClB,OAAO,CAAC;QAAE,YAAY,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACvC,eAAe,CAAC,EAAE,CAChB,aAAa,EAAE,MAAM,EACrB,OAAO,EAAE,MAAM,KACZ,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,CAAC;IAC7B,aAAa,CAAC,EAAE,CACd,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,OAAO,EAChB,IAAI,CAAC,EAAE,IAAI,KACR,OAAO,CAAC,IAAI,CAAC,CAAC;IACnB,aAAa,CAAC,EAAE,UAAU,CAAC;IAC3B,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IACvB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B;AAKD,wBAAgB,mBAAmB,CAAC,EAClC,KAAK,EACL,QAAQ,GACT,EAAE;IACD,KAAK,EAAE,uBAAuB,CAAC;IAC/B,QAAQ,EAAE,SAAS,CAAC;CACrB,2CAMA;AAED,wBAAgB,cAAc,IAAI,uBAAuB,CAMxD;AAED,wBAAgB,sBAAsB,IAAI,uBAAuB,GAAG,IAAI,CAEvE"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { createContext, useContext } from 'react';
|
|
4
|
+
const SidebarDataContext = createContext(null);
|
|
5
|
+
SidebarDataContext.displayName = 'SidebarDataContext';
|
|
6
|
+
export function SidebarDataProvider({ value, children, }) {
|
|
7
|
+
return (_jsx(SidebarDataContext.Provider, { value: value, children: children }));
|
|
8
|
+
}
|
|
9
|
+
export function useSidebarData() {
|
|
10
|
+
const ctx = useContext(SidebarDataContext);
|
|
11
|
+
if (!ctx) {
|
|
12
|
+
throw new Error('useSidebarData must be used within a SidebarDataProvider');
|
|
13
|
+
}
|
|
14
|
+
return ctx;
|
|
15
|
+
}
|
|
16
|
+
export function useSidebarDataOptional() {
|
|
17
|
+
return useContext(SidebarDataContext);
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=sidebar-data-context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sidebar-data-context.js","sourceRoot":"","sources":["../../../src/components/sidebar/sidebar-data-context.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAEb,OAAO,EAAE,aAAa,EAAE,UAAU,EAAkB,MAAM,OAAO,CAAC;AAgClE,MAAM,kBAAkB,GAAG,aAAa,CAAiC,IAAI,CAAC,CAAC;AAC/E,kBAAkB,CAAC,WAAW,GAAG,oBAAoB,CAAC;AAEtD,MAAM,UAAU,mBAAmB,CAAC,EAClC,KAAK,EACL,QAAQ,GAIT;IACC,OAAO,CACL,KAAC,kBAAkB,CAAC,QAAQ,IAAC,KAAK,EAAE,KAAK,YACtC,QAAQ,GACmB,CAC/B,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,cAAc;IAC5B,MAAM,GAAG,GAAG,UAAU,CAAC,kBAAkB,CAAC,CAAC;IAC3C,IAAI,CAAC,GAAG,EAAE,CAAC;QACT,MAAM,IAAI,KAAK,CAAC,0DAA0D,CAAC,CAAC;IAC9E,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,MAAM,UAAU,sBAAsB;IACpC,OAAO,UAAU,CAAC,kBAAkB,CAAC,CAAC;AACxC,CAAC","sourcesContent":["'use client';\n\nimport { createContext, useContext, type ReactNode } from 'react';\nimport type { Event, Hook, Step, WorkflowRun } from '@workflow/world';\nimport type { SpanSelectionInfo } from './entity-detail-panel';\n\nexport interface SidebarDataContextValue {\n run: WorkflowRun;\n events: Event[];\n spanDetailData: WorkflowRun | Step | Hook | Event | null;\n spanDetailError?: Error | null;\n spanDetailLoading?: boolean;\n onSpanSelect: (info: SpanSelectionInfo) => void;\n onStreamClick?: (streamId: string) => void;\n onRunClick?: (runId: string) => void;\n onWakeUpSleep?: (\n runId: string,\n correlationId: string\n ) => Promise<{ stoppedCount: number }>;\n onLoadEventData?: (\n correlationId: string,\n eventId: string\n ) => Promise<unknown | null>;\n onResolveHook?: (\n hookToken: string,\n payload: unknown,\n hook?: Hook\n ) => Promise<void>;\n encryptionKey?: Uint8Array;\n onDecrypt?: () => void;\n isDecrypting?: boolean;\n hasEncryptedData?: boolean;\n}\n\nconst SidebarDataContext = createContext<SidebarDataContextValue | null>(null);\nSidebarDataContext.displayName = 'SidebarDataContext';\n\nexport function SidebarDataProvider({\n value,\n children,\n}: {\n value: SidebarDataContextValue;\n children: ReactNode;\n}) {\n return (\n <SidebarDataContext.Provider value={value}>\n {children}\n </SidebarDataContext.Provider>\n );\n}\n\nexport function useSidebarData(): SidebarDataContextValue {\n const ctx = useContext(SidebarDataContext);\n if (!ctx) {\n throw new Error('useSidebarData must be used within a SidebarDataProvider');\n }\n return ctx;\n}\n\nexport function useSidebarDataOptional(): SidebarDataContextValue | null {\n return useContext(SidebarDataContext);\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stream-viewer.d.ts","sourceRoot":"","sources":["../../src/components/stream-viewer.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"stream-viewer.d.ts","sourceRoot":"","sources":["../../src/components/stream-viewer.tsx"],"names":[],"mappings":"AAWA,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,OAAO,CAAC;CAChB;AAED,KAAK,KAAK,GAAG,WAAW,CAAC;AAEzB,UAAU,iBAAiB;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,KAAK,EAAE,CAAC;IAChB,MAAM,EAAE,OAAO,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,oEAAoE;IACpE,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,8EAA8E;IAC9E,WAAW,CAAC,EAAE,MAAM,IAAI,CAAC;CAC1B;AAgED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,EAC3B,QAAQ,EAAE,SAAS,EACnB,MAAM,EACN,MAAM,EACN,KAAK,EACL,SAAS,EACT,WAAW,GACZ,EAAE,iBAAiB,2CAmGnB"}
|
|
@@ -5,37 +5,13 @@ import { Virtuoso } from 'react-virtuoso';
|
|
|
5
5
|
import { DataInspector } from './ui/data-inspector';
|
|
6
6
|
import { Skeleton } from './ui/skeleton';
|
|
7
7
|
// ──────────────────────────────────────────────────────────────────────────
|
|
8
|
-
// Helpers
|
|
9
|
-
// ──────────────────────────────────────────────────────────────────────────
|
|
10
|
-
function deserializeChunkText(text) {
|
|
11
|
-
try {
|
|
12
|
-
const parsed = JSON.parse(text);
|
|
13
|
-
if (typeof parsed === 'string') {
|
|
14
|
-
return parsed;
|
|
15
|
-
}
|
|
16
|
-
return JSON.stringify(parsed, null, 2);
|
|
17
|
-
}
|
|
18
|
-
catch {
|
|
19
|
-
return text;
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
function parseChunkData(text) {
|
|
23
|
-
try {
|
|
24
|
-
return JSON.parse(text);
|
|
25
|
-
}
|
|
26
|
-
catch {
|
|
27
|
-
return text;
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
// ──────────────────────────────────────────────────────────────────────────
|
|
31
8
|
// Chunk row — memoized to prevent remounts during polling
|
|
32
9
|
// ──────────────────────────────────────────────────────────────────────────
|
|
33
10
|
const ChunkRow = React.memo(function ChunkRow({ chunk, index, }) {
|
|
34
|
-
|
|
35
|
-
return (_jsxs("div", { className: "text-[11px] rounded-md border p-3", style: {
|
|
11
|
+
return (_jsx("div", { className: "text-[11px] rounded-md border p-3", style: {
|
|
36
12
|
borderColor: 'var(--ds-gray-300)',
|
|
37
13
|
backgroundColor: 'var(--ds-gray-100)',
|
|
38
|
-
}, children: [_jsxs("span", { className: "select-none
|
|
14
|
+
}, children: _jsxs("div", { className: "flex items-start gap-2", children: [_jsxs("span", { className: "select-none pt-px", style: { color: 'var(--ds-gray-500)' }, children: ["[", index, "]"] }), _jsx("div", { className: "min-w-0 flex-1", children: typeof chunk.value === 'string' ? (_jsx("span", { className: "whitespace-pre-wrap break-words", style: { color: 'var(--ds-gray-1000)' }, children: chunk.value })) : (_jsx(DataInspector, { data: chunk.value, expandLevel: 1 })) })] }) }));
|
|
39
15
|
});
|
|
40
16
|
// ──────────────────────────────────────────────────────────────────────────
|
|
41
17
|
// Skeleton loading
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stream-viewer.js","sourceRoot":"","sources":["../../src/components/stream-viewer.tsx"],"names":[],"mappings":"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","sourcesContent":["'use client';\n\nimport React, { useEffect, useRef } from 'react';\nimport { Virtuoso, type VirtuosoHandle } from 'react-virtuoso';\nimport { DataInspector } from './ui/data-inspector';\nimport { Skeleton } from './ui/skeleton';\n\n// ──────────────────────────────────────────────────────────────────────────\n// Helpers\n// ──────────────────────────────────────────────────────────────────────────\n\nfunction deserializeChunkText(text: string): string {\n try {\n const parsed = JSON.parse(text);\n if (typeof parsed === 'string') {\n return parsed;\n }\n return JSON.stringify(parsed, null, 2);\n } catch {\n return text;\n }\n}\n\nfunction parseChunkData(text: string): unknown {\n try {\n return JSON.parse(text);\n } catch {\n return text;\n }\n}\n\n// ──────────────────────────────────────────────────────────────────────────\n// Types\n// ──────────────────────────────────────────────────────────────────────────\n\nexport interface StreamChunk {\n id: number;\n text: string;\n}\n\ntype Chunk = StreamChunk;\n\ninterface StreamViewerProps {\n streamId: string;\n chunks: Chunk[];\n isLive: boolean;\n error?: string | null;\n /** True while the initial stream connection is being established */\n isLoading?: boolean;\n /** Called when the user scrolls near the bottom, for triggering pagination */\n onScrollEnd?: () => void;\n}\n\n// ──────────────────────────────────────────────────────────────────────────\n// Chunk row — memoized to prevent remounts during polling\n// ──────────────────────────────────────────────────────────────────────────\n\nconst ChunkRow = React.memo(function ChunkRow({\n chunk,\n index,\n}: {\n chunk: Chunk;\n index: number;\n}) {\n const parsed = parseChunkData(chunk.text);\n\n return (\n <div\n className=\"text-[11px] rounded-md border p-3\"\n style={{\n borderColor: 'var(--ds-gray-300)',\n backgroundColor: 'var(--ds-gray-100)',\n }}\n >\n <span\n className=\"select-none mr-2\"\n style={{ color: 'var(--ds-gray-500)' }}\n >\n [{index}]\n </span>\n {typeof parsed === 'string' ? (\n <span\n className=\"whitespace-pre-wrap break-words\"\n style={{ color: 'var(--ds-gray-1000)' }}\n >\n {deserializeChunkText(parsed)}\n </span>\n ) : (\n <DataInspector data={parsed} expandLevel={1} />\n )}\n </div>\n );\n});\n\n// ──────────────────────────────────────────────────────────────────────────\n// Skeleton loading\n// ──────────────────────────────────────────────────────────────────────────\n\nfunction StreamSkeleton() {\n return (\n <div className=\"flex flex-col gap-3 animate-in fade-in\">\n <Skeleton style={{ width: 120, height: 16, borderRadius: 4 }} />\n {[1, 2, 3, 4].map((i) => (\n <Skeleton key={i} style={{ height: 56, borderRadius: 6 }} />\n ))}\n </div>\n );\n}\n\n// ──────────────────────────────────────────────────────────────────────────\n// Main component\n// ──────────────────────────────────────────────────────────────────────────\n\n/**\n * StreamViewer component that displays real-time stream data.\n * Each chunk is rendered with DataInspector for proper display\n * of complex types (Map, Set, Date, custom classes, etc.).\n */\nexport function StreamViewer({\n streamId: _streamId,\n chunks,\n isLive,\n error,\n isLoading,\n onScrollEnd,\n}: StreamViewerProps) {\n const virtuosoRef = useRef<VirtuosoHandle>(null);\n const prevChunkCountRef = useRef(0);\n\n // Auto-scroll to bottom when new chunks arrive (live streaming)\n useEffect(() => {\n if (chunks.length > prevChunkCountRef.current && chunks.length > 0) {\n virtuosoRef.current?.scrollToIndex({\n index: chunks.length - 1,\n align: 'end',\n });\n }\n prevChunkCountRef.current = chunks.length;\n }, [chunks.length]);\n\n // Show skeleton when loading and no chunks have arrived yet\n if (isLoading && chunks.length === 0) {\n return (\n <div className=\"flex flex-col h-full\">\n <StreamSkeleton />\n </div>\n );\n }\n\n return (\n <div className=\"flex flex-col h-full\">\n {/* Live indicator */}\n {isLive && (\n <div className=\"flex items-center gap-1.5 mb-2 px-1\">\n <span\n className=\"inline-block w-2 h-2 rounded-full\"\n style={{ backgroundColor: 'var(--ds-green-600)' }}\n />\n <span className=\"text-xs\" style={{ color: 'var(--ds-green-700)' }}>\n Live\n </span>\n </div>\n )}\n\n {/* Header */}\n {chunks.length > 0 && (\n <div className=\"flex items-center gap-2 mb-2 px-1\">\n <span\n className=\"text-[13px] font-medium\"\n style={{ color: 'var(--ds-gray-900)' }}\n >\n Stream Chunks\n </span>\n <span\n className=\"text-xs tabular-nums\"\n style={{ color: 'var(--ds-gray-600)' }}\n >\n ({chunks.length})\n </span>\n </div>\n )}\n\n {/* Content */}\n <div className=\"flex-1 min-h-0\">\n {error ? (\n <div\n className=\"text-[11px] rounded-md border p-3\"\n style={{\n borderColor: 'var(--ds-red-300)',\n backgroundColor: 'var(--ds-red-100)',\n color: 'var(--ds-red-700)',\n }}\n >\n <div>Error reading stream:</div>\n <div>{error}</div>\n </div>\n ) : chunks.length === 0 ? (\n <div\n className=\"text-[11px] rounded-md border p-3\"\n style={{\n borderColor: 'var(--ds-gray-300)',\n backgroundColor: 'var(--ds-gray-100)',\n color: 'var(--ds-gray-600)',\n }}\n >\n {isLive ? 'Waiting for stream data...' : 'Stream is empty'}\n </div>\n ) : (\n <Virtuoso\n ref={virtuosoRef}\n totalCount={chunks.length}\n overscan={10}\n endReached={() => onScrollEnd?.()}\n itemContent={(index) => (\n <div style={{ paddingBottom: 8 }}>\n <ChunkRow chunk={chunks[index]} index={index} />\n </div>\n )}\n style={{ flex: 1, minHeight: 0 }}\n />\n )}\n </div>\n </div>\n );\n}\n"]}
|
|
1
|
+
{"version":3,"file":"stream-viewer.js","sourceRoot":"","sources":["../../src/components/stream-viewer.tsx"],"names":[],"mappings":"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","sourcesContent":["'use client';\n\nimport React, { useEffect, useRef } from 'react';\nimport { Virtuoso, type VirtuosoHandle } from 'react-virtuoso';\nimport { DataInspector } from './ui/data-inspector';\nimport { Skeleton } from './ui/skeleton';\n\n// ──────────────────────────────────────────────────────────────────────────\n// Types\n// ──────────────────────────────────────────────────────────────────────────\n\nexport interface StreamChunk {\n id: number;\n value: unknown;\n}\n\ntype Chunk = StreamChunk;\n\ninterface StreamViewerProps {\n streamId: string;\n chunks: Chunk[];\n isLive: boolean;\n error?: string | null;\n /** True while the initial stream connection is being established */\n isLoading?: boolean;\n /** Called when the user scrolls near the bottom, for triggering pagination */\n onScrollEnd?: () => void;\n}\n\n// ──────────────────────────────────────────────────────────────────────────\n// Chunk row — memoized to prevent remounts during polling\n// ──────────────────────────────────────────────────────────────────────────\n\nconst ChunkRow = React.memo(function ChunkRow({\n chunk,\n index,\n}: {\n chunk: Chunk;\n index: number;\n}) {\n return (\n <div\n className=\"text-[11px] rounded-md border p-3\"\n style={{\n borderColor: 'var(--ds-gray-300)',\n backgroundColor: 'var(--ds-gray-100)',\n }}\n >\n <div className=\"flex items-start gap-2\">\n <span\n className=\"select-none pt-px\"\n style={{ color: 'var(--ds-gray-500)' }}\n >\n [{index}]\n </span>\n <div className=\"min-w-0 flex-1\">\n {typeof chunk.value === 'string' ? (\n <span\n className=\"whitespace-pre-wrap break-words\"\n style={{ color: 'var(--ds-gray-1000)' }}\n >\n {chunk.value}\n </span>\n ) : (\n <DataInspector data={chunk.value} expandLevel={1} />\n )}\n </div>\n </div>\n </div>\n );\n});\n\n// ──────────────────────────────────────────────────────────────────────────\n// Skeleton loading\n// ──────────────────────────────────────────────────────────────────────────\n\nfunction StreamSkeleton() {\n return (\n <div className=\"flex flex-col gap-3 animate-in fade-in\">\n <Skeleton style={{ width: 120, height: 16, borderRadius: 4 }} />\n {[1, 2, 3, 4].map((i) => (\n <Skeleton key={i} style={{ height: 56, borderRadius: 6 }} />\n ))}\n </div>\n );\n}\n\n// ──────────────────────────────────────────────────────────────────────────\n// Main component\n// ──────────────────────────────────────────────────────────────────────────\n\n/**\n * StreamViewer component that displays real-time stream data.\n * Each chunk is rendered with DataInspector for proper display\n * of complex types (Map, Set, Date, custom classes, etc.).\n */\nexport function StreamViewer({\n streamId: _streamId,\n chunks,\n isLive,\n error,\n isLoading,\n onScrollEnd,\n}: StreamViewerProps) {\n const virtuosoRef = useRef<VirtuosoHandle>(null);\n const prevChunkCountRef = useRef(0);\n\n // Auto-scroll to bottom when new chunks arrive (live streaming)\n useEffect(() => {\n if (chunks.length > prevChunkCountRef.current && chunks.length > 0) {\n virtuosoRef.current?.scrollToIndex({\n index: chunks.length - 1,\n align: 'end',\n });\n }\n prevChunkCountRef.current = chunks.length;\n }, [chunks.length]);\n\n // Show skeleton when loading and no chunks have arrived yet\n if (isLoading && chunks.length === 0) {\n return (\n <div className=\"flex flex-col h-full\">\n <StreamSkeleton />\n </div>\n );\n }\n\n return (\n <div className=\"flex flex-col h-full\">\n {/* Live indicator */}\n {isLive && (\n <div className=\"flex items-center gap-1.5 mb-2 px-1\">\n <span\n className=\"inline-block w-2 h-2 rounded-full\"\n style={{ backgroundColor: 'var(--ds-green-600)' }}\n />\n <span className=\"text-xs\" style={{ color: 'var(--ds-green-700)' }}>\n Live\n </span>\n </div>\n )}\n\n {/* Header */}\n {chunks.length > 0 && (\n <div className=\"flex items-center gap-2 mb-2 px-1\">\n <span\n className=\"text-[13px] font-medium\"\n style={{ color: 'var(--ds-gray-900)' }}\n >\n Stream Chunks\n </span>\n <span\n className=\"text-xs tabular-nums\"\n style={{ color: 'var(--ds-gray-600)' }}\n >\n ({chunks.length})\n </span>\n </div>\n )}\n\n {/* Content */}\n <div className=\"flex-1 min-h-0\">\n {error ? (\n <div\n className=\"text-[11px] rounded-md border p-3\"\n style={{\n borderColor: 'var(--ds-red-300)',\n backgroundColor: 'var(--ds-red-100)',\n color: 'var(--ds-red-700)',\n }}\n >\n <div>Error reading stream:</div>\n <div>{error}</div>\n </div>\n ) : chunks.length === 0 ? (\n <div\n className=\"text-[11px] rounded-md border p-3\"\n style={{\n borderColor: 'var(--ds-gray-300)',\n backgroundColor: 'var(--ds-gray-100)',\n color: 'var(--ds-gray-600)',\n }}\n >\n {isLive ? 'Waiting for stream data...' : 'Stream is empty'}\n </div>\n ) : (\n <Virtuoso\n ref={virtuosoRef}\n totalCount={chunks.length}\n overscan={10}\n endReached={() => onScrollEnd?.()}\n itemContent={(index) => (\n <div style={{ paddingBottom: 8 }}>\n <ChunkRow chunk={chunks[index]} index={index} />\n </div>\n )}\n style={{ flex: 1, minHeight: 0 }}\n />\n )}\n </div>\n </div>\n );\n}\n"]}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { WorkflowRun } from '@workflow/core/runtime';
|
|
2
|
+
import type { Event } from '@workflow/world';
|
|
3
|
+
import { type SidebarDataContextValue } from './sidebar/sidebar-data-context';
|
|
4
|
+
declare const NewTraceViewer: ({ run, events, sidebarData, }: {
|
|
5
|
+
run: WorkflowRun;
|
|
6
|
+
events: Event[];
|
|
7
|
+
sidebarData: SidebarDataContextValue;
|
|
8
|
+
}) => import("react/jsx-runtime").JSX.Element;
|
|
9
|
+
export { NewTraceViewer };
|
|
10
|
+
//# sourceMappingURL=trace-viewer-new.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trace-viewer-new.d.ts","sourceRoot":"","sources":["../../src/components/trace-viewer-new.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAC;AAG7C,OAAO,EAEL,KAAK,uBAAuB,EAC7B,MAAM,gCAAgC,CAAC;AAGxC,QAAA,MAAM,cAAc,GAAI,+BAIrB;IACD,GAAG,EAAE,WAAW,CAAC;IACjB,MAAM,EAAE,KAAK,EAAE,CAAC;IAChB,WAAW,EAAE,uBAAuB,CAAC;CACtC,4CA2BA,CAAC;AAEF,OAAO,EAAE,cAAc,EAAE,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useMemo } from 'react';
|
|
3
|
+
import { buildTrace } from '../lib/trace-builder';
|
|
4
|
+
import { NewTraceViewer as NewTraceViewerComponent } from './new-trace-viewer/trace-viewer';
|
|
5
|
+
import { SidebarDataProvider, } from './sidebar/sidebar-data-context';
|
|
6
|
+
const NewTraceViewer = ({ run, events, sidebarData, }) => {
|
|
7
|
+
// Build trace only when actual data changes — no timer-driven rebuilds.
|
|
8
|
+
// Active span widths are animated imperatively by useLiveTick at 60fps.
|
|
9
|
+
const traceWithMeta = useMemo(() => {
|
|
10
|
+
if (!run?.runId) {
|
|
11
|
+
return undefined;
|
|
12
|
+
}
|
|
13
|
+
return buildTrace(run, events, new Date());
|
|
14
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps -- `new Date()` is intentionally not a dep; useLiveTick handles live growth
|
|
15
|
+
}, [run, events]);
|
|
16
|
+
const trace = traceWithMeta;
|
|
17
|
+
if (!trace) {
|
|
18
|
+
return (_jsx("div", { className: "relative w-full h-full flex items-center justify-center", children: _jsx("div", { className: "text-gray-500 text-sm", children: "Loading trace\u2026" }) }));
|
|
19
|
+
}
|
|
20
|
+
return (_jsx(SidebarDataProvider, { value: sidebarData, children: _jsx("div", { className: "relative w-full h-full flex", children: _jsx(NewTraceViewerComponent, { trace: trace }) }) }));
|
|
21
|
+
};
|
|
22
|
+
export { NewTraceViewer };
|
|
23
|
+
//# sourceMappingURL=trace-viewer-new.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trace-viewer-new.js","sourceRoot":"","sources":["../../src/components/trace-viewer-new.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;AAGhC,OAAO,EAAE,UAAU,EAAsB,MAAM,sBAAsB,CAAC;AACtE,OAAO,EAAE,cAAc,IAAI,uBAAuB,EAAE,MAAM,iCAAiC,CAAC;AAC5F,OAAO,EACL,mBAAmB,GAEpB,MAAM,gCAAgC,CAAC;AAGxC,MAAM,cAAc,GAAG,CAAC,EACtB,GAAG,EACH,MAAM,EACN,WAAW,GAKZ,EAAE,EAAE;IACH,wEAAwE;IACxE,wEAAwE;IACxE,MAAM,aAAa,GAA8B,OAAO,CAAC,GAAG,EAAE;QAC5D,IAAI,CAAC,GAAG,EAAE,KAAK,EAAE,CAAC;YAChB,OAAO,SAAS,CAAC;QACnB,CAAC;QACD,OAAO,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,IAAI,EAAE,CAAC,CAAC;QAC3C,mIAAmI;IACrI,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC,CAAC;IAClB,MAAM,KAAK,GAAG,aAAa,CAAC;IAE5B,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,CACL,cAAK,SAAS,EAAC,yDAAyD,YACtE,cAAK,SAAS,EAAC,uBAAuB,oCAAqB,GACvD,CACP,CAAC;IACJ,CAAC;IAED,OAAO,CACL,KAAC,mBAAmB,IAAC,KAAK,EAAE,WAAW,YACrC,cAAK,SAAS,EAAC,6BAA6B,YAC1C,KAAC,uBAAuB,IAAC,KAAK,EAAE,KAAc,GAAI,GAC9C,GACc,CACvB,CAAC;AACJ,CAAC,CAAC;AAEF,OAAO,EAAE,cAAc,EAAE,CAAC","sourcesContent":["import { useMemo } from 'react';\nimport type { WorkflowRun } from '@workflow/core/runtime';\nimport type { Event } from '@workflow/world';\nimport { buildTrace, type TraceWithMeta } from '../lib/trace-builder';\nimport { NewTraceViewer as NewTraceViewerComponent } from './new-trace-viewer/trace-viewer';\nimport {\n SidebarDataProvider,\n type SidebarDataContextValue,\n} from './sidebar/sidebar-data-context';\nimport type { Trace } from './trace-viewer/types';\n\nconst NewTraceViewer = ({\n run,\n events,\n sidebarData,\n}: {\n run: WorkflowRun;\n events: Event[];\n sidebarData: SidebarDataContextValue;\n}) => {\n // Build trace only when actual data changes — no timer-driven rebuilds.\n // Active span widths are animated imperatively by useLiveTick at 60fps.\n const traceWithMeta: TraceWithMeta | undefined = useMemo(() => {\n if (!run?.runId) {\n return undefined;\n }\n return buildTrace(run, events, new Date());\n // eslint-disable-next-line react-hooks/exhaustive-deps -- `new Date()` is intentionally not a dep; useLiveTick handles live growth\n }, [run, events]);\n const trace = traceWithMeta;\n\n if (!trace) {\n return (\n <div className=\"relative w-full h-full flex items-center justify-center\">\n <div className=\"text-gray-500 text-sm\">Loading trace…</div>\n </div>\n );\n }\n\n return (\n <SidebarDataProvider value={sidebarData}>\n <div className=\"relative w-full h-full flex\">\n <NewTraceViewerComponent trace={trace as Trace} />\n </div>\n </SidebarDataProvider>\n );\n};\n\nexport { NewTraceViewer };\n"]}
|
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
import { type DecodedStreamChunkSource } from '../../lib/stream-display';
|
|
2
|
+
declare const BYTES_DISPLAY_TYPE = "__workflow_bytes_display__";
|
|
3
|
+
interface BytesDisplay {
|
|
4
|
+
__type: typeof BYTES_DISPLAY_TYPE;
|
|
5
|
+
text: string;
|
|
6
|
+
decodedFrom?: DecodedStreamChunkSource;
|
|
7
|
+
}
|
|
8
|
+
export declare function isBytesDisplay(value: unknown): value is BytesDisplay;
|
|
1
9
|
/**
|
|
2
10
|
* Context for passing stream click handlers down to DataInspector instances.
|
|
3
11
|
* Exported so that parent components (e.g., AttributePanel) can provide the handler.
|
|
@@ -13,6 +21,18 @@ export type DecryptClickContextValue = {
|
|
|
13
21
|
};
|
|
14
22
|
export declare const DecryptClickContext: import("react").Context<DecryptClickContextValue | undefined>;
|
|
15
23
|
export declare const RunClickContext: import("react").Context<((runId: string) => void) | undefined>;
|
|
24
|
+
/**
|
|
25
|
+
* Recursively walk data and replace RunRef/StreamRef/typed array objects with
|
|
26
|
+
* non-expandable versions so ObjectInspector doesn't show their internals.
|
|
27
|
+
* Only recurses into plain objects and arrays to avoid stripping class
|
|
28
|
+
* instances (Date, Error, URL, Headers, etc.) that have their own rendering in
|
|
29
|
+
* NodeRenderer. Map and Set containers are preserved while their contents are
|
|
30
|
+
* prepared for display.
|
|
31
|
+
*
|
|
32
|
+
* Exported for testing the typed-array detection path used by hydrated
|
|
33
|
+
* AI agent stream chunks (e.g. `{ delta: new Uint8Array(...) }`).
|
|
34
|
+
*/
|
|
35
|
+
export declare function collapseRefs(data: unknown): unknown;
|
|
16
36
|
export interface DataInspectorProps {
|
|
17
37
|
/** The data to inspect */
|
|
18
38
|
data: unknown;
|
|
@@ -30,4 +50,5 @@ export interface DataInspectorProps {
|
|
|
30
50
|
isDecrypting?: boolean;
|
|
31
51
|
}
|
|
32
52
|
export declare function DataInspector({ data, expandLevel, name, onStreamClick, onRunClick, onDecrypt, isDecrypting, }: DataInspectorProps): import("react/jsx-runtime").JSX.Element;
|
|
53
|
+
export {};
|
|
33
54
|
//# sourceMappingURL=data-inspector.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"data-inspector.d.ts","sourceRoot":"","sources":["../../../src/components/ui/data-inspector.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"data-inspector.d.ts","sourceRoot":"","sources":["../../../src/components/ui/data-inspector.tsx"],"names":[],"mappings":"AA4BA,OAAO,EACL,KAAK,wBAAwB,EAG9B,MAAM,0BAA0B,CAAC;AAkBlC,QAAA,MAAM,kBAAkB,+BAA+B,CAAC;AAYxD,UAAU,YAAY;IACpB,MAAM,EAAE,OAAO,kBAAkB,CAAC;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,wBAAwB,CAAC;CACxC;AAmCD,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,YAAY,CAIpE;AAoBD;;;GAGG;AACH,eAAO,MAAM,kBAAkB,sCACjB,MAAM,KAAK,IAAI,cACjB,CAAC;AAEb;;;GAGG;AACH,MAAM,MAAM,wBAAwB,GAAG;IACrC,SAAS,EAAE,MAAM,IAAI,CAAC;IACtB,YAAY,EAAE,OAAO,CAAC;CACvB,CAAC;AAEF,eAAO,MAAM,mBAAmB,+DAEpB,CAAC;AAEb,eAAO,MAAM,eAAe,mCACjB,MAAM,KAAK,IAAI,cACd,CAAC;AAsZb;;;;;;;;;;GAUG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CA2BnD;AAED,MAAM,WAAW,kBAAkB;IACjC,0BAA0B;IAC1B,IAAI,EAAE,OAAO,CAAC;IACd,wCAAwC;IACxC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,sCAAsC;IACtC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,kDAAkD;IAClD,aAAa,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IAC3C,+CAA+C;IAC/C,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,yEAAyE;IACzE,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IACvB,kDAAkD;IAClD,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAED,wBAAgB,aAAa,CAAC,EAC5B,IAAI,EACJ,WAAe,EACf,IAAI,EACJ,aAAa,EACb,UAAU,EACV,SAAS,EACT,YAAoB,GACrB,EAAE,kBAAkB,2CAsDpB"}
|
|
@@ -12,6 +12,7 @@ import { createContext, useContext, useEffect, useMemo, useRef, useState, } from
|
|
|
12
12
|
import { ObjectInspector, ObjectLabel, ObjectName, ObjectRootLabel, ObjectValue, } from 'react-inspector';
|
|
13
13
|
import { useDarkMode } from '../../hooks/use-dark-mode';
|
|
14
14
|
import { ENCRYPTED_DISPLAY_NAME } from '../../lib/hydration';
|
|
15
|
+
import { formatArrayBufferViewForDisplay, } from '../../lib/stream-display';
|
|
15
16
|
import { inspectorThemeDark, inspectorThemeExtendedDark, inspectorThemeExtendedLight, inspectorThemeLight, } from './inspector-theme';
|
|
16
17
|
import { Spinner } from './spinner';
|
|
17
18
|
// ---------------------------------------------------------------------------
|
|
@@ -21,6 +22,27 @@ import { Spinner } from './spinner';
|
|
|
21
22
|
const STREAM_REF_TYPE = '__workflow_stream_ref__';
|
|
22
23
|
const CLASS_INSTANCE_REF_TYPE = '__workflow_class_instance_ref__';
|
|
23
24
|
const RUN_REF_TYPE = '__workflow_run_ref__';
|
|
25
|
+
const BYTES_DISPLAY_TYPE = '__workflow_bytes_display__';
|
|
26
|
+
function deserializeChunkText(text) {
|
|
27
|
+
try {
|
|
28
|
+
const parsed = JSON.parse(text);
|
|
29
|
+
if (typeof parsed === 'string') {
|
|
30
|
+
return parsed;
|
|
31
|
+
}
|
|
32
|
+
return JSON.stringify(parsed, null, 2);
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
return text;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
function parseChunkData(text) {
|
|
39
|
+
try {
|
|
40
|
+
return JSON.parse(text);
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
return text;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
24
46
|
function isStreamRef(value) {
|
|
25
47
|
if (value === null || typeof value !== 'object')
|
|
26
48
|
return false;
|
|
@@ -34,6 +56,12 @@ function isRunRef(value) {
|
|
|
34
56
|
const desc = Object.getOwnPropertyDescriptor(value, '__type');
|
|
35
57
|
return desc?.value === RUN_REF_TYPE;
|
|
36
58
|
}
|
|
59
|
+
export function isBytesDisplay(value) {
|
|
60
|
+
if (value === null || typeof value !== 'object')
|
|
61
|
+
return false;
|
|
62
|
+
const desc = Object.getOwnPropertyDescriptor(value, '__type');
|
|
63
|
+
return desc?.value === BYTES_DISPLAY_TYPE;
|
|
64
|
+
}
|
|
37
65
|
function isClassInstanceRef(value) {
|
|
38
66
|
return (value !== null &&
|
|
39
67
|
typeof value === 'object' &&
|
|
@@ -101,6 +129,29 @@ function RunRefInline({ runRef }) {
|
|
|
101
129
|
// Extended theme context (for colors react-inspector doesn't support natively)
|
|
102
130
|
// ---------------------------------------------------------------------------
|
|
103
131
|
const ExtendedThemeContext = createContext(inspectorThemeExtendedLight);
|
|
132
|
+
function DecodedBytesChunk({ decodedText, source, }) {
|
|
133
|
+
const [selectedView, setSelectedView] = useState('decoded');
|
|
134
|
+
const parsed = parseChunkData(decodedText);
|
|
135
|
+
return (_jsxs("div", { className: "min-w-0", children: [selectedView === 'decoded' ? (_jsx("div", { className: "min-w-0", children: typeof parsed === 'string' ? (_jsx("span", { className: "whitespace-pre-wrap break-words", style: { color: 'var(--ds-gray-1000)' }, children: deserializeChunkText(parsed) })) : (_jsx(DataInspector, { data: parsed, expandLevel: 1 })) })) : (_jsx(DecodedBytesInspector, { decodedText: decodedText, source: source })), _jsx("div", { className: "mt-2 flex", children: _jsxs("div", { className: "inline-flex overflow-hidden rounded border", style: { borderColor: 'var(--ds-gray-400)' }, title: `${source.type} decoded as ${source.encoding.toUpperCase()} text. Switch to Bytes to inspect the summarized raw value.`, children: [_jsx("button", { type: "button", className: "h-5 px-1.5 text-[10px] font-medium", style: {
|
|
136
|
+
backgroundColor: selectedView === 'decoded'
|
|
137
|
+
? 'var(--ds-gray-200)'
|
|
138
|
+
: 'var(--ds-gray-100)',
|
|
139
|
+
color: 'var(--ds-gray-900)',
|
|
140
|
+
}, onClick: () => setSelectedView('decoded'), "aria-pressed": selectedView === 'decoded', "aria-label": "Show decoded text", children: "Decoded" }), _jsx("button", { type: "button", className: "h-5 border-l px-1.5 text-[10px] font-medium", style: {
|
|
141
|
+
borderColor: 'var(--ds-gray-400)',
|
|
142
|
+
backgroundColor: selectedView === 'bytes'
|
|
143
|
+
? 'var(--ds-gray-200)'
|
|
144
|
+
: 'var(--ds-gray-100)',
|
|
145
|
+
color: 'var(--ds-gray-900)',
|
|
146
|
+
}, onClick: () => setSelectedView('bytes'), "aria-pressed": selectedView === 'bytes', "aria-label": "Show raw bytes summary", children: "Bytes" })] }) })] }));
|
|
147
|
+
}
|
|
148
|
+
function DecodedBytesInspector({ decodedText, source, }) {
|
|
149
|
+
const [expanded, setExpanded] = useState(false);
|
|
150
|
+
return (_jsxs("div", { className: "font-mono", children: [_jsxs("button", { type: "button", className: "flex max-w-full items-start gap-1 text-left", style: { color: 'var(--ds-gray-1000)' }, onClick: () => setExpanded((value) => !value), title: `${source.type} decoded as ${source.encoding.toUpperCase()} text`, children: [_jsx("span", { className: "select-none", style: { color: 'var(--ds-gray-700)' }, children: expanded ? '▼' : '▶' }), _jsx("span", { className: "min-w-0 break-words", children: source.rawSummary })] }), expanded && (_jsxs("div", { className: "mt-1 pl-5", children: [_jsx("span", { style: { color: 'var(--ds-gray-700)' }, children: "decoded: " }), _jsx("span", { className: "whitespace-pre-wrap break-words", style: { color: 'var(--ds-green-900)' }, children: JSON.stringify(decodedText) })] }))] }));
|
|
151
|
+
}
|
|
152
|
+
function BytesDisplayLabel({ name, display, }) {
|
|
153
|
+
return (_jsxs("div", { className: "inline-block min-w-0 align-top", children: [name != null && _jsx(ObjectName, { name: name }), name != null && _jsx("span", { children: ": " }), display.decodedFrom ? (_jsx(DecodedBytesChunk, { decodedText: display.text, source: display.decodedFrom })) : (_jsx("span", { className: "whitespace-pre-wrap break-words", style: { color: 'var(--ds-gray-1000)' }, children: display.text }))] }));
|
|
154
|
+
}
|
|
104
155
|
// ---------------------------------------------------------------------------
|
|
105
156
|
// Custom nodeRenderer
|
|
106
157
|
// ---------------------------------------------------------------------------
|
|
@@ -117,6 +168,9 @@ const ExtendedThemeContext = createContext(inspectorThemeExtendedLight);
|
|
|
117
168
|
*/
|
|
118
169
|
function NodeRenderer({ depth, name, data, isNonenumerable, }) {
|
|
119
170
|
const extendedTheme = useContext(ExtendedThemeContext);
|
|
171
|
+
if (isBytesDisplay(data)) {
|
|
172
|
+
return _jsx(BytesDisplayLabel, { name: name, display: data });
|
|
173
|
+
}
|
|
120
174
|
// Encrypted marker → flat label with Lock icon, clickable when onDecrypt is available
|
|
121
175
|
if (data !== null &&
|
|
122
176
|
typeof data === 'object' &&
|
|
@@ -172,20 +226,52 @@ function makeOpaqueRef(ref) {
|
|
|
172
226
|
}
|
|
173
227
|
return opaque;
|
|
174
228
|
}
|
|
229
|
+
function makeBytesDisplay(display) {
|
|
230
|
+
const opaque = Object.create(null);
|
|
231
|
+
Object.defineProperty(opaque, '__type', {
|
|
232
|
+
value: BYTES_DISPLAY_TYPE,
|
|
233
|
+
enumerable: false,
|
|
234
|
+
});
|
|
235
|
+
Object.defineProperty(opaque, 'text', {
|
|
236
|
+
value: display.text,
|
|
237
|
+
enumerable: false,
|
|
238
|
+
});
|
|
239
|
+
Object.defineProperty(opaque, 'decodedFrom', {
|
|
240
|
+
value: display.decodedFrom,
|
|
241
|
+
enumerable: false,
|
|
242
|
+
});
|
|
243
|
+
return opaque;
|
|
244
|
+
}
|
|
175
245
|
/**
|
|
176
|
-
* Recursively walk data and replace RunRef/StreamRef objects with
|
|
246
|
+
* Recursively walk data and replace RunRef/StreamRef/typed array objects with
|
|
177
247
|
* non-expandable versions so ObjectInspector doesn't show their internals.
|
|
178
248
|
* Only recurses into plain objects and arrays to avoid stripping class
|
|
179
|
-
* instances (Date, Error,
|
|
180
|
-
*
|
|
249
|
+
* instances (Date, Error, URL, Headers, etc.) that have their own rendering in
|
|
250
|
+
* NodeRenderer. Map and Set containers are preserved while their contents are
|
|
251
|
+
* prepared for display.
|
|
252
|
+
*
|
|
253
|
+
* Exported for testing the typed-array detection path used by hydrated
|
|
254
|
+
* AI agent stream chunks (e.g. `{ delta: new Uint8Array(...) }`).
|
|
181
255
|
*/
|
|
182
|
-
function collapseRefs(data) {
|
|
256
|
+
export function collapseRefs(data) {
|
|
183
257
|
if (data === null || typeof data !== 'object')
|
|
184
258
|
return data;
|
|
259
|
+
if (ArrayBuffer.isView(data) && !(data instanceof DataView)) {
|
|
260
|
+
return makeBytesDisplay(formatArrayBufferViewForDisplay(data));
|
|
261
|
+
}
|
|
185
262
|
if (isRunRef(data) || isStreamRef(data))
|
|
186
263
|
return makeOpaqueRef(data);
|
|
187
264
|
if (Array.isArray(data))
|
|
188
265
|
return data.map(collapseRefs);
|
|
266
|
+
if (data instanceof Map) {
|
|
267
|
+
return new Map(Array.from(data.entries(), ([key, value]) => [
|
|
268
|
+
collapseRefs(key),
|
|
269
|
+
collapseRefs(value),
|
|
270
|
+
]));
|
|
271
|
+
}
|
|
272
|
+
if (data instanceof Set) {
|
|
273
|
+
return new Set(Array.from(data.values(), collapseRefs));
|
|
274
|
+
}
|
|
189
275
|
// Only recurse into plain objects — leave class instances untouched
|
|
190
276
|
const proto = Object.getPrototypeOf(data);
|
|
191
277
|
if (proto !== Object.prototype && proto !== null)
|
|
@@ -235,9 +321,18 @@ function useStableInspectorData(next) {
|
|
|
235
321
|
function isObjectLike(value) {
|
|
236
322
|
return typeof value === 'object' && value !== null;
|
|
237
323
|
}
|
|
324
|
+
function isSameBytesDisplay(a, b) {
|
|
325
|
+
return (a.text === b.text &&
|
|
326
|
+
a.decodedFrom?.type === b.decodedFrom?.type &&
|
|
327
|
+
a.decodedFrom?.encoding === b.decodedFrom?.encoding &&
|
|
328
|
+
a.decodedFrom?.rawSummary === b.decodedFrom?.rawSummary);
|
|
329
|
+
}
|
|
238
330
|
function isDeepEqual(a, b, seen = new WeakMap()) {
|
|
239
331
|
if (Object.is(a, b))
|
|
240
332
|
return true;
|
|
333
|
+
if (isBytesDisplay(a) || isBytesDisplay(b)) {
|
|
334
|
+
return isBytesDisplay(a) && isBytesDisplay(b) && isSameBytesDisplay(a, b);
|
|
335
|
+
}
|
|
241
336
|
if (a instanceof Date && b instanceof Date) {
|
|
242
337
|
return a.getTime() === b.getTime();
|
|
243
338
|
}
|