From 8299c9da49760097a8ea8c04e9a04452d6ae41da Mon Sep 17 00:00:00 2001 From: Aadesh Kheria Date: Wed, 6 May 2026 13:54:11 -0700 Subject: [PATCH 1/3] initial commit --- .../dashboards/[dashboardId]/page-client.tsx | 2 +- .../dashboard-sandbox-host.tsx | 119 ++++++++++++++---- 2 files changed, 96 insertions(+), 25 deletions(-) diff --git a/apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/dashboards/[dashboardId]/page-client.tsx b/apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/dashboards/[dashboardId]/page-client.tsx index 17ad8f25bb..333fc15fac 100644 --- a/apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/dashboards/[dashboardId]/page-client.tsx +++ b/apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/dashboards/[dashboardId]/page-client.tsx @@ -391,7 +391,7 @@ function DashboardDetailContent({ {/* Both panels are always in the DOM so the iframe never unmounts/reloads. The chat panel animates its width; the dashboard panel adjusts via flex-1. */} -
+
{/* Dashboard iframe panel */}
((result, str, i) => result + str + (values[i] ?? ''), ''); } - const isDev = process.env.NODE_ENV === "development"; +function getEsmFallbackVersion(version: string): string { + const parts = version.split("."); + const [major, minor, patchString] = parts; + const patch = Number(patchString); + return `${major}.${minor}.${patch - 1}`; +} + function getDependencyScripts(esmVersion: string, esmFallbackVersion: string, dashboardUrl: string): string { if (isDev) { return html` `; @@ -72,6 +98,30 @@ function getDependencyScripts(esmVersion: string, esmFallbackVersion: string, da return html` `; } @@ -118,7 +174,7 @@ function getSandboxDocument(artifact: DashboardArtifact, baseUrl: string, dashbo const sourceCode = escapeScriptContent(artifact.runtimeCodegen.uiRuntimeSourceCode); const darkClass = initialTheme === "dark" ? "dark" : ""; const esmVersion = packageJson.version; - const esmFallbackVersion = "2.8.71"; + const esmFallbackVersion = getEsmFallbackVersion(esmVersion); const devScriptSrc = isDev ? ` ${dashboardUrl}` : ''; const devConnectSrc = isDev ? ` ${dashboardUrl}` : ''; @@ -307,10 +363,18 @@ function getSandboxDocument(artifact: DashboardArtifact, baseUrl: string, dashbo }; async function waitForDeps() { - if (window.__depsReady) return; - await new Promise(resolve => { - window.addEventListener('deps-ready', resolve, { once: true }); - }); + if (!window.__depsReady) { + await new Promise(resolve => { + window.addEventListener('deps-ready', resolve, { once: true }); + }); + } + if (window.__depsError) { + const error = new Error(window.__depsError.message || 'There was a problem loading custom dashboards. Please refresh the page and try again.'); + if (window.__depsError.stack) { + error.stack = window.__depsError.stack; + } + throw error; + } } async function requestAccessToken() { @@ -735,6 +799,13 @@ export const DashboardSandboxHost = memo(function DashboardSandboxHost({ return; } + if (type === "dashboard-sandbox-dependency-error") { + const err = new Error(event.data.message ?? 'Unknown custom dashboard dependency error'); + if (event.data.stack) err.stack = event.data.stack; + captureError('dashboard-sandbox-dependency-error', err); + return; + } + if (type === "dashboard-error-boundary") { const err = new Error(event.data.message ?? 'Unknown dashboard error'); if (event.data.stack) err.stack = event.data.stack; From ec9ad36bf5d78361c1ba721d905990bc8ea71e81 Mon Sep 17 00:00:00 2001 From: Aadesh Kheria Date: Wed, 6 May 2026 15:18:41 -0700 Subject: [PATCH 2/3] Enhance version fallback logic in dashboard sandbox host --- .../commands/create-dashboard/dashboard-sandbox-host.tsx | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/apps/dashboard/src/components/commands/create-dashboard/dashboard-sandbox-host.tsx b/apps/dashboard/src/components/commands/create-dashboard/dashboard-sandbox-host.tsx index f538d69252..f2312cbdb6 100644 --- a/apps/dashboard/src/components/commands/create-dashboard/dashboard-sandbox-host.tsx +++ b/apps/dashboard/src/components/commands/create-dashboard/dashboard-sandbox-host.tsx @@ -22,9 +22,10 @@ const isDev = process.env.NODE_ENV === "development"; function getEsmFallbackVersion(version: string): string { const parts = version.split("."); - const [major, minor, patchString] = parts; - const patch = Number(patchString); - return `${major}.${minor}.${patch - 1}`; + if (parts.length !== 3) return version; + const patch = Number(parts[2]); + if (!Number.isInteger(patch) || patch <= 0) return version; + return `${parts[0]}.${parts[1]}.${patch - 1}`; } function getDependencyScripts(esmVersion: string, esmFallbackVersion: string, dashboardUrl: string): string { From 7e2db741529dba0a6c3fb7ef284d70eb9a01d723 Mon Sep 17 00:00:00 2001 From: Aadesh Kheria Date: Mon, 11 May 2026 10:38:38 -0700 Subject: [PATCH 3/3] Implement ESM version stamping in dashboard components --- .../dashboards/[dashboardId]/page-client.tsx | 10 ++++++---- .../create-dashboard-preview.tsx | 8 +++++--- .../create-dashboard/dashboard-sandbox-host.tsx | 17 ++++++++++++++++- 3 files changed, 27 insertions(+), 8 deletions(-) diff --git a/apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/dashboards/[dashboardId]/page-client.tsx b/apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/dashboards/[dashboardId]/page-client.tsx index 333fc15fac..dfcc3f76b8 100644 --- a/apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/dashboards/[dashboardId]/page-client.tsx +++ b/apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/dashboards/[dashboardId]/page-client.tsx @@ -1,7 +1,8 @@ "use client"; -import { DashboardSandboxHost, type DashboardRuntimeError, type WidgetSelection } from "@/components/commands/create-dashboard/dashboard-sandbox-host"; +import { DashboardSandboxHost, stampEsmVersion, type DashboardRuntimeError, type WidgetSelection } from "@/components/commands/create-dashboard/dashboard-sandbox-host"; +import packageJson from "../../../../../../../../package.json"; import { useRouter, useRouterConfirm } from "@/components/router"; import { StreamingCodeViewer } from "@/components/streaming-code-viewer"; import { ActionDialog, Button, Typography, useToast } from "@/components/ui"; @@ -239,8 +240,9 @@ function DashboardDetailContent({ const handleCodeUpdate = useCallback((toolCall: ToolCallContent) => { if (typeof toolCall.args.content === "string") { - setPendingCode(toolCall.args.content); - setCurrentTsxSource(toolCall.args.content); + const stamped = stampEsmVersion(toolCall.args.content, packageJson.version); + setPendingCode(stamped); + setCurrentTsxSource(stamped); clearTimeout(codePhaseTimerRef.current); setCodePhase("typing"); codePhaseTimerRef.current = setTimeout(() => { @@ -450,7 +452,7 @@ function DashboardDetailContent({ } + toolComponents={ setCurrentTsxSource(stampEsmVersion(code, packageJson.version))} currentCode={currentTsxSource} />} useOffWhiteLightMode composerPlaceholder={currentHasSource ? undefined : DASHBOARD_COMPOSER_PLACEHOLDER} runningStatusMessages={!isCreating ? UPDATE_STATUS_MESSAGES : undefined} diff --git a/apps/dashboard/src/components/commands/create-dashboard/create-dashboard-preview.tsx b/apps/dashboard/src/components/commands/create-dashboard/create-dashboard-preview.tsx index 6691a3bf4e..aa75b67d12 100644 --- a/apps/dashboard/src/components/commands/create-dashboard/create-dashboard-preview.tsx +++ b/apps/dashboard/src/components/commands/create-dashboard/create-dashboard-preview.tsx @@ -21,8 +21,9 @@ import { useChat, type UIMessage } from "@ai-sdk/react"; import { convertToModelMessages, DefaultChatTransport } from "ai"; import { memo, useCallback, useMemo, useRef, useState } from "react"; import { CmdKPreviewProps } from "../../cmdk-commands"; -import { DashboardSandboxHost } from "./dashboard-sandbox-host"; +import { DashboardSandboxHost, stampEsmVersion } from "./dashboard-sandbox-host"; import { StreamingCodeViewer } from "../../streaming-code-viewer"; +import packageJson from "../../../../package.json"; type DashboardArtifact = { prompt: string, @@ -176,18 +177,19 @@ const CreateDashboardPreviewInner = memo(function CreateDashboardPreviewInner({ phase = "idle"; } - const displayCode = toolPart?.code ?? ""; + const displayCode = toolPart?.code ? stampEsmVersion(toolPart.code, packageJson.version) : ""; if (toolPart?.state === "input-available" && !artifact && !finalizedRef.current) { finalizedRef.current = true; const sanitized = sanitizeGeneratedCode(toolPart.code); + const stamped = stampEsmVersion(sanitized, packageJson.version); setArtifact({ prompt, projectId, runtimeCodegen: { title: prompt.slice(0, 120), description: "", - uiRuntimeSourceCode: sanitized, + uiRuntimeSourceCode: stamped, }, }); setIframeReady(false); diff --git a/apps/dashboard/src/components/commands/create-dashboard/dashboard-sandbox-host.tsx b/apps/dashboard/src/components/commands/create-dashboard/dashboard-sandbox-host.tsx index f2312cbdb6..f0b9cee996 100644 --- a/apps/dashboard/src/components/commands/create-dashboard/dashboard-sandbox-host.tsx +++ b/apps/dashboard/src/components/commands/create-dashboard/dashboard-sandbox-host.tsx @@ -28,6 +28,21 @@ function getEsmFallbackVersion(version: string): string { return `${parts[0]}.${parts[1]}.${patch - 1}`; } +const ESM_VERSION_HEADER = "// @stack-esm-version:"; +const ESM_VERSION_REGEX = /^\/\/\s*@stack-esm-version:\s*(\S+)\s*$/m; + +function extractEsmVersion(sourceCode: string): string | null { + const match = sourceCode.match(ESM_VERSION_REGEX); + return match ? match[1] : null; +} + +export function stampEsmVersion(sourceCode: string, version: string): string { + if (ESM_VERSION_REGEX.test(sourceCode)) { + return sourceCode.replace(ESM_VERSION_REGEX, `${ESM_VERSION_HEADER} ${version}`); + } + return `${ESM_VERSION_HEADER} ${version}\n${sourceCode}`; +} + function getDependencyScripts(esmVersion: string, esmFallbackVersion: string, dashboardUrl: string): string { if (isDev) { return html` @@ -174,7 +189,7 @@ function escapeScriptContent(code: string): string { function getSandboxDocument(artifact: DashboardArtifact, baseUrl: string, dashboardUrl: string, initialTheme: "light" | "dark", showControls: boolean, initialChatOpen: boolean): string { const sourceCode = escapeScriptContent(artifact.runtimeCodegen.uiRuntimeSourceCode); const darkClass = initialTheme === "dark" ? "dark" : ""; - const esmVersion = packageJson.version; + const esmVersion = extractEsmVersion(artifact.runtimeCodegen.uiRuntimeSourceCode) ?? packageJson.version; const esmFallbackVersion = getEsmFallbackVersion(esmVersion); const devScriptSrc = isDev ? ` ${dashboardUrl}` : ''; const devConnectSrc = isDev ? ` ${dashboardUrl}` : '';