@opengeni/react 5.1.0-canary.0 → 5.2.0-canary.0

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 (66) hide show
  1. package/dist/artifacts.d.ts +2 -0
  2. package/dist/artifacts.js +1391 -2
  3. package/dist/artifacts.js.map +1 -1
  4. package/dist/chunk-2TKI3WEG.js +73 -0
  5. package/dist/chunk-2TKI3WEG.js.map +1 -0
  6. package/dist/{chunk-M2HNWZYR.js → chunk-IHQII5WO.js} +69 -18
  7. package/dist/chunk-IHQII5WO.js.map +1 -0
  8. package/dist/{chunk-HUMIRRYI.js → chunk-IYCR4343.js} +19 -19
  9. package/dist/{chunk-HUMIRRYI.js.map → chunk-IYCR4343.js.map} +1 -1
  10. package/dist/{chunk-WS6D5BHH.js → chunk-QXJCNVSD.js} +2268 -2217
  11. package/dist/chunk-QXJCNVSD.js.map +1 -0
  12. package/dist/{chunk-BV5A4OTE.js → chunk-T5FRXMC3.js} +21 -2
  13. package/dist/{chunk-BV5A4OTE.js.map → chunk-T5FRXMC3.js.map} +1 -1
  14. package/dist/{chunk-BRFMGY4L.js → chunk-UGMKPUEM.js} +28 -3
  15. package/dist/chunk-UGMKPUEM.js.map +1 -0
  16. package/dist/components/artifacts/inline-html-document.d.ts +2 -0
  17. package/dist/components/artifacts/published-html-artifact-frame.d.ts +2 -0
  18. package/dist/components/artifacts/visualization-assets.gen.d.ts +2 -0
  19. package/dist/components/markdown.d.ts +13 -1
  20. package/dist/{computer-viewer-7TEZC6Y2.js → computer-viewer-AA4JH2AP.js} +2 -2
  21. package/dist/connect.js +1 -1
  22. package/dist/index.d.ts +2 -1
  23. package/dist/index.js +7 -4
  24. package/dist/index.js.map +1 -1
  25. package/dist/interaction.js +1 -1
  26. package/dist/{platform-activity-row-27LKAWZD.js → platform-activity-row-UW4UVVM4.js} +6 -3
  27. package/dist/platform-activity-row-UW4UVVM4.js.map +1 -0
  28. package/dist/session-ui.js +4 -3
  29. package/dist/session-ui.js.map +1 -1
  30. package/dist/session.js +1 -1
  31. package/dist/sites-ui.d.ts +2 -1
  32. package/dist/sites.js +12 -4
  33. package/dist/sites.js.map +1 -1
  34. package/dist/timeline/activity-rail.d.ts +1 -0
  35. package/dist/timeline/platform-activity-row.d.ts +1 -1
  36. package/dist/timeline/retained-image.d.ts +16 -0
  37. package/dist/timeline/rolling-activity.d.ts +9 -0
  38. package/dist/timeline/shared.d.ts +4 -1
  39. package/dist/timeline/turn-summary.d.ts +4 -1
  40. package/package.json +4 -4
  41. package/src/artifacts.ts +2 -0
  42. package/src/components/artifacts/inline-html-document.ts +24 -0
  43. package/src/components/artifacts/published-html-artifact-frame.tsx +32 -2
  44. package/src/components/artifacts/visualization-assets/base.css +1015 -0
  45. package/src/components/artifacts/visualization-assets/helpers.html +349 -0
  46. package/src/components/artifacts/visualization-assets.gen.ts +3 -0
  47. package/src/components/copy-button.tsx +7 -2
  48. package/src/components/markdown.tsx +111 -34
  49. package/src/components/message-timeline.tsx +48 -3
  50. package/src/hooks/use-computer-session.ts +36 -1
  51. package/src/index.ts +6 -1
  52. package/src/sites-ui.tsx +23 -6
  53. package/src/timeline/activity-rail.tsx +20 -3
  54. package/src/timeline/platform-activity-row.tsx +5 -2
  55. package/src/timeline/retained-image.ts +91 -0
  56. package/src/timeline/rolling-activity.tsx +83 -0
  57. package/src/timeline/shared.tsx +33 -12
  58. package/src/timeline/tool-renderers.tsx +7 -91
  59. package/src/timeline/turn-summary.tsx +21 -15
  60. package/styles/compiled.css +122 -0
  61. package/styles/index.css +49 -0
  62. package/dist/chunk-BRFMGY4L.js.map +0 -1
  63. package/dist/chunk-M2HNWZYR.js.map +0 -1
  64. package/dist/chunk-WS6D5BHH.js.map +0 -1
  65. package/dist/platform-activity-row-27LKAWZD.js.map +0 -1
  66. /package/dist/{computer-viewer-7TEZC6Y2.js.map → computer-viewer-AA4JH2AP.js.map} +0 -0
@@ -13,7 +13,7 @@ import {
13
13
  useComputerFrameStream,
14
14
  useComputerSession,
15
15
  useComputerSessions
16
- } from "./chunk-BV5A4OTE.js";
16
+ } from "./chunk-T5FRXMC3.js";
17
17
  import {
18
18
  useInteractionInterventions,
19
19
  useInteractionInvalidation
@@ -6,7 +6,6 @@ function PlatformActivityRow({
6
6
  t: displayName,
7
7
  b: BotIcon,
8
8
  m: Markdown,
9
- r: truncate,
10
9
  j,
11
10
  s
12
11
  }) {
@@ -19,7 +18,11 @@ function PlatformActivityRow({
19
18
  children: "Thought"
20
19
  }),
21
20
  running: item.streaming,
22
- preview: truncate(item.text, 110),
21
+ compactPreview: item.text.replace(/\*\*|__|`/g, "").replace(/\s+/g, " "),
22
+ preview: j("span", {
23
+ className: "og-reasoning-preview",
24
+ children: j(Markdown, { streaming: item.streaming, children: item.text })
25
+ }),
23
26
  children: j("div", {
24
27
  className: "text-og-base leading-6 text-og-fg-muted [&_strong]:text-og-fg-muted",
25
28
  children: j(Markdown, { streaming: item.streaming, children: item.text })
@@ -166,4 +169,4 @@ function startupDuration(durationMs) {
166
169
  export {
167
170
  PlatformActivityRow as default
168
171
  };
169
- //# sourceMappingURL=platform-activity-row-27LKAWZD.js.map
172
+ //# sourceMappingURL=platform-activity-row-UW4UVVM4.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/timeline/platform-activity-row.tsx"],"sourcesContent":["import type { ReasoningItem, SandboxItem, StartupPhaseItem } from \"./types\";\n\ntype RowJsx = typeof import(\"react/jsx-runtime\").jsx;\ntype RowJsxs = typeof import(\"react/jsx-runtime\").jsxs;\n\nexport default function PlatformActivityRow({\n item,\n d: ActivityDisclosure,\n p: PayloadBlock,\n t: displayName,\n b: BotIcon,\n m: Markdown,\n j,\n s,\n}: {\n item: ReasoningItem | SandboxItem | StartupPhaseItem;\n d: typeof import(\"./shared\").ActivityDisclosure;\n p: typeof import(\"./shared\").PayloadBlock;\n t: (name: string) => string;\n b: typeof import(\"lucide-react\").BotIcon;\n m: typeof import(\"../components/markdown\").Markdown;\n r: typeof import(\"../lib/format\").truncate;\n j: RowJsx;\n s: RowJsxs;\n}) {\n if (item.kind === \"reasoning\") {\n return j(ActivityDisclosure, {\n icon: brainIcon(j, s),\n iconTone: \"muted\",\n title: item.streaming\n ? \"Thinking\"\n : j(\"span\", {\n className: \"font-normal italic text-og-fg-subtle\",\n children: \"Thought\",\n }),\n running: item.streaming,\n compactPreview: item.text.replace(/\\*\\*|__|`/g, \"\").replace(/\\s+/g, \" \"),\n preview: j(\"span\", {\n className: \"og-reasoning-preview\",\n children: j(Markdown, { streaming: item.streaming, children: item.text }),\n }),\n children: j(\"div\", {\n className: \"text-og-base leading-6 text-og-fg-muted [&_strong]:text-og-fg-muted\",\n children: j(Markdown, { streaming: item.streaming, children: item.text }),\n }),\n });\n }\n if (item.kind === \"sandbox\") {\n return s(ActivityDisclosure, {\n icon: terminalIcon(j, s),\n iconTone:\n item.status === \"failed\" ? \"failed\" : item.status === \"running\" ? \"running\" : \"muted\",\n title: sandboxRowTitle(item, displayName),\n running: item.status === \"running\",\n failed: item.status === \"failed\",\n cancelled: item.status === \"cancelled\",\n preview: item.command ?? undefined,\n children: [\n item.command ? j(PayloadBlock, { label: \"Command\", value: item.command }, \"command\") : null,\n item.output ? j(PayloadBlock, { label: \"Output\", value: item.output }, \"output\") : null,\n ],\n });\n }\n\n const failed = item.status === \"failed\";\n const running = item.status === \"running\";\n const duration = startupDuration(item.durationMs);\n return j(ActivityDisclosure, {\n icon: j(BotIcon, { className: \"size-3.5\" }),\n iconTone: failed ? \"failed\" : running ? \"running\" : \"muted\",\n title:\n item.blockedReason === \"rotation_in_progress\"\n ? \"Waiting for sandbox rotation\"\n : startupPhaseTitle(item.phase, item.status, item.outcome),\n preview:\n item.phase === \"model_preparation\"\n ? \"Includes overlapping sandbox, rig, repository, and runtime setup shown below.\"\n : undefined,\n running,\n failed,\n cancelled: item.status === \"cancelled\",\n chip: duration ? { tone: failed ? \"bad\" : \"muted\", text: duration } : undefined,\n expandable: false,\n });\n}\n\nfunction brainIcon(j: RowJsx, s: RowJsxs) {\n return lucideIcon(j, s, \"brain\", [\n j(\"path\", { d: \"M 12 18V5\" }, \"spine\"),\n j(\"path\", { d: \"M15 13a4.17 4.17 0 0 1-3-4 4.17 4.17 0 0 1-3 4\" }, \"center\"),\n j(\"path\", { d: \"M17.598 6.5A3 3 0 1 0 12 5a3 3 0 1 0-5.598 1.5\" }, \"top\"),\n j(\"path\", { d: \"M17.997 5.125a4 4 0 0 1 2.526 5.77\" }, \"upper-right\"),\n j(\"path\", { d: \"M18 18a4 4 0 0 0 2-7.464\" }, \"right\"),\n j(\"path\", { d: \"M19.967 17.483A4 4 0 1 1 12 18a4 4 0 1 1-7.967-.517\" }, \"base\"),\n j(\"path\", { d: \"M6 18a4 4 0 0 1-2-7.464\" }, \"left\"),\n j(\"path\", { d: \"M6.003 5.125a4 4 0 0 0-2.526 5.77\" }, \"upper-left\"),\n ]);\n}\n\nfunction terminalIcon(j: RowJsx, s: RowJsxs) {\n return lucideIcon(j, s, \"square-terminal\", [\n j(\"path\", { d: \"m7 11 2-2-2-2\" }, \"prompt\"),\n j(\"path\", { d: \"M11 13h4\" }, \"cursor\"),\n j(\"rect\", { width: 18, height: 18, x: 3, y: 3, rx: 2, ry: 2 }, \"frame\"),\n ]);\n}\n\nfunction lucideIcon(j: RowJsx, s: RowJsxs, name: string, children: ReturnType<RowJsx>[]) {\n return s(\"svg\", {\n \"aria-hidden\": \"true\",\n className: `lucide lucide-${name} size-3.5`,\n fill: \"none\",\n height: 24,\n stroke: \"currentColor\",\n strokeLinecap: \"round\",\n strokeLinejoin: \"round\",\n strokeWidth: 2,\n viewBox: \"0 0 24 24\",\n width: 24,\n children,\n });\n}\n\nfunction sandboxRowTitle(item: SandboxItem, displayName: (name: string) => string): string {\n if (item.name === \"sandbox.provision\") {\n return startupPhaseTitle(\n \"sandbox\",\n item.status === \"cancelled\" ? \"complete\" : item.status,\n item.origin ?? null,\n );\n }\n return displayName(item.name);\n}\n\nfunction startupPhaseTitle(\n phase: StartupPhaseItem[\"phase\"],\n status: StartupPhaseItem[\"status\"],\n outcome: StartupPhaseItem[\"outcome\"],\n): string {\n if (status === \"complete\" && phase === \"sandbox\" && outcome && outcome !== \"skipped\") {\n return `Sandbox ${outcome === \"resumed\" ? \"reattached\" : outcome}`;\n }\n if (status === \"complete\" && phase === \"rig\" && outcome === \"skipped\") {\n return \"Rig already ready\";\n }\n const statusIndex =\n status === \"running\" ? 0 : status === \"failed\" ? 1 : status === \"cancelled\" ? 2 : 3;\n return STARTUP_PHASE_TITLES[phase][statusIndex];\n}\n\nconst STARTUP_PHASE_TITLES: Record<\n StartupPhaseItem[\"phase\"],\n readonly [string, string, string, string]\n> = {\n queue: [\n \"Waiting for a worker\",\n \"Worker startup failed\",\n \"Worker wait interrupted\",\n \"Worker started\",\n ],\n sandbox: [\n \"Starting sandbox\",\n \"Sandbox didn’t start\",\n \"Sandbox startup interrupted\",\n \"Sandbox ready\",\n ],\n rig: [\"Setting up rig\", \"Rig setup failed\", \"Rig setup interrupted\", \"Rig ready\"],\n repository: [\n \"Preparing repository\",\n \"Repository preparation failed\",\n \"Repository preparation interrupted\",\n \"Repository ready\",\n ],\n files: [\n \"Preparing files\",\n \"File preparation failed\",\n \"File preparation interrupted\",\n \"Files ready\",\n ],\n tools: [\n \"Connecting tools\",\n \"Tool connection failed\",\n \"Tool connection interrupted\",\n \"Tools ready\",\n ],\n model_preparation: [\n \"Preparing runtime and model request\",\n \"Runtime/model preparation failed\",\n \"Runtime/model preparation interrupted\",\n \"Model request dispatched\",\n ],\n provider_first_byte: [\n \"Waiting for model\",\n \"Model didn’t respond\",\n \"Model wait interrupted\",\n \"Model started responding\",\n ],\n};\n\nfunction startupDuration(durationMs: number | null): string | null {\n if (durationMs === null || !Number.isFinite(durationMs) || durationMs < 0) return null;\n if (durationMs < 1_000) return `${Math.round(durationMs)}ms`;\n if (durationMs < 60_000) return `${(durationMs / 1_000).toFixed(1)}s`;\n const minutes = Math.floor(durationMs / 60_000);\n const seconds = Math.round((durationMs % 60_000) / 1_000);\n return `${minutes}m ${String(seconds).padStart(2, \"0\")}s`;\n}\n"],"mappings":"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","names":[]}
@@ -16,21 +16,22 @@ import {
16
16
  setStartupDetails,
17
17
  useStartupDetails,
18
18
  userMessageLikelyNeedsDisclosure
19
- } from "./chunk-WS6D5BHH.js";
19
+ } from "./chunk-QXJCNVSD.js";
20
20
  import "./chunk-YBM6CQRU.js";
21
21
  import "./chunk-5M6VTFJ5.js";
22
22
  import "./chunk-ZYRGEKWS.js";
23
23
  import "./chunk-NOSYBS2D.js";
24
24
  import "./chunk-PAJU5KKL.js";
25
- import "./chunk-M2HNWZYR.js";
25
+ import "./chunk-IHQII5WO.js";
26
26
  import "./chunk-JVYQRRC4.js";
27
27
  import "./chunk-45XEUVTK.js";
28
28
  import "./chunk-HQV2I5HV.js";
29
+ import "./chunk-2TKI3WEG.js";
29
30
  import "./chunk-R4KRSFGA.js";
30
31
  import "./chunk-VZTQ73XT.js";
31
32
  import {
32
33
  createOlderHistoryLoadReceipt
33
- } from "./chunk-HUMIRRYI.js";
34
+ } from "./chunk-IYCR4343.js";
34
35
  import "./chunk-NYESIADM.js";
35
36
  import "./chunk-PLYRL5ER.js";
36
37
  import "./chunk-KZ73RL76.js";
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/timeline/startup-timings.tsx"],"sourcesContent":["import type { StartupPhaseItem } from \"./types\";\n\nconst LABELS: Record<StartupPhaseItem[\"phase\"], string> = {\n queue: \"Worker queue\",\n sandbox: \"Sandbox\",\n rig: \"Rig\",\n repository: \"Repository\",\n files: \"Files\",\n tools: \"Tools\",\n model_preparation: \"Runtime & model request\",\n provider_first_byte: \"First model response\",\n};\n\nexport function StartupTimings({ phases }: { phases: StartupPhaseItem[] }) {\n if (!phases.length)\n return <p className=\"text-og-sm text-og-fg-subtle\">No startup timings recorded yet.</p>;\n const byTurn = new Map<string | null, StartupPhaseItem[]>();\n for (const phase of phases) {\n const group = byTurn.get(phase.turnId) ?? [];\n group.push(phase);\n byTurn.set(phase.turnId, group);\n }\n const turns = [...byTurn.entries()]\n .map(([turnId, turnPhases]) => ({\n turnId,\n phases: turnPhases,\n startedAt: turnPhases.reduce(\n (earliest, phase) => (phase.startedAt < earliest ? phase.startedAt : earliest),\n turnPhases[0]!.startedAt,\n ),\n }))\n .sort((a, b) => b.startedAt.localeCompare(a.startedAt));\n return (\n <div className=\"space-y-3\">\n <p className=\"text-og-xs text-og-fg-subtle\">\n Each turn has its own startup. Phases can overlap; durations are not additive.\n </p>\n {turns.map((turn, index) => (\n <StartupTurn\n key={turn.turnId ?? \"unassigned\"}\n {...turn}\n latest={index === 0 && turn.turnId !== null}\n />\n ))}\n </div>\n );\n}\n\nfunction StartupTurn({\n turnId,\n phases,\n startedAt,\n latest,\n}: {\n turnId: string | null;\n phases: StartupPhaseItem[];\n startedAt: string;\n latest: boolean;\n}) {\n const status = phases.some((phase) => phase.status === \"failed\")\n ? \"Failed\"\n : phases.some((phase) => phase.status === \"running\")\n ? \"In progress\"\n : phases.some((phase) => phase.status === \"cancelled\")\n ? \"Interrupted\"\n : \"Ready\";\n return (\n <details open={latest} className=\"group border-b border-og-border pb-3\">\n <summary className=\"cursor-pointer rounded py-3 text-og-sm text-og-fg-muted focus-visible:outline-2 focus-visible:outline-og-accent\">\n <span className=\"font-medium\">\n {turnId === null ? \"Unassigned events\" : latest ? \"Latest turn\" : \"Earlier turn\"}\n </span>\n <span className=\"ml-2 text-og-xs text-og-fg-subtle\">\n {new Date(startedAt).toLocaleTimeString([], {\n hour: \"2-digit\",\n minute: \"2-digit\",\n second: \"2-digit\",\n })}\n </span>\n <span\n className={\n status === \"Failed\"\n ? \"ml-2 text-og-xs text-og-status-failed\"\n : \"ml-2 text-og-xs text-og-fg-subtle\"\n }\n >\n {status}\n </span>\n <span className=\"mt-1 block break-all pl-4 font-og-mono text-og-xs text-og-fg-subtle\">\n {turnId ?? \"No turn ID recorded\"}\n </span>\n </summary>\n <div className=\"pb-2\">\n <p className=\"text-og-xs text-og-fg-subtle\">\n Started <time dateTime={startedAt}>{new Date(startedAt).toLocaleString()}</time>\n </p>\n <div className=\"overflow-x-auto\">\n <table className=\"w-full text-left text-og-xs\">\n <caption className=\"sr-only\">\n Startup phases for {turnId ?? \"unassigned events\"}\n </caption>\n <thead>\n <tr className=\"border-b border-og-border text-og-fg-subtle\">\n <th scope=\"col\" className=\"py-2 font-medium\">\n Phase\n </th>\n <th scope=\"col\" className=\"px-3 py-2 font-medium\">\n Status\n </th>\n <th scope=\"col\" className=\"py-2 text-right font-medium\">\n Duration\n </th>\n </tr>\n </thead>\n <tbody>\n {phases.map((phase) => (\n <tr\n key={phase.id}\n className=\"border-b border-og-border/40\"\n title={`Turn: ${phase.turnId ?? \"unknown\"} · Started: ${phase.startedAt}`}\n >\n <th scope=\"row\" className=\"py-2.5 font-normal text-og-fg-muted\">\n {LABELS[phase.phase]}\n </th>\n <td\n className={`px-3 py-2.5 ${phase.status === \"failed\" ? \"text-og-status-failed\" : \"text-og-fg-subtle\"}`}\n >\n {phase.status === \"running\" ? \"In progress\" : phase.status}\n </td>\n <td className=\"py-2.5 text-right font-og-mono tabular-nums text-og-fg-muted\">\n {phase.durationMs === null\n ? \"—\"\n : phase.durationMs < 1000\n ? `${Math.round(phase.durationMs)} ms`\n : `${(phase.durationMs / 1000).toFixed(1)} s`}\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n </div>\n </details>\n );\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/timeline/startup-timings.tsx"],"sourcesContent":["import type { StartupPhaseItem } from \"./types\";\n\nconst LABELS: Record<StartupPhaseItem[\"phase\"], string> = {\n queue: \"Worker queue\",\n sandbox: \"Sandbox\",\n rig: \"Rig\",\n repository: \"Repository\",\n files: \"Files\",\n tools: \"Tools\",\n model_preparation: \"Runtime & model request\",\n provider_first_byte: \"First model response\",\n};\n\nexport function StartupTimings({ phases }: { phases: StartupPhaseItem[] }) {\n if (!phases.length)\n return <p className=\"text-og-sm text-og-fg-subtle\">No startup timings recorded yet.</p>;\n const byTurn = new Map<string | null, StartupPhaseItem[]>();\n for (const phase of phases) {\n const group = byTurn.get(phase.turnId) ?? [];\n group.push(phase);\n byTurn.set(phase.turnId, group);\n }\n const turns = [...byTurn.entries()]\n .map(([turnId, turnPhases]) => ({\n turnId,\n phases: turnPhases,\n startedAt: turnPhases.reduce(\n (earliest, phase) => (phase.startedAt < earliest ? phase.startedAt : earliest),\n turnPhases[0]!.startedAt,\n ),\n }))\n .sort((a, b) => b.startedAt.localeCompare(a.startedAt));\n return (\n <div className=\"space-y-3\">\n <p className=\"text-og-xs text-og-fg-subtle\">\n Each turn has its own startup. Phases can overlap; durations are not additive.\n </p>\n {turns.map((turn, index) => (\n <StartupTurn\n key={turn.turnId ?? \"unassigned\"}\n {...turn}\n latest={index === 0 && turn.turnId !== null}\n />\n ))}\n </div>\n );\n}\n\nfunction StartupTurn({\n turnId,\n phases,\n startedAt,\n latest,\n}: {\n turnId: string | null;\n phases: StartupPhaseItem[];\n startedAt: string;\n latest: boolean;\n}) {\n const status = phases.some((phase) => phase.status === \"failed\")\n ? \"Failed\"\n : phases.some((phase) => phase.status === \"running\")\n ? \"In progress\"\n : phases.some((phase) => phase.status === \"cancelled\")\n ? \"Interrupted\"\n : \"Ready\";\n return (\n <details open={latest} className=\"group border-b border-og-border pb-3\">\n <summary className=\"cursor-pointer rounded py-3 text-og-sm text-og-fg-muted focus-visible:outline-2 focus-visible:outline-og-accent\">\n <span className=\"font-medium\">\n {turnId === null ? \"Unassigned events\" : latest ? \"Latest turn\" : \"Earlier turn\"}\n </span>\n <span className=\"ml-2 text-og-xs text-og-fg-subtle\">\n {new Date(startedAt).toLocaleTimeString([], {\n hour: \"2-digit\",\n minute: \"2-digit\",\n second: \"2-digit\",\n })}\n </span>\n <span\n className={\n status === \"Failed\"\n ? \"ml-2 text-og-xs text-og-status-failed\"\n : \"ml-2 text-og-xs text-og-fg-subtle\"\n }\n >\n {status}\n </span>\n <span className=\"mt-1 block break-all pl-4 font-og-mono text-og-xs text-og-fg-subtle\">\n {turnId ?? \"No turn ID recorded\"}\n </span>\n </summary>\n <div className=\"pb-2\">\n <p className=\"text-og-xs text-og-fg-subtle\">\n Started <time dateTime={startedAt}>{new Date(startedAt).toLocaleString()}</time>\n </p>\n <div className=\"overflow-x-auto\">\n <table className=\"w-full text-left text-og-xs\">\n <caption className=\"sr-only\">\n Startup phases for {turnId ?? \"unassigned events\"}\n </caption>\n <thead>\n <tr className=\"border-b border-og-border text-og-fg-subtle\">\n <th scope=\"col\" className=\"py-2 font-medium\">\n Phase\n </th>\n <th scope=\"col\" className=\"px-3 py-2 font-medium\">\n Status\n </th>\n <th scope=\"col\" className=\"py-2 text-right font-medium\">\n Duration\n </th>\n </tr>\n </thead>\n <tbody>\n {phases.map((phase) => (\n <tr\n key={phase.id}\n className=\"border-b border-og-border/40\"\n title={`Turn: ${phase.turnId ?? \"unknown\"} · Started: ${phase.startedAt}`}\n >\n <th scope=\"row\" className=\"py-2.5 font-normal text-og-fg-muted\">\n {LABELS[phase.phase]}\n </th>\n <td\n className={`px-3 py-2.5 ${phase.status === \"failed\" ? \"text-og-status-failed\" : \"text-og-fg-subtle\"}`}\n >\n {phase.status === \"running\" ? \"In progress\" : phase.status}\n </td>\n <td className=\"py-2.5 text-right font-og-mono tabular-nums text-og-fg-muted\">\n {phase.durationMs === null\n ? \"—\"\n : phase.durationMs < 1000\n ? `${Math.round(phase.durationMs)} ms`\n : `${(phase.durationMs / 1000).toFixed(1)} s`}\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n </div>\n </details>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAeW,cAkBP,YAlBO;AAbX,IAAM,SAAoD;AAAA,EACxD,OAAO;AAAA,EACP,SAAS;AAAA,EACT,KAAK;AAAA,EACL,YAAY;AAAA,EACZ,OAAO;AAAA,EACP,OAAO;AAAA,EACP,mBAAmB;AAAA,EACnB,qBAAqB;AACvB;AAEO,SAAS,eAAe,EAAE,OAAO,GAAmC;AACzE,MAAI,CAAC,OAAO;AACV,WAAO,oBAAC,OAAE,WAAU,gCAA+B,8CAAgC;AACrF,QAAM,SAAS,oBAAI,IAAuC;AAC1D,aAAW,SAAS,QAAQ;AAC1B,UAAM,QAAQ,OAAO,IAAI,MAAM,MAAM,KAAK,CAAC;AAC3C,UAAM,KAAK,KAAK;AAChB,WAAO,IAAI,MAAM,QAAQ,KAAK;AAAA,EAChC;AACA,QAAM,QAAQ,CAAC,GAAG,OAAO,QAAQ,CAAC,EAC/B,IAAI,CAAC,CAAC,QAAQ,UAAU,OAAO;AAAA,IAC9B;AAAA,IACA,QAAQ;AAAA,IACR,WAAW,WAAW;AAAA,MACpB,CAAC,UAAU,UAAW,MAAM,YAAY,WAAW,MAAM,YAAY;AAAA,MACrE,WAAW,CAAC,EAAG;AAAA,IACjB;AAAA,EACF,EAAE,EACD,KAAK,CAAC,GAAG,MAAM,EAAE,UAAU,cAAc,EAAE,SAAS,CAAC;AACxD,SACE,qBAAC,SAAI,WAAU,aACb;AAAA,wBAAC,OAAE,WAAU,gCAA+B,4FAE5C;AAAA,IACC,MAAM,IAAI,CAAC,MAAM,UAChB;AAAA,MAAC;AAAA;AAAA,QAEE,GAAG;AAAA,QACJ,QAAQ,UAAU,KAAK,KAAK,WAAW;AAAA;AAAA,MAFlC,KAAK,UAAU;AAAA,IAGtB,CACD;AAAA,KACH;AAEJ;AAEA,SAAS,YAAY;AAAA,EACnB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAKG;AACD,QAAM,SAAS,OAAO,KAAK,CAAC,UAAU,MAAM,WAAW,QAAQ,IAC3D,WACA,OAAO,KAAK,CAAC,UAAU,MAAM,WAAW,SAAS,IAC/C,gBACA,OAAO,KAAK,CAAC,UAAU,MAAM,WAAW,WAAW,IACjD,gBACA;AACR,SACE,qBAAC,aAAQ,MAAM,QAAQ,WAAU,wCAC/B;AAAA,yBAAC,aAAQ,WAAU,mHACjB;AAAA,0BAAC,UAAK,WAAU,eACb,qBAAW,OAAO,sBAAsB,SAAS,gBAAgB,gBACpE;AAAA,MACA,oBAAC,UAAK,WAAU,qCACb,cAAI,KAAK,SAAS,EAAE,mBAAmB,CAAC,GAAG;AAAA,QAC1C,MAAM;AAAA,QACN,QAAQ;AAAA,QACR,QAAQ;AAAA,MACV,CAAC,GACH;AAAA,MACA;AAAA,QAAC;AAAA;AAAA,UACC,WACE,WAAW,WACP,0CACA;AAAA,UAGL;AAAA;AAAA,MACH;AAAA,MACA,oBAAC,UAAK,WAAU,uEACb,oBAAU,uBACb;AAAA,OACF;AAAA,IACA,qBAAC,SAAI,WAAU,QACb;AAAA,2BAAC,OAAE,WAAU,gCAA+B;AAAA;AAAA,QAClC,oBAAC,UAAK,UAAU,WAAY,cAAI,KAAK,SAAS,EAAE,eAAe,GAAE;AAAA,SAC3E;AAAA,MACA,oBAAC,SAAI,WAAU,mBACb,+BAAC,WAAM,WAAU,+BACf;AAAA,6BAAC,aAAQ,WAAU,WAAU;AAAA;AAAA,UACP,UAAU;AAAA,WAChC;AAAA,QACA,oBAAC,WACC,+BAAC,QAAG,WAAU,+CACZ;AAAA,8BAAC,QAAG,OAAM,OAAM,WAAU,oBAAmB,mBAE7C;AAAA,UACA,oBAAC,QAAG,OAAM,OAAM,WAAU,yBAAwB,oBAElD;AAAA,UACA,oBAAC,QAAG,OAAM,OAAM,WAAU,+BAA8B,sBAExD;AAAA,WACF,GACF;AAAA,QACA,oBAAC,WACE,iBAAO,IAAI,CAAC,UACX;AAAA,UAAC;AAAA;AAAA,YAEC,WAAU;AAAA,YACV,OAAO,SAAS,MAAM,UAAU,SAAS,kBAAe,MAAM,SAAS;AAAA,YAEvE;AAAA,kCAAC,QAAG,OAAM,OAAM,WAAU,uCACvB,iBAAO,MAAM,KAAK,GACrB;AAAA,cACA;AAAA,gBAAC;AAAA;AAAA,kBACC,WAAW,eAAe,MAAM,WAAW,WAAW,0BAA0B,mBAAmB;AAAA,kBAElG,gBAAM,WAAW,YAAY,gBAAgB,MAAM;AAAA;AAAA,cACtD;AAAA,cACA,oBAAC,QAAG,WAAU,gEACX,gBAAM,eAAe,OAClB,WACA,MAAM,aAAa,MACjB,GAAG,KAAK,MAAM,MAAM,UAAU,CAAC,QAC/B,IAAI,MAAM,aAAa,KAAM,QAAQ,CAAC,CAAC,MAC/C;AAAA;AAAA;AAAA,UAlBK,MAAM;AAAA,QAmBb,CACD,GACH;AAAA,SACF,GACF;AAAA,OACF;AAAA,KACF;AAEJ;","names":[]}
package/dist/session.js CHANGED
@@ -28,7 +28,7 @@ import {
28
28
  useSession,
29
29
  useSessionEvents,
30
30
  useTurnQueue
31
- } from "./chunk-HUMIRRYI.js";
31
+ } from "./chunk-IYCR4343.js";
32
32
  import {
33
33
  FILE_ONLY_MESSAGE_TEXT,
34
34
  composeSendInput,
@@ -11,9 +11,10 @@ type SiteScope = {
11
11
  };
12
12
  /** Shared native/embedded read boundary: pin content to the observed version,
13
13
  * and never accept a response belonging to another workspace or Site. */
14
- export declare function loadSiteSnapshot(client: Pick<SiteClient, "getWorkspaceArtifact" | "getWorkspaceArtifactHtml">, workspaceId: string, siteId: string, options?: {
14
+ export declare function loadSiteSnapshot(client: Pick<SiteClient, "getWorkspaceArtifact" | "getWorkspaceArtifactHtml"> & Partial<Pick<OpenGeniClient, "getWorkspaceArtifactContent">>, workspaceId: string, siteId: string, options?: {
15
15
  signal?: AbortSignal;
16
16
  includeArchivedContent?: boolean;
17
+ versionId?: string;
17
18
  }): Promise<{
18
19
  detail: WorkspaceArtifactDetailResponse;
19
20
  content: SiteDisplayContent | null;
package/dist/sites.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  PublishedHtmlArtifactFrame
3
- } from "./chunk-BRFMGY4L.js";
3
+ } from "./chunk-UGMKPUEM.js";
4
4
 
5
5
  // src/sites-ui.tsx
6
6
  import { useEffect, useRef, useState } from "react";
@@ -11,16 +11,24 @@ async function loadSiteSnapshot(client, workspaceId, siteId, options = {}) {
11
11
  options.signal?.throwIfAborted();
12
12
  if (detail.artifact.id !== siteId || detail.artifact.workspaceId !== workspaceId)
13
13
  throw new Error("Site scope mismatch");
14
- const versionId = detail.artifact.currentVersion?.id;
15
- const content = versionId && (detail.artifact.status === "active" || options.includeArchivedContent) ? {
14
+ const selectedVersion = options.versionId ? detail.versions.find((version) => version.id === options.versionId) : detail.artifact.currentVersion;
15
+ const versionId = options.versionId ?? selectedVersion?.id;
16
+ let content = selectedVersion && versionId && (detail.artifact.status === "active" || options.includeArchivedContent) ? {
16
17
  artifactId: siteId,
17
18
  versionId,
18
- requestedTools: detail.artifact.currentVersion.requestedTools,
19
+ requestedTools: selectedVersion.requestedTools,
19
20
  html: await client.getWorkspaceArtifactHtml(workspaceId, siteId, {
20
21
  ...requestOptions,
21
22
  versionId
22
23
  })
23
24
  } : null;
25
+ if (versionId && !selectedVersion && (detail.artifact.status === "active" || options.includeArchivedContent)) {
26
+ if (!client.getWorkspaceArtifactContent) throw new Error("Site version unavailable");
27
+ content = await client.getWorkspaceArtifactContent(workspaceId, siteId, {
28
+ ...requestOptions,
29
+ versionId
30
+ });
31
+ }
24
32
  options.signal?.throwIfAborted();
25
33
  if (content && (content.artifactId !== siteId || content.versionId !== versionId))
26
34
  throw new Error("Site content mismatch");
package/dist/sites.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/sites-ui.tsx"],"sourcesContent":["import { useEffect, useRef, useState } from \"react\";\nimport type {\n OpenGeniClient,\n WorkspaceArtifact,\n WorkspaceArtifactContentResponse,\n WorkspaceArtifactDetailResponse,\n WorkspaceArtifactListResponse,\n} from \"@opengeni/sdk\";\nimport {\n PublishedHtmlArtifactFrame,\n type PublishedHtmlArtifactToolBridge,\n} from \"./components/artifacts/published-html-artifact-frame\";\n\n/** Implement with an authenticated host proxy. Never put an organization key\n * in browser props; replace the client object when the host actor changes. */\nexport type SiteClient = Pick<\n OpenGeniClient,\n | \"listWorkspaceArtifacts\"\n | \"getWorkspaceArtifact\"\n | \"getWorkspaceArtifactHtml\"\n | \"rollbackWorkspaceArtifact\"\n | \"setWorkspaceArtifactStatus\"\n>;\ntype SiteDisplayContent = Pick<\n WorkspaceArtifactContentResponse,\n \"artifactId\" | \"versionId\" | \"html\" | \"requestedTools\"\n>;\ntype SiteScope = { client: SiteClient; workspaceId: string; className?: string };\n/** Shared native/embedded read boundary: pin content to the observed version,\n * and never accept a response belonging to another workspace or Site. */\nexport async function loadSiteSnapshot(\n client: Pick<SiteClient, \"getWorkspaceArtifact\" | \"getWorkspaceArtifactHtml\">,\n workspaceId: string,\n siteId: string,\n options: { signal?: AbortSignal; includeArchivedContent?: boolean } = {},\n): Promise<{\n detail: WorkspaceArtifactDetailResponse;\n content: SiteDisplayContent | null;\n}> {\n const requestOptions = options.signal ? { signal: options.signal } : {};\n const detail = await client.getWorkspaceArtifact(workspaceId, siteId, requestOptions);\n options.signal?.throwIfAborted();\n if (detail.artifact.id !== siteId || detail.artifact.workspaceId !== workspaceId)\n throw new Error(\"Site scope mismatch\");\n const versionId = detail.artifact.currentVersion?.id;\n const content =\n versionId && (detail.artifact.status === \"active\" || options.includeArchivedContent)\n ? {\n artifactId: siteId,\n versionId,\n requestedTools: detail.artifact.currentVersion!.requestedTools,\n html: await client.getWorkspaceArtifactHtml(workspaceId, siteId, {\n ...requestOptions,\n versionId,\n }),\n }\n : null;\n options.signal?.throwIfAborted();\n if (content && (content.artifactId !== siteId || content.versionId !== versionId))\n throw new Error(\"Site content mismatch\");\n return { detail: structuredClone(detail), content: content ? structuredClone(content) : null };\n}\nexport type SiteListProps = SiteScope & {\n status?: \"active\" | \"archived\";\n onOpen: (site: WorkspaceArtifact) => void;\n};\nexport type SiteDetailProps = SiteScope & {\n siteId: string;\n /** Presentation hint only: the backend still enforces artifacts:publish. */\n canPublish?: boolean;\n toolBridge?: PublishedHtmlArtifactToolBridge;\n};\n\nfunction useScopeKey(values: readonly unknown[]) {\n const [scope, setScope] = useState(values);\n const [generation, setGeneration] = useState(0);\n if (values.some((value, index) => value !== scope[index])) {\n setScope(values);\n setGeneration(generation + 1);\n }\n return generation;\n}\n\nexport function SiteList(props: SiteListProps) {\n const key = useScopeKey([props.client, props.workspaceId, props.status]);\n return <ScopedSiteList key={key} {...props} />;\n}\nfunction ScopedSiteList({\n client,\n workspaceId,\n status = \"active\",\n onOpen,\n className,\n}: SiteListProps) {\n const [page, setPage] = useState<WorkspaceArtifactListResponse | null>(null);\n const [cursor, setCursor] = useState<string | undefined>();\n const [error, setError] = useState(false);\n const [reload, setReload] = useState(0);\n useEffect(() => {\n const abort = new AbortController();\n setPage(null);\n setError(false);\n void Promise.resolve()\n .then(() =>\n client.listWorkspaceArtifacts(workspaceId, {\n status,\n ...(cursor ? { cursor } : {}),\n limit: 50,\n signal: abort.signal,\n }),\n )\n .then((result) => {\n if (!abort.signal.aborted) setPage(structuredClone(result));\n })\n .catch(() => {\n if (!abort.signal.aborted) setError(true);\n });\n return () => abort.abort();\n }, [client, workspaceId, status, cursor, reload]);\n return (\n <section className={className} aria-label=\"Sites\" aria-busy={!page && !error}>\n {error ? (\n <p role=\"alert\">Sites are unavailable or access has changed. Refresh to check access.</p>\n ) : !page ? (\n <p role=\"status\">Loading Sites…</p>\n ) : page.artifacts.length === 0 ? (\n <p role=\"status\">No {status} Sites.</p>\n ) : (\n <ul>\n {page.artifacts.map((site) => (\n <li key={site.id}>\n <button type=\"button\" onClick={() => onOpen(structuredClone(site))}>\n {site.title}\n </button>\n <p>{site.description}</p>\n <span>\n {site.status} · revision {site.currentVersion?.revision ?? \"unpublished\"}\n </span>\n </li>\n ))}\n </ul>\n )}\n {page?.nextCursor && (\n <button type=\"button\" onClick={() => setCursor(page.nextCursor!)}>\n Next page\n </button>\n )}\n {cursor && (\n <button type=\"button\" onClick={() => setCursor(undefined)}>\n First page\n </button>\n )}\n <button type=\"button\" onClick={() => setReload((value) => value + 1)}>\n Refresh Sites\n </button>\n </section>\n );\n}\n\nexport function SiteDetail(props: SiteDetailProps) {\n const key = useScopeKey([props.client, props.workspaceId, props.siteId]);\n return <ScopedSiteDetail key={key} {...props} />;\n}\nfunction ScopedSiteDetail({\n client,\n workspaceId,\n siteId,\n canPublish = false,\n toolBridge,\n className,\n}: SiteDetailProps) {\n const [loaded, setLoaded] = useState<{\n detail: WorkspaceArtifactDetailResponse;\n content: SiteDisplayContent | null;\n } | null>(null);\n const [error, setError] = useState(false);\n const [reload, setReload] = useState(0);\n const [busy, setBusy] = useState(false);\n const [rollbackId, setRollbackId] = useState(\"\");\n const [confirmation, setConfirmation] = useState<\"status\" | \"rollback\" | null>(null);\n const mutation = useRef<AbortController | null>(null);\n useEffect(() => () => mutation.current?.abort(), []);\n useEffect(() => {\n const abort = new AbortController();\n setLoaded(null);\n setError(false);\n setConfirmation(null);\n setRollbackId(\"\");\n void Promise.resolve()\n .then(async () => {\n const snapshot = await loadSiteSnapshot(client, workspaceId, siteId, {\n signal: abort.signal,\n });\n if (!abort.signal.aborted) setLoaded(snapshot);\n })\n .catch(() => {\n if (!abort.signal.aborted) {\n setLoaded(null);\n setError(true);\n }\n });\n return () => abort.abort();\n }, [client, workspaceId, siteId, reload]);\n // Recheck live read authority without rebuilding the iframe on every tick.\n // No overlapping polls, and failures remove the document and tool bridge.\n useEffect(() => {\n if (!loaded || busy) return;\n const abort = new AbortController();\n let checking = false;\n const timer = setInterval(() => {\n if (checking) return;\n checking = true;\n void Promise.resolve()\n .then(() => client.getWorkspaceArtifact(workspaceId, siteId, { signal: abort.signal }))\n .then((detail) => {\n if (abort.signal.aborted) return;\n if (detail.artifact.id !== siteId || detail.artifact.workspaceId !== workspaceId)\n throw new Error(\"Site scope mismatch\");\n if (\n detail.artifact.currentVersion?.id !== loaded.detail.artifact.currentVersion?.id ||\n detail.artifact.status !== loaded.detail.artifact.status\n ) {\n setLoaded(null);\n setReload((value) => value + 1);\n }\n })\n .catch(() => {\n if (!abort.signal.aborted) {\n setLoaded(null);\n setError(true);\n }\n })\n .finally(() => {\n checking = false;\n });\n }, 15_000);\n return () => {\n abort.abort();\n clearInterval(timer);\n };\n }, [client, workspaceId, siteId, loaded, busy]);\n const commit = async () => {\n const current = loaded?.detail.artifact.currentVersion;\n if (!canPublish || !loaded || !current || !confirmation || mutation.current) return;\n const abort = new AbortController();\n mutation.current = abort;\n setBusy(true);\n try {\n const common = { expectedCurrentVersionId: current.id, idempotencyKey: crypto.randomUUID() };\n if (confirmation === \"rollback\") {\n if (!loaded.detail.versions.some((version) => version.id === rollbackId))\n throw new Error(\"Unknown version\");\n await client.rollbackWorkspaceArtifact(\n workspaceId,\n siteId,\n { ...common, versionId: rollbackId, reason: \"Restore explicitly selected Site version\" },\n { signal: abort.signal },\n );\n } else {\n await client.setWorkspaceArtifactStatus(\n workspaceId,\n siteId,\n {\n ...common,\n status: loaded.detail.artifact.status === \"active\" ? \"archived\" : \"active\",\n reason: \"Explicit Site status change\",\n },\n { signal: abort.signal },\n );\n }\n if (!abort.signal.aborted) {\n setLoaded(null);\n setReload((value) => value + 1);\n }\n } catch {\n if (!abort.signal.aborted) {\n setLoaded(null);\n setError(true);\n }\n } finally {\n if (!abort.signal.aborted) {\n mutation.current = null;\n setBusy(false);\n setConfirmation(null);\n }\n }\n };\n const site = loaded?.detail.artifact;\n return (\n <section\n className={className}\n aria-label=\"Site details\"\n aria-busy={busy || (!loaded && !error)}\n >\n {error && (\n <p role=\"alert\">\n Site state could not be confirmed or access has changed. Refresh before continuing.\n </p>\n )}\n {!loaded && !error && <p role=\"status\">Loading Site…</p>}\n {site && (\n <>\n <h2>{site.title}</h2>\n <p>{site.description}</p>\n <p>\n {site.status} · revision {site.currentVersion?.revision ?? \"unpublished\"}\n </p>\n {loaded.content && (\n <PublishedHtmlArtifactFrame\n html={loaded.content.html}\n title={site.title}\n {...(toolBridge ? { toolBridge } : {})}\n />\n )}\n <h3>Versions</h3>\n <ul>\n {loaded.detail.versions.map((version) => (\n <li key={version.id}>\n Revision {version.revision} · {version.createdAt}\n {version.id === site.currentVersion?.id ? \" · current\" : \"\"}\n </li>\n ))}\n </ul>\n {loaded.detail.versionsTruncated && (\n <p>Older versions are not included in this response.</p>\n )}\n {canPublish && site.currentVersion && (\n <fieldset disabled={busy}>\n <legend>Manage Site</legend>\n <button type=\"button\" onClick={() => setConfirmation(\"status\")}>\n {site.status === \"active\" ? \"Archive Site\" : \"Restore Site\"}\n </button>\n <label>\n Version to restore\n <select\n value={rollbackId}\n onChange={(event) => {\n setRollbackId(event.target.value);\n setConfirmation(null);\n }}\n >\n <option value=\"\">Choose a version</option>\n {loaded.detail.versions\n .filter((version) => version.id !== site.currentVersion?.id)\n .map((version) => (\n <option key={version.id} value={version.id}>\n Revision {version.revision}\n </option>\n ))}\n </select>\n </label>\n <button\n type=\"button\"\n disabled={!rollbackId}\n onClick={() => setConfirmation(\"rollback\")}\n >\n Review rollback\n </button>\n {confirmation && (\n <div role=\"group\" aria-label=\"Confirm Site change\">\n <p>\n {confirmation === \"rollback\"\n ? \"Make the selected version current?\"\n : site.status === \"active\"\n ? \"Archive this Site for workspace users?\"\n : \"Restore this Site for workspace users?\"}\n </p>\n <button type=\"button\" onClick={() => void commit()}>\n Confirm change\n </button>\n <button type=\"button\" onClick={() => setConfirmation(null)}>\n Keep current state\n </button>\n </div>\n )}\n </fieldset>\n )}\n </>\n )}\n <button type=\"button\" disabled={busy} onClick={() => setReload((value) => value + 1)}>\n Refresh Site\n </button>\n </section>\n );\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/sites-ui.tsx"],"sourcesContent":["import { useEffect, useRef, useState } from \"react\";\nimport type {\n OpenGeniClient,\n WorkspaceArtifact,\n WorkspaceArtifactContentResponse,\n WorkspaceArtifactDetailResponse,\n WorkspaceArtifactListResponse,\n} from \"@opengeni/sdk\";\nimport {\n PublishedHtmlArtifactFrame,\n type PublishedHtmlArtifactToolBridge,\n} from \"./components/artifacts/published-html-artifact-frame\";\n\n/** Implement with an authenticated host proxy. Never put an organization key\n * in browser props; replace the client object when the host actor changes. */\nexport type SiteClient = Pick<\n OpenGeniClient,\n | \"listWorkspaceArtifacts\"\n | \"getWorkspaceArtifact\"\n | \"getWorkspaceArtifactHtml\"\n | \"rollbackWorkspaceArtifact\"\n | \"setWorkspaceArtifactStatus\"\n>;\ntype SiteDisplayContent = Pick<\n WorkspaceArtifactContentResponse,\n \"artifactId\" | \"versionId\" | \"html\" | \"requestedTools\"\n>;\ntype SiteScope = { client: SiteClient; workspaceId: string; className?: string };\n/** Shared native/embedded read boundary: pin content to the observed version,\n * and never accept a response belonging to another workspace or Site. */\nexport async function loadSiteSnapshot(\n client: Pick<SiteClient, \"getWorkspaceArtifact\" | \"getWorkspaceArtifactHtml\"> &\n Partial<Pick<OpenGeniClient, \"getWorkspaceArtifactContent\">>,\n workspaceId: string,\n siteId: string,\n options: { signal?: AbortSignal; includeArchivedContent?: boolean; versionId?: string } = {},\n): Promise<{\n detail: WorkspaceArtifactDetailResponse;\n content: SiteDisplayContent | null;\n}> {\n const requestOptions = options.signal ? { signal: options.signal } : {};\n const detail = await client.getWorkspaceArtifact(workspaceId, siteId, requestOptions);\n options.signal?.throwIfAborted();\n if (detail.artifact.id !== siteId || detail.artifact.workspaceId !== workspaceId)\n throw new Error(\"Site scope mismatch\");\n const selectedVersion = options.versionId\n ? detail.versions.find((version) => version.id === options.versionId)\n : detail.artifact.currentVersion;\n const versionId = options.versionId ?? selectedVersion?.id;\n let content: SiteDisplayContent | null =\n selectedVersion &&\n versionId &&\n (detail.artifact.status === \"active\" || options.includeArchivedContent)\n ? {\n artifactId: siteId,\n versionId,\n requestedTools: selectedVersion!.requestedTools,\n html: await client.getWorkspaceArtifactHtml(workspaceId, siteId, {\n ...requestOptions,\n versionId,\n }),\n }\n : null;\n if (\n versionId &&\n !selectedVersion &&\n (detail.artifact.status === \"active\" || options.includeArchivedContent)\n ) {\n if (!client.getWorkspaceArtifactContent) throw new Error(\"Site version unavailable\");\n content = await client.getWorkspaceArtifactContent(workspaceId, siteId, {\n ...requestOptions,\n versionId,\n });\n }\n options.signal?.throwIfAborted();\n if (content && (content.artifactId !== siteId || content.versionId !== versionId))\n throw new Error(\"Site content mismatch\");\n return { detail: structuredClone(detail), content: content ? structuredClone(content) : null };\n}\nexport type SiteListProps = SiteScope & {\n status?: \"active\" | \"archived\";\n onOpen: (site: WorkspaceArtifact) => void;\n};\nexport type SiteDetailProps = SiteScope & {\n siteId: string;\n /** Presentation hint only: the backend still enforces artifacts:publish. */\n canPublish?: boolean;\n toolBridge?: PublishedHtmlArtifactToolBridge;\n};\n\nfunction useScopeKey(values: readonly unknown[]) {\n const [scope, setScope] = useState(values);\n const [generation, setGeneration] = useState(0);\n if (values.some((value, index) => value !== scope[index])) {\n setScope(values);\n setGeneration(generation + 1);\n }\n return generation;\n}\n\nexport function SiteList(props: SiteListProps) {\n const key = useScopeKey([props.client, props.workspaceId, props.status]);\n return <ScopedSiteList key={key} {...props} />;\n}\nfunction ScopedSiteList({\n client,\n workspaceId,\n status = \"active\",\n onOpen,\n className,\n}: SiteListProps) {\n const [page, setPage] = useState<WorkspaceArtifactListResponse | null>(null);\n const [cursor, setCursor] = useState<string | undefined>();\n const [error, setError] = useState(false);\n const [reload, setReload] = useState(0);\n useEffect(() => {\n const abort = new AbortController();\n setPage(null);\n setError(false);\n void Promise.resolve()\n .then(() =>\n client.listWorkspaceArtifacts(workspaceId, {\n status,\n ...(cursor ? { cursor } : {}),\n limit: 50,\n signal: abort.signal,\n }),\n )\n .then((result) => {\n if (!abort.signal.aborted) setPage(structuredClone(result));\n })\n .catch(() => {\n if (!abort.signal.aborted) setError(true);\n });\n return () => abort.abort();\n }, [client, workspaceId, status, cursor, reload]);\n return (\n <section className={className} aria-label=\"Sites\" aria-busy={!page && !error}>\n {error ? (\n <p role=\"alert\">Sites are unavailable or access has changed. Refresh to check access.</p>\n ) : !page ? (\n <p role=\"status\">Loading Sites…</p>\n ) : page.artifacts.length === 0 ? (\n <p role=\"status\">No {status} Sites.</p>\n ) : (\n <ul>\n {page.artifacts.map((site) => (\n <li key={site.id}>\n <button type=\"button\" onClick={() => onOpen(structuredClone(site))}>\n {site.title}\n </button>\n <p>{site.description}</p>\n <span>\n {site.status} · revision {site.currentVersion?.revision ?? \"unpublished\"}\n </span>\n </li>\n ))}\n </ul>\n )}\n {page?.nextCursor && (\n <button type=\"button\" onClick={() => setCursor(page.nextCursor!)}>\n Next page\n </button>\n )}\n {cursor && (\n <button type=\"button\" onClick={() => setCursor(undefined)}>\n First page\n </button>\n )}\n <button type=\"button\" onClick={() => setReload((value) => value + 1)}>\n Refresh Sites\n </button>\n </section>\n );\n}\n\nexport function SiteDetail(props: SiteDetailProps) {\n const key = useScopeKey([props.client, props.workspaceId, props.siteId]);\n return <ScopedSiteDetail key={key} {...props} />;\n}\nfunction ScopedSiteDetail({\n client,\n workspaceId,\n siteId,\n canPublish = false,\n toolBridge,\n className,\n}: SiteDetailProps) {\n const [loaded, setLoaded] = useState<{\n detail: WorkspaceArtifactDetailResponse;\n content: SiteDisplayContent | null;\n } | null>(null);\n const [error, setError] = useState(false);\n const [reload, setReload] = useState(0);\n const [busy, setBusy] = useState(false);\n const [rollbackId, setRollbackId] = useState(\"\");\n const [confirmation, setConfirmation] = useState<\"status\" | \"rollback\" | null>(null);\n const mutation = useRef<AbortController | null>(null);\n useEffect(() => () => mutation.current?.abort(), []);\n useEffect(() => {\n const abort = new AbortController();\n setLoaded(null);\n setError(false);\n setConfirmation(null);\n setRollbackId(\"\");\n void Promise.resolve()\n .then(async () => {\n const snapshot = await loadSiteSnapshot(client, workspaceId, siteId, {\n signal: abort.signal,\n });\n if (!abort.signal.aborted) setLoaded(snapshot);\n })\n .catch(() => {\n if (!abort.signal.aborted) {\n setLoaded(null);\n setError(true);\n }\n });\n return () => abort.abort();\n }, [client, workspaceId, siteId, reload]);\n // Recheck live read authority without rebuilding the iframe on every tick.\n // No overlapping polls, and failures remove the document and tool bridge.\n useEffect(() => {\n if (!loaded || busy) return;\n const abort = new AbortController();\n let checking = false;\n const timer = setInterval(() => {\n if (checking) return;\n checking = true;\n void Promise.resolve()\n .then(() => client.getWorkspaceArtifact(workspaceId, siteId, { signal: abort.signal }))\n .then((detail) => {\n if (abort.signal.aborted) return;\n if (detail.artifact.id !== siteId || detail.artifact.workspaceId !== workspaceId)\n throw new Error(\"Site scope mismatch\");\n if (\n detail.artifact.currentVersion?.id !== loaded.detail.artifact.currentVersion?.id ||\n detail.artifact.status !== loaded.detail.artifact.status\n ) {\n setLoaded(null);\n setReload((value) => value + 1);\n }\n })\n .catch(() => {\n if (!abort.signal.aborted) {\n setLoaded(null);\n setError(true);\n }\n })\n .finally(() => {\n checking = false;\n });\n }, 15_000);\n return () => {\n abort.abort();\n clearInterval(timer);\n };\n }, [client, workspaceId, siteId, loaded, busy]);\n const commit = async () => {\n const current = loaded?.detail.artifact.currentVersion;\n if (!canPublish || !loaded || !current || !confirmation || mutation.current) return;\n const abort = new AbortController();\n mutation.current = abort;\n setBusy(true);\n try {\n const common = { expectedCurrentVersionId: current.id, idempotencyKey: crypto.randomUUID() };\n if (confirmation === \"rollback\") {\n if (!loaded.detail.versions.some((version) => version.id === rollbackId))\n throw new Error(\"Unknown version\");\n await client.rollbackWorkspaceArtifact(\n workspaceId,\n siteId,\n { ...common, versionId: rollbackId, reason: \"Restore explicitly selected Site version\" },\n { signal: abort.signal },\n );\n } else {\n await client.setWorkspaceArtifactStatus(\n workspaceId,\n siteId,\n {\n ...common,\n status: loaded.detail.artifact.status === \"active\" ? \"archived\" : \"active\",\n reason: \"Explicit Site status change\",\n },\n { signal: abort.signal },\n );\n }\n if (!abort.signal.aborted) {\n setLoaded(null);\n setReload((value) => value + 1);\n }\n } catch {\n if (!abort.signal.aborted) {\n setLoaded(null);\n setError(true);\n }\n } finally {\n if (!abort.signal.aborted) {\n mutation.current = null;\n setBusy(false);\n setConfirmation(null);\n }\n }\n };\n const site = loaded?.detail.artifact;\n return (\n <section\n className={className}\n aria-label=\"Site details\"\n aria-busy={busy || (!loaded && !error)}\n >\n {error && (\n <p role=\"alert\">\n Site state could not be confirmed or access has changed. Refresh before continuing.\n </p>\n )}\n {!loaded && !error && <p role=\"status\">Loading Site…</p>}\n {site && (\n <>\n <h2>{site.title}</h2>\n <p>{site.description}</p>\n <p>\n {site.status} · revision {site.currentVersion?.revision ?? \"unpublished\"}\n </p>\n {loaded.content && (\n <PublishedHtmlArtifactFrame\n html={loaded.content.html}\n title={site.title}\n {...(toolBridge ? { toolBridge } : {})}\n />\n )}\n <h3>Versions</h3>\n <ul>\n {loaded.detail.versions.map((version) => (\n <li key={version.id}>\n Revision {version.revision} · {version.createdAt}\n {version.id === site.currentVersion?.id ? \" · current\" : \"\"}\n </li>\n ))}\n </ul>\n {loaded.detail.versionsTruncated && (\n <p>Older versions are not included in this response.</p>\n )}\n {canPublish && site.currentVersion && (\n <fieldset disabled={busy}>\n <legend>Manage Site</legend>\n <button type=\"button\" onClick={() => setConfirmation(\"status\")}>\n {site.status === \"active\" ? \"Archive Site\" : \"Restore Site\"}\n </button>\n <label>\n Version to restore\n <select\n value={rollbackId}\n onChange={(event) => {\n setRollbackId(event.target.value);\n setConfirmation(null);\n }}\n >\n <option value=\"\">Choose a version</option>\n {loaded.detail.versions\n .filter((version) => version.id !== site.currentVersion?.id)\n .map((version) => (\n <option key={version.id} value={version.id}>\n Revision {version.revision}\n </option>\n ))}\n </select>\n </label>\n <button\n type=\"button\"\n disabled={!rollbackId}\n onClick={() => setConfirmation(\"rollback\")}\n >\n Review rollback\n </button>\n {confirmation && (\n <div role=\"group\" aria-label=\"Confirm Site change\">\n <p>\n {confirmation === \"rollback\"\n ? \"Make the selected version current?\"\n : site.status === \"active\"\n ? \"Archive this Site for workspace users?\"\n : \"Restore this Site for workspace users?\"}\n </p>\n <button type=\"button\" onClick={() => void commit()}>\n Confirm change\n </button>\n <button type=\"button\" onClick={() => setConfirmation(null)}>\n Keep current state\n </button>\n </div>\n )}\n </fieldset>\n )}\n </>\n )}\n <button type=\"button\" disabled={busy} onClick={() => setReload((value) => value + 1)}>\n Refresh Site\n </button>\n </section>\n );\n}\n"],"mappings":"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","names":[]}
@@ -22,3 +22,4 @@ export type ActivityRailProps = {
22
22
  className?: string | undefined;
23
23
  };
24
24
  export declare function ActivityRail({ items, startupActive, toolRegistry, onOpenSession, onMemoryClick, loadRetainedScreenshot, loadRetainedArtifact, bare, className, }: ActivityRailProps): import("react").JSX.Element;
25
+ export declare function renderActivity(item: ActivityItem, toolRegistry: ToolRegistry, onOpenSession: ((sessionId: string) => void) | undefined, onMemoryClick: ((memoryId: string) => void) | undefined, loadRetainedScreenshot: RetainedScreenshotLoader | undefined, loadRetainedArtifact: RetainedArtifactLoader | undefined): import("react").JSX.Element;
@@ -1,7 +1,7 @@
1
1
  import type { ReasoningItem, SandboxItem, StartupPhaseItem } from "./types.js";
2
2
  type RowJsx = typeof import("react/jsx-runtime").jsx;
3
3
  type RowJsxs = typeof import("react/jsx-runtime").jsxs;
4
- export default function PlatformActivityRow({ item, d: ActivityDisclosure, p: PayloadBlock, t: displayName, b: BotIcon, m: Markdown, r: truncate, j, s, }: {
4
+ export default function PlatformActivityRow({ item, d: ActivityDisclosure, p: PayloadBlock, t: displayName, b: BotIcon, m: Markdown, j, s, }: {
5
5
  item: ReasoningItem | SandboxItem | StartupPhaseItem;
6
6
  d: typeof import("./shared.js").ActivityDisclosure;
7
7
  p: typeof import("./shared.js").PayloadBlock;
@@ -0,0 +1,16 @@
1
+ import type { RetainedArtifactReference } from "@opengeni/sdk";
2
+ import type { ToolRendererProps } from "./registry.js";
3
+ type RetainedImageState = {
4
+ kind: "loading";
5
+ } | {
6
+ kind: "ready";
7
+ url: string;
8
+ } | {
9
+ kind: "unavailable";
10
+ label: string;
11
+ } | {
12
+ kind: "error";
13
+ message: string;
14
+ };
15
+ export declare function useRetainedImageObjectUrl(artifact: RetainedArtifactReference, load: ToolRendererProps["loadRetainedArtifact"]): RetainedImageState;
16
+ export {};
@@ -0,0 +1,9 @@
1
+ import type { ToolRegistry } from "./registry.js";
2
+ import type { ActivityItem } from "./types.js";
3
+ /** One stable viewport; updates replace its content without moving the conversation. */
4
+ export declare function RollingActivity({ items, toolRegistry, previousItem, }: {
5
+ items: ActivityItem[];
6
+ /** The standalone item visible immediately before this reel mounted. */
7
+ previousItem?: ActivityItem | undefined;
8
+ toolRegistry?: ToolRegistry;
9
+ }): import("react").JSX.Element | null;
@@ -14,6 +14,8 @@ export declare function ToolCallTruncationProvider({ value, children, }: {
14
14
  children: ReactNode;
15
15
  }): import("react").JSX.Element;
16
16
  export type ActivityDisclosureProps = {
17
+ /** Override the rolling preview; null keeps rapidly streaming details out of the header. */
18
+ compactPreview?: ReactNode;
17
19
  icon: ReactNode;
18
20
  /** Icon tint. Defaults to the muted foreground; renderers pass accent/failed. */
19
21
  iconTone?: "accent" | "failed" | "running" | "muted" | undefined;
@@ -67,7 +69,8 @@ export type ActivityDisclosureProps = {
67
69
  * inline media, and at most one right-gutter settle chip. Compact by default;
68
70
  * the body mounts only when expanded.
69
71
  */
70
- export declare function ActivityDisclosure({ icon, iconTone: iconToneProp, title, titleMono, running, preview, media, chip: chipProp, failed, cancelled, expandable, defaultOpen, children, }: ActivityDisclosureProps): import("react").JSX.Element;
72
+ export declare const CompactActivityContext: import("react").Context<boolean>;
73
+ export declare function ActivityDisclosure({ icon, iconTone: iconToneProp, title, titleMono, running, preview, compactPreview, media, chip: chipProp, failed, cancelled, expandable, defaultOpen, children, }: ActivityDisclosureProps): import("react").JSX.Element;
71
74
  export declare function TermBlock({ command, workdir, output, live, tailLines, failed, }: {
72
75
  /**
73
76
  * The command shown in the prompt header. Pass `null` when the row title
@@ -56,6 +56,8 @@ type ReplaceTurnSummaryFacets = Readonly<{
56
56
  }>;
57
57
  export type TurnSummaryFacetConfiguration = ModifyTurnSummaryFacets | ReplaceTurnSummaryFacets;
58
58
  export type TurnSummaryOptions = Readonly<{
59
+ /** Experimental compact live activity reel. */
60
+ rolling?: boolean;
59
61
  facets?: TurnSummaryFacetConfiguration;
60
62
  }>;
61
63
  export type TurnSummaryProps = {
@@ -73,6 +75,7 @@ export type TurnSummaryProps = {
73
75
  durationMs?: number | undefined;
74
76
  /** Start expanded. */
75
77
  defaultOpen?: boolean | undefined;
78
+ liveHeader?: ReactNode;
76
79
  /**
77
80
  * A nested fold — a cluster or sub-turn INSIDE an already-expanded turn. It
78
81
  * drops the bordered/filled chip and renders as a plain disclosure node on the
@@ -113,4 +116,4 @@ export type TurnSummaryProps = {
113
116
  /** The rendered activity rail revealed on expand. */
114
117
  children: ReactNode;
115
118
  };
116
- export declare function TurnSummary({ items, outcome, failureText, durationMs, defaultOpen, bare, facets: facetConfiguration, settleFold, foldKey, copyText, contextCompactionCount, children, }: TurnSummaryProps): import("react").JSX.Element;
119
+ export declare function TurnSummary({ items, outcome, failureText, durationMs, defaultOpen, liveHeader, bare, facets: facetConfiguration, settleFold, foldKey, copyText, contextCompactionCount, children, }: TurnSummaryProps): import("react").JSX.Element;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opengeni/react",
3
- "version": "5.1.0-canary.0",
3
+ "version": "5.2.0-canary.0",
4
4
  "description": "React hooks and styled components for OpenGeni: live session streaming, chat composer, message timeline, session status, and fleet views — token-themed (CSS variables), dark-first, built on Tailwind v4 + Radix + Motion.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -118,7 +118,7 @@
118
118
  },
119
119
  "scripts": {
120
120
  "typecheck": "tsc --noEmit",
121
- "build": "bun run build:css && bun ../../scripts/build-typescript-package.ts",
121
+ "build": "bun run build:css && bun ../../scripts/generate-visualization-assets.ts && bun ../../scripts/build-typescript-package.ts",
122
122
  "build:css": "bun scripts/build-compiled-css.ts",
123
123
  "check:css": "bun scripts/build-compiled-css.ts --check",
124
124
  "demo": "vite dev demo --port 3100",
@@ -133,8 +133,8 @@
133
133
  "@dnd-kit/utilities": "3.2.2",
134
134
  "@fontsource-variable/noto-sans-arabic": "5.2.10",
135
135
  "@fontsource-variable/noto-sans-jp": "5.2.10",
136
- "@opengeni/connect": "^0.2.0-canary.6",
137
- "@opengeni/sdk": "^5.1.0-canary.0",
136
+ "@opengeni/connect": "^0.2.0-canary.7",
137
+ "@opengeni/sdk": "^5.1.0-canary.1",
138
138
  "clsx": "^2.1.1",
139
139
  "dequal": "2.0.3",
140
140
  "lucide-react": "^1.8.0",
package/src/artifacts.ts CHANGED
@@ -1,3 +1,5 @@
1
+ export { inlineHtmlDocument } from "./components/artifacts/inline-html-document";
2
+ export { useRetainedImageObjectUrl } from "./timeline/retained-image";
1
3
  /** Public artifact surfaces. Import from `@opengeni/react/artifacts`. */
2
4
  export {
3
5
  ArtifactSurface,
@@ -0,0 +1,24 @@
1
+ import { VISUALIZATION_CSS, VISUALIZATION_HELPERS } from "./visualization-assets.gen";
2
+
3
+ /** Conversation styling/helpers only. Rendering and tool transport remain in the Site frame. */
4
+ export function inlineHtmlDocument(fragment: string): string {
5
+ return (
6
+ '<!doctype html><html><head><meta name="viewport" content="width=device-width,initial-scale=1"><style>' +
7
+ VISUALIZATION_CSS +
8
+ "</style><style>html,body{margin:0;min-height:0}body{padding:16px;box-sizing:border-box}</style></head><body>" +
9
+ fragment +
10
+ VISUALIZATION_HELPERS +
11
+ `<script>
12
+ (()=>{
13
+ window.addEventListener('message',event=>{
14
+ if(event.source!==parent||event.data?.type!=='opengeni.preview.theme')return;
15
+ if(event.data.theme==='light'||event.data.theme==='dark')document.documentElement.style.colorScheme=event.data.theme;
16
+ previous=0;resize();
17
+ });
18
+ let previous=0;
19
+ const resize=()=>{const height=Math.ceil(document.body.getBoundingClientRect().height);if(height!==previous){previous=height;parent.postMessage({type:'opengeni.preview.height',height},'*')}};
20
+ new ResizeObserver(resize).observe(document.body);resize();
21
+ })();
22
+ </script></body></html>`
23
+ );
24
+ }
@@ -18,7 +18,8 @@ import type {
18
18
  ToolGatewayCallResponse,
19
19
  ToolGatewayDeclarationsResponse,
20
20
  } from "@opengeni/sdk";
21
- import { useEffect, useRef, type CSSProperties } from "react";
21
+ import { useEffect, useRef, useState, type CSSProperties } from "react";
22
+ import { resolveSiteClientScript } from "@opengeni/sdk/site-document";
22
23
 
23
24
  export const PUBLISHED_HTML_ARTIFACT_IFRAME_SANDBOX = [
24
25
  "allow-downloads",
@@ -34,6 +35,8 @@ export const PUBLISHED_HTML_ARTIFACT_IFRAME_SANDBOX = [
34
35
 
35
36
  export type PublishedHtmlArtifactFrameProps = {
36
37
  html: string;
38
+ autoHeight?: boolean;
39
+ theme?: "light" | "dark";
37
40
  title: string;
38
41
  className?: string;
39
42
  style?: CSSProperties;
@@ -58,6 +61,7 @@ const SITE_BRIDGE_BOOTSTRAP_SCRIPT = `<script>(()=>{const key=${JSON.stringify(
58
61
 
59
62
  export function publishedHtmlArtifactDocument(html: string, toolBridgeEnabled: boolean): string {
60
63
  if (!toolBridgeEnabled) return html;
64
+ html = resolveSiteClientScript(html);
61
65
  const doctypeEnd = leadingDoctypeEnd(html);
62
66
  if (doctypeEnd >= 0) {
63
67
  return `${html.slice(0, doctypeEnd + 1)}${SITE_BRIDGE_BOOTSTRAP_SCRIPT}${html.slice(doctypeEnd + 1)}`;
@@ -87,6 +91,28 @@ function leadingDoctypeEnd(html: string): number {
87
91
  */
88
92
  export function PublishedHtmlArtifactFrame(props: PublishedHtmlArtifactFrameProps) {
89
93
  const frameRef = useRef<HTMLIFrameElement | null>(null);
94
+ const [height, setHeight] = useState<number>();
95
+ useEffect(() => {
96
+ if (!props.autoHeight) return;
97
+ const receive = (event: MessageEvent) => {
98
+ if (
99
+ event.source !== frameRef.current?.contentWindow ||
100
+ event.data?.type !== "opengeni.preview.height"
101
+ )
102
+ return;
103
+ const value = event.data.height;
104
+ if (typeof value === "number" && Number.isFinite(value))
105
+ setHeight(Math.min(1200, Math.max(80, value)));
106
+ };
107
+ window.addEventListener("message", receive);
108
+ return () => window.removeEventListener("message", receive);
109
+ }, [props.autoHeight]);
110
+ useEffect(() => {
111
+ frameRef.current?.contentWindow?.postMessage(
112
+ { type: "opengeni.preview.theme", theme: props.theme },
113
+ "*",
114
+ );
115
+ }, [props.theme]);
90
116
  const bridgeRef = useRef(props.toolBridge);
91
117
  const onFrameLoadRef = useRef<() => void>(() => undefined);
92
118
  const frameLoadPendingRef = useRef(false);
@@ -198,11 +224,15 @@ export function PublishedHtmlArtifactFrame(props: PublishedHtmlArtifactFrameProp
198
224
  referrerPolicy="no-referrer"
199
225
  srcDoc={publishedHtmlArtifactDocument(props.html, toolBridgeEnabled)}
200
226
  onLoad={() => {
227
+ frameRef.current?.contentWindow?.postMessage(
228
+ { type: "opengeni.preview.theme", theme: props.theme },
229
+ "*",
230
+ );
201
231
  frameLoadPendingRef.current = true;
202
232
  onFrameLoadRef.current();
203
233
  }}
204
234
  className={props.className}
205
- style={props.style}
235
+ style={{ ...props.style, ...(props.autoHeight && height ? { height } : {}) }}
206
236
  />
207
237
  );
208
238
  }