shadow-claw 1.26.0 → 1.27.1
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/.agents/skills/main/skill-creator/SKILL.md +39 -0
- package/.agents/skills/main/skill-creator/references/declarative-pipelines.md +44 -0
- package/.agents/skills/main/skill-creator/references/declarative-tools.md +35 -0
- package/.agents/skills/main/skill-creator/references/frontmatter-spec.md +50 -0
- package/.well-known/agent-skills/index.json +14 -0
- package/README.md +5 -3
- package/bin/build/build.mjs +148 -15
- package/bin/build/build.test.mjs +128 -0
- package/bin/cli.mjs +35 -0
- package/bin/commands/mcp.mjs +277 -55
- package/bin/commands/mcp.test.mjs +275 -1
- package/bin/commands/skills-index.mjs +447 -0
- package/bin/commands/skills-index.test.mjs +243 -0
- package/bin/site-config/utils/custom-elements/get-approved-custom-element-scripts.test.mjs +2 -0
- package/bin/site-config/utils/custom-elements/sanitize-embedded-custom-element-scripts.test.mjs +10 -1
- package/dist/lib/components/index.js +25 -25
- package/dist/lib/components/settings/shadow-claw-accounts.js +1 -1
- package/dist/lib/components/settings/shadow-claw-channel-config.js +1 -1
- package/dist/lib/components/settings/shadow-claw-control-plane.js +1 -1
- package/dist/lib/components/settings/shadow-claw-git.js +1 -1
- package/dist/lib/components/settings/shadow-claw-integrations.js +1 -1
- package/dist/lib/components/settings/shadow-claw-llm.js +1 -1
- package/dist/lib/components/settings/shadow-claw-mcp-remote.js +1 -1
- package/dist/lib/components/settings/shadow-claw-networking.js +1 -1
- package/dist/lib/components/settings/shadow-claw-peerjs.js +1 -1
- package/dist/lib/components/settings/shadow-claw-storage.js +1 -1
- package/dist/lib/components/settings/shadow-claw-task-server.js +1 -1
- package/dist/lib/components/settings/shadow-claw-webvm.js +1 -1
- package/dist/lib/components/shadow-claw-a2ui.js +1 -1
- package/dist/lib/components/shadow-claw-accounts.js +1 -1
- package/dist/lib/components/shadow-claw-channel-config.js +1 -1
- package/dist/lib/components/shadow-claw-channels.js +1 -1
- package/dist/lib/components/shadow-claw-chat.js +1 -1
- package/dist/lib/components/shadow-claw-control-plane.js +1 -1
- package/dist/lib/components/shadow-claw-conversations.js +1 -1
- package/dist/lib/components/shadow-claw-file-viewer.js +1 -1
- package/dist/lib/components/shadow-claw-files.js +1 -1
- package/dist/lib/components/shadow-claw-git.js +1 -1
- package/dist/lib/components/shadow-claw-integrations.js +1 -1
- package/dist/lib/components/shadow-claw-llm.js +1 -1
- package/dist/lib/components/shadow-claw-mcp-remote.js +1 -1
- package/dist/lib/components/shadow-claw-networking.js +1 -1
- package/dist/lib/components/shadow-claw-page-header.js +1 -1
- package/dist/lib/components/shadow-claw-pages.js +1 -1
- package/dist/lib/components/shadow-claw-peerjs.js +1 -1
- package/dist/lib/components/shadow-claw-settings.js +1 -1
- package/dist/lib/components/shadow-claw-storage.js +1 -1
- package/dist/lib/components/shadow-claw-task-server.js +1 -1
- package/dist/lib/components/shadow-claw-tasks.js +1 -1
- package/dist/lib/components/shadow-claw-terminal.js +1 -1
- package/dist/lib/components/shadow-claw-tools.js +1 -1
- package/dist/lib/components/shadow-claw-webvm.js +1 -1
- package/dist/lib/components/shadow-claw.js +1 -1
- package/dist/lib/{configurePeerJs-CrlGan0m.js → configurePeerJs-oODzltaC.js} +2 -2
- package/dist/lib/{configurePeerJs-CrlGan0m.js.map → configurePeerJs-oODzltaC.js.map} +1 -1
- package/dist/lib/core/control-plane-client.d.ts +1 -0
- package/dist/lib/{downloadGroupFile-DboUjmp2.js → downloadGroupFile-DmcBQU1n.js} +2 -2
- package/dist/lib/{downloadGroupFile-DboUjmp2.js.map → downloadGroupFile-DmcBQU1n.js.map} +1 -1
- package/dist/lib/{file-viewer-BrK2Wxgh.js → file-viewer-C3YKnq_-.js} +4 -3
- package/dist/lib/{file-viewer-BrK2Wxgh.js.map → file-viewer-C3YKnq_-.js.map} +1 -1
- package/dist/lib/index.js +26 -26
- package/dist/lib/{initControlPlane-CsO4UR6_.js → initControlPlane-C2zURVIS.js} +86 -13
- package/dist/lib/initControlPlane-C2zURVIS.js.map +1 -0
- package/dist/lib/{markdown-eeSTFnMA.js → markdown-C6EHl9zs.js} +3 -3
- package/dist/lib/{markdown-eeSTFnMA.js.map → markdown-C6EHl9zs.js.map} +1 -1
- package/dist/lib/{orchestrator-CJvoC2Uu.js → orchestrator-CACLa_Ro.js} +7 -6
- package/dist/lib/{orchestrator-CJvoC2Uu.js.map → orchestrator-CACLa_Ro.js.map} +1 -1
- package/dist/lib/{orchestrator-DCfomsn9.js → orchestrator-KRjx0eba.js} +6 -534
- package/dist/lib/{orchestrator-DCfomsn9.js.map → orchestrator-KRjx0eba.js.map} +1 -1
- package/dist/lib/parsePath-DwC_YZjw.js +16 -0
- package/dist/lib/parsePath-DwC_YZjw.js.map +1 -0
- package/dist/lib/{peerjs-Dp02bXcG.js → peerjs-DFWOBcXf.js} +4 -4
- package/dist/lib/{peerjs-Dp02bXcG.js.map → peerjs-DFWOBcXf.js.map} +1 -1
- package/dist/lib/{readGroupFileBytes-Bve-e5e_.js → readGroupFileBytes-C8oOe8Iu.js} +3 -16
- package/dist/lib/readGroupFileBytes-C8oOe8Iu.js.map +1 -0
- package/dist/lib/security/custom-element-security.d.ts +8 -0
- package/dist/lib/server/control-plane-types.d.ts +1 -1
- package/dist/lib/{shadow-claw-D8xINM3c.js → shadow-claw-6UHdiy4a.js} +5 -5
- package/dist/lib/{shadow-claw-D8xINM3c.js.map → shadow-claw-6UHdiy4a.js.map} +1 -1
- package/dist/lib/{shadow-claw-a2ui-7rJqG4Ke.js → shadow-claw-a2ui-CpZUTzlh.js} +5 -4
- package/dist/lib/{shadow-claw-a2ui-7rJqG4Ke.js.map → shadow-claw-a2ui-CpZUTzlh.js.map} +1 -1
- package/dist/lib/{shadow-claw-accounts-CdruwN8A.js → shadow-claw-accounts-03oJ__XC.js} +2 -2
- package/dist/lib/{shadow-claw-accounts-CdruwN8A.js.map → shadow-claw-accounts-03oJ__XC.js.map} +1 -1
- package/dist/lib/{shadow-claw-channel-config-Bj0-Nk3t.js → shadow-claw-channel-config-DmfwJc6G.js} +3 -3
- package/dist/lib/{shadow-claw-channel-config-Bj0-Nk3t.js.map → shadow-claw-channel-config-DmfwJc6G.js.map} +1 -1
- package/dist/lib/{shadow-claw-channels-C_jI4KhP.js → shadow-claw-channels-1N6Jl-By.js} +3 -3
- package/dist/lib/{shadow-claw-channels-C_jI4KhP.js.map → shadow-claw-channels-1N6Jl-By.js.map} +1 -1
- package/dist/lib/{shadow-claw-chat-B16MspoP.js → shadow-claw-chat-BMoqQJRK.js} +10 -10
- package/dist/lib/{shadow-claw-chat-B16MspoP.js.map → shadow-claw-chat-BMoqQJRK.js.map} +1 -1
- package/dist/lib/{shadow-claw-control-plane-x8Ldid_h.js → shadow-claw-control-plane-UG0o7pCz.js} +6 -6
- package/dist/lib/{shadow-claw-control-plane-x8Ldid_h.js.map → shadow-claw-control-plane-UG0o7pCz.js.map} +1 -1
- package/dist/lib/{shadow-claw-conversations-Ct1kAYdB.js → shadow-claw-conversations-BwXep3iu.js} +4 -3
- package/dist/lib/{shadow-claw-conversations-Ct1kAYdB.js.map → shadow-claw-conversations-BwXep3iu.js.map} +1 -1
- package/dist/lib/{shadow-claw-file-viewer-BfDHHgpA.js → shadow-claw-file-viewer-DUxzVxDT.js} +14 -10
- package/dist/lib/shadow-claw-file-viewer-DUxzVxDT.js.map +1 -0
- package/dist/lib/{shadow-claw-files-EYhOPYIH.js → shadow-claw-files-DIREEnT2.js} +7 -7
- package/dist/lib/{shadow-claw-files-EYhOPYIH.js.map → shadow-claw-files-DIREEnT2.js.map} +1 -1
- package/dist/lib/{shadow-claw-git-tcSpT-P0.js → shadow-claw-git-Bg1SWgsF.js} +4 -4
- package/dist/lib/{shadow-claw-git-tcSpT-P0.js.map → shadow-claw-git-Bg1SWgsF.js.map} +1 -1
- package/dist/lib/{shadow-claw-integrations-NbcCx_ZI.js → shadow-claw-integrations-Ds-CLPhj.js} +2 -2
- package/dist/lib/{shadow-claw-integrations-NbcCx_ZI.js.map → shadow-claw-integrations-Ds-CLPhj.js.map} +1 -1
- package/dist/lib/{shadow-claw-llm-BazJdD5f.js → shadow-claw-llm-CazBrVpM.js} +3 -3
- package/dist/lib/{shadow-claw-llm-BazJdD5f.js.map → shadow-claw-llm-CazBrVpM.js.map} +1 -1
- package/dist/lib/{shadow-claw-mcp-remote-CYmhpg7a.js → shadow-claw-mcp-remote-CT5Q-54E.js} +2 -2
- package/dist/lib/{shadow-claw-mcp-remote-CYmhpg7a.js.map → shadow-claw-mcp-remote-CT5Q-54E.js.map} +1 -1
- package/dist/lib/{shadow-claw-networking-DImPxe0H.js → shadow-claw-networking-Df85tCbO.js} +2 -2
- package/dist/lib/{shadow-claw-networking-DImPxe0H.js.map → shadow-claw-networking-Df85tCbO.js.map} +1 -1
- package/dist/lib/{shadow-claw-page-header-CcHUfFUx.js → shadow-claw-page-header-Cti2fzf-.js} +2 -2
- package/dist/lib/{shadow-claw-page-header-CcHUfFUx.js.map → shadow-claw-page-header-Cti2fzf-.js.map} +1 -1
- package/dist/lib/{shadow-claw-pages-D54jF1Qq.js → shadow-claw-pages-BgPyIEZO.js} +15 -11
- package/dist/lib/shadow-claw-pages-BgPyIEZO.js.map +1 -0
- package/dist/lib/{shadow-claw-peerjs-B9-T8Nlx.js → shadow-claw-peerjs-xkBXILed.js} +3 -3
- package/dist/lib/{shadow-claw-peerjs-B9-T8Nlx.js.map → shadow-claw-peerjs-xkBXILed.js.map} +1 -1
- package/dist/lib/{shadow-claw-settings-Bt1VAe-1.js → shadow-claw-settings-CN89xRVU.js} +4 -4
- package/dist/lib/{shadow-claw-settings-Bt1VAe-1.js.map → shadow-claw-settings-CN89xRVU.js.map} +1 -1
- package/dist/lib/{shadow-claw-storage-CFOjGf1d.js → shadow-claw-storage-VnhcObCe.js} +3 -3
- package/dist/lib/{shadow-claw-storage-CFOjGf1d.js.map → shadow-claw-storage-VnhcObCe.js.map} +1 -1
- package/dist/lib/{shadow-claw-task-server-BiKa2GOm.js → shadow-claw-task-server-jgEC2hHB.js} +2 -2
- package/dist/lib/{shadow-claw-task-server-BiKa2GOm.js.map → shadow-claw-task-server-jgEC2hHB.js.map} +1 -1
- package/dist/lib/{shadow-claw-tasks-DDHd8W4d.js → shadow-claw-tasks-i_evIufy.js} +6 -6
- package/dist/lib/{shadow-claw-tasks-DDHd8W4d.js.map → shadow-claw-tasks-i_evIufy.js.map} +1 -1
- package/dist/lib/{shadow-claw-terminal-kB6_tWKz.js → shadow-claw-terminal-CwScROlu.js} +2 -2
- package/dist/lib/{shadow-claw-terminal-kB6_tWKz.js.map → shadow-claw-terminal-CwScROlu.js.map} +1 -1
- package/dist/lib/{shadow-claw-tools-DxXIm0ku.js → shadow-claw-tools-DD3fyXP4.js} +5 -4
- package/dist/lib/{shadow-claw-tools-DxXIm0ku.js.map → shadow-claw-tools-DD3fyXP4.js.map} +1 -1
- package/dist/lib/{shadow-claw-webvm-Dc8oo7ao.js → shadow-claw-webvm-DbJq4I3-.js} +2 -2
- package/dist/lib/{shadow-claw-webvm-Dc8oo7ao.js.map → shadow-claw-webvm-DbJq4I3-.js.map} +1 -1
- package/dist/lib/{syncWebMcpRegistration-jyRGbC9w.js → syncWebMcpRegistration-DNLnQ-jz.js} +3 -2
- package/dist/lib/{syncWebMcpRegistration-jyRGbC9w.js.map → syncWebMcpRegistration-DNLnQ-jz.js.map} +1 -1
- package/dist/lib/tools-DwwB9RBa.js +546 -0
- package/dist/lib/tools-DwwB9RBa.js.map +1 -0
- package/dist/lib/{trusted-types-CkLDpLiZ.js → trusted-types-Dx0RZlrd.js} +19 -8
- package/dist/lib/trusted-types-Dx0RZlrd.js.map +1 -0
- package/dist/lib/utils/index.js +1 -1
- package/dist/lib/utils/utils.js +1 -1
- package/dist/public/.well-known/agent-skills/index.json +14 -0
- package/dist/public/AGENTS.md +5 -3
- package/dist/public/README.md +5 -3
- package/dist/public/agent.worker.js +1 -1
- package/dist/public/{configurePeerJs-COcwE0E7.js → configurePeerJs-BqgeBjP7.js} +1 -1
- package/dist/public/custom-element-security-FU04Cq05.js +1 -0
- package/dist/public/dist-B9m1QM9v.js +58 -0
- package/dist/public/docs/README.md +31 -31
- package/dist/public/docs/example/article/index.html +1 -1
- package/dist/public/docs/publishing/index.html +1 -1
- package/dist/public/docs/skill-creator/index.html +1 -1
- package/dist/public/docs/subsystems/a2ui.md +11 -1
- package/dist/public/docs/subsystems/cli.md +32 -0
- package/dist/public/docs/subsystems/control-plane.md +8 -2
- package/dist/public/docs/subsystems/custom-element-security.md +19 -9
- package/dist/public/docs/subsystems/mcp-server.md +39 -15
- package/dist/public/docs/subsystems/skills.md +30 -0
- package/dist/public/docs/subsystems/webmcp.md +9 -0
- package/dist/public/downloadGroupFile-D8KRJGGL.js +1 -0
- package/dist/public/e2e/README.md +7 -4
- package/dist/public/{e2e-bridge-CHARpbpW.js → e2e-bridge-Ceqr5kGc.js} +1 -1
- package/dist/public/effect-BJCrpFdp.js +1 -0
- package/dist/public/file-viewer-C-6Jc_tb.js +1 -0
- package/dist/public/index.html +1 -1
- package/dist/public/index.js +1 -1
- package/dist/public/initControlPlane-BN9cWyO0.js +1 -0
- package/dist/public/main/index.html +1 -1
- package/dist/public/main/memory/index.html +1 -1
- package/dist/public/{markdown-1I3O6Mmd.js → markdown-C3M4OW_A.js} +1 -1
- package/dist/public/{orchestrator-Cl95w2vb.js → orchestrator-CMbCTjBf.js} +7 -7
- package/dist/public/{orchestrator-D-xlXG92.js → orchestrator-DHjdLtqa.js} +663 -663
- package/dist/public/peerjs-DUCKH-m9.js +1 -0
- package/dist/public/service-worker.js +1 -1
- package/dist/public/{shadow-claw-CaoKmIIB.js → shadow-claw-EAt2ml5Y.js} +3 -3
- package/dist/public/{shadow-claw-accounts-CJvYC4li.js → shadow-claw-accounts-xUOLBsQZ.js} +1 -1
- package/dist/public/{shadow-claw-channels-3K62sU5f.js → shadow-claw-channels-XsfuWFF8.js} +4 -4
- package/dist/public/{shadow-claw-chat-Cu2keU2I.js → shadow-claw-chat-CbSaOZ4q.js} +7 -7
- package/dist/public/{shadow-claw-control-plane-D1OwlQI_.js → shadow-claw-control-plane-DHvN3Ukg.js} +2 -2
- package/dist/public/{shadow-claw-conversations-DDtg3BEZ.js → shadow-claw-conversations-BWs5VVfs.js} +2 -2
- package/dist/public/{shadow-claw-file-viewer-BR__1z9S.js → shadow-claw-file-viewer-BWsoW5QS.js} +5 -4
- package/dist/public/{shadow-claw-files-BJSyZ-Bl.js → shadow-claw-files-CG7MqWiV.js} +8 -8
- package/dist/public/{shadow-claw-git-MAjhXRLc.js → shadow-claw-git-DBRPZNav.js} +6 -6
- package/dist/public/{shadow-claw-integrations-82UoFuDR.js → shadow-claw-integrations-BBVnO0Fc.js} +8 -8
- package/dist/public/{shadow-claw-llm-R8j0lwPP.js → shadow-claw-llm-DMvLgKXo.js} +2 -2
- package/dist/public/{shadow-claw-mcp-remote-BzZoz4LX.js → shadow-claw-mcp-remote-Bkx0gsmF.js} +2 -2
- package/dist/public/{shadow-claw-networking-DLEd9cNm.js → shadow-claw-networking-Dd8Rw31D.js} +2 -2
- package/dist/public/{shadow-claw-notifications-1vwR7TbT.js → shadow-claw-notifications-Dbevj-lq.js} +2 -2
- package/dist/public/{shadow-claw-page-header-DMKbkv3s.js → shadow-claw-page-header-BccSHItx.js} +1 -1
- package/dist/public/{shadow-claw-pages-CjyeIV__.js → shadow-claw-pages-3_lQAv0t.js} +4 -3
- package/dist/public/{shadow-claw-settings-BfbT4dBU.js → shadow-claw-settings-t8TIlgrM.js} +5 -5
- package/dist/public/{shadow-claw-storage-C-mWQQML.js → shadow-claw-storage-CfEXoSIE.js} +2 -2
- package/dist/public/{shadow-claw-task-server-D3lHp0Nc.js → shadow-claw-task-server-DxQSsgRZ.js} +2 -2
- package/dist/public/{shadow-claw-tasks-DVVWEm-c.js → shadow-claw-tasks-DNpicQwz.js} +14 -14
- package/dist/public/{shadow-claw-terminal-BwuTRp-O.js → shadow-claw-terminal-DpY6zU_r.js} +1 -1
- package/dist/public/{shadow-claw-toast-ClCwgzFG.js → shadow-claw-toast-BkrQIP-3.js} +1 -1
- package/dist/public/{shadow-claw-tools-zFLk2nbV.js → shadow-claw-tools-WSwWohnk.js} +2 -2
- package/dist/public/{shadow-claw-webvm-qR9X7fg7.js → shadow-claw-webvm-CP6oFjg5.js} +2 -2
- package/dist/public/syncWebMcpRegistration-DOn9gLnD.js +1 -0
- package/dist/public/toast-BXgUfbyh.js +1 -0
- package/dist/public/tools-DvckJZG2.js +1 -0
- package/dist/server.js +188 -188
- package/package.json +3 -1
- package/src/components/shadow-claw-a2ui/shadow-claw-a2ui.stories.ts +1380 -93
- package/src/components/shadow-claw-a2ui/shadow-claw-a2ui.ts +11 -6
- package/src/components/shadow-claw-file-viewer/shadow-claw-file-viewer.test.ts +8 -1
- package/src/components/shadow-claw-file-viewer/shadow-claw-file-viewer.ts +13 -5
- package/src/components/shadow-claw-pages/utils/buildHtmlPageSrcdoc.ts +13 -5
- package/src/core/control-plane-client.ts +15 -0
- package/src/core/utils/initControlPlane.test.ts +187 -0
- package/src/core/utils/initControlPlane.ts +194 -20
- package/src/security/custom-element-security.test.ts +51 -0
- package/src/security/custom-element-security.ts +33 -15
- package/src/server/control-plane-types.ts +1 -0
- package/src/server/control-plane.test.ts +69 -0
- package/src/server/control-plane.ts +45 -3
- package/src/server/mcp/tools/built-in-tools.ts +80 -5
- package/src/server/mcp/tools/client-tool-relay.ts +183 -26
- package/src/server/mcp/tools/mcp-tools.test.ts +140 -0
- package/src/server/middleware/static-files.test.ts +142 -0
- package/src/server/middleware/static-files.ts +66 -8
- package/src/testing/jest-setup.ts +14 -0
- package/src/worker/utils/handleMessage.ts +4 -1
- package/dist/lib/initControlPlane-CsO4UR6_.js.map +0 -1
- package/dist/lib/readGroupFileBytes-Bve-e5e_.js.map +0 -1
- package/dist/lib/shadow-claw-file-viewer-BfDHHgpA.js.map +0 -1
- package/dist/lib/shadow-claw-pages-D54jF1Qq.js.map +0 -1
- package/dist/lib/trusted-types-CkLDpLiZ.js.map +0 -1
- package/dist/public/custom-element-security-NCqQ5lmC.js +0 -1
- package/dist/public/downloadGroupFile-G0BZQgQg.js +0 -1
- package/dist/public/effect-rHYr4nfu.js +0 -1
- package/dist/public/file-viewer-8PdCURDD.js +0 -1
- package/dist/public/initControlPlane-CcGXax0A.js +0 -1
- package/dist/public/peerjs-BZdxWQFv.js +0 -1
- package/dist/public/syncWebMcpRegistration-DD42YsYV.js +0 -1
- package/dist/public/toast-HAq8XWFj.js +0 -58
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"shadow-claw-pages-D54jF1Qq.js","names":["Buffer","shadowClawPagesStyles","shadowClawPagesTemplate"],"sources":["../../src/components/shadow-claw-pages/utils/announcePageChange.ts","../../src/components/shadow-claw-pages/utils/routeGroupMatches.ts","../../src/components/shadow-claw-pages/utils/resolveWorkspaceLinkPath.ts","../../src/components/shadow-claw-pages/utils/rewriteWorkspacePreviewHtml.ts","../../src/components/shadow-claw-pages/utils/buildHtmlPageSrcdoc.ts","../../src/components/shadow-claw-pages/utils/calculatePaginationDisabledState.ts","../../src/components/shadow-claw-pages/utils/confirmRemoveAllPages.ts","../../src/components/shadow-claw-pages/utils/dispatchStorageProxyCommand.ts","../../src/components/shadow-claw-pages/utils/ensurePreviewIframe.ts","../../src/components/shadow-claw-pages/utils/parseAutoRefreshInterval.ts","../../src/components/shadow-claw-pages/utils/fetchAutoRefreshInterval.ts","../../src/components/shadow-claw-pages/utils/pageRefKey.ts","../../src/components/shadow-claw-pages/utils/getSelectedPageIndex.ts","../../src/components/shadow-claw-pages/utils/groupPagesByGroup.ts","../../src/components/shadow-claw-pages/utils/handleAnchorNavigation.ts","../../src/components/shadow-claw-pages/utils/handleAutoRefreshConfigEvent.ts","../../src/components/shadow-claw-pages/utils/shouldRefreshOnFileSaved.ts","../../src/components/shadow-claw-pages/utils/handleFileSavedEvent.ts","../../src/components/shadow-claw-pages/utils/isNavigationSuppressed.ts","../../src/components/shadow-claw-pages/utils/shouldHandleKeyDownNavigation.ts","../../src/components/shadow-claw-pages/utils/handleKeyDownNavigation.ts","../../src/components/shadow-claw-pages/utils/handleMouseDownGesture.ts","../../src/components/shadow-claw-pages/utils/detectSwipeDirection.ts","../../src/components/shadow-claw-pages/utils/handleMouseUpGesture.ts","../../src/components/shadow-claw-pages/utils/reorderPagesList.ts","../../src/components/shadow-claw-pages/utils/handlePageReorder.ts","../../src/components/shadow-claw-pages/utils/handleTouchEndGesture.ts","../../src/components/shadow-claw-pages/utils/handleTouchStartGesture.ts","../../src/components/shadow-claw-pages/utils/handleVisibilityStateChange.ts","../../src/components/shadow-claw-pages/utils/handleWindowFocusEvent.ts","../../src/components/shadow-claw-pages/utils/pageFileTypes.ts","../../src/components/shadow-claw-pages/utils/parseIframeMessage.ts","../../src/components/shadow-claw-pages/utils/mimeTypeForImageExt.ts","../../src/components/shadow-claw-pages/utils/readImageAsDataUrl.ts","../../src/components/shadow-claw-pages/utils/removePreviewIframe.ts","../../src/components/shadow-claw-pages/utils/requestConfirmation.ts","../../src/components/shadow-claw-pages/utils/resolveFrontmatterToggle.ts","../../src/components/shadow-claw-pages/utils/resolveRouteGroupId.ts","../../src/components/shadow-claw-pages/utils/resolveWorkspaceFileTarget.ts","../../src/components/shadow-claw-pages/utils/resolveMarkdownImages.ts","../../src/components/shadow-claw-pages/utils/shouldRunAutoRefresh.ts","../../src/components/shadow-claw-pages/utils/syncIframeTheme.ts","../../src/components/shadow-claw-pages/utils/toggleSidebarState.ts","../../src/components/shadow-claw-pages/shadow-claw-pages.ts"],"sourcesContent":["import type { SavedPageRef } from \"../../../db/types.js\";\n\n/**\n * Updates an accessibility live announcer element text when page navigation occurs.\n */\nexport function announcePageChange(\n page: SavedPageRef,\n frontmatterTitle: string | null | undefined,\n announcerEl: HTMLElement | null | undefined,\n): void {\n if (!announcerEl) {\n return;\n }\n\n const title = frontmatterTitle || page.path;\n announcerEl.textContent = `Navigated to page: ${title}`;\n}\n","/**\n * Compares two group IDs for route matching, taking into account\n * group aliases (such as 'main' vs 'br:main') and colon normalization.\n */\nexport function routeGroupMatches(\n routeGroupId: string,\n expectedGroupId: string,\n): boolean {\n if (routeGroupId === expectedGroupId) {\n return true;\n }\n\n if (\n (routeGroupId === \"main\" && expectedGroupId === \"br:main\") ||\n (routeGroupId === \"br:main\" && expectedGroupId === \"main\")\n ) {\n return true;\n }\n\n if (!routeGroupId.includes(\":\") && !expectedGroupId.includes(\":\")) {\n return false;\n }\n\n const normalize = (value: string) => value.trim().replace(/:/g, \"-\");\n\n return normalize(routeGroupId) === normalize(expectedGroupId);\n}\n","import {\n applyBasePath,\n getFileRouteDirPath,\n getWorkspaceRouteRequestPath,\n resolveHrefAgainstRoute,\n} from \"../../../core/app-routes.js\";\nimport { routeGroupMatches } from \"./routeGroupMatches.js\";\n\n/**\n * Resolves a workspace relative link or route candidate to its canonical target path within a given group.\n */\nexport function resolveWorkspaceLinkPath(\n href: string,\n filePath: string,\n groupId: string,\n origin: string = typeof window !== \"undefined\" ? window.location.origin : \"\",\n): string | null {\n const trimmed = href.trim();\n if (!trimmed || trimmed.startsWith(\"#\")) {\n return null;\n }\n\n const rawPath = trimmed.split(/[?#]/, 1)[0];\n const normalizedRoutePath = rawPath.replace(/^(?:\\.\\/)+/u, \"\");\n const routeCandidates: string[] = [];\n\n if (normalizedRoutePath.startsWith(\"files/\")) {\n routeCandidates.push(`/${normalizedRoutePath}`);\n }\n\n if (rawPath.startsWith(\"/\")) {\n const nestedFilesIndex = rawPath.lastIndexOf(\"/files/\");\n if (nestedFilesIndex > 0) {\n routeCandidates.push(rawPath.slice(nestedFilesIndex));\n }\n\n routeCandidates.push(rawPath);\n }\n\n for (const candidate of routeCandidates) {\n const route = getWorkspaceRouteRequestPath(candidate);\n if (route && routeGroupMatches(route.groupId, groupId)) {\n return route.path;\n }\n }\n\n const routeDir = applyBasePath(getFileRouteDirPath(groupId, filePath));\n const resolved = resolveHrefAgainstRoute(\n trimmed,\n routeDir,\n origin || (typeof window !== \"undefined\" ? window.location.origin : \"\"),\n );\n if (!resolved || (origin && resolved.origin !== origin)) {\n return null;\n }\n\n const route = getWorkspaceRouteRequestPath(resolved.pathname);\n if (!route || !routeGroupMatches(route.groupId, groupId)) {\n return null;\n }\n\n return route.path;\n}\n","import {\n isPossibleAppRoute,\n resolveHrefAgainstRoute,\n} from \"../../../core/app-routes.js\";\nimport { resolveWorkspaceLinkPath } from \"./resolveWorkspaceLinkPath.js\";\n\n/**\n * Rewrites internal links, scripts, and media source attributes in preview HTML\n * so that relative asset references correctly target workspace route endpoints.\n */\nexport function rewriteWorkspacePreviewHtml(\n html: string,\n filePath: string,\n routeDir: string,\n groupId: string,\n origin: string = typeof window !== \"undefined\" ? window.location.origin : \"\",\n): string {\n if (!html) {\n return html;\n }\n\n const effectiveOrigin =\n origin || (typeof window !== \"undefined\" ? window.location.origin : \"\");\n const parsed = new DOMParser().parseFromString(html, \"text/html\");\n\n const rewrite = (selector: string, attribute: \"href\" | \"src\") => {\n const nodes = Array.from(parsed.querySelectorAll(selector));\n for (const node of nodes) {\n const currentValue = node.getAttribute(attribute) || \"\";\n const trimmed = currentValue.trim();\n if (\n !trimmed ||\n trimmed.startsWith(\"#\") ||\n trimmed.startsWith(\"javascript:\")\n ) {\n continue;\n }\n\n const resolved = resolveHrefAgainstRoute(\n trimmed,\n routeDir,\n effectiveOrigin,\n );\n if (\n !resolved ||\n (effectiveOrigin && resolved.origin !== effectiveOrigin)\n ) {\n continue;\n }\n\n if (attribute === \"href\") {\n const isInternal =\n isPossibleAppRoute(resolved.pathname) ||\n Boolean(\n resolveWorkspaceLinkPath(\n trimmed,\n filePath,\n groupId,\n effectiveOrigin,\n ),\n );\n if (!isInternal) {\n continue;\n }\n }\n\n node.setAttribute(\n attribute,\n `${resolved.pathname}${resolved.search}${resolved.hash}`,\n );\n }\n };\n\n rewrite(\"a[href]\", \"href\");\n rewrite(\"img[src]\", \"src\");\n rewrite(\"audio[src]\", \"src\");\n rewrite(\"video[src]\", \"src\");\n rewrite(\"source[src]\", \"src\");\n\n return parsed.body.innerHTML;\n}\n","import type { Config } from \"dompurify\";\nimport {\n applyBasePath,\n getFileRouteDirPath,\n} from \"../../../core/app-routes.js\";\nimport { rewriteWorkspacePreviewHtml } from \"./rewriteWorkspacePreviewHtml.js\";\nimport { sanitizeSrcdocHtml } from \"../../../security/trusted-types.js\";\nimport {\n getIframeHtmlClass,\n getIframeThemeStyleHtml,\n} from \"../../../ui/iframe-theme.js\";\nimport {\n getApprovedCustomElementScripts,\n getIframeCsp,\n isAllowedCustomElement,\n} from \"../../../security/custom-element-security.js\";\n\nexport const defaultPreviewSanitizeOptions: Config = {\n // Allow blob URLs for locally resolved OPFS preview assets.\n ALLOWED_URI_REGEXP:\n /^(?:(?:https?|mailto|ftp|tel|file|blob|data):|[^a-z]|[a-z+.\\-]+(?:[^a-z+.\\-:]|$))/i,\n ADD_TAGS: [\"iframe\", \"figure\", \"figcaption\"],\n CUSTOM_ELEMENT_HANDLING: {\n tagNameCheck: (tagName: string) => isAllowedCustomElement(tagName),\n attributeNameCheck: () => true,\n allowCustomizedBuiltInElements: false,\n },\n ADD_ATTR: [\n \"allow\",\n \"allowfullscreen\",\n \"frameborder\",\n \"scrolling\",\n \"referrerpolicy\",\n \"loading\",\n ],\n};\n\nexport interface BuildHtmlSrcdocOptions {\n content: string;\n filePath: string;\n searchParams?: string;\n groupId: string;\n origin?: string;\n sanitizeOptions?: Config;\n resolveRelativeImagesInHtmlFn?: (\n html: string,\n filePath: string,\n groupId: string,\n ) => Promise<string>;\n}\n\n/**\n * Builds complete HTML srcdoc document string for sandboxed iframe previews.\n */\nexport async function buildHtmlPageSrcdoc({\n content,\n filePath,\n searchParams = \"\",\n groupId,\n origin = typeof window !== \"undefined\" ? window.location?.origin : \"\",\n sanitizeOptions = defaultPreviewSanitizeOptions,\n resolveRelativeImagesInHtmlFn,\n}: BuildHtmlSrcdocOptions): Promise<string> {\n const routeDir = applyBasePath(getFileRouteDirPath(groupId, filePath));\n const resolvedHtml = rewriteWorkspacePreviewHtml(\n content,\n filePath,\n routeDir,\n groupId,\n origin,\n );\n\n const inlinedHtml = resolveRelativeImagesInHtmlFn\n ? await resolveRelativeImagesInHtmlFn(resolvedHtml, filePath, groupId)\n : resolvedHtml;\n\n const safeContent = sanitizeSrcdocHtml(inlinedHtml, sanitizeOptions);\n\n // Nonce-gated CSP: only the bridge script and approved custom element scripts may run.\n const nonce = crypto.randomUUID().replace(/-/g, \"\");\n const bridgeScriptUrl = applyBasePath(\n \"/assets/file-viewer-preview-bridge.js\",\n );\n const storageBridgeScriptUrl = applyBasePath(\n \"/assets/iframe-storage-bridge.js\",\n );\n\n const approvedScripts = getApprovedCustomElementScripts();\n const cspContent = getIframeCsp(nonce);\n\n const configScript =\n typeof document !== \"undefined\"\n ? document.getElementById(\"shadow-claw-site-config\")\n : null;\n const siteConfigHtml =\n configScript && configScript.textContent\n ? `<script id=\"shadow-claw-site-config\" type=\"application/json\">${configScript.textContent}</script>`\n : \"\";\n\n const searchScriptHtml = searchParams\n ? `<script nonce=\"${nonce}\">(function(){try{Object.defineProperty(window.location,\"search\",{get:function(){return ${JSON.stringify(searchParams)};},configurable:true});}catch(e){}})();</script>`\n : \"\";\n\n const customElementScriptsHtml = approvedScripts\n .map((src) => {\n const isExternal =\n src.startsWith(\"http://\") ||\n src.startsWith(\"https://\") ||\n src.startsWith(\"//\");\n const resolvedSrc = isExternal\n ? src\n : applyBasePath(\n src.startsWith(\"/\") ? src : `/${src.replace(/^pages\\/main\\//, \"\")}`,\n );\n return `<script type=\"module\" src=\"${resolvedSrc}\" nonce=\"${nonce}\"></script>`;\n })\n .join(\"\\n\");\n\n const themeStylesheetLink = `<link rel=\"stylesheet\" href=\"${applyBasePath(\n \"/theme.css\",\n )}\">`;\n\n return [\n \"<!doctype html>\",\n `<html class=\"${getIframeHtmlClass()}\"><head><meta charset=\"utf-8\"><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">`,\n `<meta http-equiv=\"Content-Security-Policy\" content=\"${cspContent}\">`,\n `<base href=\"${routeDir}\" target=\"_blank\">`,\n searchScriptHtml,\n siteConfigHtml,\n `<script src=\"${storageBridgeScriptUrl}\" nonce=\"${nonce}\"></script>`,\n `<script src=\"${bridgeScriptUrl}\" nonce=\"${nonce}\"></script>`,\n getIframeThemeStyleHtml(),\n themeStylesheetLink,\n customElementScriptsHtml,\n \"</head><body>\",\n safeContent,\n \"</body></html>\",\n ].join(\"\");\n}\n","/**\n * Calculates whether previous and next navigation buttons should be disabled based on current page index.\n */\nexport function calculatePaginationDisabledState(\n selectedIndex: number,\n totalPages: number,\n): { isPrevDisabled: boolean; isNextDisabled: boolean } {\n if (totalPages === 0) {\n return { isPrevDisabled: true, isNextDisabled: true };\n }\n\n const isPrevDisabled = selectedIndex <= 0;\n const isNextDisabled = selectedIndex < 0 || selectedIndex >= totalPages - 1;\n\n return { isPrevDisabled, isNextDisabled };\n}\n","import type { ShadowClawDatabase } from \"../../../db/types.js\";\nimport { orchestratorStore } from \"../../../stores/orchestrator.js\";\n\n/**\n * Prompts user confirmation before purging all pages from IndexedDB via orchestratorStore.\n */\nexport async function confirmRemoveAllPages(\n db: ShadowClawDatabase | null,\n requestConfirmationFn: (options: {\n title: string;\n message: string;\n confirmLabel?: string;\n cancelLabel?: string;\n }) => Promise<boolean>,\n removeAllFn: (db: ShadowClawDatabase) => Promise<void> = (database) =>\n orchestratorStore.removeAllPages(database),\n): Promise<boolean> {\n if (!db) {\n return false;\n }\n\n const confirmed = await requestConfirmationFn({\n title: \"Remove All Pages\",\n message: \"Remove ALL saved pages from Pages? This cannot be undone!\",\n confirmLabel: \"Remove All\",\n cancelLabel: \"Cancel\",\n });\n\n if (!confirmed) {\n return false;\n }\n\n await removeAllFn(db);\n return true;\n}\n","import {\n iframeStorageClear,\n iframeStorageDelete,\n iframeStorageGet,\n iframeStorageGetAll,\n iframeStorageSet,\n} from \"./iframe-storage-proxy.js\";\n\nexport interface IframeStorageHandlers {\n setItem: typeof iframeStorageSet;\n deleteItem: typeof iframeStorageDelete;\n clear: typeof iframeStorageClear;\n getAll: typeof iframeStorageGetAll;\n getItem: typeof iframeStorageGet;\n putItem: typeof iframeStorageSet;\n}\n\nconst defaultHandlers: IframeStorageHandlers = {\n setItem: iframeStorageSet,\n deleteItem: iframeStorageDelete,\n clear: iframeStorageClear,\n getAll: iframeStorageGetAll,\n getItem: iframeStorageGet,\n putItem: iframeStorageSet,\n};\n\n/**\n * Dispatches an iframe storage proxy command for a given page key.\n */\nexport async function dispatchStorageProxyCommand(\n method: string,\n args: Record<string, unknown>,\n pageKey: string,\n handlers: IframeStorageHandlers = defaultHandlers,\n): Promise<unknown> {\n switch (method) {\n // localStorage-style operations\n case \"setItem\":\n await handlers.setItem(\n pageKey,\n String(args.key || \"\"),\n args.value as string,\n );\n return undefined;\n\n case \"removeItem\":\n await handlers.deleteItem(pageKey, String(args.key || \"\"));\n return undefined;\n\n case \"clear\":\n await handlers.clear(pageKey);\n return undefined;\n\n case \"getAllItems\":\n return await handlers.getAll(pageKey);\n\n // IndexedDB-style operations\n case \"idb-get\":\n return await handlers.getItem(\n `${pageKey}::idb::${args.dbName}::${args.storeName}`,\n String(args.key || \"\"),\n );\n\n case \"idb-getAll\":\n return await handlers.getAll(\n `${pageKey}::idb::${args.dbName}::${args.storeName}`,\n );\n\n case \"idb-put\": {\n const idbKey =\n args.key != null ? String(args.key) : `__auto_${Date.now()}`;\n await handlers.putItem(\n `${pageKey}::idb::${args.dbName}::${args.storeName}`,\n idbKey,\n args.value,\n );\n return idbKey;\n }\n\n case \"idb-delete\":\n await handlers.deleteItem(\n `${pageKey}::idb::${args.dbName}::${args.storeName}`,\n String(args.key || \"\"),\n );\n return undefined;\n\n case \"idb-clear\":\n await handlers.clear(\n `${pageKey}::idb::${args.dbName}::${args.storeName}`,\n );\n return undefined;\n\n case \"idb-deleteDatabase\":\n await handlers.clear(`${pageKey}::idb::${args.dbName}::__default__`);\n return undefined;\n\n case \"idb-count\": {\n const items = (await handlers.getAll(\n `${pageKey}::idb::${args.dbName}::${args.storeName}`,\n )) as Record<string, unknown>;\n return Object.keys(items).length;\n }\n\n default:\n throw new Error(`Unknown storage proxy method: ${method}`);\n }\n}\n\n/**\n * Executes a storage proxy command and posts the result back to the iframe source window.\n */\nexport async function handleStorageProxyMessage(\n source: WindowProxy,\n requestId: string,\n method: string,\n args: Record<string, unknown>,\n pageKey: string,\n handlers: IframeStorageHandlers = defaultHandlers,\n): Promise<void> {\n if (!requestId) {\n return;\n }\n\n try {\n const result = await dispatchStorageProxyCommand(\n method,\n args,\n pageKey,\n handlers,\n );\n source.postMessage(\n {\n type: \"shadow-claw-storage-proxy-result\",\n requestId,\n result: result ?? null,\n },\n \"*\",\n );\n } catch (err) {\n source.postMessage(\n {\n type: \"shadow-claw-storage-proxy-result\",\n requestId,\n error: err instanceof Error ? err.message : String(err),\n },\n \"*\",\n );\n }\n}\n","import { getIframeSandboxPolicy } from \"../../../security/custom-element-security.js\";\n\nexport interface EnsurePreviewIframeOptions {\n root: ShadowRoot | HTMLElement;\n rendered: HTMLElement;\n selectedPath?: string | null;\n onIframeLoad?: (contentWindow: Window | null) => void;\n}\n\n/**\n * Returns existing or creates a new sandboxed preview iframe element inserted before rendered container.\n */\nexport function ensurePreviewIframe({\n root,\n rendered,\n selectedPath,\n onIframeLoad,\n}: EnsurePreviewIframeOptions): HTMLIFrameElement {\n const existing = root.querySelector(\"[data-pages-iframe]\");\n if (existing instanceof HTMLIFrameElement) {\n return existing;\n }\n\n const iframe = document.createElement(\"iframe\");\n iframe.className = \"pages__iframe\";\n iframe.setAttribute(\"data-pages-iframe\", \"\");\n iframe.setAttribute(\n \"title\",\n selectedPath ? `Preview: ${selectedPath}` : \"Page preview\",\n );\n iframe.setAttribute(\"sandbox\", getIframeSandboxPolicy());\n iframe.setAttribute(\"allow\", \"fullscreen\");\n iframe.hidden = true;\n if (onIframeLoad) {\n iframe.addEventListener(\"load\", () => {\n onIframeLoad(iframe.contentWindow);\n });\n }\n rendered.before(iframe);\n\n return iframe;\n}\n","/**\n * Parses and bounds an auto-refresh interval configuration value in seconds.\n * Returns an integer between 0 and 86400 (inclusive).\n */\nexport function parseAutoRefreshInterval(value: unknown): number {\n if (typeof value === \"string\" || typeof value === \"number\") {\n const parsed = parseInt(String(value), 10);\n if (!isNaN(parsed) && parsed >= 0) {\n return Math.min(parsed, 86400);\n }\n }\n return 0;\n}\n","import type { ShadowClawDatabase } from \"../../../db/types.js\";\nimport { getConfig } from \"../../../db/getConfig.js\";\nimport { CONFIG_KEYS } from \"../../../config/config.js\";\nimport { parseAutoRefreshInterval } from \"./parseAutoRefreshInterval.js\";\n\n/**\n * Fetches and parses the auto-refresh interval configuration from IndexedDB.\n */\nexport async function fetchAutoRefreshInterval(\n db: ShadowClawDatabase | null,\n getConfigFn: typeof getConfig = getConfig,\n): Promise<number> {\n if (!db) {\n return 0;\n }\n\n try {\n const stored = await getConfigFn(\n db,\n CONFIG_KEYS.PAGES_AUTO_REFRESH_INTERVAL,\n );\n return parseAutoRefreshInterval(stored);\n } catch {\n return 0;\n }\n}\n","import type { SavedPageRef } from \"../../../db/types.js\";\n\n/**\n * Returns a unique composite key for a saved page reference.\n * Normalizes 'main' group ID to 'br:main'.\n */\nexport function pageRefKey(page: SavedPageRef | null): string {\n if (!page) {\n return \"\";\n }\n\n let normalizedGroupId = page.groupId;\n if (normalizedGroupId === \"main\") {\n normalizedGroupId = \"br:main\";\n }\n\n return `${normalizedGroupId}\\u0000${page.path}`;\n}\n","import type { SavedPageRef } from \"../../../db/types.js\";\nimport { pageRefKey } from \"./pageRefKey.js\";\n\n/**\n * Returns the index of the active page reference within a list of saved page references.\n * Returns -1 if the page is null or not found.\n */\nexport function getSelectedPageIndex(\n selectedPage: SavedPageRef | null,\n pages: SavedPageRef[] = [],\n): number {\n if (!selectedPage) {\n return -1;\n }\n\n const targetKey = pageRefKey(selectedPage);\n return pages.findIndex((p) => pageRefKey(p) === targetKey);\n}\n","import type { SavedPageRef } from \"../../../db/types.js\";\n\n/**\n * Groups an array of saved page references by their target group ID.\n */\nexport function groupPagesByGroup(\n pages: SavedPageRef[] = [],\n): Map<string, SavedPageRef[]> {\n const pagesByGroup = new Map<string, SavedPageRef[]>();\n\n pages.forEach((page) => {\n const groupPages = pagesByGroup.get(page.groupId) || [];\n groupPages.push(page);\n pagesByGroup.set(page.groupId, groupPages);\n });\n\n return pagesByGroup;\n}\n","/**\n * Scrolls a target element or named anchor into view inside a rendered page container.\n * Returns true if an anchor target was found and scrolled to.\n */\nexport function handleAnchorNavigation(\n anchor: string,\n renderedContainer: HTMLElement | null,\n): boolean {\n if (!renderedContainer || renderedContainer.hidden) {\n return false;\n }\n\n const id = anchor.replace(/^#/, \"\");\n const target =\n renderedContainer.querySelector(`[id=\"${id}\"]`) ||\n renderedContainer.querySelector(`a[name=\"${id}\"]`);\n if (target) {\n target.scrollIntoView({ behavior: \"smooth\", block: \"start\" });\n return true;\n }\n\n return false;\n}\n","import { parseAutoRefreshInterval } from \"./parseAutoRefreshInterval.js\";\n\n/**\n * Extracts and parses auto-refresh interval from configuration event detail.\n */\nexport function handleAutoRefreshConfigEvent(event: Event): number | null {\n const detail = (event as CustomEvent).detail;\n if (detail && typeof detail.interval !== \"undefined\") {\n return parseAutoRefreshInterval(detail.interval);\n }\n return null;\n}\n","import type { SavedPageRef } from \"../../../db/types.js\";\nimport { routeGroupMatches } from \"./routeGroupMatches.js\";\n\n/**\n * Determines whether a file-saved event details block matches the actively selected preview page.\n */\nexport function shouldRefreshOnFileSaved(\n detail: { groupId?: string; path?: string } | null | undefined,\n selectedPage: SavedPageRef | null | undefined,\n): boolean {\n if (!detail || !selectedPage || !detail.groupId || !detail.path) {\n return false;\n }\n\n if (detail.path !== selectedPage.path) {\n return false;\n }\n\n return (\n detail.groupId === selectedPage.groupId ||\n routeGroupMatches(detail.groupId, selectedPage.groupId)\n );\n}\n","import { shouldRefreshOnFileSaved } from \"./shouldRefreshOnFileSaved.js\";\nimport type { SavedPageRef } from \"../../../db/types.js\";\n\n/**\n * Handles file-saved event details and evaluates if re-render is required.\n */\nexport function handleFileSavedEvent(\n event: Event,\n selectedPage: SavedPageRef | null,\n): boolean {\n const detail = (event as CustomEvent).detail;\n return shouldRefreshOnFileSaved(detail, selectedPage);\n}\n","/**\n * Determines whether key, touch, or mouse navigation should be suppressed\n * based on event target elements, active focus, contenteditable attributes, or data attributes.\n */\nexport function isNavigationSuppressed(\n event?: UIEvent | Event | null,\n extraEl?: EventTarget | null,\n): boolean {\n const navAttributes = [\n \"data-no-nav\",\n \"data-no-swipe\",\n \"data-no-page-nav\",\n \"data-prevent-nav\",\n \"data-prevent-page-nav\",\n \"data-isolate-input\",\n \"data-isolate-navigation\",\n \"data-game-controls\",\n ];\n\n const checkElement = (el: EventTarget | null): boolean => {\n if (!el || !(el instanceof HTMLElement)) {\n return false;\n }\n const tagName = el.tagName.toLowerCase();\n if (\n tagName === \"input\" ||\n tagName === \"textarea\" ||\n tagName === \"select\" ||\n tagName === \"option\" ||\n tagName === \"iframe\"\n ) {\n return true;\n }\n if (\n el.classList.contains(\"pages__preview-frame\") ||\n el.isContentEditable ||\n el.contentEditable === \"true\" ||\n el.getAttribute(\"contenteditable\") === \"true\" ||\n el.hasAttribute(\"contenteditable\")\n ) {\n return true;\n }\n if (\n el.closest(\"[data-pages-list]\") ||\n el.closest(\"[data-pages-dropdown]\") ||\n el.closest(\".pages__sidebar\") ||\n el.closest(\".pages__preview-frame\") ||\n el.closest(\"iframe\") ||\n navAttributes.some((attr) => el.closest(`[${attr}]`))\n ) {\n return true;\n }\n return false;\n };\n\n if (extraEl && checkElement(extraEl)) {\n return true;\n }\n\n if (event) {\n const path =\n typeof (event as any).composedPath === \"function\"\n ? (event as any).composedPath()\n : [];\n for (const node of path) {\n if (node instanceof HTMLElement) {\n const nodeTag = node.tagName.toLowerCase();\n if (\n navAttributes.some((attr) => node.hasAttribute(attr)) ||\n nodeTag === \"input\" ||\n nodeTag === \"textarea\" ||\n nodeTag === \"select\" ||\n nodeTag === \"option\" ||\n nodeTag === \"iframe\" ||\n node.classList.contains(\"pages__preview-frame\") ||\n node.isContentEditable ||\n node.contentEditable === \"true\" ||\n node.getAttribute(\"contenteditable\") === \"true\" ||\n node.hasAttribute(\"contenteditable\")\n ) {\n return true;\n }\n }\n }\n if (event.target && checkElement(event.target)) {\n return true;\n }\n }\n\n return false;\n}\n","/**\n * Determines whether a keydown event should trigger previous or next page navigation.\n */\nexport function shouldHandleKeyDownNavigation(\n event: KeyboardEvent,\n isSuppressed: boolean,\n): \"next\" | \"previous\" | null {\n if (isSuppressed) {\n return null;\n }\n\n if (event.key !== \"ArrowLeft\" && event.key !== \"ArrowRight\") {\n return null;\n }\n\n if (event.ctrlKey || event.altKey || event.metaKey) {\n return null;\n }\n\n return event.key === \"ArrowLeft\" ? \"previous\" : \"next\";\n}\n","import { isNavigationSuppressed } from \"./isNavigationSuppressed.js\";\nimport { shouldHandleKeyDownNavigation } from \"./shouldHandleKeyDownNavigation.js\";\n\n/**\n * Handles keydown keyboard navigation for Pages.\n */\nexport function handleKeyDownNavigation(\n event: KeyboardEvent,\n isConnected: boolean,\n shadowRoot: ShadowRoot | null,\n onNavigate: (direction: \"previous\" | \"next\") => void,\n): void {\n if (!isConnected) {\n return;\n }\n\n const activeEl = shadowRoot?.activeElement || document.activeElement;\n const target = (event.target as HTMLElement) || null;\n const suppressed =\n isNavigationSuppressed(event, target) ||\n isNavigationSuppressed(undefined, activeEl);\n\n const direction = shouldHandleKeyDownNavigation(event, suppressed);\n if (!direction) {\n return;\n }\n\n event.preventDefault();\n onNavigate(direction);\n}\n","export interface MouseState {\n mouseStartX: number;\n mouseStartY: number;\n mouseStartTime: number;\n isMouseDown: boolean;\n}\n\n/**\n * Handles mousedown event state updates.\n */\nexport function handleMouseDownGesture(\n event: MouseEvent,\n isSuppressed: boolean,\n now: number = Date.now(),\n): MouseState {\n if (event.button !== 0 || isSuppressed) {\n return {\n mouseStartX: 0,\n mouseStartY: 0,\n mouseStartTime: 0,\n isMouseDown: false,\n };\n }\n\n return {\n mouseStartX: event.clientX,\n mouseStartY: event.clientY,\n mouseStartTime: now,\n isMouseDown: true,\n };\n}\n","/**\n * Determines whether a mouse or touch drag gesture represents a horizontal page navigation swipe.\n */\nexport function detectSwipeDirection(\n startX: number,\n startY: number,\n endX: number,\n endY: number,\n startTime: number,\n endTime: number = Date.now(),\n minDistance: number = 50,\n maxTime: number = 600,\n): \"next\" | \"previous\" | null {\n const deltaX = endX - startX;\n const deltaY = endY - startY;\n const deltaTime = endTime - startTime;\n\n if (\n Math.abs(deltaX) >= minDistance &&\n Math.abs(deltaX) > Math.abs(deltaY) &&\n deltaTime <= maxTime\n ) {\n return deltaX < 0 ? \"next\" : \"previous\";\n }\n\n return null;\n}\n","import { detectSwipeDirection } from \"./detectSwipeDirection.js\";\nimport type { MouseState } from \"./handleMouseDownGesture.js\";\n\n/**\n * Evaluates mouseup event swipe gesture.\n */\nexport function handleMouseUpGesture(\n event: MouseEvent,\n mouseState: MouseState,\n isSuppressed: boolean,\n hasSelection: boolean,\n now: number = Date.now(),\n): \"previous\" | \"next\" | null {\n if (!mouseState.isMouseDown || isSuppressed || hasSelection) {\n return null;\n }\n\n return detectSwipeDirection(\n mouseState.mouseStartX,\n mouseState.mouseStartY,\n event.clientX,\n event.clientY,\n mouseState.mouseStartTime,\n now,\n );\n}\n","/**\n * Reorders an element in an array from `fromIndex` to `toIndex`.\n * Returns a new array with the item moved, or the original array if indices are invalid/unchanged.\n */\nexport function reorderPagesList<T>(\n items: T[],\n fromIndex: number,\n toIndex: number,\n): T[] {\n if (\n fromIndex === toIndex ||\n fromIndex < 0 ||\n fromIndex >= items.length ||\n toIndex < 0 ||\n toIndex >= items.length\n ) {\n return items;\n }\n\n const result = [...items];\n const [moved] = result.splice(fromIndex, 1);\n result.splice(toIndex, 0, moved);\n return result;\n}\n","import type { ShadowClawDatabase, SavedPageRef } from \"../../../db/types.js\";\nimport { reorderPagesList } from \"./reorderPagesList.js\";\nimport { orchestratorStore } from \"../../../stores/orchestrator.js\";\n\nexport interface HandlePageReorderOptions {\n db: ShadowClawDatabase | null;\n currentPages: SavedPageRef[];\n fromIndex: number;\n toIndex: number;\n reorderStoreFn?: (\n db: ShadowClawDatabase,\n pages: SavedPageRef[],\n ) => Promise<void>;\n}\n\nexport interface HandlePageReorderResult {\n reordered: boolean;\n reorderedPages: SavedPageRef[];\n movedToFirst: SavedPageRef | null;\n}\n\n/**\n * Handles page reorder operation, persisting new ordering and returning reordered state details.\n */\nexport async function handlePageReorder({\n db,\n currentPages,\n fromIndex,\n toIndex,\n reorderStoreFn = (database, pages) =>\n orchestratorStore.reorderPages(database, pages),\n}: HandlePageReorderOptions): Promise<HandlePageReorderResult> {\n if (!db || fromIndex === toIndex) {\n return {\n reordered: false,\n reorderedPages: currentPages,\n movedToFirst: null,\n };\n }\n\n const reorderedPages = reorderPagesList(currentPages, fromIndex, toIndex);\n if (reorderedPages === currentPages) {\n return {\n reordered: false,\n reorderedPages: currentPages,\n movedToFirst: null,\n };\n }\n\n await reorderStoreFn(db, reorderedPages);\n const moved = reorderedPages[toIndex] || null;\n\n return {\n reordered: true,\n reorderedPages,\n movedToFirst: toIndex === 0 ? moved : null,\n };\n}\n","import { detectSwipeDirection } from \"./detectSwipeDirection.js\";\nimport type { TouchState } from \"./handleTouchStartGesture.js\";\n\n/**\n * Evaluates touchend event swipe gesture.\n */\nexport function handleTouchEndGesture(\n event: TouchEvent,\n touchState: TouchState,\n isSuppressed: boolean,\n now: number = Date.now(),\n): \"previous\" | \"next\" | null {\n if (!touchState.touchStartTime || isSuppressed) {\n return null;\n }\n\n if (event.changedTouches && event.changedTouches.length === 1) {\n const touchEndX = event.changedTouches[0].clientX;\n const touchEndY = event.changedTouches[0].clientY;\n\n return detectSwipeDirection(\n touchState.touchStartX,\n touchState.touchStartY,\n touchEndX,\n touchEndY,\n touchState.touchStartTime,\n now,\n );\n }\n\n return null;\n}\n","export interface TouchState {\n touchStartX: number;\n touchStartY: number;\n touchStartTime: number;\n}\n\n/**\n * Handles touchstart event state updates.\n */\nexport function handleTouchStartGesture(\n event: TouchEvent,\n isSuppressed: boolean,\n now: number = Date.now(),\n): TouchState | null {\n if (isSuppressed) {\n return { touchStartX: 0, touchStartY: 0, touchStartTime: 0 };\n }\n\n if (event.touches && event.touches.length === 1) {\n return {\n touchStartX: event.touches[0].clientX,\n touchStartY: event.touches[0].clientY,\n touchStartTime: now,\n };\n }\n\n return null;\n}\n","export type VisibilityStateAction = \"render-and-timer\" | \"clear-timer\" | \"noop\";\n\n/**\n * Determines action to take when document visibility state changes.\n */\nexport function handleVisibilityStateChange(\n isHidden: boolean,\n isConnected: boolean,\n isTimerRunning: boolean,\n): VisibilityStateAction {\n if (!isHidden && isConnected) {\n return \"render-and-timer\";\n }\n if (isHidden && isTimerRunning) {\n return \"clear-timer\";\n }\n return \"noop\";\n}\n","/**\n * Evaluates whether window focus requires re-rendering selected page.\n */\nexport function handleWindowFocusEvent(\n isHidden: boolean,\n isConnected: boolean,\n): boolean {\n return !isHidden && isConnected;\n}\n","/**\n * Utility functions for checking page file types.\n */\n\nexport function isHtmlPath(path: string): boolean {\n return /\\.(html?|xhtml)$/iu.test(path);\n}\n\nexport function isMarkdownPath(path: string): boolean {\n return /\\.(md|markdown)$/iu.test(path);\n}\n","export type ParsedIframeMessage =\n | { kind: \"broadcast-result\"; channel: string; payload: unknown }\n | {\n kind: \"storage-proxy\";\n requestId: string;\n method: string;\n args: Record<string, unknown>;\n }\n | { kind: \"swipe\"; direction: \"left\" | \"right\" | string }\n | { kind: \"iframe-resize\"; height: number }\n | { kind: \"file-viewer-link\"; href: string };\n\n/**\n * Parses and validates raw MessageEvent.data sent from iframes.\n */\nexport function parseIframeMessage(data: unknown): ParsedIframeMessage | null {\n if (!data || typeof data !== \"object\") {\n return null;\n }\n\n const payload = data as Record<string, unknown>;\n\n if (\n payload.type === \"shadow-claw-broadcast-result\" &&\n typeof payload.channel === \"string\"\n ) {\n return {\n kind: \"broadcast-result\",\n channel: payload.channel,\n payload: payload.payload,\n };\n }\n\n if (payload.type === \"shadow-claw-storage-proxy\") {\n return {\n kind: \"storage-proxy\",\n requestId: String(payload.requestId || \"\"),\n method: String(payload.method || \"\"),\n args: (payload.args && typeof payload.args === \"object\"\n ? payload.args\n : {}) as Record<string, unknown>,\n };\n }\n\n if (\n payload.type === \"shadow-claw-swipe\" &&\n typeof payload.direction === \"string\"\n ) {\n return {\n kind: \"swipe\",\n direction: payload.direction,\n };\n }\n\n if (\n payload.type === \"shadow-claw-iframe-resize\" &&\n typeof payload.height === \"number\"\n ) {\n return {\n kind: \"iframe-resize\",\n height: payload.height,\n };\n }\n\n if (\n payload.type === \"shadow-claw-file-viewer-link\" &&\n typeof payload.href === \"string\"\n ) {\n return {\n kind: \"file-viewer-link\",\n href: payload.href,\n };\n }\n\n return null;\n}\n","/**\n * Maps a file extension to its corresponding image MIME type.\n * Defaults to 'image/jpeg' if the extension is unrecognized.\n */\nexport function mimeTypeForImageExt(ext: string): string {\n const map: Record<string, string> = {\n apng: \"image/apng\",\n avif: \"image/avif\",\n gif: \"image/gif\",\n jpg: \"image/jpeg\",\n jpeg: \"image/jpeg\",\n png: \"image/png\",\n svg: \"image/svg+xml\",\n webp: \"image/webp\",\n };\n\n return map[ext] ?? \"image/jpeg\";\n}\n","import type { ShadowClawDatabase } from \"../../../db/types.js\";\nimport { readGroupFileBytes } from \"../../../storage/readGroupFileBytes.js\";\nimport { writeGroupFile } from \"../../../storage/writeGroupFile.js\";\nimport { mimeTypeForImageExt } from \"./mimeTypeForImageExt.js\";\nimport { applyBasePath } from \"../../../core/app-routes.js\";\n\nexport interface ReadImageAsDataUrlOptions {\n db: ShadowClawDatabase | null;\n groupId: string;\n workspacePath: string;\n readGroupFileBytesFn?: typeof readGroupFileBytes;\n writeGroupFileFn?: typeof writeGroupFile;\n fetchFn?: typeof fetch;\n}\n\n/**\n * Reads image binary data from database or fetch fallback, returning a base64 Data URL.\n */\nexport async function readImageAsDataUrl({\n db,\n groupId,\n workspacePath,\n readGroupFileBytesFn = readGroupFileBytes,\n writeGroupFileFn = writeGroupFile,\n fetchFn = typeof fetch !== \"undefined\" ? fetch : undefined,\n}: ReadImageAsDataUrlOptions): Promise<string | null> {\n if (db) {\n try {\n const bytes = await readGroupFileBytesFn(db, groupId, workspacePath);\n const ext = workspacePath.split(\".\").pop()?.toLowerCase() || \"\";\n const mimeType = mimeTypeForImageExt(ext);\n\n const blobBytes = new Uint8Array(bytes.byteLength);\n blobBytes.set(new Uint8Array(bytes));\n\n const base64 = Buffer.from(blobBytes).toString(\"base64\");\n return `data:${mimeType};base64,${base64}`;\n } catch {\n // Fall through to network fetch fallback\n }\n }\n\n if (!fetchFn) {\n return null;\n }\n\n try {\n const cleanPath = workspacePath.replace(/^\\/+/, \"\");\n const candidates = [\n applyBasePath(`/files/main/${cleanPath}`),\n applyBasePath(`/static-main/${cleanPath}`),\n applyBasePath(`/pages/main/${cleanPath}`),\n ];\n for (const url of candidates) {\n try {\n const fullUrl =\n typeof window !== \"undefined\" && window.location?.origin\n ? new URL(url, window.location.origin).toString()\n : url;\n const res = await fetchFn(fullUrl);\n if (res.ok) {\n const blob = await res.blob();\n if (db) {\n try {\n const buffer = await blob.arrayBuffer();\n await writeGroupFileFn(\n db,\n groupId,\n workspacePath,\n new Uint8Array(buffer),\n );\n } catch {}\n }\n\n if (typeof FileReader !== \"undefined\") {\n return await new Promise<string>((resolve, reject) => {\n const reader = new FileReader();\n reader.onload = () => resolve(reader.result as string);\n reader.onerror = reject;\n reader.readAsDataURL(blob);\n });\n }\n\n const arrayBuffer = await blob.arrayBuffer();\n const base64 = Buffer.from(arrayBuffer).toString(\"base64\");\n const mimeType =\n blob.type ||\n mimeTypeForImageExt(workspacePath.split(\".\").pop() || \"\");\n return `data:${mimeType};base64,${base64}`;\n }\n } catch {}\n }\n } catch {}\n\n return null;\n}\n","/**\n * Clears srcdoc and removes preview iframe from shadow root if present.\n */\nexport function removePreviewIframe(root: ShadowRoot | HTMLElement): void {\n const iframe = root.querySelector(\"[data-pages-iframe]\");\n if (!(iframe instanceof HTMLIFrameElement)) {\n return;\n }\n\n iframe.removeAttribute(\"srcdoc\");\n iframe.remove();\n}\n","import { showWarning } from \"../../../ui/toast.js\";\n\nexport interface RequestConfirmationOptions {\n title: string;\n message: string;\n confirmLabel?: string;\n cancelLabel?: string;\n}\n\n/**\n * Requests user confirmation via host app shell dialog or fallback toast warning.\n */\nexport async function requestConfirmation(\n options: RequestConfirmationOptions,\n appShell: any = typeof document !== \"undefined\"\n ? document.querySelector(\"shadow-claw\")\n : null,\n showWarningFn: typeof showWarning = showWarning,\n): Promise<boolean> {\n if (appShell && typeof appShell.requestDialog === \"function\") {\n return await appShell.requestDialog({ mode: \"confirm\", ...options });\n }\n\n showWarningFn(options.message, 4500);\n return false;\n}\n","import type { ShadowClawDatabase } from \"../../../db/types.js\";\nimport { getConfig } from \"../../../db/getConfig.js\";\nimport { isTruthyConfigValue } from \"../../../common/utils/config-value.mjs\";\n\n/**\n * Resolves a frontmatter toggle configuration boolean from database with fallback.\n */\nexport async function resolveFrontmatterToggle(\n db: ShadowClawDatabase | null,\n key: string,\n getConfigFn: typeof getConfig = getConfig,\n): Promise<boolean> {\n if (!db || typeof (db as any).transaction !== \"function\") {\n return true;\n }\n\n try {\n return isTruthyConfigValue(await getConfigFn(db, key), true);\n } catch {\n return true;\n }\n}\n","import { routeGroupMatches } from \"./routeGroupMatches.js\";\n\n/**\n * Resolves a target route group ID against an expected group ID and known workspace groups.\n */\nexport function resolveRouteGroupId(\n routeGroupId: string,\n expectedGroupId: string,\n groups: Array<{ groupId: string }> = [],\n): string | null {\n if (\n routeGroupId === expectedGroupId ||\n routeGroupMatches(routeGroupId, expectedGroupId)\n ) {\n return expectedGroupId;\n }\n\n const exact = groups.find((group) => group.groupId === routeGroupId);\n if (exact) {\n return exact.groupId;\n }\n\n const alias = groups.find((group) =>\n routeGroupMatches(routeGroupId, group.groupId),\n );\n if (alias) {\n return alias.groupId;\n }\n\n return routeGroupId || null;\n}\n","import { getWorkspaceRouteRequestPath } from \"../../../core/app-routes.js\";\nimport { resolveRouteGroupId } from \"./resolveRouteGroupId.js\";\nimport { resolveWorkspaceLinkPath } from \"./resolveWorkspaceLinkPath.js\";\n\n/**\n * Resolves an arbitrary href from a workspace preview page to its target group ID and path.\n */\nexport function resolveWorkspaceFileTarget(\n href: string,\n filePath: string,\n groupId: string,\n groups: Array<{ groupId: string }> = [],\n origin: string = typeof window !== \"undefined\" ? window.location.origin : \"\",\n): { groupId: string; path: string } | null {\n const trimmed = href.trim();\n if (!trimmed || trimmed.startsWith(\"#\")) {\n return null;\n }\n\n const routeCandidates: string[] = [];\n let rawPath = trimmed.split(/[?#]/, 1)[0];\n\n if (/^[a-zA-Z][a-zA-Z\\d+.-]*:/u.test(rawPath) || rawPath.startsWith(\"//\")) {\n let parsed: URL;\n try {\n parsed = new URL(\n rawPath,\n origin || (typeof window !== \"undefined\" ? window.location.origin : \"\"),\n );\n } catch {\n return null;\n }\n\n if (origin && parsed.origin !== origin) {\n return null;\n }\n\n rawPath = parsed.pathname;\n }\n\n const normalizedRoutePath = rawPath.replace(/^(?:\\.\\/)+/u, \"\");\n if (normalizedRoutePath.startsWith(\"files/\")) {\n routeCandidates.push(`/${normalizedRoutePath}`);\n }\n\n if (rawPath.startsWith(\"/\")) {\n const nestedFilesIndex = rawPath.lastIndexOf(\"/files/\");\n if (nestedFilesIndex > 0) {\n routeCandidates.push(rawPath.slice(nestedFilesIndex));\n }\n\n routeCandidates.push(rawPath);\n }\n\n for (const candidate of routeCandidates) {\n const route = getWorkspaceRouteRequestPath(candidate);\n if (!route) {\n continue;\n }\n\n const resolvedGroupId = resolveRouteGroupId(route.groupId, groupId, groups);\n if (!resolvedGroupId) {\n continue;\n }\n\n return { groupId: resolvedGroupId, path: route.path };\n }\n\n const path = resolveWorkspaceLinkPath(trimmed, filePath, groupId, origin);\n if (!path) {\n return null;\n }\n\n return { groupId, path };\n}\n","import type { GroupMeta } from \"../../../db/types.js\";\nimport { resolveWorkspaceFileTarget } from \"./resolveWorkspaceFileTarget.js\";\n\nexport interface ResolveMarkdownImagesOptions {\n container: HTMLElement;\n groupId: string;\n filePath: string;\n groups: GroupMeta[];\n readImageAsDataUrlFn: (\n groupId: string,\n workspacePath: string,\n ) => Promise<string | null>;\n}\n\n/**\n * Scans container for relative images, resolves workspace targets, and replaces src attributes with Data URLs.\n */\nexport async function resolveMarkdownImages({\n container,\n groupId,\n filePath,\n groups,\n readImageAsDataUrlFn,\n}: ResolveMarkdownImagesOptions): Promise<void> {\n const images = Array.from(container.querySelectorAll(\"img[src]\"));\n if (images.length === 0) {\n return;\n }\n\n await Promise.all(\n images.map(async (img) => {\n const src = img.getAttribute(\"src\") || \"\";\n if (!src || /^(?:blob:|data:|#)/u.test(src)) {\n return;\n }\n\n const target = resolveWorkspaceFileTarget(src, filePath, groupId, groups);\n if (!target) {\n return;\n }\n\n const dataUrl = await readImageAsDataUrlFn(target.groupId, target.path);\n if (!dataUrl) {\n return;\n }\n\n img.setAttribute(\"src\", dataUrl);\n }),\n );\n}\n","/**\n * Determines whether the pages auto-refresh timer loop should be actively running.\n */\nexport function shouldRunAutoRefresh(\n intervalSec: number,\n isHidden: boolean,\n isConnected: boolean,\n): boolean {\n return intervalSec > 0 && !isHidden && isConnected;\n}\n","/**\n * Synchronizes current theme mode and custom CSS properties with the preview iframe window.\n */\nexport function syncIframeTheme(targetWindow: Window | null): void {\n if (!targetWindow) {\n return;\n }\n\n const isDark =\n typeof document !== \"undefined\" &&\n document.documentElement.classList.contains(\"dark-mode\");\n\n const customProperties: Record<string, string> = {};\n if (\n typeof document !== \"undefined\" &&\n typeof getComputedStyle !== \"undefined\"\n ) {\n const styles = getComputedStyle(document.documentElement);\n for (let i = 0; i < styles.length; i++) {\n const prop = styles[i];\n if (prop.startsWith(\"--\")) {\n customProperties[prop] = styles.getPropertyValue(prop);\n }\n }\n }\n\n targetWindow.postMessage(\n {\n type: \"shadow-claw-theme-update\",\n theme: isDark ? \"dark\" : \"light\",\n customProperties,\n },\n \"*\",\n );\n}\n","export interface ToggleSidebarStateOptions {\n root: ShadowRoot | HTMLElement | null;\n currentOpen: boolean;\n force?: boolean;\n}\n\n/**\n * Updates DOM sidebar collapse classes and dropdown open attributes based on toggle state.\n * Returns the new sidebar open boolean.\n */\nexport function toggleSidebarState({\n root,\n currentOpen,\n force,\n}: ToggleSidebarStateOptions): boolean {\n if (!root) {\n return currentOpen;\n }\n\n const dropdown = root.querySelector(\"[data-pages-dropdown]\");\n const isDropdownOpen =\n dropdown instanceof HTMLDetailsElement && dropdown.open;\n\n let nextOpen: boolean;\n if (force !== undefined) {\n nextOpen = force;\n } else {\n nextOpen = !(isDropdownOpen || currentOpen);\n }\n\n const sidebar = root.querySelector(\".pages__sidebar\");\n const content = root.querySelector(\".pages__content\");\n\n if (sidebar) {\n sidebar.classList.toggle(\"collapsed\", !nextOpen);\n }\n if (content) {\n content.classList.toggle(\"pages__content--sidebar-collapsed\", !nextOpen);\n }\n\n if (dropdown instanceof HTMLDetailsElement) {\n if (nextOpen) {\n dropdown.setAttribute(\"open\", \"\");\n } else {\n dropdown.removeAttribute(\"open\");\n }\n }\n\n return nextOpen;\n}\n","import { Signal } from \"signal-polyfill\";\n\nimport { effect } from \"../../core/effect.js\";\n\nimport { splitFrontmatter } from \"../../common/utils/frontmatter.mjs\";\nimport { CONFIG_KEYS } from \"../../config/config.js\";\nimport { renderMarkdown } from \"../../content/markdown.js\";\n\nimport {\n applyBasePath,\n buildRoutePath,\n getFileRouteDirPath,\n isPossibleAppRoute,\n resolveHrefAgainstRoute,\n} from \"../../core/app-routes.js\";\n\nimport { getDb } from \"../../db/db.js\";\nimport { getConfig } from \"../../db/getConfig.js\";\nimport { isAllowedCustomElement } from \"../../security/custom-element-security.js\";\n\nimport {\n setSanitizedHtml,\n setTrustedSrcdoc,\n} from \"../../security/trusted-types.js\";\n\nimport { readGroupFile } from \"../../storage/readGroupFile.js\";\nimport { getStaticPageContent } from \"../../storage/staticMainSite.js\";\nimport { writeGroupFile } from \"../../storage/writeGroupFile.js\";\nimport { fileViewerStore } from \"../../stores/file-viewer.js\";\nimport { orchestratorStore } from \"../../stores/orchestrator.js\";\nimport { toolsStore } from \"../../stores/tools.js\";\n\nimport { showError, showSuccess } from \"../../ui/toast.js\";\n\nimport {\n getNamespacedItem,\n removeNamespacedItem,\n setNamespacedItem,\n} from \"../../utils/namespacedStorage.js\";\n\nimport { announcePageChange } from \"./utils/announcePageChange.js\";\nimport { buildHtmlPageSrcdoc } from \"./utils/buildHtmlPageSrcdoc.js\";\nimport { calculatePaginationDisabledState } from \"./utils/calculatePaginationDisabledState.js\";\nimport { confirmRemoveAllPages } from \"./utils/confirmRemoveAllPages.js\";\nimport { handleStorageProxyMessage } from \"./utils/dispatchStorageProxyCommand.js\";\nimport { ensurePreviewIframe } from \"./utils/ensurePreviewIframe.js\";\nimport { fetchAutoRefreshInterval } from \"./utils/fetchAutoRefreshInterval.js\";\nimport { getSelectedPageIndex } from \"./utils/getSelectedPageIndex.js\";\nimport { groupPagesByGroup } from \"./utils/groupPagesByGroup.js\";\nimport { handleAnchorNavigation } from \"./utils/handleAnchorNavigation.js\";\nimport { handleAutoRefreshConfigEvent } from \"./utils/handleAutoRefreshConfigEvent.js\";\nimport { handleFileSavedEvent } from \"./utils/handleFileSavedEvent.js\";\nimport { handleKeyDownNavigation } from \"./utils/handleKeyDownNavigation.js\";\nimport { handleMouseDownGesture } from \"./utils/handleMouseDownGesture.js\";\nimport { handleMouseUpGesture } from \"./utils/handleMouseUpGesture.js\";\nimport { handlePageReorder } from \"./utils/handlePageReorder.js\";\nimport { handleTouchEndGesture } from \"./utils/handleTouchEndGesture.js\";\nimport { handleTouchStartGesture } from \"./utils/handleTouchStartGesture.js\";\nimport { handleVisibilityStateChange } from \"./utils/handleVisibilityStateChange.js\";\nimport { handleWindowFocusEvent } from \"./utils/handleWindowFocusEvent.js\";\nimport { IframeBroadcastProxy } from \"./utils/iframe-broadcast-proxy.js\";\nimport { isNavigationSuppressed } from \"./utils/isNavigationSuppressed.js\";\nimport { isHtmlPath, isMarkdownPath } from \"./utils/pageFileTypes.js\";\nimport { pageRefKey } from \"./utils/pageRefKey.js\";\nimport { parseIframeMessage } from \"./utils/parseIframeMessage.js\";\nimport { readImageAsDataUrl } from \"./utils/readImageAsDataUrl.js\";\nimport { removePreviewIframe } from \"./utils/removePreviewIframe.js\";\nimport { requestConfirmation } from \"./utils/requestConfirmation.js\";\nimport { resolveFrontmatterToggle } from \"./utils/resolveFrontmatterToggle.js\";\nimport { resolveMarkdownImages } from \"./utils/resolveMarkdownImages.js\";\nimport { resolveWorkspaceLinkPath } from \"./utils/resolveWorkspaceLinkPath.js\";\nimport { rewriteWorkspacePreviewHtml } from \"./utils/rewriteWorkspacePreviewHtml.js\";\nimport { shouldRunAutoRefresh } from \"./utils/shouldRunAutoRefresh.js\";\nimport { syncIframeTheme } from \"./utils/syncIframeTheme.js\";\nimport { toggleSidebarState } from \"./utils/toggleSidebarState.js\";\n\nimport ShadowClawElement from \"../shadow-claw-element.js\";\n\nimport type { Config } from \"dompurify\";\n\nimport type {\n GroupMeta,\n SavedPageRef,\n ShadowClawDatabase,\n} from \"../../db/types.js\";\n\nimport \"../common/shadow-claw-page-header-action-button/shadow-claw-page-header-action-button.js\";\nimport \"../shadow-claw-page-header/shadow-claw-page-header.js\";\n\nimport shadowClawPagesStyles from \"./shadow-claw-pages.css\" with { type: \"css\" };\nimport shadowClawPagesTemplate from \"./shadow-claw-pages.html\" with { type: \"html\" };\n\nconst previewSanitizeOptions: Config = {\n // Allow blob URLs for locally resolved OPFS preview assets.\n ALLOWED_URI_REGEXP:\n /^(?:(?:https?|mailto|ftp|tel|file|blob|data):|[^a-z]|[a-z+.\\-]+(?:[^a-z+.\\-:]|$))/i,\n ADD_TAGS: [\"iframe\", \"figure\", \"figcaption\"],\n CUSTOM_ELEMENT_HANDLING: {\n tagNameCheck: (tagName: string) => isAllowedCustomElement(tagName),\n attributeNameCheck: () => true,\n allowCustomizedBuiltInElements: false,\n },\n ADD_ATTR: [\n \"allow\",\n \"allowfullscreen\",\n \"frameborder\",\n \"scrolling\",\n \"referrerpolicy\",\n \"loading\",\n ],\n};\n\nconst elementName = \"shadow-claw-pages\";\n\nexport class ShadowClawPages extends ShadowClawElement {\n static styles = shadowClawPagesStyles;\n static template = shadowClawPagesTemplate;\n\n autoRefreshIntervalSec: number = 0;\n autoRefreshTimer: ReturnType<typeof setInterval> | null = null;\n\n broadcastProxy: IframeBroadcastProxy | null = null;\n db: ShadowClawDatabase | null = null;\n draggedPageIndex: number | null = null;\n isMouseDown: boolean = false;\n mouseStartTime: number = 0;\n mouseStartX: number = 0;\n mouseStartY: number = 0;\n navFadeTimer: ReturnType<typeof setTimeout> | null = null;\n pageFrontmatter = new Signal.State<Record<string, any> | null>(null);\n previewFrameWindow: Window | null = null;\n renderToken: number = 0;\n sidebarOpen: boolean = false;\n themeObserver: MutationObserver | null = null;\n touchStartTime: number = 0;\n touchStartX: number = 0;\n touchStartY: number = 0;\n\n private dsdInitialPath: string | null = null;\n private renderedContent: string | null = null;\n private renderedFrontmatterToggle: boolean | null = null;\n private renderedKey: string | null = null;\n private routingReady: boolean = false;\n\n constructor() {\n super();\n }\n\n async connectedCallback() {\n const root = this.shadowRoot;\n if (!root) {\n throw new Error(\"shadowRoot not found\");\n }\n\n const host = this.closest(\"shadow-claw\");\n // Use the authoritative class set synchronously by theme-init.ts rather\n // than re-reading localStorage directly. theme-init.ts applies a\n // null → __PRERENDER_MAIN_MEMORY__ fallback that a plain\n // `localStorage.getItem(...) === \"true\"` check would miss (it would return\n // false when the key was never explicitly stored). The sc-prerender-override\n // class on <html> is the single canonical signal for whether SSR content\n // should be suppressed, so reading it here keeps the two in lockstep.\n const isOverride = document.documentElement.classList.contains(\n \"sc-prerender-override\",\n );\n const isNoSeed = host?.getAttribute(\"data-prerender-no-seed\") === \"true\";\n\n if (isOverride || isNoSeed) {\n const rendered = root.querySelector(\"[data-pages-rendered]\");\n if (rendered instanceof HTMLElement) {\n rendered.hidden = true;\n rendered.textContent = \"\";\n }\n } else {\n const dsdSelected = root\n .querySelector(\"[data-pages-dropdown-selected]\")\n ?.textContent?.trim();\n if (dsdSelected) {\n this.dsdInitialPath = dsdSelected;\n }\n }\n\n this.db = await getDb();\n\n await orchestratorStore.whenInitialized;\n\n this.broadcastProxy = new IframeBroadcastProxy(\n () =>\n this.previewFrameWindow ||\n (\n this.shadowRoot?.querySelector(\n \"[data-pages-iframe]\",\n ) as HTMLIFrameElement\n )?.contentWindow ||\n null,\n );\n\n window.addEventListener(\"message\", this.handleIframeMessage);\n document.addEventListener(\"visibilitychange\", this.handleVisibilityChange);\n window.addEventListener(\"focus\", this.handleWindowFocus);\n window.addEventListener(\n \"shadow-claw-pages-auto-refresh-change\",\n this.handleAutoRefreshConfigChange,\n );\n document.addEventListener(\"shadow-claw-file-saved\", this.handleFileSaved);\n document.addEventListener(\"keydown\", this.handleKeyDown);\n\n root.addEventListener(\"click\", (event: Event) => {\n const dropdown = root.querySelector(\"[data-pages-dropdown]\");\n if (dropdown instanceof HTMLDetailsElement && dropdown.open) {\n const target = event.target as HTMLElement;\n const toggleBtn = root.querySelector(\"[data-pages-sidebar-toggle]\");\n if (\n !dropdown.contains(target) &&\n (!toggleBtn || !toggleBtn.contains(target))\n ) {\n dropdown.removeAttribute(\"open\");\n }\n }\n });\n\n const viewer = root.querySelector(\".pages__viewer\");\n const viewerScroll = root.querySelector(\".pages__viewer-scroll\");\n const handleViewerInteraction = () => {\n this.showNavButtonsTemporarily(2000);\n };\n\n if (viewer instanceof HTMLElement) {\n viewer.addEventListener(\"pointermove\", handleViewerInteraction, {\n passive: true,\n });\n viewer.addEventListener(\"pointerdown\", handleViewerInteraction, {\n passive: true,\n });\n viewer.addEventListener(\"touchstart\", handleViewerInteraction, {\n passive: true,\n });\n viewer.addEventListener(\"touchstart\", this.handleTouchStart, {\n passive: true,\n });\n viewer.addEventListener(\"touchend\", this.handleTouchEnd, {\n passive: true,\n });\n viewer.addEventListener(\"mousedown\", this.handleMouseDown, {\n passive: true,\n });\n viewer.addEventListener(\"mouseup\", this.handleMouseUp, {\n passive: true,\n });\n viewer.addEventListener(\"click\", handleViewerInteraction, {\n passive: true,\n });\n viewer.addEventListener(\"focusin\", handleViewerInteraction, {\n passive: true,\n });\n }\n\n if (viewerScroll instanceof HTMLElement) {\n viewerScroll.addEventListener(\"scroll\", handleViewerInteraction, {\n passive: true,\n });\n }\n\n const toggleBtn = root.querySelector(\"[data-pages-sidebar-toggle]\");\n if (toggleBtn) {\n toggleBtn.addEventListener(\"click\", () => {\n this.toggleSidebar();\n });\n }\n\n const removeAllBtn = root.querySelector(\".pages__remove-all-btn\");\n if (removeAllBtn) {\n removeAllBtn.addEventListener(\"click\", () => {\n void this.handleRemoveAll();\n });\n }\n\n const prevBtn = root.querySelector(\"[data-pages-prev]\");\n if (prevBtn) {\n prevBtn.addEventListener(\"click\", () => {\n this.goToPreviousPage();\n });\n }\n\n const nextBtn = root.querySelector(\"[data-pages-next]\");\n if (nextBtn) {\n nextBtn.addEventListener(\"click\", () => {\n this.goToNextPage();\n });\n }\n\n this.toggleSidebar(this.sidebarOpen);\n\n this.setupEffects();\n\n this.themeObserver = new MutationObserver((mutations) => {\n for (const m of mutations) {\n if (m.type === \"attributes\" && m.attributeName === \"class\") {\n this.syncIframeTheme();\n }\n }\n });\n this.themeObserver.observe(document.documentElement, {\n attributes: true,\n attributeFilter: [\"class\"],\n });\n\n // Wait for the parent ShadowClaw to finish URL routing before allowing\n // the effect to trigger page renders. Without this gate the effect fires\n // immediately with the store's default (pre-rendered) pinned page, causing\n // a one-frame flash of SSR content before the URL-requested page loads.\n await orchestratorStore.whenReady;\n this.routingReady = true;\n void this.renderSelectedPage();\n void this.setupAutoRefreshTimer();\n }\n\n disconnectedCallback() {\n this.renderedKey = null;\n this.renderedContent = null;\n this.renderedFrontmatterToggle = null;\n this.dsdInitialPath = null;\n\n if (this.themeObserver) {\n this.themeObserver.disconnect();\n this.themeObserver = null;\n }\n\n if (this.navFadeTimer !== null) {\n clearTimeout(this.navFadeTimer);\n this.navFadeTimer = null;\n }\n if (this.autoRefreshTimer !== null) {\n clearInterval(this.autoRefreshTimer);\n this.autoRefreshTimer = null;\n }\n window.removeEventListener(\"message\", this.handleIframeMessage);\n document.removeEventListener(\n \"visibilitychange\",\n this.handleVisibilityChange,\n );\n window.removeEventListener(\"focus\", this.handleWindowFocus);\n window.removeEventListener(\n \"shadow-claw-pages-auto-refresh-change\",\n this.handleAutoRefreshConfigChange,\n );\n document.removeEventListener(\n \"shadow-claw-file-saved\",\n this.handleFileSaved,\n );\n document.removeEventListener(\"keydown\", this.handleKeyDown);\n this.broadcastProxy?.dispose();\n this.broadcastProxy = null;\n this.previewFrameWindow = null;\n super.disconnectedCallback?.();\n }\n\n announcePageChange(page: SavedPageRef) {\n const root = this.shadowRoot;\n if (!root) {\n return;\n }\n const announcer = root.querySelector(\"[data-pages-announcer]\");\n if (announcer instanceof HTMLElement) {\n const fm = this.pageFrontmatter.get();\n announcePageChange(page, fm?.title, announcer);\n }\n }\n\n goToNextPage() {\n const pages = orchestratorStore.pages;\n const index = getSelectedPageIndex(this.selectedPage, pages);\n if (index >= 0 && index < pages.length - 1) {\n this.navigateToPage(pages[index + 1]);\n }\n }\n\n goToPreviousPage() {\n const pages = orchestratorStore.pages;\n const index = getSelectedPageIndex(this.selectedPage, pages);\n if (index > 0) {\n this.navigateToPage(pages[index - 1]);\n }\n }\n\n handleAnchorNavigation(anchor: string): boolean {\n const root = this.shadowRoot;\n if (!root) {\n return false;\n }\n\n const rendered = root.querySelector(\"[data-pages-rendered]\") as HTMLElement;\n return handleAnchorNavigation(anchor, rendered);\n }\n\n handleAutoRefreshConfigChange = (event: Event) => {\n const interval = handleAutoRefreshConfigEvent(event);\n if (interval !== null) {\n this.autoRefreshIntervalSec = interval;\n }\n void this.setupAutoRefreshTimer();\n };\n\n handleFileSaved = (event: Event) => {\n if (handleFileSavedEvent(event, this.selectedPage)) {\n void this.renderSelectedPage();\n }\n };\n\n handleIframeMessage = (event: MessageEvent) => {\n const msg = parseIframeMessage(event.data);\n if (!msg) {\n return;\n }\n\n if (msg.kind === \"broadcast-result\") {\n this.broadcastProxy?.handleResultFromIframe(\n event.source as WindowProxy,\n msg.channel,\n msg.payload,\n );\n return;\n }\n\n if (msg.kind === \"storage-proxy\") {\n if (this.previewFrameWindow && event.source !== this.previewFrameWindow) {\n return;\n }\n\n const pageKey = this.selectedPage?.path || \"__default__\";\n void handleStorageProxyMessage(\n event.source as WindowProxy,\n msg.requestId,\n msg.method,\n msg.args,\n pageKey,\n );\n return;\n }\n\n if (msg.kind === \"swipe\") {\n if (this.previewFrameWindow && event.source !== this.previewFrameWindow) {\n return;\n }\n this.showNavButtonsTemporarily(2000);\n if (msg.direction === \"left\") {\n this.goToNextPage();\n } else if (msg.direction === \"right\") {\n this.goToPreviousPage();\n }\n return;\n }\n\n if (msg.kind === \"iframe-resize\") {\n const root = this.shadowRoot;\n const iframe = root?.querySelector(\"[data-pages-iframe]\");\n if (\n iframe instanceof HTMLIFrameElement &&\n (!this.previewFrameWindow ||\n event.source === this.previewFrameWindow ||\n (iframe.contentWindow && event.source === iframe.contentWindow))\n ) {\n this.previewFrameWindow = iframe.contentWindow;\n iframe.style.setProperty(\"height\", `${msg.height}px`, \"important\");\n }\n return;\n }\n\n if (!this.db || msg.kind !== \"file-viewer-link\") {\n return;\n }\n\n if (this.previewFrameWindow && event.source !== this.previewFrameWindow) {\n return;\n }\n\n const basePath = this.selectedPage?.path || \"\";\n const groupId =\n this.selectedPage?.groupId || orchestratorStore.activeGroupId;\n const routeDir = applyBasePath(getFileRouteDirPath(groupId, basePath));\n const resolved = resolveHrefAgainstRoute(\n msg.href,\n routeDir,\n window.location.origin,\n );\n if (!resolved) {\n return;\n }\n\n const hasGameSave = resolved.searchParams.has(\"gameSave\");\n\n if (hasGameSave) {\n this.reloadPreviewWithSearchParams(resolved.search);\n\n return;\n }\n\n const isInternal =\n resolved.origin === window.location.origin &&\n (isPossibleAppRoute(resolved.pathname) ||\n Boolean(resolveWorkspaceLinkPath(msg.href, basePath, groupId)));\n\n if (!isInternal) {\n window.open(resolved.href, \"_blank\", \"noopener,noreferrer\");\n\n return;\n }\n\n const targetPath = `${resolved.pathname}${resolved.search}${resolved.hash}`;\n const nav = (window as any).navigation;\n if (nav && typeof nav.navigate === \"function\") {\n nav.navigate(targetPath);\n\n return;\n }\n\n window.history.pushState({}, \"\", targetPath);\n window.dispatchEvent(new PopStateEvent(\"popstate\"));\n };\n\n handleKeyDown = (event: KeyboardEvent) => {\n handleKeyDownNavigation(\n event,\n this.isConnected,\n this.shadowRoot,\n (direction) => {\n this.showNavButtonsTemporarily(2000);\n if (direction === \"previous\") {\n this.goToPreviousPage();\n } else {\n this.goToNextPage();\n }\n },\n );\n };\n\n handleMouseDown = (event: MouseEvent) => {\n const state = handleMouseDownGesture(event, isNavigationSuppressed(event));\n this.mouseStartX = state.mouseStartX;\n this.mouseStartY = state.mouseStartY;\n this.mouseStartTime = state.mouseStartTime;\n this.isMouseDown = state.isMouseDown;\n };\n\n handleMouseUp = (event: MouseEvent) => {\n const selection = window.getSelection();\n const hasSelection = Boolean(selection && selection.toString().length > 0);\n const direction = handleMouseUpGesture(\n event,\n {\n mouseStartX: this.mouseStartX,\n mouseStartY: this.mouseStartY,\n mouseStartTime: this.mouseStartTime,\n isMouseDown: this.isMouseDown,\n },\n isNavigationSuppressed(event),\n hasSelection,\n );\n this.isMouseDown = false;\n if (direction) {\n this.showNavButtonsTemporarily(2000);\n if (direction === \"next\") {\n this.goToNextPage();\n } else {\n this.goToPreviousPage();\n }\n }\n };\n\n handleTouchEnd = (event: TouchEvent) => {\n const direction = handleTouchEndGesture(\n event,\n {\n touchStartX: this.touchStartX,\n touchStartY: this.touchStartY,\n touchStartTime: this.touchStartTime,\n },\n isNavigationSuppressed(event),\n );\n if (direction) {\n this.showNavButtonsTemporarily(2000);\n if (direction === \"next\") {\n this.goToNextPage();\n } else {\n this.goToPreviousPage();\n }\n }\n this.touchStartTime = 0;\n };\n\n handleTouchStart = (event: TouchEvent) => {\n const updated = handleTouchStartGesture(\n event,\n isNavigationSuppressed(event),\n );\n if (updated) {\n this.touchStartX = updated.touchStartX;\n this.touchStartY = updated.touchStartY;\n this.touchStartTime = updated.touchStartTime;\n }\n };\n\n handleVisibilityChange = () => {\n const action = handleVisibilityStateChange(\n document.hidden,\n this.isConnected,\n this.autoRefreshTimer !== null,\n );\n if (action === \"render-and-timer\") {\n void this.renderSelectedPage();\n void this.setupAutoRefreshTimer();\n } else if (action === \"clear-timer\" && this.autoRefreshTimer !== null) {\n clearInterval(this.autoRefreshTimer);\n this.autoRefreshTimer = null;\n }\n };\n\n handleWindowFocus = () => {\n if (handleWindowFocusEvent(document.hidden, this.isConnected)) {\n void this.renderSelectedPage();\n }\n };\n\n navigateToPage(page: SavedPageRef) {\n this.selectedPage = page;\n this.showNavButtonsTemporarily(2500);\n this.announcePageChange(page);\n document.dispatchEvent(\n new CustomEvent(\"shadow-claw-navigate\", {\n detail: {\n page: \"pages\",\n groupId: page.groupId,\n path: page.path,\n },\n bubbles: true,\n composed: true,\n }),\n );\n }\n\n renderPageList(pages: SavedPageRef[], groups: GroupMeta[]) {\n const root = this.shadowRoot;\n if (!root) {\n return;\n }\n\n const status = root.querySelector(\"[data-pages-status]\");\n if (status instanceof HTMLElement) {\n status.textContent =\n pages.length === 1 ? \"1 saved page\" : `${pages.length} saved pages`;\n }\n\n const clearBtn = root.querySelector(\".pages__remove-all-btn\");\n if (clearBtn) {\n clearBtn.toggleAttribute(\"disabled\", pages.length === 0);\n }\n\n const dropdownSelected = root.querySelector(\n \"[data-pages-dropdown-selected]\",\n );\n if (dropdownSelected instanceof HTMLElement) {\n if (this.selectedPage) {\n dropdownSelected.textContent = this.selectedPage.path;\n } else {\n dropdownSelected.textContent = \"Select a page...\";\n }\n }\n\n const lists = root.querySelectorAll(\"[data-pages-list]\");\n if (lists.length === 0) {\n return;\n }\n\n lists.forEach((list) => {\n if (list instanceof HTMLElement) {\n list.replaceChildren();\n }\n });\n\n const prevBtn = root.querySelector(\"[data-pages-prev]\");\n const nextBtn = root.querySelector(\"[data-pages-next]\");\n const header = root.querySelector(\"shadow-claw-page-header\");\n\n const fm = this.pageFrontmatter.get();\n if (header) {\n if (fm && fm.title) {\n if (this.selectedPage) {\n const routeUrl = applyBasePath(\n buildRoutePath({\n page: \"pages\",\n groupId: this.selectedPage.groupId,\n path: this.selectedPage.path,\n }),\n );\n\n let absoluteUrl = routeUrl;\n if (typeof window !== \"undefined\" && window.location?.origin) {\n try {\n absoluteUrl = new URL(routeUrl, window.location.origin).href;\n } catch {\n // Fallback\n }\n }\n\n header.setAttribute(\n \"page-title\",\n `<a href=\"${absoluteUrl}\">${fm.title}</a>`,\n );\n header.setAttribute(\"title\", fm.title);\n } else {\n header.setAttribute(\"page-title\", fm.title);\n header.setAttribute(\"title\", fm.title);\n }\n } else {\n header.setAttribute(\"page-title\", \"Pages\");\n header.setAttribute(\"title\", \"Pages\");\n }\n }\n\n if (\n prevBtn instanceof HTMLButtonElement &&\n nextBtn instanceof HTMLButtonElement\n ) {\n const idx = getSelectedPageIndex(this.selectedPage, pages);\n const { isPrevDisabled, isNextDisabled } =\n calculatePaginationDisabledState(idx, pages.length);\n prevBtn.disabled = isPrevDisabled;\n prevBtn.hidden = isPrevDisabled;\n nextBtn.disabled = isNextDisabled;\n nextBtn.hidden = isNextDisabled;\n }\n\n if (pages.length === 0) {\n return;\n }\n\n const groupNameById = new Map(\n groups.map((group) => [group.groupId, group.name]),\n );\n const pagesByGroup = groupPagesByGroup(pages);\n\n lists.forEach((list) => {\n if (!(list instanceof HTMLElement)) {\n return;\n }\n\n for (const [groupId, groupPages] of pagesByGroup) {\n const details = document.createElement(\"details\");\n details.className = \"pages__group-details\";\n\n const stateKey = `shadow-claw-pages-group-collapsed-${groupId}`;\n let isCollapsed = false;\n try {\n isCollapsed = getNamespacedItem(stateKey) === \"true\";\n } catch {\n // Ignore\n }\n if (!isCollapsed) {\n details.open = true;\n }\n\n details.addEventListener(\"toggle\", () => {\n try {\n if (details.open) {\n removeNamespacedItem(stateKey);\n } else {\n setNamespacedItem(stateKey, \"true\");\n }\n } catch {\n // Ignore\n }\n });\n\n const summary = document.createElement(\"summary\");\n summary.className = \"pages__group-label\";\n\n const labelText = document.createElement(\"span\");\n labelText.textContent = groupNameById.get(groupId) || groupId;\n\n const icon = document.createElement(\"span\");\n icon.className = \"pages__group-icon\";\n icon.textContent = \"▼\";\n\n summary.appendChild(labelText);\n summary.appendChild(icon);\n details.appendChild(summary);\n\n const groupPagesContainer = document.createElement(\"div\");\n groupPagesContainer.className = \"pages__group-pages\";\n\n groupPages.forEach((page) => {\n const path = page.path;\n const globalIndex = pages.findIndex(\n (p) => p.path === page.path && p.groupId === page.groupId,\n );\n\n const row = document.createElement(\"div\");\n row.className = \"pages__list-item\";\n if (\n this.selectedPage &&\n pageRefKey(page) === pageRefKey(this.selectedPage)\n ) {\n row.classList.add(\"active\");\n }\n\n const dragHandle = document.createElement(\"span\");\n dragHandle.className = \"pages__drag-handle\";\n dragHandle.setAttribute(\"draggable\", \"true\");\n dragHandle.title = \"Drag to reorder\";\n dragHandle.textContent = \"⠿\";\n\n dragHandle.addEventListener(\"dragstart\", (e) => {\n this.draggedPageIndex = globalIndex;\n row.classList.add(\"dragging\");\n if (e.dataTransfer) {\n e.dataTransfer.effectAllowed = \"move\";\n }\n });\n\n row.addEventListener(\"dragend\", () => {\n this.draggedPageIndex = null;\n row.classList.remove(\"dragging\");\n });\n\n row.addEventListener(\"dragover\", (e) => {\n e.preventDefault();\n if (\n this.draggedPageIndex !== null &&\n this.draggedPageIndex !== globalIndex\n ) {\n row.classList.add(\"drag-over\");\n }\n });\n\n row.addEventListener(\"dragleave\", () => {\n row.classList.remove(\"drag-over\");\n });\n\n row.addEventListener(\"drop\", (e) => {\n e.preventDefault();\n row.classList.remove(\"drag-over\");\n if (\n this.draggedPageIndex !== null &&\n this.draggedPageIndex !== globalIndex\n ) {\n void this.handleReorder(this.draggedPageIndex, globalIndex);\n }\n });\n\n const effectiveDefault = orchestratorStore.effectiveDefaultPage;\n const isDefault =\n effectiveDefault &&\n effectiveDefault.path === page.path &&\n effectiveDefault.groupId === page.groupId;\n\n const selectBtn = document.createElement(\"button\");\n selectBtn.type = \"button\";\n selectBtn.className = \"pages__select\";\n selectBtn.title = `Open ${path}`;\n\n const pathSpan = document.createElement(\"span\");\n pathSpan.className = \"pages__list-path\";\n pathSpan.textContent = path;\n selectBtn.appendChild(pathSpan);\n\n selectBtn.addEventListener(\"click\", () => {\n this.selectedPage = page;\n this.renderPageList(\n orchestratorStore.pages,\n orchestratorStore.groups,\n );\n void this.renderSelectedPage();\n\n this.sidebarOpen = false;\n const details = list.closest(\"details\");\n if (details) {\n details.removeAttribute(\"open\");\n }\n\n document.dispatchEvent(\n new CustomEvent(\"shadow-claw-navigate\", {\n detail: {\n page: \"pages\",\n groupId: page.groupId,\n path: page.path,\n },\n bubbles: true,\n composed: true,\n }),\n );\n });\n\n const editBtn = document.createElement(\"button\");\n editBtn.className = \"pages__edit\";\n editBtn.type = \"button\";\n editBtn.title = \"Edit in file editor\";\n editBtn.setAttribute(\"aria-label\", `Edit ${path} in file editor`);\n editBtn.textContent = \"✏️\";\n\n editBtn.addEventListener(\"click\", async (event) => {\n event.stopPropagation();\n if (!this.db) {\n return;\n }\n try {\n await fileViewerStore.openFile(this.db, path, groupId);\n } catch (error) {\n const message =\n error instanceof Error ? error.message : String(error);\n showError(`Failed to edit file: ${message}`, 4500);\n }\n });\n\n const removeBtn = document.createElement(\"button\");\n removeBtn.className = \"pages__remove\";\n removeBtn.type = \"button\";\n removeBtn.title = \"Remove from Pages\";\n removeBtn.setAttribute(\n \"aria-label\",\n `Remove ${path} from Pages in ${(groupNameById.get(groupId) || groupId) as string}`,\n );\n removeBtn.textContent = \"✕\";\n\n removeBtn.addEventListener(\"click\", async (event) => {\n event.stopPropagation();\n if (!this.db) {\n return;\n }\n\n const confirmed = await requestConfirmation({\n title: \"Remove Page\",\n message: `Are you sure you want to remove this page from Pages?\\n\\n${path}`,\n confirmLabel: \"Remove\",\n cancelLabel: \"Cancel\",\n });\n\n if (!confirmed) {\n return;\n }\n\n try {\n await orchestratorStore.removePage(this.db, path, groupId);\n showSuccess(`Removed ${path} from Pages`, 2400);\n } catch (error) {\n const message =\n error instanceof Error ? error.message : String(error);\n showError(`Failed to remove page: ${message}`, 4500);\n }\n });\n\n row.appendChild(dragHandle);\n if (isDefault) {\n const defaultSpan = document.createElement(\"span\");\n defaultSpan.className = \"pages__default-btn is-default\";\n defaultSpan.title = \"Default page\";\n defaultSpan.textContent = \"⭐\";\n row.appendChild(defaultSpan);\n }\n row.appendChild(selectBtn);\n row.appendChild(editBtn);\n row.appendChild(removeBtn);\n groupPagesContainer.appendChild(row);\n });\n\n details.appendChild(groupPagesContainer);\n list.appendChild(details);\n }\n });\n }\n\n rewriteWorkspacePreviewHtml(html: string, filePath: string): string {\n const groupId =\n this.selectedPage?.groupId || orchestratorStore.activeGroupId;\n const routeDir = applyBasePath(getFileRouteDirPath(groupId, filePath));\n return rewriteWorkspacePreviewHtml(\n html,\n filePath,\n routeDir,\n groupId,\n window.location.origin,\n );\n }\n\n get selectedPage(): SavedPageRef | null {\n return orchestratorStore.activePinnedPage;\n }\n\n set selectedPage(val: SavedPageRef | null) {\n if (pageRefKey(val) === pageRefKey(this.selectedPage)) {\n return;\n }\n\n if (this.db) {\n void orchestratorStore.setActivePinnedPage(this.db, val);\n } else {\n orchestratorStore._activePinnedPage.set(val);\n }\n\n if (val) {\n this.announcePageChange(val);\n }\n\n this.renderPageList(orchestratorStore.pages, orchestratorStore.groups);\n void this.renderSelectedPage();\n }\n\n setupEffects() {\n this.addCleanup(\n effect(() => {\n const declTools = toolsStore.declarativeTools;\n if (this.broadcastProxy && declTools.length > 0) {\n this.broadcastProxy.registerChannelsFromTools(declTools);\n }\n }),\n );\n\n // Effect 1: Render the sidebar list and header.\n // Depends on: pages, groups, activePinnedPage (via getSelectedPageIndex), and pageFrontmatter.\n this.addCleanup(\n effect(() => {\n const pages = orchestratorStore.pages;\n const groups = orchestratorStore.groups;\n this.renderPageList(pages, groups);\n }),\n );\n\n // Effect 2: Ensure valid active page selection and trigger content render.\n // Depends on: pages, activePinnedPage.\n // Does NOT depend on pageFrontmatter, preventing infinite render loops when frontmatter updates.\n this.addCleanup(\n effect(() => {\n const pages = orchestratorStore.pages;\n const activePinnedPage = orchestratorStore.activePinnedPage;\n\n if (pages.length === 0) {\n if (activePinnedPage !== null) {\n this.selectedPage = null;\n }\n } else if (\n !activePinnedPage ||\n !pages.some(\n (page) => pageRefKey(page) === pageRefKey(activePinnedPage),\n )\n ) {\n this.selectedPage =\n orchestratorStore.effectiveDefaultPage || pages[0];\n }\n\n // Guard: skip renders until URL routing has been applied by the parent\n // ShadowClaw. This prevents the effect from flashing the default\n // pre-rendered page before applyRouteFromCurrentLocation runs.\n if (!this.routingReady) {\n return;\n }\n\n void this.renderSelectedPage();\n }),\n );\n }\n\n showNavButtonsTemporarily(durationMs = 2500) {\n const root = this.shadowRoot;\n if (!root) {\n return;\n }\n\n const viewer = root.querySelector(\".pages__viewer\");\n if (viewer instanceof HTMLElement) {\n viewer.classList.add(\"pages__viewer--nav-visible\");\n }\n\n if (this.navFadeTimer !== null) {\n clearTimeout(this.navFadeTimer);\n }\n\n this.navFadeTimer = setTimeout(() => {\n this.navFadeTimer = null;\n if (viewer instanceof HTMLElement) {\n viewer.classList.remove(\"pages__viewer--nav-visible\");\n }\n }, durationMs);\n }\n\n toggleSidebar(force?: boolean) {\n this.sidebarOpen = toggleSidebarState({\n root: this.shadowRoot,\n currentOpen: this.sidebarOpen,\n force,\n });\n }\n\n async buildHtmlPageSrcdoc(\n content: string,\n filePath: string,\n searchParams: string = \"\",\n ): Promise<string> {\n const groupId =\n this.selectedPage?.groupId || orchestratorStore.activeGroupId;\n return await buildHtmlPageSrcdoc({\n content,\n filePath,\n searchParams,\n groupId,\n origin: typeof window !== \"undefined\" ? window.location?.origin : \"\",\n resolveRelativeImagesInHtmlFn: (c, p, g) =>\n this.resolveRelativeImagesInHtml(c, p, g),\n });\n }\n\n async handleRemoveAll() {\n const btn = this.shadowRoot?.querySelector(\".pages__remove-all-btn\");\n try {\n btn?.toggleAttribute(\"disabled\", true);\n if (btn) {\n btn.textContent = \"⏳\";\n }\n\n const success = await confirmRemoveAllPages(this.db, (opts) =>\n requestConfirmation(opts),\n );\n if (success) {\n showSuccess(\"Removed all pages from Pages\", 2400);\n }\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n showError(`Failed to remove all pages: ${message}`, 4500);\n console.error(\"Remove all pages error:\", err);\n } finally {\n btn?.toggleAttribute(\"disabled\", false);\n if (btn) {\n btn.textContent = \"🗑️ Remove All\";\n }\n }\n }\n\n async handleReorder(fromIndex: number, toIndex: number) {\n const result = await handlePageReorder({\n db: this.db,\n currentPages: orchestratorStore.pages,\n fromIndex,\n toIndex,\n });\n\n if (result.movedToFirst) {\n this.selectedPage = result.movedToFirst;\n void this.renderSelectedPage();\n\n document.dispatchEvent(\n new CustomEvent(\"shadow-claw-navigate\", {\n detail: {\n page: \"pages\",\n groupId: result.movedToFirst.groupId,\n path: result.movedToFirst.path,\n },\n bubbles: true,\n composed: true,\n }),\n );\n }\n }\n\n async renderSelectedPage() {\n const root = this.shadowRoot;\n if (!root) {\n return;\n }\n\n const empty = root.querySelector(\"[data-pages-empty]\");\n const rendered = root.querySelector(\"[data-pages-rendered]\");\n\n if (!(empty instanceof HTMLElement) || !(rendered instanceof HTMLElement)) {\n return;\n }\n\n const selectedPage = this.selectedPage;\n if (!this.db || !selectedPage) {\n this.renderedKey = null;\n this.renderedContent = null;\n this.renderedFrontmatterToggle = null;\n empty.hidden = false;\n rendered.hidden = true;\n rendered.textContent = \"\";\n this.pageFrontmatter.set(null);\n removePreviewIframe(root);\n\n return;\n }\n\n const token = ++this.renderToken;\n\n try {\n let content: string;\n try {\n content = await readGroupFile(\n this.db,\n selectedPage.groupId,\n selectedPage.path,\n );\n } catch (readErr) {\n try {\n const staticContent = await getStaticPageContent(selectedPage.path);\n if (typeof staticContent === \"string\") {\n content = staticContent;\n void Promise.resolve(\n writeGroupFile(\n this.db,\n selectedPage.groupId,\n selectedPage.path,\n content,\n ),\n ).catch(() => {});\n } else {\n throw readErr;\n }\n } catch {\n throw readErr;\n }\n }\n\n if (token !== this.renderToken) {\n return;\n }\n\n empty.hidden = true;\n\n const pageKey = `${selectedPage.groupId}:${selectedPage.path}`;\n\n if (isHtmlPath(selectedPage.path)) {\n const parsedFrontmatter = splitFrontmatter(content);\n const newData =\n Object.keys(parsedFrontmatter.data).length > 0\n ? parsedFrontmatter.data\n : null;\n\n const currentData = this.pageFrontmatter.get();\n if (JSON.stringify(currentData) !== JSON.stringify(newData)) {\n this.pageFrontmatter.set(newData);\n }\n\n if (\n this.renderedKey === pageKey &&\n this.renderedContent === content &&\n root.querySelector(\"[data-pages-iframe]\")\n ) {\n this.showNavButtonsTemporarily(2500);\n\n return;\n }\n\n this.renderedKey = pageKey;\n this.renderedContent = content;\n this.renderedFrontmatterToggle = null;\n rendered.hidden = true;\n const iframe = this.ensurePreviewIframe(root, rendered);\n iframe.hidden = false;\n this.previewFrameWindow = null;\n setTrustedSrcdoc(\n iframe,\n await this.buildHtmlPageSrcdoc(\n parsedFrontmatter.content,\n selectedPage.path,\n ),\n );\n this.showNavButtonsTemporarily(2500);\n\n return;\n }\n\n removePreviewIframe(root);\n\n if (isMarkdownPath(selectedPage.path)) {\n const parsedFrontmatter = splitFrontmatter(content);\n const newData =\n Object.keys(parsedFrontmatter.data).length > 0\n ? parsedFrontmatter.data\n : null;\n\n const currentData = this.pageFrontmatter.get();\n if (JSON.stringify(currentData) !== JSON.stringify(newData)) {\n this.pageFrontmatter.set(newData);\n }\n\n const renderFrontmatter = await resolveFrontmatterToggle(\n this.db,\n CONFIG_KEYS.MARKDOWN_FRONTMATTER_PAGES,\n );\n\n // Check if already rendered with matching content and settings\n if (\n this.renderedKey === pageKey &&\n this.renderedContent === content &&\n this.renderedFrontmatterToggle === renderFrontmatter &&\n rendered.children.length > 0 &&\n !rendered.hidden\n ) {\n this.showNavButtonsTemporarily(2500);\n\n return;\n }\n\n // Check if DSD SSR content is already present for this initial page\n if (\n !this.renderedKey &&\n this.dsdInitialPath &&\n this.dsdInitialPath === selectedPage.path &&\n rendered.children.length > 0 &&\n !rendered.hidden\n ) {\n this.renderedKey = pageKey;\n this.renderedContent = content;\n this.renderedFrontmatterToggle = renderFrontmatter;\n await this.resolveMarkdownImages(\n rendered,\n selectedPage.groupId,\n selectedPage.path,\n );\n this.showNavButtonsTemporarily(2500);\n\n return;\n }\n\n this.renderedKey = pageKey;\n this.renderedContent = content;\n this.renderedFrontmatterToggle = renderFrontmatter;\n rendered.hidden = false;\n\n const html = await renderMarkdown(content, {\n renderFrontmatter,\n });\n if (token !== this.renderToken) {\n return;\n }\n\n const routeDir = applyBasePath(\n getFileRouteDirPath(selectedPage.groupId, selectedPage.path),\n );\n const resolvedHtml = rewriteWorkspacePreviewHtml(\n html,\n selectedPage.path,\n routeDir,\n selectedPage.groupId,\n window.location.origin,\n );\n if (token !== this.renderToken) {\n return;\n }\n\n setSanitizedHtml(rendered, resolvedHtml, previewSanitizeOptions);\n await this.resolveMarkdownImages(\n rendered,\n selectedPage.groupId,\n selectedPage.path,\n );\n this.showNavButtonsTemporarily(2500);\n\n return;\n }\n\n if (\n this.renderedKey === pageKey &&\n this.renderedContent === content &&\n !rendered.hidden\n ) {\n this.showNavButtonsTemporarily(2500);\n\n return;\n }\n\n this.renderedKey = pageKey;\n this.renderedContent = content;\n this.renderedFrontmatterToggle = null;\n this.pageFrontmatter.set(null);\n rendered.hidden = false;\n rendered.textContent = content;\n this.showNavButtonsTemporarily(2500);\n } catch (error) {\n this.renderedKey = null;\n this.renderedContent = null;\n this.renderedFrontmatterToggle = null;\n empty.hidden = false;\n rendered.hidden = true;\n rendered.textContent = \"\";\n this.pageFrontmatter.set(null);\n removePreviewIframe(root);\n const message = error instanceof Error ? error.message : String(error);\n showError(`Failed to load page ${selectedPage.path}: ${message}`, 5000);\n }\n }\n\n async resolveMarkdownImages(\n content: HTMLElement,\n groupId: string,\n filePath: string,\n ): Promise<void> {\n const groups = Array.isArray(orchestratorStore.groups)\n ? orchestratorStore.groups\n : [];\n await resolveMarkdownImages({\n container: content,\n groupId,\n filePath,\n groups,\n readImageAsDataUrlFn: (g, p) =>\n readImageAsDataUrl({\n db: this.db,\n groupId: g,\n workspacePath: p,\n }),\n });\n }\n\n async resolveRelativeImagesInHtml(\n html: string,\n filePath: string,\n groupId: string,\n ): Promise<string> {\n if (!html) {\n return html;\n }\n\n const parsed = new DOMParser().parseFromString(html, \"text/html\");\n await this.resolveMarkdownImages(parsed.body, groupId, filePath);\n return parsed.body.innerHTML;\n }\n\n async setupAutoRefreshTimer(): Promise<void> {\n if (this.autoRefreshTimer !== null) {\n clearInterval(this.autoRefreshTimer);\n this.autoRefreshTimer = null;\n }\n\n if (!this.db) {\n return;\n }\n\n const sec = await fetchAutoRefreshInterval(this.db, getConfig);\n this.autoRefreshIntervalSec = sec;\n\n if (shouldRunAutoRefresh(sec, document.hidden, this.isConnected)) {\n this.autoRefreshTimer = setInterval(() => {\n if (shouldRunAutoRefresh(sec, document.hidden, this.isConnected)) {\n void this.renderSelectedPage();\n }\n }, sec * 1000);\n }\n }\n\n private ensurePreviewIframe(\n root: ShadowRoot,\n rendered: HTMLElement,\n ): HTMLIFrameElement {\n return ensurePreviewIframe({\n root,\n rendered,\n selectedPath: this.selectedPage?.path,\n onIframeLoad: (win) => {\n this.previewFrameWindow = win;\n this.syncIframeTheme();\n },\n });\n }\n\n private syncIframeTheme(): void {\n syncIframeTheme(this.previewFrameWindow);\n }\n\n private async reloadPreviewWithSearchParams(\n searchParams: string,\n ): Promise<void> {\n if (!this.selectedPage || !this.renderedContent) {\n return;\n }\n\n const root = this.shadowRoot;\n const rendered = root?.querySelector(\"#rendered\") as HTMLElement;\n if (!root || !rendered) {\n return;\n }\n\n const parsedFrontmatter = splitFrontmatter(this.renderedContent);\n const iframe = this.ensurePreviewIframe(root, rendered);\n iframe.hidden = false;\n this.previewFrameWindow = null;\n setTrustedSrcdoc(\n iframe,\n await this.buildHtmlPageSrcdoc(\n parsedFrontmatter.content,\n this.selectedPage.path,\n searchParams,\n ),\n );\n }\n}\n\nif (!customElements.get(elementName)) {\n customElements.define(elementName, ShadowClawPages);\n}\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"trusted-types-CkLDpLiZ.js","names":[],"sources":["../../src/security/custom-element-security.ts","../../src/utils/utils.ts","../../src/security/trusted-types.ts"],"sourcesContent":["import { CONFIG_KEYS } from \"../config/config.js\";\nimport { getDb } from \"../db/db.js\";\nimport { getConfig } from \"../db/getConfig.js\";\nimport { getDOMPurify, parseHostPatternMatch } from \"./iframe-sanitizer.js\";\nimport { toTrustedScriptUrl } from \"./trusted-types.js\";\n\nimport type { Config } from \"dompurify\";\nimport type { ShadowClawDatabase } from \"../db/types.js\";\n\n/** Default allowed custom elements: none by default */\nexport const DEFAULT_ALLOWED_CUSTOM_ELEMENTS: string[] = [];\n\n/** Default allowed custom element host patterns: none by default */\nexport const DEFAULT_ALLOWED_CUSTOM_ELEMENT_HOST_PATTERNS: string[] = [];\n\nlet activeAllowedElements: Set<string> = new Set(\n DEFAULT_ALLOWED_CUSTOM_ELEMENTS.map((el) => el.toLowerCase().trim()),\n);\n\nlet activeHostPatterns: string[] = [\n ...DEFAULT_ALLOWED_CUSTOM_ELEMENT_HOST_PATTERNS,\n];\nlet activeHostMatchers: Array<(hostname: string) => boolean> = [];\n\nfunction rebuildHostMatchers(patterns: string[]): void {\n activeHostMatchers = patterns\n .map((p) => parseHostPatternMatch(p))\n .filter(Boolean);\n}\n\nrebuildHostMatchers(activeHostPatterns);\n\n/**\n * Normalizes an element tag name or list into an array of lowercase strings.\n */\nfunction normalizeElementList(elements: string[] | string): string[] {\n if (Array.isArray(elements)) {\n return elements\n .map((s) => (typeof s === \"string\" ? s.toLowerCase().trim() : \"\"))\n .filter(Boolean);\n }\n if (typeof elements === \"string\") {\n return elements\n .split(/[\\n,]+/)\n .map((s) => s.toLowerCase().trim())\n .filter(Boolean);\n }\n return [];\n}\n\n/**\n * Normalizes a list of host patterns into an array of trimmed strings.\n */\nfunction normalizePatternList(patterns: string[] | string): string[] {\n if (Array.isArray(patterns)) {\n return patterns\n .map((s) => (typeof s === \"string\" ? s.trim() : \"\"))\n .filter(Boolean);\n }\n if (typeof patterns === \"string\") {\n return patterns\n .split(/[\\n,]+/)\n .map((s) => s.trim())\n .filter(Boolean);\n }\n return [];\n}\n\n/**\n * Set the allowed custom elements in memory.\n */\nexport function setAllowedCustomElements(elements: string[] | string): void {\n const list = normalizeElementList(elements);\n activeAllowedElements = new Set(list);\n}\n\n/**\n * Get the current list of allowed custom elements.\n */\nexport function getAllowedCustomElements(): string[] {\n return Array.from(activeAllowedElements);\n}\n\n/**\n * Set the allowed custom element host patterns in memory.\n */\nexport function setAllowedCustomElementHostPatterns(\n patterns: string[] | string,\n): void {\n const list = normalizePatternList(patterns);\n activeHostPatterns = list;\n rebuildHostMatchers(list);\n}\n\n/**\n * Get the current list of allowed custom element host patterns.\n */\nexport function getAllowedCustomElementHostPatterns(): string[] {\n return [...activeHostPatterns];\n}\n\n/**\n * Check if a custom element tag name is approved.\n * Built-in ShadowClaw elements (\"shadow-claw\" and \"shadow-claw-*\") are always allowed.\n * Standard non-hyphenated HTML elements pass tag name check.\n */\nexport function isAllowedCustomElement(tagName: string): boolean {\n if (!tagName || typeof tagName !== \"string\") {\n return false;\n }\n\n const lower = tagName.trim().toLowerCase();\n\n // If not a custom element (no hyphen), allow standard HTML tag handling\n if (!lower.includes(\"-\")) {\n return true;\n }\n\n // ShadowClaw core elements are built-in and always permitted\n if (lower === \"shadow-claw\" || lower.startsWith(\"shadow-claw-\")) {\n return true;\n }\n\n // Check against explicit allowlist\n return activeAllowedElements.has(lower);\n}\n\n/**\n * Check if a script URL source is from an approved domain or same-origin.\n */\nexport function isSafeCustomElementSource(urlStr: string): boolean {\n if (!urlStr || typeof urlStr !== \"string\") {\n return false;\n }\n\n const trimmed = urlStr.trim();\n if (!trimmed) {\n return false;\n }\n\n // Reject dangerous pseudo-protocols\n if (/^(?:javascript|data|vbscript):/i.test(trimmed)) {\n return false;\n }\n\n // Allow blob: URLs (used by internal web workers)\n if (/^blob:/i.test(trimmed)) {\n return true;\n }\n\n try {\n const base =\n typeof window !== \"undefined\" &&\n window.location?.origin &&\n window.location.origin !== \"null\"\n ? window.location.origin\n : \"http://localhost\";\n const url = new URL(trimmed, base);\n\n if (url.protocol !== \"http:\" && url.protocol !== \"https:\") {\n return false;\n }\n\n // Same-origin is trusted\n if (\n typeof window !== \"undefined\" &&\n window.location?.origin &&\n window.location.origin !== \"null\" &&\n url.origin === window.location.origin\n ) {\n return true;\n }\n\n const hostname = url.hostname.toLowerCase();\n\n return activeHostMatchers.some((matcher) => matcher(hostname));\n } catch {\n return false;\n }\n}\n\nexport const DEFAULT_IFRAME_SANDBOX_POLICY =\n \"allow-modals allow-scripts allow-popups allow-popups-to-escape-sandbox\";\n\nexport const DEFAULT_WORKER_SRC = [\"'self'\", \"blob:\", \"data:\"];\nexport const DEFAULT_CONNECT_SRC = [\"'self'\", \"blob:\", \"data:\"];\nexport const DEFAULT_STYLE_SRC = [\n \"'self'\",\n \"'unsafe-inline'\",\n \"https:\",\n \"http:\",\n];\nexport const DEFAULT_IMG_SRC = [\"'self'\", \"blob:\", \"data:\", \"https:\", \"http:\"];\n\nlet activeIframeSandboxPolicy: string = DEFAULT_IFRAME_SANDBOX_POLICY;\nlet activeWorkerSrc: string[] = [...DEFAULT_WORKER_SRC];\nlet activeConnectSrc: string[] = [...DEFAULT_CONNECT_SRC];\nlet activeScriptSrc: string[] = [];\nlet activeStyleSrc: string[] = [...DEFAULT_STYLE_SRC];\nlet activeImgSrc: string[] = [...DEFAULT_IMG_SRC];\n\n/**\n * Get the active iframe sandbox policy string.\n */\nexport function getIframeSandboxPolicy(): string {\n return activeIframeSandboxPolicy;\n}\n\n/**\n * Set the iframe sandbox policy.\n */\nexport function setIframeSandboxPolicy(policy: string[] | string): void {\n if (Array.isArray(policy)) {\n activeIframeSandboxPolicy = policy\n .map((s) => (typeof s === \"string\" ? s.trim() : \"\"))\n .filter(Boolean)\n .join(\" \");\n } else if (typeof policy === \"string\" && policy.trim()) {\n activeIframeSandboxPolicy = policy.trim();\n } else {\n activeIframeSandboxPolicy = DEFAULT_IFRAME_SANDBOX_POLICY;\n }\n}\n\n/**\n * Generate CSP header string for the sandboxed preview iframe.\n */\nexport function getIframeCsp(nonce: string): string {\n const allowedPatterns = getAllowedCustomElementHostPatterns();\n const approvedScripts = getApprovedCustomElementScripts();\n\n const allowedScriptHosts = new Set<string>();\n for (const pattern of allowedPatterns) {\n if (pattern && /^(\\*\\.)?[a-zA-Z0-9.-]+(?::[0-9]+)?$/.test(pattern)) {\n allowedScriptHosts.add(`https://${pattern}`);\n allowedScriptHosts.add(`http://${pattern}`);\n }\n }\n for (const scriptUrl of approvedScripts) {\n try {\n const parsed = new URL(\n scriptUrl,\n typeof window !== \"undefined\" && window.location?.origin\n ? window.location.origin\n : \"http://localhost\",\n );\n allowedScriptHosts.add(parsed.origin);\n } catch {}\n }\n\n const scriptSources = [\n `'nonce-${nonce}'`,\n ...Array.from(allowedScriptHosts),\n ...activeScriptSrc,\n ];\n\n const connectSources = [\n ...activeConnectSrc,\n ...Array.from(allowedScriptHosts),\n ];\n\n const directives: string[] = [\n `script-src ${Array.from(new Set(scriptSources)).join(\" \")}`,\n `worker-src ${Array.from(new Set(activeWorkerSrc)).join(\" \")}`,\n `connect-src ${Array.from(new Set(connectSources)).join(\" \")}`,\n `style-src ${Array.from(new Set(activeStyleSrc)).join(\" \")}`,\n `img-src ${Array.from(new Set(activeImgSrc)).join(\" \")}`,\n ];\n\n return directives.join(\"; \");\n}\n\n/**\n * Configure custom element security and iframe sandbox policy from a site config object or options.\n */\nexport function configureCustomElementSecurity(config: {\n allowedCustomElements?: string[] | string;\n allowedCustomElementDomains?: string[] | string;\n customElements?:\n | {\n allowedElements?: string[] | string;\n allowedDomains?: string[] | string;\n scripts?: Array<string | { src: string }>;\n }\n | Array<string | { src: string }>;\n security?: {\n iframeSandbox?: string[] | string;\n allowSameOrigin?: boolean;\n allowIframeSameOrigin?: boolean;\n workerSrc?: string[] | string;\n connectSrc?: string[] | string;\n scriptSrc?: string[] | string;\n styleSrc?: string[] | string;\n imgSrc?: string[] | string;\n };\n}): void {\n if (!config || typeof config !== \"object\") {\n return;\n }\n\n // Extract allowed elements\n const elements =\n config.allowedCustomElements ||\n (typeof config.customElements === \"object\" &&\n !Array.isArray(config.customElements)\n ? config.customElements?.allowedElements\n : undefined);\n\n if (elements !== undefined) {\n setAllowedCustomElements(elements);\n }\n\n // Extract allowed domains\n const domains =\n config.allowedCustomElementDomains ||\n (typeof config.customElements === \"object\" &&\n !Array.isArray(config.customElements)\n ? config.customElements?.allowedDomains\n : undefined);\n\n if (domains !== undefined) {\n setAllowedCustomElementHostPatterns(domains);\n }\n\n // Extract security iframe sandbox settings\n if (config.security?.iframeSandbox !== undefined) {\n setIframeSandboxPolicy(config.security.iframeSandbox);\n } else if (\n config.security?.allowSameOrigin === true ||\n config.security?.allowIframeSameOrigin === true\n ) {\n if (!activeIframeSandboxPolicy.includes(\"allow-same-origin\")) {\n activeIframeSandboxPolicy =\n `${activeIframeSandboxPolicy} allow-same-origin`.trim();\n }\n }\n\n // Extract CSP overrides if configured\n if (config.security?.workerSrc !== undefined) {\n activeWorkerSrc = normalizePatternList(config.security.workerSrc);\n }\n if (config.security?.connectSrc !== undefined) {\n activeConnectSrc = normalizePatternList(config.security.connectSrc);\n }\n if (config.security?.scriptSrc !== undefined) {\n activeScriptSrc = normalizePatternList(config.security.scriptSrc);\n }\n if (config.security?.styleSrc !== undefined) {\n activeStyleSrc = normalizePatternList(config.security.styleSrc);\n }\n if (config.security?.imgSrc !== undefined) {\n activeImgSrc = normalizePatternList(config.security.imgSrc);\n }\n}\n\n/**\n * Initializes custom element security synchronously from embedded site-config script in the DOM if available.\n */\nexport function initCustomElementSecurityFromEmbeddedConfig(): void {\n if (typeof document === \"undefined\") {\n return;\n }\n\n const configScript = document.getElementById(\"shadow-claw-site-config\");\n if (configScript && configScript.textContent) {\n try {\n const config = JSON.parse(configScript.textContent);\n configureCustomElementSecurity(config);\n } catch {\n // ignore JSON parse error\n }\n }\n}\n\n/**\n * Retrieve approved custom element script URLs from the embedded site config.\n */\nexport function getApprovedCustomElementScripts(): string[] {\n if (typeof document === \"undefined\") {\n return [];\n }\n\n const configScript = document.getElementById(\"shadow-claw-site-config\");\n if (!configScript || !configScript.textContent) {\n return [];\n }\n\n try {\n const config = JSON.parse(configScript.textContent);\n const scripts =\n typeof config.customElements === \"object\" &&\n !Array.isArray(config.customElements)\n ? config.customElements?.scripts\n : undefined;\n\n if (Array.isArray(scripts)) {\n return scripts\n .map((s: any) => (typeof s === \"string\" ? s : s?.src))\n .filter(\n (s): s is string =>\n typeof s === \"string\" && isSafeCustomElementSource(s),\n );\n }\n } catch {}\n\n return [];\n}\n\n/**\n * Load allowed custom elements and host patterns from IndexedDB.\n */\nexport async function loadCustomElementSecurityFromDb(\n db?: ShadowClawDatabase | null,\n): Promise<void> {\n try {\n const database = db ?? (await getDb());\n if (!database) {\n return;\n }\n\n const [elementsVal, hostsVal] = await Promise.all([\n getConfig(database, CONFIG_KEYS.ALLOWED_CUSTOM_ELEMENTS),\n getConfig(database, CONFIG_KEYS.ALLOWED_CUSTOM_ELEMENT_HOST_PATTERNS),\n ]);\n\n if (typeof elementsVal === \"string\" && elementsVal.trim()) {\n try {\n const parsed = JSON.parse(elementsVal);\n setAllowedCustomElements(parsed);\n } catch {\n setAllowedCustomElements(elementsVal);\n }\n }\n\n if (typeof hostsVal === \"string\" && hostsVal.trim()) {\n try {\n const parsed = JSON.parse(hostsVal);\n setAllowedCustomElementHostPatterns(parsed);\n } catch {\n setAllowedCustomElementHostPatterns(hostsVal);\n }\n }\n } catch (err) {\n console.warn(\"Failed to load custom element security from db:\", err);\n }\n}\n\nlet originalCustomElementsDefine: typeof customElements.define | null = null;\nlet isRegistryGuardInstalled = false;\n\n/**\n * Monkey-patches customElements.define to prevent registration of unapproved custom elements.\n */\nexport function installCustomElementsRegistryGuard(): void {\n initCustomElementSecurityFromEmbeddedConfig();\n\n if (\n isRegistryGuardInstalled ||\n typeof customElements === \"undefined\" ||\n typeof customElements.define !== \"function\"\n ) {\n return;\n }\n\n originalCustomElementsDefine = customElements.define.bind(customElements);\n\n customElements.define = function (\n name: string,\n constructor: CustomElementConstructor,\n options?: ElementDefinitionOptions,\n ) {\n const lowerName = (name || \"\").toLowerCase().trim();\n if (!isAllowedCustomElement(lowerName)) {\n const errorMsg = `[Security] Registration blocked: <${name}> is not an approved custom element.`;\n console.error(errorMsg);\n throw new Error(errorMsg);\n }\n\n return originalCustomElementsDefine!(name, constructor, options);\n };\n\n isRegistryGuardInstalled = true;\n}\n\n/**\n * Restores the original customElements.define (useful for testing).\n */\nexport function uninstallCustomElementsRegistryGuard(): void {\n if (!isRegistryGuardInstalled || !originalCustomElementsDefine) {\n return;\n }\n\n customElements.define = originalCustomElementsDefine;\n originalCustomElementsDefine = null;\n isRegistryGuardInstalled = false;\n}\n\n/**\n * Installs a MutationObserver on a DOM tree to detect and strip unapproved custom elements.\n */\nexport function installCustomElementDomGuard(\n root: Node = typeof document !== \"undefined\"\n ? document.documentElement\n : (null as any),\n): MutationObserver | null {\n if (typeof MutationObserver === \"undefined\" || !root) {\n return null;\n }\n\n // Sweep existing unapproved custom elements already present in root\n if (typeof (root as any).querySelectorAll === \"function\") {\n try {\n const existing = (root as Element).querySelectorAll(\"*\");\n existing.forEach((el) => {\n const tagName = el.tagName ? el.tagName.toLowerCase() : \"\";\n if (tagName.includes(\"-\") && !isAllowedCustomElement(tagName)) {\n console.warn(\n `[Security] Removing existing unapproved custom element: <${tagName}>`,\n );\n el.remove();\n }\n });\n } catch {}\n }\n\n const observer = new MutationObserver((mutations) => {\n for (const mutation of mutations) {\n mutation.addedNodes.forEach((node) => {\n if (node.nodeType === 1 /* Node.ELEMENT_NODE */) {\n const el = node as Element;\n const tagName = el.tagName ? el.tagName.toLowerCase() : \"\";\n if (tagName.includes(\"-\") && !isAllowedCustomElement(tagName)) {\n console.warn(\n `[Security] Removing unapproved custom element: <${tagName}>`,\n );\n el.remove();\n }\n }\n });\n }\n });\n\n observer.observe(root, { childList: true, subtree: true });\n\n return observer;\n}\n\n/**\n * Load an approved custom element script module dynamically.\n * Enforces domain validation and Trusted Types.\n */\nexport async function loadApprovedCustomElementScript(\n src: string,\n options: {\n type?: string;\n async?: boolean;\n defer?: boolean;\n } = {},\n): Promise<HTMLScriptElement> {\n if (!isSafeCustomElementSource(src)) {\n throw new Error(\n `[Security] Refused to load script from unapproved host: ${src}`,\n );\n }\n\n if (typeof document === \"undefined\") {\n throw new Error(\"Cannot load script outside browser document environment.\");\n }\n\n const existingScript = document.querySelector(`script[src=\"${src}\"]`);\n if (existingScript instanceof HTMLScriptElement) {\n return existingScript;\n }\n\n const trustedUrl = toTrustedScriptUrl(src) as string;\n\n return new Promise((resolve, reject) => {\n const script = document.createElement(\"script\");\n script.type = options.type || \"module\";\n if (options.async) script.async = true;\n if (options.defer) script.defer = true;\n script.src = trustedUrl;\n\n script.onload = () => resolve(script);\n script.onerror = (err) =>\n reject(\n new Error(`Failed to load custom element script: ${src} (${err})`),\n );\n\n document.head.appendChild(script);\n });\n}\n\nlet purifyHookRegistered = false;\n\n/**\n * Ensures DOMPurify has the custom element sanitization hook registered.\n */\nexport function ensureCustomElementSanitizerHook(): void {\n if (purifyHookRegistered) {\n return;\n }\n\n const purify = getDOMPurify();\n\n if (purify && typeof purify.addHook === \"function\") {\n const sanitizeCustomElementNode = (node: Node) => {\n if (node && node.nodeType === 1 /* ELEMENT_NODE */) {\n const el = node as Element;\n const tagName = (el.tagName || \"\").toLowerCase();\n if (tagName.includes(\"-\") && !isAllowedCustomElement(tagName)) {\n if (typeof el.remove === \"function\") {\n el.remove();\n }\n if (el.parentNode) {\n el.parentNode.removeChild(el);\n }\n }\n }\n };\n\n purify.addHook(\"uponSanitizeElement\", sanitizeCustomElementNode);\n purify.addHook(\"afterSanitizeElements\", sanitizeCustomElementNode);\n purifyHookRegistered = true;\n }\n}\n\n/**\n * Get DOMPurify configuration for custom element handling.\n */\nexport function getCustomElementPurifyConfig(): Config {\n ensureCustomElementSanitizerHook();\n\n return {\n CUSTOM_ELEMENT_HANDLING: {\n tagNameCheck: (tagName: string) => isAllowedCustomElement(tagName),\n attributeNameCheck: () => true,\n allowCustomizedBuiltInElements: false,\n },\n };\n}\n","/// <reference lib=\"dom\" />\nimport type { Config } from \"dompurify\";\nimport { parseRouteFromUrl } from \"../core/app-routes.js\";\nimport {\n ensureIframeSanitizerHook,\n getDOMPurify,\n} from \"../security/iframe-sanitizer.js\";\nimport {\n ensureCustomElementSanitizerHook,\n isAllowedCustomElement,\n} from \"../security/custom-element-security.js\";\n\nexport type HashInput = File | Blob | ArrayBuffer | ArrayBufferView;\n\n/**\n * Format a date for use in a filename: yyyy-mm-dd_hh-mm-ss\n */\nexport function formatDateForFilename(date = new Date()): string {\n const pad = (n: number) => String(n).padStart(2, \"0\");\n\n const yyyy = date.getFullYear();\n const mm = pad(date.getMonth() + 1);\n const dd = pad(date.getDate());\n\n const hh = pad(date.getHours());\n const min = pad(date.getMinutes());\n const ss = pad(date.getSeconds());\n\n return `${yyyy}-${mm}-${dd}_${hh}-${min}-${ss}`;\n}\n\n/**\n * Format a timestamp for display: e.g. \"Sun, Mar 1, 1:25 PM\"\n */\nexport function formatTimestamp(timestamp: number): string {\n const date = new Date(timestamp);\n\n return new Intl.DateTimeFormat(\"en-US\", {\n weekday: \"short\",\n month: \"short\",\n day: \"numeric\",\n hour: \"numeric\",\n minute: \"2-digit\",\n hour12: true,\n }).format(date);\n}\n\n/**\n * Escape HTML special characters in a string.\n */\nexport function escapeHtml(str: string): string {\n const div = document.createElement(\"div\");\n div.textContent = str;\n\n return div.innerHTML;\n}\n\n/**\n * Sanitize HTML content using DOMPurify, allowing custom element tags.\n */\nexport function sanitizeHtml(\n dirty: string | Node = \"\",\n options: Config = {},\n): string {\n ensureIframeSanitizerHook();\n ensureCustomElementSanitizerHook();\n\n return getDOMPurify().sanitize(dirty, {\n ADD_TAGS: [\"iframe\", \"figure\", \"figcaption\"],\n ADD_ATTR: [\n \"allow\",\n \"allowfullscreen\",\n \"frameborder\",\n \"scrolling\",\n \"referrerpolicy\",\n \"loading\",\n ],\n CUSTOM_ELEMENT_HANDLING: {\n tagNameCheck: (tagName: string) => isAllowedCustomElement(tagName),\n attributeNameCheck: () => true,\n allowCustomizedBuiltInElements: false,\n },\n ...options,\n });\n}\n\n/**\n * Interface representing the detailed internal navigation parameters\n */\nexport interface ShadowClawNavigateDetail {\n page: string;\n groupId?: string;\n path?: string;\n anchor?: string;\n}\n\n/**\n * Parses a special or relative link and dispatches the 'shadow-claw-navigate' custom event on document.\n * Returns true if the link was handled/intercepted, false otherwise.\n */\nexport function handleSpecialLinkNavigation(\n href: string,\n basePath: string = \"\",\n currentGroupId?: string,\n): boolean {\n let trimmed = href.trim();\n if (!trimmed) {\n return false;\n }\n\n // Handle malformed query strings where '?' is used instead of '&' (e.g. #Page?param1=val1?param2=val2)\n const firstQuestion = trimmed.indexOf(\"?\");\n if (firstQuestion !== -1) {\n const before = trimmed.slice(0, firstQuestion + 1);\n const after = trimmed.slice(firstQuestion + 1);\n trimmed = before + after.replace(/\\?/g, \"&\");\n }\n\n // 1. Check if it is a case-insensitive special link starting with \"/#\" or \"#\" matching standard pages\n if (trimmed.startsWith(\"/#\") || trimmed.startsWith(\"#\")) {\n const withoutHash = trimmed.startsWith(\"/#\")\n ? trimmed.slice(2)\n : trimmed.slice(1);\n\n // Parse parts: Page?query#anchor\n const pagePart = withoutHash.split(/[?#]/, 1)[0];\n const pageName = pagePart.toLowerCase();\n\n // Valid pages\n const validPages = [\"chat\", \"files\", \"tasks\", \"pages\", \"settings\"];\n if (validPages.includes(pageName)) {\n // Create a dummy absolute URL to parse searchParams easily\n const fakeUrl = trimmed.startsWith(\"/#\")\n ? trimmed.replace(/^\\/#/, \"http://local/\")\n : trimmed.replace(/^#/, \"http://local/\");\n const urlLike = new URL(fakeUrl, \"http://local/\");\n\n const groupId =\n urlLike.searchParams.get(\"groupId\") ||\n urlLike.searchParams.get(\"conversationId\") ||\n currentGroupId;\n const path =\n urlLike.searchParams.get(\"file\") ||\n urlLike.searchParams.get(\"path\") ||\n undefined;\n // Support: ?anchor=some-heading, ?anchor=L10-L20, or #fragment\n const anchorParam = urlLike.searchParams.get(\"anchor\");\n const anchor = anchorParam\n ? anchorParam\n : urlLike.hash\n ? urlLike.hash.slice(1)\n : undefined;\n\n const detail: ShadowClawNavigateDetail = {\n page: pageName,\n groupId: groupId || undefined,\n path: path || undefined,\n anchor: anchor || undefined,\n };\n\n document.dispatchEvent(\n new CustomEvent(\"shadow-claw-navigate\", {\n detail,\n bubbles: true,\n composed: true,\n }),\n );\n\n return true;\n }\n }\n\n // 1.5. Check if it is an absolute application route (e.g., /files/room:123/path, /chat/...)\n if (trimmed.startsWith(\"/\")) {\n try {\n const urlLike = new URL(trimmed, window.location.origin);\n const route = parseRouteFromUrl(urlLike, currentGroupId);\n if (route) {\n document.dispatchEvent(\n new CustomEvent(\"shadow-claw-navigate\", {\n detail: {\n page: route.page,\n groupId: route.groupId,\n path: route.path,\n anchor:\n route.anchor ||\n (urlLike.hash ? urlLike.hash.slice(1) : undefined),\n },\n bubbles: true,\n composed: true,\n }),\n );\n\n return true;\n }\n } catch {\n // Fallback to relative workspace path resolution below\n }\n }\n\n // 2. Relative or absolute workspace paths, e.g., \"docs/README.md\"\n // If it does not have a scheme (http, https, mailto, etc.) and is not external:\n const hasScheme = /^[a-zA-Z][a-zA-Z\\d+.-]*:/.test(trimmed);\n if (\n !hasScheme &&\n !trimmed.startsWith(\"//\") &&\n !trimmed.startsWith(\"javascript:\")\n ) {\n // Resolve absolute vs relative\n let resolvedPath = trimmed.split(/[?#]/, 1)[0].replace(/\\\\/g, \"/\");\n const isAbsolute = resolvedPath.startsWith(\"/\");\n resolvedPath = resolvedPath.replace(/^\\/+/, \"\");\n\n const urlLike = new URL(trimmed, \"http://local/\");\n const anchor = urlLike.hash ? urlLike.hash.slice(1) : undefined;\n\n let finalPath = resolvedPath;\n if (!isAbsolute && basePath) {\n const baseParts = basePath\n .replace(/\\\\/g, \"/\")\n .replace(/^\\/+/, \"\")\n .split(\"/\")\n .filter(Boolean);\n baseParts.pop(); // Remove the filename of base path\n\n const pathParts = resolvedPath.split(\"/\");\n const stack = [...baseParts];\n for (const part of pathParts) {\n if (!part || part === \".\") {\n continue;\n }\n\n if (part === \"..\") {\n stack.pop();\n } else {\n stack.push(part);\n }\n }\n\n finalPath = stack.join(\"/\");\n }\n\n if (finalPath) {\n const detail: ShadowClawNavigateDetail = {\n page: \"files\",\n groupId: currentGroupId || undefined,\n path: finalPath,\n anchor: anchor || undefined,\n };\n\n document.dispatchEvent(\n new CustomEvent(\"shadow-claw-navigate\", {\n detail,\n bubbles: true,\n composed: true,\n }),\n );\n\n return true;\n }\n }\n\n return false;\n}\n\n/**\n * Convert various input types to an ArrayBuffer for hashing.\n */\nexport function toArrayBuffer(input: HashInput): Promise<ArrayBuffer> {\n if (input instanceof Blob) {\n return input.arrayBuffer();\n }\n\n if (input instanceof ArrayBuffer) {\n return Promise.resolve(input.slice(0) as ArrayBuffer);\n }\n\n const { buffer, byteOffset, byteLength } = input;\n\n return Promise.resolve(\n buffer.slice(byteOffset, byteOffset + byteLength) as ArrayBuffer,\n );\n}\n\n/**\n * Convert an ArrayBuffer to a hex string.\n */\nexport function bufferToHex(buffer: ArrayBuffer): string {\n return Array.from(new Uint8Array(buffer))\n .map((b) => b.toString(16).padStart(2, \"0\"))\n .join(\"\");\n}\n\n/**\n * Compute the SHA-256 hash and return it as a hex string.\n */\nexport async function computeSha256(input: HashInput): Promise<string> {\n const data = await toArrayBuffer(input);\n const hashBuffer = await crypto.subtle.digest(\"SHA-256\", data);\n\n return bufferToHex(hashBuffer);\n}\n","/// <reference lib=\"dom\" />\nimport type { Config } from \"dompurify\";\n\nimport { escapeHtml, sanitizeHtml } from \"../utils/utils.js\";\n\ntype TrustedMarkup = string | { toString: () => string };\n\ntype TrustedTypesPolicyLike = {\n createHTML: (input: string) => TrustedMarkup;\n createScriptURL?: (input: string) => TrustedMarkup;\n};\n\ntype TrustedTypesFactoryLike = {\n createPolicy: (\n name: string,\n rules: {\n createHTML?: (input: string) => string;\n createScriptURL?: (input: string) => string;\n },\n ) => TrustedTypesPolicyLike;\n getPolicy?: (name: string) => TrustedTypesPolicyLike | null;\n};\n\nconst APP_TRUSTED_TYPES_POLICY_NAME = \"shadowclaw\";\n\nlet cachedPolicy: TrustedTypesPolicyLike | null | undefined;\n\nfunction getTrustedTypesFactory(): TrustedTypesFactoryLike | null {\n const factory = globalThis.trustedTypes;\n if (!factory || typeof factory.createPolicy !== \"function\") {\n return null;\n }\n\n return factory as TrustedTypesFactoryLike;\n}\n\nfunction getTrustedTypesPolicy(): TrustedTypesPolicyLike | null {\n if (cachedPolicy !== undefined) {\n return cachedPolicy;\n }\n\n const factory = getTrustedTypesFactory();\n if (!factory) {\n cachedPolicy = null;\n\n return cachedPolicy;\n }\n\n if (typeof factory.getPolicy === \"function\") {\n const existingPolicy = factory.getPolicy(APP_TRUSTED_TYPES_POLICY_NAME);\n if (existingPolicy) {\n cachedPolicy = existingPolicy;\n\n return cachedPolicy;\n }\n }\n\n try {\n cachedPolicy = factory.createPolicy(APP_TRUSTED_TYPES_POLICY_NAME, {\n // Input is already sanitized by sanitizeToTrustedHtml before policy use.\n // Keep this an identity transform so caller-provided sanitize options\n // (for example blob URL allowlists) are not lost.\n createHTML: (input: string) => input,\n createScriptURL: (input: string) => input,\n });\n } catch {\n if (typeof factory.getPolicy === \"function\") {\n cachedPolicy = factory.getPolicy(APP_TRUSTED_TYPES_POLICY_NAME) ?? null;\n } else {\n cachedPolicy = null;\n }\n }\n\n return cachedPolicy;\n}\n\nexport function getTrustedTypesPolicyName(): string {\n return APP_TRUSTED_TYPES_POLICY_NAME;\n}\n\nexport function sanitizeToTrustedHtml(\n dirty: string | Node = \"\",\n options: Config = {},\n): TrustedMarkup {\n const sanitized = sanitizeHtml(dirty, options);\n const policy = getTrustedTypesPolicy();\n\n if (!policy) {\n return sanitized;\n }\n\n return policy.createHTML(sanitized);\n}\n\nexport function escapeToTrustedHtml(text: string): TrustedMarkup {\n return sanitizeToTrustedHtml(escapeHtml(text));\n}\n\nexport function sanitizeSrcdocHtml(html: string, options: Config = {}): string {\n return sanitizeHtml(html, options);\n}\n\nexport function toTrustedHtmlPresanitized(html: string): TrustedMarkup {\n const policy = getTrustedTypesPolicy();\n\n if (!policy) {\n return html;\n }\n\n return policy.createHTML(html);\n}\n\nexport function setSanitizedHtml(\n element: Element,\n dirty: string | Node = \"\",\n options: Config = {},\n): TrustedMarkup {\n const trustedHtml = sanitizeToTrustedHtml(dirty, options);\n\n element.innerHTML = trustedHtml as string;\n\n return trustedHtml;\n}\n\nexport function setEscapedHtml(element: Element, text: string): TrustedMarkup {\n const trustedHtml = escapeToTrustedHtml(text);\n\n element.innerHTML = trustedHtml as string;\n\n return trustedHtml;\n}\n\nexport function setSanitizedSrcdoc(\n iframe: HTMLIFrameElement,\n dirty: string,\n options: Config = {},\n): TrustedMarkup {\n const trustedHtml = sanitizeToTrustedHtml(dirty, options);\n\n iframe.srcdoc = trustedHtml as string;\n\n return trustedHtml;\n}\n\nexport function setTrustedSrcdoc(\n iframe: HTMLIFrameElement,\n html: string,\n): TrustedMarkup {\n const trustedHtml = toTrustedHtmlPresanitized(html);\n\n iframe.srcdoc = trustedHtml as string;\n\n return trustedHtml;\n}\n\nexport function toTrustedScriptUrl(url: string): TrustedMarkup {\n const policy = getTrustedTypesPolicy();\n\n if (!policy || typeof policy.createScriptURL !== \"function\") {\n return url;\n }\n\n return policy.createScriptURL(url);\n}\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{r as e}from"./config-CrHchneq.js";import{c as t}from"./app-routes-Bs-riIvr.js";import{n}from"./txPromise-EBECky1b.js";import{t as r}from"./getConfig-D89uJgo5.js";import{i,n as a,t as o}from"./iframe-sanitizer-y2Z1pPwY.js";function s(e=new Date){let t=e=>String(e).padStart(2,`0`);return`${e.getFullYear()}-${t(e.getMonth()+1)}-${t(e.getDate())}_${t(e.getHours())}-${t(e.getMinutes())}-${t(e.getSeconds())}`}function c(e){let t=new Date(e);return new Intl.DateTimeFormat(`en-US`,{weekday:`short`,month:`short`,day:`numeric`,hour:`numeric`,minute:`2-digit`,hour12:!0}).format(t)}function l(e){let t=document.createElement(`div`);return t.textContent=e,t.innerHTML}function u(e=``,t={}){return o(),ie(),a().sanitize(e,{ADD_TAGS:[`iframe`,`figure`,`figcaption`],ADD_ATTR:[`allow`,`allowfullscreen`,`frameborder`,`scrolling`,`referrerpolicy`,`loading`],CUSTOM_ELEMENT_HANDLING:{tagNameCheck:e=>M(e),attributeNameCheck:()=>!0,allowCustomizedBuiltInElements:!1},...t})}function d(e,n=``,r){let i=e.trim();if(!i)return!1;let a=i.indexOf(`?`);if(a!==-1&&(i=i.slice(0,a+1)+i.slice(a+1).replace(/\?/g,`&`)),i.startsWith(`/#`)||i.startsWith(`#`)){let e=(i.startsWith(`/#`)?i.slice(2):i.slice(1)).split(/[?#]/,1)[0].toLowerCase();if([`chat`,`files`,`tasks`,`pages`,`settings`].includes(e)){let t=i.startsWith(`/#`)?i.replace(/^\/#/,`http://local/`):i.replace(/^#/,`http://local/`),n=new URL(t,`http://local/`),a=n.searchParams.get(`groupId`)||n.searchParams.get(`conversationId`)||r,o=n.searchParams.get(`file`)||n.searchParams.get(`path`)||void 0,s=n.searchParams.get(`anchor`)||(n.hash?n.hash.slice(1):void 0),c={page:e,groupId:a||void 0,path:o||void 0,anchor:s||void 0};return document.dispatchEvent(new CustomEvent(`shadow-claw-navigate`,{detail:c,bubbles:!0,composed:!0})),!0}}if(i.startsWith(`/`))try{let e=new URL(i,window.location.origin),n=t(e,r);if(n)return document.dispatchEvent(new CustomEvent(`shadow-claw-navigate`,{detail:{page:n.page,groupId:n.groupId,path:n.path,anchor:n.anchor||(e.hash?e.hash.slice(1):void 0)},bubbles:!0,composed:!0})),!0}catch{}if(!/^[a-zA-Z][a-zA-Z\d+.-]*:/.test(i)&&!i.startsWith(`//`)&&!i.startsWith(`javascript:`)){let e=i.split(/[?#]/,1)[0].replace(/\\/g,`/`),t=e.startsWith(`/`);e=e.replace(/^\/+/,``);let a=new URL(i,`http://local/`),o=a.hash?a.hash.slice(1):void 0,s=e;if(!t&&n){let t=n.replace(/\\/g,`/`).replace(/^\/+/,``).split(`/`).filter(Boolean);t.pop();let r=e.split(`/`),i=[...t];for(let e of r)!e||e===`.`||(e===`..`?i.pop():i.push(e));s=i.join(`/`)}if(s){let e={page:`files`,groupId:r||void 0,path:s,anchor:o||void 0};return document.dispatchEvent(new CustomEvent(`shadow-claw-navigate`,{detail:e,bubbles:!0,composed:!0})),!0}}return!1}const f=`shadowclaw`;let p;function m(){let e=globalThis.trustedTypes;return!e||typeof e.createPolicy!=`function`?null:e}function h(){if(p!==void 0)return p;let e=m();if(!e)return p=null,p;if(typeof e.getPolicy==`function`){let t=e.getPolicy(f);if(t)return p=t,p}try{p=e.createPolicy(f,{createHTML:e=>e,createScriptURL:e=>e})}catch{p=typeof e.getPolicy==`function`?e.getPolicy(f)??null:null}return p}function g(e=``,t={}){let n=u(e,t),r=h();return r?r.createHTML(n):n}function _(e,t={}){return u(e,t)}function v(e){let t=h();return t?t.createHTML(e):e}function y(e,t=``,n={}){let r=g(t,n);return e.innerHTML=r,r}function ee(e,t){let n=v(t);return e.srcdoc=n,n}function b(e){let t=h();return!t||typeof t.createScriptURL!=`function`?e:t.createScriptURL(e)}const x=[],S=[];let C=new Set(x.map(e=>e.toLowerCase().trim())),w=[...S],T=[];function E(e){T=e.map(e=>i(e)).filter(Boolean)}E(w);function D(e){return Array.isArray(e)?e.map(e=>typeof e==`string`?e.toLowerCase().trim():``).filter(Boolean):typeof e==`string`?e.split(/[\n,]+/).map(e=>e.toLowerCase().trim()).filter(Boolean):[]}function O(e){return Array.isArray(e)?e.map(e=>typeof e==`string`?e.trim():``).filter(Boolean):typeof e==`string`?e.split(/[\n,]+/).map(e=>e.trim()).filter(Boolean):[]}function k(e){let t=D(e);C=new Set(t)}function A(e){let t=O(e);w=t,E(t)}function j(){return[...w]}function M(e){if(!e||typeof e!=`string`)return!1;let t=e.trim().toLowerCase();return!t.includes(`-`)||t===`shadow-claw`||t.startsWith(`shadow-claw-`)?!0:C.has(t)}function te(e){if(!e||typeof e!=`string`)return!1;let t=e.trim();if(!t||/^(?:javascript|data|vbscript):/i.test(t))return!1;if(/^blob:/i.test(t))return!0;try{let e=typeof window<`u`&&window.location?.origin&&window.location.origin!==`null`?window.location.origin:`http://localhost`,n=new URL(t,e);if(n.protocol!==`http:`&&n.protocol!==`https:`)return!1;if(typeof window<`u`&&window.location?.origin&&window.location.origin!==`null`&&n.origin===window.location.origin)return!0;let r=n.hostname.toLowerCase();return T.some(e=>e(r))}catch{return!1}}const N=`allow-modals allow-scripts allow-popups allow-popups-to-escape-sandbox`,P=[`'self'`,`blob:`,`data:`],F=[`'self'`,`blob:`,`data:`],I=[`'self'`,`'unsafe-inline'`,`https:`,`http:`],L=[`'self'`,`blob:`,`data:`,`https:`,`http:`];let R=N,z=[...P],B=[...F],V=[],H=[...I],U=[...L];function W(){return R}function G(e){R=Array.isArray(e)?e.map(e=>typeof e==`string`?e.trim():``).filter(Boolean).join(` `):typeof e==`string`&&e.trim()?e.trim():N}function K(e){let t=j(),n=Y(),r=new Set;for(let e of t)e&&/^(\*\.)?[a-zA-Z0-9.-]+(?::[0-9]+)?$/.test(e)&&(r.add(`https://${e}`),r.add(`http://${e}`));for(let e of n)try{let t=new URL(e,typeof window<`u`&&window.location?.origin?window.location.origin:`http://localhost`);r.add(t.origin)}catch{}let i=[`'nonce-${e}'`,...Array.from(r),...V],a=[...B,...Array.from(r)];return[`script-src ${Array.from(new Set(i)).join(` `)}`,`worker-src ${Array.from(new Set(z)).join(` `)}`,`connect-src ${Array.from(new Set(a)).join(` `)}`,`style-src ${Array.from(new Set(H)).join(` `)}`,`img-src ${Array.from(new Set(U)).join(` `)}`].join(`; `)}function q(e){if(!e||typeof e!=`object`)return;let t=e.allowedCustomElements||(typeof e.customElements==`object`&&!Array.isArray(e.customElements)?e.customElements?.allowedElements:void 0);t!==void 0&&k(t);let n=e.allowedCustomElementDomains||(typeof e.customElements==`object`&&!Array.isArray(e.customElements)?e.customElements?.allowedDomains:void 0);n!==void 0&&A(n),e.security?.iframeSandbox===void 0?(e.security?.allowSameOrigin===!0||e.security?.allowIframeSameOrigin===!0)&&(R.includes(`allow-same-origin`)||(R=`${R} allow-same-origin`.trim())):G(e.security.iframeSandbox),e.security?.workerSrc!==void 0&&(z=O(e.security.workerSrc)),e.security?.connectSrc!==void 0&&(B=O(e.security.connectSrc)),e.security?.scriptSrc!==void 0&&(V=O(e.security.scriptSrc)),e.security?.styleSrc!==void 0&&(H=O(e.security.styleSrc)),e.security?.imgSrc!==void 0&&(U=O(e.security.imgSrc))}function J(){if(typeof document>`u`)return;let e=document.getElementById(`shadow-claw-site-config`);if(e&&e.textContent)try{q(JSON.parse(e.textContent))}catch{}}function Y(){if(typeof document>`u`)return[];let e=document.getElementById(`shadow-claw-site-config`);if(!e||!e.textContent)return[];try{let t=JSON.parse(e.textContent),n=typeof t.customElements==`object`&&!Array.isArray(t.customElements)?t.customElements?.scripts:void 0;if(Array.isArray(n))return n.map(e=>typeof e==`string`?e:e?.src).filter(e=>typeof e==`string`&&te(e))}catch{}return[]}async function X(t){try{let i=t??await n();if(!i)return;let[a,o]=await Promise.all([r(i,e.ALLOWED_CUSTOM_ELEMENTS),r(i,e.ALLOWED_CUSTOM_ELEMENT_HOST_PATTERNS)]);if(typeof a==`string`&&a.trim())try{k(JSON.parse(a))}catch{k(a)}if(typeof o==`string`&&o.trim())try{A(JSON.parse(o))}catch{A(o)}}catch(e){console.warn(`Failed to load custom element security from db:`,e)}}let Z=null,Q=!1;function ne(){J(),!(Q||typeof customElements>`u`||typeof customElements.define!=`function`)&&(Z=customElements.define.bind(customElements),customElements.define=function(e,t,n){if(!M((e||``).toLowerCase().trim())){let t=`[Security] Registration blocked: <${e}> is not an approved custom element.`;throw console.error(t),Error(t)}return Z(e,t,n)},Q=!0)}function re(e=typeof document<`u`?document.documentElement:null){if(typeof MutationObserver>`u`||!e)return null;if(typeof e.querySelectorAll==`function`)try{e.querySelectorAll(`*`).forEach(e=>{let t=e.tagName?e.tagName.toLowerCase():``;t.includes(`-`)&&!M(t)&&(console.warn(`[Security] Removing existing unapproved custom element: <${t}>`),e.remove())})}catch{}let t=new MutationObserver(e=>{for(let t of e)t.addedNodes.forEach(e=>{if(e.nodeType===1){let t=e,n=t.tagName?t.tagName.toLowerCase():``;n.includes(`-`)&&!M(n)&&(console.warn(`[Security] Removing unapproved custom element: <${n}>`),t.remove())}})});return t.observe(e,{childList:!0,subtree:!0}),t}let $=!1;function ie(){if($)return;let e=a();if(e&&typeof e.addHook==`function`){let t=e=>{if(e&&e.nodeType===1){let t=e,n=(t.tagName||``).toLowerCase();n.includes(`-`)&&!M(n)&&(typeof t.remove==`function`&&t.remove(),t.parentNode&&t.parentNode.removeChild(t))}};e.addHook(`uponSanitizeElement`,t),e.addHook(`afterSanitizeElements`,t),$=!0}}export{d as _,re as a,X as c,ee as d,v as f,c as g,s as h,W as i,_ as l,l as m,Y as n,ne as o,b as p,K as r,M as s,q as t,y as u};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{bn as e}from"./orchestrator-D-xlXG92.js";import{t}from"./getGroupDir-P1h9wl6S.js";async function n(n,r,i){let a=await t(n,r),{dirs:o,filename:s}=e(i),c=a;for(let e of o)c=await c.getDirectoryHandle(e);let l=await(await c.getFileHandle(s)).getFile(),u=URL.createObjectURL(l),d=document.createElement(`a`);d.href=u,d.download=s,document.body.appendChild(d),d.click(),document.body.removeChild(d),URL.revokeObjectURL(u)}export{n as t};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{u as e}from"./toast-HAq8XWFj.js";let t=!0;const n=new e.subtle.Watcher(()=>{t&&(t=!1,globalThis.queueMicrotask(r))});function r(){t=!0;for(let e of n.getPending())e.get();n.watch()}function i(t){let r,i=new e.Computed(()=>{typeof r==`function`&&r(),r=t()});return n.watch(i),i.get(),()=>{n.unwatch(i),typeof r==`function`&&r(),r=void 0}}export{i as t};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{o as e}from"./config-CrHchneq.js";import{u as t}from"./toast-HAq8XWFj.js";import{bn as n,gn as r,yn as i}from"./orchestrator-D-xlXG92.js";import{t as a}from"./getGroupDir-P1h9wl6S.js";async function o(e,t,r){let i=await a(e,t),{dirs:o,filename:s}=n(r),c=i;for(let e of o)c=await c.getDirectoryHandle(e);return await(await c.getFileHandle(s)).getFile()}const s=new class{_file;constructor(){this._file=new t.State(null)}closeFile(){this._file.set(null)}get file(){return this._file.get()}getFile(){return this.file}getPreviewBinaryMimeType(e){return{"3gp":`video/3gpp`,"7z":`application/x-7z-compressed`,aac:`audio/aac`,apng:`image/apng`,avi:`video/x-msvideo`,avif:`image/avif`,bin:`application/octet-stream`,bmp:`image/bmp`,db:`application/vnd.sqlite3`,dll:`application/octet-stream`,dmg:`application/octet-stream`,dylib:`application/octet-stream`,exe:`application/vnd.microsoft.portable-executable`,flac:`audio/flac`,flv:`video/x-flv`,gif:`image/gif`,gz:`application/gzip`,heic:`image/heic`,heif:`image/heif`,ico:`image/x-icon`,iso:`application/octet-stream`,jpeg:`image/jpeg`,jpg:`image/jpeg`,m4a:`audio/mp4`,m4v:`video/mp4`,mkv:`video/x-matroska`,mov:`video/mp4`,mp3:`audio/mpeg`,mp4:`video/mp4`,oga:`audio/ogg`,ogg:`audio/ogg`,ogv:`video/ogg`,png:`image/png`,rar:`application/vnd.rar`,so:`application/octet-stream`,sqlite:`application/vnd.sqlite3`,sqlite3:`application/vnd.sqlite3`,tar:`application/x-tar`,tif:`image/tiff`,tiff:`image/tiff`,wasm:`application/wasm`,wav:`audio/wav`,weba:`audio/webm`,webm:`video/webm`,webp:`image/webp`,wmv:`video/x-ms-wmv`,zip:`application/zip`}[e.toLowerCase().split(`.`).pop()||``]||``}async openFile(t,n,a=e){try{let e=n.split(`/`).pop()||n,s=/\.pdf$/i.test(e),c=this.getPreviewBinaryMimeType(e);if(s){let r=await i(t,a,n);this._file.set({name:e,path:n,groupId:a,content:``,kind:`pdf`,binaryContent:r,mimeType:`application/pdf`});return}if(c){let r=await o(t,a,n);this._file.set({name:e,path:n,groupId:a,content:``,kind:`binary`,binaryContent:null,nativeFile:r,mimeType:c});return}let l=await r(t,a,n);this._file.set({name:e,path:n,groupId:a,content:l,kind:`text`,binaryContent:null,mimeType:`text/plain`})}catch(e){throw console.error(`Failed to open file:`,n,e),e}}};export{s as t};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{i as e}from"./rolldown-runtime-aKtaBQYM.js";import{r as t}from"./config-CrHchneq.js";import{i as n}from"./app-routes-Bs-riIvr.js";import{n as r}from"./txPromise-EBECky1b.js";import{t as i}from"./ulid-BY7rQVLN.js";import{t as a}from"./browser-nBz_r6l4.js";import{t as o}from"./getAllTasks-vpBlgGsc.js";var s=e(a(),1),c=class{_transport;_url;_httpUrl;_token;_clientId;_peerId;_deviceLabel;_capabilities;_version;_heartbeatIntervalMs;_reconnectDelayMs;_maxReconnectDelayMs;_handlers;_WebSocketClass;_EventSourceClass;_fetchFn;_ws=null;_es=null;_heartbeatTimer=null;_reconnectTimer=null;_currentReconnectDelay;_isDestroyed=!1;_state=`disconnected`;constructor(e){if(this._transport=e.transport||`sse`,this._clientId=e.clientId,this._peerId=e.peerId,this._deviceLabel=e.deviceLabel||`ShadowClaw Browser Client`,this._capabilities=e.capabilities||[`webmcp`,`opfs`,`push`],this._version=e.version||`1.23.4`,this._token=e.token,this._heartbeatIntervalMs=e.heartbeatIntervalMs||1e4,this._reconnectDelayMs=e.reconnectDelayMs||1e3,this._maxReconnectDelayMs=e.maxReconnectDelayMs||3e4,this._currentReconnectDelay=this._reconnectDelayMs,this._handlers=new Map,this._WebSocketClass=e.WebSocketClass||(typeof WebSocket<`u`?WebSocket:null),this._EventSourceClass=e.EventSourceClass||(typeof EventSource<`u`?EventSource:null),this._fetchFn=e.fetchFn||(typeof fetch<`u`?fetch.bind(globalThis):(()=>Promise.reject(Error(`fetch not available`)))),e.handlers)for(let[t,n]of Object.entries(e.handlers))this.registerHandler(t,n);let t=typeof location<`u`?location:null,n=t?`${t.protocol}//${t.host}`:`http://127.0.0.1:8888`,r=t?`${t.protocol===`https:`?`wss:`:`ws:`}//${t.host}`:`ws://127.0.0.1:8888`;this._url=e.url||`${r}/ws/control`,this._httpUrl=e.httpUrl||n}get transport(){return this._transport}registerHandler(e,t){this._handlers.set(e,t)}unregisterHandler(e){this._handlers.delete(e)}getState(){return this._state}connect(){this._isDestroyed||this._state===`connected`||this._state===`connecting`||(this._transport===`websocket`?this._connectWebSocket():this._connectSse())}_connectWebSocket(){if(!this._WebSocketClass){console.warn(`[ControlPlaneClient] WebSocket not supported in this environment`);return}this._state=`connecting`;let e=new URL(this._url,`ws://127.0.0.1:8888`);this._token&&e.searchParams.set(`token`,this._token);try{let t=new this._WebSocketClass(e.toString());this._ws=t,t.onopen=()=>{this._state=`connected`,this._currentReconnectDelay=this._reconnectDelayMs,this._sendRegister(),this._startHeartbeat()},t.onmessage=e=>{this._handleMessage(e.data)},t.onclose=()=>{this._cleanupConnection(),this._isDestroyed||this._scheduleReconnect()},t.onerror=e=>{console.warn(`[ControlPlaneClient] WebSocket error:`,e)}}catch(e){console.warn(`[ControlPlaneClient] Failed to establish WebSocket connection:`,e),this._cleanupConnection(),this._scheduleReconnect()}}_connectSse(){if(!this._EventSourceClass){(s.default===void 0||!s.default.env?.JEST_WORKER_ID)&&console.warn(`[ControlPlaneClient] EventSource not supported in this environment`);return}this._state=`connecting`;let e=new URL(`/api/control/events`,this._httpUrl);e.searchParams.set(`clientId`,this._clientId),this._token&&e.searchParams.set(`token`,this._token);try{let t=new this._EventSourceClass(e.toString());this._es=t,t.onopen=()=>{this._state=`connected`,this._currentReconnectDelay=this._reconnectDelayMs,this._sendRegister(),this._startHeartbeat()},typeof t.addEventListener==`function`&&t.addEventListener(`command:execute`,e=>{this._handleMessage(e.data)}),t.onmessage=e=>{this._handleMessage(e.data)},t.onerror=e=>{console.warn(`[ControlPlaneClient] SSE connection error:`,e),this._cleanupConnection(),this._isDestroyed||this._scheduleReconnect()}}catch(e){console.warn(`[ControlPlaneClient] Failed to establish SSE connection:`,e),this._cleanupConnection(),this._scheduleReconnect()}}disconnect(){this._isDestroyed=!0,this._cleanupConnection(),this._reconnectTimer&&=(clearTimeout(this._reconnectTimer),null)}_cleanupConnection(){if(this._state=`disconnected`,this._stopHeartbeat(),this._ws){try{this._ws.close()}catch{}this._ws=null}if(this._es){try{this._es.close()}catch{}this._es=null}}_scheduleReconnect(){this._reconnectTimer||this._isDestroyed||(this._reconnectTimer=setTimeout(()=>{this._reconnectTimer=null,this._isDestroyed||this.connect()},this._currentReconnectDelay),this._currentReconnectDelay=Math.min(this._currentReconnectDelay*1.5,this._maxReconnectDelayMs))}_startHeartbeat(){this._stopHeartbeat(),this._heartbeatTimer=setInterval(()=>{this._sendHeartbeat()},this._heartbeatIntervalMs)}_stopHeartbeat(){this._heartbeatTimer&&=(clearInterval(this._heartbeatTimer),null)}_sendRegister(){let e={clientId:this._clientId,deviceLabel:this._deviceLabel,capabilities:this._capabilities,version:this._version,transport:this._transport,peerId:this._peerId};this._sendMessage({id:i(),type:`client:register`,payload:e})}_sendHeartbeat(){let e={clientId:this._clientId,timestamp:Date.now()};this._sendMessage({id:i(),type:`client:heartbeat`,payload:e})}_sendMessage(e){if(this._transport===`websocket`){this._ws&&(this._ws.readyState===1||this._ws.readyState===this._WebSocketClass?.OPEN)&&this._ws.send(JSON.stringify(e));return}let t=new URL(`/api/control/messages`,this._httpUrl),n={"Content-Type":`application/json`};this._token&&(n[`x-control-token`]=this._token,n.Authorization=`Bearer ${this._token}`);let r={method:`POST`,headers:n,body:JSON.stringify(e)},i=t.hostname.toLowerCase(),a=i===`localhost`||i===`127.0.0.1`||i===`::1`||i===`[::1]`,o=/^(10\.|172\.(1[6-9]|2\d|3[01])\.|192\.168\.)/.test(i);a?r.targetAddressSpace=`loopback`:o&&(r.targetAddressSpace=`private`),this._fetchFn(t.toString(),r).catch(e=>{console.warn(`[ControlPlaneClient] Failed to send message via HTTP POST:`,e)})}async _handleMessage(e){if(!e||typeof e!=`string`)return;let t;try{t=JSON.parse(e)}catch{return}if(t.type===`command:execute`){let{commandId:e,action:n,args:r}=t.payload,a=this._handlers.get(n);if(!a){this._sendMessage({id:i(),type:`command:result`,replyTo:t.id,payload:{commandId:e,success:!1,error:`Unknown action: ${n}`}});return}try{let n=await a(r);this._sendMessage({id:i(),type:`command:result`,replyTo:t.id,payload:{commandId:e,success:!0,data:n}})}catch(n){this._sendMessage({id:i(),type:`command:result`,replyTo:t.id,payload:{commandId:e,success:!1,error:n.message||String(n)}})}}}};function l(){if(typeof localStorage<`u`)try{let e=localStorage.getItem(t.CONTROL_PLANE_CLIENT_ID);if(e&&e.trim())return e.trim()}catch{}let e=n(),r=e?`${e}-${i().toLowerCase()}`:`client-${i().toLowerCase()}`;if(typeof localStorage<`u`)try{localStorage.setItem(t.CONTROL_PLANE_CLIENT_ID,r)}catch{}return r}function u(){if(typeof localStorage<`u`)try{let e=localStorage.getItem(t.CONTROL_PLANE_ENABLED);if(e!==null)return e===`true`||e===`1`}catch{}return!1}async function d(e){if(typeof localStorage<`u`)try{let e=localStorage.getItem(t.CONTROL_PLANE_ENABLED);if(e!==null)return e===`true`||e===`1`}catch{}if(e)try{let{getConfig:n}=await import(`./getConfig-D89uJgo5.js`).then(e=>e.n),r=await n(e,t.CONTROL_PLANE_ENABLED);if(r!=null)return r===`true`||r===`1`}catch{}return!1}function f(e){if(typeof EventSource>`u`&&typeof WebSocket>`u`)return!1;let t=e||(typeof location<`u`?location:null);return!(!t||t.protocol===`file:`||typeof document<`u`&&document.querySelector(`meta[name="shadowclaw-static-only"]`))}function p(e){let n=``;if(typeof localStorage<`u`)try{n=(localStorage.getItem(t.CONTROL_PLANE_URL)||``).trim()}catch{}let r=e||(typeof location<`u`?location:null),i=r&&(r.protocol===`file:`||r.hostname&&(r.hostname.endsWith(`.github.io`)||r.hostname.endsWith(`.pages.dev`))),a=n;a||=i?`http://127.0.0.1:8888`:r&&r.host?`${r.protocol}//${r.host}`:`http://127.0.0.1:8888`,a=a.replace(/\/+$/,``);let o=a.replace(/^https?:/,e=>e===`https:`?`wss:`:`ws:`);return{httpUrl:a,wsUrl:`${o}/ws/control`}}function m(){let e=[];return typeof navigator<`u`&&(navigator.storage&&typeof navigator.storage.getDirectory==`function`&&e.push(`opfs`),`serviceWorker`in navigator&&typeof window<`u`&&`PushManager`in window&&e.push(`push`),(typeof document<`u`&&document.modelContext||navigator&&navigator.modelContext)&&e.push(`webmcp`)),typeof RTCPeerConnection<`u`&&e.push(`peerjs`),e}function h(){if(typeof navigator>`u`)return`ShadowClaw Node`;let e=navigator.userAgent,t=`Desktop`;/iPad/i.test(e)?t=`iPad`:/iPhone/i.test(e)?t=`iPhone`:/Android/i.test(e)?t=`Android`:/Macintosh/i.test(e)?t=`Mac`:/Windows/i.test(e)?t=`Windows`:/Linux/i.test(e)&&(t=`Linux`);let n=`Browser`;return/Chrome/i.test(e)&&!/Edg/i.test(e)?n=`Chrome`:/Safari/i.test(e)&&!/Chrome/i.test(e)?n=`Safari`:/Firefox/i.test(e)?n=`Firefox`:/Edg/i.test(e)&&(n=`Edge`),`${t} ${n}`}let g=null;async function _(e,t={},n={}){let i=l(),a=h(),s=m();switch(e){case`send-message`:{if(!t.text)throw Error(`Missing text parameter`);let{orchestratorStore:e}=await import(`./orchestrator-D-xlXG92.js`).then(e=>e.n),r=n.orchestrator||e.orchestrator,i=t.groupId||e.activeGroupId||`br:main`;return r?.browserChat?.submit?(r.browserChat.submit(t.text,i),{queued:!0,groupId:i}):r?.submitMessage?(r.submitMessage(t.text,i),{queued:!0,groupId:i}):e.sendMessage?(e.sendMessage(t.text),{queued:!0,groupId:i}):{queued:!1,error:`Orchestrator not ready`}}case`list-tasks`:{let e=await o(await r());return t?.groupId&&(e=e.filter(e=>e.groupId===t.groupId)),{tasks:e}}case`read-state`:{let{orchestratorStore:e}=await import(`./orchestrator-D-xlXG92.js`).then(e=>e.n),t=n.orchestrator||e.orchestrator;return{clientId:i,deviceLabel:a,capabilities:s,activeGroupId:n.orchestrator?.activeGroupId||e.activeGroupId||t?.activeGroupId||`br:main`,state:n.orchestrator?.state||e.state||t?.state||`idle`}}case`list-tools`:{try{let{getWebMcpTools:e}=await import(`./webmcp-DAjmliCx.js`).then(e=>e.a),t=await e();if(t&&t.length>0)return{tools:t.map(e=>({name:e.name,description:e.description,inputSchema:e.inputSchema,annotations:e.annotations}))}}catch{}let{TOOL_DEFINITIONS:e}=await import(`./tools-C8x3nmo4.js`).then(e=>e.n),{parseWebMcpInputSchema:t}=await import(`./webmcp-DAjmliCx.js`).then(e=>e.a);return{tools:e.map(e=>({name:e.name,description:e.description,inputSchema:t(e.input_schema)}))}}case`invoke-tool`:{if(!t.toolName)throw Error(`Missing toolName parameter`);let e=typeof document<`u`&&document.modelContext||typeof navigator<`u`&&navigator.modelContext;if(e){if(typeof e.getTools==`function`)try{let n=await e.getTools(),r=Array.isArray(n)?n.find(e=>e.name===t.toolName):void 0;if(r&&typeof r.execute==`function`)return{result:await r.execute(t.input||{})}}catch{}if(typeof e.executeTool==`function`)return{result:await e.executeTool({name:t.toolName},typeof t.input==`string`?t.input:JSON.stringify(t.input||{}))};if(typeof e.invoke==`function`)return{result:await e.invoke(t.toolName,t.input||{})}}let{orchestratorStore:r}=await import(`./orchestrator-D-xlXG92.js`).then(e=>e.n),i=n.orchestrator||r.orchestrator,a=i?.agentWorker;if(a&&typeof a.postMessage==`function`){let e=Date.now().toString(36)+Math.random().toString(36).slice(2);return{result:await new Promise((n,r)=>{let o=setTimeout(()=>{a.removeEventListener(`message`,s),r(Error(`Timeout waiting for tool execution`))},6e4),s=t=>{let i=t.data;i&&i.type===`execute-tool-result`&&i.callId===e&&(clearTimeout(o),a.removeEventListener(`message`,s),i.error?r(Error(i.error)):n(i.result))};a.addEventListener(`message`,s),a.postMessage({type:`execute-tool`,callId:e,payload:{name:t.toolName,input:t.input||{},groupId:t.groupId||i.activeGroupId||`br:main`}})})}}throw Error(`Tool ${t.toolName} could not be executed (no context or worker available)`)}case`trigger-backup`:{let{orchestratorStore:e}=await import(`./orchestrator-D-xlXG92.js`).then(e=>e.n),a=t.groupId||n.orchestrator?.activeGroupId||e.activeGroupId||`br:main`,o=await r(),{getGroupDir:s}=await import(`./getGroupDir-P1h9wl6S.js`).then(e=>e.n),c=await s(o,a);async function l(e,t=``){let n=[];for await(let[r,i]of e.entries()){let e=t?`${t}/${r}`:r;if(i.kind===`directory`){let t=await l(i,e);n.push(...t)}else n.push(e)}return n}async function u(e){try{let t=e.split(`/`),n=c;for(let e=0;e<t.length-1;e++)n=await n.getDirectoryHandle(t[e]);let r=await(await(await n.getFileHandle(t[t.length-1])).getFile()).arrayBuffer();return new Uint8Array(r)}catch{return null}}let{BackupController:d}=await import(`./backup-controller-CvzDOq4T.js`);return await new d({clientId:i,token:t.token,serverBaseUrl:p().httpUrl,fileEnumerator:()=>l(c),fileReader:e=>u(e)}).initiate()}default:throw Error(`Unknown action '${e}'`)}}function v(e={}){if(g){try{g.disconnect()}catch{}g=null}let n=e.clientId&&e.clientId.trim()||l(),r=m(),i=h(),a=null;if(typeof localStorage<`u`)try{let e=localStorage.getItem(t.CONTROL_PLANE_TRANSPORT);(e===`sse`||e===`websocket`)&&(a=e)}catch{}let o=e.transport||a||`sse`,s;if(typeof localStorage<`u`)try{s=localStorage.getItem(t.PEERJS_MY_PEER_ID)||void 0}catch{}let{httpUrl:u,wsUrl:d}=p(),v=new c({clientId:n,deviceLabel:i,capabilities:r,peerId:s,transport:o,httpUrl:u,url:d,handlers:{"send-message":t=>_(`send-message`,t,e),"list-tasks":t=>_(`list-tasks`,t,e),"read-state":t=>_(`read-state`,t,e),"invoke-tool":t=>_(`invoke-tool`,t,e),"list-tools":t=>_(`list-tools`,t,e),"trigger-backup":t=>_(`trigger-backup`,t,e)}});return e.autoConnect!==!1&&f()&&v.connect(),g=v,v}function y(){if(g){try{g.disconnect()}catch{}g=null}}export{v as createDefaultControlPlaneClient,_ as executeClientControlCommand,d as isControlPlaneEnabled,u as isControlPlaneEnabledSync,f as shouldConnectControlPlane,y as stopControlPlaneClient};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import"./config-CrHchneq.js";import{n as e}from"./txPromise-EBECky1b.js";import{u as t}from"./toast-HAq8XWFj.js";import{Zt as n,cn as r,nn as i,yn as a}from"./orchestrator-D-xlXG92.js";import{t as o}from"./ulid-BY7rQVLN.js";const s={apng:`image/apng`,avif:`image/avif`,bmp:`image/bmp`,css:`text/css`,gif:`image/gif`,htm:`text/html`,html:`text/html`,jpeg:`image/jpeg`,jpg:`image/jpeg`,js:`text/javascript`,json:`application/json`,markdown:`text/markdown`,md:`text/markdown`,mp3:`audio/mpeg`,mp4:`video/mp4`,oga:`audio/ogg`,ogg:`audio/ogg`,ogv:`video/ogg`,pdf:`application/pdf`,png:`image/png`,svg:`image/svg+xml`,txt:`text/plain`,wav:`audio/wav`,webm:`video/webm`,webp:`image/webp`};function c(e){return e.trim().replace(/[\u0000-\u001f\u007f]+/g,``).replace(/[\\/:*?"<>|]+/g,`-`).replace(/\s+/g,` `).replace(/^\.+/,``).trim()||`attachment`}function l(e,t=``){if(t)return t;let n=e.toLowerCase().split(`.`).pop()||``;return s[n]||`application/octet-stream`}function u(e){return e.previewDisposition===`inline`||l(e.fileName,e.mimeType||``)===`image/png`}function d(e,t=``,n=Date.now()){let r=c(e),i=t.trim().replace(/[^a-zA-Z0-9._-]+/g,`-`).replace(/^-+|-+$/g,``);return`attachments/${n}-${i?`${i}-`:``}${r}`}async function f(e,t,n=[]){let i=[];for(let a of n){let n=c(a.fileName||``),o=a.path||d(n,a.id),s=a.source,u=l(n,a.mimeType||``),f=a.size;if(s){let i=await p(s);u=l(n,a.mimeType||i.type),f=typeof f==`number`?f:i.size,await r(e,t,o,i)}i.push(m({...a,fileName:n,mimeType:u,size:f,path:o,previewDisposition:a.previewDisposition||(u===`image/png`?`inline`:`file`)}))}return i}async function p(e){if(e.kind===`local-file`)return e.file;if(e.kind===`inline-text`)return new Blob([e.text],{type:e.mimeType||`text/plain`});let t=await fetch(e.url,{headers:e.headers});if(!t.ok)throw Error(`Attachment download failed: HTTP ${t.status} ${t.statusText}`);return await t.blob()}function m(e){let{source:t,...n}=e;return n}const h=new Set([`TASK_STATE_COMPLETED`,`TASK_STATE_FAILED`,`TASK_STATE_CANCELED`,`TASK_STATE_REJECTED`]),g=new Set([`TASK_STATE_INPUT_REQUIRED`,`TASK_STATE_AUTH_REQUIRED`]),_={SEND_MESSAGE:`SendMessage`,SEND_STREAMING_MESSAGE:`SendStreamingMessage`,GET_TASK:`GetTask`,CANCEL_TASK:`CancelTask`,GET_AGENT_CARD:`GetAgentCard`},v={EVENT:`agui/event`},y={STATUS_UPDATE:`tasks/statusUpdate`,ARTIFACT_UPDATE:`tasks/artifactUpdate`},b={JOIN:`room/join`,ROSTER:`room/roster`,LEAVE:`room/leave`,MESSAGE:`room/message`,INVITE:`room/invite`,RELAY:`room/relay`,A2UI:`room/a2ui`,A2UI_ACTION:`room/a2ui-action`},x={TASK_NOT_FOUND:-32001,TASK_NOT_CANCELABLE:-32002,PUSH_NOTIFICATION_NOT_SUPPORTED:-32003,UNSUPPORTED_OPERATION:-32004,CONTENT_TYPE_NOT_SUPPORTED:-32005,INVALID_AGENT_RESPONSE:-32006,PARSE_ERROR:-32700,INVALID_REQUEST:-32600,METHOD_NOT_FOUND:-32601,INVALID_PARAMS:-32602,INTERNAL_ERROR:-32603};function S(e){return typeof e==`object`&&!!e&&e.jsonrpc===`2.0`&&typeof e.id==`string`&&typeof e.method==`string`}function C(e){return typeof e==`object`&&!!e&&e.jsonrpc===`2.0`&&typeof e.id==`string`&&!(`method`in e)}function w(e){let t={url:`webrtc://${e.peerId}`,protocolBinding:`https://xt-ml.github.io/shadow-claw/bindings/webrtc-datachannel/v1`,protocolVersion:`1.0`},n={streaming:e.streaming??!0,pushNotifications:!1};return{name:e.name,description:e.description??`AI assistant agent (${e.name})`,version:e.version??`1.0.0`,supportedInterfaces:[t],capabilities:n,defaultInputModes:[`text/plain`,`application/json`],defaultOutputModes:[`text/plain`,`application/json`],skills:e.skills??[],iconUrl:e.iconUrl}}function T(){return{jsonrpc:`2.0`,id:o(),method:_.GET_AGENT_CARD}}function E(e,t){return{jsonrpc:`2.0`,id:e,result:t}}function D(e){if(e.error)return console.warn(`GetAgentCard returned error:`,e.error),null;let t=e.result;return!t||typeof t!=`object`||typeof t.name!=`string`||typeof t.version!=`string`?null:t}var O=class{_cards=new Map;clear(){this._cards.clear()}delete(e){this._cards.delete(e)}entries(){return this._cards.entries()}get(e){return this._cards.get(e)}getDisplayName(e){return this._cards.get(e)?.name??e}has(e){return this._cards.has(e)}set(e,t){this._cards.set(e,t)}supportsStreaming(e){return this._cards.get(e)?.capabilities?.streaming??!1}};const k={maxTasks:100,maxHistoryPerTask:50},A=new Map([[`TASK_STATE_SUBMITTED`,new Set([`TASK_STATE_WORKING`,`TASK_STATE_REJECTED`,`TASK_STATE_CANCELED`,`TASK_STATE_FAILED`])],[`TASK_STATE_WORKING`,new Set([`TASK_STATE_COMPLETED`,`TASK_STATE_FAILED`,`TASK_STATE_CANCELED`,`TASK_STATE_INPUT_REQUIRED`,`TASK_STATE_AUTH_REQUIRED`])],[`TASK_STATE_INPUT_REQUIRED`,new Set([`TASK_STATE_WORKING`,`TASK_STATE_CANCELED`,`TASK_STATE_FAILED`])],[`TASK_STATE_AUTH_REQUIRED`,new Set([`TASK_STATE_WORKING`,`TASK_STATE_CANCELED`,`TASK_STATE_FAILED`])]]);var j=class{_config;_contextActiveTask=new Map;_listeners=new Set;_taskOrder=[];_tasks=new Map;constructor(e){this._config={...k,...e}}addArtifact(e,t,n=!1){let r=this._tasks.get(e);if(!r)return;if(r.artifacts||=[],n){let e=r.artifacts.find(e=>e.artifactId===t.artifactId);e?e.parts.push(...t.parts):r.artifacts.push(t)}else r.artifacts.push(t);let i={taskId:r.id,contextId:r.contextId??``,artifact:t,append:n,lastChunk:!1};this._emit({type:`artifactUpdate`,taskId:r.id,contextId:r.contextId??``,payload:i})}cancelTask(e){let t=this._tasks.get(e);return!t||h.has(t.status.state)?!1:(this._transitionState(t,`TASK_STATE_CANCELED`,{messageId:o(),role:`ROLE_AGENT`,parts:[{text:`Task canceled by peer request.`}]}),!0)}clear(){this._tasks.clear(),this._taskOrder=[],this._contextActiveTask.clear()}emitRunError(e,t,n){let r=this._tasks.get(e);if(!r)return;let i={type:`RUN_ERROR`,message:t,code:n,timestamp:Date.now()};this._emitAGUI(r,i)}emitRunFinished(e){let t=this._tasks.get(e);if(!t)return;let n={type:`RUN_FINISHED`,threadId:t.contextId??t.id,runId:t.id,timestamp:Date.now()};this._emitAGUI(t,n)}emitRunStarted(e){let t=this._tasks.get(e);if(!t)return;let n={type:`RUN_STARTED`,threadId:t.contextId??t.id,runId:t.id,timestamp:Date.now()};this._emitAGUI(t,n)}emitStateSnapshot(e,t){let n=this._tasks.get(e);if(!n)return;let r={type:`STATE_SNAPSHOT`,snapshot:t,timestamp:Date.now()};this._emitAGUI(n,r)}emitTextMessageContent(e,t,n){let r=this._tasks.get(e);if(!r)return;let i={type:`TEXT_MESSAGE_CONTENT`,messageId:t,delta:n,timestamp:Date.now()};this._emitAGUI(r,i)}emitTextMessageEnd(e,t){let n=this._tasks.get(e);if(!n)return;let r={type:`TEXT_MESSAGE_END`,messageId:t,timestamp:Date.now()};this._emitAGUI(n,r)}emitTextMessageStart(e,t,n=`assistant`){let r=this._tasks.get(e);if(!r)return;let i={type:`TEXT_MESSAGE_START`,messageId:t,role:n,timestamp:Date.now()};this._emitAGUI(r,i)}emitToolCallEnd(e,t){let n=this._tasks.get(e);if(!n)return;let r={type:`TOOL_CALL_END`,toolCallId:t,timestamp:Date.now()};this._emitAGUI(n,r)}emitToolCallStart(e,t,n,r){let i=this._tasks.get(e);if(!i)return;let a={type:`TOOL_CALL_START`,toolCallId:t,toolCallName:n,parentMessageId:r,timestamp:Date.now()};this._emitAGUI(i,a)}getActiveTaskForContext(e){let t=this._contextActiveTask.get(e);if(t)return this._tasks.get(t)}getActiveTasks(){return Array.from(this._tasks.values()).filter(e=>!h.has(e.status.state))}getAllTasks(){return Array.from(this._tasks.values())}getTask(e){return this._tasks.get(e)}handleSendMessage(e){let t=e.message,n=t.contextId??o(),r=t.taskId??this._contextActiveTask.get(n);return r&&this._tasks.has(r)?this._continueTask(r,t):this._createTask(n,t)}markCompleted(e,t){let n=this._tasks.get(e);n&&this._transitionState(n,`TASK_STATE_COMPLETED`,t)}markFailed(e,t){let n=this._tasks.get(e);n&&this._transitionState(n,`TASK_STATE_FAILED`,{messageId:o(),role:`ROLE_AGENT`,parts:[{text:t}]})}markInputRequired(e,t){let n=this._tasks.get(e);n&&this._transitionState(n,`TASK_STATE_INPUT_REQUIRED`,t)}markWorking(e){let t=this._tasks.get(e);t&&this._transitionState(t,`TASK_STATE_WORKING`)}off(e){this._listeners.delete(e)}on(e){this._listeners.add(e)}_addTask(e){for(this._tasks.set(e.id,e),this._taskOrder.push(e.id);this._taskOrder.length>this._config.maxTasks;){let e=this._taskOrder.shift(),t=this._tasks.get(e);if(t&&h.has(t.status.state))this._tasks.delete(e),t.contextId&&this._contextActiveTask.delete(t.contextId);else{this._taskOrder.unshift(e);break}}}_continueTask(e,t){let n=this._tasks.get(e);return g.has(n.status.state)&&this._transitionState(n,`TASK_STATE_WORKING`),n.history||=[],n.history.push(t),n.history.length>this._config.maxHistoryPerTask&&(n.history=n.history.slice(-this._config.maxHistoryPerTask)),this._touchTask(e),{task:n}}_createTask(e,t){let n=o(),r={id:n,contextId:e,status:{state:`TASK_STATE_SUBMITTED`,timestamp:new Date().toISOString()},history:[t]};return this._addTask(r),this._contextActiveTask.set(e,n),this._emitStatusUpdate(r),{task:r}}_emit(e){for(let t of this._listeners)try{t(e)}catch(e){console.error(`PeerTaskManager: listener error`,e)}}_emitAGUI(e,t){this._emit({type:`aguiEvent`,taskId:e.id,contextId:e.contextId??``,payload:t})}_emitStatusUpdate(e){let t={taskId:e.id,contextId:e.contextId??``,status:e.status};this._emit({type:`statusUpdate`,taskId:e.id,contextId:e.contextId??``,payload:t})}_touchTask(e){let t=this._taskOrder.indexOf(e);t!==-1&&(this._taskOrder.splice(t,1),this._taskOrder.push(e))}_transitionState(e,t,n){let r=e.status.state,i=A.get(r);if(i&&!i.has(t)){console.warn(`PeerTaskManager: invalid transition ${r} → ${t} for task ${e.id}`);return}if(h.has(r)){console.warn(`PeerTaskManager: task ${e.id} is in terminal state ${r}, cannot transition`);return}e.status={state:t,message:n,timestamp:new Date().toISOString()},h.has(t)&&e.contextId&&this._contextActiveTask.get(e.contextId)===e.id&&this._contextActiveTask.delete(e.contextId),this._emitStatusUpdate(e)}};const M=new t.State(null);var N=class r{static _RECONNECT_BASE_MS=1e3;static _RECONNECT_MAX_MS=6e4;connectedPeersSignal=new t.State([]);connections=new Map;messageCallback=null;myPeerId=``;peerCards=new O;running=!1;serverConfig={};transferProgressSignal=M;trustedPeerIds=new Set;type=`peerjs`;typingCallback=null;_inboundRemap=new Map;_localCard=null;_onTaskCompleteCallback=null;peer=null;_pendingInboundFile=null;_pendingRequests=new Map;_reconnectAttempts=0;_reconnectTimer=null;_roomNotificationHandler=null;_taskManagers=new Map;constructor(){typeof globalThis.addEventListener==`function`&&globalThis.addEventListener(`peerjs-dc-handle-chunk`,e=>{if(e?.detail?.chunkInfo){let{count:t,total:n}=e.detail.chunkInfo,r=t+1;M.set({count:r,total:n,direction:`receive`}),r>=n&&setTimeout(()=>M.set(null),1500)}})}completeActiveTask(e){let t=e.replace(/^peer:/,``),n=this._taskManagers.get(t);if(!n)return!1;let r=n.getActiveTasks();if(r.length===0)return!1;let i=r[r.length-1];return n.markWorking(i.id),n.markCompleted(i.id),!0}configure(e,t,n={}){this.myPeerId=e.trim(),this.trustedPeerIds=new Set(t.map(e=>e.trim()).filter(Boolean)),this.serverConfig=n}connectPeer(e){this._getOrOpenConnection(e)}getTaskManager(e){let t=this._taskManagers.get(e);return t||(t=new j,this._taskManagers.set(e,t),t.on(t=>{this._forwardTaskEvent(e,t)})),t}isConfigured(){return this.myPeerId.length>0}isPeerConnected(e){let t=this.connections.get(e);return!!t&&!!t.open}onMessage(e){this.messageCallback=e}onTaskComplete(e){this._onTaskCompleteCallback=e}onTyping(e){this.typingCallback=e}sendRoomNotification(e,t){let n=this._getOrOpenConnection(e);if(!n)return!1;if(n.open)try{return n.send(t),!0}catch(t){return console.error(`PeerJsChannel: failed to send room notification to ${e}:`,t),!1}return this._waitForOpen(n).then(()=>{try{n.send(t)}catch(t){console.error(`PeerJsChannel: failed to flush room notification to ${e}:`,t)}}).catch(()=>{}),!0}setRoomNotificationHandler(e){this._roomNotificationHandler=e}setTyping(e,t){let n=e.replace(/^peer:/,``),r=this.connections.get(n);if(r)try{r.send({type:`typing`,typing:t})}catch{}}start(){!this.isConfigured()||this.running||(this.running=!0,this._localCard=w({peerId:this.myPeerId,name:this.myPeerId,description:`ShadowClaw AI assistant`,streaming:!0}),this._initPeer())}stop(){if(this.running=!1,this._reconnectTimer!==null&&(clearTimeout(this._reconnectTimer),this._reconnectTimer=null),this._reconnectAttempts=0,this.connections.forEach(e=>{try{e.close()}catch{}}),this.connections.clear(),this.peerCards.clear(),this._taskManagers.clear(),this._pendingRequests.forEach(({timer:e})=>clearTimeout(e)),this._pendingRequests.clear(),this._updateConnectedPeersSignal(),this.peer){try{this.peer.destroy()}catch{}this.peer=null}}async send(t,n,r){let i=t.replace(/^peer:/,``),s=this._getOrOpenConnection(i);if(!s){console.warn(`PeerJsChannel: no connection available for ${i}`);return}try{await this._waitForOpen(s);let{attachments:i}=P(n),c=[...(r||[]).filter(e=>!!e.path),...i.map(e=>({path:e.path,mimeType:`application/octet-stream`}))],l=new Map,u=[];try{let n=await e();for(let e of c)if(e.path)try{let r=await a(n,t,e.path),i=e.path;l.has(e.path)||l.set(e.path,i);let o=e.mimeType||`application/octet-stream`;s.send({type:`__file_header`,name:i,mimeType:o,size:r.length});let c=this._trackSendProgress(s,r.length);s.send(r.buffer),await c,u.push({kind:`file`,name:i,mimeType:o,size:r.length})}catch(t){console.warn(`PeerJsChannel: failed to process file ${e.path}:`,t)}}catch(e){console.error(`PeerJsChannel: failed to access DB`,e)}let d=n;for(let[e,t]of l){let n=e.replace(/[.*+?^${}()|[\]\\]/g,`\\$&`);d=d.replace(RegExp(`(!?\\[.*?\\])\\(${n}\\)`,`g`),`$1(${t})`)}let f=[...u,{kind:`text`,text:d}],p=o(),m={jsonrpc:`2.0`,id:p,method:_.SEND_MESSAGE,params:{message:{messageId:o(),role:`ROLE_AGENT`,parts:f}}};s.send(m),this._registerPendingRequest(p,e=>{})}catch(e){console.error(`PeerJsChannel: send failed for ${i}:`,e),window.dispatchEvent(new CustomEvent(`shadow-claw-peer-error`,{detail:{remotePeerId:i,error:e instanceof Error?e.message:String(e)}}))}}async sendA2UI(e,t){let n=e.replace(/^peer:/,``),r=this._getOrOpenConnection(n);if(!r){console.warn(`PeerJsChannel.sendA2UI: no connection available for ${n}`);return}try{await this._waitForOpen(r);let e={jsonrpc:`2.0`,method:`message/send`,id:o(),params:{message:{role:`agent`,parts:[{kind:`a2ui`,envelope:t}]}}};r.send(e)}catch(e){console.error(`PeerJsChannel.sendA2UI: failed for ${n}:`,e)}}async sendA2UIAction(e,t){let n=e.replace(/^peer:/,``),r=this._getOrOpenConnection(n);if(!r){console.warn(`PeerJsChannel.sendA2UIAction: no connection available for ${n}`);return}try{await this._waitForOpen(r);let e={jsonrpc:`2.0`,method:`message/send`,id:o(),params:{message:{role:`user`,parts:[{kind:`a2ui-action`,action:t}]}}};r.send(e)}catch(e){console.error(`PeerJsChannel.sendA2UIAction: failed for ${n}:`,e)}}_exchangeAgentCards(e,t){if(!this._localCard)return;let n=T();t.send(n),this._registerPendingRequest(n.id,t=>{let n=D(t);n&&(this.peerCards.set(e,n),console.log(`PeerJsChannel: received AgentCard from ${e}: "${n.name}"`))})}_forwardTaskEvent(e,t){let n=this.connections.get(e);if(!n)return;let r;switch(t.type){case`statusUpdate`:r=y.STATUS_UPDATE;break;case`artifactUpdate`:r=y.ARTIFACT_UPDATE;break;case`aguiEvent`:r=v.EVENT;break;default:return}let i={jsonrpc:`2.0`,method:r,params:t.payload};try{n.send(i)}catch(n){console.error(`PeerJsChannel: failed to forward ${t.type} to ${e}:`,n)}}_getOrOpenConnection(e){let t=this.connections.get(e);if(t)return t;if(!this.peer)return null;try{let t=this.peer.connect(e,{reliable:!0,serialization:`binary`});return t?(this._handleIncomingConnection(t),t):null}catch(t){return console.error(`PeerJsChannel: failed to connect to ${e}:`,t),null}}_handleA2ACancelTask(e,t){let n=t.params;if(!n?.taskId){this._sendJsonRpcError(e,t.id,{code:x.INVALID_PARAMS,message:`Missing taskId in CancelTask params`});return}let r=this._taskManagers.get(e);if(!r){this._sendJsonRpcError(e,t.id,{code:x.TASK_NOT_FOUND,message:`Task not found: ${n.taskId}`});return}if(!r.cancelTask(n.taskId)){this._sendJsonRpcError(e,t.id,{code:x.TASK_NOT_CANCELABLE,message:`Task not cancelable: ${n.taskId}`});return}let i=this.connections.get(e);if(i){let e=r.getTask(n.taskId),a={jsonrpc:`2.0`,id:t.id,result:{task:e}};i.send(a)}}_handleA2AGetTask(e,t){let n=t.params;if(!n?.taskId){this._sendJsonRpcError(e,t.id,{code:x.INVALID_PARAMS,message:`Missing taskId in GetTask params`});return}let r=this._taskManagers.get(e)?.getTask(n.taskId);if(!r){this._sendJsonRpcError(e,t.id,{code:x.TASK_NOT_FOUND,message:`Task not found: ${n.taskId}`});return}let i=this.connections.get(e);if(i){let e={jsonrpc:`2.0`,id:t.id,result:{task:r}};i.send(e)}}_handleA2AJsonRpc(e,t){if(C(t)){let e=this._pendingRequests.get(t.id);e&&(clearTimeout(e.timer),this._pendingRequests.delete(t.id),e.resolve(t));return}let n=t.method;if(n){if(n.startsWith(`room/`)){this._roomNotificationHandler?.(e,n,t.params);return}if(S(t)){switch(n){case _.GET_AGENT_CARD:this._handleGetAgentCard(e,t);break;case _.SEND_MESSAGE:this._handleA2ASendMessage(e,t);break;case _.CANCEL_TASK:this._handleA2ACancelTask(e,t);break;case _.GET_TASK:this._handleA2AGetTask(e,t);break;default:if(n===`message/send`){let n=t.params;n?.message?.parts&&Array.isArray(n.message.parts)&&this._processInboundA2AEnvelope(e,n.message.parts).catch(e=>console.error(`PeerJsChannel: failed to process inbound A2A envelope`,e))}else this._sendJsonRpcError(e,t.id,{code:x.METHOD_NOT_FOUND,message:`Method not found: ${n}`})}return}switch(n){case v.EVENT:this._handleAGUIEventNotification(e,t.params);break;case y.STATUS_UPDATE:this._handleTaskStatusNotification(e,t.params);break;case y.ARTIFACT_UPDATE:break;case`message/send`:{let n=t.params;n?.message?.parts&&Array.isArray(n.message.parts)&&this._processInboundA2AEnvelope(e,n.message.parts).catch(e=>console.error(`PeerJsChannel: failed to process inbound A2A envelope`,e))}break}}}_handleA2ASendMessage(e,t){let n=t.params;if(!n?.message){this._sendJsonRpcError(e,t.id,{code:x.INVALID_PARAMS,message:`Missing message in SendMessage params`});return}let r=this._taskManagers.get(e);r||(r=new j,this._taskManagers.set(e,r),r.on(t=>{this._forwardTaskEvent(e,t)}));let i=r.handleSendMessage(n),a=this.connections.get(e);if(a){let e={jsonrpc:`2.0`,id:t.id,result:i};a.send(e)}n.message.parts&&Array.isArray(n.message.parts)&&this._processInboundA2AEnvelope(e,n.message.parts,i.task?.id,i.task?.contextId).catch(e=>console.error(`PeerJsChannel: failed to process A2A SendMessage`,e))}_handleAGUIEventNotification(e,t){if(!t||typeof t!=`object`)return;let n=t;window.dispatchEvent(new CustomEvent(`shadow-claw-agui-event`,{detail:{remotePeerId:e,event:n}}))}_handleGetAgentCard(e,t){if(!this._localCard){this._sendJsonRpcError(e,t.id,{code:x.INTERNAL_ERROR,message:`Agent card not available`});return}let n=E(t.id,this._localCard),r=this.connections.get(e);r&&r.send(n)}_handleInboundData(t,r){if(r instanceof ArrayBuffer||r instanceof Uint8Array){if(this._pendingInboundFile){let a=this._pendingInboundFile.name,o=`peer:${t}`,s=new Uint8Array(r);e().then(async e=>{let t=a,r=1;for(;await i(e,o,t);){let e=a.lastIndexOf(`.`);if(e>0&&e<a.length-1){let n=a.substring(0,e),i=a.substring(e);t=`${n} (${r})${i}`}else t=`${a} (${r})`;r++}t!==a&&this._inboundRemap.set(a,t),n(e,o,t,s).catch(e=>{console.error(`PeerJsChannel: failed to write inbound file bytes`,e)})}),this._pendingInboundFile=null}return}if(!r||typeof r!=`object`)return;let a=r;if(a.type===`__file_header`){this._pendingInboundFile={name:a.name,mimeType:a.mimeType,size:a.size};return}if(a.type===`typing`){this.typingCallback?.(`peer:${t}`,!!a.typing);return}if(a.type===`chat`){let e=typeof a.text==`string`?a.text.trim():``;e&&this.messageCallback?.({id:o(),groupId:`peer:${t}`,sender:t,content:e,timestamp:Date.now(),channel:`peerjs`});return}if(a.jsonrpc===`2.0`){this._handleA2AJsonRpc(t,a);return}if(a.type===`command:execute`){let e=a.payload||{},n=e.action||``,r=e.args||{},i=e.commandId||``;import(`./initControlPlane-CcGXax0A.js`).then(({executeClientControlCommand:e})=>e(n,r)).then(e=>{let r=this.connections.get(t);if(r){let t=!!e?.error;r.send({id:o(),type:`command:result`,payload:{commandId:i,action:n,success:!t,data:e,...t?{error:e.error}:{}}})}}).catch(e=>{let r=this.connections.get(t);r&&r.send({id:o(),type:`command:result`,payload:{commandId:i,action:n,success:!1,error:e?.message||String(e)}})});return}}_isTrustedPeer(e){if(this.trustedPeerIds.size===0||this.trustedPeerIds.has(e))return!0;for(let t of this.trustedPeerIds){let n=t.trim();if(n.endsWith(`*`)&&e.startsWith(n.slice(0,-1))||n===`cli`&&e.startsWith(`cli-`))return!0}return!1}_handleIncomingConnection(e){let t=e.peer;if(!this._isTrustedPeer(t)){console.warn(`PeerJsChannel: rejecting connection from untrusted peer: ${t}`);try{e.close()}catch{}return}this.connections.set(t,e),this._updateConnectedPeersSignal(),e.on(`open`,()=>{console.log(`PeerJsChannel: connection opened with ${t}`),this._exchangeAgentCards(t,e)}),e.on(`data`,e=>{this._handleInboundData(t,e)}),e.on(`close`,()=>{console.log(`PeerJsChannel: connection closed with ${t}`),this.connections.delete(t),this.peerCards.delete(t),this._taskManagers.delete(t),this._updateConnectedPeersSignal()}),e.on(`error`,e=>{console.error(`PeerJsChannel: connection error with ${t}:`,e),this.connections.delete(t),this._updateConnectedPeersSignal(),window.dispatchEvent(new CustomEvent(`shadow-claw-peer-error`,{detail:{remotePeerId:t,error:e.message}}))}),e.on(`iceStateChanged`,e=>{(e===`failed`||e===`disconnected`||e===`closed`)&&(console.warn(`PeerJsChannel: ICE state changed to ${e} for ${t}`),this.connections.delete(t),this._updateConnectedPeersSignal())})}_handleTaskStatusNotification(e,t){if(!t||typeof t!=`object`)return;let n=t;if(n.status?.state&&h.has(n.status.state)){let t=`peer:${e}`;this._onTaskCompleteCallback?.(t)}window.dispatchEvent(new CustomEvent(`shadow-claw-task-status`,{detail:{remotePeerId:e,...n}}))}async _initPeer(){let{Peer:e}=await import(`./bundler-Ca-Xwln8.js`),t={},n=this.serverConfig.host??`0.peerjs.com`,r=this.serverConfig.port??443,i=this.serverConfig.path??`/`,a=this.serverConfig.secure??!0;t.host=n,t.port=r,t.path=i,t.secure=a,t.debug=3,t.config={iceServers:this.serverConfig.iceServers??[{urls:`stun:stun.l.google.com:19302`},{urls:`stun:stun1.l.google.com:19302`}]},this.peer=new e(this.myPeerId,t),this.peer.on(`open`,e=>{console.log(`PeerJsChannel: connected to signaling server, peer ID: ${e}`),this._reconnectAttempts=0}),this.peer.on(`connection`,e=>{this._handleIncomingConnection(e)}),this.peer.on(`error`,e=>{console.error(`PeerJsChannel: peer error [${e.type}]:`,e.message),(e.type===`peer-unavailable`||e.type===`unavailable-id`)&&window.dispatchEvent(new CustomEvent(`shadow-claw-peer-error`,{detail:{error:e.message}})),!(e.type===`peer-unavailable`||e.type===`network`||e.type===`disconnected`)&&e.type===`unavailable-id`&&console.warn(`PeerJsChannel: peer ID is already in use. Stop the channel and reconfigure.`)}),this.peer.on(`disconnected`,()=>{this.running&&this._scheduleReconnect()}),this.peer.on(`close`,()=>{console.log(`PeerJsChannel: peer closed`)})}_registerPendingRequest(e,t){let n=setTimeout(()=>{this._pendingRequests.delete(e),console.warn(`PeerJsChannel: JSON-RPC request ${e} timed out (10s)`)},1e4);this._pendingRequests.set(e,{resolve:t,timer:n})}_scheduleReconnect(){if(this._reconnectTimer!==null)return;let e=Math.min(r._RECONNECT_BASE_MS*2**this._reconnectAttempts,r._RECONNECT_MAX_MS);this._reconnectAttempts++,console.log(`PeerJsChannel: disconnected from signaling server, reconnecting in ${(e/1e3).toFixed(1)}s (attempt ${this._reconnectAttempts})`),this._reconnectTimer=setTimeout(()=>{if(this._reconnectTimer=null,this.running)try{this.peer?.reconnect?.()}catch{this._scheduleReconnect()}},e)}_sendJsonRpcError(e,t,n){let r=this.connections.get(e);if(!r)return;let i={jsonrpc:`2.0`,id:t,error:n};try{r.send(i)}catch{}}_trackSendProgress(e,t){return new Promise(n=>{let r=e._dc;if(!r||t===0){this.transferProgressSignal.set(null),n();return}this.transferProgressSignal.set({count:0,total:t,direction:`send`});let i=setInterval(()=>{let e=r.bufferedAmount,a=Math.max(0,t-e);this.transferProgressSignal.set({count:a,total:t,direction:`send`}),e===0&&(clearInterval(i),this.transferProgressSignal.set({count:t,total:t,direction:`send`}),setTimeout(()=>this.transferProgressSignal.set(null),1500),n())},80)})}_updateConnectedPeersSignal(){this.connectedPeersSignal.set(Array.from(this.connections.keys()))}_waitForOpen(e){return e.open?Promise.resolve():new Promise((t,n)=>{let r=setTimeout(()=>{n(Error(`Connection open timeout (5s)`))},5e3);e.on(`open`,()=>{clearTimeout(r),t()}),e.on(`error`,e=>{clearTimeout(r),n(e)})})}async _processInboundA2AEnvelope(e,t,n,r){let i=`peer:${e}`,a=``,s=[],c=[],l;for(let e of t)if(e.kind===`text`&&typeof e.text==`string`)a+=e.text;else if(e.kind===`file`){let t=e.name||`attachment`;if(this._inboundRemap.has(t)){let e=this._inboundRemap.get(t),n=t.replace(/[.*+?^${}()|[\]\\]/g,`\\$&`);a=a.replace(RegExp(`(!?\\[.*?\\])\\(${n}\\)`,`g`),`$1(${e})`),this._inboundRemap.delete(t),t=e}let n=t.split(`/`).pop()||`attachment`;s.push({fileName:n,mimeType:e.mimeType,path:t,size:e.size||0})}else e.kind===`a2ui`&&e.envelope?c.push(e.envelope):e.kind===`a2ui-action`&&e.action&&(l=e.action);a=a.trim(),!(!a&&s.length===0&&c.length===0&&!l)&&this.messageCallback?.({id:o(),groupId:i,sender:e,content:a,timestamp:Date.now(),channel:`peerjs`,attachments:s.length>0?s:void 0,a2uiEnvelopes:c.length>0?c:void 0,a2uiAction:l,taskId:n,contextId:r})}};function P(e){let t=[],n=/!?\[([^\]]*)\]\(([^)]+)\)/g,r,i=e;for(;(r=n.exec(e))!==null;){let e=r[1],n=F((r[2]||``).trim());n&&t.push({alt:e,path:n})}return{remainingText:i,attachments:t}}function F(e){if(!e)return null;let t=e.trim();if(/^[a-zA-Z][a-zA-Z\d+.-]*:/.test(t)||t.startsWith(`//`))return null;let n=t.replace(/\\/g,`/`).replace(/^\/+/,``).replace(/^\.\//,``);if(!n)return null;let r=n.split(`/`).filter(Boolean);return r.some(e=>e===`..`)?null:r.join(`/`)}export{f as a,l as i,M as n,u as o,b as r,N as t};
|