@workflow/web 5.0.0-beta.36 → 5.0.0-beta.38

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.
Files changed (33) hide show
  1. package/build/client/assets/app-_i85JgUF.css +1 -0
  2. package/build/client/assets/{arrow-up-right-Dv3gGqIf.js → arrow-up-right-BRTGGI7c.js} +1 -1
  3. package/build/client/assets/{entry.client-Q4eUIqMI.js → entry.client-LwI3HNYl.js} +1 -1
  4. package/build/client/assets/{highlighted-body-B3W2YXNL-C5gyMelW.js → highlighted-body-B3W2YXNL-DwhUiBi7.js} +2 -2
  5. package/build/client/assets/{home-0OfTSXd1.js → home-DBrnNvHF.js} +7 -7
  6. package/build/client/assets/{index-Q81MFBxC.js → index-PFjW8YjQ.js} +20 -20
  7. package/build/client/assets/loader-circle-WvWWlrvM.js +12 -0
  8. package/build/client/assets/manifest-70ec0eba.js +1 -0
  9. package/build/client/assets/{mermaid-3ZIDBTTL-C_EWPx9a.js → mermaid-3ZIDBTTL-xYKZZytQ.js} +1063 -288
  10. package/build/client/assets/root-CINgYZFD.css +1 -0
  11. package/build/client/assets/{root-BPK1T9Ck.js → root-Cimnh7R3.js} +15 -30
  12. package/build/client/assets/{run-detail-CrqNzQ_y.js → run-detail-Dr7nmBuO.js} +74 -168
  13. package/build/client/assets/{workflow-graph-viewer-DrfqsDRu.js → workflow-graph-viewer-tTf4FHzV.js} +65 -87
  14. package/build/client/assets/{zstd-browser-decoder-Ds2MNSdp.js → zstd-browser-decoder-B15ptsR4.js} +2 -2
  15. package/build/server/assets/{server-build-4Pq8AwvA.js → app-BUMjG2-y.js} +129788 -119883
  16. package/build/server/assets/{highlighted-body-B3W2YXNL-C7tx66m_.js → highlighted-body-B3W2YXNL-Bkx5Bh9I.js} +3 -4
  17. package/build/server/assets/{index-Cnj8rNtV.js → index-DVvcuTAp.js} +50 -52
  18. package/build/server/assets/{mermaid-3ZIDBTTL-DStR4R-M.js → mermaid-3ZIDBTTL-CSJYRI2g.js} +4 -5
  19. package/build/server/assets/{token-CYc8-6E0.js → token-BXRDO8X7.js} +1 -2
  20. package/build/server/assets/{token-util-D94FNaX0.js → token-util-2RA-Rh-5.js} +1 -2
  21. package/build/server/assets/{zstd-browser-decoder-DXnLXD-w.js → zstd-browser-decoder-Cqnyq-Ly.js} +4 -5
  22. package/build/server/index.js +41 -2
  23. package/handler.d.ts +22 -0
  24. package/handler.js +186 -0
  25. package/package.json +20 -8
  26. package/registry.d.ts +29 -0
  27. package/registry.js +89 -0
  28. package/build/client/assets/encryption-CLVP4klT.js +0 -51
  29. package/build/client/assets/index-STTN0-2V.js +0 -306
  30. package/build/client/assets/manifest-485c4078.js +0 -1
  31. package/build/client/assets/root-15oK726f.css +0 -1
  32. package/build/client/assets/server-build-DblSGQ6A.css +0 -1
  33. package/build/server/assets/app-BSsmG188.js +0 -9217
@@ -1,9 +1,7 @@
1
- import { r as reactExports, j as jsxRuntimeExports, p as reactDomExports, G as ReactDOM, d as useNavigate, e as useSearchParams, c as Link, w as withComponentProps, H as useParams } from "./index-Q81MFBxC.js";
2
- import { C as Check, a as Copy, d as CircleAlert, U as parseStepName, G as parseWorkflowName, V as ErrorCard, Y as format, Z as Zap, S as Send, R as ResolveHookModal, t as ChevronUp, X, Q as ErrorBoundary, _ as Circle, u as unwrapOrThrow, W as WorkflowWebAPIError, K as unwrapServerActionResult, $ as useEscapeKeydown, w as composeEventHandlers, a0 as useCallbackRef, a1 as useLayoutEffect2, v as useControllableState, a2 as useId, a3 as createContext2, x as Presence, z as createContextScope, p as hideOthers, q as ReactRemoveScroll, a4 as useFocusGuards, a5 as LAYOUT, a6 as wakeUpRun, n as resumeHook, A as Alert, e as AlertTitle, g as getErrorTitle, h as AlertDescription, i as getErrorMessage, b as Skeleton$1, a7 as RunActionsButtons, H as StatusBadge, j as CopyableText, c as RelativeTime, T as Tabs, M as TabsList, N as TabsTrigger, O as TabsContent, B as cancelRun, a8 as recreateRun } from "./workflow-graph-viewer-DrfqsDRu.js";
3
- import { c as createLucideIcon, W as cn, X as DataInspector, Y as DecryptClickContext, Z as Button, $ as Spinner, a0 as Lock, a1 as CollapsibleRoot, a2 as CollapsibleTrigger, a3 as CollapsibleContent, M as cva, a4 as RESERVED_ATTRIBUTE_KEY_PREFIX, a5 as ContextCardProvider, h as useToast, a6 as Skeleton, a7 as Yr, a8 as isEncryptedMarker, C as ChevronRight, a9 as TimestampTooltip, aa as formatDuration, ab as isHookLifecycleEventType, ac as isTerminalStepEventType, ad as isWaitEventType, ae as isStepEventType, af as _r, ag as RunClickContext, ah as StreamClickContext, ai as Collapsible, aj as isExpiredMarker, ak as isDoStreamStep, al as extractConversation, am as getEventDataRefFields, an as hasEncryptedFields, ao as useSidebarDataOptional, ap as isTerminalWorkflowRunStatus, aq as clsx, ar as useActiveSpan, as as useSidebarData, at as Tooltip, au as TooltipTrigger, av as IconButton, aw as TooltipContent, H as ChevronDown, ax as useRowWindow, ay as isSpanDimmedBySearch, az as ROW_HEIGHT_PX, aA as getSpanDurationMs, aB as isSpanErrored, aC as formatDurationPrecise, aD as TooltipProvider, aE as ActiveSpanProvider, aF as useReducedMotion, aG as searchSpans, aH as computeRootBounds, aI as computeTimeMarkers, aJ as clampViewportToRoot, aK as getHighResInMs, aL as scrollRowIntoView, aM as TIMELINE_PADDING_PX, aN as Minimap, aO as Timeline, aP as TimelineHeader, aQ as wheelZoomScaleFactor, aR as wheelDeltaToPixels, aS as SidebarDataProvider, aT as fetchHook, l as fetchEvents, aU as hydrateResourceIOAsync, J as fetchRun, aV as fetchStep, aW as hydrateResourceIO, aX as fetchStreams, aY as Slot, I as useComposedRefs, aZ as Slottable, e as cn$1, a_ as buttonVariants, a$ as fetchEvent, b0 as fetchEventsByCorrelationId, b1 as isEncryptedData, b2 as hydrateData, b3 as getWebRevivers, T as Tooltip$1, a as TooltipTrigger$1, b as TooltipContent$1, b4 as LIVE_UPDATE_INTERVAL_MS$1, u as useServerConfig, b5 as getEncryptionKeyForRun, t as toast, L as LoaderCircle, b6 as StreamViewer } from "./mermaid-3ZIDBTTL-C_EWPx9a.js";
4
- import { A as ArrowUpRight } from "./arrow-up-right-Dv3gGqIf.js";
5
- import { decrypt, importKey } from "./encryption-CLVP4klT.js";
6
- import "./index-STTN0-2V.js";
1
+ import { r as reactExports, j as jsxRuntimeExports, o as reactDomExports, D as ReactDOM, d as useNavigate, e as useSearchParams, c as Link, w as withComponentProps, G as useParams } from "./index-PFjW8YjQ.js";
2
+ import { C as CircleAlert, O as parseStepName, B as parseWorkflowName, Q as ErrorCard, U as format, Z as Zap, S as Send, R as ResolveHookModal, q as ChevronUp, X, N as ErrorBoundary, V as Circle, u as unwrapOrThrow, W as WorkflowWebAPIError, I as unwrapServerActionResult, Y as useEscapeKeydown, t as composeEventHandlers, _ as useCallbackRef, $ as useLayoutEffect2, s as useControllableState, a0 as useId, a1 as createContext2, v as Presence, x as createContextScope, n as hideOthers, o as ReactRemoveScroll, a2 as useFocusGuards, a3 as LAYOUT, a4 as wakeUpRun, l as resumeHook, A as Alert, c as AlertTitle, g as getErrorTitle, d as AlertDescription, e as getErrorMessage, a as Skeleton$1, a5 as RunActionsButtons, F as StatusBadge, h as CopyableText, b as RelativeTime, T as Tabs, K as TabsList, L as TabsTrigger, M as TabsContent, y as cancelRun, a6 as recreateRun } from "./workflow-graph-viewer-tTf4FHzV.js";
3
+ import { c as createLucideIcon, X as cn, Y as CopyableDataBlock, Z as CollapsibleRoot, $ as CollapsibleTrigger, a0 as CollapsibleContent, a1 as CopyButton, N as cva, a2 as RESERVED_ATTRIBUTE_KEY_PREFIX, a3 as Spinner, a4 as ContextCardProvider, h as useToast, a5 as Skeleton, a6 as DecryptClickContext, a7 as Yr, a8 as isEncryptedMarker, m as ChevronRight, a9 as TimestampTooltip, aa as formatDuration, C as Check, l as Copy, ab as DataInspector, ac as isHookLifecycleEventType, ad as isTerminalStepEventType, ae as isWaitEventType, af as isStepEventType, ag as _r, ah as RunClickContext, ai as StreamClickContext, aj as Collapsible, ak as isExpiredMarker, al as isDoStreamStep, am as extractConversation, an as EncryptedDataBlock, ao as getEventDataRefFields, ap as hasEncryptedFields, aq as useSidebarDataOptional, ar as isTerminalWorkflowRunStatus, as as clsx, at as useActiveSpan, au as useSidebarData, av as Tooltip, aw as TooltipTrigger, ax as IconButton, ay as TooltipContent, J as ChevronDown, az as useRowWindow, aA as isSpanDimmedBySearch, aB as ROW_HEIGHT_PX, aC as getSpanDurationMs, aD as isSpanErrored, aE as formatDurationPrecise, aF as TooltipProvider, aG as ActiveSpanProvider, aH as useReducedMotion, aI as searchSpans, aJ as computeRootBounds, aK as computeTimeMarkers, aL as clampViewportToRoot, aM as getHighResInMs, aN as scrollRowIntoView, aO as TIMELINE_PADDING_PX, aP as Minimap, aQ as Timeline, aR as TimelineHeader, aS as wheelZoomScaleFactor, aT as wheelDeltaToPixels, aU as SidebarDataProvider, aV as fetchHook, n as fetchEvents, aW as hydrateResourceIOAsync, M as fetchRun, aX as fetchStep, aY as hydrateResourceIO, aZ as fetchStreams, a_ as apiBase, a$ as Slot, L as useComposedRefs, b0 as Slottable, e as cn$1, b1 as buttonVariants, b2 as fetchEvent, b3 as fetchEventsByCorrelationId, b4 as isEncryptedData, b5 as hydrateData, b6 as decrypt, b7 as deriveRunPayloadKeys, b8 as getWebRevivers, T as Tooltip$1, a as TooltipTrigger$1, b as TooltipContent$1, b9 as LIVE_UPDATE_INTERVAL_MS$1, u as useServerConfig, ba as getEncryptionKeyForRun, t as toast, bb as StreamViewerSkeleton, bc as Lock, bd as StreamViewer } from "./mermaid-3ZIDBTTL-xYKZZytQ.js";
4
+ import { A as ArrowUpRight } from "./arrow-up-right-BRTGGI7c.js";
7
5
  /**
8
6
  * @license lucide-react v0.575.0 - ISC
9
7
  *
@@ -105,27 +103,6 @@ function looksLikeWorkflowIdSearchInput(query) {
105
103
  }
106
104
  return /\d/.test(trimmed);
107
105
  }
108
- function CopyButton({ copyText, ariaLabel, className }) {
109
- const [copied, setCopied] = reactExports.useState(false);
110
- const timeoutRef = reactExports.useRef(null);
111
- reactExports.useEffect(() => {
112
- return () => {
113
- if (timeoutRef.current) {
114
- clearTimeout(timeoutRef.current);
115
- }
116
- };
117
- }, []);
118
- return jsxRuntimeExports.jsx("button", { type: "button", "aria-label": ariaLabel, className: cn("cursor-pointer text-gray-800 hover:text-gray-1000 bg-transparent border-0 p-1 m-0", className), onClick: (e) => {
119
- e.stopPropagation();
120
- if (timeoutRef.current) {
121
- clearTimeout(timeoutRef.current);
122
- }
123
- void navigator.clipboard.writeText(copyText).then(() => {
124
- setCopied(true);
125
- timeoutRef.current = setTimeout(() => setCopied(false), 1e3);
126
- });
127
- }, children: jsxRuntimeExports.jsxs("div", { className: "relative w-3 h-3", children: [jsxRuntimeExports.jsx("div", { className: cn("absolute inset-0 flex items-center justify-center transition-all duration-150 ease-out", copied ? "scale-100 opacity-100" : "scale-0 opacity-0"), children: jsxRuntimeExports.jsx(Check, { className: "w-3 h-3" }) }), jsxRuntimeExports.jsx("div", { className: cn("absolute inset-0 flex items-center justify-center transition-all duration-150 ease-out", copied ? "scale-0 opacity-0" : "scale-100 opacity-100"), children: jsxRuntimeExports.jsx(Copy, { className: "w-3 h-3" }) })] }) });
128
- }
129
106
  const ELLIPSIS = "…";
130
107
  const MIN_START = 3;
131
108
  const MIN_END = 3;
@@ -406,29 +383,6 @@ function MiddleTruncate({ value, className, onCopy: onCopyProp, ...props }) {
406
383
  }, [onCopyProp, isTruncated, prefixText, suffixText, value]);
407
384
  return jsxRuntimeExports.jsxs("span", { title: isTruncated ? value : void 0, ...props, ref, className: cn("relative inline-grid min-w-0 max-w-full overflow-hidden whitespace-nowrap", className), onCopy: handleCopy, children: [isTruncated && jsxRuntimeExports.jsx("span", { className: "sr-only select-none", children: value }), jsxRuntimeExports.jsx("span", { "aria-hidden": "true", className: "pointer-events-none col-start-1 row-start-1 invisible select-none whitespace-nowrap", children: value }), jsxRuntimeExports.jsx("span", { "aria-hidden": isTruncated || void 0, className: "col-start-1 row-start-1 min-w-0 overflow-hidden", ref: visibleRef, children: isTruncated ? jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [jsxRuntimeExports.jsx("span", { children: prefixText }), jsxRuntimeExports.jsx("span", { children: ELLIPSIS }), jsxRuntimeExports.jsx("span", { children: suffixText })] }) : displayText }), jsxRuntimeExports.jsx("span", { "aria-hidden": "true", className: "pointer-events-none absolute left-0 top-0 inline-block invisible select-none whitespace-nowrap", ref: measureRef })] });
408
385
  }
409
- const encryptedPlaceholderPreview = `{
410
- "input": "[encrypted]",
411
- "result": "[encrypted]"
412
- }`;
413
- function EncryptedDataBlock() {
414
- const ctx = reactExports.useContext(DecryptClickContext);
415
- return jsxRuntimeExports.jsxs("div", { className: "relative min-h-20 overflow-hidden rounded-md border border-gray-alpha-400 bg-background-100", children: [jsxRuntimeExports.jsx("pre", { "aria-hidden": "true", className: "pointer-events-none m-0 select-none p-3 font-mono text-label-12 text-gray-900 blur-[4px]", children: encryptedPlaceholderPreview }), jsxRuntimeExports.jsx("div", { className: "absolute inset-0 flex items-center justify-center", children: ctx ? jsxRuntimeExports.jsxs(Button, { onClick: ctx.onDecrypt, disabled: ctx.isDecrypting, size: "xs", children: [ctx.isDecrypting ? jsxRuntimeExports.jsx(Spinner, { size: 10 }) : jsxRuntimeExports.jsx(Lock, { className: "h-3 w-3" }), jsxRuntimeExports.jsx("span", { children: "Decrypt" })] }) : jsxRuntimeExports.jsxs("span", { className: "inline-flex items-center gap-1 rounded border border-gray-alpha-400 bg-gray-100 px-1.5 py-0.5 text-button-12 font-medium text-gray-700", children: [jsxRuntimeExports.jsx(Lock, { className: "h-3 w-3" }), "Encrypted"] }) })] });
416
- }
417
- const serializeForClipboard = (value) => {
418
- if (typeof value === "string")
419
- return value;
420
- if (typeof value === "number" || typeof value === "boolean" || value === null) {
421
- return String(value);
422
- }
423
- try {
424
- return JSON.stringify(value, null, 2);
425
- } catch {
426
- return String(value);
427
- }
428
- };
429
- function CopyableDataBlock({ data }) {
430
- return jsxRuntimeExports.jsxs("div", { className: "relative overflow-x-auto rounded-md border border-gray-alpha-400 p-3", children: [jsxRuntimeExports.jsx(CopyButton, { copyText: serializeForClipboard(data), ariaLabel: "Copy data", className: "absolute right-2 top-2 z-10 flex h-6 w-6 items-center justify-center rounded-md border border-gray-alpha-400 !bg-background-100 p-0 text-gray-900 transition-transform transition-colors duration-100 hover:bg-gray-200 active:scale-95 active:bg-gray-300" }), jsxRuntimeExports.jsx(DataInspector, { data })] });
431
- }
432
386
  function isReservedAttributeKey(key) {
433
387
  return key.startsWith(RESERVED_ATTRIBUTE_KEY_PREFIX);
434
388
  }
@@ -2100,6 +2054,8 @@ const attributeToDisplayFn = {
2100
2054
  receivedCount: (value) => String(value),
2101
2055
  lastReceivedAt: localMillisecondTimeOrNull,
2102
2056
  disposedAt: localMillisecondTimeOrNull,
2057
+ // Internal resume plumbing — not surfaced in the UI
2058
+ resumeContext: (_value) => null,
2103
2059
  // Event details
2104
2060
  eventType: (value) => String(value),
2105
2061
  correlationId: (value) => String(value),
@@ -2205,7 +2161,11 @@ const attributeToDisplayFn = {
2205
2161
  if (typeof value !== "string" || value.length === 0)
2206
2162
  return null;
2207
2163
  return String(value);
2208
- }
2164
+ },
2165
+ // Internal encryption plumbing: the run's X25519 public key, used by
2166
+ // cross-run writers to seal payloads to this run. Not actionable for users
2167
+ // and not secret — hidden rather than rendered as 44 opaque base64 chars.
2168
+ encryptionPublicKey: (_value) => null
2209
2169
  };
2210
2170
  const resolvableAttributes = [
2211
2171
  "input",
@@ -3329,15 +3289,14 @@ function NewTraceViewerContent({ trace, onLoadMore, hasMore, isLoadingMore }) {
3329
3289
  }, [animateTo, clampToRoot]);
3330
3290
  const ZOOM_FACTOR = 0.5;
3331
3291
  const zoomBy = reactExports.useCallback((factor) => {
3332
- setViewport((prev) => {
3333
- const center = (prev.start + prev.end) / 2;
3334
- const newDuration = Math.max(MIN_VIEWPORT_MS, (prev.end - prev.start) * factor);
3335
- return clampToRoot({
3336
- start: center - newDuration / 2,
3337
- end: center + newDuration / 2
3338
- });
3339
- });
3340
- }, [setViewport, clampToRoot]);
3292
+ const { start, end } = viewportRef.current;
3293
+ const center = (start + end) / 2;
3294
+ const newDuration = Math.max(MIN_VIEWPORT_MS, (end - start) * factor);
3295
+ animateTo(clampToRoot({
3296
+ start: center - newDuration / 2,
3297
+ end: center + newDuration / 2
3298
+ }));
3299
+ }, [animateTo, clampToRoot]);
3341
3300
  const zoomIn = reactExports.useCallback(() => zoomBy(ZOOM_FACTOR), [zoomBy]);
3342
3301
  const zoomOut = reactExports.useCallback(() => zoomBy(1 / ZOOM_FACTOR), [zoomBy]);
3343
3302
  const isAtMinZoom = viewDuration >= root.duration;
@@ -3832,7 +3791,7 @@ async function readStream(_env, streamId, runId, signal, cursor) {
3832
3791
  if (cursor) {
3833
3792
  params.set("cursor", cursor);
3834
3793
  }
3835
- const url = `/api/stream/${encodeURIComponent(streamId)}?${params.toString()}`;
3794
+ const url = `${apiBase()}/api/stream/${encodeURIComponent(streamId)}?${params.toString()}`;
3836
3795
  const response = await fetch(url, { signal });
3837
3796
  if (!response.ok) {
3838
3797
  const errorData = await response.json().catch(() => null);
@@ -5171,6 +5130,9 @@ function detectEncoding(data) {
5171
5130
  function useStreamReader(env, streamId, runId, encryptionKey, runStatus) {
5172
5131
  const [chunks, setChunks] = reactExports.useState([]);
5173
5132
  const [isLive, setIsLive] = reactExports.useState(false);
5133
+ const [isInitialLoading, setIsInitialLoading] = reactExports.useState(
5134
+ Boolean(streamId && runId)
5135
+ );
5174
5136
  const [error, setError] = reactExports.useState(null);
5175
5137
  const abortControllerRef = reactExports.useRef(null);
5176
5138
  const chunkIdRef = reactExports.useRef(0);
@@ -5199,9 +5161,8 @@ function useStreamReader(env, streamId, runId, encryptionKey, runStatus) {
5199
5161
  if (!cryptoKey) {
5200
5162
  return { encrypted: true };
5201
5163
  }
5202
- const payload = frameData.slice(4);
5203
5164
  hydrated = hydrateData(
5204
- await decrypt(cryptoKey, payload),
5165
+ await decrypt(frameData, cryptoKey),
5205
5166
  revivers
5206
5167
  );
5207
5168
  } else {
@@ -5218,6 +5179,8 @@ function useStreamReader(env, streamId, runId, encryptionKey, runStatus) {
5218
5179
  reactExports.useEffect(() => {
5219
5180
  setChunks([]);
5220
5181
  setError(null);
5182
+ setIsLive(false);
5183
+ setIsInitialLoading(Boolean(streamId && runId));
5221
5184
  chunkIdRef.current = 0;
5222
5185
  frameCountRef.current = 0;
5223
5186
  serverCursorRef.current = null;
@@ -5226,13 +5189,12 @@ function useStreamReader(env, streamId, runId, encryptionKey, runStatus) {
5226
5189
  pollTimerRef.current = null;
5227
5190
  }
5228
5191
  if (!streamId || !runId) {
5229
- setIsLive(false);
5192
+ setIsInitialLoading(false);
5230
5193
  return;
5231
5194
  }
5232
5195
  let mounted = true;
5233
5196
  const abortController = new AbortController();
5234
5197
  abortControllerRef.current = abortController;
5235
- setIsLive(true);
5236
5198
  const revivers = getWebRevivers();
5237
5199
  const parseLegacyLine = (line) => {
5238
5200
  const chunkId = chunkIdRef.current++;
@@ -5354,13 +5316,14 @@ function useStreamReader(env, streamId, runId, encryptionKey, runStatus) {
5354
5316
  };
5355
5317
  const readStreamData = async () => {
5356
5318
  try {
5357
- const cryptoKey = encryptionKey ? await importKey(encryptionKey) : void 0;
5319
+ const cryptoKey = encryptionKey ? await deriveRunPayloadKeys(encryptionKey) : void 0;
5358
5320
  const initialChunks = [];
5359
5321
  const result = await fetchAndParse(initialChunks, cryptoKey);
5360
5322
  if (result.encrypted) {
5361
5323
  if (mounted) {
5362
5324
  setError("This stream is encrypted. Click Decrypt to view.");
5363
5325
  setIsLive(false);
5326
+ setIsInitialLoading(false);
5364
5327
  }
5365
5328
  return;
5366
5329
  }
@@ -5368,11 +5331,13 @@ function useStreamReader(env, streamId, runId, encryptionKey, runStatus) {
5368
5331
  serverCursorRef.current = result.cursor;
5369
5332
  if (!mounted || abortController.signal.aborted) return;
5370
5333
  setChunks(initialChunks);
5334
+ setIsInitialLoading(false);
5371
5335
  if (result.done) {
5372
5336
  setIsLive(false);
5373
5337
  return;
5374
5338
  }
5375
5339
  if (isRunActive(runStatusRef.current)) {
5340
+ setIsLive(true);
5376
5341
  const poll = async () => {
5377
5342
  if (!mounted || abortController.signal.aborted) return;
5378
5343
  try {
@@ -5410,6 +5375,7 @@ function useStreamReader(env, streamId, runId, encryptionKey, runStatus) {
5410
5375
  if (mounted) {
5411
5376
  setError(err instanceof Error ? err.message : String(err));
5412
5377
  setIsLive(false);
5378
+ setIsInitialLoading(false);
5413
5379
  }
5414
5380
  }
5415
5381
  };
@@ -5430,7 +5396,7 @@ function useStreamReader(env, streamId, runId, encryptionKey, runStatus) {
5430
5396
  setIsLive(false);
5431
5397
  }
5432
5398
  }, [runStatus]);
5433
- return { chunks, isLive, error };
5399
+ return { chunks, isLive, isInitialLoading, error };
5434
5400
  }
5435
5401
  function LiveStatus({ hasError, errorMessage }) {
5436
5402
  return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex items-center gap-2", children: /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip$1, { children: [
@@ -5641,6 +5607,7 @@ function RunDetailView({
5641
5607
  const {
5642
5608
  chunks: streamChunks,
5643
5609
  isLive: streamIsLive,
5610
+ isInitialLoading: streamIsInitialLoading,
5644
5611
  error: streamError
5645
5612
  } = useStreamReader(env, selectedStreamId, runId, encryptionKey, run.status);
5646
5613
  const handleCancelClick = () => {
@@ -5855,115 +5822,54 @@ function RunDetailView({
5855
5822
  onExactIdSearch: searchByExactId
5856
5823
  }
5857
5824
  ) }) }) }),
5858
- /* @__PURE__ */ jsxRuntimeExports.jsx(TabsContent, { value: "streams", className: "mt-0 flex-1 min-h-0", children: /* @__PURE__ */ jsxRuntimeExports.jsx(ErrorBoundary, { title: "Failed to load stream data", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "h-full flex gap-4", children: [
5859
- /* @__PURE__ */ jsxRuntimeExports.jsxs(
5860
- "div",
5861
- {
5862
- className: "w-64 flex-shrink-0 border rounded-lg overflow-hidden",
5863
- style: {
5864
- borderColor: "var(--ds-gray-300)",
5865
- backgroundColor: "var(--ds-background-100)"
5866
- },
5867
- children: [
5868
- /* @__PURE__ */ jsxRuntimeExports.jsxs(
5869
- "div",
5870
- {
5871
- className: "px-3 py-2 border-b text-xs font-medium",
5872
- style: {
5873
- borderColor: "var(--ds-gray-300)",
5874
- color: "var(--ds-gray-900)"
5875
- },
5876
- children: [
5877
- "Streams (",
5878
- streams.length,
5879
- ")"
5880
- ]
5881
- }
5882
- ),
5883
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "overflow-auto max-h-[calc(100vh-400px)]", children: streamsLoading ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "p-4 flex items-center justify-center", children: /* @__PURE__ */ jsxRuntimeExports.jsx(LoaderCircle, { className: "h-4 w-4 animate-spin text-muted-foreground" }) }) : streamsError ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "p-4 text-xs text-destructive", children: streamsError.message }) : streams.length === 0 ? /* @__PURE__ */ jsxRuntimeExports.jsx(
5884
- "div",
5885
- {
5886
- className: "p-4 text-xs",
5887
- style: { color: "var(--ds-gray-600)" },
5888
- children: "No streams found for this run"
5889
- }
5890
- ) : streams.map((streamId) => /* @__PURE__ */ jsxRuntimeExports.jsx(
5891
- "button",
5892
- {
5893
- type: "button",
5894
- onClick: () => setSelectedStreamId(streamId),
5895
- className: "w-full text-left px-3 py-2 text-xs font-mono truncate hover:bg-accent transition-colors",
5896
- style: {
5897
- backgroundColor: selectedStreamId === streamId ? "var(--ds-gray-200)" : "transparent",
5898
- color: "var(--ds-gray-1000)"
5899
- },
5900
- title: streamId,
5901
- children: streamId
5902
- },
5903
- streamId
5904
- )) })
5905
- ]
5906
- }
5907
- ),
5908
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1 min-w-0", children: selectedStreamId ? (streamError == null ? void 0 : streamError.includes("encrypted")) && !encryptionKey ? /* @__PURE__ */ jsxRuntimeExports.jsxs(
5909
- "div",
5910
- {
5911
- className: "h-full flex flex-col items-center justify-center gap-3 rounded-lg border p-4",
5912
- style: {
5913
- borderColor: "var(--ds-gray-300)",
5914
- backgroundColor: "var(--ds-gray-100)"
5825
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TabsContent, { value: "streams", className: "mt-0 flex-1 min-h-0", children: /* @__PURE__ */ jsxRuntimeExports.jsx(ErrorBoundary, { title: "Failed to load stream data", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "relative -mx-6 flex h-full min-h-0 overflow-hidden border-t border-gray-alpha-400 bg-background-100", children: [
5826
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex w-[340px] shrink-0 flex-col border-r border-gray-alpha-400 bg-background-100", children: [
5827
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
5828
+ "div",
5829
+ {
5830
+ "aria-hidden": "true",
5831
+ className: "h-10 min-h-10 border-b border-gray-alpha-400"
5832
+ }
5833
+ ),
5834
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "min-h-0 flex-1 divide-y divide-gray-400 overflow-y-auto", children: streamsLoading ? /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col divide-y divide-gray-400", children: [
5835
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex h-10 items-center pl-4 pr-2", children: /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton$1, { className: "h-3.5 w-24" }) }),
5836
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex h-10 items-center pl-4 pr-2", children: /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton$1, { className: "h-3.5 w-32" }) }),
5837
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex h-10 items-center pl-4 pr-2", children: /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton$1, { className: "h-3.5 w-20" }) })
5838
+ ] }) : streamsError ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "px-4 py-2 text-label-12 text-red-900", children: streamsError.message }) : streams.length === 0 ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex h-10 items-center px-4 text-label-12 text-gray-900", children: "No streams found for this run" }) : streams.map((streamId) => /* @__PURE__ */ jsxRuntimeExports.jsx(
5839
+ "button",
5840
+ {
5841
+ type: "button",
5842
+ onClick: () => setSelectedStreamId(streamId),
5843
+ className: `flex h-10 w-full min-w-0 items-center truncate pl-4 pr-2 text-left text-label-14 transition-colors ${selectedStreamId === streamId ? "bg-gray-100 text-gray-1000 hover:bg-gray-200 active:bg-gray-200" : "bg-transparent text-gray-900 hover:bg-gray-100 hover:text-gray-1000 focus-visible:bg-gray-100 focus-visible:text-gray-1000"}`,
5844
+ title: streamId,
5845
+ children: streamId
5915
5846
  },
5916
- children: [
5917
- /* @__PURE__ */ jsxRuntimeExports.jsx(
5918
- Lock,
5919
- {
5920
- className: "h-6 w-6",
5921
- style: { color: "var(--ds-gray-700)" }
5922
- }
5923
- ),
5924
- /* @__PURE__ */ jsxRuntimeExports.jsx(
5925
- "div",
5926
- {
5927
- className: "text-sm",
5928
- style: { color: "var(--ds-gray-900)" },
5929
- children: "This stream is encrypted."
5930
- }
5931
- ),
5932
- /* @__PURE__ */ jsxRuntimeExports.jsx(
5933
- DecryptButton,
5934
- {
5935
- onClick: handleDecrypt,
5936
- loading: isDecrypting
5937
- }
5938
- )
5939
- ]
5940
- }
5941
- ) : /* @__PURE__ */ jsxRuntimeExports.jsx(
5847
+ streamId
5848
+ )) })
5849
+ ] }),
5850
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex min-w-0 flex-1 flex-col overflow-hidden bg-background-100", children: streamsLoading ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "min-h-0 flex-1", children: /* @__PURE__ */ jsxRuntimeExports.jsx(StreamViewerSkeleton, {}) }) : selectedStreamId ? (streamError == null ? void 0 : streamError.includes("encrypted")) && !encryptionKey ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex h-full items-center justify-center p-4", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col items-center gap-3 text-center", children: [
5851
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Lock, { className: "h-8 w-8 text-gray-700" }),
5852
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-1", children: [
5853
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-label-14 font-medium text-gray-1000", children: "Encrypted Stream" }),
5854
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-label-12 text-gray-900", children: "Decrypt this stream to view its chunks." })
5855
+ ] }),
5856
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
5857
+ DecryptButton,
5858
+ {
5859
+ onClick: handleDecrypt,
5860
+ loading: isDecrypting
5861
+ }
5862
+ )
5863
+ ] }) }) : /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "min-h-0 flex-1", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
5942
5864
  StreamViewer,
5943
5865
  {
5944
5866
  streamId: selectedStreamId,
5945
5867
  chunks: streamChunks,
5946
5868
  isLive: streamIsLive,
5869
+ isLoading: streamIsInitialLoading,
5947
5870
  error: (streamError == null ? void 0 : streamError.includes("encrypted")) ? null : streamError
5948
5871
  }
5949
- ) : /* @__PURE__ */ jsxRuntimeExports.jsx(
5950
- "div",
5951
- {
5952
- className: "h-full flex items-center justify-center rounded-lg border",
5953
- style: {
5954
- borderColor: "var(--ds-gray-300)",
5955
- backgroundColor: "var(--ds-gray-100)"
5956
- },
5957
- children: /* @__PURE__ */ jsxRuntimeExports.jsx(
5958
- "div",
5959
- {
5960
- className: "text-sm",
5961
- style: { color: "var(--ds-gray-600)" },
5962
- children: streams.length > 0 ? "Select a stream to view its data" : "No streams available"
5963
- }
5964
- )
5965
- }
5966
- ) })
5872
+ ) }) : /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex h-full items-center justify-center", children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-label-14 text-gray-600", children: streams.length > 0 ? "Select a stream to view its data" : "No streams available" }) }) })
5967
5873
  ] }) }) }),
5968
5874
  false
5969
5875
  ]