gemi 0.133.0 → 0.135.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.
Files changed (47) hide show
  1. package/dist/ai/index.d.ts +2 -2
  2. package/dist/ai/index.d.ts.map +1 -1
  3. package/dist/ai/index.js +9 -9
  4. package/dist/ai/index.js.map +4 -4
  5. package/dist/ai/providers/realtime.d.ts +75 -4
  6. package/dist/ai/providers/realtime.d.ts.map +1 -1
  7. package/dist/ai/providers/sideband.d.ts +7 -2
  8. package/dist/ai/providers/sideband.d.ts.map +1 -1
  9. package/dist/ai/voice/energyVad.d.ts +42 -0
  10. package/dist/ai/voice/energyVad.d.ts.map +1 -0
  11. package/dist/ai/voice/index.d.ts +7 -0
  12. package/dist/ai/voice/index.d.ts.map +1 -1
  13. package/dist/ai/voice/index.js +601 -1
  14. package/dist/ai/voice/index.js.map +1 -1
  15. package/dist/ai/voice/liveTranscription.d.ts +99 -0
  16. package/dist/ai/voice/liveTranscription.d.ts.map +1 -0
  17. package/dist/ai/voice/transcriptionState.d.ts +52 -0
  18. package/dist/ai/voice/transcriptionState.d.ts.map +1 -0
  19. package/dist/ai/voice/useLiveTranscription.d.ts +86 -0
  20. package/dist/ai/voice/useLiveTranscription.d.ts.map +1 -0
  21. package/dist/bin/gemi.js.map +1 -1
  22. package/dist/chunk-6hstj70n.js +24 -0
  23. package/dist/{chunk-s21kn0x8.js.map → chunk-6hstj70n.js.map} +3 -3
  24. package/dist/{chunk-wevj4981.js → chunk-e2tjw0qx.js} +7 -7
  25. package/dist/{chunk-wevj4981.js.map → chunk-e2tjw0qx.js.map} +4 -4
  26. package/dist/{chunk-s55t7rxw.js → chunk-n68a4r72.js} +1 -1
  27. package/dist/{chunk-b6yb3svm.js → chunk-rhjh79np.js} +2 -2
  28. package/dist/{chunk-b6yb3svm.js.map → chunk-rhjh79np.js.map} +1 -1
  29. package/dist/{chunk-4pvv8qs0.js → chunk-sxcxmwbt.js} +1 -1
  30. package/dist/client/index.js +8 -2
  31. package/dist/client/index.js.map +1 -1
  32. package/dist/client/islands.d.ts +10 -0
  33. package/dist/client/islands.d.ts.map +1 -1
  34. package/dist/facades/index.js +1 -1
  35. package/dist/http/index.js +1 -1
  36. package/dist/i18n/index.js +1 -1
  37. package/dist/kernel/index.js +1 -1
  38. package/dist/server/index.js +1 -1
  39. package/dist/server/modulePreloads.d.ts +14 -2
  40. package/dist/server/modulePreloads.d.ts.map +1 -1
  41. package/dist/services/index.js +1 -1
  42. package/dist/services/router/staticDocument.d.ts +6 -3
  43. package/dist/services/router/staticDocument.d.ts.map +1 -1
  44. package/package.json +1 -1
  45. package/dist/chunk-s21kn0x8.js +0 -24
  46. /package/dist/{chunk-s55t7rxw.js.map → chunk-n68a4r72.js.map} +0 -0
  47. /package/dist/{chunk-4pvv8qs0.js.map → chunk-sxcxmwbt.js.map} +0 -0
@@ -1,5 +1,5 @@
1
1
  // @bun
2
- import{R as S,T as h,U as u}from"./chunk-b6yb3svm.js";import{ma as q,na as w}from"./chunk-mpqvmge4.js";import"./chunk-a22h5cby.js";import"./chunk-epvpmakp.js";import"./chunk-r3v2cnrj.js";import"./chunk-4278e429.js";import"./chunk-kk18xqgc.js";import"./chunk-sa6cxt3g.js";import{ti as N}from"./chunk-zv5qyrqg.js";import{Lk as y}from"./chunk-x9bk5s21.js";import{_k as C}from"./chunk-99a4e6zf.js";import"./chunk-rnp5k8m3.js";import{join as $J}from"path";import{createServer as zJ}from"vite";import{join as l}from"path";import{IncomingMessage as d,ServerResponse as p}from"http";import{Socket as i}from"net";function c(J){return J.replace(/\x1b\[[0-9;]*m/g,"").replace(/\[[0-9;]*m/g,"").replace(/\n\s*\n/g,`
2
+ import{R as S,T as h,U as u}from"./chunk-rhjh79np.js";import{ma as q,na as w}from"./chunk-mpqvmge4.js";import"./chunk-a22h5cby.js";import"./chunk-epvpmakp.js";import"./chunk-r3v2cnrj.js";import"./chunk-4278e429.js";import"./chunk-kk18xqgc.js";import"./chunk-sa6cxt3g.js";import{ti as N}from"./chunk-zv5qyrqg.js";import{Lk as y}from"./chunk-x9bk5s21.js";import{_k as C}from"./chunk-99a4e6zf.js";import"./chunk-rnp5k8m3.js";import{join as $J}from"path";import{createServer as zJ}from"vite";import{join as l}from"path";import{IncomingMessage as d,ServerResponse as p}from"http";import{Socket as i}from"net";function c(J){return J.replace(/\x1b\[[0-9;]*m/g,"").replace(/\[[0-9;]*m/g,"").replace(/\n\s*\n/g,`
3
3
  `).split(`
4
4
  `).map((W)=>W.trim()).filter((W)=>W.length>0).join(`
5
5
  `).trim()}function _(J){return`
@@ -1,6 +1,6 @@
1
1
  // @bun
2
- import{Ba as y}from"./chunk-kk18xqgc.js";import{createElement as k}from"react";function z(i,n){let s=Object.keys(n).sort((p,e)=>e.length-p.length).map((p)=>p.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")),b=new RegExp(s.join("|"),"g");return i.replace(b,(p)=>n[p])}async function L(i,n,s=[],b){let p=[...s.map((t)=>`${i}/views/${t}.tsx`),b?`${i}/views/${b}.tsx`:`${i}/views/RootLayout.tsx`],e=new Set;for(let t of p){let u=n.moduleGraph.getModulesByFile(t);if(u)for(let l of u)e.add(l)}let g=[],x=[],r={};for(let t of e)if(t)for(let u of t.importedModules){if(u.file.includes("module.css"))r[u.file]=u.ssrTransformResult.map.sourcesContent.join("");if(u.file.includes(".css"))x.push(u.file)}for(let t of x){let u=await n.transformRequest(t+"?direct"),l=t.includes("module.css"),v="";if(l)v=z(r[t],u.default);g.push({isDev:!0,id:t,content:l?v:u.code})}return g.map((t,u)=>{return k("style",{key:u,type:"text/css","data-vite-dev-id":t.id,dangerouslySetInnerHTML:{__html:t.content}})})}async function _(i=[]){return i.map((n,s)=>{return k("style",{key:s,id:n?.id,type:"text/css",dangerouslySetInnerHTML:{__html:n.content}})})}import{existsSync as J}from"fs";import{basename as N}from"path";import{networkInterfaces as O}from"os";var q={name:"gemi",version:"0.133.0",private:!1,license:"MIT",author:"Enes Tufekci <enes@gemijs.dev>",repository:{type:"git",url:"git+https://github.com/nstfkc/gemi.git",directory:"packages/gemi"},bin:{gemi:"./dist/bin/gemi.js","gemi-orm-generator":"./dist/bin/orm-generator.js"},files:["dist/**/*","ide/typescript-plugin/package.json","skills/**/*"],module:!0,exports:{"./http":"./http/index.ts","./client":"./client/index.ts","./ai":"./ai/index.ts","./ai/client":"./ai/client/index.ts","./ai/voice":"./ai/voice/index.ts","./testing":"./testing/index.ts","./app":"./app/index.ts","./facades":"./facades/index.ts","./email":"./email/index.ts","./vite":"./dist/vite/index.mjs","./kernel":"./kernel/index.ts","./services":"./services/index.ts","./i18n":"./i18n/index.ts","./dictionary":"./i18n/dictionaryRuntime.ts","./server":"./server/index.ts","./config":"./config/index.ts","./container":"./container/index.ts","./foundation":"./foundation/index.ts","./database":"./database/index.ts","./orm":"./orm/index.ts","./support":"./support/index.ts","./console/run":"./console/run.ts","./queue/work":"./services/queue/work.ts","./stats/route-table":"./stats/route-table.ts","./ide/typescript-plugin":"./ide/typescript-plugin/index.ts","./bun/preload":"./bun/preload.ts","./bun/plugin":"./bun/plugin.ts","./vitest":"./vitest/index.ts"},scripts:{lint:"oxlint",typecheck:"tsc --noEmit -p tsconfig.json && tsc --noEmit -p tsconfig.browser.json && tsc --noEmit -p ide/typescript-plugin/tsconfig.json",build:"NODE_ENV=production bun run build:core && bun run build:bin && bun run build:types && bun run build:client && bun run build:plugin && bun run build:ts-plugin && bun run build:client-types && bun run build:augmentation","build:core":"bun ./scripts/build.ts","build:bin":"bun build --outdir=./dist/bin --target=bun --external=vite --external=react-dom --external=react/jsx-runtime --external=bun --external=sharp --external=@azure/storage-blob --external=typescript --sourcemap ./bin/gemi.ts ./bin/orm-generator.ts && bun ./scripts/prepare-bin.ts","build:client":"rm -rf dist/client dist/testing dist/ai/client dist/ai/voice dist/chunks && vite build -c vite.client.config.mts","build:plugin":"vite build -c vite.plugin.config.mts","build:ts-plugin":"bun ./scripts/build-ts-plugin.ts","build:types":"tsc -p tsconfig.build.json","build:client-types":"tsc -p tsconfig.browser.json",test:"bun --bun x vitest","test:types":"vitest run --typecheck.only","test:live":"bun --bun x vitest run ai/live","test:packaging":"bun --bun x vitest run --config vitest.packaging.config.ts","build:publish":"bun scripts/build-publish.ts",prepublishOnly:"echo 'Do not publish from this directory \u2014 its exports point at TS source. Run: bun run build:publish, then publish from .publish/' && exit 1","build:augmentation":"bun ./scripts/wire-augmentation.ts"},dependencies:{"@aws-sdk/client-s3":"^3.629.0","@aws-sdk/s3-request-presigner":"^3.629.0","ast-types":"^0.14.2",commander:"^12.1.0",history:"^5.3.0","jsx-email":"2.0.0-rc2.1","magic-string":"^0.30.17",open:"^10.1.0","react-error-boundary":"^6.0.0",recast:"^0.23.9",resend:"^6.12.3",satori:"^0.12.2","temporal-polyfill":"^0.2.5","twitter-api-v2":"^1.20.2","urlpattern-polyfill":"^10.0.0",uuid:"^9.0.1"},devDependencies:{"@babel/parser":"^7.25.4","@prisma/generator-helper":"^6.5.0","@repo/typescript-config":"*","@testing-library/react":"^16.3.2","@types/bun":"^1.3.14","@types/eslint":"^8.56.5","@types/node":"^20.11.24","@types/react":"^19.0.2","@types/react-dom":"^19.0.2",eslint:"^8.57.0",jsdom:"^30.0.1",oxlint:"^1.39.0",postgres:"^3.4.5",react:"19.2.3","react-dom":"19.2.3",typescript:"^5.7.3",vitest:"^4.0.0"},peerDependencies:{"@azure/storage-blob":"^12.28.0",react:">=19","react-dom":">=19",sharp:"^0.34.2",typescript:">=5",vite:"^8.0.0",postgres:"^3.4.0"},peerDependenciesMeta:{"@azure/storage-blob":{optional:!0},typescript:{optional:!0},postgres:{optional:!0}}};var Q=[" \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2557\u2588\u2588\u2557","\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D \u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2551","\u2588\u2588\u2551 \u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2554\u2588\u2588\u2588\u2588\u2554\u2588\u2588\u2551\u2588\u2588\u2551","\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u255D \u2588\u2588\u2551\u255A\u2588\u2588\u2554\u255D\u2588\u2588\u2551\u2588\u2588\u2551","\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2551 \u255A\u2550\u255D \u2588\u2588\u2551\u2588\u2588\u2551"," \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D\u255A\u2550\u255D"],W=Boolean(process.stdout.isTTY)&&!process.env.NO_COLOR,c=(i,n)=>W?`\x1B[${i}m${n}\x1B[0m`:n,X=(i)=>c("1",i),d=(i)=>c("2",i),j=(i)=>c("36",i),Y=(i)=>c("32",i),Z=(i)=>c("35",i);function $(){return q.version??"?"}function f(i){for(let n of Object.values(O()))for(let s of n??[])if((s.family==="IPv4"||s.family===4)&&!s.internal)return`http://${s.address}:${i}`;return null}function H(i){return y(i).filter((n)=>J(n)).map((n)=>N(n))}function T(i){let{port:n,rootDir:s}=i,b=`http://localhost:${n}`,p=f(n),e=H(s),g=(r,t)=>` ${Y("\u279C")} ${X(r.padEnd(9))}${t}`,x=["",...Q.map((r)=>Z(r)),"",` ${d("gemi")} ${j(`v${$()}`)}`,"",g("Local:",j(b)),g("Network:",p?j(p):d("unavailable")),g("Env:",e.length?e.join(", "):d("none")),""];console.log(x.join(`
2
+ import{Ba as y}from"./chunk-kk18xqgc.js";import{createElement as k}from"react";function z(i,n){let s=Object.keys(n).sort((p,e)=>e.length-p.length).map((p)=>p.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")),b=new RegExp(s.join("|"),"g");return i.replace(b,(p)=>n[p])}async function L(i,n,s=[],b){let p=[...s.map((t)=>`${i}/views/${t}.tsx`),b?`${i}/views/${b}.tsx`:`${i}/views/RootLayout.tsx`],e=new Set;for(let t of p){let u=n.moduleGraph.getModulesByFile(t);if(u)for(let l of u)e.add(l)}let g=[],x=[],r={};for(let t of e)if(t)for(let u of t.importedModules){if(u.file.includes("module.css"))r[u.file]=u.ssrTransformResult.map.sourcesContent.join("");if(u.file.includes(".css"))x.push(u.file)}for(let t of x){let u=await n.transformRequest(t+"?direct"),l=t.includes("module.css"),v="";if(l)v=z(r[t],u.default);g.push({isDev:!0,id:t,content:l?v:u.code})}return g.map((t,u)=>{return k("style",{key:u,type:"text/css","data-vite-dev-id":t.id,dangerouslySetInnerHTML:{__html:t.content}})})}async function _(i=[]){return i.map((n,s)=>{return k("style",{key:s,id:n?.id,type:"text/css",dangerouslySetInnerHTML:{__html:n.content}})})}import{existsSync as J}from"fs";import{basename as N}from"path";import{networkInterfaces as O}from"os";var q={name:"gemi",version:"0.135.0",private:!1,license:"MIT",author:"Enes Tufekci <enes@gemijs.dev>",repository:{type:"git",url:"git+https://github.com/nstfkc/gemi.git",directory:"packages/gemi"},bin:{gemi:"./dist/bin/gemi.js","gemi-orm-generator":"./dist/bin/orm-generator.js"},files:["dist/**/*","ide/typescript-plugin/package.json","skills/**/*"],module:!0,exports:{"./http":"./http/index.ts","./client":"./client/index.ts","./ai":"./ai/index.ts","./ai/client":"./ai/client/index.ts","./ai/voice":"./ai/voice/index.ts","./testing":"./testing/index.ts","./app":"./app/index.ts","./facades":"./facades/index.ts","./email":"./email/index.ts","./vite":"./dist/vite/index.mjs","./kernel":"./kernel/index.ts","./services":"./services/index.ts","./i18n":"./i18n/index.ts","./dictionary":"./i18n/dictionaryRuntime.ts","./server":"./server/index.ts","./config":"./config/index.ts","./container":"./container/index.ts","./foundation":"./foundation/index.ts","./database":"./database/index.ts","./orm":"./orm/index.ts","./support":"./support/index.ts","./console/run":"./console/run.ts","./queue/work":"./services/queue/work.ts","./stats/route-table":"./stats/route-table.ts","./ide/typescript-plugin":"./ide/typescript-plugin/index.ts","./bun/preload":"./bun/preload.ts","./bun/plugin":"./bun/plugin.ts","./vitest":"./vitest/index.ts"},scripts:{lint:"oxlint",typecheck:"tsc --noEmit -p tsconfig.json && tsc --noEmit -p tsconfig.browser.json && tsc --noEmit -p ide/typescript-plugin/tsconfig.json",build:"NODE_ENV=production bun run build:core && bun run build:bin && bun run build:types && bun run build:client && bun run build:plugin && bun run build:ts-plugin && bun run build:client-types && bun run build:augmentation","build:core":"bun ./scripts/build.ts","build:bin":"bun build --outdir=./dist/bin --target=bun --external=vite --external=react-dom --external=react/jsx-runtime --external=bun --external=sharp --external=@azure/storage-blob --external=typescript --sourcemap ./bin/gemi.ts ./bin/orm-generator.ts && bun ./scripts/prepare-bin.ts","build:client":"rm -rf dist/client dist/testing dist/ai/client dist/ai/voice dist/chunks && vite build -c vite.client.config.mts","build:plugin":"vite build -c vite.plugin.config.mts","build:ts-plugin":"bun ./scripts/build-ts-plugin.ts","build:types":"tsc -p tsconfig.build.json","build:client-types":"tsc -p tsconfig.browser.json",test:"bun --bun x vitest","test:types":"vitest run --typecheck.only","test:live":"bun --bun x vitest run ai/live","test:packaging":"bun --bun x vitest run --config vitest.packaging.config.ts","build:publish":"bun scripts/build-publish.ts",prepublishOnly:"echo 'Do not publish from this directory \u2014 its exports point at TS source. Run: bun run build:publish, then publish from .publish/' && exit 1","build:augmentation":"bun ./scripts/wire-augmentation.ts"},dependencies:{"@aws-sdk/client-s3":"^3.629.0","@aws-sdk/s3-request-presigner":"^3.629.0","ast-types":"^0.14.2",commander:"^12.1.0",history:"^5.3.0","jsx-email":"2.0.0-rc2.1","magic-string":"^0.30.17",open:"^10.1.0","react-error-boundary":"^6.0.0",recast:"^0.23.9",resend:"^6.12.3",satori:"^0.12.2","temporal-polyfill":"^0.2.5","twitter-api-v2":"^1.20.2","urlpattern-polyfill":"^10.0.0",uuid:"^9.0.1"},devDependencies:{"@babel/parser":"^7.25.4","@prisma/generator-helper":"^6.5.0","@repo/typescript-config":"*","@testing-library/react":"^16.3.2","@types/bun":"^1.3.14","@types/eslint":"^8.56.5","@types/node":"^20.11.24","@types/react":"^19.0.2","@types/react-dom":"^19.0.2",eslint:"^8.57.0",jsdom:"^30.0.1",oxlint:"^1.39.0",postgres:"^3.4.5",react:"19.2.3","react-dom":"19.2.3",typescript:"^5.7.3",vitest:"^4.0.0"},peerDependencies:{"@azure/storage-blob":"^12.28.0",react:">=19","react-dom":">=19",sharp:"^0.34.2",typescript:">=5",vite:"^8.0.0",postgres:"^3.4.0"},peerDependenciesMeta:{"@azure/storage-blob":{optional:!0},typescript:{optional:!0},postgres:{optional:!0}}};var Q=[" \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2557\u2588\u2588\u2557","\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D \u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2551","\u2588\u2588\u2551 \u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2554\u2588\u2588\u2588\u2588\u2554\u2588\u2588\u2551\u2588\u2588\u2551","\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u255D \u2588\u2588\u2551\u255A\u2588\u2588\u2554\u255D\u2588\u2588\u2551\u2588\u2588\u2551","\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2551 \u255A\u2550\u255D \u2588\u2588\u2551\u2588\u2588\u2551"," \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D\u255A\u2550\u255D"],W=Boolean(process.stdout.isTTY)&&!process.env.NO_COLOR,c=(i,n)=>W?`\x1B[${i}m${n}\x1B[0m`:n,X=(i)=>c("1",i),d=(i)=>c("2",i),j=(i)=>c("36",i),Y=(i)=>c("32",i),Z=(i)=>c("35",i);function $(){return q.version??"?"}function f(i){for(let n of Object.values(O()))for(let s of n??[])if((s.family==="IPv4"||s.family===4)&&!s.internal)return`http://${s.address}:${i}`;return null}function H(i){return y(i).filter((n)=>J(n)).map((n)=>N(n))}function T(i){let{port:n,rootDir:s}=i,b=`http://localhost:${n}`,p=f(n),e=H(s),g=(r,t)=>` ${Y("\u279C")} ${X(r.padEnd(9))}${t}`,x=["",...Q.map((r)=>Z(r)),"",` ${d("gemi")} ${j(`v${$()}`)}`,"",g("Local:",j(b)),g("Network:",p?j(p):d("unavailable")),g("Env:",e.length?e.join(", "):d("none")),""];console.log(x.join(`
3
3
  `))}function D(i=process.env.SERVER_IDLE_TIMEOUT){if(i===void 0||i.trim()==="")return 10;let n=Number(i.trim());if(!Number.isInteger(n)||n<0||n>255)throw Error(`SERVER_IDLE_TIMEOUT must be a whole number of seconds from 0 to 255 (0 disables the timeout), got ${JSON.stringify(i)}.`);return n}
4
4
  export{L as R,_ as S,T,D as U};
5
5
 
6
- //# debugId=BE91EE18CD33A91064756E2164756E21
6
+ //# debugId=97E38DD84A148DCD64756E2164756E21
@@ -7,6 +7,6 @@
7
7
  "/**\n * Bun's default, and what both servers use when `SERVER_IDLE_TIMEOUT` is unset.\n */\nexport const DEFAULT_SERVER_IDLE_TIMEOUT = 10;\n\n/**\n * The `idleTimeout` (seconds) both `gemi dev` and `gemi start` pass to\n * `Bun.serve`, from `SERVER_IDLE_TIMEOUT` (#787).\n *\n * One reader for both servers, so a long-poll that works under `gemi start`\n * also works under `gemi dev`. Before this, only `httpProd` read the variable\n * and the dev server always ran at Bun's 10 seconds.\n *\n * It is the time a connection may stay silent, a response that has not started\n * included, before Bun closes it; `0` disables it. It does not apply to an\n * upgraded websocket (the HMR relay included), which has its own\n * `websocket.idleTimeout`.\n *\n * Unset or blank means the default. Anything that is not a whole number from 0\n * to 255 (Bun's own limits) fails the boot with the variable's name, instead\n * of Bun's \"expects idleTimeout to be an integer\", which does not say where the\n * value came from.\n */\nexport function serverIdleTimeout(raw: string | undefined = process.env.SERVER_IDLE_TIMEOUT): number {\n if (raw === undefined || raw.trim() === \"\") return DEFAULT_SERVER_IDLE_TIMEOUT;\n\n const seconds = Number(raw.trim());\n if (!Number.isInteger(seconds) || seconds < 0 || seconds > 255) {\n throw new Error(\n `SERVER_IDLE_TIMEOUT must be a whole number of seconds from 0 to 255 ` +\n `(0 disables the timeout), got ${JSON.stringify(raw)}.`,\n );\n }\n return seconds;\n}\n"
8
8
  ],
9
9
  "mappings": ";yCAAA,wBAAS,cAGT,SAAS,CAAc,CAAC,EAAc,EAAwC,CAC5E,IAAM,EAAc,OAAO,KAAK,CAAM,EACnC,KAAK,CAAC,EAAG,IAAM,EAAE,OAAS,EAAE,MAAM,EAClC,IAAI,CAAC,IAAQ,EAAI,QAAQ,sBAAuB,MAAM,CAAC,EAGpD,EAAQ,IAAI,OAAO,EAAY,KAAK,GAAG,EAAG,GAAG,EAEnD,OAAO,EAAK,QAAQ,EAAO,CAAC,IAAU,EAAO,EAAM,EAGrD,eAAsB,CAAe,CACnC,EACA,EACA,EAAyB,CAAC,EAE1B,EACA,CACA,IAAM,EAAQ,CACZ,GAAG,EAAa,IAAI,CAAC,IAAS,GAAG,WAAgB,OAAU,EAC3D,EAAS,GAAG,WAAgB,QAAe,GAAG,wBAChD,EAEM,EAAU,IAAI,IACpB,QAAW,KAAQ,EAAO,CACxB,IAAM,EAAM,EAAK,YAAY,iBAAiB,CAAI,EAClD,GAAI,EACF,QAAW,KAAK,EAAK,EAAQ,IAAI,CAAC,EAItC,IAAM,EAAS,CAAC,EACV,EAAa,CAAC,EACd,EAA2C,CAAC,EAClD,QAAW,KAAO,EAChB,GAAI,EACF,QAAW,KAAY,EAAI,gBAAiB,CAC1C,GAAI,EAAS,KAAK,SAAS,YAAY,EACrC,EAAiB,EAAS,MAAQ,EAAS,mBAAmB,IAAI,eAAe,KAAK,EAAE,EAE1F,GAAI,EAAS,KAAK,SAAS,MAAM,EAC/B,EAAW,KAAK,EAAS,IAAI,EAMrC,QAAW,KAAiB,EAAY,CACtC,IAAM,EAAY,MAAM,EAAK,iBAAiB,EAAgB,SAAS,EAEjE,EAAc,EAAc,SAAS,YAAY,EAEnD,EAAuB,GAE3B,GAAI,EACF,EAAuB,EACrB,EAAiB,GAGhB,EAA6D,OAChE,EAGF,EAAO,KAAK,CACV,MAAO,GACP,GAAI,EACJ,QAAS,EAAc,EAAuB,EAAU,IAC1D,CAAC,EAGH,OAAO,EAAO,IAAI,CAAC,EAAO,IAAM,CAC9B,OAAO,EAAc,QAAS,CAC5B,IAAK,EACL,KAAM,WACN,mBAAoB,EAAM,GAC1B,wBAAyB,CAAE,OAAQ,EAAM,OAAQ,CACnD,CAAC,EACF,EAGH,eAAsB,CAAY,CAAC,EAAS,CAAC,EAAG,CAC9C,OAAO,EAAO,IAAI,CAAC,EAAO,IAAM,CAC9B,OAAO,EAAc,QAAS,CAC5B,IAAK,EACL,GAAI,GAAO,GACX,KAAM,WACN,wBAAyB,CAAE,OAAQ,EAAM,OAAQ,CACnD,CAAC,EACF,EC3FH,qBAAS,WACT,mBAAS,aACT,4BAAS,i1HAKT,IAAM,EAAM,CACV,oKACA,mLACA,yKACA,oKACA,mLACA,yJACF,EAEM,EAAW,QAAQ,QAAQ,OAAO,KAAK,GAAK,CAAC,QAAQ,IAAI,SACzD,EAAQ,CAAC,EAAc,IAC3B,EAAW,QAAQ,KAAQ,WAAgB,EACvC,EAAO,CAAC,IAAc,EAAM,IAAK,CAAC,EAClC,EAAM,CAAC,IAAc,EAAM,IAAK,CAAC,EACjC,EAAO,CAAC,IAAc,EAAM,KAAM,CAAC,EACnC,EAAQ,CAAC,IAAc,EAAM,KAAM,CAAC,EACpC,EAAU,CAAC,IAAc,EAAM,KAAM,CAAC,EAE5C,SAAS,CAAW,EAAW,CAC7B,OAAQ,EAA6B,SAAW,IAGlD,SAAS,CAAU,CAAC,EAAsC,CACxD,QAAW,KAAU,OAAO,OAAO,EAAkB,CAAC,EACpD,QAAW,KAAS,GAAU,CAAC,EAG7B,IADa,EAAM,SAAW,QAAW,EAAM,SAAuB,IAC1D,CAAC,EAAM,SAAU,MAAO,UAAU,EAAM,WAAW,IAGnE,OAAO,KAGT,SAAS,CAAc,CAAC,EAA2B,CACjD,OAAO,EAAS,CAAO,EACpB,OAAO,CAAC,IAAS,EAAW,CAAI,CAAC,EACjC,IAAI,CAAC,IAAS,EAAS,CAAI,CAAC,EAG1B,SAAS,CAAkB,CAAC,EAGhC,CACD,IAAQ,OAAM,WAAY,EACpB,EAAQ,oBAAoB,IAC5B,EAAU,EAAW,CAAI,EACzB,EAAM,EAAe,CAAO,EAE5B,EAAM,CAAC,EAAe,IAC1B,KAAK,EAAM,QAAE,MAAM,EAAK,EAAM,OAAO,CAAC,CAAC,IAAI,IAEvC,EAAM,CACV,GACA,GAAG,EAAI,IAAI,CAAC,IAAS,EAAQ,CAAI,CAAC,EAClC,GACA,KAAK,EAAI,MAAM,KAAK,EAAK,IAAI,EAAY,GAAG,IAC5C,GACA,EAAI,SAAU,EAAK,CAAK,CAAC,EACzB,EAAI,WAAY,EAAU,EAAK,CAAO,EAAI,EAAI,aAAa,CAAC,EAC5D,EAAI,OAAQ,EAAI,OAAS,EAAI,KAAK,IAAI,EAAI,EAAI,MAAM,CAAC,EACrD,EACF,EAEA,QAAQ,IAAI,EAAI,KAAK;AAAA,CAAI,CAAC,EC/CrB,SAAS,CAAiB,CAAC,EAA0B,QAAQ,IAAI,oBAA6B,CACnG,GAAI,IAAQ,QAAa,EAAI,KAAK,IAAM,GAAI,MArBH,IAuBzC,IAAM,EAAU,OAAO,EAAI,KAAK,CAAC,EACjC,GAAI,CAAC,OAAO,UAAU,CAAO,GAAK,EAAU,GAAK,EAAU,IACzD,MAAU,MACR,qGACmC,KAAK,UAAU,CAAG,IACvD,EAEF,OAAO",
10
- "debugId": "BE91EE18CD33A91064756E2164756E21",
10
+ "debugId": "97E38DD84A148DCD64756E2164756E21",
11
11
  "names": []
12
12
  }
@@ -1,5 +1,5 @@
1
1
  // @bun
2
- import{$b as C9,Xb as j9,_b as Y3,_c as V9,cc as e,pc as K9,vc as Q9}from"./chunk-2cnawkke.js";import{fd as d3,hd as N3,kd as v9,ld as g9,md as G$,od as J$}from"./chunk-x5hj0mqp.js";import{Fd as A,Gd as y9,Hd as f9,Jd as w9,Kd as V$,rd as R9,wd as E9,yd as b9}from"./chunk-xymr3asa.js";import{Nd as N}from"./chunk-py1twqh8.js";import{Ff as o3,Qf as t3,Re as h3,Sf as n,Wf as s3,Xf as c9,Yf as p9,Zd as l,ae as A9,cg as y3,df as Z3,dg as i9,ee as B$,eg as G3,fg as n9,gg as t9,he as z$,hg as f3,ig as a,jf as V3,jg as I3,kf as g3,kg as u3,lf as q,of as $$,pf as a9,pg as e9,qf as r9,qg as Z$,re as W$,se as c3,sf as w,we as U3,wg as N$,xe as W3}from"./chunk-wevj4981.js";import{Bh as p,Dh as m,Sh as n3,ei as Y9,ii as B3,ji as J3,ki as z3}from"./chunk-0rhf4g12.js";import{qi as m9}from"./chunk-zv5qyrqg.js";import{Bi as v}from"./chunk-4t41m5f1.js";import{Hi as m3}from"./chunk-hj88dcss.js";import{Ki as X$,Li as p3,Oi as F3,Pi as l3,Si as K$}from"./chunk-z61dj480.js";import{ej as u9,jj as d9}from"./chunk-vnw91fe1.js";import{Bj as u,zj as k9}from"./chunk-ysc7ykss.js";import{Cj as O}from"./chunk-jx5zx48j.js";import{Ij as U$}from"./chunk-z9xxthp1.js";import{wk as i3}from"./chunk-zyhmn3hy.js";import{Dk as H3,Gk as y}from"./chunk-jx2mgvvt.js";import{Pk as v3}from"./chunk-gqgpwb88.js";import{_k as l9}from"./chunk-99a4e6zf.js";var L$="mcp",_$=/^[\x21\x23-\x5B\x5D-\x7E]+$/;class x extends e{status;constructor($,Z){super($);this.status=Z;this.name="McpToolError"}}class h extends Error{reason;constructor($,Z){super($);this.reason=Z;this.name="McpCallRefusedError"}}var a3=/^[A-Za-z0-9_-]{1,64}$/,x$=/:([A-Za-z_][A-Za-z0-9_]*)([?*+]?)/g,r3=4000,T=1e5,D$=/^(text\/|application\/([\w.+-]*\+)?(json|xml))/i,H9=new WeakMap;function r2($){return H9.get($)}class i{router;dispatcher;static token="router.mcp";plans=new Map;scopeTools=new Map;files;featureOn;constructor($,Z,z={}){this.router=$;this.dispatcher=Z;this.files=q$(z.files),this.featureOn=z.featureOn??W3;for(let[G,W]of Object.entries($.routes??{}))this.plans.set(G,O$(W)?this.planNative(G,W):this.plan(G,W));this.resolveScopes()}list($,Z){if(_3($),$.kind==="local")return this.descriptors(Z);let z=[];for(let[G,W]of this.plans){if(!W.remote||!this.grants($.principal,G))continue;if($9(W.remote,Z))z.push(W.remote)}return z}async available($,Z){let z=[];for(let G of this.list($,Z))if(await this.isOn(G))z.push(G);return z}descriptors($){let Z=[];for(let{descriptor:z}of this.plans.values())if($9(z,$))Z.push(z);return Z}get maxFileBytes(){return this.files.maxBytes}scopes(){return[...this.scopeTools].map(([$,{description:Z}])=>({name:$,description:Z}))}scopesFor($){return[...this.scopeTools].filter(([,{tools:Z}])=>Z.has($)).map(([Z])=>Z)}async execute($,Z,z,G,W={}){_3($);let X=this.plans.get(Z);if(X&&!await this.isOn(X.descriptor)){if($.kind==="remote")throw new h(`There is no tool named "${Z}".`,"unknown-tool");throw new x(`There is no tool named "${Z}".`,404)}if($.kind==="remote"){if(!X?.remote||!this.grants($.principal,Z))throw new h(`There is no tool named "${Z}".`,"unknown-tool");if(X.descriptor.requiresApproval&&W.approved!==!0)throw new h(`"${Z}" needs the user's approval, and this call does not have it.`,"approval-required");G=void 0}if(!X)throw Error(`McpRegistry: there is no tool named "${Z}".`);if(X.kind==="tool")return await this.executeNative(X,$,z,G,W);let Y=X,K=$.kind==="remote"?Y.remote:Y.descriptor,Q=K.inputSchema.safeParse(z);if(Q.ok===!1)throw new x(`Invalid arguments for "${Z}": ${Q.errors.join(", ")}`);let V=Q.value,H={caller:$,req:$.req,tool:K,input:V,ctx:G},U=await this.fillPath(Y,H),{path:F}=this.dispatcher.getRouteHandlerAndParams(new Request(`http://gemi.internal/api${U}`));if(F!==K.url)throw new x(`"${Z}" has nothing at ${U}.`,404);let D={};for(let I of Y.jsonKeys)if(V[I]!==void 0)D[I]=V[I];let _,P="";if(Y.fileFields.length>0)_=await this.formData(Y,D,H);else if(K.method==="GET")P=v$(D);else if(Y.jsonKeys.length>0)_=D;let M=this.router.credentials?await this.bind(Y,"the credentials",()=>this.router.credentials(H)):void 0,j={...M?{credentials:M}:{},...W.signal?{signal:W.signal}:{},...W.progress?{progress:W.progress}:{},...$.kind==="remote"?{identity:{user:$.principal.user,grant:{via:$.principal.via,id:$.principal.id,scopes:$.principal.scopes,...$.principal.clientId?{clientId:$.principal.clientId}:{}}}}:{}},k;try{let I=P?`${U}?${P}`:U;k=Object.keys(j).length>0?await this.dispatcher.dispatchAs($.req,K.method,I,_,j):await this.dispatcher.dispatchAs($.req,K.method,I,_)}catch(I){throw console.error(`[gemi/mcp] Dispatching "${Z}" failed:`,I),new x(`"${Z}" failed on the server.`,500)}if(!Y.result&&!K.outputSchema)return await X9(Z,k);return await this.project(Y,H,k)}async isOn($){return $.feature===void 0||await this.featureOn($.feature)===!0}plan($,Z){if(!a3.test($))throw Error(`McpRouter: "${$}" is not a valid tool name. A routes key is the tool's name as a model and an MCP client see it, used verbatim \u2014 letters, digits, "_" and "-", at most 64.`);let z=`McpRouter: "${$}" (${Z?.method} ${Z?.url})`;if(!(Z instanceof Object)||Z.__internal_brand!=="McpRoute")throw Error(`McpRouter: "${$}" is not a route or a tool. Declare it with this.fromApiRoute(...) or this.fromTool(...).`);let{method:G,url:W,meta:X}=Z;if(X.feature!==void 0&&(typeof X.feature!=="string"||X.feature===""))throw Error(`${z}: feature must be a feature key from app/features.`);if(W.startsWith("/__gemi__"))throw Error(`${z} is a framework route, not an app route.`);let Y=this.dispatcher.flatRoutes[W]?.[G];if(!Y)throw Error(`${z} names no route of this app. Expose a route by the path and verb it is mounted at.`);let K=[...W.matchAll(x$)].map(([,J,C])=>({name:J,modifier:C})),Q=X.params??{};for(let J of K)if(!(J.name in Q))throw Error(`${z}: the path param "${J.name}" must be bound or declared "input".`);for(let[J,C]of Object.entries(Q)){if(!K.some((g)=>g.name===J))throw Error(`${z}: "${J}" in params is not a param of the url.`);if(z9(C))E$(z,`params.${J}`,C);else Z9(z,`params.${J}`,C)}let V=[],H;if(X.input){if(H=X.input.toJSONSchema(),H.type!=="object"||!H.properties)throw Error(`${z}: input must be an s.object(...), the fields of the request body.`);V=Object.keys(H.properties)}let U=Object.entries(X.files??{}).map(([J,C])=>({name:J,binder:C}));for(let J of U)Z9(z,`files.${J.name}`,J.binder);if(X.result!==void 0&&typeof X.result!=="function")throw Error(`${z}: result must be a function.`);if(X.output!==void 0&&typeof X.output?.safeParse!=="function")throw Error(`${z}: output must be a schema, built with s.`);if(X.title!==void 0&&(typeof X.title!=="string"||X.title===""))throw Error(`${z}: title must be a non-empty string.`);let F=G9(z,G,X.annotations);if(U.length>0&&G==="GET")throw Error(`${z}: a GET has no body to carry a file.`);let D={},_=(J,C)=>{if(J in D)throw Error(`${z}: "${J}" is the input key of two params or files, and the model can only send one.`);D[J]=C},P=new Map,M=new Map;for(let J of K){let C=Q[J.name];if(C==="input"){let g=p.string().describe(`The ":${J.name}" segment of the url.`);_(J.name,J.modifier==="?"||J.modifier==="*"?g.optional():g)}else if(z9(C)){let g=C.as??J.name;_(g,C.input),M.set(J.name,{key:g,param:C})}else P.set(J.name,C)}let j={};for(let J of U)if(J.binder==="input")_(J.name,p.string().describe("The id of an attachment the user uploaded or a tool produced (gemi_att_\u2026), whose file is sent as this field.")),j[J.name]=this.remoteFileSchema();let k=[...Object.keys(D),...U.map((J)=>J.name)];for(let J of new Set(k))if(V.includes(J))throw Error(`${z}: "${J}" is both an input field and a param or file, and the model can only send one.`);let I=Object.freeze({kind:"route",name:$,description:X.description,method:G,url:W,inputSchema:W9(X.input,H,p.object(D)),...X.output?{outputSchema:X.output}:{},...X.title?{title:X.title}:{},annotations:F,tags:Object.freeze([...X.tags??[]]),requiresApproval:X.requiresApproval===!0,...X.feature!==void 0?{feature:X.feature}:{},...Y.source?{source:Y.source}:{}}),r=!U.every((J)=>J.binder==="input")?null:U.length===0?I:Object.freeze({...I,inputSchema:W9(X.input,H,p.object(f$(D,Object.keys(j))),j)});return{kind:"route",descriptor:I,remote:r,params:K,paramBinders:P,modelParams:M,fileFields:U,jsonKeys:V,...X.result?{result:X.result}:{}}}remoteFileSchema(){let{maxBytes:$,fetch:Z}=this.files,z={name:{type:"string",description:"The file's name, like report.pdf."},mimeType:{type:"string",description:"The file's media type, like application/pdf."},data:{type:"string",contentEncoding:"base64",description:`The file's bytes, base64-encoded (RFC 4648, standard alphabet). At most ${$} bytes decoded.`}};if(Z)z.url={type:"string",format:"uri",description:"An https URL the server downloads the file from, instead of data."};let G={type:"object",description:Z?"A file, sent as base64 in data or fetched from url: exactly one of the two.":"A file, sent as base64 in data.",properties:z,required:["name","mimeType"],additionalProperties:!1},W=Object.keys(z),X=(Y)=>{if(typeof Y!=="object"||Y===null||Array.isArray(Y))return{ok:!1,errors:["a file must be an object"]};let K=[],Q={};for(let V of Object.keys(Y))if(!W.includes(V))K.push(`a file has no field "${V}"`);for(let V of W){let H=Y[V];if(H===void 0||H===null){if(V==="name"||V==="mimeType")K.push(`a file needs "${V}"`);continue}if(typeof H!=="string")K.push(`a file's "${V}" must be a string`);else Q[V]=H}return K.length>0?{ok:!1,errors:K}:{ok:!0,value:Q}};return{toJSONSchema:()=>G,safeParse:X,parse(Y){let K=X(Y);if(K.ok===!1)throw Error(K.errors.join(", "));return K.value}}}planNative($,Z){if(!a3.test($))throw Error(`McpRouter: "${$}" is not a valid tool name. A routes key is the tool's name as a model and an MCP client see it, used verbatim \u2014 letters, digits, "_" and "-", at most 64.`);let z=`McpRouter: "${$}" (a native tool)`,{tool:G,meta:W={}}=Z;if(!(G instanceof Object)||typeof G.name!=="string")throw Error(`${z} is not an AgentTool. Pass one built with AgentTool.create(...).`);if(G.answeredBy==="client"||typeof G.execute!=="function")throw Error(`${z}: "${G.name}" is answered by the client, and only a tool the server runs can be called through the registry.`);if(typeof G.inputSchema==="function")throw Error(`${z}: "${G.name}" resolves its input schema per run, and the registry lists one schema to every caller. Give it a fixed inputSchema.`);if(typeof G.inputSchema?.safeParse!=="function")throw Error(`${z}: its inputSchema must be a schema, built with s.`);if(typeof W!=="object"||W===null)throw Error(`${z}: the meta must be an object.`);if(W.description!==void 0&&(typeof W.description!=="string"||W.description.trim()===""))throw Error(`${z}: description must be a non-empty string.`);if(W.title!==void 0&&(typeof W.title!=="string"||W.title===""))throw Error(`${z}: title must be a non-empty string.`);if(W.tags!==void 0&&(!Array.isArray(W.tags)||W.tags.some((Q)=>typeof Q!=="string")))throw Error(`${z}: tags must be an array of strings.`);if(W.requiresApproval===!1&&G.requiresApproval)throw Error(`${z}: "${G.name}" requires approval, and requiresApproval: false would run it without asking. Leave it out, or register a tool that does not ask.`);let X=W.remote;if(X!==void 0){if(typeof X!=="object"||X===null||typeof X.context!=="function")throw Error(`${z}: remote must be { context(call) }, building the AgentContext a remote call runs with.`);if(X.progress!==void 0&&typeof X.progress!=="function")throw Error(`${z}: remote.progress must be a function.`)}let Y=W.description??G.description;if(typeof Y!=="string"||Y.trim()==="")throw Error(`${z} needs a description: the tool's own, or the meta's.`);let K=Object.freeze({kind:"tool",name:$,description:Y,inputSchema:G.inputSchema,...G.outputSchema?{outputSchema:G.outputSchema}:{},...W.title?{title:W.title}:{},annotations:G9(z,void 0,W.annotations),tags:Object.freeze([...W.tags??[]]),requiresApproval:G.requiresApproval||W.requiresApproval===!0});return{kind:"tool",descriptor:K,remote:X?K:null,tool:G,meta:W}}nativeTool($){let Z=this.plans.get($);if(Z?.kind!=="tool")throw Error(`McpRegistry: there is no native tool named "${$}".`);return Z.tool}startNative($,Z,z,G){let W=this.plans.get(Z);if(W?.kind!=="tool")throw Error(`McpRegistry: there is no native tool named "${Z}".`);if($===void 0)return W.tool.execute(z,G);if(_3($),$.kind!=="local")throw Error("McpRegistry: startNative is for a local caller. A remote call goes through execute().");let X=W.descriptor.inputSchema.safeParse(z);if(X.ok===!1)throw new x(`Invalid arguments for "${Z}": ${X.errors.join(", ")}`);return this.runNative(W,{caller:$,req:$.req,tool:W.descriptor,input:X.value},G)}runNative($,Z,z){let G={...z};return H9.set(G,{...Z,ctx:G}),$.tool.execute(Z.input,G)}async executeNative($,Z,z,G,W){let{name:X}=$.descriptor,Y=$.descriptor.inputSchema.safeParse(z);if(Y.ok===!1)throw new x(`Invalid arguments for "${X}": ${Y.errors.join(", ")}`);let K={caller:Z,req:Z.req,tool:$.descriptor,input:Y.value},Q=(I,L3)=>{if(!W.progress)return;let r;try{r=$.meta.remote?.progress?$.meta.remote.progress(I,L3):j$(I,L3)}catch(J){console.error(`[gemi/mcp] The progress mapping of "${X}" failed:`,J);return}if(r)W.progress(r)};if(Z.kind==="local"){if(!G)throw Error(`McpRegistry: "${X}" is a native tool, which runs with the tool context of an agent call, and none was passed to execute().`);return await e3(this.runNative($,{...K,ctx:G},G),Q)}let V=$.meta.remote,H=await this.bind($,"the remote context",()=>V.context(K));if(typeof H!=="object"||H===null)throw console.error(`[gemi/mcp] The remote context of "${X}" is not an object:`,H),new x(`"${X}" failed on the server.`,500);let U=$.tool.timeoutMs,F=[...W.signal?[W.signal]:[],...U!==void 0?[AbortSignal.timeout(U)]:[]],D=F.length===0?new AbortController().signal:F.length===1?F[0]:AbortSignal.any(F),_=C$($,H,D),P;try{P=await e3(this.runNative($,{...K,ctx:_},_),Q,D)}catch(I){if(D.aborted&&I===D.reason){if(W.signal?.aborted)throw new x(`"${X}" was cancelled.`,499);throw new x(`"${X}" did not finish within ${U} ms.`,504)}if(I instanceof x)throw I;if(I instanceof e||I instanceof h)throw new x(I.message);throw console.error(`[gemi/mcp] "${X}" failed for a remote caller:`,I),new x(`"${X}" failed on the server.`,500)}let M=(I)=>{return console.error(`[gemi/mcp] "${X}" ${I}`),new x(`"${X}" failed on the server.`,500)};if(K9(P))throw M("answered a job handle, and a remote call has no background jobs.");let j=P;if($.descriptor.outputSchema){let I=$.descriptor.outputSchema.safeParse(j);if(I.ok===!1)throw M(`answered what its output schema refuses: ${I.errors.join(", ")}`);j=I.value}if(j===void 0)return null;if(typeof j==="string")return j.length>T?`${j.slice(0,T)}\u2026 [cut at ${T} of ${j.length} characters]`:j;let k=JSON.stringify(j);if(k!==void 0&&k.length>T)return`${k.slice(0,T)}\u2026 [cut at ${T} of ${k.length} characters]`;return j}async fillPath($,Z){let{input:z,req:G}=Z,W=$.descriptor.url;for(let X of $.params){let Y=$.paramBinders.get(X.name),K=$.modelParams.get(X.name),Q;if(Y||K){if(Q=K?await this.bind($,`the param "${X.name}"`,()=>K.param.bind(z[K.key],G,Z),{refusals:!0}):await this.bind($,`the param "${X.name}"`,()=>Y(G,Z)),Q===void 0||Q===null||Q==="")throw console.error(`[gemi/mcp] The ${K?"resolver":"binder"} for "${X.name}" of "${$.descriptor.name}" returned ${JSON.stringify(Q)}.`),new x(`"${$.descriptor.name}" failed on the server.`,500)}else Q=z[X.name];let V=`:${X.name}${X.modifier}`;if(Q===void 0||Q===null||Q===""){if(X.modifier!=="?"&&X.modifier!=="*")throw new x(`"${X.name}" of "${$.descriptor.name}" must not be empty.`);W=W.replace(`/${V}`,"");continue}W=W.replace(V,w$($.descriptor.name,X,String(Q)))}return W}async formData($,Z,z){let{input:G,ctx:W}=z,X=$.descriptor.name;if(z.caller.kind==="remote"){let K=new FormData;for(let[Q,V]of Object.entries(Z))x3(K,Q,V);for(let Q of $.fileFields)K.append(Q.name,await this.remoteFile(X,Q.name,G[Q.name]));return K}if(!W)throw Error(`McpRegistry: "${X}" sends a file, which is resolved through the tool context's attachments, and none was passed to execute().`);let Y=new FormData;for(let[K,Q]of Object.entries(Z))x3(Y,K,Q);for(let K of $.fileFields){let Q=K.binder==="input"?G[K.name]:await this.bind($,`the file "${K.name}"`,()=>K.binder(W,z));if(typeof Q!=="string"||Q==="")throw new x(`"${X}" needs a file for "${K.name}", and this turn has none. Ask the user to attach one.`);Y.append(K.name,await W.attachments.file(Q))}return Y}async remoteFile($,Z,z){let G=(H)=>new x(`"${Z}" of "${$}" ${H}`,400),W=z,{maxBytes:X,fetch:Y}=this.files;if(!T$(W.name))throw G("needs a name of 1 to 255 characters, without control characters or slashes.");if(!M$.test(W.mimeType))throw G(`has a mimeType that is not a media type: "${W.mimeType.slice(0,100)}".`);let K=typeof W.data==="string",Q=typeof W.url==="string";if(K===Q)throw G(Y?"needs exactly one of data or url.":"needs its bytes, base64, in data.");if(K){let H=W.data.replace(/\s+/g,"");if(Math.floor(H.length*3/4)-R$(H)>X)throw G(`is larger than the ${X} bytes a file may be.`);if(H.length%4!==0||!k$.test(H))throw G("has data that is not base64 (RFC 4648, standard alphabet, padded).");return new File([Buffer.from(H,"base64")],W.name,{type:W.mimeType})}if(!Y)throw G("cannot be fetched from a URL here. Send its bytes, base64, in data.");let V;try{V=new URL(W.url)}catch{throw G("has a url that is not a URL.")}if(V.protocol!=="https:")throw G("can only be fetched from an https URL.");try{let H=await Y9(V.href,{...Y,maxSize:Math.min(Y.maxSize??X,X),redirect:"follow"});if(!H.ok)throw G(`could not be fetched: ${V.host} answered ${H.status}.`);let U=await H.arrayBuffer();return new File([U],W.name,{type:W.mimeType})}catch(H){if(H instanceof x)throw H;throw G(`could not be fetched from ${V.host}: ${H instanceof Error?H.message:"failed"}.`)}}grants($,Z){for(let z of $.scopes??[])if(this.scopeTools.get(z)?.tools.has(Z))return!0;return!1}resolveScopes(){let $=this.router.scopes;if($===void 0){this.scopeTools.set(L$,{description:"Use this app's tools as you",tools:new Set(this.plans.keys())});return}if(typeof $!=="object"||$===null)throw Error("McpRouter: scopes must be an object of scope names.");let Z=new Set([...this.plans.values()].flatMap(({descriptor:z})=>z.tags));for(let[z,G]of Object.entries($)){let W=`McpRouter: scope "${z}"`;if(!_$.test(z))throw Error(`${W} is not a valid OAuth scope: printable ASCII, no spaces or quotes.`);if(typeof G?.description!=="string"||G.description==="")throw Error(`${W} needs a description: it is what a consent screen shows.`);let X=new Set;for(let Y of G.tags??[]){if(!Z.has(Y))throw Error(`${W} names the tag "${Y}", which no tool has.`);for(let[K,{descriptor:Q}]of this.plans)if(Q.tags.includes(Y))X.add(K)}for(let Y of G.names??[]){if(!this.plans.has(Y))throw Error(`${W} names "${Y}", which is no tool.`);X.add(Y)}if(X.size===0)throw Error(`${W} reaches no tool. Give it tags or names.`);this.scopeTools.set(z,{description:G.description,tools:X})}}async project($,Z,z){let{name:G,outputSchema:W}=$.descriptor;if(z.status<200||z.status>=300)return await X9(G,z);let X=(U,F)=>{if(F===void 0)console.error(`[gemi/mcp] "${G}" ${U}`);else console.error(`[gemi/mcp] "${G}" ${U}`,F);return new x(`"${G}" failed on the server.`,500)},Y=z.headers.get("Content-Type"),K=await z.text(),Q=null;if(K!=="")try{Q=JSON.parse(K)}catch{throw X(`answered ${Y??"a body with no content-type"} that is not JSON, and its result or output needs JSON.`)}let V=Q;if($.result)try{V=await $.result(Q,Z)}catch(U){throw X("failed in its result projection:",U)}if(W){let U=W.safeParse(V);if(U.ok===!1)throw X(`answered what its output schema refuses: ${U.errors.join(", ")}`);V=U.value}if(V===void 0)return null;let H=JSON.stringify(V);if(H!==void 0&&H.length>T)return`${H.slice(0,T)}\u2026 [cut at ${T} of ${H.length} characters]`;return V}async bind($,Z,z,G={}){try{return await z()}catch(W){if(G.refusals&&W instanceof e)throw W;throw console.error(`[gemi/mcp] Binding ${Z} of "${$.descriptor.name}" failed:`,W),new x(`"${$.descriptor.name}" failed on the server.`,500)}}}function O$($){return $ instanceof Object&&$.__internal_brand==="McpTool"}function A$($){return typeof $==="object"&&$!==null&&typeof $.next==="function"&&Symbol.asyncIterator in $}async function e3($,Z,z){let G;if(z)G=new Promise((X,Y)=>{if(z.aborted)Y(z.reason);else z.addEventListener("abort",()=>Y(z.reason),{once:!0})}),G.catch(()=>{});let W=(X)=>G?Promise.race([X,G]):X;if(!A$($))return await W(Promise.resolve($));try{let X=0,Y=await W($.next());while(!Y.done)Z(Y.value,++X),Y=await W($.next());return Y.value}catch(X){throw $.return(void 0).catch(()=>{}),X}}function j$($,Z){if(typeof $==="string")return{progress:Z,message:$};if(typeof $==="object"&&$!==null){let{progress:z,total:G,message:W}=$;if(typeof z==="number"&&Number.isFinite(z))return{progress:z,...typeof G==="number"?{total:G}:{},...typeof W==="string"?{message:W}:{}};if(typeof W==="string")return{progress:Z,message:W}}return{progress:Z}}function C$($,Z,z){let G=$.descriptor.name,W=`mcp_${crypto.randomUUID()}`,X=`mcp_call_${crypto.randomUUID()}`,Y=(Q)=>async()=>{throw new e(`"${G}" was called by a remote MCP client, which has no ${Q}.`,{retryable:!1})},K={put:Y("attachment store"),get:Y("attachment store"),read:Y("attachment store"),file:Y("attachment store")};return{context:Z,body:{},runId:W,toolCallId:X,signal:z,step:1,depth:0,resumed:!1,attachments:K,turn:Object.freeze({attachments:Object.freeze([])}),runAgent:Y("agent run to nest a sub-agent in"),generateImage:Y("attachment store to put an image in"),editImage:Y("attachment store to put an image in"),generate:(Q)=>V9({...Q,signal:Q.signal?AbortSignal.any([z,Q.signal]):z},{origin:{mcp:G,runId:W,toolCallId:X}}),jobs:Q9({jobs:void 0,threadId:void 0,runId:W,toolCallId:X,toolName:G,depth:0,async:$.tool.async,attachments:null})}}function _3($){if($?.kind==="local"&&$.req)return;if($?.kind==="remote"&&$.req&&$.principal?.user&&typeof $.principal.id==="string"&&Array.isArray($.principal.scopes))return;throw Error('McpRegistry: a caller is { kind: "local", req } or { kind: "remote", req, principal }, with the principal a caller resolver verified.')}function $9($,Z){if(Z?.names&&!Z.names.includes($.name))return!1;if(Z?.tags&&!$.tags.some((z)=>Z.tags.includes(z)))return!1;return!0}var S$=10485760;function q$($){let Z=$?.maxBytes??S$;if(!Number.isSafeInteger(Z)||Z<=0)throw Error("McpRegistry: files.maxBytes must be a positive whole number of bytes.");let z=$?.fetchUrls===!0?{}:typeof $?.fetchUrls==="object"&&$.fetchUrls!==null?$.fetchUrls:null;return{maxBytes:Z,fetch:z}}function T$($){if($.length===0||$.length>255)return!1;for(let Z of $){let z=Z.codePointAt(0);if(z<32||z===127||Z==="/"||Z==="\\")return!1}return!0}var M$=/^[A-Za-z0-9][A-Za-z0-9!#$&^_.+-]{0,126}\/[A-Za-z0-9][A-Za-z0-9!#$&^_.+-]{0,126}(\s*;.{0,200})?$/,k$=/^[A-Za-z0-9+/]*={0,2}$/;function R$($){return $.endsWith("==")?2:$.endsWith("=")?1:0}function Z9($,Z,z){if(z!=="input"&&typeof z!=="function")throw Error(`${$}: ${Z} must be a function or "input".`)}function z9($){return $ instanceof Object&&$.__internal_brand==="McpModelParam"}function E$($,Z,z){if(z.as!==void 0&&(typeof z.as!=="string"||z.as===""))throw Error(`${$}: ${Z}.as must be a non-empty string.`);let G=z.input;if(typeof G?.safeParse!=="function"||typeof G.toJSONSchema!=="function")throw Error(`${$}: ${Z}.input must be a schema, built with s.`);if(typeof z.bind!=="function")throw Error(`${$}: ${Z}.bind must be a function.`)}var b$=new Set(["readOnlyHint","destructiveHint","idempotentHint","openWorldHint"]);function y$($){switch($){case"GET":return{readOnlyHint:!0};case"DELETE":return{destructiveHint:!0};case"PUT":return{idempotentHint:!0};default:return{}}}function G9($,Z,z){if(z!==void 0&&(typeof z!=="object"||z===null))throw Error(`${$}: annotations must be an object of hints.`);let G=Z?y$(Z):{};for(let[W,X]of Object.entries(z??{})){if(!b$.has(W))throw Error(`${$}: "${W}" is not a tool annotation. Use readOnlyHint, destructiveHint, idempotentHint or openWorldHint.`);if(X===void 0)continue;if(typeof X!=="boolean")throw Error(`${$}: annotations.${W} must be true or false.`);G[W]=X}if(G.readOnlyHint===!0&&(G.destructiveHint||G.idempotentHint))throw Error(`${$} is read-only${z?.readOnlyHint?"":` (a ${Z})`} and also ${G.destructiveHint?"destructive":"idempotent"}, which only a tool that is not read-only can be. Set readOnlyHint: false if it changes something.`);return Object.freeze(G)}function W9($,Z,z,G={}){let W=z.toJSONSchema(),X=Object.fromEntries(Object.entries(G).map(([Q,V])=>[Q,V.toJSONSchema()])),Y={...Z??{},type:"object",properties:{...Z?.properties??{},...W.properties,...X},required:[...Z?.required??[],...W.required??[],...Object.keys(G)],additionalProperties:!1},K=(Q)=>{if(typeof Q!=="object"||Q===null||Array.isArray(Q))return{ok:!1,errors:["expected an object"]};let V=[],H={};if($){let F=$.safeParse(Q);if(F.ok===!1)V.push(...F.errors);else H={...F.value}}let U=z.safeParse(Q);if(U.ok===!1)V.push(...U.errors);else H={...H,...U.value};for(let[F,D]of Object.entries(G)){let _=Q[F];if(_===void 0){V.push(`"${F}" is required`);continue}let P=D.safeParse(_);if(P.ok===!1)V.push(...P.errors.map((M)=>`${F}: ${M}`));else H[F]=P.value}return V.length>0?{ok:!1,errors:V}:{ok:!0,value:H}};return{toJSONSchema:()=>Y,safeParse:K,parse(Q){let V=K(Q);if(V.ok===!1)throw Error(V.errors.join(", "));return V.value}}}function f$($,Z){return Object.fromEntries(Object.entries($).filter(([z])=>!Z.includes(z)))}function w$($,Z,z){let G=Z.modifier==="*"||Z.modifier==="+"?z.split("/"):[z];if(G.some((W)=>W==="."||W===".."))throw new x(`"${z}" is not a valid value for "${Z.name}" of "${$}".`);return G.map(encodeURIComponent).join("/")}function x3($,Z,z){if(z===void 0||z===null)return;if(Array.isArray(z)){for(let G of z)x3($,Z,G);return}$.append(Z,typeof z==="object"?JSON.stringify(z):String(z))}function v$($){let Z=new URLSearchParams,z=(G,W)=>{if(W===void 0||W===null)return;if(Array.isArray(W)){for(let X of W)z(G,X);return}Z.append(G,typeof W==="object"?JSON.stringify(W):String(W))};for(let[G,W]of Object.entries($))z(G,W);return Z.toString()}async function X9($,Z){if(Z.status>=200&&Z.status<300){let G=Z.headers.get("Content-Type");if(G&&!D$.test(G)){let X=(await Z.arrayBuffer()).byteLength;return`"${$}" answered with ${X} bytes of ${G}, which is not shown.`}let W=await Z.text();if(W==="")return null;if(W.length>T)return`${W.slice(0,T)}\u2026 [cut at ${T} of ${W.length} characters]`;try{return JSON.parse(W)}catch{return W}}let z=await Z.text();if(Z.status>=400&&Z.status<500){let G=z.length>r3?`${z.slice(0,r3)}\u2026`:z;throw new x(`"${$}" was refused with ${Z.status}${G?`: ${G}`:"."}`,Z.status)}if(Z.status<500)console.error(`[gemi/mcp] "${$}" answered ${Z.status}${Z.headers.get("Location")?` to ${Z.headers.get("Location")}`:""}, which a tool call cannot follow.`);throw new x(`"${$}" failed on the server.`,Z.status)}import{createHash as g$,randomBytes as h$,timingSafeEqual as m$}from"crypto";function D3($){let Z=$.headers.get("authorization");if(!Z)return null;let z=/^Bearer[ ]+([\x21-\x7e]+)$/i.exec(Z.trim());return z?z[1]:null}class u${options;name="api-key";constructor($){this.options=$;if(typeof $?.prefix!=="string"||!/^[A-Za-z0-9_-]{3,32}$/.test($.prefix))throw Error('McpApiKeyResolver: prefix is required: 3 to 32 letters, digits, _ or -, like "myapp_mcp_".');if(typeof $.verify!=="function")throw Error("McpApiKeyResolver: verify must be a function that looks a key up.")}static generate($){return`${$}${h$(32).toString("base64url")}`}static hash($){return g$("sha256").update($).digest("hex")}static hashesMatch($,Z){let z=Buffer.from($),G=Buffer.from(Z);return z.length===G.length&&m$(z,G)}async resolve($){let Z=D3($);if(!Z?.startsWith(this.options.prefix))return null;let z=await this.options.verify(Z,$);if(!z)return{ok:!1,error:"invalid_token",description:"The API key is not valid."};if(!z.user||typeof z.id!=="string"||z.id===""||!Array.isArray(z.scopes))throw Error("McpApiKeyResolver: verify must answer { user, id, scopes } for a key it knows, or null.");return{ok:!0,principal:{user:z.user,via:this.name,id:z.id,scopes:[...z.scopes]}}}}import{createHash as S9,randomBytes as N9}from"crypto";async function O3($,Z){let z=d$();if(!z)return null;let G=await z.consume($,Z);return G.allowed?null:Math.max(1,Math.ceil(G.retryAfter/1000))}function d$(){try{let $=y();return $.bound(l)?$.make(l):null}catch{return null}}var A3=["2026-07-28"],X3=["2025-11-25","2025-06-18","2025-03-26"],j3=[...A3,...X3],C3="io.modelcontextprotocol/protocolVersion",S3="io.modelcontextprotocol/clientCapabilities";var q3="io.modelcontextprotocol/serverInfo",L={ParseError:-32700,InvalidRequest:-32600,MethodNotFound:-32601,InvalidParams:-32602,InternalError:-32603,HeaderMismatch:-32020,MissingRequiredClientCapability:-32021,UnsupportedProtocolVersion:-32022};class B extends Error{code;data;status;constructor($,Z,z,G=200){super(Z);this.code=$;this.data=z;this.status=G;this.name="JsonRpcError"}}function R($,Z){return{jsonrpc:"2.0",id:$,error:{code:Z.code,message:Z.message,...Z.data!==void 0?{data:Z.data}:{}}}}function U9($){if(Array.isArray($))throw new B(L.InvalidRequest,"Batched requests are not supported.",void 0,400);if(typeof $!=="object"||$===null||$.jsonrpc!=="2.0")throw new B(L.InvalidRequest,"Not a JSON-RPC 2.0 message.",void 0,400);let Z=$,z=Z.id,G=typeof z==="string"||typeof z==="number"&&Number.isFinite(z);if(typeof Z.method==="string"){if(Z.params!==void 0&&(typeof Z.params!=="object"||Z.params===null||Array.isArray(Z.params)))throw new B(L.InvalidRequest,"params must be an object.",void 0,400);if(z===void 0)return{kind:"notification",message:Z};if(!G)throw new B(L.InvalidRequest,"id must be a string or a number.",void 0,400);return{kind:"request",message:Z}}if(G&&(("result"in Z)||("error"in Z)))return{kind:"response",message:Z};throw new B(L.InvalidRequest,"Not a JSON-RPC request, notification or response.",void 0,400)}function T3($,Z){let z=$.outputSchema?.toJSONSchema(),G={...$.annotations,...$.title&&!Z?{title:$.title}:{}};return{name:$.name,...$.title?{title:$.title}:{},description:$.description,inputSchema:$.inputSchema.toJSONSchema(),...z&&(Z||z.type==="object")?{outputSchema:z}:{},...Object.keys(G).length>0?{annotations:G}:{}}}function S($){return typeof $==="object"&&$!==null&&!Array.isArray($)}function J9($){let Z=/^=\?base64\?([A-Za-z0-9+/]*={0,2})\?=$/.exec($);if(!Z)return $;try{let z=Buffer.from(Z[1],"base64");return new TextDecoder("utf-8",{fatal:!0}).decode(z)}catch{return null}}import{createHmac as c$,timingSafeEqual as p$}from"crypto";function M3($,Z,z){let G=Buffer.from(JSON.stringify(z)).toString("base64url");return`${Z}.${G}.${F9($,Z,G).toString("base64url")}`}function k3($,Z,z,G=Date.now()){if(typeof z!=="string"||z.length>8192)return null;let W=z.split(".");if(W.length!==3||W[0]!==Z)return null;let[,X,Y]=W,K=Buffer.from(Y,"base64url"),Q=F9($,Z,X);if(K.length!==Q.length||!p$(K,Q))return null;let V;try{V=JSON.parse(Buffer.from(X,"base64url").toString("utf8"))}catch{return null}if(typeof V!=="object"||V===null)return null;if(typeof V.exp!=="number"||V.exp<=G)return null;return V}function F9($,Z,z){return c$("sha256",Y3($)).update(`${Z}.${z}`).digest()}var R3="gemi.mcp.request-state.v1",B9="gemi.mcp.session.v1",i$=86400000,P9=600000,I9="gemi_approval",E3=2000,l$={limit:600,window:60},n$={limit:30,window:60};class $3{registry;static token="router.mcp.http";endpoint;resolvers;context;allowedOrigins;rateLimit;maxBodyBytes;serverInfo;instructions;nonces;approvalTimeoutMs;feature;featureOn;pending=new Map;inflight=new Map;constructor($,Z,z={}){this.registry=$;if(typeof Z.url!=="string")throw Error(`route.mcp.remote.url is required: the endpoint's canonical URL, like "https://example.com/mcp".`);this.endpoint=o$(Z.url);let G=Z.resolvers??[];if(!Array.isArray(G)||G.length===0)throw Error("route.mcp.remote is enabled without a caller resolver. Configure route.mcp.remote.resolvers \u2014 an McpOAuthServer, an McpApiKeyResolver, or your own \u2014 or leave the endpoint off. Without one every request would be refused, or answered as nobody.");for(let W of G)if(typeof W?.resolve!=="function"||typeof W.name!=="string"||W.name==="")throw Error("route.mcp.remote.resolvers: each resolver needs a name and a resolve().");if(this.resolvers=G,Y3(R3),this.context={resource:this.resource,registry:$},this.allowedOrigins=new Set((Z.allowedOrigins??[]).map((W)=>{if(new URL(W).origin!==W)throw Error(`route.mcp.remote.allowedOrigins: "${W}" is not an origin (scheme://host[:port]).`);return W})),this.allowedOrigins.add(this.endpoint.origin),this.rateLimit=Z.rateLimit===!1?!1:Z.rateLimit??l$,this.maxBodyBytes=Z.maxBodyBytes??Math.ceil($.maxFileBytes*1.4)+1048576,this.serverInfo={name:Z.server?.name??"gemi",version:Z.server?.version??"1.0.0"},this.instructions=Z.server?.instructions,this.nonces=Z.nonces??new j9,this.approvalTimeoutMs=Z.approvalTimeoutMs??P9,Z.feature!==void 0){if(typeof Z.feature!=="string"||Z.feature==="")throw Error("route.mcp.remote.feature must be a feature key from app/features.");this.feature=Z.feature}this.featureOn=z.featureOn??W3;for(let W of G)W.boot?.(this.context)}get resource(){return this.endpoint.href.replace(/\/$/,"")}async handle($){let Z=new URL($.url);if(Z.host!==this.endpoint.host)return null;if(this.feature!==void 0){if(!this.ownsPath(Z.pathname))return null;if(await this.featureOn(this.feature)!==!0)return null}for(let W of this.resolvers){let X=await W.handle?.($,this.context);if(X)return X}if(Z.pathname!==this.endpoint.pathname)return null;let z=$.headers.get("origin");if(z!==null&&!this.allowedOrigins.has(z))return f(R(null,new B(L.InvalidRequest,"Origin not allowed.")),403);let G=z?s$(z):{};if($.method==="OPTIONS")return new Response(null,{status:204,headers:{...G,"Access-Control-Allow-Methods":"POST","Access-Control-Allow-Headers":"Authorization, Content-Type, Accept, MCP-Protocol-Version, Mcp-Session-Id, Mcp-Method, Mcp-Name, Last-Event-ID","Access-Control-Max-Age":"600"}});if($.method!=="POST")return L9(new Response(null,{status:405,headers:{Allow:"POST, OPTIONS"}}),G);return L9(await this.post($),G)}ownsPath($){let Z=this.endpoint.pathname.replace(/\/$/,"");return $===this.endpoint.pathname||$===Z||$.startsWith(`${Z}/`)||$.startsWith("/.well-known/")}async post($){let Z=null;for(let Y of this.resolvers){let K=await Y.resolve($,this.context);if(K===null)continue;if(K.ok===!1)return await this.failedAttempt($)??this.unauthorized(K.description);Z={...K.principal,via:Y.name};break}if(!Z)return(D3($)!==null?await this.failedAttempt($):null)??this.unauthorized();let z=await this.spend(Z);if(z)return z;let G=$.headers.get("content-type")??"";if(!/^application\/json\s*(;|$)/i.test(G))return new Response("Content-Type must be application/json.",{status:415});let W;try{W=JSON.parse(await t$($,this.maxBodyBytes))}catch(Y){if(Y instanceof Q3)return f(R(null,new B(L.InvalidRequest,`The request is larger than ${this.maxBodyBytes} bytes.`)),413);return f(R(null,new B(L.ParseError,"Parse error.")),400)}let X=new m($,{},"api",this.endpoint.pathname);return await v.run(X,async()=>{try{return await this.dispatch($,X,Z,W)}catch(Y){if(Y instanceof B){let K=S(W)&&(typeof W.id==="string"||typeof W.id==="number")?W.id:null;return f(R(K,Y),Y.status)}return console.error("[gemi/mcp] The MCP endpoint failed:",Y),f(R(null,new B(L.InternalError,"Internal error.")),500)}},{user:Z.user})}async dispatch($,Z,z,G){let W=U9(G),X={kind:"remote",req:Z,principal:z};if(W.kind==="response"){let _=this.session($,z),P=this.pending.get(String(W.message.id));if(P&&P.session===_.id)this.pending.delete(String(W.message.id)),P.resolve(W.message);return new Response(null,{status:202})}let{message:Y}=W,K=Y.params??{},Q=S(K._meta)?K._meta:{};if(typeof Q[C3]==="string"){if(this.checkModernHeaders($,Y,Q[C3]),W.kind==="notification")return new Response(null,{status:202});return await this.respond(Y,async(_,P)=>this.modern({principal:z,caller:X,message:Y,params:K,era:{modern:!0},stream:_,signal:P}),x9(K),$.signal)}if(Y.method==="initialize"){if(W.kind!=="request")throw new B(L.InvalidRequest,"initialize is a request.",void 0,400);return this.initialize(W.message,K,z)}let V=this.session($,z),H=$.headers.get("mcp-protocol-version");if(H!==null&&H!==V.state.v)throw new B(L.InvalidRequest,`MCP-Protocol-Version ${H} is not the session's ${V.state.v}.`,void 0,400);if(W.kind==="notification"){if(Y.method==="notifications/cancelled"){let _=K.requestId;this.inflight.get(`${V.id}:${String(_)}`)?.abort()}return new Response(null,{status:202})}let U=`${V.id}:${String(Y.id)}`,F=new AbortController;this.inflight.set(U,F);let D=AbortSignal.any([F.signal,$.signal]);try{return await this.respond(Y,async(_,P)=>this.legacy({principal:z,caller:X,message:Y,params:K,era:{modern:!1,session:V.state,sessionId:V.id},stream:_,signal:P}),x9(K)||r$(this.registry,Y,V.state),D,()=>this.inflight.delete(U))}catch(_){throw this.inflight.delete(U),_}}async modern($){switch($.message.method){case"server/discover":return this.complete({supportedVersions:j3,capabilities:{tools:{}},...this.instructions?{instructions:this.instructions}:{},ttlMs:60000,cacheScope:"private"});case"tools/list":return this.complete({tools:(await this.registry.available($.caller)).map((Z)=>T3(Z,!0)),ttlMs:60000,cacheScope:"private"});case"tools/call":return await this.callTool($);default:throw new B(L.MethodNotFound,`Method not found: ${$.message.method}`,void 0,404)}}async legacy($){switch($.message.method){case"ping":return{};case"tools/list":return{tools:(await this.registry.available($.caller)).map((Z)=>T3(Z,!1))};case"tools/call":return await this.callTool($);default:throw new B(L.MethodNotFound,`Method not found: ${$.message.method}`)}}complete($){return{resultType:"complete",...$,_meta:{[q3]:this.serverInfo}}}initialize($,Z,z){let G=Z.protocolVersion,W=X3.includes(G)?G:X3[0],X=S(Z.capabilities)?Z.capabilities:{},Y={v:W,e:_9(X.elicitation),p:K3(z),exp:Date.now()+i$},K=M3(B9,"gms1",Y);return f({jsonrpc:"2.0",id:$.id,result:{protocolVersion:W,capabilities:{tools:{listChanged:!1}},serverInfo:this.serverInfo,...this.instructions?{instructions:this.instructions}:{}}},200,{"Mcp-Session-Id":K})}session($,Z){let z=$.headers.get("mcp-session-id");if(!z)throw new B(L.InvalidRequest,"Missing Mcp-Session-Id. Send initialize first, or a request carrying io.modelcontextprotocol/protocolVersion in _meta.",void 0,400);let G=k3(B9,"gms1",z);if(!G||G.p!==K3(Z))throw new B(L.InvalidRequest,"Session not found.",void 0,404);return{id:z,state:G}}checkModernHeaders($,Z,z){if(!A3.includes(z))throw new B(L.UnsupportedProtocolVersion,"Unsupported protocol version",{supported:j3,requested:z},400);let G=(Y)=>new B(L.HeaderMismatch,`Header mismatch: ${Y}`,void 0,400);if($.headers.get("mcp-protocol-version")!==z)throw G("MCP-Protocol-Version does not match the protocol version in _meta.");if($.headers.get("mcp-method")!==Z.method)throw G("Mcp-Method does not match the method.");let W=Z.params??{},X=Z.method==="tools/call"||Z.method==="prompts/get"?W.name:Z.method==="resources/read"?W.uri:void 0;if(X!==void 0){let Y=$.headers.get("mcp-name");if(Y===null||J9(Y)!==X)throw G("Mcp-Name does not match the request's name.")}}async callTool($){let{params:Z,caller:z,principal:G}=$,W=Z.name;if(typeof W!=="string")throw new B(L.InvalidParams,"tools/call needs a tool name.");let X=Z.arguments??{},Y=(await this.registry.available(z,{names:[W]}))[0];if(!Y)throw new B(L.InvalidParams,`Unknown tool: ${W}`);let K=!1;if(Y.requiresApproval){let F=Y.inputSchema.safeParse(X);if(F.ok===!1)return this.toolResult($,{content:[{type:"text",text:`Invalid arguments for "${W}": ${F.errors.join(", ")}`}],isError:!0});let D=await this.approval($,Y,X);if(D.kind==="answer")return D.result;K=!0}let Q=e$($),V;try{V=await this.registry.execute(z,W,X,void 0,{approved:K,signal:$.signal,...Q?{progress:Q}:{}})}catch(F){if(F instanceof x)return this.toolResult($,{content:[{type:"text",text:F.message}],isError:!0});if(F instanceof h)throw new B(L.InvalidParams,F.reason==="unknown-tool"?`Unknown tool: ${W}`:F.message);return console.error(`[gemi/mcp] "${W}" failed for ${G.via}:${G.id}:`,F),this.toolResult($,{content:[{type:"text",text:`"${W}" failed on the server.`}],isError:!0})}let H=typeof V==="string"?V:JSON.stringify(V??null),U=Y.outputSchema&&($.era.modern||S(V))?{structuredContent:V}:{};return this.toolResult($,{content:[{type:"text",text:H}],...U,isError:!1})}toolResult($,Z){return $.era.modern?this.complete(Z):Z}async approval($,Z,z){let G=$2(Z,z),W=(V)=>({kind:"answer",result:this.toolResult($,{content:[{type:"text",text:V}],isError:!0})});if($.era.modern){let V=S($.params._meta)?$.params._meta:{},H=S(V[S3])?V[S3]:{},U=S($.params.inputResponses)?$.params.inputResponses:null,F=$.params.requestState,D=a$(z);if(U&&F!==void 0){let P=k3(R3,"grs1",F);if(!P||P.p!==K3($.principal)||P.t!==Z.name||P.a!==D)throw new B(L.InvalidParams,"requestState is not valid for this call.");if(!await this.spendNonce(P.n,P.exp))throw new B(L.InvalidParams,"requestState has already been used.");return D9(U[I9])?{kind:"approved"}:W(`The user did not approve "${Z.name}", and it did not run.`)}if(!_9(H.elicitation))throw new B(L.MissingRequiredClientCapability,`"${Z.name}" needs the user's approval, and this client cannot ask for it (elicitation).`,{requiredCapabilities:{elicitation:{form:{}}}},400);let _={p:K3($.principal),t:Z.name,a:D,n:N9(16).toString("base64url"),exp:Date.now()+P9};return{kind:"answer",result:{resultType:"input_required",inputRequests:{[I9]:{method:"elicitation/create",params:{mode:"form",...G}}},requestState:M3(R3,"grs1",_),_meta:{[q3]:this.serverInfo}}}}let X=$.era;if(!X.session.e||!$.stream)return W(`"${Z.name}" needs the user's approval, and this client cannot ask for it (elicitation). It did not run.`);let Y=`gemi-approval-${N9(12).toString("base64url")}`,K=X.sessionId,Q=await new Promise((V)=>{let H=setTimeout(()=>{this.pending.delete(Y),V(null)},this.approvalTimeoutMs),U=(F)=>{clearTimeout(H),V(F)};this.pending.set(Y,{session:K,resolve:U}),$.signal.addEventListener("abort",()=>{this.pending.delete(Y),U(null)}),$.stream.send({jsonrpc:"2.0",id:Y,method:"elicitation/create",params:X.session.v==="2025-11-25"?{mode:"form",...G}:G})});return Q&&!Q.error&&D9(Q.result)?{kind:"approved"}:W(`The user did not approve "${Z.name}", and it did not run.`)}async spendNonce($,Z){try{return await this.nonces.consume($,Z)}catch(z){return console.error("[gemi/mcp] Spending an approval failed:",z),!1}}async respond($,Z,z,G,W){if(!z)try{let Q=await Z(null,G);return f({jsonrpc:"2.0",id:$.id,result:Q},200)}finally{W?.()}let X=new AbortController,Y=AbortSignal.any([X.signal,G]),K=new q9(()=>X.abort());return(async()=>{try{let Q=await Z(K,Y);K.send({jsonrpc:"2.0",id:$.id,result:Q})}catch(Q){if(Q instanceof B)K.send(R($.id,Q));else console.error("[gemi/mcp] The MCP endpoint failed:",Q),K.send(R($.id,new B(L.InternalError,"Internal error.")))}finally{W?.(),K.close()}})(),new Response(K.readable,{status:200,headers:{"Content-Type":"text/event-stream","Cache-Control":"no-store","X-Accel-Buffering":"no"}})}unauthorized($){let Z=this.resolvers.map((G)=>G.challenge?.(this.context)).find(Boolean)??'Bearer realm="mcp"',z=$?`${Z}, error="invalid_token", error_description="${$.replace(/["\\]/g,"")}"`:Z;return f(R(null,new B(L.InvalidRequest,"Unauthorized.")),401,{"WWW-Authenticate":z})}async failedAttempt($){let Z=A9(new m($,{},"api",this.endpoint.pathname)),z=await O3(`mcp-auth-failed:${Z}`,n$);return z===null?null:O9(z)}async spend($){if(!this.rateLimit)return null;let Z=await O3(`mcp-endpoint:${$.via}:${$.id}`,this.rateLimit);return Z===null?null:O9(Z)}}class q9{readable;controller;closed=!1;encoder=new TextEncoder;constructor($){this.readable=new ReadableStream({start:(Z)=>{this.controller=Z},cancel:()=>{this.closed=!0,$()}})}send($){if(this.closed)return;this.controller.enqueue(this.encoder.encode(`event: message
2
+ import{$b as C9,Xb as j9,_b as Y3,_c as V9,cc as e,pc as K9,vc as Q9}from"./chunk-2cnawkke.js";import{fd as d3,hd as N3,kd as v9,ld as g9,md as G$,od as J$}from"./chunk-x5hj0mqp.js";import{Fd as A,Gd as y9,Hd as f9,Jd as w9,Kd as V$,rd as R9,wd as E9,yd as b9}from"./chunk-xymr3asa.js";import{Nd as N}from"./chunk-py1twqh8.js";import{Ff as o3,Qf as t3,Re as h3,Sf as n,Wf as s3,Xf as c9,Yf as p9,Zd as l,ae as A9,cg as y3,df as Z3,dg as i9,ee as B$,eg as G3,fg as n9,gg as t9,he as z$,hg as f3,ig as a,jf as V3,jg as I3,kf as g3,kg as u3,lf as q,of as $$,pf as a9,pg as e9,qf as r9,qg as Z$,re as W$,se as c3,sf as w,we as U3,wg as N$,xe as W3}from"./chunk-e2tjw0qx.js";import{Bh as p,Dh as m,Sh as n3,ei as Y9,ii as B3,ji as J3,ki as z3}from"./chunk-0rhf4g12.js";import{qi as m9}from"./chunk-zv5qyrqg.js";import{Bi as v}from"./chunk-4t41m5f1.js";import{Hi as m3}from"./chunk-hj88dcss.js";import{Ki as X$,Li as p3,Oi as F3,Pi as l3,Si as K$}from"./chunk-z61dj480.js";import{ej as u9,jj as d9}from"./chunk-vnw91fe1.js";import{Bj as u,zj as k9}from"./chunk-ysc7ykss.js";import{Cj as O}from"./chunk-jx5zx48j.js";import{Ij as U$}from"./chunk-z9xxthp1.js";import{wk as i3}from"./chunk-zyhmn3hy.js";import{Dk as H3,Gk as y}from"./chunk-jx2mgvvt.js";import{Pk as v3}from"./chunk-gqgpwb88.js";import{_k as l9}from"./chunk-99a4e6zf.js";var L$="mcp",_$=/^[\x21\x23-\x5B\x5D-\x7E]+$/;class x extends e{status;constructor($,Z){super($);this.status=Z;this.name="McpToolError"}}class h extends Error{reason;constructor($,Z){super($);this.reason=Z;this.name="McpCallRefusedError"}}var a3=/^[A-Za-z0-9_-]{1,64}$/,x$=/:([A-Za-z_][A-Za-z0-9_]*)([?*+]?)/g,r3=4000,T=1e5,D$=/^(text\/|application\/([\w.+-]*\+)?(json|xml))/i,H9=new WeakMap;function r2($){return H9.get($)}class i{router;dispatcher;static token="router.mcp";plans=new Map;scopeTools=new Map;files;featureOn;constructor($,Z,z={}){this.router=$;this.dispatcher=Z;this.files=q$(z.files),this.featureOn=z.featureOn??W3;for(let[G,W]of Object.entries($.routes??{}))this.plans.set(G,O$(W)?this.planNative(G,W):this.plan(G,W));this.resolveScopes()}list($,Z){if(_3($),$.kind==="local")return this.descriptors(Z);let z=[];for(let[G,W]of this.plans){if(!W.remote||!this.grants($.principal,G))continue;if($9(W.remote,Z))z.push(W.remote)}return z}async available($,Z){let z=[];for(let G of this.list($,Z))if(await this.isOn(G))z.push(G);return z}descriptors($){let Z=[];for(let{descriptor:z}of this.plans.values())if($9(z,$))Z.push(z);return Z}get maxFileBytes(){return this.files.maxBytes}scopes(){return[...this.scopeTools].map(([$,{description:Z}])=>({name:$,description:Z}))}scopesFor($){return[...this.scopeTools].filter(([,{tools:Z}])=>Z.has($)).map(([Z])=>Z)}async execute($,Z,z,G,W={}){_3($);let X=this.plans.get(Z);if(X&&!await this.isOn(X.descriptor)){if($.kind==="remote")throw new h(`There is no tool named "${Z}".`,"unknown-tool");throw new x(`There is no tool named "${Z}".`,404)}if($.kind==="remote"){if(!X?.remote||!this.grants($.principal,Z))throw new h(`There is no tool named "${Z}".`,"unknown-tool");if(X.descriptor.requiresApproval&&W.approved!==!0)throw new h(`"${Z}" needs the user's approval, and this call does not have it.`,"approval-required");G=void 0}if(!X)throw Error(`McpRegistry: there is no tool named "${Z}".`);if(X.kind==="tool")return await this.executeNative(X,$,z,G,W);let Y=X,K=$.kind==="remote"?Y.remote:Y.descriptor,Q=K.inputSchema.safeParse(z);if(Q.ok===!1)throw new x(`Invalid arguments for "${Z}": ${Q.errors.join(", ")}`);let V=Q.value,H={caller:$,req:$.req,tool:K,input:V,ctx:G},U=await this.fillPath(Y,H),{path:F}=this.dispatcher.getRouteHandlerAndParams(new Request(`http://gemi.internal/api${U}`));if(F!==K.url)throw new x(`"${Z}" has nothing at ${U}.`,404);let D={};for(let I of Y.jsonKeys)if(V[I]!==void 0)D[I]=V[I];let _,P="";if(Y.fileFields.length>0)_=await this.formData(Y,D,H);else if(K.method==="GET")P=v$(D);else if(Y.jsonKeys.length>0)_=D;let M=this.router.credentials?await this.bind(Y,"the credentials",()=>this.router.credentials(H)):void 0,j={...M?{credentials:M}:{},...W.signal?{signal:W.signal}:{},...W.progress?{progress:W.progress}:{},...$.kind==="remote"?{identity:{user:$.principal.user,grant:{via:$.principal.via,id:$.principal.id,scopes:$.principal.scopes,...$.principal.clientId?{clientId:$.principal.clientId}:{}}}}:{}},k;try{let I=P?`${U}?${P}`:U;k=Object.keys(j).length>0?await this.dispatcher.dispatchAs($.req,K.method,I,_,j):await this.dispatcher.dispatchAs($.req,K.method,I,_)}catch(I){throw console.error(`[gemi/mcp] Dispatching "${Z}" failed:`,I),new x(`"${Z}" failed on the server.`,500)}if(!Y.result&&!K.outputSchema)return await X9(Z,k);return await this.project(Y,H,k)}async isOn($){return $.feature===void 0||await this.featureOn($.feature)===!0}plan($,Z){if(!a3.test($))throw Error(`McpRouter: "${$}" is not a valid tool name. A routes key is the tool's name as a model and an MCP client see it, used verbatim \u2014 letters, digits, "_" and "-", at most 64.`);let z=`McpRouter: "${$}" (${Z?.method} ${Z?.url})`;if(!(Z instanceof Object)||Z.__internal_brand!=="McpRoute")throw Error(`McpRouter: "${$}" is not a route or a tool. Declare it with this.fromApiRoute(...) or this.fromTool(...).`);let{method:G,url:W,meta:X}=Z;if(X.feature!==void 0&&(typeof X.feature!=="string"||X.feature===""))throw Error(`${z}: feature must be a feature key from app/features.`);if(W.startsWith("/__gemi__"))throw Error(`${z} is a framework route, not an app route.`);let Y=this.dispatcher.flatRoutes[W]?.[G];if(!Y)throw Error(`${z} names no route of this app. Expose a route by the path and verb it is mounted at.`);let K=[...W.matchAll(x$)].map(([,J,C])=>({name:J,modifier:C})),Q=X.params??{};for(let J of K)if(!(J.name in Q))throw Error(`${z}: the path param "${J.name}" must be bound or declared "input".`);for(let[J,C]of Object.entries(Q)){if(!K.some((g)=>g.name===J))throw Error(`${z}: "${J}" in params is not a param of the url.`);if(z9(C))E$(z,`params.${J}`,C);else Z9(z,`params.${J}`,C)}let V=[],H;if(X.input){if(H=X.input.toJSONSchema(),H.type!=="object"||!H.properties)throw Error(`${z}: input must be an s.object(...), the fields of the request body.`);V=Object.keys(H.properties)}let U=Object.entries(X.files??{}).map(([J,C])=>({name:J,binder:C}));for(let J of U)Z9(z,`files.${J.name}`,J.binder);if(X.result!==void 0&&typeof X.result!=="function")throw Error(`${z}: result must be a function.`);if(X.output!==void 0&&typeof X.output?.safeParse!=="function")throw Error(`${z}: output must be a schema, built with s.`);if(X.title!==void 0&&(typeof X.title!=="string"||X.title===""))throw Error(`${z}: title must be a non-empty string.`);let F=G9(z,G,X.annotations);if(U.length>0&&G==="GET")throw Error(`${z}: a GET has no body to carry a file.`);let D={},_=(J,C)=>{if(J in D)throw Error(`${z}: "${J}" is the input key of two params or files, and the model can only send one.`);D[J]=C},P=new Map,M=new Map;for(let J of K){let C=Q[J.name];if(C==="input"){let g=p.string().describe(`The ":${J.name}" segment of the url.`);_(J.name,J.modifier==="?"||J.modifier==="*"?g.optional():g)}else if(z9(C)){let g=C.as??J.name;_(g,C.input),M.set(J.name,{key:g,param:C})}else P.set(J.name,C)}let j={};for(let J of U)if(J.binder==="input")_(J.name,p.string().describe("The id of an attachment the user uploaded or a tool produced (gemi_att_\u2026), whose file is sent as this field.")),j[J.name]=this.remoteFileSchema();let k=[...Object.keys(D),...U.map((J)=>J.name)];for(let J of new Set(k))if(V.includes(J))throw Error(`${z}: "${J}" is both an input field and a param or file, and the model can only send one.`);let I=Object.freeze({kind:"route",name:$,description:X.description,method:G,url:W,inputSchema:W9(X.input,H,p.object(D)),...X.output?{outputSchema:X.output}:{},...X.title?{title:X.title}:{},annotations:F,tags:Object.freeze([...X.tags??[]]),requiresApproval:X.requiresApproval===!0,...X.feature!==void 0?{feature:X.feature}:{},...Y.source?{source:Y.source}:{}}),r=!U.every((J)=>J.binder==="input")?null:U.length===0?I:Object.freeze({...I,inputSchema:W9(X.input,H,p.object(f$(D,Object.keys(j))),j)});return{kind:"route",descriptor:I,remote:r,params:K,paramBinders:P,modelParams:M,fileFields:U,jsonKeys:V,...X.result?{result:X.result}:{}}}remoteFileSchema(){let{maxBytes:$,fetch:Z}=this.files,z={name:{type:"string",description:"The file's name, like report.pdf."},mimeType:{type:"string",description:"The file's media type, like application/pdf."},data:{type:"string",contentEncoding:"base64",description:`The file's bytes, base64-encoded (RFC 4648, standard alphabet). At most ${$} bytes decoded.`}};if(Z)z.url={type:"string",format:"uri",description:"An https URL the server downloads the file from, instead of data."};let G={type:"object",description:Z?"A file, sent as base64 in data or fetched from url: exactly one of the two.":"A file, sent as base64 in data.",properties:z,required:["name","mimeType"],additionalProperties:!1},W=Object.keys(z),X=(Y)=>{if(typeof Y!=="object"||Y===null||Array.isArray(Y))return{ok:!1,errors:["a file must be an object"]};let K=[],Q={};for(let V of Object.keys(Y))if(!W.includes(V))K.push(`a file has no field "${V}"`);for(let V of W){let H=Y[V];if(H===void 0||H===null){if(V==="name"||V==="mimeType")K.push(`a file needs "${V}"`);continue}if(typeof H!=="string")K.push(`a file's "${V}" must be a string`);else Q[V]=H}return K.length>0?{ok:!1,errors:K}:{ok:!0,value:Q}};return{toJSONSchema:()=>G,safeParse:X,parse(Y){let K=X(Y);if(K.ok===!1)throw Error(K.errors.join(", "));return K.value}}}planNative($,Z){if(!a3.test($))throw Error(`McpRouter: "${$}" is not a valid tool name. A routes key is the tool's name as a model and an MCP client see it, used verbatim \u2014 letters, digits, "_" and "-", at most 64.`);let z=`McpRouter: "${$}" (a native tool)`,{tool:G,meta:W={}}=Z;if(!(G instanceof Object)||typeof G.name!=="string")throw Error(`${z} is not an AgentTool. Pass one built with AgentTool.create(...).`);if(G.answeredBy==="client"||typeof G.execute!=="function")throw Error(`${z}: "${G.name}" is answered by the client, and only a tool the server runs can be called through the registry.`);if(typeof G.inputSchema==="function")throw Error(`${z}: "${G.name}" resolves its input schema per run, and the registry lists one schema to every caller. Give it a fixed inputSchema.`);if(typeof G.inputSchema?.safeParse!=="function")throw Error(`${z}: its inputSchema must be a schema, built with s.`);if(typeof W!=="object"||W===null)throw Error(`${z}: the meta must be an object.`);if(W.description!==void 0&&(typeof W.description!=="string"||W.description.trim()===""))throw Error(`${z}: description must be a non-empty string.`);if(W.title!==void 0&&(typeof W.title!=="string"||W.title===""))throw Error(`${z}: title must be a non-empty string.`);if(W.tags!==void 0&&(!Array.isArray(W.tags)||W.tags.some((Q)=>typeof Q!=="string")))throw Error(`${z}: tags must be an array of strings.`);if(W.requiresApproval===!1&&G.requiresApproval)throw Error(`${z}: "${G.name}" requires approval, and requiresApproval: false would run it without asking. Leave it out, or register a tool that does not ask.`);let X=W.remote;if(X!==void 0){if(typeof X!=="object"||X===null||typeof X.context!=="function")throw Error(`${z}: remote must be { context(call) }, building the AgentContext a remote call runs with.`);if(X.progress!==void 0&&typeof X.progress!=="function")throw Error(`${z}: remote.progress must be a function.`)}let Y=W.description??G.description;if(typeof Y!=="string"||Y.trim()==="")throw Error(`${z} needs a description: the tool's own, or the meta's.`);let K=Object.freeze({kind:"tool",name:$,description:Y,inputSchema:G.inputSchema,...G.outputSchema?{outputSchema:G.outputSchema}:{},...W.title?{title:W.title}:{},annotations:G9(z,void 0,W.annotations),tags:Object.freeze([...W.tags??[]]),requiresApproval:G.requiresApproval||W.requiresApproval===!0});return{kind:"tool",descriptor:K,remote:X?K:null,tool:G,meta:W}}nativeTool($){let Z=this.plans.get($);if(Z?.kind!=="tool")throw Error(`McpRegistry: there is no native tool named "${$}".`);return Z.tool}startNative($,Z,z,G){let W=this.plans.get(Z);if(W?.kind!=="tool")throw Error(`McpRegistry: there is no native tool named "${Z}".`);if($===void 0)return W.tool.execute(z,G);if(_3($),$.kind!=="local")throw Error("McpRegistry: startNative is for a local caller. A remote call goes through execute().");let X=W.descriptor.inputSchema.safeParse(z);if(X.ok===!1)throw new x(`Invalid arguments for "${Z}": ${X.errors.join(", ")}`);return this.runNative(W,{caller:$,req:$.req,tool:W.descriptor,input:X.value},G)}runNative($,Z,z){let G={...z};return H9.set(G,{...Z,ctx:G}),$.tool.execute(Z.input,G)}async executeNative($,Z,z,G,W){let{name:X}=$.descriptor,Y=$.descriptor.inputSchema.safeParse(z);if(Y.ok===!1)throw new x(`Invalid arguments for "${X}": ${Y.errors.join(", ")}`);let K={caller:Z,req:Z.req,tool:$.descriptor,input:Y.value},Q=(I,L3)=>{if(!W.progress)return;let r;try{r=$.meta.remote?.progress?$.meta.remote.progress(I,L3):j$(I,L3)}catch(J){console.error(`[gemi/mcp] The progress mapping of "${X}" failed:`,J);return}if(r)W.progress(r)};if(Z.kind==="local"){if(!G)throw Error(`McpRegistry: "${X}" is a native tool, which runs with the tool context of an agent call, and none was passed to execute().`);return await e3(this.runNative($,{...K,ctx:G},G),Q)}let V=$.meta.remote,H=await this.bind($,"the remote context",()=>V.context(K));if(typeof H!=="object"||H===null)throw console.error(`[gemi/mcp] The remote context of "${X}" is not an object:`,H),new x(`"${X}" failed on the server.`,500);let U=$.tool.timeoutMs,F=[...W.signal?[W.signal]:[],...U!==void 0?[AbortSignal.timeout(U)]:[]],D=F.length===0?new AbortController().signal:F.length===1?F[0]:AbortSignal.any(F),_=C$($,H,D),P;try{P=await e3(this.runNative($,{...K,ctx:_},_),Q,D)}catch(I){if(D.aborted&&I===D.reason){if(W.signal?.aborted)throw new x(`"${X}" was cancelled.`,499);throw new x(`"${X}" did not finish within ${U} ms.`,504)}if(I instanceof x)throw I;if(I instanceof e||I instanceof h)throw new x(I.message);throw console.error(`[gemi/mcp] "${X}" failed for a remote caller:`,I),new x(`"${X}" failed on the server.`,500)}let M=(I)=>{return console.error(`[gemi/mcp] "${X}" ${I}`),new x(`"${X}" failed on the server.`,500)};if(K9(P))throw M("answered a job handle, and a remote call has no background jobs.");let j=P;if($.descriptor.outputSchema){let I=$.descriptor.outputSchema.safeParse(j);if(I.ok===!1)throw M(`answered what its output schema refuses: ${I.errors.join(", ")}`);j=I.value}if(j===void 0)return null;if(typeof j==="string")return j.length>T?`${j.slice(0,T)}\u2026 [cut at ${T} of ${j.length} characters]`:j;let k=JSON.stringify(j);if(k!==void 0&&k.length>T)return`${k.slice(0,T)}\u2026 [cut at ${T} of ${k.length} characters]`;return j}async fillPath($,Z){let{input:z,req:G}=Z,W=$.descriptor.url;for(let X of $.params){let Y=$.paramBinders.get(X.name),K=$.modelParams.get(X.name),Q;if(Y||K){if(Q=K?await this.bind($,`the param "${X.name}"`,()=>K.param.bind(z[K.key],G,Z),{refusals:!0}):await this.bind($,`the param "${X.name}"`,()=>Y(G,Z)),Q===void 0||Q===null||Q==="")throw console.error(`[gemi/mcp] The ${K?"resolver":"binder"} for "${X.name}" of "${$.descriptor.name}" returned ${JSON.stringify(Q)}.`),new x(`"${$.descriptor.name}" failed on the server.`,500)}else Q=z[X.name];let V=`:${X.name}${X.modifier}`;if(Q===void 0||Q===null||Q===""){if(X.modifier!=="?"&&X.modifier!=="*")throw new x(`"${X.name}" of "${$.descriptor.name}" must not be empty.`);W=W.replace(`/${V}`,"");continue}W=W.replace(V,w$($.descriptor.name,X,String(Q)))}return W}async formData($,Z,z){let{input:G,ctx:W}=z,X=$.descriptor.name;if(z.caller.kind==="remote"){let K=new FormData;for(let[Q,V]of Object.entries(Z))x3(K,Q,V);for(let Q of $.fileFields)K.append(Q.name,await this.remoteFile(X,Q.name,G[Q.name]));return K}if(!W)throw Error(`McpRegistry: "${X}" sends a file, which is resolved through the tool context's attachments, and none was passed to execute().`);let Y=new FormData;for(let[K,Q]of Object.entries(Z))x3(Y,K,Q);for(let K of $.fileFields){let Q=K.binder==="input"?G[K.name]:await this.bind($,`the file "${K.name}"`,()=>K.binder(W,z));if(typeof Q!=="string"||Q==="")throw new x(`"${X}" needs a file for "${K.name}", and this turn has none. Ask the user to attach one.`);Y.append(K.name,await W.attachments.file(Q))}return Y}async remoteFile($,Z,z){let G=(H)=>new x(`"${Z}" of "${$}" ${H}`,400),W=z,{maxBytes:X,fetch:Y}=this.files;if(!T$(W.name))throw G("needs a name of 1 to 255 characters, without control characters or slashes.");if(!M$.test(W.mimeType))throw G(`has a mimeType that is not a media type: "${W.mimeType.slice(0,100)}".`);let K=typeof W.data==="string",Q=typeof W.url==="string";if(K===Q)throw G(Y?"needs exactly one of data or url.":"needs its bytes, base64, in data.");if(K){let H=W.data.replace(/\s+/g,"");if(Math.floor(H.length*3/4)-R$(H)>X)throw G(`is larger than the ${X} bytes a file may be.`);if(H.length%4!==0||!k$.test(H))throw G("has data that is not base64 (RFC 4648, standard alphabet, padded).");return new File([Buffer.from(H,"base64")],W.name,{type:W.mimeType})}if(!Y)throw G("cannot be fetched from a URL here. Send its bytes, base64, in data.");let V;try{V=new URL(W.url)}catch{throw G("has a url that is not a URL.")}if(V.protocol!=="https:")throw G("can only be fetched from an https URL.");try{let H=await Y9(V.href,{...Y,maxSize:Math.min(Y.maxSize??X,X),redirect:"follow"});if(!H.ok)throw G(`could not be fetched: ${V.host} answered ${H.status}.`);let U=await H.arrayBuffer();return new File([U],W.name,{type:W.mimeType})}catch(H){if(H instanceof x)throw H;throw G(`could not be fetched from ${V.host}: ${H instanceof Error?H.message:"failed"}.`)}}grants($,Z){for(let z of $.scopes??[])if(this.scopeTools.get(z)?.tools.has(Z))return!0;return!1}resolveScopes(){let $=this.router.scopes;if($===void 0){this.scopeTools.set(L$,{description:"Use this app's tools as you",tools:new Set(this.plans.keys())});return}if(typeof $!=="object"||$===null)throw Error("McpRouter: scopes must be an object of scope names.");let Z=new Set([...this.plans.values()].flatMap(({descriptor:z})=>z.tags));for(let[z,G]of Object.entries($)){let W=`McpRouter: scope "${z}"`;if(!_$.test(z))throw Error(`${W} is not a valid OAuth scope: printable ASCII, no spaces or quotes.`);if(typeof G?.description!=="string"||G.description==="")throw Error(`${W} needs a description: it is what a consent screen shows.`);let X=new Set;for(let Y of G.tags??[]){if(!Z.has(Y))throw Error(`${W} names the tag "${Y}", which no tool has.`);for(let[K,{descriptor:Q}]of this.plans)if(Q.tags.includes(Y))X.add(K)}for(let Y of G.names??[]){if(!this.plans.has(Y))throw Error(`${W} names "${Y}", which is no tool.`);X.add(Y)}if(X.size===0)throw Error(`${W} reaches no tool. Give it tags or names.`);this.scopeTools.set(z,{description:G.description,tools:X})}}async project($,Z,z){let{name:G,outputSchema:W}=$.descriptor;if(z.status<200||z.status>=300)return await X9(G,z);let X=(U,F)=>{if(F===void 0)console.error(`[gemi/mcp] "${G}" ${U}`);else console.error(`[gemi/mcp] "${G}" ${U}`,F);return new x(`"${G}" failed on the server.`,500)},Y=z.headers.get("Content-Type"),K=await z.text(),Q=null;if(K!=="")try{Q=JSON.parse(K)}catch{throw X(`answered ${Y??"a body with no content-type"} that is not JSON, and its result or output needs JSON.`)}let V=Q;if($.result)try{V=await $.result(Q,Z)}catch(U){throw X("failed in its result projection:",U)}if(W){let U=W.safeParse(V);if(U.ok===!1)throw X(`answered what its output schema refuses: ${U.errors.join(", ")}`);V=U.value}if(V===void 0)return null;let H=JSON.stringify(V);if(H!==void 0&&H.length>T)return`${H.slice(0,T)}\u2026 [cut at ${T} of ${H.length} characters]`;return V}async bind($,Z,z,G={}){try{return await z()}catch(W){if(G.refusals&&W instanceof e)throw W;throw console.error(`[gemi/mcp] Binding ${Z} of "${$.descriptor.name}" failed:`,W),new x(`"${$.descriptor.name}" failed on the server.`,500)}}}function O$($){return $ instanceof Object&&$.__internal_brand==="McpTool"}function A$($){return typeof $==="object"&&$!==null&&typeof $.next==="function"&&Symbol.asyncIterator in $}async function e3($,Z,z){let G;if(z)G=new Promise((X,Y)=>{if(z.aborted)Y(z.reason);else z.addEventListener("abort",()=>Y(z.reason),{once:!0})}),G.catch(()=>{});let W=(X)=>G?Promise.race([X,G]):X;if(!A$($))return await W(Promise.resolve($));try{let X=0,Y=await W($.next());while(!Y.done)Z(Y.value,++X),Y=await W($.next());return Y.value}catch(X){throw $.return(void 0).catch(()=>{}),X}}function j$($,Z){if(typeof $==="string")return{progress:Z,message:$};if(typeof $==="object"&&$!==null){let{progress:z,total:G,message:W}=$;if(typeof z==="number"&&Number.isFinite(z))return{progress:z,...typeof G==="number"?{total:G}:{},...typeof W==="string"?{message:W}:{}};if(typeof W==="string")return{progress:Z,message:W}}return{progress:Z}}function C$($,Z,z){let G=$.descriptor.name,W=`mcp_${crypto.randomUUID()}`,X=`mcp_call_${crypto.randomUUID()}`,Y=(Q)=>async()=>{throw new e(`"${G}" was called by a remote MCP client, which has no ${Q}.`,{retryable:!1})},K={put:Y("attachment store"),get:Y("attachment store"),read:Y("attachment store"),file:Y("attachment store")};return{context:Z,body:{},runId:W,toolCallId:X,signal:z,step:1,depth:0,resumed:!1,attachments:K,turn:Object.freeze({attachments:Object.freeze([])}),runAgent:Y("agent run to nest a sub-agent in"),generateImage:Y("attachment store to put an image in"),editImage:Y("attachment store to put an image in"),generate:(Q)=>V9({...Q,signal:Q.signal?AbortSignal.any([z,Q.signal]):z},{origin:{mcp:G,runId:W,toolCallId:X}}),jobs:Q9({jobs:void 0,threadId:void 0,runId:W,toolCallId:X,toolName:G,depth:0,async:$.tool.async,attachments:null})}}function _3($){if($?.kind==="local"&&$.req)return;if($?.kind==="remote"&&$.req&&$.principal?.user&&typeof $.principal.id==="string"&&Array.isArray($.principal.scopes))return;throw Error('McpRegistry: a caller is { kind: "local", req } or { kind: "remote", req, principal }, with the principal a caller resolver verified.')}function $9($,Z){if(Z?.names&&!Z.names.includes($.name))return!1;if(Z?.tags&&!$.tags.some((z)=>Z.tags.includes(z)))return!1;return!0}var S$=10485760;function q$($){let Z=$?.maxBytes??S$;if(!Number.isSafeInteger(Z)||Z<=0)throw Error("McpRegistry: files.maxBytes must be a positive whole number of bytes.");let z=$?.fetchUrls===!0?{}:typeof $?.fetchUrls==="object"&&$.fetchUrls!==null?$.fetchUrls:null;return{maxBytes:Z,fetch:z}}function T$($){if($.length===0||$.length>255)return!1;for(let Z of $){let z=Z.codePointAt(0);if(z<32||z===127||Z==="/"||Z==="\\")return!1}return!0}var M$=/^[A-Za-z0-9][A-Za-z0-9!#$&^_.+-]{0,126}\/[A-Za-z0-9][A-Za-z0-9!#$&^_.+-]{0,126}(\s*;.{0,200})?$/,k$=/^[A-Za-z0-9+/]*={0,2}$/;function R$($){return $.endsWith("==")?2:$.endsWith("=")?1:0}function Z9($,Z,z){if(z!=="input"&&typeof z!=="function")throw Error(`${$}: ${Z} must be a function or "input".`)}function z9($){return $ instanceof Object&&$.__internal_brand==="McpModelParam"}function E$($,Z,z){if(z.as!==void 0&&(typeof z.as!=="string"||z.as===""))throw Error(`${$}: ${Z}.as must be a non-empty string.`);let G=z.input;if(typeof G?.safeParse!=="function"||typeof G.toJSONSchema!=="function")throw Error(`${$}: ${Z}.input must be a schema, built with s.`);if(typeof z.bind!=="function")throw Error(`${$}: ${Z}.bind must be a function.`)}var b$=new Set(["readOnlyHint","destructiveHint","idempotentHint","openWorldHint"]);function y$($){switch($){case"GET":return{readOnlyHint:!0};case"DELETE":return{destructiveHint:!0};case"PUT":return{idempotentHint:!0};default:return{}}}function G9($,Z,z){if(z!==void 0&&(typeof z!=="object"||z===null))throw Error(`${$}: annotations must be an object of hints.`);let G=Z?y$(Z):{};for(let[W,X]of Object.entries(z??{})){if(!b$.has(W))throw Error(`${$}: "${W}" is not a tool annotation. Use readOnlyHint, destructiveHint, idempotentHint or openWorldHint.`);if(X===void 0)continue;if(typeof X!=="boolean")throw Error(`${$}: annotations.${W} must be true or false.`);G[W]=X}if(G.readOnlyHint===!0&&(G.destructiveHint||G.idempotentHint))throw Error(`${$} is read-only${z?.readOnlyHint?"":` (a ${Z})`} and also ${G.destructiveHint?"destructive":"idempotent"}, which only a tool that is not read-only can be. Set readOnlyHint: false if it changes something.`);return Object.freeze(G)}function W9($,Z,z,G={}){let W=z.toJSONSchema(),X=Object.fromEntries(Object.entries(G).map(([Q,V])=>[Q,V.toJSONSchema()])),Y={...Z??{},type:"object",properties:{...Z?.properties??{},...W.properties,...X},required:[...Z?.required??[],...W.required??[],...Object.keys(G)],additionalProperties:!1},K=(Q)=>{if(typeof Q!=="object"||Q===null||Array.isArray(Q))return{ok:!1,errors:["expected an object"]};let V=[],H={};if($){let F=$.safeParse(Q);if(F.ok===!1)V.push(...F.errors);else H={...F.value}}let U=z.safeParse(Q);if(U.ok===!1)V.push(...U.errors);else H={...H,...U.value};for(let[F,D]of Object.entries(G)){let _=Q[F];if(_===void 0){V.push(`"${F}" is required`);continue}let P=D.safeParse(_);if(P.ok===!1)V.push(...P.errors.map((M)=>`${F}: ${M}`));else H[F]=P.value}return V.length>0?{ok:!1,errors:V}:{ok:!0,value:H}};return{toJSONSchema:()=>Y,safeParse:K,parse(Q){let V=K(Q);if(V.ok===!1)throw Error(V.errors.join(", "));return V.value}}}function f$($,Z){return Object.fromEntries(Object.entries($).filter(([z])=>!Z.includes(z)))}function w$($,Z,z){let G=Z.modifier==="*"||Z.modifier==="+"?z.split("/"):[z];if(G.some((W)=>W==="."||W===".."))throw new x(`"${z}" is not a valid value for "${Z.name}" of "${$}".`);return G.map(encodeURIComponent).join("/")}function x3($,Z,z){if(z===void 0||z===null)return;if(Array.isArray(z)){for(let G of z)x3($,Z,G);return}$.append(Z,typeof z==="object"?JSON.stringify(z):String(z))}function v$($){let Z=new URLSearchParams,z=(G,W)=>{if(W===void 0||W===null)return;if(Array.isArray(W)){for(let X of W)z(G,X);return}Z.append(G,typeof W==="object"?JSON.stringify(W):String(W))};for(let[G,W]of Object.entries($))z(G,W);return Z.toString()}async function X9($,Z){if(Z.status>=200&&Z.status<300){let G=Z.headers.get("Content-Type");if(G&&!D$.test(G)){let X=(await Z.arrayBuffer()).byteLength;return`"${$}" answered with ${X} bytes of ${G}, which is not shown.`}let W=await Z.text();if(W==="")return null;if(W.length>T)return`${W.slice(0,T)}\u2026 [cut at ${T} of ${W.length} characters]`;try{return JSON.parse(W)}catch{return W}}let z=await Z.text();if(Z.status>=400&&Z.status<500){let G=z.length>r3?`${z.slice(0,r3)}\u2026`:z;throw new x(`"${$}" was refused with ${Z.status}${G?`: ${G}`:"."}`,Z.status)}if(Z.status<500)console.error(`[gemi/mcp] "${$}" answered ${Z.status}${Z.headers.get("Location")?` to ${Z.headers.get("Location")}`:""}, which a tool call cannot follow.`);throw new x(`"${$}" failed on the server.`,Z.status)}import{createHash as g$,randomBytes as h$,timingSafeEqual as m$}from"crypto";function D3($){let Z=$.headers.get("authorization");if(!Z)return null;let z=/^Bearer[ ]+([\x21-\x7e]+)$/i.exec(Z.trim());return z?z[1]:null}class u${options;name="api-key";constructor($){this.options=$;if(typeof $?.prefix!=="string"||!/^[A-Za-z0-9_-]{3,32}$/.test($.prefix))throw Error('McpApiKeyResolver: prefix is required: 3 to 32 letters, digits, _ or -, like "myapp_mcp_".');if(typeof $.verify!=="function")throw Error("McpApiKeyResolver: verify must be a function that looks a key up.")}static generate($){return`${$}${h$(32).toString("base64url")}`}static hash($){return g$("sha256").update($).digest("hex")}static hashesMatch($,Z){let z=Buffer.from($),G=Buffer.from(Z);return z.length===G.length&&m$(z,G)}async resolve($){let Z=D3($);if(!Z?.startsWith(this.options.prefix))return null;let z=await this.options.verify(Z,$);if(!z)return{ok:!1,error:"invalid_token",description:"The API key is not valid."};if(!z.user||typeof z.id!=="string"||z.id===""||!Array.isArray(z.scopes))throw Error("McpApiKeyResolver: verify must answer { user, id, scopes } for a key it knows, or null.");return{ok:!0,principal:{user:z.user,via:this.name,id:z.id,scopes:[...z.scopes]}}}}import{createHash as S9,randomBytes as N9}from"crypto";async function O3($,Z){let z=d$();if(!z)return null;let G=await z.consume($,Z);return G.allowed?null:Math.max(1,Math.ceil(G.retryAfter/1000))}function d$(){try{let $=y();return $.bound(l)?$.make(l):null}catch{return null}}var A3=["2026-07-28"],X3=["2025-11-25","2025-06-18","2025-03-26"],j3=[...A3,...X3],C3="io.modelcontextprotocol/protocolVersion",S3="io.modelcontextprotocol/clientCapabilities";var q3="io.modelcontextprotocol/serverInfo",L={ParseError:-32700,InvalidRequest:-32600,MethodNotFound:-32601,InvalidParams:-32602,InternalError:-32603,HeaderMismatch:-32020,MissingRequiredClientCapability:-32021,UnsupportedProtocolVersion:-32022};class B extends Error{code;data;status;constructor($,Z,z,G=200){super(Z);this.code=$;this.data=z;this.status=G;this.name="JsonRpcError"}}function R($,Z){return{jsonrpc:"2.0",id:$,error:{code:Z.code,message:Z.message,...Z.data!==void 0?{data:Z.data}:{}}}}function U9($){if(Array.isArray($))throw new B(L.InvalidRequest,"Batched requests are not supported.",void 0,400);if(typeof $!=="object"||$===null||$.jsonrpc!=="2.0")throw new B(L.InvalidRequest,"Not a JSON-RPC 2.0 message.",void 0,400);let Z=$,z=Z.id,G=typeof z==="string"||typeof z==="number"&&Number.isFinite(z);if(typeof Z.method==="string"){if(Z.params!==void 0&&(typeof Z.params!=="object"||Z.params===null||Array.isArray(Z.params)))throw new B(L.InvalidRequest,"params must be an object.",void 0,400);if(z===void 0)return{kind:"notification",message:Z};if(!G)throw new B(L.InvalidRequest,"id must be a string or a number.",void 0,400);return{kind:"request",message:Z}}if(G&&(("result"in Z)||("error"in Z)))return{kind:"response",message:Z};throw new B(L.InvalidRequest,"Not a JSON-RPC request, notification or response.",void 0,400)}function T3($,Z){let z=$.outputSchema?.toJSONSchema(),G={...$.annotations,...$.title&&!Z?{title:$.title}:{}};return{name:$.name,...$.title?{title:$.title}:{},description:$.description,inputSchema:$.inputSchema.toJSONSchema(),...z&&(Z||z.type==="object")?{outputSchema:z}:{},...Object.keys(G).length>0?{annotations:G}:{}}}function S($){return typeof $==="object"&&$!==null&&!Array.isArray($)}function J9($){let Z=/^=\?base64\?([A-Za-z0-9+/]*={0,2})\?=$/.exec($);if(!Z)return $;try{let z=Buffer.from(Z[1],"base64");return new TextDecoder("utf-8",{fatal:!0}).decode(z)}catch{return null}}import{createHmac as c$,timingSafeEqual as p$}from"crypto";function M3($,Z,z){let G=Buffer.from(JSON.stringify(z)).toString("base64url");return`${Z}.${G}.${F9($,Z,G).toString("base64url")}`}function k3($,Z,z,G=Date.now()){if(typeof z!=="string"||z.length>8192)return null;let W=z.split(".");if(W.length!==3||W[0]!==Z)return null;let[,X,Y]=W,K=Buffer.from(Y,"base64url"),Q=F9($,Z,X);if(K.length!==Q.length||!p$(K,Q))return null;let V;try{V=JSON.parse(Buffer.from(X,"base64url").toString("utf8"))}catch{return null}if(typeof V!=="object"||V===null)return null;if(typeof V.exp!=="number"||V.exp<=G)return null;return V}function F9($,Z,z){return c$("sha256",Y3($)).update(`${Z}.${z}`).digest()}var R3="gemi.mcp.request-state.v1",B9="gemi.mcp.session.v1",i$=86400000,P9=600000,I9="gemi_approval",E3=2000,l$={limit:600,window:60},n$={limit:30,window:60};class $3{registry;static token="router.mcp.http";endpoint;resolvers;context;allowedOrigins;rateLimit;maxBodyBytes;serverInfo;instructions;nonces;approvalTimeoutMs;feature;featureOn;pending=new Map;inflight=new Map;constructor($,Z,z={}){this.registry=$;if(typeof Z.url!=="string")throw Error(`route.mcp.remote.url is required: the endpoint's canonical URL, like "https://example.com/mcp".`);this.endpoint=o$(Z.url);let G=Z.resolvers??[];if(!Array.isArray(G)||G.length===0)throw Error("route.mcp.remote is enabled without a caller resolver. Configure route.mcp.remote.resolvers \u2014 an McpOAuthServer, an McpApiKeyResolver, or your own \u2014 or leave the endpoint off. Without one every request would be refused, or answered as nobody.");for(let W of G)if(typeof W?.resolve!=="function"||typeof W.name!=="string"||W.name==="")throw Error("route.mcp.remote.resolvers: each resolver needs a name and a resolve().");if(this.resolvers=G,Y3(R3),this.context={resource:this.resource,registry:$},this.allowedOrigins=new Set((Z.allowedOrigins??[]).map((W)=>{if(new URL(W).origin!==W)throw Error(`route.mcp.remote.allowedOrigins: "${W}" is not an origin (scheme://host[:port]).`);return W})),this.allowedOrigins.add(this.endpoint.origin),this.rateLimit=Z.rateLimit===!1?!1:Z.rateLimit??l$,this.maxBodyBytes=Z.maxBodyBytes??Math.ceil($.maxFileBytes*1.4)+1048576,this.serverInfo={name:Z.server?.name??"gemi",version:Z.server?.version??"1.0.0"},this.instructions=Z.server?.instructions,this.nonces=Z.nonces??new j9,this.approvalTimeoutMs=Z.approvalTimeoutMs??P9,Z.feature!==void 0){if(typeof Z.feature!=="string"||Z.feature==="")throw Error("route.mcp.remote.feature must be a feature key from app/features.");this.feature=Z.feature}this.featureOn=z.featureOn??W3;for(let W of G)W.boot?.(this.context)}get resource(){return this.endpoint.href.replace(/\/$/,"")}async handle($){let Z=new URL($.url);if(Z.host!==this.endpoint.host)return null;if(this.feature!==void 0){if(!this.ownsPath(Z.pathname))return null;if(await this.featureOn(this.feature)!==!0)return null}for(let W of this.resolvers){let X=await W.handle?.($,this.context);if(X)return X}if(Z.pathname!==this.endpoint.pathname)return null;let z=$.headers.get("origin");if(z!==null&&!this.allowedOrigins.has(z))return f(R(null,new B(L.InvalidRequest,"Origin not allowed.")),403);let G=z?s$(z):{};if($.method==="OPTIONS")return new Response(null,{status:204,headers:{...G,"Access-Control-Allow-Methods":"POST","Access-Control-Allow-Headers":"Authorization, Content-Type, Accept, MCP-Protocol-Version, Mcp-Session-Id, Mcp-Method, Mcp-Name, Last-Event-ID","Access-Control-Max-Age":"600"}});if($.method!=="POST")return L9(new Response(null,{status:405,headers:{Allow:"POST, OPTIONS"}}),G);return L9(await this.post($),G)}ownsPath($){let Z=this.endpoint.pathname.replace(/\/$/,"");return $===this.endpoint.pathname||$===Z||$.startsWith(`${Z}/`)||$.startsWith("/.well-known/")}async post($){let Z=null;for(let Y of this.resolvers){let K=await Y.resolve($,this.context);if(K===null)continue;if(K.ok===!1)return await this.failedAttempt($)??this.unauthorized(K.description);Z={...K.principal,via:Y.name};break}if(!Z)return(D3($)!==null?await this.failedAttempt($):null)??this.unauthorized();let z=await this.spend(Z);if(z)return z;let G=$.headers.get("content-type")??"";if(!/^application\/json\s*(;|$)/i.test(G))return new Response("Content-Type must be application/json.",{status:415});let W;try{W=JSON.parse(await t$($,this.maxBodyBytes))}catch(Y){if(Y instanceof Q3)return f(R(null,new B(L.InvalidRequest,`The request is larger than ${this.maxBodyBytes} bytes.`)),413);return f(R(null,new B(L.ParseError,"Parse error.")),400)}let X=new m($,{},"api",this.endpoint.pathname);return await v.run(X,async()=>{try{return await this.dispatch($,X,Z,W)}catch(Y){if(Y instanceof B){let K=S(W)&&(typeof W.id==="string"||typeof W.id==="number")?W.id:null;return f(R(K,Y),Y.status)}return console.error("[gemi/mcp] The MCP endpoint failed:",Y),f(R(null,new B(L.InternalError,"Internal error.")),500)}},{user:Z.user})}async dispatch($,Z,z,G){let W=U9(G),X={kind:"remote",req:Z,principal:z};if(W.kind==="response"){let _=this.session($,z),P=this.pending.get(String(W.message.id));if(P&&P.session===_.id)this.pending.delete(String(W.message.id)),P.resolve(W.message);return new Response(null,{status:202})}let{message:Y}=W,K=Y.params??{},Q=S(K._meta)?K._meta:{};if(typeof Q[C3]==="string"){if(this.checkModernHeaders($,Y,Q[C3]),W.kind==="notification")return new Response(null,{status:202});return await this.respond(Y,async(_,P)=>this.modern({principal:z,caller:X,message:Y,params:K,era:{modern:!0},stream:_,signal:P}),x9(K),$.signal)}if(Y.method==="initialize"){if(W.kind!=="request")throw new B(L.InvalidRequest,"initialize is a request.",void 0,400);return this.initialize(W.message,K,z)}let V=this.session($,z),H=$.headers.get("mcp-protocol-version");if(H!==null&&H!==V.state.v)throw new B(L.InvalidRequest,`MCP-Protocol-Version ${H} is not the session's ${V.state.v}.`,void 0,400);if(W.kind==="notification"){if(Y.method==="notifications/cancelled"){let _=K.requestId;this.inflight.get(`${V.id}:${String(_)}`)?.abort()}return new Response(null,{status:202})}let U=`${V.id}:${String(Y.id)}`,F=new AbortController;this.inflight.set(U,F);let D=AbortSignal.any([F.signal,$.signal]);try{return await this.respond(Y,async(_,P)=>this.legacy({principal:z,caller:X,message:Y,params:K,era:{modern:!1,session:V.state,sessionId:V.id},stream:_,signal:P}),x9(K)||r$(this.registry,Y,V.state),D,()=>this.inflight.delete(U))}catch(_){throw this.inflight.delete(U),_}}async modern($){switch($.message.method){case"server/discover":return this.complete({supportedVersions:j3,capabilities:{tools:{}},...this.instructions?{instructions:this.instructions}:{},ttlMs:60000,cacheScope:"private"});case"tools/list":return this.complete({tools:(await this.registry.available($.caller)).map((Z)=>T3(Z,!0)),ttlMs:60000,cacheScope:"private"});case"tools/call":return await this.callTool($);default:throw new B(L.MethodNotFound,`Method not found: ${$.message.method}`,void 0,404)}}async legacy($){switch($.message.method){case"ping":return{};case"tools/list":return{tools:(await this.registry.available($.caller)).map((Z)=>T3(Z,!1))};case"tools/call":return await this.callTool($);default:throw new B(L.MethodNotFound,`Method not found: ${$.message.method}`)}}complete($){return{resultType:"complete",...$,_meta:{[q3]:this.serverInfo}}}initialize($,Z,z){let G=Z.protocolVersion,W=X3.includes(G)?G:X3[0],X=S(Z.capabilities)?Z.capabilities:{},Y={v:W,e:_9(X.elicitation),p:K3(z),exp:Date.now()+i$},K=M3(B9,"gms1",Y);return f({jsonrpc:"2.0",id:$.id,result:{protocolVersion:W,capabilities:{tools:{listChanged:!1}},serverInfo:this.serverInfo,...this.instructions?{instructions:this.instructions}:{}}},200,{"Mcp-Session-Id":K})}session($,Z){let z=$.headers.get("mcp-session-id");if(!z)throw new B(L.InvalidRequest,"Missing Mcp-Session-Id. Send initialize first, or a request carrying io.modelcontextprotocol/protocolVersion in _meta.",void 0,400);let G=k3(B9,"gms1",z);if(!G||G.p!==K3(Z))throw new B(L.InvalidRequest,"Session not found.",void 0,404);return{id:z,state:G}}checkModernHeaders($,Z,z){if(!A3.includes(z))throw new B(L.UnsupportedProtocolVersion,"Unsupported protocol version",{supported:j3,requested:z},400);let G=(Y)=>new B(L.HeaderMismatch,`Header mismatch: ${Y}`,void 0,400);if($.headers.get("mcp-protocol-version")!==z)throw G("MCP-Protocol-Version does not match the protocol version in _meta.");if($.headers.get("mcp-method")!==Z.method)throw G("Mcp-Method does not match the method.");let W=Z.params??{},X=Z.method==="tools/call"||Z.method==="prompts/get"?W.name:Z.method==="resources/read"?W.uri:void 0;if(X!==void 0){let Y=$.headers.get("mcp-name");if(Y===null||J9(Y)!==X)throw G("Mcp-Name does not match the request's name.")}}async callTool($){let{params:Z,caller:z,principal:G}=$,W=Z.name;if(typeof W!=="string")throw new B(L.InvalidParams,"tools/call needs a tool name.");let X=Z.arguments??{},Y=(await this.registry.available(z,{names:[W]}))[0];if(!Y)throw new B(L.InvalidParams,`Unknown tool: ${W}`);let K=!1;if(Y.requiresApproval){let F=Y.inputSchema.safeParse(X);if(F.ok===!1)return this.toolResult($,{content:[{type:"text",text:`Invalid arguments for "${W}": ${F.errors.join(", ")}`}],isError:!0});let D=await this.approval($,Y,X);if(D.kind==="answer")return D.result;K=!0}let Q=e$($),V;try{V=await this.registry.execute(z,W,X,void 0,{approved:K,signal:$.signal,...Q?{progress:Q}:{}})}catch(F){if(F instanceof x)return this.toolResult($,{content:[{type:"text",text:F.message}],isError:!0});if(F instanceof h)throw new B(L.InvalidParams,F.reason==="unknown-tool"?`Unknown tool: ${W}`:F.message);return console.error(`[gemi/mcp] "${W}" failed for ${G.via}:${G.id}:`,F),this.toolResult($,{content:[{type:"text",text:`"${W}" failed on the server.`}],isError:!0})}let H=typeof V==="string"?V:JSON.stringify(V??null),U=Y.outputSchema&&($.era.modern||S(V))?{structuredContent:V}:{};return this.toolResult($,{content:[{type:"text",text:H}],...U,isError:!1})}toolResult($,Z){return $.era.modern?this.complete(Z):Z}async approval($,Z,z){let G=$2(Z,z),W=(V)=>({kind:"answer",result:this.toolResult($,{content:[{type:"text",text:V}],isError:!0})});if($.era.modern){let V=S($.params._meta)?$.params._meta:{},H=S(V[S3])?V[S3]:{},U=S($.params.inputResponses)?$.params.inputResponses:null,F=$.params.requestState,D=a$(z);if(U&&F!==void 0){let P=k3(R3,"grs1",F);if(!P||P.p!==K3($.principal)||P.t!==Z.name||P.a!==D)throw new B(L.InvalidParams,"requestState is not valid for this call.");if(!await this.spendNonce(P.n,P.exp))throw new B(L.InvalidParams,"requestState has already been used.");return D9(U[I9])?{kind:"approved"}:W(`The user did not approve "${Z.name}", and it did not run.`)}if(!_9(H.elicitation))throw new B(L.MissingRequiredClientCapability,`"${Z.name}" needs the user's approval, and this client cannot ask for it (elicitation).`,{requiredCapabilities:{elicitation:{form:{}}}},400);let _={p:K3($.principal),t:Z.name,a:D,n:N9(16).toString("base64url"),exp:Date.now()+P9};return{kind:"answer",result:{resultType:"input_required",inputRequests:{[I9]:{method:"elicitation/create",params:{mode:"form",...G}}},requestState:M3(R3,"grs1",_),_meta:{[q3]:this.serverInfo}}}}let X=$.era;if(!X.session.e||!$.stream)return W(`"${Z.name}" needs the user's approval, and this client cannot ask for it (elicitation). It did not run.`);let Y=`gemi-approval-${N9(12).toString("base64url")}`,K=X.sessionId,Q=await new Promise((V)=>{let H=setTimeout(()=>{this.pending.delete(Y),V(null)},this.approvalTimeoutMs),U=(F)=>{clearTimeout(H),V(F)};this.pending.set(Y,{session:K,resolve:U}),$.signal.addEventListener("abort",()=>{this.pending.delete(Y),U(null)}),$.stream.send({jsonrpc:"2.0",id:Y,method:"elicitation/create",params:X.session.v==="2025-11-25"?{mode:"form",...G}:G})});return Q&&!Q.error&&D9(Q.result)?{kind:"approved"}:W(`The user did not approve "${Z.name}", and it did not run.`)}async spendNonce($,Z){try{return await this.nonces.consume($,Z)}catch(z){return console.error("[gemi/mcp] Spending an approval failed:",z),!1}}async respond($,Z,z,G,W){if(!z)try{let Q=await Z(null,G);return f({jsonrpc:"2.0",id:$.id,result:Q},200)}finally{W?.()}let X=new AbortController,Y=AbortSignal.any([X.signal,G]),K=new q9(()=>X.abort());return(async()=>{try{let Q=await Z(K,Y);K.send({jsonrpc:"2.0",id:$.id,result:Q})}catch(Q){if(Q instanceof B)K.send(R($.id,Q));else console.error("[gemi/mcp] The MCP endpoint failed:",Q),K.send(R($.id,new B(L.InternalError,"Internal error.")))}finally{W?.(),K.close()}})(),new Response(K.readable,{status:200,headers:{"Content-Type":"text/event-stream","Cache-Control":"no-store","X-Accel-Buffering":"no"}})}unauthorized($){let Z=this.resolvers.map((G)=>G.challenge?.(this.context)).find(Boolean)??'Bearer realm="mcp"',z=$?`${Z}, error="invalid_token", error_description="${$.replace(/["\\]/g,"")}"`:Z;return f(R(null,new B(L.InvalidRequest,"Unauthorized.")),401,{"WWW-Authenticate":z})}async failedAttempt($){let Z=A9(new m($,{},"api",this.endpoint.pathname)),z=await O3(`mcp-auth-failed:${Z}`,n$);return z===null?null:O9(z)}async spend($){if(!this.rateLimit)return null;let Z=await O3(`mcp-endpoint:${$.via}:${$.id}`,this.rateLimit);return Z===null?null:O9(Z)}}class q9{readable;controller;closed=!1;encoder=new TextEncoder;constructor($){this.readable=new ReadableStream({start:(Z)=>{this.controller=Z},cancel:()=>{this.closed=!0,$()}})}send($){if(this.closed)return;this.controller.enqueue(this.encoder.encode(`event: message
3
3
  data: ${JSON.stringify($)}
4
4
 
5
5
  `))}close(){if(this.closed)return;this.closed=!0,this.controller.close()}}class Q3 extends Error{}async function t$($,Z){let z=Number($.headers.get("content-length"));if(Number.isFinite(z)&&z>Z)throw new Q3;if(!$.body)return"";let G=$.body.getReader(),W=[],X=0;for(;;){let{done:Y,value:K}=await G.read();if(Y)break;if(X+=K.byteLength,X>Z)throw await G.cancel(),new Q3;W.push(K)}return Buffer.concat(W).toString("utf8")}function f($,Z,z={}){return new Response(JSON.stringify($),{status:Z,headers:{"Content-Type":"application/json","Cache-Control":"no-store",...z}})}function L9($,Z){for(let[z,G]of Object.entries(Z))$.headers.set(z,G);return $}function s$($){return{"Access-Control-Allow-Origin":$,"Access-Control-Expose-Headers":"Mcp-Session-Id, WWW-Authenticate",Vary:"Origin"}}function o$($){let Z;try{Z=new URL($)}catch{throw Error(`route.mcp.remote.url: "${$}" is not a URL.`)}let z=Z.hostname==="localhost"||Z.hostname==="127.0.0.1"||Z.hostname==="[::1]";if(Z.protocol!=="https:"&&!(Z.protocol==="http:"&&z))throw Error("route.mcp.remote.url must be https (http only on localhost): tokens travel to it.");if(Z.search||Z.hash||Z.username||Z.password)throw Error("route.mcp.remote.url must have no query, fragment or credentials.");if(Z.pathname==="/"||Z.pathname.endsWith("/"))throw Error('route.mcp.remote.url needs a path of its own, like "/mcp", without a trailing slash.');return Z}function K3($){return S9("sha256").update(`${$.via}\x00${$.id}\x00${$.user?.id}`).digest("base64url").slice(0,32)}function a$($){return S9("sha256").update(C9($??{})).digest("base64url")}function _9($){if(!S($))return!1;if(Object.keys($).length===0)return!0;return"form"in $}function x9($){let Z=S($._meta)?$._meta:{};return typeof Z.progressToken==="string"||typeof Z.progressToken==="number"}function r$($,Z,z){if(Z.method!=="tools/call"||!z.e)return!1;let G=Z.params?.name;return typeof G==="string"&&$.descriptors({names:[G]})[0]?.requiresApproval===!0}function e$($){let z=(S($.params._meta)?$.params._meta:{}).progressToken;if(!$.stream||typeof z!=="string"&&typeof z!=="number")return;let G=-1/0;return(W)=>{if(typeof W?.progress!=="number"||!Number.isFinite(W.progress)||W.progress<=G)return;G=W.progress,$.stream.send({jsonrpc:"2.0",method:"notifications/progress",params:{progressToken:z,progress:W.progress,...typeof W.total==="number"?{total:W.total}:{},...typeof W.message==="string"?{message:W.message.slice(0,1000)}:{}}})}}function $2($,Z){let z=JSON.stringify(Z??{},null,1),G=z.length>E3?`${z.slice(0,E3)}\u2026 (${z.length-E3} more characters not shown)`:z;return{message:`Allow "${$.title??$.name}" to run? ${$.description}
@@ -3041,6 +3041,7 @@ function island(loader, options = {}) {
3041
3041
  if (typeof loader !== "function") throw new Error("island() takes `() => import(\"./Component\")` and options since gemi 0.110. The island(\"name\", Component, () => import(\"./x.island\")) form was removed: see UPGRADE.md.");
3042
3042
  const exportName = options.export ?? "default";
3043
3043
  const load = options.load ?? "eager";
3044
+ const preloadDynamic = options.preloadDynamic === true ? true : void 0;
3044
3045
  const key = loader[ISLAND_MODULE_KEY];
3045
3046
  const label = `island(${key ?? "() => import(…)"}${exportName === "default" ? "" : `#${exportName}`})`;
3046
3047
  const pick = (mod) => {
@@ -3052,10 +3053,15 @@ function island(loader, options = {}) {
3052
3053
  const inlineComponent = () => inline ??= loader.gemiModule ? pick(loader.gemiModule) : lazy(() => loader().then((mod) => ({ default: pick(mod) })));
3053
3054
  const register = (collector) => {
3054
3055
  const known = collector.islands.findIndex((entry) => key !== void 0 && entry.module === key && entry.export === exportName && entry.load === load);
3055
- return known !== -1 ? known : collector.islands.push({
3056
+ if (known !== -1) {
3057
+ if (preloadDynamic) collector.islands[known].preloadDynamic = true;
3058
+ return known;
3059
+ }
3060
+ return collector.islands.push({
3056
3061
  module: key,
3057
3062
  export: exportName,
3058
- load
3063
+ load,
3064
+ preloadDynamic
3059
3065
  }) - 1;
3060
3066
  };
3061
3067
  const start = (collector, props) => {