@tangle-network/sandbox-ui 0.115.0 → 0.115.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -44,7 +44,7 @@ Use `EmbeddedAppView` when a workspace presents a running web app beside an agen
44
44
  Render it in a container with a defined height.
45
45
 
46
46
  ```tsx
47
- import { EmbeddedAppView } from "@tangle-network/sandbox-ui/workbench"
47
+ import { EmbeddedAppView } from "@tangle-network/sandbox-ui/workbench/embedded-app"
48
48
 
49
49
  <main className="h-full min-h-0">
50
50
  <EmbeddedAppView
@@ -372,6 +372,7 @@ Retheming is absolutely supported, but the documentation was thinner than it sho
372
372
  | `/workspace` | SandboxWorkbench, WorkspaceLayout, DirectoryPane, RuntimePane, StatusBar |
373
373
  | `/openui` | OpenUIArtifactRenderer and schema types for structured artifact rendering |
374
374
  | `/files` | FileTree, FilePreview, FileTabs, FileArtifactPane |
375
+ | `/workbench/embedded-app` | EmbeddedAppView and preview status types without terminal or editor modules |
375
376
  | `/dashboard` | [Sidebar](./docs/sidebar.md), DashboardLayout, BillingDashboard, UsageChart, ProfileSelector |
376
377
  | `/editor` | TipTap collaborative editor (requires optional peers) |
377
378
  | `/terminal` | xterm.js terminal view (requires optional peers) |
@@ -0,0 +1,55 @@
1
+ import * as React$1 from "react";
2
+ //#region src/workbench/preview-policy.d.ts
3
+ type PreviewReadiness = {
4
+ state: "unknown";
5
+ } | {
6
+ state: "checking";
7
+ } | {
8
+ state: "ready";
9
+ checkedAt: string;
10
+ statusCode: number;
11
+ } | {
12
+ state: "failed";
13
+ checkedAt: string;
14
+ message: string;
15
+ };
16
+ type PreviewAccess = {
17
+ state: "unknown";
18
+ } | {
19
+ state: "public" | "authenticated";
20
+ source: "enforced-policy";
21
+ expiresAt?: string;
22
+ };
23
+ //#endregion
24
+ //#region src/workbench/embedded-app-view.d.ts
25
+ interface EmbeddedApp {
26
+ /** Stable app identity. The host uses it to preserve selection across updates. */
27
+ id: string;
28
+ name: string;
29
+ /** Resolved, credential-free sandbox preview URL. */
30
+ previewUrl?: string;
31
+ /** The host supplies this state from its application or preview service. */
32
+ status: "starting" | "ready" | "unavailable";
33
+ statusMessage?: string;
34
+ }
35
+ interface EmbeddedAppViewProps {
36
+ app: EmbeddedApp;
37
+ /** Product-approved origins, obtained independently of the app URL. */
38
+ allowedOrigins?: readonly string[];
39
+ /** Service-observed HTTP result. Never derive it from iframe load. */
40
+ readiness?: PreviewReadiness;
41
+ /** Enforced access policy, supplied by the host service. */
42
+ access?: PreviewAccess;
43
+ /** Product actions beside the app name in the ready preview header. */
44
+ toolbarActions?: React$1.ReactNode;
45
+ /** Recheck or restart the preview through the host's own service. */
46
+ onRetry?: () => void;
47
+ className?: string;
48
+ }
49
+ /**
50
+ * An app-sized preview surface for a product workspace.
51
+ * The host owns app discovery, persistence, access policy, and readiness checks.
52
+ */
53
+ declare function EmbeddedAppView({ app, allowedOrigins, readiness, access, toolbarActions, onRetry, className }: EmbeddedAppViewProps): React$1.JSX.Element;
54
+ //#endregion
55
+ export { PreviewReadiness as a, PreviewAccess as i, EmbeddedAppView as n, EmbeddedAppViewProps as r, EmbeddedApp as t };
@@ -0,0 +1,342 @@
1
+ import { t as cn$1 } from "./utils-DzWbktWG.js";
2
+ import { Button } from "@tangle-network/ui/primitives";
3
+ import { jsx, jsxs } from "react/jsx-runtime";
4
+ import * as React$1 from "react";
5
+ import { focusField } from "@tangle-network/ui/utils";
6
+ import { ExternalLink, RotateCw } from "lucide-react";
7
+ //#region src/workbench/preview-policy.ts
8
+ /** Only an actual verified HTTP outcome can establish application readiness. */
9
+ function previewReadinessLabel(readiness) {
10
+ if (readiness?.state === "checking") return "Checking application readiness";
11
+ if (readiness?.state === "failed") return "Application check failed";
12
+ if (readiness?.state === "ready" && Number.isFinite(Date.parse(readiness.checkedAt)) && Number.isInteger(readiness.statusCode) && readiness.statusCode >= 200 && readiness.statusCode < 400) return `Application responded: HTTP ${readiness.statusCode}`;
13
+ return "Application readiness not verified";
14
+ }
15
+ function previewAccessLabel(access) {
16
+ if (!access || access.state === "unknown" || access.source !== "enforced-policy") return "Access not verified";
17
+ return access.state === "public" ? "Public URL" : "Authentication required";
18
+ }
19
+ /** The product supplies the initial URL and any additional approved origins. */
20
+ function safePreviewUrl(value, base, allowedOrigins) {
21
+ let url;
22
+ try {
23
+ url = base ? new URL(value, base) : new URL(value);
24
+ } catch {
25
+ throw new Error("Enter a valid preview URL.");
26
+ }
27
+ const loopback = [
28
+ "localhost",
29
+ "127.0.0.1",
30
+ "[::1]"
31
+ ].includes(url.hostname);
32
+ if (url.protocol !== "https:" && !(url.protocol === "http:" && loopback)) throw new Error("Use an HTTPS preview URL, or HTTP on localhost for local development.");
33
+ if (url.username || url.password) throw new Error("Preview URLs must not contain credentials.");
34
+ if (allowedOrigins && !allowedOrigins.includes(url.origin)) throw new Error("That origin is not approved for this sandbox preview.");
35
+ return url.href;
36
+ }
37
+ //#endregion
38
+ //#region src/workbench/preview-view.tsx
39
+ function PreviewView({ url, allowedOrigins, access, readiness, onCheckReadiness, onNavigate, variant = "browser", title = "Sandbox preview", toolbarActions, className }) {
40
+ const initial = React$1.useMemo(() => {
41
+ try {
42
+ return {
43
+ url: safePreviewUrl(url),
44
+ error: null
45
+ };
46
+ } catch (failure) {
47
+ return {
48
+ url: null,
49
+ error: failure instanceof Error ? failure.message : "Preview URL is invalid."
50
+ };
51
+ }
52
+ }, [url]);
53
+ const [address, setAddress] = React$1.useState(url);
54
+ const [location, setLocation] = React$1.useState({
55
+ source: url,
56
+ active: initial.url
57
+ });
58
+ const [iframeKey, setIframeKey] = React$1.useState(0);
59
+ const [loading, setLoading] = React$1.useState(true);
60
+ const [slow, setSlow] = React$1.useState(false);
61
+ const [addressError, setAddressError] = React$1.useState(null);
62
+ const errorId = React$1.useId();
63
+ const stateId = React$1.useId();
64
+ const activeUrl = location.source === url ? location.active : initial.url;
65
+ React$1.useEffect(() => {
66
+ setAddress(url);
67
+ setLocation({
68
+ source: url,
69
+ active: initial.url
70
+ });
71
+ setIframeKey((key) => key + 1);
72
+ setLoading(true);
73
+ setSlow(false);
74
+ setAddressError(null);
75
+ }, [url, initial.url]);
76
+ React$1.useEffect(() => {
77
+ if (!loading || !activeUrl) return;
78
+ const timer = setTimeout(() => setSlow(true), 8e3);
79
+ return () => clearTimeout(timer);
80
+ }, [
81
+ iframeKey,
82
+ loading,
83
+ activeUrl
84
+ ]);
85
+ const reload = () => {
86
+ setIframeKey((key) => key + 1);
87
+ setLoading(true);
88
+ setSlow(false);
89
+ };
90
+ const navigate = () => {
91
+ try {
92
+ if (!initial.url) throw new Error(initial.error ?? "Preview URL is invalid.");
93
+ const origins = [new URL(initial.url).origin, ...allowedOrigins ?? []];
94
+ const next = safePreviewUrl(address, activeUrl ?? initial.url, origins);
95
+ setAddress(next);
96
+ setLocation({
97
+ source: url,
98
+ active: next
99
+ });
100
+ setAddressError(null);
101
+ reload();
102
+ onNavigate?.(next);
103
+ } catch (failure) {
104
+ setAddressError(failure instanceof Error ? failure.message : "Preview address is invalid.");
105
+ }
106
+ };
107
+ const error = initial.error ?? addressError;
108
+ const currentReadiness = activeUrl === initial.url ? readiness : void 0;
109
+ const currentAccess = activeUrl === initial.url ? access : void 0;
110
+ const sameApplicationOrigin = activeUrl && typeof window !== "undefined" && new URL(activeUrl).origin === window.location.origin;
111
+ return /* @__PURE__ */ jsxs("div", {
112
+ className: cn$1("flex h-full min-h-0 min-w-0 flex-col bg-surface-container", className),
113
+ children: [
114
+ variant === "browser" ? /* @__PURE__ */ jsxs("form", {
115
+ "aria-label": "Preview navigation",
116
+ onSubmit: (event) => {
117
+ event.preventDefault();
118
+ navigate();
119
+ },
120
+ className: "flex flex-wrap items-center gap-2 border-b border-border bg-surface-container-low px-2 py-2",
121
+ children: [
122
+ /* @__PURE__ */ jsx(Button, {
123
+ type: "button",
124
+ variant: "ghost",
125
+ size: "sm",
126
+ onClick: reload,
127
+ disabled: !activeUrl,
128
+ "aria-label": "Reload preview",
129
+ children: /* @__PURE__ */ jsx(RotateCw, {
130
+ "aria-hidden": "true",
131
+ className: "size-4"
132
+ })
133
+ }),
134
+ /* @__PURE__ */ jsx("input", {
135
+ value: address,
136
+ onChange: (event) => {
137
+ setAddress(event.target.value);
138
+ setAddressError(null);
139
+ },
140
+ "aria-label": "Preview address",
141
+ "aria-invalid": !!error,
142
+ "aria-describedby": error ? errorId : stateId,
143
+ spellCheck: false,
144
+ autoComplete: "off",
145
+ className: `h-9 min-w-0 flex-1 rounded-md border bg-surface-container px-2.5 font-mono text-sm text-foreground ${focusField}`
146
+ }),
147
+ /* @__PURE__ */ jsx(Button, {
148
+ type: "submit",
149
+ variant: "outline",
150
+ size: "sm",
151
+ disabled: !initial.url,
152
+ children: "Go"
153
+ }),
154
+ activeUrl && /* @__PURE__ */ jsx(Button, {
155
+ asChild: true,
156
+ type: "button",
157
+ variant: "ghost",
158
+ size: "sm",
159
+ children: /* @__PURE__ */ jsx("a", {
160
+ href: activeUrl,
161
+ target: "_blank",
162
+ rel: "noopener noreferrer",
163
+ "aria-label": "Open preview in new tab",
164
+ children: /* @__PURE__ */ jsx(ExternalLink, {
165
+ "aria-hidden": "true",
166
+ className: "size-4"
167
+ })
168
+ })
169
+ })
170
+ ]
171
+ }) : /* @__PURE__ */ jsxs("div", {
172
+ className: "flex min-w-0 flex-wrap items-center gap-2 border-b border-border bg-surface-container-low px-3 py-2",
173
+ children: [
174
+ /* @__PURE__ */ jsx("h2", {
175
+ className: cn$1("min-w-0 truncate text-sm font-medium text-foreground", toolbarActions ? "basis-full sm:basis-auto sm:flex-1" : "flex-1"),
176
+ children: title
177
+ }),
178
+ toolbarActions && /* @__PURE__ */ jsx("div", {
179
+ className: "flex shrink-0 items-center gap-1",
180
+ children: toolbarActions
181
+ }),
182
+ /* @__PURE__ */ jsx(Button, {
183
+ type: "button",
184
+ variant: "ghost",
185
+ size: "sm",
186
+ onClick: reload,
187
+ disabled: !activeUrl,
188
+ "aria-label": `Reload ${title}`,
189
+ className: toolbarActions ? "ml-auto sm:ml-0" : void 0,
190
+ children: /* @__PURE__ */ jsx(RotateCw, {
191
+ "aria-hidden": "true",
192
+ className: "size-4"
193
+ })
194
+ }),
195
+ activeUrl && /* @__PURE__ */ jsx(Button, {
196
+ asChild: true,
197
+ type: "button",
198
+ variant: "ghost",
199
+ size: "sm",
200
+ children: /* @__PURE__ */ jsx("a", {
201
+ href: activeUrl,
202
+ target: "_blank",
203
+ rel: "noopener noreferrer",
204
+ "aria-label": `Open ${title} in new tab`,
205
+ children: /* @__PURE__ */ jsx(ExternalLink, {
206
+ "aria-hidden": "true",
207
+ className: "size-4"
208
+ })
209
+ })
210
+ })
211
+ ]
212
+ }),
213
+ error && /* @__PURE__ */ jsx("p", {
214
+ id: errorId,
215
+ role: "alert",
216
+ className: "px-3 py-2 text-sm text-destructive",
217
+ children: error
218
+ }),
219
+ (variant === "browser" || readiness || access || onCheckReadiness) && /* @__PURE__ */ jsxs("div", {
220
+ id: stateId,
221
+ className: "flex flex-wrap items-center gap-x-4 gap-y-1 border-b border-border px-3 py-2 text-xs text-muted-foreground",
222
+ children: [
223
+ /* @__PURE__ */ jsx("span", { children: previewAccessLabel(currentAccess) }),
224
+ /* @__PURE__ */ jsx("span", {
225
+ role: "status",
226
+ children: previewReadinessLabel(currentReadiness)
227
+ }),
228
+ currentReadiness && "checkedAt" in currentReadiness && /* @__PURE__ */ jsxs("time", {
229
+ dateTime: currentReadiness.checkedAt,
230
+ children: ["Checked ", currentReadiness.checkedAt]
231
+ }),
232
+ currentAccess && "expiresAt" in currentAccess && currentAccess.expiresAt && /* @__PURE__ */ jsxs("time", {
233
+ dateTime: currentAccess.expiresAt,
234
+ children: ["Expires ", currentAccess.expiresAt]
235
+ }),
236
+ onCheckReadiness && /* @__PURE__ */ jsx(Button, {
237
+ type: "button",
238
+ variant: "outline",
239
+ size: "sm",
240
+ onClick: onCheckReadiness,
241
+ disabled: currentReadiness?.state === "checking",
242
+ children: "Check application"
243
+ })
244
+ ]
245
+ }),
246
+ /* @__PURE__ */ jsxs("div", {
247
+ className: "relative min-h-0 min-w-0 flex-1 bg-surface-container-lowest",
248
+ children: [activeUrl && /* @__PURE__ */ jsx("iframe", {
249
+ src: activeUrl,
250
+ title,
251
+ className: "h-full w-full border-0 bg-white",
252
+ referrerPolicy: "no-referrer",
253
+ sandbox: sameApplicationOrigin ? "allow-scripts allow-forms" : "allow-scripts allow-same-origin allow-forms",
254
+ onLoad: () => {
255
+ setLoading(false);
256
+ setSlow(false);
257
+ },
258
+ onError: () => {
259
+ setLoading(false);
260
+ setAddressError("The preview frame could not be loaded. Check the application or open the URL separately.");
261
+ }
262
+ }, `${activeUrl}:${iframeKey}`), loading && activeUrl && /* @__PURE__ */ jsx("div", {
263
+ role: "status",
264
+ className: "pointer-events-none absolute inset-0 flex items-center justify-center bg-surface-container-lowest",
265
+ children: /* @__PURE__ */ jsx("p", {
266
+ className: "px-4 text-center text-sm text-muted-foreground",
267
+ children: slow ? "The preview frame is still loading. This does not establish whether the application is ready." : "Loading preview frame…"
268
+ })
269
+ })]
270
+ })
271
+ ]
272
+ });
273
+ }
274
+ //#endregion
275
+ //#region src/workbench/embedded-app-view.tsx
276
+ /**
277
+ * An app-sized preview surface for a product workspace.
278
+ * The host owns app discovery, persistence, access policy, and readiness checks.
279
+ */
280
+ function EmbeddedAppView({ app, allowedOrigins, readiness, access, toolbarActions, onRetry, className }) {
281
+ let previewUrl = null;
282
+ let urlError = null;
283
+ if (app.status === "ready") try {
284
+ previewUrl = safePreviewUrl(app.previewUrl ?? "", void 0, allowedOrigins);
285
+ } catch (failure) {
286
+ urlError = failure instanceof Error ? failure.message : "Preview URL is invalid.";
287
+ }
288
+ if (previewUrl) return /* @__PURE__ */ jsx("section", {
289
+ "aria-label": `${app.name} app`,
290
+ className: cn$1("h-full min-h-0 min-w-0", className),
291
+ children: /* @__PURE__ */ jsx(PreviewView, {
292
+ url: previewUrl,
293
+ allowedOrigins,
294
+ readiness,
295
+ access,
296
+ title: app.name,
297
+ toolbarActions,
298
+ variant: "embedded"
299
+ }, app.id)
300
+ });
301
+ const starting = app.status === "starting";
302
+ const message = starting ? app.statusMessage ?? "The app preview is starting." : urlError ?? app.statusMessage ?? "The app preview is unavailable.";
303
+ return /* @__PURE__ */ jsx("section", {
304
+ "aria-label": `${app.name} app`,
305
+ className: cn$1("flex h-full min-h-0 min-w-0 flex-col bg-surface-container", className),
306
+ children: /* @__PURE__ */ jsx("div", {
307
+ className: "flex min-h-0 flex-1 items-center justify-center p-6",
308
+ children: /* @__PURE__ */ jsxs("div", {
309
+ className: "max-w-md text-center",
310
+ children: [
311
+ /* @__PURE__ */ jsx("h2", {
312
+ className: "text-base font-medium text-foreground",
313
+ children: app.name
314
+ }),
315
+ /* @__PURE__ */ jsx("p", {
316
+ role: starting ? "status" : "alert",
317
+ className: "mt-2 text-sm text-muted-foreground",
318
+ children: message
319
+ }),
320
+ (readiness || access) && /* @__PURE__ */ jsxs("p", {
321
+ className: "mt-2 text-xs text-muted-foreground",
322
+ children: [
323
+ previewReadinessLabel(readiness),
324
+ " · ",
325
+ previewAccessLabel(access)
326
+ ]
327
+ }),
328
+ !starting && onRetry && /* @__PURE__ */ jsx(Button, {
329
+ type: "button",
330
+ variant: "outline",
331
+ size: "sm",
332
+ className: "mt-4",
333
+ onClick: onRetry,
334
+ children: "Retry preview"
335
+ })
336
+ ]
337
+ })
338
+ })
339
+ });
340
+ }
341
+ //#endregion
342
+ export { PreviewView as n, EmbeddedAppView as t };
package/dist/globals.css CHANGED
@@ -6124,6 +6124,9 @@
6124
6124
  outline-offset: -1px;
6125
6125
  box-shadow: none;
6126
6126
  }
6127
+ .focus-field-within :is(input:not([type=button],[type=submit],[type=reset],[type=image],[type=checkbox],[type=radio],[type=range],[type=color],[type=file]),textarea,select,[contenteditable]:not([contenteditable=false])):focus-visible {
6128
+ outline: none;
6129
+ }
6127
6130
  body {
6128
6131
  -webkit-font-smoothing: antialiased;
6129
6132
  -moz-osx-font-smoothing: grayscale;
@@ -1,5 +1,6 @@
1
1
  import { v as ExposedPort } from "./index-DPePq7c8.js";
2
2
  import { _ as RichFileTreeGitStatus, g as RichFileTreeGitEntry } from "./index-CXX5IpH2.js";
3
+ import { a as PreviewReadiness, i as PreviewAccess } from "./embedded-app-view-B_vMTtJn.js";
3
4
  import * as React$1 from "react";
4
5
  import { CSSProperties } from "react";
5
6
  //#region src/workbench/types.d.ts
@@ -273,28 +274,6 @@ interface DiffViewProps {
273
274
  */
274
275
  declare function DiffView({ filename, baseline, current, showFileHeader, defaultWrap, className }: DiffViewProps): React$1.JSX.Element;
275
276
  //#endregion
276
- //#region src/workbench/preview-policy.d.ts
277
- type PreviewReadiness = {
278
- state: "unknown";
279
- } | {
280
- state: "checking";
281
- } | {
282
- state: "ready";
283
- checkedAt: string;
284
- statusCode: number;
285
- } | {
286
- state: "failed";
287
- checkedAt: string;
288
- message: string;
289
- };
290
- type PreviewAccess = {
291
- state: "unknown";
292
- } | {
293
- state: "public" | "authenticated";
294
- source: "enforced-policy";
295
- expiresAt?: string;
296
- };
297
- //#endregion
298
277
  //#region src/workbench/preview-view.d.ts
299
278
  interface PreviewViewProps {
300
279
  /** A product-authorized preview URL. Relative navigation stays on its origin. */
@@ -315,37 +294,6 @@ interface PreviewViewProps {
315
294
  }
316
295
  declare function PreviewView({ url, allowedOrigins, access, readiness, onCheckReadiness, onNavigate, variant, title, toolbarActions, className }: PreviewViewProps): React$1.JSX.Element;
317
296
  //#endregion
318
- //#region src/workbench/embedded-app-view.d.ts
319
- interface EmbeddedApp {
320
- /** Stable app identity. The host uses it to preserve selection across updates. */
321
- id: string;
322
- name: string;
323
- /** Resolved, credential-free sandbox preview URL. */
324
- previewUrl?: string;
325
- /** The host supplies this state from its application or preview service. */
326
- status: "starting" | "ready" | "unavailable";
327
- statusMessage?: string;
328
- }
329
- interface EmbeddedAppViewProps {
330
- app: EmbeddedApp;
331
- /** Product-approved origins, obtained independently of the app URL. */
332
- allowedOrigins?: readonly string[];
333
- /** Service-observed HTTP result. Never derive it from iframe load. */
334
- readiness?: PreviewReadiness;
335
- /** Enforced access policy, supplied by the host service. */
336
- access?: PreviewAccess;
337
- /** Product actions beside the app name in the ready preview header. */
338
- toolbarActions?: React$1.ReactNode;
339
- /** Recheck or restart the preview through the host's own service. */
340
- onRetry?: () => void;
341
- className?: string;
342
- }
343
- /**
344
- * An app-sized preview surface for a product workspace.
345
- * The host owns app discovery, persistence, access policy, and readiness checks.
346
- */
347
- declare function EmbeddedAppView({ app, allowedOrigins, readiness, access, toolbarActions, onRetry, className }: EmbeddedAppViewProps): React$1.JSX.Element;
348
- //#endregion
349
297
  //#region src/workbench/syntax.d.ts
350
298
  /** Resolve a Prism language id from an explicit hint or the filename. */
351
299
  declare function resolveLanguage(filename: string, explicit?: string): string;
@@ -364,4 +312,4 @@ interface CodeSurfaceProps {
364
312
  */
365
313
  declare function CodeSurface({ code, filename, language, showLineNumbers, className }: CodeSurfaceProps): React$1.JSX.Element;
366
314
  //#endregion
367
- export { ArtifactView as A, buildUnifiedPatch as C, PillTabsProps as D, PillTabs as E, SandboxArtifactTerminal as F, ChangesPaneProps as M, SandboxArtifact as N, ChangesPane as O, SandboxArtifactPaneProps as P, DiffStats as S, PillTabItem as T, FileBreadcrumbProps as _, EmbeddedApp as a, PanelHeader as b, PreviewView as c, PreviewReadiness as d, DiffView as f, FileBreadcrumb as g, CodeViewProps as h, resolveLanguage as i, ChangedFile as j, SandboxArtifactPane as k, PreviewViewProps as l, CodeView as m, CodeSurface as n, EmbeddedAppView as o, DiffViewProps as p, CodeSurfaceProps as r, EmbeddedAppViewProps as s, BRAND_PRISM_THEME as t, PreviewAccess as u, DiffStatsBadge as v, computeDiffStats as w, PanelHeaderProps as x, GitStatusBadge as y };
315
+ export { SandboxArtifactTerminal as A, ChangesPane as C, ChangesPaneProps as D, ChangedFile as E, SandboxArtifact as O, PillTabsProps as S, ArtifactView as T, DiffStats as _, PreviewView as a, PillTabItem as b, DiffViewProps as c, FileBreadcrumb as d, FileBreadcrumbProps as f, PanelHeaderProps as g, PanelHeader as h, resolveLanguage as i, SandboxArtifactPaneProps as k, CodeView as l, GitStatusBadge as m, CodeSurface as n, PreviewViewProps as o, DiffStatsBadge as p, CodeSurfaceProps as r, DiffView as s, BRAND_PRISM_THEME as t, CodeViewProps as u, buildUnifiedPatch as v, SandboxArtifactPane as w, PillTabs as x, computeDiffStats as y };
package/dist/index.d.ts CHANGED
@@ -9,7 +9,8 @@ import { d as useSessionStream, l as UseSessionStreamOptions, n as UseSidecarAut
9
9
  import { AgentStreamEvent, AppendUserMessageOptions, ApplySdkEventOptions, AuthUser, AutomationStreamEvent, BeginAssistantMessageOptions, BotStreamEvent, CompleteAssistantMessageOptions, RealtimeSessionOptions, RealtimeSessionRegistry, RealtimeSessionRegistryProps, RealtimeSessionState, RealtimeSessionTarget, SSEEvent, SandboxMetrics, SdkSessionAttachment, SdkSessionEvent, SdkSessionSeed, SidecarMetricsPayload, TaskStreamEvent, TerminalStreamEvent, UseAuthOptions, UseAuthResult, UsePtySessionOptions, UsePtySessionReturn, UseRunGroupsOptions, UseSSEStreamOptions, UseSSEStreamResult, UseSandboxMetricsOptions, UseSandboxMetricsResult, UseSdkSessionOptions, UseSdkSessionReturn, UseToolCallStreamReturn, createAuthFetcher, useApiKey, useAuth, useAutoScroll, useCreateSession, useDeleteSession, useDropdownMenu, useLiveTime, usePtySession, useRealtimeSession, useRenameSession, useRunCollapseState, useRunGroups, useSSEStream, useSandboxMetrics, useSdkSession, useSessions, useToolCallStream } from "./hooks.js";
10
10
  import { $ as InputProps, $t as ToastProvider, A as DropZoneProps, At as Table, B as DropdownMenuSeparator, Bt as TabsList, C as DialogFooter, Ct as SkeletonTable, D as DialogTitle, Dt as StatusPillProps, E as DialogPortal, Et as StatusPill, F as DropdownMenuItem, Ft as TableHead, G as DropdownMenuTrigger, H as DropdownMenuSub, I as DropdownMenuLabel, It as TableHeader, J as FilterField, Jt as Textarea, K as EmptyState, Kt as TextShimmer, L as DropdownMenuPortal, Lt as TableRow, M as DropdownMenuCheckboxItem, Mt as TableCaption, N as DropdownMenuContent, Nt as TableCell, O as DialogTrigger, Ot as StatusTone, P as DropdownMenuGroup, Pt as TableFooter, Q as Input, Qt as ToastContainer, R as DropdownMenuRadioGroup, Rt as Tabs, S as DialogDescription, St as SkeletonCard, T as DialogOverlay, Tt as StatCardProps, U as DropdownMenuSubContent, Ut as TerminalDisplay, V as DropdownMenuShortcut, Vt as TabsTrigger, W as DropdownMenuSubTrigger, X as InlineCode, Xt as ThemeToggle, Y as FilterFieldProps, Yt as TextareaProps, Z as InlineCodeProps, Zt as Toast, _ as CodeBlockProps, _t as SelectTrigger, a as AvatarImage, an as badgeVariants, at as Progress, b as DialogClose, bn as TangleKnot, bt as SidebarDropZoneProps, c as Button, cn as useToast, ct as SegmentedControlProps, d as CardContent, dt as SelectGroup, en as Toolbar, et as Label, f as CardDescription, ft as SelectItem, g as CodeBlock, gt as SelectSeparator, h as CardTitle, ht as SelectScrollUpButton, i as AvatarFallback, in as UploadProgressProps, it as MetricStripProps, j as DropdownMenu, jt as TableBody, k as DropZone, kt as Switch, l as ButtonProps, lt as Select, m as CardHeader, mt as SelectScrollDownButton, nn as UploadFile, nt as MetricProps, o as Badge, on as buttonVariants, ot as SegmentedControl, p as CardFooter, pt as SelectLabel, q as EmptyStateProps, qt as TextShimmerProps, r as Avatar, rn as UploadProgress, rt as MetricStrip, s as BadgeProps, sn as useTheme, st as SegmentedControlOption, tn as ToolbarProps, tt as Metric, u as Card, ut as SelectContent, v as CopyButton, vn as Logo, vt as SelectValue, w as DialogHeader, wt as StatCard, x as DialogContent, xt as Skeleton, y as Dialog, yn as LogoProps, yt as SidebarDropZone, z as DropdownMenuRadioItem, zt as TabsContent } from "./index-PRM636Ex.js";
11
11
  import { $ as TerminalProps, A as ShellShouldRevalidateArgs, B as SessionSidebarLink, C as SandboxWorkbenchLayoutOptions, D as SandboxWorkbenchSessionProps, E as SandboxWorkbenchProps, F as SessionSidebar, G as SessionOptimisticController, H as SessionSidebarVariant, I as SessionSidebarBadge, J as useOptimisticSessionItems, K as UseOptimisticSessionItemsOptions, L as SessionSidebarFilter, M as createShellShouldRevalidate, N as shellShouldRevalidate, O as SessionActivityMonitor, P as formatRelativeAge, Q as TerminalPanel, R as SessionSidebarGroupBy, S as SandboxWorkbenchFileArtifact, T as SandboxWorkbenchOpenUIArtifact, U as SESSION_CREATED_EVENT, V as SessionSidebarProps, W as SessionCreatedDetail, X as RuntimePaneProps, Y as RuntimePane, Z as TerminalLine, _ as FormAudit, a as ApprovalQueue, at as StatusBannerProps, b as SandboxWorkbenchArtifact, c as CalendarView, ct as WorkspacePaneHeader, d as TaskBoardColumn, dt as WorkspaceLayoutProps, et as ContextBadge, f as TaskBoardItem, g as AuditResultsProps, h as AuditResults, i as ApprovalItem, it as StatusBanner, j as ShellShouldRevalidateOptions, k as SessionActivityMonitorProps, l as CalendarViewProps, lt as WorkspacePaneHeaderProps, m as AuditCheck, n as ArtifactPaneProps, nt as StatusBarProps, o as ApprovalQueueProps, ot as DirectoryPane, p as TaskBoardProps, q as dispatchSessionCreated, r as ApprovalConfidenceStat, rt as BannerType, s as CalendarEvent, st as DirectoryPaneProps, t as ArtifactPane, tt as StatusBar, u as TaskBoard, ut as WorkspaceLayout, v as AgentWorkbench, w as SandboxWorkbenchMarkdownArtifact, x as SandboxWorkbenchCustomArtifact, y as SandboxWorkbench, z as SessionSidebarItem } from "./index-CKRaj1pM.js";
12
- import { A as ArtifactView, C as buildUnifiedPatch, D as PillTabsProps, E as PillTabs, F as SandboxArtifactTerminal, M as ChangesPaneProps, N as SandboxArtifact, O as ChangesPane, P as SandboxArtifactPaneProps, S as DiffStats, T as PillTabItem, _ as FileBreadcrumbProps, a as EmbeddedApp, b as PanelHeader, c as PreviewView, d as PreviewReadiness, f as DiffView, g as FileBreadcrumb, h as CodeViewProps, i as resolveLanguage, j as ChangedFile, k as SandboxArtifactPane, l as PreviewViewProps, m as CodeView, n as CodeSurface, o as EmbeddedAppView, p as DiffViewProps, r as CodeSurfaceProps, s as EmbeddedAppViewProps, t as BRAND_PRISM_THEME, u as PreviewAccess, v as DiffStatsBadge, w as computeDiffStats, x as PanelHeaderProps, y as GitStatusBadge } from "./index-CesPlOyx.js";
12
+ import { A as SandboxArtifactTerminal, C as ChangesPane, D as ChangesPaneProps, E as ChangedFile, O as SandboxArtifact, S as PillTabsProps, T as ArtifactView, _ as DiffStats, a as PreviewView, b as PillTabItem, c as DiffViewProps, d as FileBreadcrumb, f as FileBreadcrumbProps, g as PanelHeaderProps, h as PanelHeader, i as resolveLanguage, k as SandboxArtifactPaneProps, l as CodeView, m as GitStatusBadge, n as CodeSurface, o as PreviewViewProps, p as DiffStatsBadge, r as CodeSurfaceProps, s as DiffView, t as BRAND_PRISM_THEME, u as CodeViewProps, v as buildUnifiedPatch, w as SandboxArtifactPane, x as PillTabs, y as computeDiffStats } from "./index-Jw7UYYcH.js";
13
+ import { a as PreviewReadiness, i as PreviewAccess, n as EmbeddedAppView, r as EmbeddedAppViewProps, t as EmbeddedApp } from "./embedded-app-view-B_vMTtJn.js";
13
14
  import { OpenUIAction, OpenUIActionsNode, OpenUIArtifactRenderer, OpenUIArtifactRendererProps, OpenUIBadgeNode, OpenUICardNode, OpenUICodeNode, OpenUIComponentNode, OpenUIGridNode, OpenUIHeadingNode, OpenUIKeyValueNode, OpenUIMarkdownNode, OpenUIPrimitive, OpenUISeparatorNode, OpenUIStackNode, OpenUIStatNode, OpenUITableNode, OpenUITextNode } from "./openui.js";
14
15
  import { ExpandedToolDetail, ExpandedToolDetailProps, FeedSegment, InlineThinkingItem, InlineThinkingItemProps, InlineToolItem, InlineToolItemProps, LiveDuration, RunGroup, RunGroupProps, RunRowShell, RunRowShellProps, RunRowStatus, RunRowStatusDot, ToolCallData, ToolCallFeed, ToolCallFeedProps, ToolCallStatus, ToolCallType, parseToolEvent } from "./run.js";
15
16
  import { ActiveProjectActivity, ActiveSessionActivityOptions, ActiveSessionConnectionOptions, ActiveSessionConnectionState, ActiveSessionReconnectState, ActiveSessionRecord, ActiveSessionStatus, ActiveSessionTransportMode, ActiveSessionsState, ChatSession, RegisterActiveSessionOptions, SessionProjectKey, activeSessionsAtom, addMessage, addParts, bumpActiveSessionActivity, clearChat, connectSession, disconnectSession, getActiveSession, getAllActiveSessions, getAllProjectActivity, getSessionsByActivity, getSessionsForNavbar, getSessionsForProject, getTotalRunningSessionCount, hasBackgroundRunningSessions, isStreamingAtom, messagesAtom, partMapAtom, registerActiveSession, resetActiveSessions, sessionAtom, setActiveSessionAttention, setActiveSessionConnection, setActiveSessionError, setActiveSessionRunning, setForegroundActiveSession, unregisterActiveSession, updateActiveSessionMeta, updatePart, useActiveSession, useActiveSessions, useActiveSessionsState, useHasBackgroundRunningSessions, useNavbarSessions, useProjectActivity, useProjectSessions, useSessionsByActivity, useTotalRunningSessions } from "./stores.js";
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { a as DiffView, c as CodeView, d as CodeSurface, f as resolveLanguage, g as PillTabs, h as PanelHeader, i as PreviewView, l as FileBreadcrumb, m as GitStatusBadge, n as ChangesPane, o as buildUnifiedPatch, p as DiffStatsBadge, r as SandboxArtifactPane, s as computeDiffStats, t as EmbeddedAppView, u as BRAND_PRISM_THEME } from "./workbench-ztU44Jt2.js";
1
+ import { a as computeDiffStats, c as BRAND_PRISM_THEME, d as DiffStatsBadge, f as GitStatusBadge, i as buildUnifiedPatch, l as CodeSurface, m as PillTabs, n as SandboxArtifactPane, o as CodeView, p as PanelHeader, r as DiffView, s as FileBreadcrumb, t as ChangesPane, u as resolveLanguage } from "./workbench-DmDMQxZ_.js";
2
2
  import { $ as SelectItem, A as DropdownMenuItem, At as Textarea, B as DropdownMenuTrigger, C as DialogTitle, Ct as TabsList, D as DropdownMenuCheckboxItem, E as DropdownMenu, Et as TerminalDisplay, F as DropdownMenuSeparator, Ft as UploadProgress, G as Label, Gt as TangleKnot, H as FilterField, I as DropdownMenuShortcut, It as badgeVariants, J as Progress, K as Metric, L as DropdownMenuSub, Lt as buttonVariants, M as DropdownMenuPortal, Mt as ToastContainer, N as DropdownMenuRadioGroup, Nt as ToastProvider, O as DropdownMenuContent, P as DropdownMenuRadioItem, Pt as Toolbar, Q as SelectGroup, R as DropdownMenuSubContent, Rt as useTheme, S as DialogPortal, St as TabsContent, T as DropZone, U as InlineCode, V as EmptyState, W as Input, Wt as Logo, X as Select, Y as SegmentedControl, Z as SelectContent, _ as DialogContent, _t as TableFooter, a as Badge, at as SelectValue, b as DialogHeader, bt as TableRow, c as CardContent, ct as SkeletonCard, d as CardHeader, dt as StatusPill, et as SelectLabel, f as CardTitle, ft as Switch, g as DialogClose, gt as TableCell, h as Dialog, ht as TableCaption, i as AvatarImage, it as SelectTrigger, j as DropdownMenuLabel, jt as ThemeToggle, k as DropdownMenuGroup, kt as TextShimmer, l as CardDescription, lt as SkeletonTable, m as CopyButton, mt as TableBody, n as Avatar, nt as SelectScrollUpButton, o as Button, ot as SidebarDropZone, p as CodeBlock, pt as Table, q as MetricStrip, r as AvatarFallback, rt as SelectSeparator, s as Card, st as Skeleton, tt as SelectScrollDownButton, u as CardFooter, ut as StatCard, v as DialogDescription, vt as TableHead, w as DialogTrigger, wt as TabsTrigger, x as DialogOverlay, xt as Tabs, y as DialogFooter, yt as TableHeader, z as DropdownMenuSubTrigger, zt as useToast } from "./primitives-Dh1vG6J3.js";
3
3
  import { S as WorkspacePaneHeader, _ as TerminalPanel, a as AuditResults, b as DirectoryPane, c as SessionActivityMonitor, d as SessionSidebar, f as SESSION_CREATED_EVENT, g as RuntimePane, h as formatRelativeAge, i as TaskBoard, l as createShellShouldRevalidate, m as useOptimisticSessionItems, n as ApprovalQueue, o as AgentWorkbench, p as dispatchSessionCreated, r as CalendarView, s as SandboxWorkbench, t as ArtifactPane, u as shellShouldRevalidate, v as StatusBar, x as WorkspaceLayout, y as StatusBanner } from "./workspace-B6AtI6ld.js";
4
4
  import { $ as SidebarRailNav, A as ResourceMeter, B as RailFlyout, C as InvoiceTable, D as canAdminSandbox, E as SandboxCard, F as CreditBalance, G as Sidebar, H as RailModeButton, I as ProfileAvatar, J as SidebarPanelContent, K as SidebarContent, L as RailButton, M as INSUFFICIENT_BALANCE_CODE, N as OutOfCreditsModal, O as ActivityFeed, P as parseInsufficientBalance, Q as SidebarRailHeader, R as RailCollapseToggle, S as PlanCards, T as NewSandboxCard, U as RailSeparator, V as RailHeader, W as RailThemeToggle, X as SidebarRail, Y as SidebarPanelHeader, Z as SidebarRailFooter, _ as HarnessPicker, a as ProcessList, at as SIDEBAR_TOTAL_WIDTH, b as HarnessLogo, c as UsageSummary, d as MetricAreaChart, et as RailTooltip, f as ProfileComparison, g as HARNESS_OPTIONS, h as DashboardLayout, i as NetworkConfig, it as SIDEBAR_RAIL_WIDTH, j as ClusterStatusBar, k as ResourceSnapshot, l as SystemLogsViewer, m as SidebarLayout, n as SnapshotList, nt as SIDEBAR_PANEL_WIDTH, o as PortsList, ot as SidebarProvider, p as ProfileSelector, q as SidebarPanel, r as BackendConfig, rt as SIDEBAR_RAIL_LABELED_WIDTH, s as GitPanel, st as useSidebar, t as PromoBanner, tt as SIDEBAR_MOBILE_WIDTH, u as VariantList, v as chatCapableHarnesses, w as SandboxTable, x as BackendSelector, y as HARNESS_BRAND, z as RailExpandable } from "./dashboard-CZ3VgNPR.js";
@@ -6,6 +6,7 @@ import { n as canonicalModelId, r as modelBrandFor, t as ModelBrandStack } from
6
6
  import { a as formatPrice, i as PricingPage, n as TemplateCard, o as BillingDashboard, r as UsageChart, t as InfoPanel } from "./info-panel-C9cqDzOL.js";
7
7
  import { t as usePtySession } from "./use-pty-session-C8cE0adT.js";
8
8
  import { CSV_PREVIEW_ROW_LIMIT, FileArtifactPane, FilePreview, FileTabs, FileTree, RichFileTree, detectFileFormat, fileExtension, filterFileTree, getCodeLanguage, getFormatLabel, getSyntaxLanguage, parseCsv, resolveFilePreviewKind } from "./files.js";
9
+ import { n as PreviewView, t as EmbeddedAppView } from "./embedded-app-view-c6-nUY7O.js";
9
10
  import { OpenUIArtifactRenderer } from "./openui.js";
10
11
  import { a as ThinkingIndicator, c as createFetchTransport, d as AgentProfilePicker, f as DEFAULT_REASONING_LEVEL_OPTIONS, i as MessageList, l as modelProvider, m as ReasoningLevelPicker, n as ChatContainer, o as UserMessage, p as HARNESS_REASONING_OPTIONS, r as ChatMessage, s as ArtifactAgentDock, t as AgentTimeline, u as snapHarnessToModel } from "./chat-BOvFAe6p.js";
11
12
  import { ExpandedToolDetail, InlineThinkingItem, InlineToolItem, LiveDuration, RunGroup, RunRowShell, RunRowStatusDot, ToolCallFeed, parseToolEvent } from "./run.js";
package/dist/styles.css CHANGED
@@ -6124,6 +6124,9 @@
6124
6124
  outline-offset: -1px;
6125
6125
  box-shadow: none;
6126
6126
  }
6127
+ .focus-field-within :is(input:not([type=button],[type=submit],[type=reset],[type=image],[type=checkbox],[type=radio],[type=range],[type=color],[type=file]),textarea,select,[contenteditable]:not([contenteditable=false])):focus-visible {
6128
+ outline: none;
6129
+ }
6127
6130
  body {
6128
6131
  -webkit-font-smoothing: antialiased;
6129
6132
  -moz-osx-font-smoothing: grayscale;
@@ -0,0 +1,2 @@
1
+ import { a as PreviewReadiness, i as PreviewAccess, n as EmbeddedAppView, r as EmbeddedAppViewProps, t as EmbeddedApp } from "../embedded-app-view-B_vMTtJn.js";
2
+ export { type EmbeddedApp, EmbeddedAppView, type EmbeddedAppViewProps, type PreviewAccess, type PreviewReadiness };
@@ -0,0 +1,2 @@
1
+ import { t as EmbeddedAppView } from "../embedded-app-view-c6-nUY7O.js";
2
+ export { EmbeddedAppView };
@@ -2,12 +2,13 @@ import { t as cn$1 } from "./utils-DzWbktWG.js";
2
2
  import { o as PortsList } from "./dashboard-CZ3VgNPR.js";
3
3
  import { n as TerminalView } from "./terminal-CN9ZgHRt.js";
4
4
  import { RichFileTree } from "./files.js";
5
+ import { n as PreviewView } from "./embedded-app-view-c6-nUY7O.js";
5
6
  import { Button, Skeleton, Textarea } from "@tangle-network/ui/primitives";
6
7
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
7
8
  import * as React$1 from "react";
8
9
  import React from "react";
9
- import { focusField, focusRing, focusRingInset } from "@tangle-network/ui/utils";
10
- import { Check, ChevronRight, Code2, Copy, ExternalLink, FileCode2, GitBranch, GitCompare, Globe, Network, RefreshCw, RotateCw, SquareTerminal } from "lucide-react";
10
+ import { focusRing, focusRingInset } from "@tangle-network/ui/utils";
11
+ import { Check, ChevronRight, Code2, Copy, FileCode2, GitBranch, GitCompare, Globe, Network, RefreshCw, SquareTerminal } from "lucide-react";
11
12
  import { FileDiff, getSingularPatch } from "@pierre/diffs";
12
13
  import { createTwoFilesPatch, diffLines } from "diff";
13
14
  //#region \0rolldown/runtime.js
@@ -7612,274 +7613,6 @@ function DiffView({ filename, baseline, current, showFileHeader = true, defaultW
7612
7613
  });
7613
7614
  }
7614
7615
  //#endregion
7615
- //#region src/workbench/preview-policy.ts
7616
- /** Only an actual verified HTTP outcome can establish application readiness. */
7617
- function previewReadinessLabel(readiness) {
7618
- if (readiness?.state === "checking") return "Checking application readiness";
7619
- if (readiness?.state === "failed") return "Application check failed";
7620
- if (readiness?.state === "ready" && Number.isFinite(Date.parse(readiness.checkedAt)) && Number.isInteger(readiness.statusCode) && readiness.statusCode >= 200 && readiness.statusCode < 400) return `Application responded: HTTP ${readiness.statusCode}`;
7621
- return "Application readiness not verified";
7622
- }
7623
- function previewAccessLabel(access) {
7624
- if (!access || access.state === "unknown" || access.source !== "enforced-policy") return "Access not verified";
7625
- return access.state === "public" ? "Public URL" : "Authentication required";
7626
- }
7627
- /** The product supplies the initial URL and any additional approved origins. */
7628
- function safePreviewUrl(value, base, allowedOrigins) {
7629
- let url;
7630
- try {
7631
- url = base ? new URL(value, base) : new URL(value);
7632
- } catch {
7633
- throw new Error("Enter a valid preview URL.");
7634
- }
7635
- const loopback = [
7636
- "localhost",
7637
- "127.0.0.1",
7638
- "[::1]"
7639
- ].includes(url.hostname);
7640
- if (url.protocol !== "https:" && !(url.protocol === "http:" && loopback)) throw new Error("Use an HTTPS preview URL, or HTTP on localhost for local development.");
7641
- if (url.username || url.password) throw new Error("Preview URLs must not contain credentials.");
7642
- if (allowedOrigins && !allowedOrigins.includes(url.origin)) throw new Error("That origin is not approved for this sandbox preview.");
7643
- return url.href;
7644
- }
7645
- //#endregion
7646
- //#region src/workbench/preview-view.tsx
7647
- function PreviewView({ url, allowedOrigins, access, readiness, onCheckReadiness, onNavigate, variant = "browser", title = "Sandbox preview", toolbarActions, className }) {
7648
- const initial = React$1.useMemo(() => {
7649
- try {
7650
- return {
7651
- url: safePreviewUrl(url),
7652
- error: null
7653
- };
7654
- } catch (failure) {
7655
- return {
7656
- url: null,
7657
- error: failure instanceof Error ? failure.message : "Preview URL is invalid."
7658
- };
7659
- }
7660
- }, [url]);
7661
- const [address, setAddress] = React$1.useState(url);
7662
- const [location, setLocation] = React$1.useState({
7663
- source: url,
7664
- active: initial.url
7665
- });
7666
- const [iframeKey, setIframeKey] = React$1.useState(0);
7667
- const [loading, setLoading] = React$1.useState(true);
7668
- const [slow, setSlow] = React$1.useState(false);
7669
- const [addressError, setAddressError] = React$1.useState(null);
7670
- const errorId = React$1.useId();
7671
- const stateId = React$1.useId();
7672
- const activeUrl = location.source === url ? location.active : initial.url;
7673
- React$1.useEffect(() => {
7674
- setAddress(url);
7675
- setLocation({
7676
- source: url,
7677
- active: initial.url
7678
- });
7679
- setIframeKey((key) => key + 1);
7680
- setLoading(true);
7681
- setSlow(false);
7682
- setAddressError(null);
7683
- }, [url, initial.url]);
7684
- React$1.useEffect(() => {
7685
- if (!loading || !activeUrl) return;
7686
- const timer = setTimeout(() => setSlow(true), 8e3);
7687
- return () => clearTimeout(timer);
7688
- }, [
7689
- iframeKey,
7690
- loading,
7691
- activeUrl
7692
- ]);
7693
- const reload = () => {
7694
- setIframeKey((key) => key + 1);
7695
- setLoading(true);
7696
- setSlow(false);
7697
- };
7698
- const navigate = () => {
7699
- try {
7700
- if (!initial.url) throw new Error(initial.error ?? "Preview URL is invalid.");
7701
- const origins = [new URL(initial.url).origin, ...allowedOrigins ?? []];
7702
- const next = safePreviewUrl(address, activeUrl ?? initial.url, origins);
7703
- setAddress(next);
7704
- setLocation({
7705
- source: url,
7706
- active: next
7707
- });
7708
- setAddressError(null);
7709
- reload();
7710
- onNavigate?.(next);
7711
- } catch (failure) {
7712
- setAddressError(failure instanceof Error ? failure.message : "Preview address is invalid.");
7713
- }
7714
- };
7715
- const error = initial.error ?? addressError;
7716
- const currentReadiness = activeUrl === initial.url ? readiness : void 0;
7717
- const currentAccess = activeUrl === initial.url ? access : void 0;
7718
- const sameApplicationOrigin = activeUrl && typeof window !== "undefined" && new URL(activeUrl).origin === window.location.origin;
7719
- return /* @__PURE__ */ jsxs("div", {
7720
- className: cn$1("flex h-full min-h-0 min-w-0 flex-col bg-surface-container", className),
7721
- children: [
7722
- variant === "browser" ? /* @__PURE__ */ jsxs("form", {
7723
- "aria-label": "Preview navigation",
7724
- onSubmit: (event) => {
7725
- event.preventDefault();
7726
- navigate();
7727
- },
7728
- className: "flex flex-wrap items-center gap-2 border-b border-border bg-surface-container-low px-2 py-2",
7729
- children: [
7730
- /* @__PURE__ */ jsx(Button, {
7731
- type: "button",
7732
- variant: "ghost",
7733
- size: "sm",
7734
- onClick: reload,
7735
- disabled: !activeUrl,
7736
- "aria-label": "Reload preview",
7737
- children: /* @__PURE__ */ jsx(RotateCw, {
7738
- "aria-hidden": "true",
7739
- className: "size-4"
7740
- })
7741
- }),
7742
- /* @__PURE__ */ jsx("input", {
7743
- value: address,
7744
- onChange: (event) => {
7745
- setAddress(event.target.value);
7746
- setAddressError(null);
7747
- },
7748
- "aria-label": "Preview address",
7749
- "aria-invalid": !!error,
7750
- "aria-describedby": error ? errorId : stateId,
7751
- spellCheck: false,
7752
- autoComplete: "off",
7753
- className: `h-9 min-w-0 flex-1 rounded-md border bg-surface-container px-2.5 font-mono text-sm text-foreground ${focusField}`
7754
- }),
7755
- /* @__PURE__ */ jsx(Button, {
7756
- type: "submit",
7757
- variant: "outline",
7758
- size: "sm",
7759
- disabled: !initial.url,
7760
- children: "Go"
7761
- }),
7762
- activeUrl && /* @__PURE__ */ jsx(Button, {
7763
- asChild: true,
7764
- type: "button",
7765
- variant: "ghost",
7766
- size: "sm",
7767
- children: /* @__PURE__ */ jsx("a", {
7768
- href: activeUrl,
7769
- target: "_blank",
7770
- rel: "noopener noreferrer",
7771
- "aria-label": "Open preview in new tab",
7772
- children: /* @__PURE__ */ jsx(ExternalLink, {
7773
- "aria-hidden": "true",
7774
- className: "size-4"
7775
- })
7776
- })
7777
- })
7778
- ]
7779
- }) : /* @__PURE__ */ jsxs("div", {
7780
- className: "flex min-w-0 flex-wrap items-center gap-2 border-b border-border bg-surface-container-low px-3 py-2",
7781
- children: [
7782
- /* @__PURE__ */ jsx("h2", {
7783
- className: cn$1("min-w-0 truncate text-sm font-medium text-foreground", toolbarActions ? "basis-full sm:basis-auto sm:flex-1" : "flex-1"),
7784
- children: title
7785
- }),
7786
- toolbarActions && /* @__PURE__ */ jsx("div", {
7787
- className: "flex shrink-0 items-center gap-1",
7788
- children: toolbarActions
7789
- }),
7790
- /* @__PURE__ */ jsx(Button, {
7791
- type: "button",
7792
- variant: "ghost",
7793
- size: "sm",
7794
- onClick: reload,
7795
- disabled: !activeUrl,
7796
- "aria-label": `Reload ${title}`,
7797
- className: toolbarActions ? "ml-auto sm:ml-0" : void 0,
7798
- children: /* @__PURE__ */ jsx(RotateCw, {
7799
- "aria-hidden": "true",
7800
- className: "size-4"
7801
- })
7802
- }),
7803
- activeUrl && /* @__PURE__ */ jsx(Button, {
7804
- asChild: true,
7805
- type: "button",
7806
- variant: "ghost",
7807
- size: "sm",
7808
- children: /* @__PURE__ */ jsx("a", {
7809
- href: activeUrl,
7810
- target: "_blank",
7811
- rel: "noopener noreferrer",
7812
- "aria-label": `Open ${title} in new tab`,
7813
- children: /* @__PURE__ */ jsx(ExternalLink, {
7814
- "aria-hidden": "true",
7815
- className: "size-4"
7816
- })
7817
- })
7818
- })
7819
- ]
7820
- }),
7821
- error && /* @__PURE__ */ jsx("p", {
7822
- id: errorId,
7823
- role: "alert",
7824
- className: "px-3 py-2 text-sm text-destructive",
7825
- children: error
7826
- }),
7827
- (variant === "browser" || readiness || access || onCheckReadiness) && /* @__PURE__ */ jsxs("div", {
7828
- id: stateId,
7829
- className: "flex flex-wrap items-center gap-x-4 gap-y-1 border-b border-border px-3 py-2 text-xs text-muted-foreground",
7830
- children: [
7831
- /* @__PURE__ */ jsx("span", { children: previewAccessLabel(currentAccess) }),
7832
- /* @__PURE__ */ jsx("span", {
7833
- role: "status",
7834
- children: previewReadinessLabel(currentReadiness)
7835
- }),
7836
- currentReadiness && "checkedAt" in currentReadiness && /* @__PURE__ */ jsxs("time", {
7837
- dateTime: currentReadiness.checkedAt,
7838
- children: ["Checked ", currentReadiness.checkedAt]
7839
- }),
7840
- currentAccess && "expiresAt" in currentAccess && currentAccess.expiresAt && /* @__PURE__ */ jsxs("time", {
7841
- dateTime: currentAccess.expiresAt,
7842
- children: ["Expires ", currentAccess.expiresAt]
7843
- }),
7844
- onCheckReadiness && /* @__PURE__ */ jsx(Button, {
7845
- type: "button",
7846
- variant: "outline",
7847
- size: "sm",
7848
- onClick: onCheckReadiness,
7849
- disabled: currentReadiness?.state === "checking",
7850
- children: "Check application"
7851
- })
7852
- ]
7853
- }),
7854
- /* @__PURE__ */ jsxs("div", {
7855
- className: "relative min-h-0 min-w-0 flex-1 bg-surface-container-lowest",
7856
- children: [activeUrl && /* @__PURE__ */ jsx("iframe", {
7857
- src: activeUrl,
7858
- title,
7859
- className: "h-full w-full border-0 bg-white",
7860
- referrerPolicy: "no-referrer",
7861
- sandbox: sameApplicationOrigin ? "allow-scripts allow-forms" : "allow-scripts allow-same-origin allow-forms",
7862
- onLoad: () => {
7863
- setLoading(false);
7864
- setSlow(false);
7865
- },
7866
- onError: () => {
7867
- setLoading(false);
7868
- setAddressError("The preview frame could not be loaded. Check the application or open the URL separately.");
7869
- }
7870
- }, `${activeUrl}:${iframeKey}`), loading && activeUrl && /* @__PURE__ */ jsx("div", {
7871
- role: "status",
7872
- className: "pointer-events-none absolute inset-0 flex items-center justify-center bg-surface-container-lowest",
7873
- children: /* @__PURE__ */ jsx("p", {
7874
- className: "px-4 text-center text-sm text-muted-foreground",
7875
- children: slow ? "The preview frame is still loading. This does not establish whether the application is ready." : "Loading preview frame…"
7876
- })
7877
- })]
7878
- })
7879
- ]
7880
- });
7881
- }
7882
- //#endregion
7883
7616
  //#region src/workbench/sandbox-artifact-pane.tsx
7884
7617
  const VIEW_ORDER = [
7885
7618
  "code",
@@ -8385,71 +8118,4 @@ function ChangesPane({ branch, ahead = 0, behind = 0, files, selectedPath, onSel
8385
8118
  });
8386
8119
  }
8387
8120
  //#endregion
8388
- //#region src/workbench/embedded-app-view.tsx
8389
- /**
8390
- * An app-sized preview surface for a product workspace.
8391
- * The host owns app discovery, persistence, access policy, and readiness checks.
8392
- */
8393
- function EmbeddedAppView({ app, allowedOrigins, readiness, access, toolbarActions, onRetry, className }) {
8394
- let previewUrl = null;
8395
- let urlError = null;
8396
- if (app.status === "ready") try {
8397
- previewUrl = safePreviewUrl(app.previewUrl ?? "", void 0, allowedOrigins);
8398
- } catch (failure) {
8399
- urlError = failure instanceof Error ? failure.message : "Preview URL is invalid.";
8400
- }
8401
- if (previewUrl) return /* @__PURE__ */ jsx("section", {
8402
- "aria-label": `${app.name} app`,
8403
- className: cn$1("h-full min-h-0 min-w-0", className),
8404
- children: /* @__PURE__ */ jsx(PreviewView, {
8405
- url: previewUrl,
8406
- allowedOrigins,
8407
- readiness,
8408
- access,
8409
- title: app.name,
8410
- toolbarActions,
8411
- variant: "embedded"
8412
- }, app.id)
8413
- });
8414
- const starting = app.status === "starting";
8415
- const message = starting ? app.statusMessage ?? "The app preview is starting." : urlError ?? app.statusMessage ?? "The app preview is unavailable.";
8416
- return /* @__PURE__ */ jsx("section", {
8417
- "aria-label": `${app.name} app`,
8418
- className: cn$1("flex h-full min-h-0 min-w-0 flex-col bg-surface-container", className),
8419
- children: /* @__PURE__ */ jsx("div", {
8420
- className: "flex min-h-0 flex-1 items-center justify-center p-6",
8421
- children: /* @__PURE__ */ jsxs("div", {
8422
- className: "max-w-md text-center",
8423
- children: [
8424
- /* @__PURE__ */ jsx("h2", {
8425
- className: "text-base font-medium text-foreground",
8426
- children: app.name
8427
- }),
8428
- /* @__PURE__ */ jsx("p", {
8429
- role: starting ? "status" : "alert",
8430
- className: "mt-2 text-sm text-muted-foreground",
8431
- children: message
8432
- }),
8433
- (readiness || access) && /* @__PURE__ */ jsxs("p", {
8434
- className: "mt-2 text-xs text-muted-foreground",
8435
- children: [
8436
- previewReadinessLabel(readiness),
8437
- " · ",
8438
- previewAccessLabel(access)
8439
- ]
8440
- }),
8441
- !starting && onRetry && /* @__PURE__ */ jsx(Button, {
8442
- type: "button",
8443
- variant: "outline",
8444
- size: "sm",
8445
- className: "mt-4",
8446
- onClick: onRetry,
8447
- children: "Retry preview"
8448
- })
8449
- ]
8450
- })
8451
- })
8452
- });
8453
- }
8454
- //#endregion
8455
- export { DiffView as a, CodeView as c, CodeSurface as d, resolveLanguage as f, PillTabs as g, PanelHeader as h, PreviewView as i, FileBreadcrumb as l, GitStatusBadge as m, ChangesPane as n, buildUnifiedPatch as o, DiffStatsBadge as p, SandboxArtifactPane as r, computeDiffStats as s, EmbeddedAppView as t, BRAND_PRISM_THEME as u };
8121
+ export { computeDiffStats as a, BRAND_PRISM_THEME as c, DiffStatsBadge as d, GitStatusBadge as f, buildUnifiedPatch as i, CodeSurface as l, PillTabs as m, SandboxArtifactPane as n, CodeView as o, PanelHeader as p, DiffView as r, FileBreadcrumb as s, ChangesPane as t, resolveLanguage as u };
@@ -1,2 +1,3 @@
1
- import { A as ArtifactView, C as buildUnifiedPatch, D as PillTabsProps, E as PillTabs, F as SandboxArtifactTerminal, M as ChangesPaneProps, N as SandboxArtifact, O as ChangesPane, P as SandboxArtifactPaneProps, S as DiffStats, T as PillTabItem, _ as FileBreadcrumbProps, a as EmbeddedApp, b as PanelHeader, c as PreviewView, d as PreviewReadiness, f as DiffView, g as FileBreadcrumb, h as CodeViewProps, i as resolveLanguage, j as ChangedFile, k as SandboxArtifactPane, l as PreviewViewProps, m as CodeView, n as CodeSurface, o as EmbeddedAppView, p as DiffViewProps, r as CodeSurfaceProps, s as EmbeddedAppViewProps, t as BRAND_PRISM_THEME, u as PreviewAccess, v as DiffStatsBadge, w as computeDiffStats, x as PanelHeaderProps, y as GitStatusBadge } from "./index-CesPlOyx.js";
1
+ import { A as SandboxArtifactTerminal, C as ChangesPane, D as ChangesPaneProps, E as ChangedFile, O as SandboxArtifact, S as PillTabsProps, T as ArtifactView, _ as DiffStats, a as PreviewView, b as PillTabItem, c as DiffViewProps, d as FileBreadcrumb, f as FileBreadcrumbProps, g as PanelHeaderProps, h as PanelHeader, i as resolveLanguage, k as SandboxArtifactPaneProps, l as CodeView, m as GitStatusBadge, n as CodeSurface, o as PreviewViewProps, p as DiffStatsBadge, r as CodeSurfaceProps, s as DiffView, t as BRAND_PRISM_THEME, u as CodeViewProps, v as buildUnifiedPatch, w as SandboxArtifactPane, x as PillTabs, y as computeDiffStats } from "./index-Jw7UYYcH.js";
2
+ import { a as PreviewReadiness, i as PreviewAccess, n as EmbeddedAppView, r as EmbeddedAppViewProps, t as EmbeddedApp } from "./embedded-app-view-B_vMTtJn.js";
2
3
  export { type ArtifactView, BRAND_PRISM_THEME, type ChangedFile, ChangesPane, type ChangesPaneProps, CodeSurface, type CodeSurfaceProps, CodeView, type CodeViewProps, type DiffStats, DiffStatsBadge, DiffView, type DiffViewProps, type EmbeddedApp, EmbeddedAppView, type EmbeddedAppViewProps, FileBreadcrumb, type FileBreadcrumbProps, GitStatusBadge, PanelHeader, type PanelHeaderProps, type PillTabItem, PillTabs, type PillTabsProps, type PreviewAccess, type PreviewReadiness, PreviewView, type PreviewViewProps, type SandboxArtifact, SandboxArtifactPane, type SandboxArtifactPaneProps, type SandboxArtifactTerminal, buildUnifiedPatch, computeDiffStats, resolveLanguage };
package/dist/workbench.js CHANGED
@@ -1,2 +1,3 @@
1
- import { a as DiffView, c as CodeView, d as CodeSurface, f as resolveLanguage, g as PillTabs, h as PanelHeader, i as PreviewView, l as FileBreadcrumb, m as GitStatusBadge, n as ChangesPane, o as buildUnifiedPatch, p as DiffStatsBadge, r as SandboxArtifactPane, s as computeDiffStats, t as EmbeddedAppView, u as BRAND_PRISM_THEME } from "./workbench-ztU44Jt2.js";
1
+ import { a as computeDiffStats, c as BRAND_PRISM_THEME, d as DiffStatsBadge, f as GitStatusBadge, i as buildUnifiedPatch, l as CodeSurface, m as PillTabs, n as SandboxArtifactPane, o as CodeView, p as PanelHeader, r as DiffView, s as FileBreadcrumb, t as ChangesPane, u as resolveLanguage } from "./workbench-DmDMQxZ_.js";
2
+ import { n as PreviewView, t as EmbeddedAppView } from "./embedded-app-view-c6-nUY7O.js";
2
3
  export { BRAND_PRISM_THEME, ChangesPane, CodeSurface, CodeView, DiffStatsBadge, DiffView, EmbeddedAppView, FileBreadcrumb, GitStatusBadge, PanelHeader, PillTabs, PreviewView, SandboxArtifactPane, buildUnifiedPatch, computeDiffStats, resolveLanguage };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tangle-network/sandbox-ui",
3
- "version": "0.115.0",
3
+ "version": "0.115.2",
4
4
  "description": "Unified UI component library for Tangle Sandbox — primitives, chat, dashboard, terminal, editor, and workspace components",
5
5
  "repository": {
6
6
  "type": "git",
@@ -42,6 +42,10 @@
42
42
  "import": "./dist/workbench.js",
43
43
  "types": "./dist/workbench.d.ts"
44
44
  },
45
+ "./workbench/embedded-app": {
46
+ "import": "./dist/workbench/embedded-app.js",
47
+ "types": "./dist/workbench/embedded-app.d.ts"
48
+ },
45
49
  "./openui": {
46
50
  "import": "./dist/openui.js",
47
51
  "types": "./dist/openui.d.ts"
@@ -119,8 +123,8 @@
119
123
  "@hocuspocus/provider": ">=2.15.0 <5.0.0",
120
124
  "@nanostores/react": ">=0.8.4 <2.0.0",
121
125
  "@tangle-network/agent-interface": "^1.0.0 || ^2.0.0",
122
- "@tangle-network/brand": "^1.6.0",
123
- "@tangle-network/ui": "^11.10.0",
126
+ "@tangle-network/brand": "^1.8.2",
127
+ "@tangle-network/ui": "^11.11.1",
124
128
  "@tanstack/react-query": "^5.0.0",
125
129
  "@tiptap/core": ">=3.20.4 <4.0.0",
126
130
  "@tiptap/extension-collaboration": ">=3.20.4 <4.0.0",
@@ -203,8 +207,8 @@
203
207
  "@storybook/react-vite": "^10.6.0",
204
208
  "@tailwindcss/postcss": "^4.3.3",
205
209
  "@tangle-network/agent-interface": "2.13.1",
206
- "@tangle-network/brand": "^1.8.0",
207
- "@tangle-network/ui": "^11.10.0",
210
+ "@tangle-network/brand": "^1.8.2",
211
+ "@tangle-network/ui": "^11.11.1",
208
212
  "@tanstack/react-query": "^5.104.0",
209
213
  "@testing-library/dom": "^10.4.2",
210
214
  "@testing-library/jest-dom": "^7.0.1",
@@ -249,6 +253,7 @@
249
253
  "test": "vitest run",
250
254
  "test:package": "node scripts/package-smoke.mjs && PACKAGE_OMIT_OPTIONAL_PEERS='[\"@hocuspocus/provider\",\"@tiptap/core\",\"@tiptap/extension-collaboration\",\"@tiptap/extension-collaboration-caret\",\"@tiptap/react\",\"@tiptap/starter-kit\",\"yjs\"]' node scripts/package-smoke.mjs",
251
255
  "test:watch": "vitest",
256
+ "test:embedded-app-package": "node scripts/embedded-app-package-smoke.mjs",
252
257
  "test:bridge": "pnpm build && vitest run src/__tests__/re-export-identity.test.ts"
253
258
  }
254
259
  }