@mariozechner/pi-web-ui 0.5.44 → 0.5.46
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 +178 -99
- package/dist/ChatPanel.d.ts +15 -10
- package/dist/ChatPanel.d.ts.map +1 -1
- package/dist/ChatPanel.js +68 -100
- package/dist/ChatPanel.js.map +1 -1
- package/dist/{state/agent-session.d.ts → agent/agent.d.ts} +23 -19
- package/dist/agent/agent.d.ts.map +1 -0
- package/dist/{state/agent-session.js → agent/agent.js} +50 -32
- package/dist/agent/agent.js.map +1 -0
- package/dist/{state → agent}/transports/AppTransport.d.ts +1 -3
- package/dist/agent/transports/AppTransport.d.ts.map +1 -0
- package/dist/{state → agent}/transports/AppTransport.js +5 -4
- package/dist/{state → agent}/transports/AppTransport.js.map +1 -1
- package/dist/{state → agent}/transports/ProviderTransport.d.ts +1 -3
- package/dist/agent/transports/ProviderTransport.d.ts.map +1 -0
- package/dist/{state → agent}/transports/ProviderTransport.js +6 -7
- package/dist/agent/transports/ProviderTransport.js.map +1 -0
- package/dist/{state → agent}/transports/index.d.ts.map +1 -1
- package/dist/agent/transports/index.js.map +1 -0
- package/dist/{state → agent}/transports/proxy-types.d.ts.map +1 -1
- package/dist/agent/transports/proxy-types.js.map +1 -0
- package/dist/agent/transports/types.d.ts +12 -0
- package/dist/agent/transports/types.d.ts.map +1 -0
- package/dist/{state → agent}/transports/types.js.map +1 -1
- package/dist/{state → agent}/types.d.ts.map +1 -1
- package/dist/{state → agent}/types.js.map +1 -1
- package/dist/app.css +1 -1
- package/dist/components/AgentInterface.d.ts +7 -4
- package/dist/components/AgentInterface.d.ts.map +1 -1
- package/dist/components/AgentInterface.js +29 -17
- package/dist/components/AgentInterface.js.map +1 -1
- package/dist/components/ConsoleBlock.d.ts +1 -0
- package/dist/components/ConsoleBlock.d.ts.map +1 -1
- package/dist/components/ConsoleBlock.js +7 -1
- package/dist/components/ConsoleBlock.js.map +1 -1
- package/dist/components/ExpandableSection.d.ts +15 -0
- package/dist/components/ExpandableSection.d.ts.map +1 -0
- package/dist/components/ExpandableSection.js +63 -0
- package/dist/components/ExpandableSection.js.map +1 -0
- package/dist/components/MessageEditor.d.ts +8 -1
- package/dist/components/MessageEditor.d.ts.map +1 -1
- package/dist/components/MessageEditor.js +149 -6
- package/dist/components/MessageEditor.js.map +1 -1
- package/dist/components/MessageList.d.ts +3 -2
- package/dist/components/MessageList.d.ts.map +1 -1
- package/dist/components/MessageList.js +14 -1
- package/dist/components/MessageList.js.map +1 -1
- package/dist/components/Messages.d.ts +15 -6
- package/dist/components/Messages.d.ts.map +1 -1
- package/dist/components/Messages.js +17 -83
- package/dist/components/Messages.js.map +1 -1
- package/dist/components/ProviderKeyInput.d.ts.map +1 -1
- package/dist/components/ProviderKeyInput.js +6 -5
- package/dist/components/ProviderKeyInput.js.map +1 -1
- package/dist/components/SandboxedIframe.d.ts +29 -7
- package/dist/components/SandboxedIframe.d.ts.map +1 -1
- package/dist/components/SandboxedIframe.js +350 -282
- package/dist/components/SandboxedIframe.js.map +1 -1
- package/dist/components/message-renderer-registry.d.ts +12 -0
- package/dist/components/message-renderer-registry.d.ts.map +1 -0
- package/dist/components/message-renderer-registry.js +12 -0
- package/dist/components/message-renderer-registry.js.map +1 -0
- package/dist/components/sandbox/ArtifactsRuntimeProvider.d.ts +35 -0
- package/dist/components/sandbox/ArtifactsRuntimeProvider.d.ts.map +1 -0
- package/dist/components/sandbox/ArtifactsRuntimeProvider.js +189 -0
- package/dist/components/sandbox/ArtifactsRuntimeProvider.js.map +1 -0
- package/dist/components/sandbox/AttachmentsRuntimeProvider.d.ts +17 -0
- package/dist/components/sandbox/AttachmentsRuntimeProvider.d.ts.map +1 -0
- package/dist/components/sandbox/AttachmentsRuntimeProvider.js +64 -0
- package/dist/components/sandbox/AttachmentsRuntimeProvider.js.map +1 -0
- package/dist/components/sandbox/ConsoleRuntimeProvider.d.ts +42 -0
- package/dist/components/sandbox/ConsoleRuntimeProvider.d.ts.map +1 -0
- package/dist/components/sandbox/ConsoleRuntimeProvider.js +161 -0
- package/dist/components/sandbox/ConsoleRuntimeProvider.js.map +1 -0
- package/dist/components/sandbox/FileDownloadRuntimeProvider.d.ts +30 -0
- package/dist/components/sandbox/FileDownloadRuntimeProvider.d.ts.map +1 -0
- package/dist/components/sandbox/FileDownloadRuntimeProvider.js +97 -0
- package/dist/components/sandbox/FileDownloadRuntimeProvider.js.map +1 -0
- package/dist/components/sandbox/RuntimeMessageBridge.d.ts +19 -0
- package/dist/components/sandbox/RuntimeMessageBridge.d.ts.map +1 -0
- package/dist/components/sandbox/RuntimeMessageBridge.js +74 -0
- package/dist/components/sandbox/RuntimeMessageBridge.js.map +1 -0
- package/dist/components/sandbox/RuntimeMessageRouter.d.ts +65 -0
- package/dist/components/sandbox/RuntimeMessageRouter.d.ts.map +1 -0
- package/dist/components/sandbox/RuntimeMessageRouter.js +168 -0
- package/dist/components/sandbox/RuntimeMessageRouter.js.map +1 -0
- package/dist/components/sandbox/SandboxRuntimeProvider.d.ts +33 -0
- package/dist/components/sandbox/SandboxRuntimeProvider.d.ts.map +1 -0
- package/dist/components/sandbox/SandboxRuntimeProvider.js +2 -0
- package/dist/components/sandbox/SandboxRuntimeProvider.js.map +1 -0
- package/dist/dialogs/ApiKeyPromptDialog.d.ts.map +1 -1
- package/dist/dialogs/ApiKeyPromptDialog.js +2 -5
- package/dist/dialogs/ApiKeyPromptDialog.js.map +1 -1
- package/dist/dialogs/ModelSelector.js.map +1 -1
- package/dist/dialogs/PersistentStorageDialog.d.ts +17 -0
- package/dist/dialogs/PersistentStorageDialog.d.ts.map +1 -0
- package/dist/dialogs/PersistentStorageDialog.js +144 -0
- package/dist/dialogs/PersistentStorageDialog.js.map +1 -0
- package/dist/dialogs/SessionListDialog.d.ts +19 -0
- package/dist/dialogs/SessionListDialog.d.ts.map +1 -0
- package/dist/dialogs/SessionListDialog.js +152 -0
- package/dist/dialogs/SessionListDialog.js.map +1 -0
- package/dist/dialogs/SettingsDialog.d.ts.map +1 -1
- package/dist/dialogs/SettingsDialog.js +1 -0
- package/dist/dialogs/SettingsDialog.js.map +1 -1
- package/dist/index.d.ts +34 -16
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +32 -14
- package/dist/index.js.map +1 -1
- package/dist/prompts/prompts.d.ts +11 -0
- package/dist/prompts/prompts.d.ts.map +1 -0
- package/dist/prompts/prompts.js +272 -0
- package/dist/prompts/prompts.js.map +1 -0
- package/dist/storage/app-storage.d.ts +17 -12
- package/dist/storage/app-storage.d.ts.map +1 -1
- package/dist/storage/app-storage.js +13 -20
- package/dist/storage/app-storage.js.map +1 -1
- package/dist/storage/backends/indexeddb-storage-backend.d.ts +27 -0
- package/dist/storage/backends/indexeddb-storage-backend.d.ts.map +1 -0
- package/dist/storage/backends/indexeddb-storage-backend.js +166 -0
- package/dist/storage/backends/indexeddb-storage-backend.js.map +1 -0
- package/dist/storage/store.d.ts +23 -0
- package/dist/storage/store.d.ts.map +1 -0
- package/dist/storage/store.js +26 -0
- package/dist/storage/store.js.map +1 -0
- package/dist/storage/stores/provider-keys-store.d.ts +14 -0
- package/dist/storage/stores/provider-keys-store.d.ts.map +1 -0
- package/dist/storage/stores/provider-keys-store.js +27 -0
- package/dist/storage/stores/provider-keys-store.js.map +1 -0
- package/dist/storage/stores/sessions-store.d.ts +31 -0
- package/dist/storage/stores/sessions-store.d.ts.map +1 -0
- package/dist/storage/stores/sessions-store.js +113 -0
- package/dist/storage/stores/sessions-store.js.map +1 -0
- package/dist/storage/stores/settings-store.d.ts +14 -0
- package/dist/storage/stores/settings-store.d.ts.map +1 -0
- package/dist/storage/stores/settings-store.js +28 -0
- package/dist/storage/stores/settings-store.js.map +1 -0
- package/dist/storage/types.d.ts +156 -22
- package/dist/storage/types.d.ts.map +1 -1
- package/dist/tools/artifacts/ArtifactElement.d.ts +0 -1
- package/dist/tools/artifacts/ArtifactElement.d.ts.map +1 -1
- package/dist/tools/artifacts/ArtifactElement.js +0 -1
- package/dist/tools/artifacts/ArtifactElement.js.map +1 -1
- package/dist/tools/artifacts/ArtifactPill.d.ts +4 -0
- package/dist/tools/artifacts/ArtifactPill.d.ts.map +1 -0
- package/dist/tools/artifacts/ArtifactPill.js +22 -0
- package/dist/tools/artifacts/ArtifactPill.js.map +1 -0
- package/dist/tools/artifacts/Console.d.ts +18 -0
- package/dist/tools/artifacts/Console.d.ts.map +1 -0
- package/dist/tools/artifacts/Console.js +95 -0
- package/dist/tools/artifacts/Console.js.map +1 -0
- package/dist/tools/artifacts/DocxArtifact.d.ts +22 -0
- package/dist/tools/artifacts/DocxArtifact.d.ts.map +1 -0
- package/dist/tools/artifacts/DocxArtifact.js +208 -0
- package/dist/tools/artifacts/DocxArtifact.js.map +1 -0
- package/dist/tools/artifacts/ExcelArtifact.d.ts +24 -0
- package/dist/tools/artifacts/ExcelArtifact.d.ts.map +1 -0
- package/dist/tools/artifacts/ExcelArtifact.js +216 -0
- package/dist/tools/artifacts/ExcelArtifact.js.map +1 -0
- package/dist/tools/artifacts/GenericArtifact.d.ts +19 -0
- package/dist/tools/artifacts/GenericArtifact.d.ts.map +1 -0
- package/dist/tools/artifacts/GenericArtifact.js +117 -0
- package/dist/tools/artifacts/GenericArtifact.js.map +1 -0
- package/dist/tools/artifacts/HtmlArtifact.d.ts +8 -11
- package/dist/tools/artifacts/HtmlArtifact.d.ts.map +1 -1
- package/dist/tools/artifacts/HtmlArtifact.js +56 -88
- package/dist/tools/artifacts/HtmlArtifact.js.map +1 -1
- package/dist/tools/artifacts/ImageArtifact.d.ts +20 -0
- package/dist/tools/artifacts/ImageArtifact.d.ts.map +1 -0
- package/dist/tools/artifacts/ImageArtifact.js +120 -0
- package/dist/tools/artifacts/ImageArtifact.js.map +1 -0
- package/dist/tools/artifacts/MarkdownArtifact.d.ts +0 -1
- package/dist/tools/artifacts/MarkdownArtifact.d.ts.map +1 -1
- package/dist/tools/artifacts/MarkdownArtifact.js +0 -4
- package/dist/tools/artifacts/MarkdownArtifact.js.map +1 -1
- package/dist/tools/artifacts/PdfArtifact.d.ts +25 -0
- package/dist/tools/artifacts/PdfArtifact.d.ts.map +1 -0
- package/dist/tools/artifacts/PdfArtifact.js +184 -0
- package/dist/tools/artifacts/PdfArtifact.js.map +1 -0
- package/dist/tools/artifacts/SvgArtifact.d.ts +0 -1
- package/dist/tools/artifacts/SvgArtifact.d.ts.map +1 -1
- package/dist/tools/artifacts/SvgArtifact.js +0 -4
- package/dist/tools/artifacts/SvgArtifact.js.map +1 -1
- package/dist/tools/artifacts/TextArtifact.d.ts +0 -1
- package/dist/tools/artifacts/TextArtifact.d.ts.map +1 -1
- package/dist/tools/artifacts/TextArtifact.js +0 -4
- package/dist/tools/artifacts/TextArtifact.js.map +1 -1
- package/dist/tools/artifacts/artifacts-tool-renderer.d.ts +11 -0
- package/dist/tools/artifacts/artifacts-tool-renderer.d.ts.map +1 -0
- package/dist/tools/artifacts/artifacts-tool-renderer.js +262 -0
- package/dist/tools/artifacts/artifacts-tool-renderer.js.map +1 -0
- package/dist/tools/artifacts/artifacts.d.ts +10 -13
- package/dist/tools/artifacts/artifacts.d.ts.map +1 -1
- package/dist/tools/artifacts/artifacts.js +166 -344
- package/dist/tools/artifacts/artifacts.js.map +1 -1
- package/dist/tools/artifacts/index.d.ts +1 -0
- package/dist/tools/artifacts/index.d.ts.map +1 -1
- package/dist/tools/artifacts/index.js +1 -0
- package/dist/tools/artifacts/index.js.map +1 -1
- package/dist/tools/extract-document.d.ts +24 -0
- package/dist/tools/extract-document.d.ts.map +1 -0
- package/dist/tools/extract-document.js +193 -0
- package/dist/tools/extract-document.js.map +1 -0
- package/dist/tools/index.d.ts +9 -7
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +17 -13
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/javascript-repl.d.ts +16 -15
- package/dist/tools/javascript-repl.d.ts.map +1 -1
- package/dist/tools/javascript-repl.js +101 -133
- package/dist/tools/javascript-repl.js.map +1 -1
- package/dist/tools/renderer-registry.d.ts +12 -0
- package/dist/tools/renderer-registry.d.ts.map +1 -1
- package/dist/tools/renderer-registry.js +78 -0
- package/dist/tools/renderer-registry.js.map +1 -1
- package/dist/tools/renderers/BashRenderer.d.ts +2 -4
- package/dist/tools/renderers/BashRenderer.d.ts.map +1 -1
- package/dist/tools/renderers/BashRenderer.js +30 -26
- package/dist/tools/renderers/BashRenderer.js.map +1 -1
- package/dist/tools/renderers/CalculateRenderer.d.ts +2 -4
- package/dist/tools/renderers/CalculateRenderer.d.ts.map +1 -1
- package/dist/tools/renderers/CalculateRenderer.js +32 -28
- package/dist/tools/renderers/CalculateRenderer.js.map +1 -1
- package/dist/tools/renderers/DefaultRenderer.d.ts +2 -4
- package/dist/tools/renderers/DefaultRenderer.d.ts.map +1 -1
- package/dist/tools/renderers/DefaultRenderer.js +78 -18
- package/dist/tools/renderers/DefaultRenderer.js.map +1 -1
- package/dist/tools/renderers/GetCurrentTimeRenderer.d.ts +2 -4
- package/dist/tools/renderers/GetCurrentTimeRenderer.d.ts.map +1 -1
- package/dist/tools/renderers/GetCurrentTimeRenderer.js +57 -21
- package/dist/tools/renderers/GetCurrentTimeRenderer.js.map +1 -1
- package/dist/tools/types.d.ts +5 -2
- package/dist/tools/types.d.ts.map +1 -1
- package/dist/utils/i18n.d.ts +424 -1
- package/dist/utils/i18n.d.ts.map +1 -1
- package/dist/utils/i18n.js +131 -7
- package/dist/utils/i18n.js.map +1 -1
- package/example/package.json +2 -1
- package/example/src/custom-messages.ts +112 -0
- package/example/src/main.ts +391 -38
- package/package.json +48 -43
- package/scripts/count-prompt-tokens.ts +88 -0
- package/src/ChatPanel.ts +93 -101
- package/src/{state/agent-session.ts → agent/agent.ts} +80 -55
- package/src/{state → agent}/transports/AppTransport.ts +6 -6
- package/src/{state → agent}/transports/ProviderTransport.ts +13 -7
- package/src/{state → agent}/transports/types.ts +8 -2
- package/src/components/AgentInterface.ts +32 -16
- package/src/components/ConsoleBlock.ts +5 -1
- package/src/components/ExpandableSection.ts +46 -0
- package/src/components/MessageEditor.ts +159 -5
- package/src/components/MessageList.ts +18 -3
- package/src/components/Messages.ts +48 -89
- package/src/components/ProviderKeyInput.ts +6 -5
- package/src/components/SandboxedIframe.ts +412 -321
- package/src/components/message-renderer-registry.ts +28 -0
- package/src/components/sandbox/ArtifactsRuntimeProvider.ts +219 -0
- package/src/components/sandbox/AttachmentsRuntimeProvider.ts +66 -0
- package/src/components/sandbox/ConsoleRuntimeProvider.ts +187 -0
- package/src/components/sandbox/FileDownloadRuntimeProvider.ts +110 -0
- package/src/components/sandbox/RuntimeMessageBridge.ts +82 -0
- package/src/components/sandbox/RuntimeMessageRouter.ts +216 -0
- package/src/components/sandbox/SandboxRuntimeProvider.ts +35 -0
- package/src/dialogs/ApiKeyPromptDialog.ts +2 -5
- package/src/dialogs/ModelSelector.ts +2 -2
- package/src/dialogs/PersistentStorageDialog.ts +141 -0
- package/src/dialogs/SessionListDialog.ts +148 -0
- package/src/dialogs/SettingsDialog.ts +1 -0
- package/src/index.ts +61 -20
- package/src/prompts/prompts.ts +282 -0
- package/src/storage/app-storage.ts +27 -24
- package/src/storage/backends/indexeddb-storage-backend.ts +193 -0
- package/src/storage/store.ts +33 -0
- package/src/storage/stores/provider-keys-store.ts +33 -0
- package/src/storage/stores/sessions-store.ts +130 -0
- package/src/storage/stores/settings-store.ts +34 -0
- package/src/storage/types.ts +182 -22
- package/src/tools/artifacts/ArtifactElement.ts +0 -1
- package/src/tools/artifacts/ArtifactPill.ts +25 -0
- package/src/tools/artifacts/Console.ts +93 -0
- package/src/tools/artifacts/DocxArtifact.ts +213 -0
- package/src/tools/artifacts/ExcelArtifact.ts +231 -0
- package/src/tools/artifacts/GenericArtifact.ts +117 -0
- package/src/tools/artifacts/HtmlArtifact.ts +64 -94
- package/src/tools/artifacts/ImageArtifact.ts +116 -0
- package/src/tools/artifacts/MarkdownArtifact.ts +0 -1
- package/src/tools/artifacts/PdfArtifact.ts +201 -0
- package/src/tools/artifacts/SvgArtifact.ts +0 -1
- package/src/tools/artifacts/TextArtifact.ts +0 -1
- package/src/tools/artifacts/artifacts-tool-renderer.ts +298 -0
- package/src/tools/artifacts/artifacts.ts +190 -366
- package/src/tools/artifacts/index.ts +1 -0
- package/src/tools/extract-document.ts +250 -0
- package/src/tools/index.ts +25 -14
- package/src/tools/javascript-repl.ts +138 -160
- package/src/tools/renderer-registry.ts +98 -0
- package/src/tools/renderers/BashRenderer.ts +33 -30
- package/src/tools/renderers/CalculateRenderer.ts +36 -31
- package/src/tools/renderers/DefaultRenderer.ts +84 -21
- package/src/tools/renderers/GetCurrentTimeRenderer.ts +68 -23
- package/src/tools/types.ts +10 -2
- package/src/utils/i18n.ts +203 -8
- package/dist/state/agent-session.d.ts.map +0 -1
- package/dist/state/agent-session.js.map +0 -1
- package/dist/state/transports/AppTransport.d.ts.map +0 -1
- package/dist/state/transports/ProviderTransport.d.ts.map +0 -1
- package/dist/state/transports/ProviderTransport.js.map +0 -1
- package/dist/state/transports/index.js.map +0 -1
- package/dist/state/transports/proxy-types.js.map +0 -1
- package/dist/state/transports/types.d.ts +0 -11
- package/dist/state/transports/types.d.ts.map +0 -1
- package/dist/storage/backends/chrome-storage-backend.d.ts +0 -18
- package/dist/storage/backends/chrome-storage-backend.d.ts.map +0 -1
- package/dist/storage/backends/chrome-storage-backend.js +0 -67
- package/dist/storage/backends/chrome-storage-backend.js.map +0 -1
- package/dist/storage/backends/indexeddb-backend.d.ts +0 -20
- package/dist/storage/backends/indexeddb-backend.d.ts.map +0 -1
- package/dist/storage/backends/indexeddb-backend.js +0 -89
- package/dist/storage/backends/indexeddb-backend.js.map +0 -1
- package/dist/storage/backends/local-storage-backend.d.ts +0 -18
- package/dist/storage/backends/local-storage-backend.d.ts.map +0 -1
- package/dist/storage/backends/local-storage-backend.js +0 -69
- package/dist/storage/backends/local-storage-backend.js.map +0 -1
- package/dist/storage/repositories/provider-keys-repository.d.ts +0 -34
- package/dist/storage/repositories/provider-keys-repository.d.ts.map +0 -1
- package/dist/storage/repositories/provider-keys-repository.js +0 -50
- package/dist/storage/repositories/provider-keys-repository.js.map +0 -1
- package/dist/storage/repositories/settings-repository.d.ts +0 -34
- package/dist/storage/repositories/settings-repository.d.ts.map +0 -1
- package/dist/storage/repositories/settings-repository.js +0 -46
- package/dist/storage/repositories/settings-repository.js.map +0 -1
- package/src/storage/backends/chrome-storage-backend.ts +0 -82
- package/src/storage/backends/indexeddb-backend.ts +0 -107
- package/src/storage/backends/local-storage-backend.ts +0 -74
- package/src/storage/repositories/provider-keys-repository.ts +0 -55
- package/src/storage/repositories/settings-repository.ts +0 -51
- /package/dist/{state → agent}/transports/index.d.ts +0 -0
- /package/dist/{state → agent}/transports/index.js +0 -0
- /package/dist/{state → agent}/transports/proxy-types.d.ts +0 -0
- /package/dist/{state → agent}/transports/proxy-types.js +0 -0
- /package/dist/{state → agent}/transports/types.js +0 -0
- /package/dist/{state → agent}/types.d.ts +0 -0
- /package/dist/{state → agent}/types.js +0 -0
- /package/src/{state → agent}/transports/index.ts +0 -0
- /package/src/{state → agent}/transports/proxy-types.ts +0 -0
- /package/src/{state → agent}/types.ts +0 -0
|
@@ -6,6 +6,17 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
6
6
|
};
|
|
7
7
|
import { LitElement } from "lit";
|
|
8
8
|
import { customElement, property } from "lit/decorators.js";
|
|
9
|
+
import { ConsoleRuntimeProvider } from "./sandbox/ConsoleRuntimeProvider.js";
|
|
10
|
+
import { RuntimeMessageBridge } from "./sandbox/RuntimeMessageBridge.js";
|
|
11
|
+
import { RUNTIME_MESSAGE_ROUTER } from "./sandbox/RuntimeMessageRouter.js";
|
|
12
|
+
/**
|
|
13
|
+
* Escape HTML special sequences in code to prevent premature tag closure
|
|
14
|
+
* @param code Code that will be injected into <script> tags
|
|
15
|
+
* @returns Escaped code safe for injection
|
|
16
|
+
*/
|
|
17
|
+
function escapeScriptContent(code) {
|
|
18
|
+
return code.replace(/<\/script/gi, "<\\/script");
|
|
19
|
+
}
|
|
9
20
|
let SandboxIframe = class SandboxIframe extends LitElement {
|
|
10
21
|
createRenderRoot() {
|
|
11
22
|
return this;
|
|
@@ -15,199 +26,314 @@ let SandboxIframe = class SandboxIframe extends LitElement {
|
|
|
15
26
|
}
|
|
16
27
|
disconnectedCallback() {
|
|
17
28
|
super.disconnectedCallback();
|
|
29
|
+
// Note: We don't unregister the sandbox here for loadContent() mode
|
|
30
|
+
// because the caller (HtmlArtifact) owns the sandbox lifecycle.
|
|
31
|
+
// For execute() mode, the sandbox is unregistered in the cleanup function.
|
|
18
32
|
this.iframe?.remove();
|
|
19
33
|
}
|
|
20
34
|
/**
|
|
21
35
|
* Load HTML content into sandbox and keep it displayed (for HTML artifacts)
|
|
22
36
|
* @param sandboxId Unique ID
|
|
23
37
|
* @param htmlContent Full HTML content
|
|
24
|
-
* @param
|
|
38
|
+
* @param providers Runtime providers to inject
|
|
39
|
+
* @param consumers Message consumers to register (optional)
|
|
25
40
|
*/
|
|
26
|
-
loadContent(sandboxId, htmlContent,
|
|
27
|
-
|
|
41
|
+
loadContent(sandboxId, htmlContent, providers = [], consumers = []) {
|
|
42
|
+
// Unregister previous sandbox if exists
|
|
43
|
+
try {
|
|
44
|
+
RUNTIME_MESSAGE_ROUTER.unregisterSandbox(sandboxId);
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
// Sandbox might not exist, that's ok
|
|
48
|
+
}
|
|
49
|
+
providers = [new ConsoleRuntimeProvider(), ...providers];
|
|
50
|
+
RUNTIME_MESSAGE_ROUTER.registerSandbox(sandboxId, providers, consumers);
|
|
51
|
+
// loadContent is always used for HTML artifacts (not standalone)
|
|
52
|
+
const completeHtml = this.prepareHtmlDocument(sandboxId, htmlContent, providers, {
|
|
53
|
+
isHtmlArtifact: true,
|
|
54
|
+
isStandalone: false,
|
|
55
|
+
});
|
|
56
|
+
// Validate HTML before loading
|
|
57
|
+
const validationError = this.validateHtml(completeHtml);
|
|
58
|
+
if (validationError) {
|
|
59
|
+
console.error("HTML validation failed:", validationError);
|
|
60
|
+
// Show error in iframe instead of crashing
|
|
61
|
+
this.iframe?.remove();
|
|
62
|
+
this.iframe = document.createElement("iframe");
|
|
63
|
+
this.iframe.style.cssText = "width: 100%; height: 100%; border: none;";
|
|
64
|
+
this.iframe.srcdoc = `
|
|
65
|
+
<html>
|
|
66
|
+
<body style="font-family: monospace; padding: 20px; background: #fff; color: #000;">
|
|
67
|
+
<h3 style="color: #c00;">HTML Validation Error</h3>
|
|
68
|
+
<pre style="background: #f5f5f5; padding: 10px; border-radius: 4px; overflow-x: auto; white-space: pre-wrap;">${validationError}</pre>
|
|
69
|
+
</body>
|
|
70
|
+
</html>
|
|
71
|
+
`;
|
|
72
|
+
this.appendChild(this.iframe);
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
// Remove previous iframe if exists
|
|
76
|
+
this.iframe?.remove();
|
|
28
77
|
if (this.sandboxUrlProvider) {
|
|
29
78
|
// Browser extension mode: use sandbox.html with postMessage
|
|
30
|
-
this.loadViaSandboxUrl(sandboxId, completeHtml
|
|
79
|
+
this.loadViaSandboxUrl(sandboxId, completeHtml);
|
|
31
80
|
}
|
|
32
81
|
else {
|
|
33
82
|
// Web mode: use srcdoc
|
|
34
|
-
this.loadViaSrcdoc(completeHtml);
|
|
83
|
+
this.loadViaSrcdoc(sandboxId, completeHtml);
|
|
35
84
|
}
|
|
36
85
|
}
|
|
37
|
-
loadViaSandboxUrl(sandboxId, completeHtml
|
|
38
|
-
//
|
|
86
|
+
loadViaSandboxUrl(sandboxId, completeHtml) {
|
|
87
|
+
// Create iframe pointing to sandbox URL
|
|
88
|
+
this.iframe = document.createElement("iframe");
|
|
89
|
+
this.iframe.sandbox.add("allow-scripts");
|
|
90
|
+
this.iframe.sandbox.add("allow-modals");
|
|
91
|
+
this.iframe.style.width = "100%";
|
|
92
|
+
this.iframe.style.height = "100%";
|
|
93
|
+
this.iframe.style.border = "none";
|
|
94
|
+
this.iframe.src = this.sandboxUrlProvider();
|
|
95
|
+
// Update router with iframe reference BEFORE appending to DOM
|
|
96
|
+
RUNTIME_MESSAGE_ROUTER.setSandboxIframe(sandboxId, this.iframe);
|
|
97
|
+
// Listen for open-external-url messages from iframe
|
|
98
|
+
const externalUrlHandler = (e) => {
|
|
99
|
+
if (e.data.type === "open-external-url" && e.source === this.iframe?.contentWindow) {
|
|
100
|
+
// Use chrome.tabs API to open in new tab
|
|
101
|
+
const chromeAPI = globalThis.chrome;
|
|
102
|
+
if (chromeAPI?.tabs) {
|
|
103
|
+
chromeAPI.tabs.create({ url: e.data.url });
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
// Fallback for non-extension context
|
|
107
|
+
window.open(e.data.url, "_blank");
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
window.addEventListener("message", externalUrlHandler);
|
|
112
|
+
// Listen for sandbox-ready and sandbox-error messages directly
|
|
39
113
|
const readyHandler = (e) => {
|
|
40
114
|
if (e.data.type === "sandbox-ready" && e.source === this.iframe?.contentWindow) {
|
|
41
115
|
window.removeEventListener("message", readyHandler);
|
|
116
|
+
window.removeEventListener("message", errorHandler);
|
|
117
|
+
// Send content to sandbox
|
|
42
118
|
this.iframe?.contentWindow?.postMessage({
|
|
43
119
|
type: "sandbox-load",
|
|
44
120
|
sandboxId,
|
|
45
121
|
code: completeHtml,
|
|
46
|
-
|
|
122
|
+
}, "*");
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
const errorHandler = (e) => {
|
|
126
|
+
if (e.data.type === "sandbox-error" && e.source === this.iframe?.contentWindow) {
|
|
127
|
+
window.removeEventListener("message", readyHandler);
|
|
128
|
+
window.removeEventListener("message", errorHandler);
|
|
129
|
+
// The sandbox.js already sent us the error via postMessage.
|
|
130
|
+
// We need to convert it to an execution-error message that the execute() consumer will handle.
|
|
131
|
+
// Simulate receiving an execution-error from the sandbox
|
|
132
|
+
window.postMessage({
|
|
133
|
+
sandboxId: sandboxId,
|
|
134
|
+
type: "execution-error",
|
|
135
|
+
error: { message: e.data.error, stack: e.data.stack },
|
|
47
136
|
}, "*");
|
|
48
137
|
}
|
|
49
138
|
};
|
|
50
139
|
window.addEventListener("message", readyHandler);
|
|
51
|
-
|
|
52
|
-
this.iframe?.remove();
|
|
53
|
-
this.iframe = document.createElement("iframe");
|
|
54
|
-
this.iframe.sandbox.add("allow-scripts");
|
|
55
|
-
this.iframe.sandbox.add("allow-modals");
|
|
56
|
-
this.iframe.style.width = "100%";
|
|
57
|
-
this.iframe.style.height = "100%";
|
|
58
|
-
this.iframe.style.border = "none";
|
|
59
|
-
this.iframe.src = this.sandboxUrlProvider();
|
|
140
|
+
window.addEventListener("message", errorHandler);
|
|
60
141
|
this.appendChild(this.iframe);
|
|
61
142
|
}
|
|
62
|
-
loadViaSrcdoc(completeHtml) {
|
|
63
|
-
//
|
|
64
|
-
this.iframe?.remove();
|
|
143
|
+
loadViaSrcdoc(sandboxId, completeHtml) {
|
|
144
|
+
// Create iframe with srcdoc
|
|
65
145
|
this.iframe = document.createElement("iframe");
|
|
66
146
|
this.iframe.sandbox.add("allow-scripts");
|
|
67
147
|
this.iframe.sandbox.add("allow-modals");
|
|
68
148
|
this.iframe.style.width = "100%";
|
|
69
149
|
this.iframe.style.height = "100%";
|
|
70
150
|
this.iframe.style.border = "none";
|
|
71
|
-
// Set content directly via srcdoc (no CSP restrictions in web apps)
|
|
72
151
|
this.iframe.srcdoc = completeHtml;
|
|
152
|
+
// Update router with iframe reference BEFORE appending to DOM
|
|
153
|
+
RUNTIME_MESSAGE_ROUTER.setSandboxIframe(sandboxId, this.iframe);
|
|
154
|
+
// Listen for open-external-url messages from iframe
|
|
155
|
+
const externalUrlHandler = (e) => {
|
|
156
|
+
if (e.data.type === "open-external-url" && e.source === this.iframe?.contentWindow) {
|
|
157
|
+
// Fallback for non-extension context
|
|
158
|
+
window.open(e.data.url, "_blank");
|
|
159
|
+
}
|
|
160
|
+
};
|
|
161
|
+
window.addEventListener("message", externalUrlHandler);
|
|
73
162
|
this.appendChild(this.iframe);
|
|
74
163
|
}
|
|
75
164
|
/**
|
|
76
165
|
* Execute code in sandbox
|
|
77
166
|
* @param sandboxId Unique ID for this execution
|
|
78
167
|
* @param code User code (plain JS for REPL, or full HTML for artifacts)
|
|
79
|
-
* @param
|
|
168
|
+
* @param providers Runtime providers to inject
|
|
169
|
+
* @param consumers Additional message consumers (optional, execute has its own internal consumer)
|
|
80
170
|
* @param signal Abort signal
|
|
81
171
|
* @returns Promise resolving to execution result
|
|
82
172
|
*/
|
|
83
|
-
async execute(sandboxId, code,
|
|
173
|
+
async execute(sandboxId, code, providers = [], consumers = [], signal, isHtmlArtifact = false) {
|
|
84
174
|
if (signal?.aborted) {
|
|
85
175
|
throw new Error("Execution aborted");
|
|
86
176
|
}
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
177
|
+
const consoleProvider = new ConsoleRuntimeProvider();
|
|
178
|
+
providers = [consoleProvider, ...providers];
|
|
179
|
+
RUNTIME_MESSAGE_ROUTER.registerSandbox(sandboxId, providers, consumers);
|
|
180
|
+
const files = [];
|
|
181
|
+
let completed = false;
|
|
90
182
|
return new Promise((resolve, reject) => {
|
|
91
|
-
|
|
92
|
-
const
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
files: files,
|
|
118
|
-
});
|
|
119
|
-
}
|
|
120
|
-
else if (e.data.type === "execution-error") {
|
|
121
|
-
completed = true;
|
|
122
|
-
cleanup();
|
|
123
|
-
resolve({
|
|
124
|
-
success: false,
|
|
125
|
-
console: logs,
|
|
126
|
-
error: e.data.error,
|
|
127
|
-
files,
|
|
128
|
-
});
|
|
129
|
-
}
|
|
183
|
+
// 4. Create execution consumer for lifecycle messages
|
|
184
|
+
const executionConsumer = {
|
|
185
|
+
async handleMessage(message) {
|
|
186
|
+
if (message.type === "file-returned") {
|
|
187
|
+
files.push({
|
|
188
|
+
fileName: message.fileName,
|
|
189
|
+
content: message.content,
|
|
190
|
+
mimeType: message.mimeType,
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
else if (message.type === "execution-complete") {
|
|
194
|
+
completed = true;
|
|
195
|
+
cleanup();
|
|
196
|
+
resolve({
|
|
197
|
+
success: true,
|
|
198
|
+
console: consoleProvider.getLogs(),
|
|
199
|
+
files,
|
|
200
|
+
returnValue: message.returnValue,
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
else if (message.type === "execution-error") {
|
|
204
|
+
completed = true;
|
|
205
|
+
cleanup();
|
|
206
|
+
resolve({ success: false, console: consoleProvider.getLogs(), error: message.error, files });
|
|
207
|
+
}
|
|
208
|
+
},
|
|
130
209
|
};
|
|
210
|
+
RUNTIME_MESSAGE_ROUTER.addConsumer(sandboxId, executionConsumer);
|
|
211
|
+
const cleanup = () => {
|
|
212
|
+
RUNTIME_MESSAGE_ROUTER.unregisterSandbox(sandboxId);
|
|
213
|
+
signal?.removeEventListener("abort", abortHandler);
|
|
214
|
+
clearTimeout(timeoutId);
|
|
215
|
+
this.iframe?.remove();
|
|
216
|
+
this.iframe = undefined;
|
|
217
|
+
};
|
|
218
|
+
// Abort handler
|
|
131
219
|
const abortHandler = () => {
|
|
132
220
|
if (!completed) {
|
|
221
|
+
completed = true;
|
|
133
222
|
cleanup();
|
|
134
223
|
reject(new Error("Execution aborted"));
|
|
135
224
|
}
|
|
136
225
|
};
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
if (readyHandler) {
|
|
142
|
-
window.removeEventListener("message", readyHandler);
|
|
143
|
-
}
|
|
144
|
-
clearTimeout(timeoutId);
|
|
145
|
-
};
|
|
146
|
-
// Set up listeners BEFORE creating iframe
|
|
147
|
-
window.addEventListener("message", messageHandler);
|
|
148
|
-
signal?.addEventListener("abort", abortHandler);
|
|
149
|
-
// Timeout after 30 seconds
|
|
226
|
+
if (signal) {
|
|
227
|
+
signal.addEventListener("abort", abortHandler);
|
|
228
|
+
}
|
|
229
|
+
// Timeout handler (30 seconds)
|
|
150
230
|
const timeoutId = setTimeout(() => {
|
|
151
231
|
if (!completed) {
|
|
232
|
+
completed = true;
|
|
152
233
|
cleanup();
|
|
153
234
|
resolve({
|
|
154
235
|
success: false,
|
|
155
|
-
|
|
156
|
-
|
|
236
|
+
console: consoleProvider.getLogs(),
|
|
237
|
+
error: { message: "Execution timeout (120s)", stack: "" },
|
|
157
238
|
files,
|
|
158
239
|
});
|
|
159
240
|
}
|
|
160
|
-
},
|
|
241
|
+
}, 120000);
|
|
242
|
+
// 4. Prepare HTML and create iframe
|
|
243
|
+
const completeHtml = this.prepareHtmlDocument(sandboxId, code, providers, {
|
|
244
|
+
isHtmlArtifact,
|
|
245
|
+
isStandalone: false,
|
|
246
|
+
});
|
|
247
|
+
// 5. Validate HTML before sending to sandbox
|
|
248
|
+
const validationError = this.validateHtml(completeHtml);
|
|
249
|
+
if (validationError) {
|
|
250
|
+
reject(new Error(`HTML validation failed: ${validationError}`));
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
161
253
|
if (this.sandboxUrlProvider) {
|
|
162
|
-
// Browser extension mode: wait for sandbox-ready
|
|
163
|
-
|
|
254
|
+
// Browser extension mode: wait for sandbox-ready
|
|
255
|
+
this.iframe = document.createElement("iframe");
|
|
256
|
+
this.iframe.sandbox.add("allow-scripts", "allow-modals");
|
|
257
|
+
this.iframe.style.cssText = "width: 100%; height: 100%; border: none;";
|
|
258
|
+
this.iframe.src = this.sandboxUrlProvider();
|
|
259
|
+
// Update router with iframe reference BEFORE appending to DOM
|
|
260
|
+
RUNTIME_MESSAGE_ROUTER.setSandboxIframe(sandboxId, this.iframe);
|
|
261
|
+
// Listen for sandbox-ready and sandbox-error messages
|
|
262
|
+
const readyHandler = (e) => {
|
|
164
263
|
if (e.data.type === "sandbox-ready" && e.source === this.iframe?.contentWindow) {
|
|
165
264
|
window.removeEventListener("message", readyHandler);
|
|
166
|
-
|
|
265
|
+
window.removeEventListener("message", errorHandler);
|
|
266
|
+
// Send content to sandbox
|
|
167
267
|
this.iframe?.contentWindow?.postMessage({
|
|
168
268
|
type: "sandbox-load",
|
|
169
269
|
sandboxId,
|
|
170
270
|
code: completeHtml,
|
|
171
|
-
|
|
271
|
+
}, "*");
|
|
272
|
+
}
|
|
273
|
+
};
|
|
274
|
+
const errorHandler = (e) => {
|
|
275
|
+
if (e.data.type === "sandbox-error" && e.source === this.iframe?.contentWindow) {
|
|
276
|
+
window.removeEventListener("message", readyHandler);
|
|
277
|
+
window.removeEventListener("message", errorHandler);
|
|
278
|
+
// Convert sandbox-error to execution-error for the execution consumer
|
|
279
|
+
window.postMessage({
|
|
280
|
+
sandboxId: sandboxId,
|
|
281
|
+
type: "execution-error",
|
|
282
|
+
error: { message: e.data.error, stack: e.data.stack },
|
|
172
283
|
}, "*");
|
|
173
284
|
}
|
|
174
285
|
};
|
|
175
286
|
window.addEventListener("message", readyHandler);
|
|
176
|
-
|
|
177
|
-
this.iframe?.remove();
|
|
178
|
-
this.iframe = document.createElement("iframe");
|
|
179
|
-
this.iframe.sandbox.add("allow-scripts");
|
|
180
|
-
this.iframe.sandbox.add("allow-modals");
|
|
181
|
-
this.iframe.style.width = "100%";
|
|
182
|
-
this.iframe.style.height = "100%";
|
|
183
|
-
this.iframe.style.border = "none";
|
|
184
|
-
this.iframe.src = this.sandboxUrlProvider();
|
|
287
|
+
window.addEventListener("message", errorHandler);
|
|
185
288
|
this.appendChild(this.iframe);
|
|
186
289
|
}
|
|
187
290
|
else {
|
|
188
291
|
// Web mode: use srcdoc
|
|
189
|
-
this.iframe?.remove();
|
|
190
292
|
this.iframe = document.createElement("iframe");
|
|
191
|
-
this.iframe.sandbox.add("allow-scripts");
|
|
192
|
-
this.iframe.
|
|
193
|
-
this.iframe.style.width = "100%";
|
|
194
|
-
this.iframe.style.height = "100%";
|
|
195
|
-
this.iframe.style.border = "none";
|
|
196
|
-
// Set content via srcdoc BEFORE appending to DOM
|
|
293
|
+
this.iframe.sandbox.add("allow-scripts", "allow-modals");
|
|
294
|
+
this.iframe.style.cssText = "width: 100%; height: 100%; border: none; display: none;";
|
|
197
295
|
this.iframe.srcdoc = completeHtml;
|
|
296
|
+
// Update router with iframe reference BEFORE appending to DOM
|
|
297
|
+
RUNTIME_MESSAGE_ROUTER.setSandboxIframe(sandboxId, this.iframe);
|
|
198
298
|
this.appendChild(this.iframe);
|
|
199
299
|
}
|
|
200
300
|
});
|
|
201
301
|
}
|
|
302
|
+
/**
|
|
303
|
+
* Validate HTML using DOMParser - returns error message if invalid, null if valid
|
|
304
|
+
* Note: JavaScript syntax validation is done in sandbox.js to avoid CSP restrictions
|
|
305
|
+
*/
|
|
306
|
+
validateHtml(html) {
|
|
307
|
+
try {
|
|
308
|
+
const parser = new DOMParser();
|
|
309
|
+
const doc = parser.parseFromString(html, "text/html");
|
|
310
|
+
// Check for parser errors
|
|
311
|
+
const parserError = doc.querySelector("parsererror");
|
|
312
|
+
if (parserError) {
|
|
313
|
+
return parserError.textContent || "Unknown parse error";
|
|
314
|
+
}
|
|
315
|
+
return null;
|
|
316
|
+
}
|
|
317
|
+
catch (error) {
|
|
318
|
+
return error.message || "Unknown validation error";
|
|
319
|
+
}
|
|
320
|
+
}
|
|
202
321
|
/**
|
|
203
322
|
* Prepare complete HTML document with runtime + user code
|
|
323
|
+
* PUBLIC so HtmlArtifact can use it for download button
|
|
204
324
|
*/
|
|
205
|
-
prepareHtmlDocument(sandboxId, userCode,
|
|
325
|
+
prepareHtmlDocument(sandboxId, userCode, providers = [], options) {
|
|
326
|
+
// Default options
|
|
327
|
+
const opts = {
|
|
328
|
+
isHtmlArtifact: false,
|
|
329
|
+
isStandalone: false,
|
|
330
|
+
...options,
|
|
331
|
+
};
|
|
206
332
|
// Runtime script that will be injected
|
|
207
|
-
const runtime = this.getRuntimeScript(sandboxId,
|
|
208
|
-
//
|
|
209
|
-
|
|
210
|
-
if (
|
|
333
|
+
const runtime = this.getRuntimeScript(sandboxId, providers, opts.isStandalone || false);
|
|
334
|
+
// Only check for HTML tags if explicitly marked as HTML artifact
|
|
335
|
+
// For javascript_repl, userCode is JavaScript that may contain HTML in string literals
|
|
336
|
+
if (opts.isHtmlArtifact) {
|
|
211
337
|
// HTML Artifact - inject runtime into existing HTML
|
|
212
338
|
const headMatch = userCode.match(/<head[^>]*>/i);
|
|
213
339
|
if (headMatch) {
|
|
@@ -224,6 +350,8 @@ let SandboxIframe = class SandboxIframe extends LitElement {
|
|
|
224
350
|
}
|
|
225
351
|
else {
|
|
226
352
|
// REPL - wrap code in HTML with runtime and call complete() when done
|
|
353
|
+
// Escape </script> in user code to prevent premature tag closure
|
|
354
|
+
const escapedUserCode = escapeScriptContent(userCode);
|
|
227
355
|
return `<!DOCTYPE html>
|
|
228
356
|
<html>
|
|
229
357
|
<head>
|
|
@@ -233,11 +361,35 @@ let SandboxIframe = class SandboxIframe extends LitElement {
|
|
|
233
361
|
<script type="module">
|
|
234
362
|
(async () => {
|
|
235
363
|
try {
|
|
236
|
-
|
|
237
|
-
|
|
364
|
+
// Wrap user code in async function to capture return value
|
|
365
|
+
const userCodeFunc = async () => {
|
|
366
|
+
${escapedUserCode}
|
|
367
|
+
};
|
|
368
|
+
|
|
369
|
+
const returnValue = await userCodeFunc();
|
|
370
|
+
|
|
371
|
+
// Call completion callbacks before complete()
|
|
372
|
+
if (window.__completionCallbacks && window.__completionCallbacks.length > 0) {
|
|
373
|
+
try {
|
|
374
|
+
await Promise.all(window.__completionCallbacks.map(cb => cb(true)));
|
|
375
|
+
} catch (e) {
|
|
376
|
+
console.error('Completion callback error:', e);
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
await window.complete(null, returnValue);
|
|
238
381
|
} catch (error) {
|
|
239
|
-
|
|
240
|
-
|
|
382
|
+
|
|
383
|
+
// Call completion callbacks before complete() (error path)
|
|
384
|
+
if (window.__completionCallbacks && window.__completionCallbacks.length > 0) {
|
|
385
|
+
try {
|
|
386
|
+
await Promise.all(window.__completionCallbacks.map(cb => cb(false)));
|
|
387
|
+
} catch (e) {
|
|
388
|
+
console.error('Completion callback error:', e);
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
await window.complete({
|
|
241
393
|
message: error?.message || String(error),
|
|
242
394
|
stack: error?.stack || new Error().stack
|
|
243
395
|
});
|
|
@@ -249,180 +401,96 @@ let SandboxIframe = class SandboxIframe extends LitElement {
|
|
|
249
401
|
}
|
|
250
402
|
}
|
|
251
403
|
/**
|
|
252
|
-
*
|
|
404
|
+
* Generate runtime script from providers
|
|
405
|
+
* @param sandboxId Unique sandbox ID
|
|
406
|
+
* @param providers Runtime providers
|
|
407
|
+
* @param isStandalone If true, skip runtime bridge and navigation interceptor (for standalone downloads)
|
|
253
408
|
*/
|
|
254
|
-
getRuntimeScript(sandboxId,
|
|
255
|
-
//
|
|
256
|
-
const
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
// Helper functions
|
|
267
|
-
window.listFiles = () => (attachments || []).map((a) => ({
|
|
268
|
-
id: a.id,
|
|
269
|
-
fileName: a.fileName,
|
|
270
|
-
mimeType: a.mimeType,
|
|
271
|
-
size: a.size,
|
|
272
|
-
}));
|
|
273
|
-
window.readTextFile = (attachmentId) => {
|
|
274
|
-
const a = (attachments || []).find((x) => x.id === attachmentId);
|
|
275
|
-
if (!a)
|
|
276
|
-
throw new Error("Attachment not found: " + attachmentId);
|
|
277
|
-
if (a.extractedText)
|
|
278
|
-
return a.extractedText;
|
|
279
|
-
try {
|
|
280
|
-
return atob(a.content);
|
|
281
|
-
}
|
|
282
|
-
catch {
|
|
283
|
-
throw new Error("Failed to decode text content for: " + attachmentId);
|
|
284
|
-
}
|
|
285
|
-
};
|
|
286
|
-
window.readBinaryFile = (attachmentId) => {
|
|
287
|
-
const a = (attachments || []).find((x) => x.id === attachmentId);
|
|
288
|
-
if (!a)
|
|
289
|
-
throw new Error("Attachment not found: " + attachmentId);
|
|
290
|
-
const bin = atob(a.content);
|
|
291
|
-
const bytes = new Uint8Array(bin.length);
|
|
292
|
-
for (let i = 0; i < bin.length; i++)
|
|
293
|
-
bytes[i] = bin.charCodeAt(i);
|
|
294
|
-
return bytes;
|
|
295
|
-
};
|
|
296
|
-
window.returnFile = async (fileName, content, mimeType) => {
|
|
297
|
-
let finalContent, finalMimeType;
|
|
298
|
-
if (content instanceof Blob) {
|
|
299
|
-
const arrayBuffer = await content.arrayBuffer();
|
|
300
|
-
finalContent = new Uint8Array(arrayBuffer);
|
|
301
|
-
finalMimeType = mimeType || content.type || "application/octet-stream";
|
|
302
|
-
if (!mimeType && !content.type) {
|
|
303
|
-
throw new Error("returnFile: MIME type is required for Blob content. Please provide a mimeType parameter (e.g., 'image/png').");
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
else if (content instanceof Uint8Array) {
|
|
307
|
-
finalContent = content;
|
|
308
|
-
if (!mimeType) {
|
|
309
|
-
throw new Error("returnFile: MIME type is required for Uint8Array content. Please provide a mimeType parameter (e.g., 'image/png').");
|
|
310
|
-
}
|
|
311
|
-
finalMimeType = mimeType;
|
|
312
|
-
}
|
|
313
|
-
else if (typeof content === "string") {
|
|
314
|
-
finalContent = content;
|
|
315
|
-
finalMimeType = mimeType || "text/plain";
|
|
316
|
-
}
|
|
317
|
-
else {
|
|
318
|
-
finalContent = JSON.stringify(content, null, 2);
|
|
319
|
-
finalMimeType = mimeType || "application/json";
|
|
320
|
-
}
|
|
321
|
-
window.parent.postMessage({
|
|
322
|
-
type: "file-returned",
|
|
323
|
-
sandboxId,
|
|
324
|
-
fileName,
|
|
325
|
-
content: finalContent,
|
|
326
|
-
mimeType: finalMimeType,
|
|
327
|
-
}, "*");
|
|
328
|
-
};
|
|
329
|
-
// Console capture
|
|
330
|
-
const originalConsole = {
|
|
331
|
-
log: console.log,
|
|
332
|
-
error: console.error,
|
|
333
|
-
warn: console.warn,
|
|
334
|
-
info: console.info,
|
|
335
|
-
};
|
|
336
|
-
["log", "error", "warn", "info"].forEach((method) => {
|
|
337
|
-
console[method] = (...args) => {
|
|
338
|
-
const text = args
|
|
339
|
-
.map((arg) => {
|
|
340
|
-
try {
|
|
341
|
-
return typeof arg === "object" ? JSON.stringify(arg) : String(arg);
|
|
342
|
-
}
|
|
343
|
-
catch {
|
|
344
|
-
return String(arg);
|
|
345
|
-
}
|
|
346
|
-
})
|
|
347
|
-
.join(" ");
|
|
348
|
-
window.parent.postMessage({
|
|
349
|
-
type: "console",
|
|
350
|
-
sandboxId,
|
|
351
|
-
method,
|
|
352
|
-
text,
|
|
353
|
-
}, "*");
|
|
354
|
-
originalConsole[method].apply(console, args);
|
|
355
|
-
};
|
|
356
|
-
});
|
|
357
|
-
// Track errors for HTML artifacts
|
|
358
|
-
let lastError = null;
|
|
359
|
-
// Error handlers
|
|
360
|
-
window.addEventListener("error", (e) => {
|
|
361
|
-
const text = (e.error?.stack || e.message || String(e)) + " at line " + (e.lineno || "?") + ":" + (e.colno || "?");
|
|
362
|
-
// Store the error
|
|
363
|
-
lastError = {
|
|
364
|
-
message: e.error?.message || e.message || String(e),
|
|
365
|
-
stack: e.error?.stack || text,
|
|
366
|
-
};
|
|
367
|
-
window.parent.postMessage({
|
|
368
|
-
type: "console",
|
|
369
|
-
sandboxId,
|
|
370
|
-
method: "error",
|
|
371
|
-
text,
|
|
372
|
-
}, "*");
|
|
373
|
-
});
|
|
374
|
-
window.addEventListener("unhandledrejection", (e) => {
|
|
375
|
-
const text = "Unhandled promise rejection: " + (e.reason?.message || e.reason || "Unknown error");
|
|
376
|
-
// Store the error
|
|
377
|
-
lastError = {
|
|
378
|
-
message: e.reason?.message || String(e.reason) || "Unhandled promise rejection",
|
|
379
|
-
stack: e.reason?.stack || text,
|
|
380
|
-
};
|
|
381
|
-
window.parent.postMessage({
|
|
382
|
-
type: "console",
|
|
383
|
-
sandboxId,
|
|
384
|
-
method: "error",
|
|
385
|
-
text,
|
|
386
|
-
}, "*");
|
|
409
|
+
getRuntimeScript(sandboxId, providers = [], isStandalone = false) {
|
|
410
|
+
// Collect all data from providers
|
|
411
|
+
const allData = {};
|
|
412
|
+
for (const provider of providers) {
|
|
413
|
+
Object.assign(allData, provider.getData());
|
|
414
|
+
}
|
|
415
|
+
// Generate bridge code (skip if standalone)
|
|
416
|
+
const bridgeCode = isStandalone
|
|
417
|
+
? ""
|
|
418
|
+
: RuntimeMessageBridge.generateBridgeCode({
|
|
419
|
+
context: "sandbox-iframe",
|
|
420
|
+
sandboxId,
|
|
387
421
|
});
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
422
|
+
// Collect all runtime functions - pass sandboxId as string literal
|
|
423
|
+
const runtimeFunctions = [];
|
|
424
|
+
for (const provider of providers) {
|
|
425
|
+
runtimeFunctions.push(`(${provider.getRuntime().toString()})(${JSON.stringify(sandboxId)});`);
|
|
426
|
+
}
|
|
427
|
+
// Build script with HTML escaping
|
|
428
|
+
// Escape </script> to prevent premature tag closure in HTML parser
|
|
429
|
+
const dataInjection = Object.entries(allData)
|
|
430
|
+
.map(([key, value]) => {
|
|
431
|
+
const jsonStr = JSON.stringify(value).replace(/<\/script/gi, "<\\/script");
|
|
432
|
+
return `window.${key} = ${jsonStr};`;
|
|
433
|
+
})
|
|
434
|
+
.join("\n");
|
|
435
|
+
// TODO the font-size is needed, as chrome seems to inject a stylesheet into iframes
|
|
436
|
+
// found in an extension context like sidepanel, settin body { font-size: 75% }. It's
|
|
437
|
+
// definitely not our code doing that.
|
|
438
|
+
// See https://stackoverflow.com/questions/71480433/chrome-is-injecting-some-stylesheet-in-popup-ui-which-reduces-the-font-size-to-7
|
|
439
|
+
// Navigation interceptor (only if NOT standalone)
|
|
440
|
+
const navigationInterceptor = isStandalone
|
|
441
|
+
? ""
|
|
442
|
+
: `
|
|
443
|
+
// Navigation interceptor: prevent all navigation and open externally
|
|
444
|
+
(function() {
|
|
445
|
+
// Intercept link clicks
|
|
446
|
+
document.addEventListener('click', function(e) {
|
|
447
|
+
const link = e.target.closest('a');
|
|
448
|
+
if (link && link.href) {
|
|
449
|
+
// Check if it's an external link (not javascript: or #hash)
|
|
450
|
+
if (link.href.startsWith('http://') || link.href.startsWith('https://')) {
|
|
451
|
+
e.preventDefault();
|
|
452
|
+
e.stopPropagation();
|
|
453
|
+
window.parent.postMessage({ type: 'open-external-url', url: link.href }, '*');
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
}, true);
|
|
457
|
+
|
|
458
|
+
// Intercept form submissions
|
|
459
|
+
document.addEventListener('submit', function(e) {
|
|
460
|
+
const form = e.target;
|
|
461
|
+
if (form && form.action) {
|
|
462
|
+
e.preventDefault();
|
|
463
|
+
e.stopPropagation();
|
|
464
|
+
window.parent.postMessage({ type: 'open-external-url', url: form.action }, '*');
|
|
465
|
+
}
|
|
466
|
+
}, true);
|
|
467
|
+
|
|
468
|
+
// Prevent window.location changes (only if not already redefined)
|
|
469
|
+
try {
|
|
470
|
+
const originalLocation = window.location;
|
|
471
|
+
Object.defineProperty(window, 'location', {
|
|
472
|
+
get: function() { return originalLocation; },
|
|
473
|
+
set: function(url) {
|
|
474
|
+
window.parent.postMessage({ type: 'open-external-url', url: url.toString() }, '*');
|
|
475
|
+
}
|
|
476
|
+
});
|
|
477
|
+
} catch (e) {
|
|
478
|
+
// Already defined, skip
|
|
479
|
+
}
|
|
480
|
+
})();
|
|
481
|
+
`;
|
|
482
|
+
return `<style>
|
|
483
|
+
html, body {
|
|
484
|
+
font-size: initial;
|
|
485
|
+
}
|
|
486
|
+
</style>
|
|
487
|
+
<script>
|
|
488
|
+
window.sandboxId = ${JSON.stringify(sandboxId)};
|
|
489
|
+
${dataInjection}
|
|
490
|
+
${bridgeCode}
|
|
491
|
+
${runtimeFunctions.join("\n")}
|
|
492
|
+
${navigationInterceptor}
|
|
493
|
+
</script>`;
|
|
426
494
|
}
|
|
427
495
|
};
|
|
428
496
|
__decorate([
|