@agimon-ai/doompi-web 0.0.1-alpha.14 → 0.0.1-alpha.16
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/dist/src/adapters/httpServer.cjs +2 -2
- package/dist/src/adapters/httpServer.cjs.map +1 -1
- package/dist/src/adapters/httpServer.d.cts +2 -0
- package/dist/src/adapters/httpServer.d.cts.map +1 -1
- package/dist/src/adapters/httpServer.d.mts +2 -0
- package/dist/src/adapters/httpServer.d.mts.map +1 -1
- package/dist/src/adapters/httpServer.mjs +2 -2
- package/dist/src/adapters/httpServer.mjs.map +1 -1
- package/dist/src/adapters/sessionHub.cjs +1 -1
- package/dist/src/adapters/sessionHub.cjs.map +1 -1
- package/dist/src/adapters/sessionHub.mjs +1 -1
- package/dist/src/adapters/sessionHub.mjs.map +1 -1
- package/dist/src/adapters/syncGuard.cjs +1 -1
- package/dist/src/adapters/syncGuard.cjs.map +1 -1
- package/dist/src/adapters/syncGuard.mjs +1 -1
- package/dist/src/adapters/syncGuard.mjs.map +1 -1
- package/dist/web/assets/{CodeEditorView-BN7uAd3p.js → CodeEditorView-x5dSJyH5.js} +2 -2
- package/dist/web/assets/{CodeEditorView-BN7uAd3p.js.map → CodeEditorView-x5dSJyH5.js.map} +1 -1
- package/dist/web/assets/{dist-Br15ikyX.js → dist-BjOHzEAd.js} +2 -2
- package/dist/web/assets/{dist-Br15ikyX.js.map → dist-BjOHzEAd.js.map} +1 -1
- package/dist/web/assets/{dist-DyJg-Ztx.js → dist-CeI3DoxX.js} +2 -2
- package/dist/web/assets/{dist-DyJg-Ztx.js.map → dist-CeI3DoxX.js.map} +1 -1
- package/dist/web/assets/{dist-D6JgiCOh.js → dist-CkiChlyh.js} +2 -2
- package/dist/web/assets/{dist-D6JgiCOh.js.map → dist-CkiChlyh.js.map} +1 -1
- package/dist/web/assets/{dist-CpWM9HPM.js → dist-DGGMgE1d.js} +2 -2
- package/dist/web/assets/{dist-CpWM9HPM.js.map → dist-DGGMgE1d.js.map} +1 -1
- package/dist/web/assets/{dist-0dAKR2Se.js → dist-DOndDXyJ.js} +2 -2
- package/dist/web/assets/{dist-0dAKR2Se.js.map → dist-DOndDXyJ.js.map} +1 -1
- package/dist/web/assets/{dist-Dhwss0kX.js → dist-DmNx_rOj.js} +2 -2
- package/dist/web/assets/{dist-Dhwss0kX.js.map → dist-DmNx_rOj.js.map} +1 -1
- package/dist/web/assets/{dist-0xJw4xv3.js → dist-K0Kxol7m.js} +2 -2
- package/dist/web/assets/{dist-0xJw4xv3.js.map → dist-K0Kxol7m.js.map} +1 -1
- package/dist/web/assets/{dist-DLyMOTCg.js → dist-gdc1AOyh.js} +2 -2
- package/dist/web/assets/{dist-DLyMOTCg.js.map → dist-gdc1AOyh.js.map} +1 -1
- package/dist/web/assets/{dist-Bnntc1cw.js → dist-scMsNAmD.js} +2 -2
- package/dist/web/assets/{dist-Bnntc1cw.js.map → dist-scMsNAmD.js.map} +1 -1
- package/dist/web/assets/index-6BGXtAmW.js +143 -0
- package/dist/web/assets/index-6BGXtAmW.js.map +1 -0
- package/dist/web/assets/index-DxH-he8Q.css +2 -0
- package/dist/web/index.html +2 -2
- package/package.json +10 -10
- package/src/adapters/httpServer.ts +62 -32
- package/src/adapters/sessionHub.ts +146 -6
- package/src/adapters/syncGuard.ts +33 -26
- package/src/web/app/Providers.tsx +1 -5
- package/src/web/app/sessionRuntime.ts +64 -2
- package/src/web/features/activity/ContextPanel.tsx +3 -0
- package/src/web/features/session/Composer.tsx +23 -22
- package/src/web/features/session/Timeline.tsx +175 -50
- package/src/web/features/sessions/SessionRail.tsx +53 -18
- package/src/web/lib/commands.ts +5 -0
- package/src/web/lib/pluginRegistry.ts +38 -0
- package/src/web/lib/pluginSlotProps.ts +31 -2
- package/src/web/lib/promptFocus.ts +2 -1
- package/src/web/lib/sessionModel.ts +13 -2
- package/src/web/routes/CockpitPage.tsx +12 -0
- package/src/web/stores/composerStore.ts +82 -1
- package/src/web/stores/sessionStore.ts +11 -3
- package/src/web/stores/sessionsStore.ts +15 -1
- package/src/web/stores/usePluginSlotProps.ts +2 -1
- package/dist/web/assets/index-BlyW0dqe.js +0 -132
- package/dist/web/assets/index-BlyW0dqe.js.map +0 -1
- package/dist/web/assets/index-_BcdH66j.css +0 -2
- package/src/web/features/remote/RemoteBanner.tsx +0 -50
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
const e=require("../../_virtual/_rolldown/runtime.cjs"),t=require("./piHubService.cjs"),n=require("./syncGuard.cjs"),r=require("./piWebSocketListener.cjs"),i=require("../types/media.cjs"),a=require("../services/fileMedia.cjs"),o=require("../services/staticAssets.cjs"),s=require("../types/hub.cjs"),c=require("../types/notification.cjs");require("../types/session.cjs");const l=require("./gitStatus.cjs"),u=require("./registryWatcher.cjs"),d=require("./serverSpawner.cjs"),f=require("./packageApiProxy.cjs"),p=require("./sessionHub.cjs"),m=require("../types/remoteAccess.cjs"),h=require("../services/remoteGuardPolicy.cjs"),g=require("../services/sessionMigration.cjs"),ee=require("./authRoutes.cjs"),te=require("./settingsRoutes.cjs"),ne=require("./providerAuth.cjs"),re=require("./remoteGuard.cjs"),ie=require("./remoteAccess.cjs"),ae=require("./bundlePublication.cjs"),oe=require("./webPush.cjs"),se=require("./remoteAccessStore.cjs"),ce=require("./remoteRoutes.cjs"),le=require("./tunnelProcess.cjs"),ue=require("./directoryListing.cjs"),de=require("./sessionFiles.cjs"),fe=require("./threadJournals.cjs"),pe=require("./webHubPluginLoader.cjs"),_=require("./webTelemetry.cjs"),me=require("./sessionWebComposition.cjs");let v=require("node:fs");v=e.__toESM(v,1);let y=require("node:path");y=e.__toESM(y,1);let b=require("node:url"),x=require("@agimon-ai/doompi/services"),he=require("node:crypto"),S=require("node:os");S=e.__toESM(S,1);let ge=require("@hono/node-server"),_e=require("@hono/node-ws"),ve=require("@earendil-works/pi-coding-agent"),C=require("@earendil-works/pi-server"),ye=require("@agimon-ai/doompi-config"),be=require("@agimon-ai/doompi/services/syncState"),w=require("@agimon-ai/doompi-web-security"),xe=require("hono"),T=require("hono/cookie"),E=require("hono/body-limit"),D=require("@agimon-ai/doompi-extension-contracts/package-api"),
|
|
2
|
-
`,1)[0]?.trim();return(e.name?.trim()||n||y.default.basename(t)||`untitled`).slice(0,80)}function L(e){return e instanceof Error?e.message:String(e)}function Me(e,t){return`${e}\n${t}`}function Ne(e,t,n,r){return p.createSessionHub({source:u.watchRegistry(e.registryDir,t),spawner:d.createServerSpawner({registryDir:e.registryDir,command:e.spawnCommand,onNotice:t}),readGit:l.readGitStatus,...n,telemetry:r,onNotice:t})}function R(e){return`repo-${(0,he.createHash)(`sha256`).update(e).digest(`base64url`).slice(0,24)}`}function Pe(e){let t=new Map,n=()=>{for(let[e,n]of t)t.set(e,{...n,repository:{...n.repository,active:!1}});for(let n of e.records())try{let e=v.default.realpathSync((0,O.findRepositoryRoot)(n.cwd));t.set(e,{repository:{id:R(e),path:e,name:y.default.basename(e)||e,active:!0},seenAt:Date.now()})}catch{}let n=[...t.entries()].filter(([,e])=>!e.repository.active).sort((e,t)=>t[1].seenAt-e[1].seenAt);for(let[e]of n.slice(12))t.delete(e);return[...t.values()].sort((e,t)=>Number(t.repository.active)-Number(e.repository.active)||t.seenAt-e.seenAt||e.repository.path.localeCompare(t.repository.path)).map(e=>e.repository)};return{list:n,resolve(e){return n().find(t=>t.id===e)?.path}}}function Fe(e,t,n,r,i){let a=[];for(let o of t){let t=`${D.DOOM_API_ROUTE_PREFIX}/${o.basePath}`,s;try{s=o.start({scope:`hub`,onNotice:n,resolveRepository:r,readRepositorySync:i})}catch(e){n(`hub API '${o.basePath}' did not start (${L(e)}); its routes stay unmounted`);continue}a.push(s),e.all(`${t}/*`,async e=>{if(e.req.query(`session`)!==void 0)return e.notFound();let r=new URL(e.req.url);r.pathname=r.pathname.slice(t.length)||`/`;try{return await s.fetch(new Request(r,e.req.raw))}catch(t){return n(`hub API '${o.basePath}' failed on ${r.pathname} (${L(t)})`),e.json({error:`The '${o.basePath}' API failed.`},500)}})}return a}function Ie(e,t,n,r){e.all(`${D.DOOM_API_ROUTE_PREFIX}/*`,async e=>{let i=e.req.query(s.API_SESSION_QUERY_PARAM);if(i===void 0)return e.notFound();let a=t.snapshot().find(e=>e.id===i);if(a===void 0)return e.json({error:`No session ${i}.`},404);if(a.apiSocketPath===void 0)return e.json({error:`Session ${i} serves no package API.`},404);let o=new URL(e.req.url);o.searchParams.delete(s.API_SESSION_QUERY_PARAM);let c=_.readTraceContext(e.req.raw.headers);try{return await r.runInSpan(`web.package_proxy`,{"operation.name":`web.package_proxy`,"http.method":e.req.method},async t=>await f.proxyToSocket({socketPath:a.apiSocketPath,path:`${o.pathname}${o.search}`,method:e.req.method,headers:e.req.raw.headers,body:e.req.raw.body,trace:_.forwardedTraceContext(t,c)}),c)}catch(t){return n(`session ${i} API is unreachable (${L(t)})`),e.json({error:`Session ${i} is not answering.`},502)}})}async function z(e){let l=e.host??`127.0.0.1`,d=e.onNotice??(()=>{}),f=_.createWebTelemetry(),p=se.createRemoteAccessStore({stateDir:e.remoteStateDir,onNotice:d}),b=e=>{try{return v.default.realpathSync((0,O.findRepositoryRoot)(e))}catch{return}},D=e=>{let t=S.default.homedir(),n=(0,O.resolveDoomConfigurationRoot)(e,t);if(n===(0,ye.globalDoomConfigDirectory)(t))return n;try{return v.default.realpathSync(n)}catch{return y.default.resolve(n)}},k=e.compositionDir===void 0?void 0:b(e.compositionDir);if(e.compositionDir!==void 0&&k===void 0)throw Error(`Cockpit composition directory is not inside a repository: ${e.compositionDir}`);let j=(0,ye.globalDoomConfigDirectory)(S.default.homedir()),M=n.createSyncGuard({repoRoot:j,onNotice:d});await M.ensureSynced();let N=async e=>{if(e===j){await M.ensureSynced();return}let t=n.createSyncGuard({repoRoot:e,onNotice:d});try{await t.ensureSynced()}finally{t.close()}},P=async e=>await N(D(e)),L=[...u.readRegistryRecords(e.registryDir,d).map(e=>D(e.cwd)),...k===void 0?[]:[D(k)]];await Promise.all([...new Set(L)].map(async e=>await N(e)));let R={assetsDir:Ae(e.assetsDir,void 0,d),apiDirectory:void 0},z=ae.createPluginBundlePublication(p.directory,d),B=Ne(e,d,{loadChannels:async e=>{let t=D(e.cwd);await N(t);let n=(0,x.readSyncRegistration)(t);return n?.webDirectory===null||n?.webDirectory===void 0?[]:await pe.loadHubChannels(n.webDirectory,d)},webComposition:(e,t)=>{let n=me.resolveSessionWebArtifacts(D(e.cwd));if(n===void 0)return;let r=z.publish(n.id,n.pluginsDir);if(r===void 0)return;let i=r.signed.manifest.revision,a=`${A}${n.id}/${String(i)}`;return{id:n.id,revision:i,manifestUrl:`${a}/manifest`,rawAssetBaseUrl:`${a}/assets`,verifiedAssetBaseUrl:`/verified-plugins/${n.id}/${String(i)}`,entryPath:n.entryPath,stylePaths:n.stylePaths,channels:[...t]}}},f),V=fe.createThreadJournals({resolve:(e,t)=>B.threadJournal(e,t),onNotice:d}),H=new Set,Le=(e,t)=>{for(let n of H)t&&!n.local||n.post(e)},U=new xe.Hono,W=(0,_e.createNodeWebSocket)({app:U}),Re,G=Oe(),K=ae.createBundlePublication({assetsDir:()=>R.assetsDir,stateDir:p.directory,onNotice:d}),q;le.reapStaleTunnel(p.directory,d);let ze=e.onHandover===void 0?void 0:t=>{let n=g.planSessionMigration(B.snapshot().map(e=>({id:e.id,cwd:e.cwd,...e.name===void 0?{}:{name:e.name}})),t.sandbox.workspaces);for(let e of g.describeStranded(n.stranded))d(e);for(let e of n.migrate){let t=B.stop(e.id);t.ok||d(`could not stop ${e.name??e.id} before the move: ${t.error}`)}e.onHandover?.({settings:t,sessions:n.migrate})},J=ie.createRemoteAccess({store:p,launchTunnel:e.remoteAccess?.launchTunnel??le.createTunnelLauncher({stateDir:p.directory,...e.cloudflaredPath===void 0?{}:{cloudflaredPath:e.cloudflaredPath},onNotice:d,onExit:e=>{d(`remote access: ${e}`),J.disable()}}),bindListener:async()=>await new Promise((e,t)=>{let n=(0,ge.serve)({fetch:U.fetch,port:0,hostname:`127.0.0.1`,serverOptions:{maxHeaderSize:16384,headersTimeout:5e3,requestTimeout:1e4}},t=>{W.injectWebSocket(n),e({port:t.port,close:async()=>await new Promise(e=>{n.closeAllConnections?.(),n.close(()=>e())})})}),r=n;r.maxConnections=64,r.maxRequestsPerSocket=100,n.once(`error`,t)}),bundleTrust:()=>K.trust(),onDeviceDropped:e=>q?.remove(e),onNotice:d,...ze===void 0?{}:{requestHandover:ze},contained:(0,Ce.insideSandbox)(process.env),broadcastLocal:e=>Le(e,!0),broadcastAll:e=>Le(e,!1),...e.remoteAccess?.now===void 0?{}:{now:e.remoteAccess.now}});q=oe.createLiveWebPush({stateDir:p.directory,isConnected:e=>J.isDeviceConnected(e),onNotice:d});let Be=B.onEvent(e=>{e.kind===`frame`&&c.parseDoomNotificationEntry(e.frame)!==void 0&&q?.notify()}),Y=re.createRemoteGuard({loopbackPort:()=>Re,tunnelPolicy:()=>J.tunnelPolicy(),authorize:e=>J.authorize((0,T.getCookie)(e,m.DEVICE_COOKIE,`host`)),trustedDevice:e=>e.env?.sealedDeviceId,channelReady:(e,t)=>J.channelFor(e,t)!==void 0,stepUp:{required:e=>J.stepUpRequired(e),verify:async(e,t,n)=>{if(typeof n!=`object`||!n)return!1;let r=n.ceremonyId,i=n.response;if(typeof r!=`string`)return!1;let a=e.env?.sealedDeviceId??J.authorize((0,T.getCookie)(e,`doompi_device`,`host`)),o=a===void 0?`local`:`device:${a}`;return await J.passkeys().finishStepUp(r,o,t,i)}},extraOrigins:h.allowedOriginsFromEnv(process.env.DOOMPI_WEB_ALLOW_ORIGIN)});U.use(`*`,Y.middleware),U.use(`*`,async(e,t)=>{let n=new URL(e.req.url).pathname;if(n===m.REMOTE_HTTP_ROUTE)return t();let r=_.requestOperation(n);if(r===void 0)return t();let i=performance.now();return await f.runInSpan(r,{"operation.name":r,"http.method":e.req.method},async()=>{await t(),await f.recordEvent(`web.api.request`,{"operation.name":r,"http.method":e.req.method,"http.status_code":e.res.status,duration_ms:Math.max(0,Math.round(performance.now()-i))})},_.readTraceContext(e.req.raw.headers))}),U.use(`*`,async(e,t)=>{if(Y.listenerOf(e)===`local`)return t();let n=Number(e.req.header(`content-length`));return Number.isFinite(n)&&n>we?e.json({error:`The tunnel request body is too large.`},413):t()}),ce.registerRemoteRoutes(U,{remote:J,listenerOf:e=>Y.listenerOf(e)});let Ve=(0,E.bodyLimit)({maxSize:we,onError:e=>e.json({error:`The tunnel request body is too large.`},413)});U.use(`*`,async(e,t)=>Y.listenerOf(e)===`local`?t():await Ve(e,t));let He=(0,E.bodyLimit)({maxSize:32768,onError:e=>e.json({error:`The telemetry batch is too large.`},413)}),Ue=_.createBrowserTelemetryRateLimit();U.post(_.WEB_TELEMETRY_ROUTE,He,async e=>{if(!Ue())return e.json({error:`Too many telemetry batches.`},429);let t;try{t=await e.req.json()}catch{return e.json({error:`The telemetry batch must be JSON.`},400)}let n=_.parseBrowserTelemetryBatch(t);if(n===void 0)return e.json({error:`The telemetry batch is invalid.`},400);for(let e of n){if(_.isBrowserErrorEvent(e)){await f.recordError(_.BROWSER_ERROR_EVENT,_.createBrowserError(e),{"browser.source":e.source,...e.session_id===void 0?{}:{"session.id":e.session_id},"failure.kind":`browser`},{includeException:!0});continue}await f.recordEvent(e.name,{...e.duration_ms===void 0?{}:{duration_ms:e.duration_ms},...e.count===void 0?{}:{count:e.count}})}return e.body(null,204)}),U.post(m.REMOTE_HTTP_ROUTE,async e=>{let t=J.authorize((0,T.getCookie)(e,m.DEVICE_COOKIE,`host`));if(t===void 0)return e.json({error:`This device is not paired.`},401);let n=J.channelFor(t,`http`);if(n===void 0)return e.json({error:`This device has no sealed HTTP channel.`},401);let r;try{r=await e.req.json()}catch{return e.json({error:`The sealed request envelope was malformed.`},400)}let i=n.open(r);if(!i.ok)return e.json({error:`The sealed request was refused: ${i.failure}.`},400);let a;try{a=JSON.parse(new TextDecoder().decode(i.plaintext))}catch{return e.json({error:`The sealed HTTP request was malformed.`},400)}let o=Te(a),s=o===void 0?void 0:Ee(o,e),c=o===void 0?void 0:De(o.body);if(o===void 0||s===void 0||c===void 0)return e.json({error:`The sealed HTTP request was invalid.`},400);let l=new URL(o.target,new URL(e.req.url).origin),u=await U.request(l,{method:o.method,headers:s,...o.method===`GET`||o.method===`HEAD`?{}:{body:Uint8Array.from(c).buffer}},{...e.env,sealedDeviceId:t}),d=Buffer.from(await u.arrayBuffer()),f=n.seal(new TextEncoder().encode(JSON.stringify({v:1,status:u.status,headers:Array.from(u.headers.entries()),body:d.toString(`base64`)})));return f.ok?e.json(f.envelope):e.json({error:`The sealed response failed: ${f.failure}.`},503)});let We=(0,E.bodyLimit)({maxSize:8192,onError:e=>e.json({error:`The Push subscription is too large.`},413)}),X=e=>e.env?.sealedDeviceId;U.get(m.REMOTE_PUSH_KEY_ROUTE,e=>X(e)===void 0?e.json({error:`A sealed paired device is required.`},401):e.json({publicKey:q?.publicKey()},200,{"Cache-Control":`no-store`})),U.post(m.REMOTE_PUSH_ROUTE,We,async e=>{let t=X(e);if(t===void 0)return e.json({error:`A sealed paired device is required.`},401);let n;try{n=await e.req.json()}catch{return e.json({error:`The Push subscription must be JSON.`},400)}return q?.subscribe(t,n)===!0?e.body(null,204):e.json({error:`The Push subscription is invalid.`},400)}),U.delete(m.REMOTE_PUSH_ROUTE,e=>{let t=X(e);return t===void 0?e.json({error:`A sealed paired device is required.`},401):(q?.remove(t),e.body(null,204))});let Ge=r.createPiWebSocketListener({onError:e=>d(`protocol: ${e.message}`)}),Ke=r.createPiWebSocketListener({onError:e=>d(`protocol: ${e.message}`)}),qe=t.createPiHubService({records:()=>B.records(),spawn:e=>B.create(e),onNotice:d}),Je={...qe,createSession:async()=>{throw new C.PiServerError(`not_implemented`,`Remote protocol clients cannot create sessions`)}},Z=new C.PiServer(qe,{listeners:[Ge],onError:e=>d(`protocol: ${e.message}`)}),Ye=new C.PiServer(Je,{listeners:[Ke],onError:e=>d(`protocol: ${e.message}`)});await Promise.all([Z.start(),Ye.start()]);let Q=ne.createProviderAuth({runtime:e.authRuntime,onNotice:d});ee.registerAuthRoutes(U,Q);let Xe=Pe(B),Ze=()=>Xe.list(),Qe=e=>Xe.resolve(e),$e=e=>{let t=Qe(e);if(t===void 0)return;let n=(0,x.readSyncDrift)({repoRoot:t}),r;try{r=(0,x.readSyncRegistration)(t)?(0,be.readSyncState)(t):void 0}catch{r=void 0}return{fresh:n.fresh,reasons:[...n.reasons],...r===void 0?{}:{mcpProjection:r.fileState.mcpProjection}}};te.registerSettingsRoutes(U,{repositories:Ze,models:()=>Q.listModels()});let et=R.apiDirectory,$=Fe(U,et===void 0&&!process.env[Se.PACKAGE_API_DIR_ENV]?[]:await(0,Se.loadPackageApis)(`hub`,{apiDirectory:et,onNotice:d}),d,Qe,$e);Ie(U,B,d,f),U.get(`/api/health`,e=>e.json({ok:!0,role:`hub`,protocol:2,sessions:B.snapshot().length,pid:process.pid,version:ke()})),U.post(s.SESSIONS_API_ROUTE,async e=>{let t;try{t=await e.req.json()}catch{return e.json({error:`The request body must be JSON.`},400)}if(!I(t)||typeof t.cwd!=`string`||t.cwd===``)return e.json({error:`A cwd string is required.`},400);let n;try{n=v.default.statSync(t.cwd)}catch{return e.json({error:`No such directory: ${t.cwd}`},400)}if(!y.default.isAbsolute(t.cwd)||!n.isDirectory())return e.json({error:`The working directory must be an absolute path to a directory, received "${t.cwd}".`},400);let r=typeof t.name==`string`&&t.name!==``?t.name:void 0;await P(t.cwd);let i=await B.create({cwd:t.cwd,name:r,trace:_.readTraceContext(e.req.raw.headers)});return i.ok?e.json({sessionId:i.sessionId},201):e.json({error:i.error},i.code===`invalid_request`?400:502)}),U.post(`${s.SESSIONS_API_ROUTE}/:sessionId/restart`,async e=>{let t=e.req.param(`sessionId`),n=B.snapshot().find(e=>e.id===t);n!==void 0&&await P(n.cwd);let r=await B.restart(t,_.readTraceContext(e.req.raw.headers));return r.ok?e.json({sessionId:r.sessionId},202):e.json({error:r.error},r.code===`invalid_request`?404:502)}),U.get(`${s.SESSIONS_API_ROUTE}/:sessionId/history`,async e=>{let t=e.req.param(`sessionId`),n=B.snapshot().find(e=>e.id===t);if(!n)return e.json({error:`Unknown session.`},404);let r=await ve.SessionManager.list(n.cwd);return e.json({sessions:r.map(e=>({id:e.id,...e.name===void 0?{}:{name:e.name},firstMessage:e.firstMessage,createdAt:e.created.toISOString(),updatedAt:e.modified.toISOString(),messageCount:e.messageCount}))})}),U.post(`${s.SESSIONS_API_ROUTE}/:sessionId/resume`,async e=>{let t=e.req.param(`sessionId`),n=B.snapshot().find(e=>e.id===t);if(!n)return e.json({error:`Unknown session.`},404);let r;try{r=await e.req.json()}catch{return e.json({error:`The request body must be JSON.`},400)}if(!I(r)||typeof r.targetSessionId!=`string`||r.targetSessionId===``)return e.json({error:`A targetSessionId string is required.`},400);let i=(await ve.SessionManager.list(n.cwd)).find(e=>e.id===r.targetSessionId);if(!i)return e.json({error:`That Pi thread does not belong to this workspace.`},404);await P(n.cwd);let a=await B.resume(t,{sessionId:i.id,name:je(i,n.cwd)},_.readTraceContext(e.req.raw.headers));return a.ok?e.json({sessionId:a.sessionId},202):e.json({error:a.error},a.code===`invalid_request`?409:502)}),U.delete(`${s.SESSIONS_API_ROUTE}/:sessionId`,e=>{let t=e.req.param(`sessionId`),n=B.stop(t);return n.ok?e.json({sessionId:t},202):e.json({error:n.error},n.code===`unknown`?404:n.code===`self`?409:502)}),U.get(`/api/sessions/:sessionId/files`,async e=>{let t=e.req.param(`sessionId`),n=B.snapshot().find(e=>e.id===t);if(!n)return e.json({error:`Unknown session.`},404);let r=e.req.query(`q`)??``,i=await de.listSessionFiles(n.cwd,r,20);return e.json({files:i})});let tt=t=>{if(!(Y.listenerOf(t)===`local`||(0,Ce.insideSandbox)(process.env)))return e.browseRoot??process.cwd()};return U.get(s.DIRECTORIES_API_ROUTE,async e=>{let t=tt(e),n=await ue.suggestDirectories(e.req.query(`q`)??``,{limit:12,...t===void 0?{}:{root:t}});return e.json({directories:n})}),U.get(i.SESSION_FILE_ROUTE,async e=>{let t=e.req.param(`sessionId`),n=B.snapshot().find(e=>e.id===t);if(!n)return e.json({error:`Unknown session.`},404);let r=e.req.query(`path`)??``,o=await de.readSessionFile(n.cwd,r,i.MAX_SESSION_FILE_BYTES);return o.status===`forbidden`?e.json({error:`The path leaves the session directory.`},403):o.status===`not-found`?e.json({error:`No such file.`},404):o.status===`too-large`?e.json({error:`The file is too large to preview.`},413):e.body(new Uint8Array(o.body),200,a.sessionFileHeaders(r))}),U.get(m.SESSION_SOCKET_ROUTE,W.upgradeWebSocket(e=>{let t=Y.listenerOf(e)===`local`,n=t?void 0:J.authorize((0,T.getCookie)(e,m.DEVICE_COOKIE,`host`)),r=n===void 0?void 0:J.channelFor(n,`session`),i=new Set,a=(0,he.randomUUID)(),o=new Map,l,u,f,p,h=e=>{for(let[t,n]of o)(e===void 0||n.sessionId===e)&&(o.delete(t),V.unsubscribe(n.sessionId,n.threadId))};return{onOpen(e,m){if(!t&&r===void 0){m.close(1008,`sealed session channel required`);return}let g=e=>{let n=JSON.stringify(e),i=n;if(!t){if(r===void 0)return;let e=r.seal(new TextEncoder().encode(n));if(!e.ok){m.close(1008,`sealed session channel failed`);return}i=JSON.stringify(e.envelope)}try{m.send(i)}catch{}};f={post:g,local:t},H.add(f),n!==void 0&&(p=J.trackSocket(n,(e,t)=>m.close(e,t))),g(s.hubHello(B.channelTypes())),g({type:s.SESSIONS_SNAPSHOT_TYPE,sessions:B.snapshot()}),l=B.onEvent(e=>{e.kind===`upsert`?g({type:s.SESSION_UPSERT_TYPE,session:e.session}):e.kind===`removed`?(i.delete(e.sessionId),h(e.sessionId),g({type:s.SESSION_REMOVED_TYPE,sessionId:e.sessionId})):e.kind===`channel`?(e.connectionId===a||e.connectionId===void 0&&i.has(e.sessionId))&&g({type:e.frameType,sessionId:e.sessionId,payload:e.payload}):(c.parseDoomNotificationEntry(e.frame)!==void 0||i.has(e.sessionId))&&g(s.sessionFrameEnvelope(e.sessionId,e.frame))}),u=V.onFrame(e=>{o.has(Me(e.sessionId,e.threadId))&&g(s.threadFrameEnvelope(e.sessionId,e.threadId,e.frame))}),d(`browser attached`)},onMessage(e){if(typeof e.data!=`string`)return;let n;try{n=JSON.parse(e.data)}catch{return}if(!t){if(r===void 0)return;let e=r.open(n);if(!e.ok)return;try{n=JSON.parse(new TextDecoder().decode(e.plaintext))}catch{return}}if(!I(n)||typeof n.sessionId!=`string`)return;let c=n.sessionId;if(typeof n.type==`string`&&B.channelTypes().includes(n.type)&&(i.has(c)||B.channelReceivesWithoutSubscription(c,n.type))){B.receiveChannel(c,n.type,n.payload,a);return}if(n.type===`subscribe`){let e=B.backlog(c);if(!e)return;i.add(c),f?.post(e);for(let e of B.channelFrames(c))f?.post(e);return}if(n.type===`unsubscribe`){i.delete(c);return}if(n.type===`history_request`){let e=B.history(c,{...typeof n.before==`string`?{before:n.before}:{},...typeof n.limit==`number`?{limit:n.limit}:{}});if(!e)return;f?.post(e);return}if(n.type===`subscribe_thread`||n.type===`unsubscribe_thread`){if(typeof n.threadId!=`string`)return;let e=n.threadId,t=Me(c,e);if(n.type===`unsubscribe_thread`){o.delete(t)&&V.unsubscribe(c,e);return}if(o.has(t)||B.backlog(c)===void 0)return;o.set(t,{sessionId:c,threadId:e}),f?.post(s.threadBacklog(c,e,V.subscribe(c,e)));return}if(n.type===`session_command`&&I(n.frame)){if(n.frame.type===`attach`)return;B.command(c,n.frame)}},onClose(){B.disconnectChannels(a),f&&H.delete(f),f=void 0,p?.(),p=void 0,l?.(),l=void 0,u?.(),u=void 0,i.clear(),h(),d(`browser detached`)}}})),U.get(m.PROTOCOL_SOCKET_ROUTE,W.upgradeWebSocket(e=>{let t=Y.listenerOf(e)===`local`,n=t?void 0:J.authorize((0,T.getCookie)(e,m.DEVICE_COOKIE,`host`)),r=n===void 0?void 0:J.channelFor(n,`protocol`),i,a;return{onOpen(e,o){if(!t&&r===void 0){o.close(1008,`sealed protocol channel required`);return}n!==void 0&&(a=J.trackSocket(n,(e,t)=>o.close(e,t))),i=(t?Ge:Ke).accept({send:e=>{if(t){o.send(e);return}if(r===void 0)return;let n=e instanceof Uint8Array?e:new Uint8Array(e),i=r.seal(n);if(!i.ok){o.close(1008,`sealed protocol channel failed`);return}o.send(new TextEncoder().encode(JSON.stringify(i.envelope)))},close:()=>o.close(),get readyState(){return o.readyState}})},async onMessage(e){let n=e.data;if(typeof n==`string`)return;let a=n instanceof Blob?new Uint8Array(await n.arrayBuffer()):(n instanceof ArrayBuffer,new Uint8Array(n));if(t){i?.onData(a);return}if(r===void 0)return;let o;try{o=JSON.parse(new TextDecoder().decode(a))}catch{return}let s=r.open(o);s.ok&&i?.onData(s.plaintext)},onClose(){a?.(),a=void 0,i?.onClose(),i=void 0},onError(e){i?.onError(e instanceof Error?e:Error(`The protocol socket failed`)),i=void 0}}})),U.get(`/manifest.webmanifest`,e=>{let t=F(y.default.join(G,`manifest.webmanifest`));return t===void 0?e.text(`The PWA manifest is unavailable.`,404):e.body(new Uint8Array(t),200,{"Cache-Control":`no-store`,"Content-Type":`application/manifest+json; charset=utf-8`})}),U.get(`/sw.js`,e=>{let t=F(y.default.join(G,`sw.js`));return t===void 0?e.text(`The trusted service worker is unavailable.`,404):e.body(new Uint8Array(t),200,{"Cache-Control":`no-cache`,"Content-Type":`text/javascript; charset=utf-8`,"Service-Worker-Allowed":`/`})}),U.get(`/pwa/*`,e=>{let t=new URL(e.req.url).pathname.slice(5),n=o.resolveAssetPath(G,`/${t}`),r=n===void 0?void 0:F(n);return n===void 0||r===void 0?e.text(`PWA asset not found.`,404):e.body(new Uint8Array(r),200,{"Cache-Control":`no-store`,"Content-Type":o.contentTypeFor(n),"X-Content-Type-Options":`nosniff`})}),U.get(`${A}*`,e=>{let t=new URL(e.req.url).pathname,n=/^\/api\/web-plugins\/([a-f0-9]{64})\/([1-9][0-9]*)\/(manifest|assets(\/.*))$/u.exec(t),r=n===null?void 0:Number(n[2]),i=n===null||!Number.isSafeInteger(r)?void 0:z.get(n[1]??``,r);if(n===null||i===void 0)return e.text(`That signed plugin composition is unavailable.`,404);if(n[3]===`manifest`)return e.json(i.signed,200,{"Cache-Control":`no-store`});let a=(0,w.assetFor)(i.signed.manifest,n[4]??``),s=a===void 0?void 0:o.resolveAssetPath(i.assetsDir,a.path),c=s===void 0?void 0:F(s);return a===void 0||s===void 0||c===void 0?e.text(`Plugin composition asset not found.`,404):e.body(new Uint8Array(c),200,{"Cache-Control":`no-store`,"Content-Length":String(c.byteLength),"Content-Type":a.contentType,"X-Content-Type-Options":`nosniff`})}),U.get(w.BUNDLE_MANIFEST_ROUTE,e=>{let t=K.current();return t===void 0?e.json({error:`No signed cockpit bundle is available.`},503):e.json(t.signed,200,{"Cache-Control":`no-store`})}),U.get(`/bundle-assets/*`,e=>{let t=new URL(e.req.url).pathname,n=/^\/bundle-assets\/([1-9][0-9]*)(\/.*)$/u.exec(t),r=n===null?void 0:Number(n[1]),i=K.current();if(n===null||!Number.isSafeInteger(r)||i===void 0||i.signed.manifest.revision!==r)return e.text(`That signed bundle revision is unavailable.`,404);let a=(0,w.assetFor)(i.signed.manifest,n[2]??``),s=a===void 0?void 0:o.resolveAssetPath(i.assetsDir,a.path),c=s===void 0?void 0:F(s);return a===void 0||s===void 0||c===void 0?e.text(`Bundle asset not found.`,404):e.body(new Uint8Array(c),200,{"Cache-Control":`no-store`,"Content-Length":String(c.byteLength),"Content-Type":a.contentType,"X-Content-Type-Options":`nosniff`})}),U.get(`/`,e=>e.redirect(m.PAIRING_PAGE_ROUTE)),U.get(`*`,e=>{let t=new URL(e.req.url).pathname,n=e.req.header(`accept`)?.includes(`text/html`)===!0;return!t.startsWith(`/api/`)&&n?e.redirect(`/`):e.text(`Not found.`,404)}),M.watch(()=>{for(let e of B.records())D(e.cwd)===j&&B.reloadChannels(e.id)}),new Promise((t,n)=>{let r=(0,ge.serve)({fetch:U.fetch,port:e.port,hostname:l},e=>{Re=e.port,W.injectWebSocket(r);let n=`http://${l}:${e.port}`;d(`cockpit on ${n}`);let i,a=async()=>{await J.close(),await new Promise(e=>{V.close(),M.close(),Z.close(),Ye.close(),Be(),q?.close(),B.close(),Q.close();for(let e of $)e.close();z.close();for(let e of W.wss.clients)e.terminate();W.wss.close(),r.closeAllConnections?.(),r.close(()=>e())}),await _.shutdownWebTelemetry(f)};t({url:n,port:e.port,close:()=>i??=a()})});r.once(`error`,e=>{M.close(),V.close(),Be(),q?.close(),B.close(),Q.close(),J.close();for(let e of $)e.close();z.close(),f.shutdown(),n(e)})})}exports.createSettingsRepositoryRegistry=Pe,exports.packagedVersion=ke,exports.serveWeb=z;
|
|
1
|
+
const e=require("../../_virtual/_rolldown/runtime.cjs"),t=require("./piHubService.cjs"),n=require("./syncGuard.cjs"),r=require("./piWebSocketListener.cjs"),i=require("../types/media.cjs"),a=require("../services/fileMedia.cjs"),o=require("../services/staticAssets.cjs"),s=require("../types/hub.cjs"),c=require("../types/notification.cjs");require("../types/session.cjs");const l=require("./gitStatus.cjs"),u=require("./registryWatcher.cjs"),d=require("./serverSpawner.cjs"),f=require("./packageApiProxy.cjs"),p=require("./sessionHub.cjs"),m=require("../types/remoteAccess.cjs"),h=require("../services/remoteGuardPolicy.cjs"),g=require("../services/sessionMigration.cjs"),ee=require("./authRoutes.cjs"),te=require("./settingsRoutes.cjs"),ne=require("./providerAuth.cjs"),re=require("./remoteGuard.cjs"),ie=require("./remoteAccess.cjs"),ae=require("./bundlePublication.cjs"),oe=require("./webPush.cjs"),se=require("./remoteAccessStore.cjs"),ce=require("./remoteRoutes.cjs"),le=require("./tunnelProcess.cjs"),ue=require("./directoryListing.cjs"),de=require("./sessionFiles.cjs"),fe=require("./threadJournals.cjs"),pe=require("./webHubPluginLoader.cjs"),_=require("./webTelemetry.cjs"),me=require("./sessionWebComposition.cjs");let v=require("node:fs");v=e.__toESM(v,1);let y=require("node:path");y=e.__toESM(y,1);let b=require("node:url"),x=require("@agimon-ai/doompi/services"),he=require("node:crypto"),S=require("node:os");S=e.__toESM(S,1);let ge=require("@hono/node-server"),_e=require("@hono/node-ws"),ve=require("@earendil-works/pi-coding-agent"),C=require("@earendil-works/pi-server"),ye=require("@agimon-ai/doompi-config"),be=require("@agimon-ai/doompi/services/syncState"),w=require("@agimon-ai/doompi-web-security"),xe=require("hono"),T=require("hono/cookie"),E=require("hono/body-limit"),D=require("@agimon-ai/doompi-extension-contracts/package-api"),O=require("@agimon-ai/doompi-extension-contracts/package-api-loader"),Se=require("@agimon-ai/doompi-extension-contracts/sandbox-harness"),k=require("@agimon-ai/doompi/utils/repository");const A=`DOOMPI_WEB_PACKAGE_ROOT`,Ce=`/api/web-plugins/`,we=8388608,j=new Set([`GET`,`HEAD`,`POST`,`PUT`,`PATCH`,`DELETE`]),M=new Set([`connection`,`content-length`,`cookie`,`forwarded`,`host`,`origin`,`transfer-encoding`,`upgrade`,`x-forwarded-for`,`x-forwarded-host`,`x-forwarded-proto`]);function Te(e){if(typeof e!=`object`||!e)return;let t=e;if(t.v!==1||typeof t.method!=`string`||!j.has(t.method)||typeof t.target!=`string`||!t.target.startsWith(`/`)||t.target.startsWith(`//`)||t.target.includes(`#`)||!Array.isArray(t.headers)||!t.headers.every(e=>Array.isArray(e)&&e.length===2&&e.every(e=>typeof e==`string`))||t.body!==void 0&&typeof t.body!=`string`)return;let n=new URL(t.target,`http://sealed.doompi.invalid`);if(n.pathname!==m.REMOTE_HTTP_ROUTE&&n.pathname!==m.REMOTE_CHANNEL_ROUTE)return t}function Ee(e,t){try{let n=new Headers;for(let[t,r]of e.headers){let e=t.toLowerCase();M.has(e)||e.startsWith(`sec-`)||n.append(t,r)}for(let e of[`cookie`,`host`,`origin`]){let r=t.req.header(e);r!==void 0&&n.set(e,r)}return n}catch{return}}function De(e){if(e===void 0)return Buffer.alloc(0);if(!/^(?:[A-Za-z\d+/]{4})*(?:[A-Za-z\d+/]{2}==|[A-Za-z\d+/]{3}=)?$/.test(e))return;let t=Buffer.from(e,`base64`);return t.toString(`base64`)===e?t:void 0}function N(e){let t=process.env[A];if(t!==void 0&&t!==``)return y.default.join(t,`dist`,e);let n=y.default.dirname((0,b.fileURLToPath)(require("url").pathToFileURL(__filename).href));for(;;){if(v.default.existsSync(y.default.join(n,`package.json`)))return y.default.join(n,`dist`,e);let t=y.default.dirname(n);if(t===n)throw Error(`doompi-web could not locate its own package root.`);n=t}}function P(){return N(`web`)}function Oe(){return N(`pwa`)}function ke(){let e=process.env[A],t=e!==void 0&&e!==``?e:y.default.dirname((0,b.fileURLToPath)(require("url").pathToFileURL(__filename).href));for(;;){let e=y.default.join(t,`package.json`);if(v.default.existsSync(e))try{let t=JSON.parse(v.default.readFileSync(e,`utf8`)),n=I(t)?t.version:void 0;return typeof n==`string`?n:`unknown`}catch{return`unknown`}let n=y.default.dirname(t);if(n===t)return`unknown`;t=n}}function Ae(e,t,n){if(e!==void 0)return e;let r=process.env.DOOMPI_WEB_DIST;if(r!==void 0&&r!==``)return r;let i=t?.webDirectory;return i!=null&&v.default.existsSync(y.default.join(i,`index.html`))?(n(`serving the synced cockpit bundle from ${i}`),i):P()}function F(e){try{return v.default.statSync(e).isFile()?v.default.readFileSync(e):void 0}catch{return}}function I(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function je(e,t){let n=e.firstMessage.split(`
|
|
2
|
+
`,1)[0]?.trim();return(e.name?.trim()||n||y.default.basename(t)||`untitled`).slice(0,80)}function L(e){return e instanceof Error?e.message:String(e)}function Me(e,t){return`${e}\n${t}`}function Ne(e,t,n,r){return p.createSessionHub({source:u.watchRegistry(e.registryDir,t),spawner:d.createServerSpawner({registryDir:e.registryDir,command:e.spawnCommand,onNotice:t}),readGit:l.readGitStatus,...n,telemetry:r,onNotice:t})}function R(e){return`repo-${(0,he.createHash)(`sha256`).update(e).digest(`base64url`).slice(0,24)}`}function Pe(e){let t=new Map,n=()=>{for(let[e,n]of t)t.set(e,{...n,repository:{...n.repository,active:!1}});for(let n of e.records())try{let e=v.default.realpathSync((0,k.findRepositoryRoot)(n.cwd));t.set(e,{repository:{id:R(e),path:e,name:y.default.basename(e)||e,active:!0},seenAt:Date.now()})}catch{}let n=[...t.entries()].filter(([,e])=>!e.repository.active).sort((e,t)=>t[1].seenAt-e[1].seenAt);for(let[e]of n.slice(12))t.delete(e);return[...t.values()].sort((e,t)=>Number(t.repository.active)-Number(e.repository.active)||t.seenAt-e.seenAt||e.repository.path.localeCompare(t.repository.path)).map(e=>e.repository)};return{list:n,resolve(e){return n().find(t=>t.id===e)?.path}}}function Fe(e,t,n,r,i){let a=[],o=new Map,s=e=>{for(let t of e){if(o.has(t.basePath))continue;let e;try{e=t.start({scope:`hub`,onNotice:n,resolveRepository:r,readRepositorySync:i})}catch(e){n(`hub API '${t.basePath}' did not start (${L(e)}); its routes stay unmounted`);continue}o.set(t.basePath,e),a.push(e)}};return s(t),e.all(`${D.DOOM_API_ROUTE_PREFIX}/:basePath/*`,async(e,t)=>{if(e.req.query(`session`)!==void 0)return t();let r=e.req.param(`basePath`),i=o.get(r);if(i===void 0)return t();let a=`${D.DOOM_API_ROUTE_PREFIX}/${r}`,s=new URL(e.req.url);s.pathname=s.pathname.slice(a.length)||`/`;try{return await i.fetch(new Request(s,e.req.raw))}catch(t){return n(`hub API '${r}' failed on ${s.pathname} (${L(t)})`),e.json({error:`The '${r}' API failed.`},500)}}),{handlers:a,add:s}}function Ie(e,t,n,r){e.all(`${D.DOOM_API_ROUTE_PREFIX}/*`,async e=>{let i=e.req.query(s.API_SESSION_QUERY_PARAM);if(i===void 0)return e.notFound();let a=t.snapshot().find(e=>e.id===i);if(a===void 0)return e.json({error:`No session ${i}.`},404);if(a.apiSocketPath===void 0)return e.json({error:`Session ${i} serves no package API.`},404);let o=new URL(e.req.url);o.searchParams.delete(s.API_SESSION_QUERY_PARAM);let c=_.readTraceContext(e.req.raw.headers);try{return await r.runInSpan(`web.package_proxy`,{"operation.name":`web.package_proxy`,"http.method":e.req.method},async t=>await f.proxyToSocket({socketPath:a.apiSocketPath,path:`${o.pathname}${o.search}`,method:e.req.method,headers:e.req.raw.headers,body:e.req.raw.body,trace:_.forwardedTraceContext(t,c)}),c)}catch(t){return n(`session ${i} API is unreachable (${L(t)})`),e.json({error:`Session ${i} is not answering.`},502)}})}async function z(e){let l=e.host??`127.0.0.1`,d=e.onNotice??(()=>{}),f=_.createWebTelemetry(),p=se.createRemoteAccessStore({stateDir:e.remoteStateDir,onNotice:d}),b=e=>{try{return v.default.realpathSync((0,k.findRepositoryRoot)(e))}catch{return}},D=e=>{let t=S.default.homedir(),n=(0,k.resolveDoomConfigurationRoot)(e,t);if(n===(0,ye.globalDoomConfigDirectory)(t))return n;try{return v.default.realpathSync(n)}catch{return y.default.resolve(n)}},A=e.compositionDir===void 0?void 0:b(e.compositionDir);if(e.compositionDir!==void 0&&A===void 0)throw Error(`Cockpit composition directory is not inside a repository: ${e.compositionDir}`);let j=(0,ye.globalDoomConfigDirectory)(S.default.homedir()),M=n.createSyncGuard({repoRoot:j,onNotice:d}),N=async e=>{},P=async e=>{if(e===j)await M.ensureSynced();else{let t=n.createSyncGuard({repoRoot:e,onNotice:d});try{await t.ensureSynced()}finally{t.close()}}await N(e)},R=async e=>{try{await P(e)}catch(t){d(`WARNING: startup sync failed for ${e}; continuing to serve the cockpit (${L(t)})`)}};await R(j);let z=async e=>await P(D(e)),Le=[...u.readRegistryRecords(e.registryDir,d).map(e=>D(e.cwd)),...A===void 0?[]:[D(A)]];await Promise.all([...new Set(Le)].map(R));let Re={assetsDir:Ae(e.assetsDir,void 0,d),apiDirectory:void 0},B=ae.createPluginBundlePublication(p.directory,d),V=Ne(e,d,{loadChannels:async e=>{let t=D(e.cwd);await P(t);let n=(0,x.readSyncRegistration)(t);return n?.webDirectory===null||n?.webDirectory===void 0?[]:await pe.loadHubChannels(n.webDirectory,d)},webComposition:(e,t)=>{let n=me.resolveSessionWebArtifacts(D(e.cwd));if(n===void 0)return;let r=B.publish(n.id,n.pluginsDir);if(r===void 0)return;let i=r.signed.manifest.revision,a=`${Ce}${n.id}/${String(i)}`;return{id:n.id,revision:i,manifestUrl:`${a}/manifest`,rawAssetBaseUrl:`${a}/assets`,verifiedAssetBaseUrl:`/verified-plugins/${n.id}/${String(i)}`,entryPath:n.entryPath,stylePaths:n.stylePaths,channels:[...t]}}},f),H=fe.createThreadJournals({resolve:(e,t)=>V.threadJournal(e,t),onNotice:d}),U=new Set,ze=(e,t)=>{for(let n of U)t&&!n.local||n.post(e)},W=new xe.Hono,G=(0,_e.createNodeWebSocket)({app:W}),Be,K=Oe(),q=ae.createBundlePublication({assetsDir:()=>Re.assetsDir,stateDir:p.directory,onNotice:d}),J;le.reapStaleTunnel(p.directory,d);let Ve=e.onHandover===void 0?void 0:t=>{let n=g.planSessionMigration(V.snapshot().map(e=>({id:e.id,cwd:e.cwd,...e.name===void 0?{}:{name:e.name}})),t.sandbox.workspaces);for(let e of g.describeStranded(n.stranded))d(e);for(let e of n.migrate){let t=V.stop(e.id);t.ok||d(`could not stop ${e.name??e.id} before the move: ${t.error}`)}e.onHandover?.({settings:t,sessions:n.migrate})},Y=ie.createRemoteAccess({store:p,launchTunnel:e.remoteAccess?.launchTunnel??le.createTunnelLauncher({stateDir:p.directory,...e.cloudflaredPath===void 0?{}:{cloudflaredPath:e.cloudflaredPath},onNotice:d,onExit:e=>{d(`remote access: ${e}`),Y.disable()}}),bindListener:async()=>await new Promise((e,t)=>{let n=(0,ge.serve)({fetch:W.fetch,port:0,hostname:`127.0.0.1`,serverOptions:{maxHeaderSize:16384,headersTimeout:5e3,requestTimeout:1e4}},t=>{G.injectWebSocket(n),e({port:t.port,close:async()=>await new Promise(e=>{n.closeAllConnections?.(),n.close(()=>e())})})}),r=n;r.maxConnections=64,r.maxRequestsPerSocket=100,n.once(`error`,t)}),bundleTrust:()=>q.trust(),onDeviceDropped:e=>J?.remove(e),onNotice:d,...Ve===void 0?{}:{requestHandover:Ve},contained:(0,Se.insideSandbox)(process.env),broadcastLocal:e=>ze(e,!0),broadcastAll:e=>ze(e,!1),...e.remoteAccess?.now===void 0?{}:{now:e.remoteAccess.now}});J=oe.createLiveWebPush({stateDir:p.directory,isConnected:e=>Y.isDeviceConnected(e),onNotice:d});let He=V.onEvent(e=>{e.kind===`frame`&&c.parseDoomNotificationEntry(e.frame)!==void 0&&J?.notify()}),X=re.createRemoteGuard({loopbackPort:()=>Be,tunnelPolicy:()=>Y.tunnelPolicy(),authorize:e=>Y.authorize((0,T.getCookie)(e,m.DEVICE_COOKIE,`host`)),trustedDevice:e=>e.env?.sealedDeviceId,channelReady:(e,t)=>Y.channelFor(e,t)!==void 0,stepUp:{required:e=>Y.stepUpRequired(e),verify:async(e,t,n)=>{if(typeof n!=`object`||!n)return!1;let r=n.ceremonyId,i=n.response;if(typeof r!=`string`)return!1;let a=e.env?.sealedDeviceId??Y.authorize((0,T.getCookie)(e,`doompi_device`,`host`)),o=a===void 0?`local`:`device:${a}`;return await Y.passkeys().finishStepUp(r,o,t,i)}},extraOrigins:h.allowedOriginsFromEnv(process.env.DOOMPI_WEB_ALLOW_ORIGIN)});W.use(`*`,X.middleware),W.use(`*`,async(e,t)=>{let n=new URL(e.req.url).pathname;if(n===m.REMOTE_HTTP_ROUTE)return t();let r=_.requestOperation(n);if(r===void 0)return t();let i=performance.now();return await f.runInSpan(r,{"operation.name":r,"http.method":e.req.method},async()=>{await t(),await f.recordEvent(`web.api.request`,{"operation.name":r,"http.method":e.req.method,"http.status_code":e.res.status,duration_ms:Math.max(0,Math.round(performance.now()-i))})},_.readTraceContext(e.req.raw.headers))}),W.use(`*`,async(e,t)=>{if(X.listenerOf(e)===`local`)return t();let n=Number(e.req.header(`content-length`));return Number.isFinite(n)&&n>we?e.json({error:`The tunnel request body is too large.`},413):t()}),ce.registerRemoteRoutes(W,{remote:Y,listenerOf:e=>X.listenerOf(e)});let Ue=(0,E.bodyLimit)({maxSize:we,onError:e=>e.json({error:`The tunnel request body is too large.`},413)});W.use(`*`,async(e,t)=>X.listenerOf(e)===`local`?t():await Ue(e,t));let We=(0,E.bodyLimit)({maxSize:32768,onError:e=>e.json({error:`The telemetry batch is too large.`},413)}),Ge=_.createBrowserTelemetryRateLimit();W.post(_.WEB_TELEMETRY_ROUTE,We,async e=>{if(!Ge())return e.json({error:`Too many telemetry batches.`},429);let t;try{t=await e.req.json()}catch{return e.json({error:`The telemetry batch must be JSON.`},400)}let n=_.parseBrowserTelemetryBatch(t);if(n===void 0)return e.json({error:`The telemetry batch is invalid.`},400);for(let e of n){if(_.isBrowserErrorEvent(e)){await f.recordError(_.BROWSER_ERROR_EVENT,_.createBrowserError(e),{"browser.source":e.source,...e.session_id===void 0?{}:{"session.id":e.session_id},"failure.kind":`browser`},{includeException:!0});continue}await f.recordEvent(e.name,{...e.duration_ms===void 0?{}:{duration_ms:e.duration_ms},...e.count===void 0?{}:{count:e.count}})}return e.body(null,204)}),W.post(m.REMOTE_HTTP_ROUTE,async e=>{let t=Y.authorize((0,T.getCookie)(e,m.DEVICE_COOKIE,`host`));if(t===void 0)return e.json({error:`This device is not paired.`},401);let n=Y.channelFor(t,`http`);if(n===void 0)return e.json({error:`This device has no sealed HTTP channel.`},401);let r;try{r=await e.req.json()}catch{return e.json({error:`The sealed request envelope was malformed.`},400)}let i=n.open(r);if(!i.ok)return e.json({error:`The sealed request was refused: ${i.failure}.`},400);let a;try{a=JSON.parse(new TextDecoder().decode(i.plaintext))}catch{return e.json({error:`The sealed HTTP request was malformed.`},400)}let o=Te(a),s=o===void 0?void 0:Ee(o,e),c=o===void 0?void 0:De(o.body);if(o===void 0||s===void 0||c===void 0)return e.json({error:`The sealed HTTP request was invalid.`},400);let l=new URL(o.target,new URL(e.req.url).origin),u=await W.request(l,{method:o.method,headers:s,...o.method===`GET`||o.method===`HEAD`?{}:{body:Uint8Array.from(c).buffer}},{...e.env,sealedDeviceId:t}),d=Buffer.from(await u.arrayBuffer()),f=n.seal(new TextEncoder().encode(JSON.stringify({v:1,status:u.status,headers:Array.from(u.headers.entries()),body:d.toString(`base64`)})));return f.ok?e.json(f.envelope):e.json({error:`The sealed response failed: ${f.failure}.`},503)});let Ke=(0,E.bodyLimit)({maxSize:8192,onError:e=>e.json({error:`The Push subscription is too large.`},413)}),Z=e=>e.env?.sealedDeviceId;W.get(m.REMOTE_PUSH_KEY_ROUTE,e=>Z(e)===void 0?e.json({error:`A sealed paired device is required.`},401):e.json({publicKey:J?.publicKey()},200,{"Cache-Control":`no-store`})),W.post(m.REMOTE_PUSH_ROUTE,Ke,async e=>{let t=Z(e);if(t===void 0)return e.json({error:`A sealed paired device is required.`},401);let n;try{n=await e.req.json()}catch{return e.json({error:`The Push subscription must be JSON.`},400)}return J?.subscribe(t,n)===!0?e.body(null,204):e.json({error:`The Push subscription is invalid.`},400)}),W.delete(m.REMOTE_PUSH_ROUTE,e=>{let t=Z(e);return t===void 0?e.json({error:`A sealed paired device is required.`},401):(J?.remove(t),e.body(null,204))});let qe=r.createPiWebSocketListener({onError:e=>d(`protocol: ${e.message}`)}),Je=r.createPiWebSocketListener({onError:e=>d(`protocol: ${e.message}`)}),Ye=t.createPiHubService({records:()=>V.records(),spawn:e=>V.create(e),onNotice:d}),Xe={...Ye,createSession:async()=>{throw new C.PiServerError(`not_implemented`,`Remote protocol clients cannot create sessions`)}},Ze=new C.PiServer(Ye,{listeners:[qe],onError:e=>d(`protocol: ${e.message}`)}),Qe=new C.PiServer(Xe,{listeners:[Je],onError:e=>d(`protocol: ${e.message}`)});await Promise.all([Ze.start(),Qe.start()]);let Q=ne.createProviderAuth({runtime:e.authRuntime,onNotice:d});ee.registerAuthRoutes(W,Q);let $e=Pe(V),et=()=>$e.list(),tt=e=>$e.resolve(e),nt=e=>{let t=tt(e);if(t===void 0)return;let n=(0,x.readSyncDrift)({repoRoot:t}),r;try{r=(0,x.readSyncRegistration)(t)?(0,be.readSyncState)(t):void 0}catch{r=void 0}return{fresh:n.fresh,reasons:[...n.reasons],...r===void 0?{}:{mcpProjection:r.fileState.mcpProjection}}};te.registerSettingsRoutes(W,{repositories:et,models:()=>Q.listModels()});let rt=Re.apiDirectory,$=Fe(W,rt===void 0&&!process.env[O.PACKAGE_API_DIR_ENV]?[]:await(0,O.loadPackageApis)(`hub`,{apiDirectory:rt,onNotice:d}),d,tt,nt);N=async e=>{let t=(0,x.readSyncRegistration)(e);if(t===void 0)return;let n=await(0,O.loadPackageApis)(`hub`,{apiDirectory:t.apiDirectory,env:{},onNotice:d});$.add(n)},await Promise.all([...new Set([j,...Le])].map(N)),Ie(W,V,d,f),W.get(`/api/health`,e=>e.json({ok:!0,role:`hub`,protocol:2,sessions:V.snapshot().length,pid:process.pid,version:ke()})),W.post(s.SESSIONS_API_ROUTE,async e=>{let t;try{t=await e.req.json()}catch{return e.json({error:`The request body must be JSON.`},400)}if(!I(t)||typeof t.cwd!=`string`||t.cwd===``)return e.json({error:`A cwd string is required.`},400);let n;try{n=v.default.statSync(t.cwd)}catch{return e.json({error:`No such directory: ${t.cwd}`},400)}if(!y.default.isAbsolute(t.cwd)||!n.isDirectory())return e.json({error:`The working directory must be an absolute path to a directory, received "${t.cwd}".`},400);let r=typeof t.name==`string`&&t.name!==``?t.name:void 0;await z(t.cwd);let i=await V.create({cwd:t.cwd,name:r,trace:_.readTraceContext(e.req.raw.headers)});return i.ok?e.json({sessionId:i.sessionId},201):e.json({error:i.error},i.code===`invalid_request`?400:502)}),W.post(`${s.SESSIONS_API_ROUTE}/:sessionId/restart`,async e=>{let t=e.req.param(`sessionId`),n=V.snapshot().find(e=>e.id===t);n!==void 0&&await z(n.cwd);let r=await V.restart(t,_.readTraceContext(e.req.raw.headers));return r.ok?e.json({sessionId:r.sessionId},202):e.json({error:r.error},r.code===`invalid_request`?404:502)}),W.get(`${s.SESSIONS_API_ROUTE}/:sessionId/history`,async e=>{let t=e.req.param(`sessionId`),n=V.snapshot().find(e=>e.id===t);if(!n)return e.json({error:`Unknown session.`},404);let r=await ve.SessionManager.list(n.cwd);return e.json({sessions:r.map(e=>({id:e.id,...e.name===void 0?{}:{name:e.name},firstMessage:e.firstMessage,createdAt:e.created.toISOString(),updatedAt:e.modified.toISOString(),messageCount:e.messageCount}))})}),W.post(`${s.SESSIONS_API_ROUTE}/:sessionId/resume`,async e=>{let t=e.req.param(`sessionId`),n=V.snapshot().find(e=>e.id===t);if(!n)return e.json({error:`Unknown session.`},404);let r;try{r=await e.req.json()}catch{return e.json({error:`The request body must be JSON.`},400)}if(!I(r)||typeof r.targetSessionId!=`string`||r.targetSessionId===``)return e.json({error:`A targetSessionId string is required.`},400);let i=(await ve.SessionManager.list(n.cwd)).find(e=>e.id===r.targetSessionId);if(!i)return e.json({error:`That Pi thread does not belong to this workspace.`},404);await z(n.cwd);let a=await V.resume(t,{sessionId:i.id,name:je(i,n.cwd)},_.readTraceContext(e.req.raw.headers));return a.ok?e.json({sessionId:a.sessionId},202):e.json({error:a.error},a.code===`invalid_request`?409:502)}),W.delete(`${s.SESSIONS_API_ROUTE}/:sessionId`,e=>{let t=e.req.param(`sessionId`),n=V.stop(t);return n.ok?e.json({sessionId:t},202):e.json({error:n.error},n.code===`unknown`?404:n.code===`self`?409:502)}),W.get(`/api/sessions/:sessionId/files`,async e=>{let t=e.req.param(`sessionId`),n=V.snapshot().find(e=>e.id===t);if(!n)return e.json({error:`Unknown session.`},404);let r=e.req.query(`q`)??``,i=await de.listSessionFiles(n.cwd,r,20);return e.json({files:i})});let it=t=>{if(!(X.listenerOf(t)===`local`||(0,Se.insideSandbox)(process.env)))return e.browseRoot??process.cwd()};return W.get(s.DIRECTORIES_API_ROUTE,async e=>{let t=it(e),n=await ue.suggestDirectories(e.req.query(`q`)??``,{limit:12,...t===void 0?{}:{root:t}});return e.json({directories:n})}),W.get(i.SESSION_FILE_ROUTE,async e=>{let t=e.req.param(`sessionId`),n=V.snapshot().find(e=>e.id===t);if(!n)return e.json({error:`Unknown session.`},404);let r=e.req.query(`path`)??``,o=await de.readSessionFile(n.cwd,r,i.MAX_SESSION_FILE_BYTES);return o.status===`forbidden`?e.json({error:`The path leaves the session directory.`},403):o.status===`not-found`?e.json({error:`No such file.`},404):o.status===`too-large`?e.json({error:`The file is too large to preview.`},413):e.body(new Uint8Array(o.body),200,a.sessionFileHeaders(r))}),W.get(m.SESSION_SOCKET_ROUTE,G.upgradeWebSocket(e=>{let t=X.listenerOf(e)===`local`,n=t?void 0:Y.authorize((0,T.getCookie)(e,m.DEVICE_COOKIE,`host`)),r=n===void 0?void 0:Y.channelFor(n,`session`),i=new Set,a=(0,he.randomUUID)(),o=new Map,l,u,f,p,h=e=>{for(let[t,n]of o)(e===void 0||n.sessionId===e)&&(o.delete(t),H.unsubscribe(n.sessionId,n.threadId))};return{onOpen(e,m){if(!t&&r===void 0){m.close(1008,`sealed session channel required`);return}let g=e=>{let n=JSON.stringify(e),i=n;if(!t){if(r===void 0)return;let e=r.seal(new TextEncoder().encode(n));if(!e.ok){m.close(1008,`sealed session channel failed`);return}i=JSON.stringify(e.envelope)}try{m.send(i)}catch{}};f={post:g,local:t},U.add(f),n!==void 0&&(p=Y.trackSocket(n,(e,t)=>m.close(e,t))),g(s.hubHello(V.channelTypes())),g({type:s.SESSIONS_SNAPSHOT_TYPE,sessions:V.snapshot()}),l=V.onEvent(e=>{e.kind===`upsert`?g({type:s.SESSION_UPSERT_TYPE,session:e.session}):e.kind===`removed`?(i.delete(e.sessionId),h(e.sessionId),g({type:s.SESSION_REMOVED_TYPE,sessionId:e.sessionId})):e.kind===`channel`?(e.connectionId===a||e.connectionId===void 0&&i.has(e.sessionId))&&g({type:e.frameType,sessionId:e.sessionId,payload:e.payload}):(c.parseDoomNotificationEntry(e.frame)!==void 0||i.has(e.sessionId))&&g(s.sessionFrameEnvelope(e.sessionId,e.frame))}),u=H.onFrame(e=>{o.has(Me(e.sessionId,e.threadId))&&g(s.threadFrameEnvelope(e.sessionId,e.threadId,e.frame))}),d(`browser attached`)},onMessage(e){if(typeof e.data!=`string`)return;let n;try{n=JSON.parse(e.data)}catch{return}if(!t){if(r===void 0)return;let e=r.open(n);if(!e.ok)return;try{n=JSON.parse(new TextDecoder().decode(e.plaintext))}catch{return}}if(!I(n)||typeof n.sessionId!=`string`)return;let c=n.sessionId;if(typeof n.type==`string`&&V.channelTypes().includes(n.type)&&(i.has(c)||V.channelReceivesWithoutSubscription(c,n.type))){V.receiveChannel(c,n.type,n.payload,a);return}if(n.type===`subscribe`){let e=V.backlog(c);if(!e)return;i.add(c),f?.post(e);for(let e of V.channelFrames(c))f?.post(e);return}if(n.type===`unsubscribe`){i.delete(c);return}if(n.type===`history_request`){let e=V.history(c,{...typeof n.before==`string`?{before:n.before}:{},...typeof n.limit==`number`?{limit:n.limit}:{}});if(!e)return;f?.post(e);return}if(n.type===`subscribe_thread`||n.type===`unsubscribe_thread`){if(typeof n.threadId!=`string`)return;let e=n.threadId,t=Me(c,e);if(n.type===`unsubscribe_thread`){o.delete(t)&&H.unsubscribe(c,e);return}if(o.has(t)||V.backlog(c)===void 0)return;o.set(t,{sessionId:c,threadId:e}),f?.post(s.threadBacklog(c,e,H.subscribe(c,e)));return}if(n.type===`session_command`&&I(n.frame)){if(n.frame.type===`attach`)return;V.command(c,n.frame)}},onClose(){V.disconnectChannels(a),f&&U.delete(f),f=void 0,p?.(),p=void 0,l?.(),l=void 0,u?.(),u=void 0,i.clear(),h(),d(`browser detached`)}}})),W.get(m.PROTOCOL_SOCKET_ROUTE,G.upgradeWebSocket(e=>{let t=X.listenerOf(e)===`local`,n=t?void 0:Y.authorize((0,T.getCookie)(e,m.DEVICE_COOKIE,`host`)),r=n===void 0?void 0:Y.channelFor(n,`protocol`),i,a;return{onOpen(e,o){if(!t&&r===void 0){o.close(1008,`sealed protocol channel required`);return}n!==void 0&&(a=Y.trackSocket(n,(e,t)=>o.close(e,t))),i=(t?qe:Je).accept({send:e=>{if(t){o.send(e);return}if(r===void 0)return;let n=e instanceof Uint8Array?e:new Uint8Array(e),i=r.seal(n);if(!i.ok){o.close(1008,`sealed protocol channel failed`);return}o.send(new TextEncoder().encode(JSON.stringify(i.envelope)))},close:()=>o.close(),get readyState(){return o.readyState}})},async onMessage(e){let n=e.data;if(typeof n==`string`)return;let a=n instanceof Blob?new Uint8Array(await n.arrayBuffer()):(n instanceof ArrayBuffer,new Uint8Array(n));if(t){i?.onData(a);return}if(r===void 0)return;let o;try{o=JSON.parse(new TextDecoder().decode(a))}catch{return}let s=r.open(o);s.ok&&i?.onData(s.plaintext)},onClose(){a?.(),a=void 0,i?.onClose(),i=void 0},onError(e){i?.onError(e instanceof Error?e:Error(`The protocol socket failed`)),i=void 0}}})),W.get(`/manifest.webmanifest`,e=>{let t=F(y.default.join(K,`manifest.webmanifest`));return t===void 0?e.text(`The PWA manifest is unavailable.`,404):e.body(new Uint8Array(t),200,{"Cache-Control":`no-store`,"Content-Type":`application/manifest+json; charset=utf-8`})}),W.get(`/sw.js`,e=>{let t=F(y.default.join(K,`sw.js`));return t===void 0?e.text(`The trusted service worker is unavailable.`,404):e.body(new Uint8Array(t),200,{"Cache-Control":`no-cache`,"Content-Type":`text/javascript; charset=utf-8`,"Service-Worker-Allowed":`/`})}),W.get(`/pwa/*`,e=>{let t=new URL(e.req.url).pathname.slice(5),n=o.resolveAssetPath(K,`/${t}`),r=n===void 0?void 0:F(n);return n===void 0||r===void 0?e.text(`PWA asset not found.`,404):e.body(new Uint8Array(r),200,{"Cache-Control":`no-store`,"Content-Type":o.contentTypeFor(n),"X-Content-Type-Options":`nosniff`})}),W.get(`${Ce}*`,e=>{let t=new URL(e.req.url).pathname,n=/^\/api\/web-plugins\/([a-f0-9]{64})\/([1-9][0-9]*)\/(manifest|assets(\/.*))$/u.exec(t),r=n===null?void 0:Number(n[2]),i=n===null||!Number.isSafeInteger(r)?void 0:B.get(n[1]??``,r);if(n===null||i===void 0)return e.text(`That signed plugin composition is unavailable.`,404);if(n[3]===`manifest`)return e.json(i.signed,200,{"Cache-Control":`no-store`});let a=(0,w.assetFor)(i.signed.manifest,n[4]??``),s=a===void 0?void 0:o.resolveAssetPath(i.assetsDir,a.path),c=s===void 0?void 0:F(s);return a===void 0||s===void 0||c===void 0?e.text(`Plugin composition asset not found.`,404):e.body(new Uint8Array(c),200,{"Cache-Control":`no-store`,"Content-Length":String(c.byteLength),"Content-Type":a.contentType,"X-Content-Type-Options":`nosniff`})}),W.get(w.BUNDLE_MANIFEST_ROUTE,e=>{let t=q.current();return t===void 0?e.json({error:`No signed cockpit bundle is available.`},503):e.json(t.signed,200,{"Cache-Control":`no-store`})}),W.get(`/bundle-assets/*`,e=>{let t=new URL(e.req.url).pathname,n=/^\/bundle-assets\/([1-9][0-9]*)(\/.*)$/u.exec(t),r=n===null?void 0:Number(n[1]),i=q.current();if(n===null||!Number.isSafeInteger(r)||i===void 0||i.signed.manifest.revision!==r)return e.text(`That signed bundle revision is unavailable.`,404);let a=(0,w.assetFor)(i.signed.manifest,n[2]??``),s=a===void 0?void 0:o.resolveAssetPath(i.assetsDir,a.path),c=s===void 0?void 0:F(s);return a===void 0||s===void 0||c===void 0?e.text(`Bundle asset not found.`,404):e.body(new Uint8Array(c),200,{"Cache-Control":`no-store`,"Content-Length":String(c.byteLength),"Content-Type":a.contentType,"X-Content-Type-Options":`nosniff`})}),W.get(`/`,e=>e.redirect(m.PAIRING_PAGE_ROUTE)),W.get(`*`,e=>{let t=new URL(e.req.url).pathname,n=e.req.header(`accept`)?.includes(`text/html`)===!0;return!t.startsWith(`/api/`)&&n?e.redirect(`/`):e.text(`Not found.`,404)}),M.watch(()=>{for(let e of V.records())D(e.cwd)===j&&V.reloadChannels(e.id)}),new Promise((t,n)=>{let r=(0,ge.serve)({fetch:W.fetch,port:e.port,hostname:l},e=>{Be=e.port,G.injectWebSocket(r);let n=`http://${l}:${e.port}`;d(`cockpit on ${n}`);let i,a=async()=>{await Y.close(),await new Promise(e=>{H.close(),M.close(),Ze.close(),Qe.close(),He(),J?.close(),V.close(),Q.close();for(let e of $.handlers)e.close();B.close();for(let e of G.wss.clients)e.terminate();G.wss.close(),r.closeAllConnections?.(),r.close(()=>e())}),await _.shutdownWebTelemetry(f)};t({url:n,port:e.port,close:()=>i??=a()})});r.once(`error`,e=>{M.close(),H.close(),He(),J?.close(),V.close(),Q.close(),Y.close();for(let e of $.handlers)e.close();B.close(),f.shutdown(),n(e)})})}exports.createSettingsRepositoryRegistry=Pe,exports.mountHubApis=Fe,exports.packagedVersion=ke,exports.serveWeb=z;
|
|
3
3
|
//# sourceMappingURL=httpServer.cjs.map
|