shadow-claw 1.32.0 → 1.33.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.well-known/mcp/server-card.json +1 -1
- package/.well-known/mcp.json +1 -1
- package/dist/electron/main.cjs +1 -1
- package/dist/lib/components/index.js +26 -26
- 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-notifications.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-notifications.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/{config-DjZ9QWc4.js → config-BcFbkaQv.js} +21 -4
- package/dist/lib/config-BcFbkaQv.js.map +1 -0
- package/dist/lib/{configurePeerJs-DD3G3Pms.js → configurePeerJs-CBMPHbwa.js} +3 -3
- package/dist/lib/{configurePeerJs-DD3G3Pms.js.map → configurePeerJs-CBMPHbwa.js.map} +1 -1
- package/dist/lib/{connections-BURqMIUv.js → connections-PZrUDf49.js} +2 -2
- package/dist/lib/{connections-BURqMIUv.js.map → connections-PZrUDf49.js.map} +1 -1
- package/dist/lib/{downloadGroupFile-B8J4up2a.js → downloadGroupFile-DSRUa9Au.js} +2 -2
- package/dist/lib/{downloadGroupFile-B8J4up2a.js.map → downloadGroupFile-DSRUa9Au.js.map} +1 -1
- package/dist/lib/{file-viewer-DoHM75Jz.js → file-viewer-11VVOpJv.js} +5 -5
- package/dist/lib/{file-viewer-DoHM75Jz.js.map → file-viewer-11VVOpJv.js.map} +1 -1
- package/dist/lib/{getGroupDir-QrN2aTo8.js → getGroupDir-BxKMYPPm.js} +3 -3
- package/dist/lib/{getGroupDir-QrN2aTo8.js.map → getGroupDir-BxKMYPPm.js.map} +1 -1
- package/dist/lib/{git-Brr7JIbs.js → git-BppibnJW.js} +3 -3
- package/dist/lib/{git-Brr7JIbs.js.map → git-BppibnJW.js.map} +1 -1
- package/dist/lib/{iframe-sanitizer-Bujgq14T.js → iframe-sanitizer-Dp8EYffI.js} +2 -2
- package/dist/lib/{iframe-sanitizer-Bujgq14T.js.map → iframe-sanitizer-Dp8EYffI.js.map} +1 -1
- package/dist/lib/index.js +27 -27
- package/dist/lib/{initChatSplitResize-BjiWoqC_.js → initChatSplitResize-CE_kWaLf.js} +2 -2
- package/dist/lib/{initChatSplitResize-BjiWoqC_.js.map → initChatSplitResize-CE_kWaLf.js.map} +1 -1
- package/dist/lib/{initControlPlane-3TUdhRBM.js → initControlPlane-BRIIOzoH.js} +18 -17
- package/dist/lib/{initControlPlane-3TUdhRBM.js.map → initControlPlane-BRIIOzoH.js.map} +1 -1
- package/dist/lib/{markdown-BFUTPQoO.js → markdown-Cq4sVwUT.js} +4 -4
- package/dist/lib/{markdown-BFUTPQoO.js.map → markdown-Cq4sVwUT.js.map} +1 -1
- package/dist/lib/{mcp-reconnect-BxJ77WSb.js → mcp-reconnect-CoHDMjmY.js} +2 -2
- package/dist/lib/{mcp-reconnect-BxJ77WSb.js.map → mcp-reconnect-CoHDMjmY.js.map} +1 -1
- package/dist/lib/{memoryStorage-D3FBwO9T.js → memoryStorage-DcFWrn_y.js} +2 -2
- package/dist/lib/{memoryStorage-D3FBwO9T.js.map → memoryStorage-DcFWrn_y.js.map} +1 -1
- package/dist/lib/{orchestrator-DW5l2bbW.js → orchestrator-C3TgDZvq.js} +81 -18
- package/dist/lib/{orchestrator-DW5l2bbW.js.map → orchestrator-C3TgDZvq.js.map} +1 -1
- package/dist/lib/{orchestrator-DLnCmeTZ.js → orchestrator-Ce9_lmL2.js} +12 -12
- package/dist/lib/{orchestrator-DLnCmeTZ.js.map → orchestrator-Ce9_lmL2.js.map} +1 -1
- package/dist/lib/{peerjs-BXlMuIQn.js → peerjs-PTYQ7yEG.js} +6 -6
- package/dist/lib/{peerjs-BXlMuIQn.js.map → peerjs-PTYQ7yEG.js.map} +1 -1
- package/dist/lib/{push-client-B419nn-i.js → push-client-DDV5Rcg6.js} +3 -3
- package/dist/lib/{push-client-B419nn-i.js.map → push-client-DDV5Rcg6.js.map} +1 -1
- package/dist/lib/{readGroupFileBytes-CSA7u-nJ.js → readGroupFileBytes-7C8G-yps.js} +2 -2
- package/dist/lib/{readGroupFileBytes-CSA7u-nJ.js.map → readGroupFileBytes-7C8G-yps.js.map} +1 -1
- package/dist/lib/{shadow-claw-DmMO4vVG.js → shadow-claw-WrWoPqFx.js} +10 -10
- package/dist/lib/{shadow-claw-DmMO4vVG.js.map → shadow-claw-WrWoPqFx.js.map} +1 -1
- package/dist/lib/{shadow-claw-a2ui-2I5nffIn.js → shadow-claw-a2ui-CcmJNXQP.js} +2 -2
- package/dist/lib/{shadow-claw-a2ui-2I5nffIn.js.map → shadow-claw-a2ui-CcmJNXQP.js.map} +1 -1
- package/dist/lib/{shadow-claw-accounts-DMb0y4ca.js → shadow-claw-accounts-CcB2429E.js} +3 -3
- package/dist/lib/{shadow-claw-accounts-DMb0y4ca.js.map → shadow-claw-accounts-CcB2429E.js.map} +1 -1
- package/dist/lib/{shadow-claw-channel-config-BhxHf6wZ.js → shadow-claw-channel-config-C4v0h8oa.js} +3 -3
- package/dist/lib/{shadow-claw-channel-config-BhxHf6wZ.js.map → shadow-claw-channel-config-C4v0h8oa.js.map} +1 -1
- package/dist/lib/{shadow-claw-channels-B5vzE9Z2.js → shadow-claw-channels-CyV88k9T.js} +3 -3
- package/dist/lib/{shadow-claw-channels-B5vzE9Z2.js.map → shadow-claw-channels-CyV88k9T.js.map} +1 -1
- package/dist/lib/{shadow-claw-chat-BsYnJ4-G.js → shadow-claw-chat-DSYtuZod.js} +11 -11
- package/dist/lib/{shadow-claw-chat-BsYnJ4-G.js.map → shadow-claw-chat-DSYtuZod.js.map} +1 -1
- package/dist/lib/{shadow-claw-control-plane-DqcgQsun.js → shadow-claw-control-plane-DBSGuDT1.js} +7 -7
- package/dist/lib/{shadow-claw-control-plane-DqcgQsun.js.map → shadow-claw-control-plane-DBSGuDT1.js.map} +1 -1
- package/dist/lib/{shadow-claw-conversations-B9Pn58g3.js → shadow-claw-conversations-Cp8pK4PM.js} +5 -5
- package/dist/lib/{shadow-claw-conversations-B9Pn58g3.js.map → shadow-claw-conversations-Cp8pK4PM.js.map} +1 -1
- package/dist/lib/{shadow-claw-file-viewer-DL6c4oPK.js → shadow-claw-file-viewer-B8G8yo48.js} +8 -8
- package/dist/lib/{shadow-claw-file-viewer-DL6c4oPK.js.map → shadow-claw-file-viewer-B8G8yo48.js.map} +1 -1
- package/dist/lib/{shadow-claw-files-C_ksPb8W.js → shadow-claw-files-D1COKzuC.js} +9 -9
- package/dist/lib/{shadow-claw-files-C_ksPb8W.js.map → shadow-claw-files-D1COKzuC.js.map} +1 -1
- package/dist/lib/{shadow-claw-git-jwsY7L1N.js → shadow-claw-git-60tWU4Ee.js} +6 -6
- package/dist/lib/{shadow-claw-git-jwsY7L1N.js.map → shadow-claw-git-60tWU4Ee.js.map} +1 -1
- package/dist/lib/{shadow-claw-integrations-yT7j07TM.js → shadow-claw-integrations-Bw1cG1ze.js} +4 -4
- package/dist/lib/{shadow-claw-integrations-yT7j07TM.js.map → shadow-claw-integrations-Bw1cG1ze.js.map} +1 -1
- package/dist/lib/{shadow-claw-llm-CEPJh1Jh.js → shadow-claw-llm-By5CvsFJ.js} +6 -6
- package/dist/lib/{shadow-claw-llm-CEPJh1Jh.js.map → shadow-claw-llm-By5CvsFJ.js.map} +1 -1
- package/dist/lib/{shadow-claw-mcp-remote-DGDWjByQ.js → shadow-claw-mcp-remote-BaNODd1v.js} +4 -4
- package/dist/lib/{shadow-claw-mcp-remote-DGDWjByQ.js.map → shadow-claw-mcp-remote-BaNODd1v.js.map} +1 -1
- package/dist/lib/{shadow-claw-networking-Bi4yvc73.js → shadow-claw-networking-DtZ5bsTz.js} +2 -2
- package/dist/lib/{shadow-claw-networking-Bi4yvc73.js.map → shadow-claw-networking-DtZ5bsTz.js.map} +1 -1
- package/dist/lib/{shadow-claw-notifications-C-JgGqQx.js → shadow-claw-notifications-C3VEba_A.js} +3 -3
- package/dist/lib/{shadow-claw-notifications-C-JgGqQx.js.map → shadow-claw-notifications-C3VEba_A.js.map} +1 -1
- package/dist/lib/{shadow-claw-page-header-DrAcWCZ9.js → shadow-claw-page-header-BLowJopA.js} +2 -2
- package/dist/lib/{shadow-claw-page-header-DrAcWCZ9.js.map → shadow-claw-page-header-BLowJopA.js.map} +1 -1
- package/dist/lib/{shadow-claw-pages-OEOClgA8.js → shadow-claw-pages-CpeUV-hw.js} +9 -9
- package/dist/lib/{shadow-claw-pages-OEOClgA8.js.map → shadow-claw-pages-CpeUV-hw.js.map} +1 -1
- package/dist/lib/{shadow-claw-peerjs-DmC2CV-9.js → shadow-claw-peerjs-DYAzJbTy.js} +3 -3
- package/dist/lib/{shadow-claw-peerjs-DmC2CV-9.js.map → shadow-claw-peerjs-DYAzJbTy.js.map} +1 -1
- package/dist/lib/{shadow-claw-settings-xAtFog0T.js → shadow-claw-settings-ByxwW3WK.js} +9 -9
- package/dist/lib/{shadow-claw-settings-xAtFog0T.js.map → shadow-claw-settings-ByxwW3WK.js.map} +1 -1
- package/dist/lib/{shadow-claw-storage-B4UHl-po.js → shadow-claw-storage-CsSPYVDJ.js} +5 -5
- package/dist/lib/{shadow-claw-storage-B4UHl-po.js.map → shadow-claw-storage-CsSPYVDJ.js.map} +1 -1
- package/dist/lib/{shadow-claw-task-server-B0eWzg57.js → shadow-claw-task-server-De2WCEw4.js} +2 -2
- package/dist/lib/{shadow-claw-task-server-B0eWzg57.js.map → shadow-claw-task-server-De2WCEw4.js.map} +1 -1
- package/dist/lib/{shadow-claw-tasks-HHU_8Gyg.js → shadow-claw-tasks-zHWT4GaE.js} +7 -7
- package/dist/lib/{shadow-claw-tasks-HHU_8Gyg.js.map → shadow-claw-tasks-zHWT4GaE.js.map} +1 -1
- package/dist/lib/{shadow-claw-terminal-CdC2G6Zz.js → shadow-claw-terminal-Bpawfv4N.js} +2 -2
- package/dist/lib/{shadow-claw-terminal-CdC2G6Zz.js.map → shadow-claw-terminal-Bpawfv4N.js.map} +1 -1
- package/dist/lib/{shadow-claw-tools-2AICxVXA.js → shadow-claw-tools-BbKdWcps.js} +7 -7
- package/dist/lib/{shadow-claw-tools-2AICxVXA.js.map → shadow-claw-tools-BbKdWcps.js.map} +1 -1
- package/dist/lib/{shadow-claw-webvm-Cy-Ia2vs.js → shadow-claw-webvm-DLqK0AxW.js} +3 -3
- package/dist/lib/{shadow-claw-webvm-Cy-Ia2vs.js.map → shadow-claw-webvm-DLqK0AxW.js.map} +1 -1
- package/dist/lib/subsystems/mcp/webmcp.d.ts +37 -0
- package/dist/lib/subsystems/providers/model-registry.d.ts +4 -1
- package/dist/lib/subsystems/providers/providers.d.ts +10 -0
- package/dist/lib/{syncWebMcpRegistration-CaAPPg2V.js → syncWebMcpRegistration-mlbbvcdm.js} +5 -5
- package/dist/lib/{syncWebMcpRegistration-CaAPPg2V.js.map → syncWebMcpRegistration-mlbbvcdm.js.map} +1 -1
- package/dist/lib/{tools-f1WPNDSS.js → tools-Bb2ujM2E.js} +4 -4
- package/dist/lib/{tools-f1WPNDSS.js.map → tools-Bb2ujM2E.js.map} +1 -1
- package/dist/lib/utils/index.js +1 -1
- package/dist/lib/utils/utils.js +1 -1
- package/dist/lib/{utils-B99XP70b.js → utils-mpsYPfS7.js} +3 -3
- package/dist/lib/{utils-B99XP70b.js.map → utils-mpsYPfS7.js.map} +1 -1
- package/dist/lib/webmcp-BVR2lBVo.js +1544 -0
- package/dist/lib/webmcp-BVR2lBVo.js.map +1 -0
- package/dist/public/.well-known/mcp/server-card.json +1 -1
- package/dist/public/.well-known/mcp.json +1 -1
- package/dist/public/agent.worker.js +44 -44
- package/dist/public/config-BqecTktB.js +1 -0
- package/dist/public/{configurePeerJs--JGpJVti.js → configurePeerJs-BPKfWuEt.js} +1 -1
- package/dist/public/{connections-6575KDGE.js → connections-C_3tYsmX.js} +1 -1
- package/dist/public/{custom-element-security-Da_6HQ6X.js → custom-element-security-DXwU3Lae.js} +1 -1
- package/dist/public/docs/example/article/index.html +2 -2
- package/dist/public/docs/publishing/index.html +2 -2
- package/dist/public/docs/skill-creator/index.html +2 -2
- package/dist/public/docs/subsystems/tools.md +4 -3
- package/dist/public/docs/subsystems/webmcp.md +58 -13
- package/dist/public/{downloadGroupFile-Dj-AMNsd.js → downloadGroupFile-DTyf5DIC.js} +1 -1
- package/dist/public/{e2e-bridge-CbYqdMp-.js → e2e-bridge-DXwWCQKw.js} +1 -1
- package/dist/public/{file-viewer-vHJ5Zsgk.js → file-viewer-ConEyDDG.js} +1 -1
- package/dist/public/{getGroupDir-BwprrdrQ.js → getGroupDir-ZfZsiq6d.js} +1 -1
- package/dist/public/{git-8F7wvoUB.js → git-BtBaLC1-.js} +2 -2
- package/dist/public/{iframe-sanitizer-viROQkRn.js → iframe-sanitizer-Corkvo_d.js} +1 -1
- package/dist/public/index.html +2 -2
- package/dist/public/index.js +1 -1
- package/dist/public/{initChatSplitResize-BA18wLQQ.js → initChatSplitResize-CUc-TEmT.js} +1 -1
- package/dist/public/{initControlPlane-C5v0FtJE.js → initControlPlane-B_uYS8a4.js} +1 -1
- package/dist/public/main/index.html +2 -2
- package/dist/public/main/memory/index.html +2 -2
- package/dist/public/{markdown-eFKxxpVP.js → markdown-Cfa6GuJs.js} +1 -1
- package/dist/public/{mcp-reconnect-CBHuaYdF.js → mcp-reconnect-CUOkdPEz.js} +1 -1
- package/dist/public/{memoryStorage-C1llaYus.js → memoryStorage-Bh8fjmip.js} +1 -1
- package/dist/public/{orchestrator-DNr2HDI2.js → orchestrator-BcSzrg6E.js} +2 -2
- package/dist/public/{orchestrator-BeJfwtvz.js → orchestrator-Bi5OdVZD.js} +11 -11
- package/dist/public/{peerjs-mG30TAJ_.js → peerjs-CzCXG-NW.js} +1 -1
- package/dist/public/{push-client-C2zMT3Sf.js → push-client-Cr3Ruahp.js} +1 -1
- package/dist/public/service-worker.js +1 -1
- package/dist/public/{shadow-claw-Ble6l0Iw.js → shadow-claw-CzUYuuOa.js} +2 -2
- package/dist/public/{shadow-claw-accounts-D1y-zbMs.js → shadow-claw-accounts-BgIHB_aP.js} +1 -1
- package/dist/public/{shadow-claw-channels-D_xfBoWp.js → shadow-claw-channels-Ce_trJ5D.js} +1 -1
- package/dist/public/{shadow-claw-chat-D_Lbi5oH.js → shadow-claw-chat-CdECLLwL.js} +1 -1
- package/dist/public/{shadow-claw-control-plane-CrnA5lM0.js → shadow-claw-control-plane-DM62UmOz.js} +2 -2
- package/dist/public/{shadow-claw-conversations-BN-hFmN1.js → shadow-claw-conversations-AM5g3C00.js} +1 -1
- package/dist/public/{shadow-claw-file-viewer-BKEpzpbx.js → shadow-claw-file-viewer-BP7gWS5g.js} +1 -1
- package/dist/public/{shadow-claw-files-DDZMk5AA.js → shadow-claw-files-RPPGszcK.js} +1 -1
- package/dist/public/{shadow-claw-git-CqOO97Re.js → shadow-claw-git-BsHEvLrb.js} +2 -2
- package/dist/public/{shadow-claw-integrations-CRGL78Fy.js → shadow-claw-integrations-B0vbcOqg.js} +1 -1
- package/dist/public/{shadow-claw-llm-DoGxEHQL.js → shadow-claw-llm-FNNamrc_.js} +2 -2
- package/dist/public/{shadow-claw-mcp-remote-DyGnK4S_.js → shadow-claw-mcp-remote-7mDgniQu.js} +1 -1
- package/dist/public/{shadow-claw-networking-DJeCdb7e.js → shadow-claw-networking-CGsetaLp.js} +1 -1
- package/dist/public/{shadow-claw-notifications-hSKJeMXb.js → shadow-claw-notifications-pnwRcR-4.js} +1 -1
- package/dist/public/{shadow-claw-page-header-DA-FG08G.js → shadow-claw-page-header-BUy15Poz.js} +1 -1
- package/dist/public/{shadow-claw-pages-DTS98Zbi.js → shadow-claw-pages-ILAjGWNk.js} +1 -1
- package/dist/public/{shadow-claw-settings-5w0ce8SP.js → shadow-claw-settings-Bx5IgVqN.js} +3 -3
- package/dist/public/{shadow-claw-storage-DqlVt27X.js → shadow-claw-storage-PAtNykaF.js} +1 -1
- package/dist/public/{shadow-claw-task-server-ByZwKI6S.js → shadow-claw-task-server-Cbbi_2OO.js} +1 -1
- package/dist/public/{shadow-claw-tasks-Dc4G4zBu.js → shadow-claw-tasks-B-jKYWZJ.js} +1 -1
- package/dist/public/{shadow-claw-terminal-DvusP7wg.js → shadow-claw-terminal-BRejND-Z.js} +1 -1
- package/dist/public/{shadow-claw-tools-BEsid8q-.js → shadow-claw-tools-DNQe3oa-.js} +1 -1
- package/dist/public/{shadow-claw-webvm-BWlIeK78.js → shadow-claw-webvm-BFuwRifU.js} +1 -1
- package/dist/public/{syncWebMcpRegistration-CqVCB6m8.js → syncWebMcpRegistration-FxKAPwaz.js} +1 -1
- package/dist/public/theme-init.js +1 -1
- package/dist/public/{tools-Cp1gequ8.js → tools-BwQKGsro.js} +1 -1
- package/dist/public/transformers-js.worker.js +1 -1
- package/dist/public/webmcp-C28PAlfy.js +1 -0
- package/dist/server.js +1 -1
- package/package.json +3 -3
- package/src/core/utils/initControlPlane.test.ts +122 -1
- package/src/core/utils/initControlPlane.ts +12 -8
- package/src/subsystems/mcp/webmcp.test.ts +253 -1
- package/src/subsystems/mcp/webmcp.ts +147 -4
- package/src/subsystems/providers/model-registry.test.ts +139 -0
- package/src/subsystems/providers/model-registry.ts +54 -2
- package/src/subsystems/providers/providers.test.ts +329 -0
- package/src/subsystems/providers/providers.ts +135 -11
- package/dist/lib/config-DjZ9QWc4.js.map +0 -1
- package/dist/lib/webmcp-BC8_WafM.js +0 -1710
- package/dist/lib/webmcp-BC8_WafM.js.map +0 -1
- package/dist/public/config-Bnwx4EfS.js +0 -1
- package/dist/public/webmcp-DBONjQWd.js +0 -2
package/dist/lib/utils/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { n as __exportAll } from "../rolldown-runtime-DZ8SGSJo.js";
|
|
2
2
|
import { ulid } from "./ulid.js";
|
|
3
|
-
import { a as formatTimestamp, c as toArrayBuffer, i as formatDateForFilename, n as computeSha256, o as handleSpecialLinkNavigation, r as escapeHtml, s as sanitizeHtml, t as bufferToHex } from "../utils-
|
|
3
|
+
import { a as formatTimestamp, c as toArrayBuffer, i as formatDateForFilename, n as computeSha256, o as handleSpecialLinkNavigation, r as escapeHtml, s as sanitizeHtml, t as bufferToHex } from "../utils-mpsYPfS7.js";
|
|
4
4
|
import { getNamespacedItem, getNamespacedStorageKey, removeNamespacedItem, setNamespacedItem } from "./namespacedStorage.js";
|
|
5
5
|
import { applyJsonPatch } from "./jsonPatch.js";
|
|
6
6
|
import { base64ToBytes, bytesToBase64 } from "./base64.js";
|
package/dist/lib/utils/utils.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { a as formatTimestamp, c as toArrayBuffer, i as formatDateForFilename, n as computeSha256, o as handleSpecialLinkNavigation, r as escapeHtml, s as sanitizeHtml, t as bufferToHex } from "../utils-
|
|
1
|
+
import { a as formatTimestamp, c as toArrayBuffer, i as formatDateForFilename, n as computeSha256, o as handleSpecialLinkNavigation, r as escapeHtml, s as sanitizeHtml, t as bufferToHex } from "../utils-mpsYPfS7.js";
|
|
2
2
|
|
|
3
3
|
export { bufferToHex, computeSha256, escapeHtml, formatDateForFilename, formatTimestamp, handleSpecialLinkNavigation, sanitizeHtml, toArrayBuffer };
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { i as __toESM } from "./rolldown-runtime-DZ8SGSJo.js";
|
|
2
2
|
import { n as getDb } from "./txPromise-CuGh-TGK.js";
|
|
3
|
-
import { r as CONFIG_KEYS } from "./config-
|
|
3
|
+
import { r as CONFIG_KEYS } from "./config-BcFbkaQv.js";
|
|
4
4
|
import { l as parseRouteFromUrl } from "./app-routes-BAEMLu9g.js";
|
|
5
5
|
import { t as getConfig } from "./getConfig-BxxXMyuM.js";
|
|
6
6
|
import { t as require_browser } from "./browser-FvTfy_Ym.js";
|
|
7
|
-
import { i as parseHostPatternMatch, n as getDOMPurify, t as ensureIframeSanitizerHook } from "./iframe-sanitizer-
|
|
7
|
+
import { i as parseHostPatternMatch, n as getDOMPurify, t as ensureIframeSanitizerHook } from "./iframe-sanitizer-Dp8EYffI.js";
|
|
8
8
|
|
|
9
9
|
//#region src/security/trusted-types.ts
|
|
10
10
|
const APP_TRUSTED_TYPES_POLICY_NAME = "shadowclaw";
|
|
@@ -553,4 +553,4 @@ async function computeSha256(input) {
|
|
|
553
553
|
|
|
554
554
|
//#endregion
|
|
555
555
|
export { sanitizeSrcdocHtml as _, formatTimestamp as a, toTrustedHtmlPresanitized as b, toArrayBuffer as c, getIframeCsp as d, getIframeSandboxPolicy as f, loadCustomElementSecurityFromDb as g, isAllowedCustomElement as h, formatDateForFilename as i, configureCustomElementSecurity as l, installCustomElementsRegistryGuard as m, computeSha256 as n, handleSpecialLinkNavigation as o, installCustomElementDomGuard as p, escapeHtml as r, sanitizeHtml as s, bufferToHex as t, getApprovedCustomElementScriptDescriptors as u, setSanitizedHtml as v, toTrustedScriptUrl as x, setTrustedSrcdoc as y };
|
|
556
|
-
//# sourceMappingURL=utils-
|
|
556
|
+
//# sourceMappingURL=utils-mpsYPfS7.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils-B99XP70b.js","names":["process"],"sources":["../../src/security/trusted-types.ts","../../src/security/custom-element-security.ts","../../src/utils/utils.ts"],"sourcesContent":["/// <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","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 globalThis !== \"undefined\" &&\n globalThis.location?.origin &&\n globalThis.location.origin !== \"null\"\n ? globalThis.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 globalThis !== \"undefined\" &&\n globalThis.location?.origin &&\n globalThis.location.origin !== \"null\" &&\n url.origin === globalThis.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 globalThis !== \"undefined\" && globalThis.location?.origin\n ? globalThis.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\nexport interface CustomElementScriptDescriptor {\n src: string;\n hasInit: boolean;\n}\n\n/**\n * Retrieve approved custom element script descriptors from the embedded site config.\n */\nexport function getApprovedCustomElementScriptDescriptors(): CustomElementScriptDescriptor[] {\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) => {\n const src = typeof s === \"string\" ? s : s?.src;\n const hasInit =\n typeof s === \"object\" && s !== null ? Boolean(s.hasInit) : false;\n return { src, hasInit };\n })\n .filter(\n (entry): entry is CustomElementScriptDescriptor =>\n typeof entry.src === \"string\" &&\n isSafeCustomElementSource(entry.src),\n );\n }\n } catch {}\n\n return [];\n}\n\n/**\n * Retrieve approved custom element script URLs from the embedded site config.\n */\nexport function getApprovedCustomElementScripts(): string[] {\n return getApprovedCustomElementScriptDescriptors().map((d) => d.src);\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 subtle =\n globalThis.crypto?.subtle ??\n (globalThis as any).window?.crypto?.subtle ??\n (typeof process !== \"undefined\"\n ? (await import(\"node:crypto\")).webcrypto?.subtle\n : undefined);\n\n if (!subtle) {\n throw new Error(\"crypto.subtle is not available in current environment\");\n }\n\n const hashBuffer = await subtle.digest(\"SHA-256\", data);\n\n return bufferToHex(hashBuffer);\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"utils-mpsYPfS7.js","names":["process"],"sources":["../../src/security/trusted-types.ts","../../src/security/custom-element-security.ts","../../src/utils/utils.ts"],"sourcesContent":["/// <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","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 globalThis !== \"undefined\" &&\n globalThis.location?.origin &&\n globalThis.location.origin !== \"null\"\n ? globalThis.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 globalThis !== \"undefined\" &&\n globalThis.location?.origin &&\n globalThis.location.origin !== \"null\" &&\n url.origin === globalThis.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 globalThis !== \"undefined\" && globalThis.location?.origin\n ? globalThis.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\nexport interface CustomElementScriptDescriptor {\n src: string;\n hasInit: boolean;\n}\n\n/**\n * Retrieve approved custom element script descriptors from the embedded site config.\n */\nexport function getApprovedCustomElementScriptDescriptors(): CustomElementScriptDescriptor[] {\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) => {\n const src = typeof s === \"string\" ? s : s?.src;\n const hasInit =\n typeof s === \"object\" && s !== null ? Boolean(s.hasInit) : false;\n return { src, hasInit };\n })\n .filter(\n (entry): entry is CustomElementScriptDescriptor =>\n typeof entry.src === \"string\" &&\n isSafeCustomElementSource(entry.src),\n );\n }\n } catch {}\n\n return [];\n}\n\n/**\n * Retrieve approved custom element script URLs from the embedded site config.\n */\nexport function getApprovedCustomElementScripts(): string[] {\n return getApprovedCustomElementScriptDescriptors().map((d) => d.src);\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 subtle =\n globalThis.crypto?.subtle ??\n (globalThis as any).window?.crypto?.subtle ??\n (typeof process !== \"undefined\"\n ? (await import(\"node:crypto\")).webcrypto?.subtle\n : undefined);\n\n if (!subtle) {\n throw new Error(\"crypto.subtle is not available in current environment\");\n }\n\n const hashBuffer = await subtle.digest(\"SHA-256\", data);\n\n return bufferToHex(hashBuffer);\n}\n"],"mappings":";;;;;;;;;AAuBA,MAAM,gCAAgC;AAEtC,IAAI;AAEJ,SAAS,yBAAyD;CAChE,MAAM,UAAU,WAAW;CAC3B,IAAI,CAAC,WAAW,OAAO,QAAQ,iBAAiB,YAC9C,OAAO;CAGT,OAAO;AACT;AAEA,SAAS,wBAAuD;CAC9D,IAAI,iBAAiB,QACnB,OAAO;CAGT,MAAM,UAAU,uBAAuB;CACvC,IAAI,CAAC,SAAS;EACZ,eAAe;EAEf,OAAO;CACT;CAEA,IAAI,OAAO,QAAQ,cAAc,YAAY;EAC3C,MAAM,iBAAiB,QAAQ,UAAU,6BAA6B;EACtE,IAAI,gBAAgB;GAClB,eAAe;GAEf,OAAO;EACT;CACF;CAEA,IAAI;EACF,eAAe,QAAQ,aAAa,+BAA+B;GAIjE,aAAa,UAAkB;GAC/B,kBAAkB,UAAkB;EACtC,CAAC;CACH,QAAQ;EACN,IAAI,OAAO,QAAQ,cAAc,YAC/B,eAAe,QAAQ,UAAU,6BAA6B,KAAK;OAEnE,eAAe;CAEnB;CAEA,OAAO;AACT;AAMA,SAAgB,sBACd,QAAuB,IACvB,UAAkB,CAAC,GACJ;CACf,MAAM,YAAY,aAAa,OAAO,OAAO;CAC7C,MAAM,SAAS,sBAAsB;CAErC,IAAI,CAAC,QACH,OAAO;CAGT,OAAO,OAAO,WAAW,SAAS;AACpC;AAMA,SAAgB,mBAAmB,MAAc,UAAkB,CAAC,GAAW;CAC7E,OAAO,aAAa,MAAM,OAAO;AACnC;AAEA,SAAgB,0BAA0B,MAA6B;CACrE,MAAM,SAAS,sBAAsB;CAErC,IAAI,CAAC,QACH,OAAO;CAGT,OAAO,OAAO,WAAW,IAAI;AAC/B;AAEA,SAAgB,iBACd,SACA,QAAuB,IACvB,UAAkB,CAAC,GACJ;CACf,MAAM,cAAc,sBAAsB,OAAO,OAAO;CAExD,QAAQ,YAAY;CAEpB,OAAO;AACT;AAsBA,SAAgB,iBACd,QACA,MACe;CACf,MAAM,cAAc,0BAA0B,IAAI;CAElD,OAAO,SAAS;CAEhB,OAAO;AACT;AAEA,SAAgB,mBAAmB,KAA4B;CAC7D,MAAM,SAAS,sBAAsB;CAErC,IAAI,CAAC,UAAU,OAAO,OAAO,oBAAoB,YAC/C,OAAO;CAGT,OAAO,OAAO,gBAAgB,GAAG;AACnC;;;;;ACzJA,MAAa,kCAA4C,CAAC;;AAG1D,MAAa,+CAAyD,CAAC;AAEvE,IAAI,wBAAqC,IAAI,IAC3C,gCAAgC,KAAK,OAAO,GAAG,YAAY,CAAC,CAAC,KAAK,CAAC,CACrE;AAEA,IAAI,qBAA+B,CACjC,GAAG,4CACL;AACA,IAAI,qBAA2D,CAAC;AAEhE,SAAS,oBAAoB,UAA0B;CACrD,qBAAqB,SAClB,KAAK,MAAM,sBAAsB,CAAC,CAAC,CAAC,CACpC,OAAO,OAAO;AACnB;AAEA,oBAAoB,kBAAkB;;;;AAKtC,SAAS,qBAAqB,UAAuC;CACnE,IAAI,MAAM,QAAQ,QAAQ,GACxB,OAAO,SACJ,KAAK,MAAO,OAAO,MAAM,WAAW,EAAE,YAAY,CAAC,CAAC,KAAK,IAAI,EAAG,CAAC,CACjE,OAAO,OAAO;CAEnB,IAAI,OAAO,aAAa,UACtB,OAAO,SACJ,MAAM,QAAQ,CAAC,CACf,KAAK,MAAM,EAAE,YAAY,CAAC,CAAC,KAAK,CAAC,CAAC,CAClC,OAAO,OAAO;CAEnB,OAAO,CAAC;AACV;;;;AAKA,SAAS,qBAAqB,UAAuC;CACnE,IAAI,MAAM,QAAQ,QAAQ,GACxB,OAAO,SACJ,KAAK,MAAO,OAAO,MAAM,WAAW,EAAE,KAAK,IAAI,EAAG,CAAC,CACnD,OAAO,OAAO;CAEnB,IAAI,OAAO,aAAa,UACtB,OAAO,SACJ,MAAM,QAAQ,CAAC,CACf,KAAK,MAAM,EAAE,KAAK,CAAC,CAAC,CACpB,OAAO,OAAO;CAEnB,OAAO,CAAC;AACV;;;;AAKA,SAAgB,yBAAyB,UAAmC;CAC1E,MAAM,OAAO,qBAAqB,QAAQ;CAC1C,wBAAwB,IAAI,IAAI,IAAI;AACtC;;;;AAYA,SAAgB,oCACd,UACM;CACN,MAAM,OAAO,qBAAqB,QAAQ;CAC1C,qBAAqB;CACrB,oBAAoB,IAAI;AAC1B;;;;AAKA,SAAgB,sCAAgD;CAC9D,OAAO,CAAC,GAAG,kBAAkB;AAC/B;;;;;;AAOA,SAAgB,uBAAuB,SAA0B;CAC/D,IAAI,CAAC,WAAW,OAAO,YAAY,UACjC,OAAO;CAGT,MAAM,QAAQ,QAAQ,KAAK,CAAC,CAAC,YAAY;CAGzC,IAAI,CAAC,MAAM,SAAS,GAAG,GACrB,OAAO;CAIT,IAAI,UAAU,iBAAiB,MAAM,WAAW,cAAc,GAC5D,OAAO;CAIT,OAAO,sBAAsB,IAAI,KAAK;AACxC;;;;AAKA,SAAgB,0BAA0B,QAAyB;CACjE,IAAI,CAAC,UAAU,OAAO,WAAW,UAC/B,OAAO;CAGT,MAAM,UAAU,OAAO,KAAK;CAC5B,IAAI,CAAC,SACH,OAAO;CAIT,IAAI,kCAAkC,KAAK,OAAO,GAChD,OAAO;CAIT,IAAI,UAAU,KAAK,OAAO,GACxB,OAAO;CAGT,IAAI;EACF,MAAM,OACJ,OAAO,eAAe,eACtB,WAAW,UAAU,UACrB,WAAW,SAAS,WAAW,SAC3B,WAAW,SAAS,SACpB;EACN,MAAM,MAAM,IAAI,IAAI,SAAS,IAAI;EAEjC,IAAI,IAAI,aAAa,WAAW,IAAI,aAAa,UAC/C,OAAO;EAIT,IACE,OAAO,eAAe,eACtB,WAAW,UAAU,UACrB,WAAW,SAAS,WAAW,UAC/B,IAAI,WAAW,WAAW,SAAS,QAEnC,OAAO;EAGT,MAAM,WAAW,IAAI,SAAS,YAAY;EAE1C,OAAO,mBAAmB,MAAM,YAAY,QAAQ,QAAQ,CAAC;CAC/D,QAAQ;EACN,OAAO;CACT;AACF;AAEA,MAAa,gCACX;AAEF,MAAa,qBAAqB;CAAC;CAAU;CAAS;AAAO;AAC7D,MAAa,sBAAsB;CAAC;CAAU;CAAS;AAAO;AAC9D,MAAa,oBAAoB;CAC/B;CACA;CACA;CACA;AACF;AACA,MAAa,kBAAkB;CAAC;CAAU;CAAS;CAAS;CAAU;AAAO;AAE7E,IAAI,4BAAoC;AACxC,IAAI,kBAA4B,CAAC,GAAG,kBAAkB;AACtD,IAAI,mBAA6B,CAAC,GAAG,mBAAmB;AACxD,IAAI,kBAA4B,CAAC;AACjC,IAAI,iBAA2B,CAAC,GAAG,iBAAiB;AACpD,IAAI,eAAyB,CAAC,GAAG,eAAe;;;;AAKhD,SAAgB,yBAAiC;CAC/C,OAAO;AACT;;;;AAKA,SAAgB,uBAAuB,QAAiC;CACtE,IAAI,MAAM,QAAQ,MAAM,GACtB,4BAA4B,OACzB,KAAK,MAAO,OAAO,MAAM,WAAW,EAAE,KAAK,IAAI,EAAG,CAAC,CACnD,OAAO,OAAO,CAAC,CACf,KAAK,GAAG;MACN,IAAI,OAAO,WAAW,YAAY,OAAO,KAAK,GACnD,4BAA4B,OAAO,KAAK;MAExC,4BAA4B;AAEhC;;;;AAKA,SAAgB,aAAa,OAAuB;CAClD,MAAM,kBAAkB,oCAAoC;CAC5D,MAAM,kBAAkB,gCAAgC;CAExD,MAAM,qCAAqB,IAAI,IAAY;CAC3C,KAAK,MAAM,WAAW,iBACpB,IAAI,WAAW,sCAAsC,KAAK,OAAO,GAAG;EAClE,mBAAmB,IAAI,WAAW,SAAS;EAC3C,mBAAmB,IAAI,UAAU,SAAS;CAC5C;CAEF,KAAK,MAAM,aAAa,iBACtB,IAAI;EACF,MAAM,SAAS,IAAI,IACjB,WACA,OAAO,eAAe,eAAe,WAAW,UAAU,SACtD,WAAW,SAAS,SACpB,kBACN;EACA,mBAAmB,IAAI,OAAO,MAAM;CACtC,QAAQ,CAAC;CAGX,MAAM,gBAAgB;EACpB,UAAU,MAAM;EAChB,GAAG,MAAM,KAAK,kBAAkB;EAChC,GAAG;CACL;CAEA,MAAM,iBAAiB,CACrB,GAAG,kBACH,GAAG,MAAM,KAAK,kBAAkB,CAClC;CAUA,OAAO;EAPL,cAAc,MAAM,KAAK,IAAI,IAAI,aAAa,CAAC,CAAC,CAAC,KAAK,GAAG;EACzD,cAAc,MAAM,KAAK,IAAI,IAAI,eAAe,CAAC,CAAC,CAAC,KAAK,GAAG;EAC3D,eAAe,MAAM,KAAK,IAAI,IAAI,cAAc,CAAC,CAAC,CAAC,KAAK,GAAG;EAC3D,aAAa,MAAM,KAAK,IAAI,IAAI,cAAc,CAAC,CAAC,CAAC,KAAK,GAAG;EACzD,WAAW,MAAM,KAAK,IAAI,IAAI,YAAY,CAAC,CAAC,CAAC,KAAK,GAAG;CAGvC,CAAC,CAAC,KAAK,IAAI;AAC7B;;;;AAKA,SAAgB,+BAA+B,QAoBtC;CACP,IAAI,CAAC,UAAU,OAAO,WAAW,UAC/B;CAIF,MAAM,WACJ,OAAO,0BACN,OAAO,OAAO,mBAAmB,YAClC,CAAC,MAAM,QAAQ,OAAO,cAAc,IAChC,OAAO,gBAAgB,kBACvB;CAEN,IAAI,aAAa,QACf,yBAAyB,QAAQ;CAInC,MAAM,UACJ,OAAO,gCACN,OAAO,OAAO,mBAAmB,YAClC,CAAC,MAAM,QAAQ,OAAO,cAAc,IAChC,OAAO,gBAAgB,iBACvB;CAEN,IAAI,YAAY,QACd,oCAAoC,OAAO;CAI7C,IAAI,OAAO,UAAU,kBAAkB,QACrC,uBAAuB,OAAO,SAAS,aAAa;MAC/C,IACL,OAAO,UAAU,oBAAoB,QACrC,OAAO,UAAU,0BAA0B,MAE3C;MAAI,CAAC,0BAA0B,SAAS,mBAAmB,GACzD,4BACE,GAAG,0BAA0B,oBAAoB,KAAK;CAC1D;CAIF,IAAI,OAAO,UAAU,cAAc,QACjC,kBAAkB,qBAAqB,OAAO,SAAS,SAAS;CAElE,IAAI,OAAO,UAAU,eAAe,QAClC,mBAAmB,qBAAqB,OAAO,SAAS,UAAU;CAEpE,IAAI,OAAO,UAAU,cAAc,QACjC,kBAAkB,qBAAqB,OAAO,SAAS,SAAS;CAElE,IAAI,OAAO,UAAU,aAAa,QAChC,iBAAiB,qBAAqB,OAAO,SAAS,QAAQ;CAEhE,IAAI,OAAO,UAAU,WAAW,QAC9B,eAAe,qBAAqB,OAAO,SAAS,MAAM;AAE9D;;;;AAKA,SAAgB,8CAAoD;CAClE,IAAI,OAAO,aAAa,aACtB;CAGF,MAAM,eAAe,SAAS,eAAe,yBAAyB;CACtE,IAAI,gBAAgB,aAAa,aAC/B,IAAI;EAEF,+BADe,KAAK,MAAM,aAAa,WACH,CAAC;CACvC,QAAQ,CAER;AAEJ;;;;AAUA,SAAgB,4CAA6E;CAC3F,IAAI,OAAO,aAAa,aACtB,OAAO,CAAC;CAGV,MAAM,eAAe,SAAS,eAAe,yBAAyB;CACtE,IAAI,CAAC,gBAAgB,CAAC,aAAa,aACjC,OAAO,CAAC;CAGV,IAAI;EACF,MAAM,SAAS,KAAK,MAAM,aAAa,WAAW;EAClD,MAAM,UACJ,OAAO,OAAO,mBAAmB,YACjC,CAAC,MAAM,QAAQ,OAAO,cAAc,IAChC,OAAO,gBAAgB,UACvB;EAEN,IAAI,MAAM,QAAQ,OAAO,GACvB,OAAO,QACJ,KAAK,MAAW;GAIf,OAAO;IAAE,KAHG,OAAO,MAAM,WAAW,IAAI,GAAG;IAG7B,SADZ,OAAO,MAAM,YAAY,MAAM,OAAO,QAAQ,EAAE,OAAO,IAAI;GACvC;EACxB,CAAC,CAAC,CACD,QACE,UACC,OAAO,MAAM,QAAQ,YACrB,0BAA0B,MAAM,GAAG,CACvC;CAEN,QAAQ,CAAC;CAET,OAAO,CAAC;AACV;;;;AAKA,SAAgB,kCAA4C;CAC1D,OAAO,0CAA0C,CAAC,CAAC,KAAK,MAAM,EAAE,GAAG;AACrE;;;;AAKA,eAAsB,gCACpB,IACe;CACf,IAAI;EACF,MAAM,WAAW,MAAO,MAAM,MAAM;EACpC,IAAI,CAAC,UACH;EAGF,MAAM,CAAC,aAAa,YAAY,MAAM,QAAQ,IAAI,CAChD,UAAU,UAAU,YAAY,uBAAuB,GACvD,UAAU,UAAU,YAAY,oCAAoC,CACtE,CAAC;EAED,IAAI,OAAO,gBAAgB,YAAY,YAAY,KAAK,GACtD,IAAI;GAEF,yBADe,KAAK,MAAM,WACI,CAAC;EACjC,QAAQ;GACN,yBAAyB,WAAW;EACtC;EAGF,IAAI,OAAO,aAAa,YAAY,SAAS,KAAK,GAChD,IAAI;GAEF,oCADe,KAAK,MAAM,QACe,CAAC;EAC5C,QAAQ;GACN,oCAAoC,QAAQ;EAC9C;CAEJ,SAAS,KAAK;EACZ,QAAQ,KAAK,mDAAmD,GAAG;CACrE;AACF;AAEA,IAAI,+BAAoE;AACxE,IAAI,2BAA2B;;;;AAK/B,SAAgB,qCAA2C;CACzD,4CAA4C;CAE5C,IACE,4BACA,OAAO,mBAAmB,eAC1B,OAAO,eAAe,WAAW,YAEjC;CAGF,+BAA+B,eAAe,OAAO,KAAK,cAAc;CAExE,eAAe,SAAS,SACtB,MACA,aACA,SACA;EAEA,IAAI,CAAC,wBADc,QAAQ,GAAE,CAAE,YAAY,CAAC,CAAC,KACT,CAAC,GAAG;GACtC,MAAM,WAAW,qCAAqC,KAAK;GAC3D,QAAQ,MAAM,QAAQ;GACtB,MAAM,IAAI,MAAM,QAAQ;EAC1B;EAEA,OAAO,6BAA8B,MAAM,aAAa,OAAO;CACjE;CAEA,2BAA2B;AAC7B;;;;AAkBA,SAAgB,6BACd,OAAa,OAAO,aAAa,cAC7B,SAAS,kBACR,MACoB;CACzB,IAAI,OAAO,qBAAqB,eAAe,CAAC,MAC9C,OAAO;CAIT,IAAI,OAAQ,KAAa,qBAAqB,YAC5C,IAAI;EAEF,AADkB,KAAiB,iBAAiB,GAC7C,CAAC,CAAC,SAAS,OAAO;GACvB,MAAM,UAAU,GAAG,UAAU,GAAG,QAAQ,YAAY,IAAI;GACxD,IAAI,QAAQ,SAAS,GAAG,KAAK,CAAC,uBAAuB,OAAO,GAAG;IAC7D,QAAQ,KACN,4DAA4D,QAAQ,EACtE;IACA,GAAG,OAAO;GACZ;EACF,CAAC;CACH,QAAQ,CAAC;CAGX,MAAM,WAAW,IAAI,kBAAkB,cAAc;EACnD,KAAK,MAAM,YAAY,WACrB,SAAS,WAAW,SAAS,SAAS;GACpC,IAAI,KAAK,aAAa,GAA2B;IAC/C,MAAM,KAAK;IACX,MAAM,UAAU,GAAG,UAAU,GAAG,QAAQ,YAAY,IAAI;IACxD,IAAI,QAAQ,SAAS,GAAG,KAAK,CAAC,uBAAuB,OAAO,GAAG;KAC7D,QAAQ,KACN,mDAAmD,QAAQ,EAC7D;KACA,GAAG,OAAO;IACZ;GACF;EACF,CAAC;CAEL,CAAC;CAED,SAAS,QAAQ,MAAM;EAAE,WAAW;EAAM,SAAS;CAAK,CAAC;CAEzD,OAAO;AACT;AAgDA,IAAI,uBAAuB;;;;AAK3B,SAAgB,mCAAyC;CACvD,IAAI,sBACF;CAGF,MAAM,SAAS,aAAa;CAE5B,IAAI,UAAU,OAAO,OAAO,YAAY,YAAY;EAClD,MAAM,6BAA6B,SAAe;GAChD,IAAI,QAAQ,KAAK,aAAa,GAAsB;IAClD,MAAM,KAAK;IACX,MAAM,WAAW,GAAG,WAAW,GAAE,CAAE,YAAY;IAC/C,IAAI,QAAQ,SAAS,GAAG,KAAK,CAAC,uBAAuB,OAAO,GAAG;KAC7D,IAAI,OAAO,GAAG,WAAW,YACvB,GAAG,OAAO;KAEZ,IAAI,GAAG,YACL,GAAG,WAAW,YAAY,EAAE;IAEhC;GACF;EACF;EAEA,OAAO,QAAQ,uBAAuB,yBAAyB;EAC/D,OAAO,QAAQ,yBAAyB,yBAAyB;EACjE,uBAAuB;CACzB;AACF;;;;;;;;AClnBA,SAAgB,sBAAsB,uBAAO,IAAI,KAAK,GAAW;CAC/D,MAAM,OAAO,MAAc,OAAO,CAAC,CAAC,CAAC,SAAS,GAAG,GAAG;CAUpD,OAAO,GARM,KAAK,YAQL,EAAE,GAPJ,IAAI,KAAK,SAAS,IAAI,CAOd,EAAE,GANV,IAAI,KAAK,QAAQ,CAMH,EAAE,GAJhB,IAAI,KAAK,SAAS,CAIE,EAAE,GAHrB,IAAI,KAAK,WAAW,CAGM,EAAE,GAF7B,IAAI,KAAK,WAAW,CAEa;AAC9C;;;;AAKA,SAAgB,gBAAgB,WAA2B;CACzD,MAAM,OAAO,IAAI,KAAK,SAAS;CAE/B,OAAO,IAAI,KAAK,eAAe,SAAS;EACtC,SAAS;EACT,OAAO;EACP,KAAK;EACL,MAAM;EACN,QAAQ;EACR,QAAQ;CACV,CAAC,CAAC,CAAC,OAAO,IAAI;AAChB;;;;AAKA,SAAgB,WAAW,KAAqB;CAC9C,MAAM,MAAM,SAAS,cAAc,KAAK;CACxC,IAAI,cAAc;CAElB,OAAO,IAAI;AACb;;;;AAKA,SAAgB,aACd,QAAuB,IACvB,UAAkB,CAAC,GACX;CACR,0BAA0B;CAC1B,iCAAiC;CAEjC,OAAO,aAAa,CAAC,CAAC,SAAS,OAAO;EACpC,UAAU;GAAC;GAAU;GAAU;EAAY;EAC3C,UAAU;GACR;GACA;GACA;GACA;GACA;GACA;EACF;EACA,yBAAyB;GACvB,eAAe,YAAoB,uBAAuB,OAAO;GACjE,0BAA0B;GAC1B,gCAAgC;EAClC;EACA,GAAG;CACL,CAAC;AACH;;;;;AAgBA,SAAgB,4BACd,MACA,WAAmB,IACnB,gBACS;CACT,IAAI,UAAU,KAAK,KAAK;CACxB,IAAI,CAAC,SACH,OAAO;CAIT,MAAM,gBAAgB,QAAQ,QAAQ,GAAG;CACzC,IAAI,kBAAkB,IAGpB,UAFe,QAAQ,MAAM,GAAG,gBAAgB,CAEjC,IADD,QAAQ,MAAM,gBAAgB,CACrB,CAAC,CAAC,QAAQ,OAAO,GAAG;CAI7C,IAAI,QAAQ,WAAW,IAAI,KAAK,QAAQ,WAAW,GAAG,GAAG;EAOvD,MAAM,YANc,QAAQ,WAAW,IAAI,IACvC,QAAQ,MAAM,CAAC,IACf,QAAQ,MAAM,CAAC,EAGS,CAAC,MAAM,QAAQ,CAAC,CAAC,CAAC,EACrB,CAAC,YAAY;EAItC,IAAI;GADgB;GAAQ;GAAS;GAAS;GAAS;EAC1C,CAAC,CAAC,SAAS,QAAQ,GAAG;GAEjC,MAAM,UAAU,QAAQ,WAAW,IAAI,IACnC,QAAQ,QAAQ,QAAQ,eAAe,IACvC,QAAQ,QAAQ,MAAM,eAAe;GACzC,MAAM,UAAU,IAAI,IAAI,SAAS,eAAe;GAEhD,MAAM,UACJ,QAAQ,aAAa,IAAI,SAAS,KAClC,QAAQ,aAAa,IAAI,gBAAgB,KACzC;GACF,MAAM,OACJ,QAAQ,aAAa,IAAI,MAAM,KAC/B,QAAQ,aAAa,IAAI,MAAM,KAC/B;GAEF,MAAM,cAAc,QAAQ,aAAa,IAAI,QAAQ;GACrD,MAAM,SAAS,cACX,cACA,QAAQ,OACN,QAAQ,KAAK,MAAM,CAAC,IACpB;GAEN,MAAM,SAAmC;IACvC,MAAM;IACN,SAAS,WAAW;IACpB,MAAM,QAAQ;IACd,QAAQ,UAAU;GACpB;GAEA,SAAS,cACP,IAAI,YAAY,wBAAwB;IACtC;IACA,SAAS;IACT,UAAU;GACZ,CAAC,CACH;GAEA,OAAO;EACT;CACF;CAGA,IAAI,QAAQ,WAAW,GAAG,GACxB,IAAI;EACF,MAAM,UAAU,IAAI,IAAI,SAAS,OAAO,SAAS,MAAM;EACvD,MAAM,QAAQ,kBAAkB,SAAS,cAAc;EACvD,IAAI,OAAO;GACT,SAAS,cACP,IAAI,YAAY,wBAAwB;IACtC,QAAQ;KACN,MAAM,MAAM;KACZ,SAAS,MAAM;KACf,MAAM,MAAM;KACZ,QACE,MAAM,WACL,QAAQ,OAAO,QAAQ,KAAK,MAAM,CAAC,IAAI;IAC5C;IACA,SAAS;IACT,UAAU;GACZ,CAAC,CACH;GAEA,OAAO;EACT;CACF,QAAQ,CAER;CAMF,IACE,CAFgB,2BAA2B,KAAK,OAEvC,KACT,CAAC,QAAQ,WAAW,IAAI,KACxB,CAAC,QAAQ,WAAW,aAAa,GACjC;EAEA,IAAI,eAAe,QAAQ,MAAM,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,QAAQ,OAAO,GAAG;EACjE,MAAM,aAAa,aAAa,WAAW,GAAG;EAC9C,eAAe,aAAa,QAAQ,QAAQ,EAAE;EAE9C,MAAM,UAAU,IAAI,IAAI,SAAS,eAAe;EAChD,MAAM,SAAS,QAAQ,OAAO,QAAQ,KAAK,MAAM,CAAC,IAAI;EAEtD,IAAI,YAAY;EAChB,IAAI,CAAC,cAAc,UAAU;GAC3B,MAAM,YAAY,SACf,QAAQ,OAAO,GAAG,CAAC,CACnB,QAAQ,QAAQ,EAAE,CAAC,CACnB,MAAM,GAAG,CAAC,CACV,OAAO,OAAO;GACjB,UAAU,IAAI;GAEd,MAAM,YAAY,aAAa,MAAM,GAAG;GACxC,MAAM,QAAQ,CAAC,GAAG,SAAS;GAC3B,KAAK,MAAM,QAAQ,WAAW;IAC5B,IAAI,CAAC,QAAQ,SAAS,KACpB;IAGF,IAAI,SAAS,MACX,MAAM,IAAI;SAEV,MAAM,KAAK,IAAI;GAEnB;GAEA,YAAY,MAAM,KAAK,GAAG;EAC5B;EAEA,IAAI,WAAW;GACb,MAAM,SAAmC;IACvC,MAAM;IACN,SAAS,kBAAkB;IAC3B,MAAM;IACN,QAAQ,UAAU;GACpB;GAEA,SAAS,cACP,IAAI,YAAY,wBAAwB;IACtC;IACA,SAAS;IACT,UAAU;GACZ,CAAC,CACH;GAEA,OAAO;EACT;CACF;CAEA,OAAO;AACT;;;;AAKA,SAAgB,cAAc,OAAwC;CACpE,IAAI,iBAAiB,MACnB,OAAO,MAAM,YAAY;CAG3B,IAAI,iBAAiB,aACnB,OAAO,QAAQ,QAAQ,MAAM,MAAM,CAAC,CAAgB;CAGtD,MAAM,EAAE,QAAQ,YAAY,eAAe;CAE3C,OAAO,QAAQ,QACb,OAAO,MAAM,YAAY,aAAa,UAAU,CAClD;AACF;;;;AAKA,SAAgB,YAAY,QAA6B;CACvD,OAAO,MAAM,KAAK,IAAI,WAAW,MAAM,CAAC,CAAC,CACtC,KAAK,MAAM,EAAE,SAAS,EAAE,CAAC,CAAC,SAAS,GAAG,GAAG,CAAC,CAAC,CAC3C,KAAK,EAAE;AACZ;;;;AAKA,eAAsB,cAAc,OAAmC;CACrE,MAAM,OAAO,MAAM,cAAc,KAAK;CACtC,MAAM,SACJ,WAAW,QAAQ,UAClB,WAAmB,QAAQ,QAAQ,WACnC,OAAOA,2BAAY,eACf,MAAM,OAAO,kCAAc,iDAAE,WAAW,SACzC;CAEN,IAAI,CAAC,QACH,MAAM,IAAI,MAAM,uDAAuD;CAKzE,OAAO,YAAY,MAFM,OAAO,OAAO,WAAW,IAAI,CAEzB;AAC/B"}
|