gemi 0.147.0 → 0.148.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.
@@ -1,5 +1,5 @@
1
1
  // @bun
2
- import{$b as K3,Kc as F9,Xb as k9,ac as M9,ec as e,md as N9,rc as U9,xc as J9}from"./chunk-ezn89ezm.js";import{Ad as V$,Cd as L$,td as p3,vd as B3,yd as d9,zd as p9}from"./chunk-2b3hh9xw.js";import{Fd as w9,Kd as v9,Md as h9,Td as x,Ud as g9,Vd as m9,Xd as u9,Yd as B$}from"./chunk-877yc341.js";import{$d as P}from"./chunk-eqv7yxk7.js";import{Af as k,Ag as x$,Bg as L3,Cg as d3,Df as Y$,Ef as G$,Ff as W$,Ge as H$,He as c3,Hf as w,Hg as X$,Ig as K$,Le as J3,Me as X3,Og as D$,Uf as a3,dg as t3,ef as m3,fg as n,jg as o3,kg as s9,le as l,lg as t9,me as z$,pe as T9,rg as f3,sf as Z3,sg as o9,te as O$,tg as G3,ug as r9,vg as e9,we as Q$,wg as w3,xg as a,yf as H3,zf as g3}from"./chunk-01tw5f26.js";import{Ai as P3,Bi as F3,Ci as z3,Th as c,Vh as m,ii as s3,wi as H9}from"./chunk-95vm1de8.js";import{Ii as i9}from"./chunk-cee5gq7t.js";import{Ti as h}from"./chunk-a8n9ec43.js";import{Zi as u3}from"./chunk-563ksar3.js";import{aj as U$,bj as i3,ej as N3,fj as n3,ij as F$}from"./chunk-n9n4qt20.js";import{Bj as n9,wj as l9}from"./chunk-xv58jnpb.js";import{Rj as f9,Tj as u}from"./chunk-86zhngpg.js";import{Uj as A}from"./chunk-attr793y.js";import{_j as I$}from"./chunk-2ery6a75.js";import{Ok as l3}from"./chunk-z7tsh9qr.js";import{Vk as U3,Yk as y}from"./chunk-1fyn63ka.js";import{fl as h3}from"./chunk-mzkzgp2j.js";import{ql as a9}from"./chunk-fqqbnp0z.js";var C$="mcp",S$=/^[\x21\x23-\x5B\x5D-\x7E]+$/;class O extends e{status;constructor($,Z){super($);this.status=Z;this.name="McpToolError"}}class v extends Error{reason;constructor($,Z){super($);this.reason=Z;this.name="McpCallRefusedError"}}var r3=/^[A-Za-z0-9_-]{1,64}$/,q$=/:([A-Za-z_][A-Za-z0-9_]*)([?*+]?)/g,e3=4000,M=1e5,T$=/^(text\/|application\/([\w.+-]*\+)?(json|xml))/i,B9=new WeakMap;function X6($){return B9.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=b$(z.files),this.featureOn=z.featureOn??X3;for(let[G,W]of Object.entries($.routes??{}))this.plans.set(G,k$(W)?this.planNative(G,W):this.plan(G,W));this.resolveScopes()}list($,Z){if(D3($),$.kind==="local")return this.descriptors(Z);let z=[];for(let[G,W]of this.plans){if(!W.remote||!this.grants($.principal,G))continue;if(W9(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(W9(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={}){D3($);let X=this.plans.get(Z);if(X&&!await this.isOn(X.descriptor)){if($.kind==="remote")throw new v(`There is no tool named "${Z}".`,"unknown-tool");throw new O(`There is no tool named "${Z}".`,404)}if($.kind==="remote"){if(!X?.remote||!this.grants($.principal,Z))throw new v(`There is no tool named "${Z}".`,"unknown-tool");if(X.descriptor.requiresApproval&&W.approved!==!0&&!W3(X))throw new v(`"${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 O(`Invalid arguments for "${Z}": ${Q.errors.join(", ")}`);let V=Q.value,H={caller:$,req:$.req,tool:K,input:V,ctx:G},J=await this.fillPath(Y,H),{path:I}=this.dispatcher.getRouteHandlerAndParams(new Request(`http://gemi.internal/api${J}`));if(I!==K.url)throw new O(`"${Z}" has nothing at ${J}.`,404);let U={};for(let _ of Y.jsonKeys)if(V[_]!==void 0)U[_]=V[_];let F,B="";if(Y.fileFields.length>0)F=await this.formData(Y,U,H);else if(K.method==="GET")B=p$(U);else if(Y.jsonKeys.length>0)F=U;let T=this.router.credentials?await this.bind(Y,"the credentials",()=>this.router.credentials(H)):void 0,j={...T?{credentials:T}:{},...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}:{}}}}:{}},C;try{let _=B?`${J}?${B}`:J;C=Object.keys(j).length>0?await this.dispatcher.dispatchAs($.req,K.method,_,F,j):await this.dispatcher.dispatchAs($.req,K.method,_,F)}catch(_){throw console.error(`[gemi/mcp] Dispatching "${Z}" failed:`,_),new O(`"${Z}" failed on the server.`,500)}if(!Y.result&&!K.outputSchema)return await V9(Z,C);return await this.project(Y,H,C)}async isOn($){return $.feature===void 0||await this.featureOn($.feature)===!0}plan($,Z){if(!r3.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(q$)].map(([,N,S])=>({name:N,modifier:S})),Q=X.params??{};for(let N of K)if(!(N.name in Q))throw Error(`${z}: the path param "${N.name}" must be bound or declared "input".`);for(let[N,S]of Object.entries(Q)){if(!K.some((g)=>g.name===N))throw Error(`${z}: "${N}" in params is not a param of the url.`);if(Y9(S))h$(z,`params.${N}`,S);else X9(z,`params.${N}`,S)}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 J=Object.entries(X.files??{}).map(([N,S])=>({name:N,binder:S}));for(let N of J)X9(z,`files.${N.name}`,N.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 I=K9(z,G,X.annotations);if(J.length>0&&G==="GET")throw Error(`${z}: a GET has no body to carry a file.`);let U={},F=(N,S)=>{if(N in U)throw Error(`${z}: "${N}" is the input key of two params or files, and the model can only send one.`);U[N]=S},B=new Map,T=new Map;for(let N of K){let S=Q[N.name];if(S==="input"){let g=c.string().describe(`The ":${N.name}" segment of the url.`);F(N.name,N.modifier==="?"||N.modifier==="*"?g.optional():g)}else if(Y9(S)){let g=S.as??N.name;F(g,S.input),T.set(N.name,{key:g,param:S})}else B.set(N.name,S)}let j={};for(let N of J)if(N.binder==="input")F(N.name,c.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[N.name]=this.remoteFileSchema();let C=[...Object.keys(U),...J.map((N)=>N.name)];for(let N of new Set(C))if(V.includes(N))throw Error(`${z}: "${N}" is both an input field and a param or file, and the model can only send one.`);let _=Object.freeze({kind:"route",name:$,description:X.description,method:G,url:W,inputSchema:Q9(X.input,H,c.object(U)),...X.output?{outputSchema:X.output}:{},...X.title?{title:X.title}:{},annotations:I,tags:Object.freeze([...X.tags??[]]),requiresApproval:X.requiresApproval===!0,...X.feature!==void 0?{feature:X.feature}:{},...Y.source?{source:Y.source}:{}}),r=!J.every((N)=>N.binder==="input")?null:J.length===0?_:Object.freeze({..._,inputSchema:Q9(X.input,H,c.object(u$(U,Object.keys(j))),j)});return{kind:"route",descriptor:_,remote:r,params:K,paramBinders:B,modelParams:T,fileFields:J,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(!r3.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:K9(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}}async approvalRequired($,Z,z,G={}){let W=this.plans.get(Z);if(!W)return!0;if(!W3(W))return W.descriptor.requiresApproval;let X=W;if($.kind!=="remote"||!X.meta.remote)return!0;let Y=X.descriptor.inputSchema.safeParse(z);if(Y.ok===!1)return!0;let K={caller:$,req:$.req,tool:X.descriptor,input:Y.value},Q;try{Q=await this.bind(X,"the remote context",()=>X.meta.remote.context(K))}catch{return!0}if(typeof Q!=="object"||Q===null)return!0;let V=G.signal??new AbortController().signal;return G9(X,Y.value,z9(Z9(X,Q,V)))}nativeApproval($){let Z=this.plans.get($);if(Z?.kind!=="tool")throw Error(`McpRegistry: there is no native tool named "${$}".`);return W3(Z)??Z.descriptor.requiresApproval}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(D3($),$.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 O(`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 B9.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 O(`Invalid arguments for "${X}": ${Y.errors.join(", ")}`);let K={caller:Z,req:Z.req,tool:$.descriptor,input:Y.value},Q=(_,_3)=>{if(!W.progress)return;let r;try{r=$.meta.remote?.progress?$.meta.remote.progress(_,_3):R$(_,_3)}catch(N){console.error(`[gemi/mcp] The progress mapping of "${X}" failed:`,N);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 $9(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 O(`"${X}" failed on the server.`,500);let J=$.tool.timeoutMs,I=[...W.signal?[W.signal]:[],...J!==void 0?[AbortSignal.timeout(J)]:[]],U=I.length===0?new AbortController().signal:I.length===1?I[0]:AbortSignal.any(I),F=Z9($,H,U);if(!W.approved&&W3($)&&await G9($,K.input,z9(F)))throw new v(`"${X}" needs the user's approval, and this call does not have it.`,"approval-required");let B;try{B=await $9(this.runNative($,{...K,ctx:F},F),Q,U)}catch(_){if(U.aborted&&_===U.reason){if(W.signal?.aborted)throw new O(`"${X}" was cancelled.`,499);throw new O(`"${X}" did not finish within ${J} ms.`,504)}if(_ instanceof O)throw _;if(_ instanceof e||_ instanceof v)throw new O(_.message);throw console.error(`[gemi/mcp] "${X}" failed for a remote caller:`,_),new O(`"${X}" failed on the server.`,500)}let T=(_)=>{return console.error(`[gemi/mcp] "${X}" ${_}`),new O(`"${X}" failed on the server.`,500)};if(U9(B))throw T("answered a job handle, and a remote call has no background jobs.");let j=B;if($.descriptor.outputSchema){let _=$.descriptor.outputSchema.safeParse(j);if(_.ok===!1)throw T(`answered what its output schema refuses: ${_.errors.join(", ")}`);j=_.value}if(j===void 0)return null;if(typeof j==="string")return j.length>M?`${j.slice(0,M)}\u2026 [cut at ${M} of ${j.length} characters]`:j;let C=JSON.stringify(j);if(C!==void 0&&C.length>M)return`${C.slice(0,M)}\u2026 [cut at ${M} of ${C.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 O(`"${$.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 O(`"${X.name}" of "${$.descriptor.name}" must not be empty.`);W=W.replace(`/${V}`,"");continue}W=W.replace(V,d$($.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))O3(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))O3(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 O(`"${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 O(`"${Z}" of "${$}" ${H}`,400),W=z,{maxBytes:X,fetch:Y}=this.files;if(!y$(W.name))throw G("needs a name of 1 to 255 characters, without control characters or slashes.");if(!f$.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)-v$(H)>X)throw G(`is larger than the ${X} bytes a file may be.`);if(H.length%4!==0||!w$.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 H9(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 J=await H.arrayBuffer();return new File([J],W.name,{type:W.mimeType})}catch(H){if(H instanceof O)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(C$,{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(!S$.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 V9(G,z);let X=(J,I)=>{if(I===void 0)console.error(`[gemi/mcp] "${G}" ${J}`);else console.error(`[gemi/mcp] "${G}" ${J}`,I);return new O(`"${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(J){throw X("failed in its result projection:",J)}if(W){let J=W.safeParse(V);if(J.ok===!1)throw X(`answered what its output schema refuses: ${J.errors.join(", ")}`);V=J.value}if(V===void 0)return null;let H=JSON.stringify(V);if(H!==void 0&&H.length>M)return`${H.slice(0,M)}\u2026 [cut at ${M} 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 O(`"${$.descriptor.name}" failed on the server.`,500)}}}function k$($){return $ instanceof Object&&$.__internal_brand==="McpTool"}function M$($){return typeof $==="object"&&$!==null&&typeof $.next==="function"&&Symbol.asyncIterator in $}async function $9($,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(!M$($))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 R$($,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 Z9($,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)=>N9({...Q,signal:Q.signal?AbortSignal.any([z,Q.signal]):z},{origin:{mcp:G,runId:W,toolCallId:X}}),jobs:J9({jobs:void 0,threadId:void 0,runId:W,toolCallId:X,toolName:G,depth:0,async:$.tool.async,attachments:null}),memory:F9()}}function W3($){if($.kind!=="tool"||$.meta.requiresApproval===!0)return;return $.tool.approvalPredicate}function z9($){return{context:$.context,body:$.body,runId:$.runId,threadId:$.threadId,toolCallId:$.toolCallId,step:$.step,depth:$.depth,signal:$.signal}}async function G9($,Z,z){try{return await $.tool.approvalPredicate(Z,z)!==!1}catch(G){return console.error(`[gemi/mcp] The requiresApproval of "${$.descriptor.name}" threw, so the call asks the user:`,G),!0}}function D3($){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 W9($,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 E$=10485760;function b$($){let Z=$?.maxBytes??E$;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 y$($){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 f$=/^[A-Za-z0-9][A-Za-z0-9!#$&^_.+-]{0,126}\/[A-Za-z0-9][A-Za-z0-9!#$&^_.+-]{0,126}(\s*;.{0,200})?$/,w$=/^[A-Za-z0-9+/]*={0,2}$/;function v$($){return $.endsWith("==")?2:$.endsWith("=")?1:0}function X9($,Z,z){if(z!=="input"&&typeof z!=="function")throw Error(`${$}: ${Z} must be a function or "input".`)}function Y9($){return $ instanceof Object&&$.__internal_brand==="McpModelParam"}function h$($,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 g$=new Set(["readOnlyHint","destructiveHint","idempotentHint","openWorldHint"]);function m$($){switch($){case"GET":return{readOnlyHint:!0};case"DELETE":return{destructiveHint:!0};case"PUT":return{idempotentHint:!0};default:return{}}}function K9($,Z,z){if(z!==void 0&&(typeof z!=="object"||z===null))throw Error(`${$}: annotations must be an object of hints.`);let G=Z?m$(Z):{};for(let[W,X]of Object.entries(z??{})){if(!g$.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 Q9($,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 I=$.safeParse(Q);if(I.ok===!1)V.push(...I.errors);else H={...I.value}}let J=z.safeParse(Q);if(J.ok===!1)V.push(...J.errors);else H={...H,...J.value};for(let[I,U]of Object.entries(G)){let F=Q[I];if(F===void 0){V.push(`"${I}" is required`);continue}let B=U.safeParse(F);if(B.ok===!1)V.push(...B.errors.map((T)=>`${I}: ${T}`));else H[I]=B.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 u$($,Z){return Object.fromEntries(Object.entries($).filter(([z])=>!Z.includes(z)))}function d$($,Z,z){let G=Z.modifier==="*"||Z.modifier==="+"?z.split("/"):[z];if(G.some((W)=>W==="."||W===".."))throw new O(`"${z}" is not a valid value for "${Z.name}" of "${$}".`);return G.map(encodeURIComponent).join("/")}function O3($,Z,z){if(z===void 0||z===null)return;if(Array.isArray(z)){for(let G of z)O3($,Z,G);return}$.append(Z,typeof z==="object"?JSON.stringify(z):String(z))}function p$($){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 V9($,Z){if(Z.status>=200&&Z.status<300){let G=Z.headers.get("Content-Type");if(G&&!T$.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>M)return`${W.slice(0,M)}\u2026 [cut at ${M} 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>e3?`${z.slice(0,e3)}\u2026`:z;throw new O(`"${$}" 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 O(`"${$}" failed on the server.`,Z.status)}import{createHash as c$,randomBytes as i$,timingSafeEqual as l$}from"crypto";function j3($){let Z=$.headers.get("authorization");if(!Z)return null;let z=/^Bearer[ ]+([\x21-\x7e]+)$/i.exec(Z.trim());return z?z[1]:null}class n${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`${$}${i$(32).toString("base64url")}`}static hash($){return c$("sha256").update($).digest("hex")}static hashesMatch($,Z){let z=Buffer.from($),G=Buffer.from(Z);return z.length===G.length&&l$(z,G)}async resolve($){let Z=j3($);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 R9,randomBytes as _9}from"crypto";async function A3($,Z){let z=s$();if(!z)return null;let G=await z.consume($,Z);return G.allowed?null:Math.max(1,Math.ceil(G.retryAfter/1000))}function s$(){try{let $=y();return $.bound(l)?$.make(l):null}catch{return null}}var x3=["2026-07-28"],Y3=["2025-11-25","2025-06-18","2025-03-26"],C3=[...x3,...Y3],S3="io.modelcontextprotocol/protocolVersion",q3="io.modelcontextprotocol/clientCapabilities";var T3="io.modelcontextprotocol/serverInfo",D={ParseError:-32700,InvalidRequest:-32600,MethodNotFound:-32601,InvalidParams:-32602,InternalError:-32603,HeaderMismatch:-32020,MissingRequiredClientCapability:-32021,UnsupportedProtocolVersion:-32022};class L 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 P9($){if(Array.isArray($))throw new L(D.InvalidRequest,"Batched requests are not supported.",void 0,400);if(typeof $!=="object"||$===null||$.jsonrpc!=="2.0")throw new L(D.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 L(D.InvalidRequest,"params must be an object.",void 0,400);if(z===void 0)return{kind:"notification",message:Z};if(!G)throw new L(D.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 L(D.InvalidRequest,"Not a JSON-RPC request, notification or response.",void 0,400)}function k3($,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 q($){return typeof $==="object"&&$!==null&&!Array.isArray($)}function I9($){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 t$,timingSafeEqual as o$}from"crypto";function M3($,Z,z){let G=Buffer.from(JSON.stringify(z)).toString("base64url");return`${Z}.${G}.${L9($,Z,G).toString("base64url")}`}function R3($,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=L9($,Z,X);if(K.length!==Q.length||!o$(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 L9($,Z,z){return t$("sha256",K3($)).update(`${Z}.${z}`).digest()}var E3="gemi.mcp.request-state.v1",D9="gemi.mcp.session.v1",a$=86400000,O9=600000,j9="gemi_approval",b3=2000,r$={limit:600,window:60},e$={limit:30,window:60};class $3{registry;static token="router.mcp.http";endpoint;resolvers;context;allowedOrigins;rateLimit;maxBodyBytes;serverInfo;instructions;nonces;approvalTimeoutMs;onCall;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=z2(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,K3(E3),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??r$,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 k9,this.approvalTimeoutMs=Z.approvalTimeoutMs??O9,Z.onCall!==void 0&&typeof Z.onCall!=="function")throw Error("route.mcp.remote.onCall must be a function.");if(this.onCall=Z.onCall,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??X3;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 L(D.InvalidRequest,"Origin not allowed.")),403);let G=z?Z2(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 A9(new Response(null,{status:405,headers:{Allow:"POST, OPTIONS"}}),G);return A9(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(j3($)!==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 $2($,this.maxBodyBytes))}catch(Y){if(Y instanceof V3)return f(R(null,new L(D.InvalidRequest,`The request is larger than ${this.maxBodyBytes} bytes.`)),413);return f(R(null,new L(D.ParseError,"Parse error.")),400)}let X=new m($,{},"api",this.endpoint.pathname);return await h.run(X,async()=>{try{return await this.dispatch($,X,Z,W)}catch(Y){if(Y instanceof L){let K=q(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 L(D.InternalError,"Internal error.")),500)}},{user:Z.user})}async dispatch($,Z,z,G){let W=P9(G),X={kind:"remote",req:Z,principal:z};if(W.kind==="response"){let F=this.session($,z),B=this.pending.get(String(W.message.id));if(B&&B.session===F.id)this.pending.delete(String(W.message.id)),B.resolve(W.message);return new Response(null,{status:202})}let{message:Y}=W,K=Y.params??{},Q=q(K._meta)?K._meta:{};if(typeof Q[S3]==="string"){if(this.checkModernHeaders($,Y,Q[S3]),W.kind==="notification")return new Response(null,{status:202});return await this.respond(Y,async(F,B)=>this.modern({principal:z,caller:X,message:Y,params:K,era:{modern:!0},stream:F,signal:B}),C9(K),$.signal)}if(Y.method==="initialize"){if(W.kind!=="request")throw new L(D.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 L(D.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 F=K.requestId;this.inflight.get(`${V.id}:${String(F)}`)?.abort()}return new Response(null,{status:202})}let J=`${V.id}:${String(Y.id)}`,I=new AbortController;this.inflight.set(J,I);let U=AbortSignal.any([I.signal,$.signal]);try{return await this.respond(Y,async(F,B)=>this.legacy({principal:z,caller:X,message:Y,params:K,era:{modern:!1,session:V.state,sessionId:V.id},stream:F,signal:B}),C9(K)||W2(this.registry,Y,V.state),U,()=>this.inflight.delete(J))}catch(F){throw this.inflight.delete(J),F}}async modern($){switch($.message.method){case"server/discover":return this.complete({supportedVersions:C3,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)=>k3(Z,!0)),ttlMs:60000,cacheScope:"private"});case"tools/call":return await this.callTool($);default:throw new L(D.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)=>k3(Z,!1))};case"tools/call":return await this.callTool($);default:throw new L(D.MethodNotFound,`Method not found: ${$.message.method}`)}}complete($){return{resultType:"complete",...$,_meta:{[T3]:this.serverInfo}}}initialize($,Z,z){let G=Z.protocolVersion,W=Y3.includes(G)?G:Y3[0],X=q(Z.capabilities)?Z.capabilities:{},Y={v:W,e:x9(X.elicitation),p:Q3(z),exp:Date.now()+a$},K=M3(D9,"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 L(D.InvalidRequest,"Missing Mcp-Session-Id. Send initialize first, or a request carrying io.modelcontextprotocol/protocolVersion in _meta.",void 0,400);let G=R3(D9,"gms1",z);if(!G||G.p!==Q3(Z))throw new L(D.InvalidRequest,"Session not found.",void 0,404);return{id:z,state:G}}checkModernHeaders($,Z,z){if(!x3.includes(z))throw new L(D.UnsupportedProtocolVersion,"Unsupported protocol version",{supported:C3,requested:z},400);let G=(Y)=>new L(D.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||I9(Y)!==X)throw G("Mcp-Name does not match the request's name.")}}async callTool($){let Z=$.params.name;if(typeof Z!=="string")throw new L(D.InvalidParams,"tools/call needs a tool name.");let z=$.params.arguments??{};if(!this.onCall)return await this.runTool($,Z,z,{approved:!1});let G=performance.now(),W={approved:!1};try{let X=await this.runTool($,Z,z,W);if(!W.pending)await this.report($,Z,z,W,G);return X}catch(X){if(!W.outcome){if(W.outcome="error",W.message=X instanceof L?X.message:"Internal error.",!(X instanceof L))W.error=X}throw await this.report($,Z,z,W,G),X}}async report($,Z,z,G,W){let{principal:X}=$;try{await this.onCall({user:X.user,via:X.via,credentialId:X.id,clientId:X.clientId??null,scopes:X.scopes,tool:Z,arguments:z,outcome:G.outcome??"ok",...G.reason!==void 0?{reason:G.reason}:{},...G.message!==void 0?{message:G.message}:{},...G.status!==void 0?{status:G.status}:{},...G.error!==void 0?{error:G.error}:{},approved:G.approved,durationMs:Math.round((performance.now()-W)*1000)/1000,req:$.caller.req})}catch(Y){console.error(`[gemi/mcp] route.mcp.remote.onCall failed for "${Z}":`,Y)}}async runTool($,Z,z,G){let{caller:W,principal:X}=$,Y=(U,F)=>{G.outcome="denied",G.reason=U,G.message=F},K=(U,F,B)=>{if(G.outcome="error",G.message=U,F!==void 0)G.status=F;if(B!==void 0)G.error=B},Q=(await this.registry.available(W,{names:[Z]}))[0];if(!Q)throw Y("unknown-tool",`Unknown tool: ${Z}`),new L(D.InvalidParams,`Unknown tool: ${Z}`);if(Q.requiresApproval){let U=Q.inputSchema.safeParse(z);if(U.ok===!1){let B=`Invalid arguments for "${Z}": ${U.errors.join(", ")}`;return K(B),this.toolResult($,{content:[{type:"text",text:B}],isError:!0})}if($.era.modern&&q($.params.inputResponses)&&$.params.requestState!==void 0||await this.registry.approvalRequired(W,Z,z,{signal:$.signal})){let B=await this.approval($,Q,z,Y,G);if(B.kind==="answer")return B.result;G.approved=!0}}let V=X2($),H;try{H=await this.registry.execute(W,Z,z,void 0,{approved:G.approved,signal:$.signal,...V?{progress:V}:{}})}catch(U){if(U instanceof O){if(U.status===401||U.status===403)Y("forbidden",U.message),G.status=U.status;else K(U.message,U.status);return this.toolResult($,{content:[{type:"text",text:U.message}],isError:!0})}if(U instanceof v){let B=U.reason==="unknown-tool"?`Unknown tool: ${Z}`:U.message;throw Y(U.reason,B),new L(D.InvalidParams,B)}console.error(`[gemi/mcp] "${Z}" failed for ${X.via}:${X.id}:`,U);let F=`"${Z}" failed on the server.`;return K(F,void 0,U),this.toolResult($,{content:[{type:"text",text:F}],isError:!0})}let J=typeof H==="string"?H:JSON.stringify(H??null),I=Q.outputSchema&&($.era.modern||q(H))?{structuredContent:H}:{};return G.outcome="ok",this.toolResult($,{content:[{type:"text",text:J}],...I,isError:!1})}toolResult($,Z){return $.era.modern?this.complete(Z):Z}async approval($,Z,z,G,W){let X=Y2(Z,z),Y=(I,U="approval-declined")=>{return G(U,I),{kind:"answer",result:this.toolResult($,{content:[{type:"text",text:I}],isError:!0})}},K=(I,U)=>{return G(I,U.message),U};if($.era.modern){let I=q($.params._meta)?$.params._meta:{},U=q(I[q3])?I[q3]:{},F=q($.params.inputResponses)?$.params.inputResponses:null,B=$.params.requestState,T=G2(z);if(F&&B!==void 0){let C=R3(E3,"grs1",B);if(!C||C.p!==Q3($.principal)||C.t!==Z.name||C.a!==T)throw K("approval-invalid",new L(D.InvalidParams,"requestState is not valid for this call."));if(!await this.spendNonce(C.n,C.exp))throw K("approval-replayed",new L(D.InvalidParams,"requestState has already been used."));return S9(F[j9])?{kind:"approved"}:Y(`The user did not approve "${Z.name}", and it did not run.`)}if(!x9(U.elicitation))throw K("approval-unavailable",new L(D.MissingRequiredClientCapability,`"${Z.name}" needs the user's approval, and this client cannot ask for it (elicitation).`,{requiredCapabilities:{elicitation:{form:{}}}},400));let j={p:Q3($.principal),t:Z.name,a:T,n:_9(16).toString("base64url"),exp:Date.now()+O9};return W.pending=!0,{kind:"answer",result:{resultType:"input_required",inputRequests:{[j9]:{method:"elicitation/create",params:{mode:"form",...X}}},requestState:M3(E3,"grs1",j),_meta:{[T3]:this.serverInfo}}}}let Q=$.era;if(!Q.session.e||!$.stream)return Y(`"${Z.name}" needs the user's approval, and this client cannot ask for it (elicitation). It did not run.`,"approval-unavailable");let V=`gemi-approval-${_9(12).toString("base64url")}`,H=Q.sessionId,J=await new Promise((I)=>{let U=setTimeout(()=>{this.pending.delete(V),I(null)},this.approvalTimeoutMs),F=(B)=>{clearTimeout(U),I(B)};this.pending.set(V,{session:H,resolve:F}),$.signal.addEventListener("abort",()=>{this.pending.delete(V),F(null)}),$.stream.send({jsonrpc:"2.0",id:V,method:"elicitation/create",params:Q.session.v==="2025-11-25"?{mode:"form",...X}:X})});return J&&!J.error&&S9(J.result)?{kind:"approved"}:Y(`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 E9(()=>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 L)K.send(R($.id,Q));else console.error("[gemi/mcp] The MCP endpoint failed:",Q),K.send(R($.id,new L(D.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 L(D.InvalidRequest,"Unauthorized.")),401,{"WWW-Authenticate":z})}async failedAttempt($){let Z=T9(new m($,{},"api",this.endpoint.pathname)),z=await A3(`mcp-auth-failed:${Z}`,e$);return z===null?null:q9(z)}async spend($){if(!this.rateLimit)return null;let Z=await A3(`mcp-endpoint:${$.via}:${$.id}`,this.rateLimit);return Z===null?null:q9(Z)}}class E9{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 K3,Kc as F9,Xb as k9,ac as M9,ec as e,md as N9,rc as U9,xc as J9}from"./chunk-b4pqgz0f.js";import{Ad as V$,Cd as L$,td as p3,vd as B3,yd as d9,zd as p9}from"./chunk-2b3hh9xw.js";import{Fd as w9,Kd as v9,Md as h9,Td as x,Ud as g9,Vd as m9,Xd as u9,Yd as B$}from"./chunk-877yc341.js";import{$d as P}from"./chunk-eqv7yxk7.js";import{Af as k,Ag as x$,Bg as L3,Cg as d3,Df as Y$,Ef as G$,Ff as W$,Ge as H$,He as c3,Hf as w,Hg as X$,Ig as K$,Le as J3,Me as X3,Og as D$,Uf as a3,dg as t3,ef as m3,fg as n,jg as o3,kg as s9,le as l,lg as t9,me as z$,pe as T9,rg as f3,sf as Z3,sg as o9,te as O$,tg as G3,ug as r9,vg as e9,we as Q$,wg as w3,xg as a,yf as H3,zf as g3}from"./chunk-01tw5f26.js";import{Ai as P3,Bi as F3,Ci as z3,Th as c,Vh as m,ii as s3,wi as H9}from"./chunk-95vm1de8.js";import{Ii as i9}from"./chunk-cee5gq7t.js";import{Ti as h}from"./chunk-a8n9ec43.js";import{Zi as u3}from"./chunk-563ksar3.js";import{aj as U$,bj as i3,ej as N3,fj as n3,ij as F$}from"./chunk-n9n4qt20.js";import{Bj as n9,wj as l9}from"./chunk-xv58jnpb.js";import{Rj as f9,Tj as u}from"./chunk-86zhngpg.js";import{Uj as A}from"./chunk-attr793y.js";import{_j as I$}from"./chunk-2ery6a75.js";import{Ok as l3}from"./chunk-z7tsh9qr.js";import{Vk as U3,Yk as y}from"./chunk-1fyn63ka.js";import{fl as h3}from"./chunk-mzkzgp2j.js";import{ql as a9}from"./chunk-fqqbnp0z.js";var C$="mcp",S$=/^[\x21\x23-\x5B\x5D-\x7E]+$/;class O extends e{status;constructor($,Z){super($);this.status=Z;this.name="McpToolError"}}class v extends Error{reason;constructor($,Z){super($);this.reason=Z;this.name="McpCallRefusedError"}}var r3=/^[A-Za-z0-9_-]{1,64}$/,q$=/:([A-Za-z_][A-Za-z0-9_]*)([?*+]?)/g,e3=4000,M=1e5,T$=/^(text\/|application\/([\w.+-]*\+)?(json|xml))/i,B9=new WeakMap;function X6($){return B9.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=b$(z.files),this.featureOn=z.featureOn??X3;for(let[G,W]of Object.entries($.routes??{}))this.plans.set(G,k$(W)?this.planNative(G,W):this.plan(G,W));this.resolveScopes()}list($,Z){if(D3($),$.kind==="local")return this.descriptors(Z);let z=[];for(let[G,W]of this.plans){if(!W.remote||!this.grants($.principal,G))continue;if(W9(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(W9(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={}){D3($);let X=this.plans.get(Z);if(X&&!await this.isOn(X.descriptor)){if($.kind==="remote")throw new v(`There is no tool named "${Z}".`,"unknown-tool");throw new O(`There is no tool named "${Z}".`,404)}if($.kind==="remote"){if(!X?.remote||!this.grants($.principal,Z))throw new v(`There is no tool named "${Z}".`,"unknown-tool");if(X.descriptor.requiresApproval&&W.approved!==!0&&!W3(X))throw new v(`"${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 O(`Invalid arguments for "${Z}": ${Q.errors.join(", ")}`);let V=Q.value,H={caller:$,req:$.req,tool:K,input:V,ctx:G},J=await this.fillPath(Y,H),{path:I}=this.dispatcher.getRouteHandlerAndParams(new Request(`http://gemi.internal/api${J}`));if(I!==K.url)throw new O(`"${Z}" has nothing at ${J}.`,404);let U={};for(let _ of Y.jsonKeys)if(V[_]!==void 0)U[_]=V[_];let F,B="";if(Y.fileFields.length>0)F=await this.formData(Y,U,H);else if(K.method==="GET")B=p$(U);else if(Y.jsonKeys.length>0)F=U;let T=this.router.credentials?await this.bind(Y,"the credentials",()=>this.router.credentials(H)):void 0,j={...T?{credentials:T}:{},...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}:{}}}}:{}},C;try{let _=B?`${J}?${B}`:J;C=Object.keys(j).length>0?await this.dispatcher.dispatchAs($.req,K.method,_,F,j):await this.dispatcher.dispatchAs($.req,K.method,_,F)}catch(_){throw console.error(`[gemi/mcp] Dispatching "${Z}" failed:`,_),new O(`"${Z}" failed on the server.`,500)}if(!Y.result&&!K.outputSchema)return await V9(Z,C);return await this.project(Y,H,C)}async isOn($){return $.feature===void 0||await this.featureOn($.feature)===!0}plan($,Z){if(!r3.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(q$)].map(([,N,S])=>({name:N,modifier:S})),Q=X.params??{};for(let N of K)if(!(N.name in Q))throw Error(`${z}: the path param "${N.name}" must be bound or declared "input".`);for(let[N,S]of Object.entries(Q)){if(!K.some((g)=>g.name===N))throw Error(`${z}: "${N}" in params is not a param of the url.`);if(Y9(S))h$(z,`params.${N}`,S);else X9(z,`params.${N}`,S)}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 J=Object.entries(X.files??{}).map(([N,S])=>({name:N,binder:S}));for(let N of J)X9(z,`files.${N.name}`,N.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 I=K9(z,G,X.annotations);if(J.length>0&&G==="GET")throw Error(`${z}: a GET has no body to carry a file.`);let U={},F=(N,S)=>{if(N in U)throw Error(`${z}: "${N}" is the input key of two params or files, and the model can only send one.`);U[N]=S},B=new Map,T=new Map;for(let N of K){let S=Q[N.name];if(S==="input"){let g=c.string().describe(`The ":${N.name}" segment of the url.`);F(N.name,N.modifier==="?"||N.modifier==="*"?g.optional():g)}else if(Y9(S)){let g=S.as??N.name;F(g,S.input),T.set(N.name,{key:g,param:S})}else B.set(N.name,S)}let j={};for(let N of J)if(N.binder==="input")F(N.name,c.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[N.name]=this.remoteFileSchema();let C=[...Object.keys(U),...J.map((N)=>N.name)];for(let N of new Set(C))if(V.includes(N))throw Error(`${z}: "${N}" is both an input field and a param or file, and the model can only send one.`);let _=Object.freeze({kind:"route",name:$,description:X.description,method:G,url:W,inputSchema:Q9(X.input,H,c.object(U)),...X.output?{outputSchema:X.output}:{},...X.title?{title:X.title}:{},annotations:I,tags:Object.freeze([...X.tags??[]]),requiresApproval:X.requiresApproval===!0,...X.feature!==void 0?{feature:X.feature}:{},...Y.source?{source:Y.source}:{}}),r=!J.every((N)=>N.binder==="input")?null:J.length===0?_:Object.freeze({..._,inputSchema:Q9(X.input,H,c.object(u$(U,Object.keys(j))),j)});return{kind:"route",descriptor:_,remote:r,params:K,paramBinders:B,modelParams:T,fileFields:J,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(!r3.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:K9(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}}async approvalRequired($,Z,z,G={}){let W=this.plans.get(Z);if(!W)return!0;if(!W3(W))return W.descriptor.requiresApproval;let X=W;if($.kind!=="remote"||!X.meta.remote)return!0;let Y=X.descriptor.inputSchema.safeParse(z);if(Y.ok===!1)return!0;let K={caller:$,req:$.req,tool:X.descriptor,input:Y.value},Q;try{Q=await this.bind(X,"the remote context",()=>X.meta.remote.context(K))}catch{return!0}if(typeof Q!=="object"||Q===null)return!0;let V=G.signal??new AbortController().signal;return G9(X,Y.value,z9(Z9(X,Q,V)))}nativeApproval($){let Z=this.plans.get($);if(Z?.kind!=="tool")throw Error(`McpRegistry: there is no native tool named "${$}".`);return W3(Z)??Z.descriptor.requiresApproval}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(D3($),$.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 O(`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 B9.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 O(`Invalid arguments for "${X}": ${Y.errors.join(", ")}`);let K={caller:Z,req:Z.req,tool:$.descriptor,input:Y.value},Q=(_,_3)=>{if(!W.progress)return;let r;try{r=$.meta.remote?.progress?$.meta.remote.progress(_,_3):R$(_,_3)}catch(N){console.error(`[gemi/mcp] The progress mapping of "${X}" failed:`,N);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 $9(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 O(`"${X}" failed on the server.`,500);let J=$.tool.timeoutMs,I=[...W.signal?[W.signal]:[],...J!==void 0?[AbortSignal.timeout(J)]:[]],U=I.length===0?new AbortController().signal:I.length===1?I[0]:AbortSignal.any(I),F=Z9($,H,U);if(!W.approved&&W3($)&&await G9($,K.input,z9(F)))throw new v(`"${X}" needs the user's approval, and this call does not have it.`,"approval-required");let B;try{B=await $9(this.runNative($,{...K,ctx:F},F),Q,U)}catch(_){if(U.aborted&&_===U.reason){if(W.signal?.aborted)throw new O(`"${X}" was cancelled.`,499);throw new O(`"${X}" did not finish within ${J} ms.`,504)}if(_ instanceof O)throw _;if(_ instanceof e||_ instanceof v)throw new O(_.message);throw console.error(`[gemi/mcp] "${X}" failed for a remote caller:`,_),new O(`"${X}" failed on the server.`,500)}let T=(_)=>{return console.error(`[gemi/mcp] "${X}" ${_}`),new O(`"${X}" failed on the server.`,500)};if(U9(B))throw T("answered a job handle, and a remote call has no background jobs.");let j=B;if($.descriptor.outputSchema){let _=$.descriptor.outputSchema.safeParse(j);if(_.ok===!1)throw T(`answered what its output schema refuses: ${_.errors.join(", ")}`);j=_.value}if(j===void 0)return null;if(typeof j==="string")return j.length>M?`${j.slice(0,M)}\u2026 [cut at ${M} of ${j.length} characters]`:j;let C=JSON.stringify(j);if(C!==void 0&&C.length>M)return`${C.slice(0,M)}\u2026 [cut at ${M} of ${C.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 O(`"${$.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 O(`"${X.name}" of "${$.descriptor.name}" must not be empty.`);W=W.replace(`/${V}`,"");continue}W=W.replace(V,d$($.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))O3(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))O3(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 O(`"${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 O(`"${Z}" of "${$}" ${H}`,400),W=z,{maxBytes:X,fetch:Y}=this.files;if(!y$(W.name))throw G("needs a name of 1 to 255 characters, without control characters or slashes.");if(!f$.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)-v$(H)>X)throw G(`is larger than the ${X} bytes a file may be.`);if(H.length%4!==0||!w$.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 H9(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 J=await H.arrayBuffer();return new File([J],W.name,{type:W.mimeType})}catch(H){if(H instanceof O)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(C$,{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(!S$.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 V9(G,z);let X=(J,I)=>{if(I===void 0)console.error(`[gemi/mcp] "${G}" ${J}`);else console.error(`[gemi/mcp] "${G}" ${J}`,I);return new O(`"${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(J){throw X("failed in its result projection:",J)}if(W){let J=W.safeParse(V);if(J.ok===!1)throw X(`answered what its output schema refuses: ${J.errors.join(", ")}`);V=J.value}if(V===void 0)return null;let H=JSON.stringify(V);if(H!==void 0&&H.length>M)return`${H.slice(0,M)}\u2026 [cut at ${M} 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 O(`"${$.descriptor.name}" failed on the server.`,500)}}}function k$($){return $ instanceof Object&&$.__internal_brand==="McpTool"}function M$($){return typeof $==="object"&&$!==null&&typeof $.next==="function"&&Symbol.asyncIterator in $}async function $9($,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(!M$($))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 R$($,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 Z9($,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)=>N9({...Q,signal:Q.signal?AbortSignal.any([z,Q.signal]):z},{origin:{mcp:G,runId:W,toolCallId:X}}),jobs:J9({jobs:void 0,threadId:void 0,runId:W,toolCallId:X,toolName:G,depth:0,async:$.tool.async,attachments:null}),memory:F9()}}function W3($){if($.kind!=="tool"||$.meta.requiresApproval===!0)return;return $.tool.approvalPredicate}function z9($){return{context:$.context,body:$.body,runId:$.runId,threadId:$.threadId,toolCallId:$.toolCallId,step:$.step,depth:$.depth,signal:$.signal}}async function G9($,Z,z){try{return await $.tool.approvalPredicate(Z,z)!==!1}catch(G){return console.error(`[gemi/mcp] The requiresApproval of "${$.descriptor.name}" threw, so the call asks the user:`,G),!0}}function D3($){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 W9($,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 E$=10485760;function b$($){let Z=$?.maxBytes??E$;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 y$($){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 f$=/^[A-Za-z0-9][A-Za-z0-9!#$&^_.+-]{0,126}\/[A-Za-z0-9][A-Za-z0-9!#$&^_.+-]{0,126}(\s*;.{0,200})?$/,w$=/^[A-Za-z0-9+/]*={0,2}$/;function v$($){return $.endsWith("==")?2:$.endsWith("=")?1:0}function X9($,Z,z){if(z!=="input"&&typeof z!=="function")throw Error(`${$}: ${Z} must be a function or "input".`)}function Y9($){return $ instanceof Object&&$.__internal_brand==="McpModelParam"}function h$($,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 g$=new Set(["readOnlyHint","destructiveHint","idempotentHint","openWorldHint"]);function m$($){switch($){case"GET":return{readOnlyHint:!0};case"DELETE":return{destructiveHint:!0};case"PUT":return{idempotentHint:!0};default:return{}}}function K9($,Z,z){if(z!==void 0&&(typeof z!=="object"||z===null))throw Error(`${$}: annotations must be an object of hints.`);let G=Z?m$(Z):{};for(let[W,X]of Object.entries(z??{})){if(!g$.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 Q9($,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 I=$.safeParse(Q);if(I.ok===!1)V.push(...I.errors);else H={...I.value}}let J=z.safeParse(Q);if(J.ok===!1)V.push(...J.errors);else H={...H,...J.value};for(let[I,U]of Object.entries(G)){let F=Q[I];if(F===void 0){V.push(`"${I}" is required`);continue}let B=U.safeParse(F);if(B.ok===!1)V.push(...B.errors.map((T)=>`${I}: ${T}`));else H[I]=B.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 u$($,Z){return Object.fromEntries(Object.entries($).filter(([z])=>!Z.includes(z)))}function d$($,Z,z){let G=Z.modifier==="*"||Z.modifier==="+"?z.split("/"):[z];if(G.some((W)=>W==="."||W===".."))throw new O(`"${z}" is not a valid value for "${Z.name}" of "${$}".`);return G.map(encodeURIComponent).join("/")}function O3($,Z,z){if(z===void 0||z===null)return;if(Array.isArray(z)){for(let G of z)O3($,Z,G);return}$.append(Z,typeof z==="object"?JSON.stringify(z):String(z))}function p$($){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 V9($,Z){if(Z.status>=200&&Z.status<300){let G=Z.headers.get("Content-Type");if(G&&!T$.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>M)return`${W.slice(0,M)}\u2026 [cut at ${M} 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>e3?`${z.slice(0,e3)}\u2026`:z;throw new O(`"${$}" 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 O(`"${$}" failed on the server.`,Z.status)}import{createHash as c$,randomBytes as i$,timingSafeEqual as l$}from"crypto";function j3($){let Z=$.headers.get("authorization");if(!Z)return null;let z=/^Bearer[ ]+([\x21-\x7e]+)$/i.exec(Z.trim());return z?z[1]:null}class n${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`${$}${i$(32).toString("base64url")}`}static hash($){return c$("sha256").update($).digest("hex")}static hashesMatch($,Z){let z=Buffer.from($),G=Buffer.from(Z);return z.length===G.length&&l$(z,G)}async resolve($){let Z=j3($);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 R9,randomBytes as _9}from"crypto";async function A3($,Z){let z=s$();if(!z)return null;let G=await z.consume($,Z);return G.allowed?null:Math.max(1,Math.ceil(G.retryAfter/1000))}function s$(){try{let $=y();return $.bound(l)?$.make(l):null}catch{return null}}var x3=["2026-07-28"],Y3=["2025-11-25","2025-06-18","2025-03-26"],C3=[...x3,...Y3],S3="io.modelcontextprotocol/protocolVersion",q3="io.modelcontextprotocol/clientCapabilities";var T3="io.modelcontextprotocol/serverInfo",D={ParseError:-32700,InvalidRequest:-32600,MethodNotFound:-32601,InvalidParams:-32602,InternalError:-32603,HeaderMismatch:-32020,MissingRequiredClientCapability:-32021,UnsupportedProtocolVersion:-32022};class L 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 P9($){if(Array.isArray($))throw new L(D.InvalidRequest,"Batched requests are not supported.",void 0,400);if(typeof $!=="object"||$===null||$.jsonrpc!=="2.0")throw new L(D.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 L(D.InvalidRequest,"params must be an object.",void 0,400);if(z===void 0)return{kind:"notification",message:Z};if(!G)throw new L(D.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 L(D.InvalidRequest,"Not a JSON-RPC request, notification or response.",void 0,400)}function k3($,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 q($){return typeof $==="object"&&$!==null&&!Array.isArray($)}function I9($){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 t$,timingSafeEqual as o$}from"crypto";function M3($,Z,z){let G=Buffer.from(JSON.stringify(z)).toString("base64url");return`${Z}.${G}.${L9($,Z,G).toString("base64url")}`}function R3($,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=L9($,Z,X);if(K.length!==Q.length||!o$(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 L9($,Z,z){return t$("sha256",K3($)).update(`${Z}.${z}`).digest()}var E3="gemi.mcp.request-state.v1",D9="gemi.mcp.session.v1",a$=86400000,O9=600000,j9="gemi_approval",b3=2000,r$={limit:600,window:60},e$={limit:30,window:60};class $3{registry;static token="router.mcp.http";endpoint;resolvers;context;allowedOrigins;rateLimit;maxBodyBytes;serverInfo;instructions;nonces;approvalTimeoutMs;onCall;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=z2(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,K3(E3),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??r$,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 k9,this.approvalTimeoutMs=Z.approvalTimeoutMs??O9,Z.onCall!==void 0&&typeof Z.onCall!=="function")throw Error("route.mcp.remote.onCall must be a function.");if(this.onCall=Z.onCall,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??X3;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 L(D.InvalidRequest,"Origin not allowed.")),403);let G=z?Z2(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 A9(new Response(null,{status:405,headers:{Allow:"POST, OPTIONS"}}),G);return A9(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(j3($)!==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 $2($,this.maxBodyBytes))}catch(Y){if(Y instanceof V3)return f(R(null,new L(D.InvalidRequest,`The request is larger than ${this.maxBodyBytes} bytes.`)),413);return f(R(null,new L(D.ParseError,"Parse error.")),400)}let X=new m($,{},"api",this.endpoint.pathname);return await h.run(X,async()=>{try{return await this.dispatch($,X,Z,W)}catch(Y){if(Y instanceof L){let K=q(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 L(D.InternalError,"Internal error.")),500)}},{user:Z.user})}async dispatch($,Z,z,G){let W=P9(G),X={kind:"remote",req:Z,principal:z};if(W.kind==="response"){let F=this.session($,z),B=this.pending.get(String(W.message.id));if(B&&B.session===F.id)this.pending.delete(String(W.message.id)),B.resolve(W.message);return new Response(null,{status:202})}let{message:Y}=W,K=Y.params??{},Q=q(K._meta)?K._meta:{};if(typeof Q[S3]==="string"){if(this.checkModernHeaders($,Y,Q[S3]),W.kind==="notification")return new Response(null,{status:202});return await this.respond(Y,async(F,B)=>this.modern({principal:z,caller:X,message:Y,params:K,era:{modern:!0},stream:F,signal:B}),C9(K),$.signal)}if(Y.method==="initialize"){if(W.kind!=="request")throw new L(D.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 L(D.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 F=K.requestId;this.inflight.get(`${V.id}:${String(F)}`)?.abort()}return new Response(null,{status:202})}let J=`${V.id}:${String(Y.id)}`,I=new AbortController;this.inflight.set(J,I);let U=AbortSignal.any([I.signal,$.signal]);try{return await this.respond(Y,async(F,B)=>this.legacy({principal:z,caller:X,message:Y,params:K,era:{modern:!1,session:V.state,sessionId:V.id},stream:F,signal:B}),C9(K)||W2(this.registry,Y,V.state),U,()=>this.inflight.delete(J))}catch(F){throw this.inflight.delete(J),F}}async modern($){switch($.message.method){case"server/discover":return this.complete({supportedVersions:C3,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)=>k3(Z,!0)),ttlMs:60000,cacheScope:"private"});case"tools/call":return await this.callTool($);default:throw new L(D.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)=>k3(Z,!1))};case"tools/call":return await this.callTool($);default:throw new L(D.MethodNotFound,`Method not found: ${$.message.method}`)}}complete($){return{resultType:"complete",...$,_meta:{[T3]:this.serverInfo}}}initialize($,Z,z){let G=Z.protocolVersion,W=Y3.includes(G)?G:Y3[0],X=q(Z.capabilities)?Z.capabilities:{},Y={v:W,e:x9(X.elicitation),p:Q3(z),exp:Date.now()+a$},K=M3(D9,"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 L(D.InvalidRequest,"Missing Mcp-Session-Id. Send initialize first, or a request carrying io.modelcontextprotocol/protocolVersion in _meta.",void 0,400);let G=R3(D9,"gms1",z);if(!G||G.p!==Q3(Z))throw new L(D.InvalidRequest,"Session not found.",void 0,404);return{id:z,state:G}}checkModernHeaders($,Z,z){if(!x3.includes(z))throw new L(D.UnsupportedProtocolVersion,"Unsupported protocol version",{supported:C3,requested:z},400);let G=(Y)=>new L(D.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||I9(Y)!==X)throw G("Mcp-Name does not match the request's name.")}}async callTool($){let Z=$.params.name;if(typeof Z!=="string")throw new L(D.InvalidParams,"tools/call needs a tool name.");let z=$.params.arguments??{};if(!this.onCall)return await this.runTool($,Z,z,{approved:!1});let G=performance.now(),W={approved:!1};try{let X=await this.runTool($,Z,z,W);if(!W.pending)await this.report($,Z,z,W,G);return X}catch(X){if(!W.outcome){if(W.outcome="error",W.message=X instanceof L?X.message:"Internal error.",!(X instanceof L))W.error=X}throw await this.report($,Z,z,W,G),X}}async report($,Z,z,G,W){let{principal:X}=$;try{await this.onCall({user:X.user,via:X.via,credentialId:X.id,clientId:X.clientId??null,scopes:X.scopes,tool:Z,arguments:z,outcome:G.outcome??"ok",...G.reason!==void 0?{reason:G.reason}:{},...G.message!==void 0?{message:G.message}:{},...G.status!==void 0?{status:G.status}:{},...G.error!==void 0?{error:G.error}:{},approved:G.approved,durationMs:Math.round((performance.now()-W)*1000)/1000,req:$.caller.req})}catch(Y){console.error(`[gemi/mcp] route.mcp.remote.onCall failed for "${Z}":`,Y)}}async runTool($,Z,z,G){let{caller:W,principal:X}=$,Y=(U,F)=>{G.outcome="denied",G.reason=U,G.message=F},K=(U,F,B)=>{if(G.outcome="error",G.message=U,F!==void 0)G.status=F;if(B!==void 0)G.error=B},Q=(await this.registry.available(W,{names:[Z]}))[0];if(!Q)throw Y("unknown-tool",`Unknown tool: ${Z}`),new L(D.InvalidParams,`Unknown tool: ${Z}`);if(Q.requiresApproval){let U=Q.inputSchema.safeParse(z);if(U.ok===!1){let B=`Invalid arguments for "${Z}": ${U.errors.join(", ")}`;return K(B),this.toolResult($,{content:[{type:"text",text:B}],isError:!0})}if($.era.modern&&q($.params.inputResponses)&&$.params.requestState!==void 0||await this.registry.approvalRequired(W,Z,z,{signal:$.signal})){let B=await this.approval($,Q,z,Y,G);if(B.kind==="answer")return B.result;G.approved=!0}}let V=X2($),H;try{H=await this.registry.execute(W,Z,z,void 0,{approved:G.approved,signal:$.signal,...V?{progress:V}:{}})}catch(U){if(U instanceof O){if(U.status===401||U.status===403)Y("forbidden",U.message),G.status=U.status;else K(U.message,U.status);return this.toolResult($,{content:[{type:"text",text:U.message}],isError:!0})}if(U instanceof v){let B=U.reason==="unknown-tool"?`Unknown tool: ${Z}`:U.message;throw Y(U.reason,B),new L(D.InvalidParams,B)}console.error(`[gemi/mcp] "${Z}" failed for ${X.via}:${X.id}:`,U);let F=`"${Z}" failed on the server.`;return K(F,void 0,U),this.toolResult($,{content:[{type:"text",text:F}],isError:!0})}let J=typeof H==="string"?H:JSON.stringify(H??null),I=Q.outputSchema&&($.era.modern||q(H))?{structuredContent:H}:{};return G.outcome="ok",this.toolResult($,{content:[{type:"text",text:J}],...I,isError:!1})}toolResult($,Z){return $.era.modern?this.complete(Z):Z}async approval($,Z,z,G,W){let X=Y2(Z,z),Y=(I,U="approval-declined")=>{return G(U,I),{kind:"answer",result:this.toolResult($,{content:[{type:"text",text:I}],isError:!0})}},K=(I,U)=>{return G(I,U.message),U};if($.era.modern){let I=q($.params._meta)?$.params._meta:{},U=q(I[q3])?I[q3]:{},F=q($.params.inputResponses)?$.params.inputResponses:null,B=$.params.requestState,T=G2(z);if(F&&B!==void 0){let C=R3(E3,"grs1",B);if(!C||C.p!==Q3($.principal)||C.t!==Z.name||C.a!==T)throw K("approval-invalid",new L(D.InvalidParams,"requestState is not valid for this call."));if(!await this.spendNonce(C.n,C.exp))throw K("approval-replayed",new L(D.InvalidParams,"requestState has already been used."));return S9(F[j9])?{kind:"approved"}:Y(`The user did not approve "${Z.name}", and it did not run.`)}if(!x9(U.elicitation))throw K("approval-unavailable",new L(D.MissingRequiredClientCapability,`"${Z.name}" needs the user's approval, and this client cannot ask for it (elicitation).`,{requiredCapabilities:{elicitation:{form:{}}}},400));let j={p:Q3($.principal),t:Z.name,a:T,n:_9(16).toString("base64url"),exp:Date.now()+O9};return W.pending=!0,{kind:"answer",result:{resultType:"input_required",inputRequests:{[j9]:{method:"elicitation/create",params:{mode:"form",...X}}},requestState:M3(E3,"grs1",j),_meta:{[T3]:this.serverInfo}}}}let Q=$.era;if(!Q.session.e||!$.stream)return Y(`"${Z.name}" needs the user's approval, and this client cannot ask for it (elicitation). It did not run.`,"approval-unavailable");let V=`gemi-approval-${_9(12).toString("base64url")}`,H=Q.sessionId,J=await new Promise((I)=>{let U=setTimeout(()=>{this.pending.delete(V),I(null)},this.approvalTimeoutMs),F=(B)=>{clearTimeout(U),I(B)};this.pending.set(V,{session:H,resolve:F}),$.signal.addEventListener("abort",()=>{this.pending.delete(V),F(null)}),$.stream.send({jsonrpc:"2.0",id:V,method:"elicitation/create",params:Q.session.v==="2025-11-25"?{mode:"form",...X}:X})});return J&&!J.error&&S9(J.result)?{kind:"approved"}:Y(`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 E9(()=>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 L)K.send(R($.id,Q));else console.error("[gemi/mcp] The MCP endpoint failed:",Q),K.send(R($.id,new L(D.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 L(D.InvalidRequest,"Unauthorized.")),401,{"WWW-Authenticate":z})}async failedAttempt($){let Z=T9(new m($,{},"api",this.endpoint.pathname)),z=await A3(`mcp-auth-failed:${Z}`,e$);return z===null?null:q9(z)}async spend($){if(!this.rateLimit)return null;let Z=await A3(`mcp-endpoint:${$.via}:${$.id}`,this.rateLimit);return Z===null?null:q9(Z)}}class E9{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 V3 extends Error{}async function $2($,Z){let z=Number($.headers.get("content-length"));if(Number.isFinite(z)&&z>Z)throw new V3;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 V3;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 A9($,Z){for(let[z,G]of Object.entries(Z))$.headers.set(z,G);return $}function Z2($){return{"Access-Control-Allow-Origin":$,"Access-Control-Expose-Headers":"Mcp-Session-Id, WWW-Authenticate",Vary:"Origin"}}function z2($){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 Q3($){return R9("sha256").update(`${$.via}\x00${$.id}\x00${$.user?.id}`).digest("base64url").slice(0,32)}function G2($){return R9("sha256").update(M9($??{})).digest("base64url")}function x9($){if(!q($))return!1;if(Object.keys($).length===0)return!0;return"form"in $}function C9($){let Z=q($._meta)?$._meta:{};return typeof Z.progressToken==="string"||typeof Z.progressToken==="number"}function W2($,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 X2($){let z=(q($.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 Y2($,Z){let z=JSON.stringify(Z??{},null,1),G=z.length>b3?`${z.slice(0,b3)}\u2026 (${z.length-b3} more characters not shown)`:z;return{message:`Allow "${$.title??$.name}" to run? ${$.description}
@@ -1,5 +1,5 @@
1
1
  // @bun
2
- import{R as S,T as h,U as u}from"./chunk-3tjn78zh.js";import{ma as q,na as w}from"./chunk-mv1rs9he.js";import"./chunk-a22h5cby.js";import"./chunk-epvpmakp.js";import"./chunk-r3v2cnrj.js";import"./chunk-twrf6d08.js";import"./chunk-kk18xqgc.js";import"./chunk-ymdpt00k.js";import{Li as N}from"./chunk-cee5gq7t.js";import{bl as y}from"./chunk-g8sh9btf.js";import{ql as C}from"./chunk-fqqbnp0z.js";import"./chunk-jzpbwvbt.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-56k4fg31.js";import{ma as q,na as w}from"./chunk-mv1rs9he.js";import"./chunk-a22h5cby.js";import"./chunk-epvpmakp.js";import"./chunk-r3v2cnrj.js";import"./chunk-twrf6d08.js";import"./chunk-kk18xqgc.js";import"./chunk-ymdpt00k.js";import{Li as N}from"./chunk-cee5gq7t.js";import{bl as y}from"./chunk-g8sh9btf.js";import{ql as C}from"./chunk-fqqbnp0z.js";import"./chunk-jzpbwvbt.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,5 +1,5 @@
1
1
  // @bun
2
- import{Ea as E}from"../chunk-bstn00nx.js";import{$a as p}from"../chunk-fka28ceg.js";import{ab as H}from"../chunk-49s8wwp2.js";import{Bb as L,Cb as Q,Db as T,Hb as U,Ib as y,Jb as F,Kb as C,Nb as D,Ob as I,Rb as b,Ub as f,Vb as k,Wb as m,nb as g,ob as W,pb as _,qb as l,rb as P,sb as u,tb as $,ub as V,vb as q,wb as B,xb as K}from"../chunk-r9exzwqt.js";import"../chunk-ezn89ezm.js";import"../chunk-2b3hh9xw.js";import"../chunk-v9z4x5j2.js";import{Td as h}from"../chunk-877yc341.js";import"../chunk-ydkv9e8w.js";import"../chunk-eqv7yxk7.js";import{Bg as R,Ne as n,Oe as v,tg as w,ue as a,ve as d,xg as A}from"../chunk-01tw5f26.js";import"../chunk-hh5bs656.js";import"../chunk-3csz8pfk.js";import"../chunk-95vm1de8.js";import"../chunk-cee5gq7t.js";import"../chunk-a8n9ec43.js";import"../chunk-563ksar3.js";import{cj as M}from"../chunk-n9n4qt20.js";import"../chunk-xv58jnpb.js";import"../chunk-313593t3.js";import"../chunk-86zhngpg.js";import"../chunk-attr793y.js";import"../chunk-2ery6a75.js";import"../chunk-73rzf7ys.js";import"../chunk-2x6cv37t.js";import"../chunk-z7tsh9qr.js";import"../chunk-mr3szvr3.js";import{Vk as O,Xk as z}from"../chunk-1fyn63ka.js";import"../chunk-e9z8p2fy.js";import"../chunk-g8sh9btf.js";import"../chunk-mzkzgp2j.js";import"../chunk-apga49vp.js";import"../chunk-fqqbnp0z.js";import"../chunk-jzpbwvbt.js";var N=[C,I,E,T,L,k,B,Q,D,y,_,U,f,V,F,H,b,K,q,m,$];class S{config={};providers=[];services=[];serviceInstances=[];serviceTokens=new Set;servicesBooted=!1;models=[];app=new z;boot(){if(this.models.length>0)p(...this.models);else s();this.app.config.merge(this.config),z.setInstance(this.app),this.app.registerMany([...N,...this.providers]),this.registerServices()}registerServices(){let j=this.serviceTokens;this.serviceInstances=[],this.serviceTokens=new Set,this.servicesBooted=!1;let X=new Map;for(let G of this.services){let J=typeof G==="function"?new G:G,x=J.constructor;if(!x.token)throw Error(`Service [${x.name}] is listed in \`services\` but does not declare a \`static token\`.`);let Y=X.get(x.token);if(Y)throw Error(`Services [${Y}] and [${x.name}] both declare the token "${x.token}". Tokens are the container's keys, so they must be unique.`);X.set(x.token,x.name);let Z=x;if(!j.has(x.token)&&this.app.bound(Z))throw Error(`Service [${x.name}] declares the token "${x.token}", which is already bound in the container by the framework or a provider. Binding it would replace that service everywhere, so pick a token nothing else owns.`);this.app.instance(Z,J),this.serviceInstances.push(J),this.serviceTokens.add(x.token)}}async waitForBoot(){await this.app.boot(),await this.bootServices(),l(this.app)}async bootServices(){if(this.servicesBooted)return;for(let j of this.serviceInstances)await j.boot();this.servicesBooted=!0}shutdown(j){return this.run(()=>this.app.shutdown(j))}run(j){return O.run(this.app,j)}resolve(j){return this.app.make(j)}apiRoutes(){return this.app.make(A)}viewRoutes(){return this.app.make(w)}domains(){return this.app.make(R)}queue(){return this.app.make(h)}mcpHttp(){return this.app.config.get("route.mcp.remote.enabled")===!0?this.app.make(g):null}sockets(){return this.app.config.get("route.channels")?this.app.make(u):null}globalMiddleware(j){return P(j)}destroy(){if(this.app.resolved(W))this.app.make(W).stop();if(this.app.flush(),z.getInstance()===this.app)z.setInstance(void 0);O.disable()}}function s(){if(Bun.env.NODE_ENV==="production")return;let j=M();if(j.length===0)return;console.warn(`[gemi] ${j.length} model${j.length===1?" is":"s are"} registered, but Kernel.models is empty.
2
+ import{Ea as E}from"../chunk-bstn00nx.js";import{$a as p}from"../chunk-fka28ceg.js";import{ab as H}from"../chunk-49s8wwp2.js";import{Bb as L,Cb as Q,Db as T,Hb as U,Ib as y,Jb as F,Kb as C,Nb as D,Ob as I,Rb as b,Ub as f,Vb as k,Wb as m,nb as g,ob as W,pb as _,qb as l,rb as P,sb as u,tb as $,ub as V,vb as q,wb as B,xb as K}from"../chunk-h34n0w2w.js";import"../chunk-b4pqgz0f.js";import"../chunk-2b3hh9xw.js";import"../chunk-v9z4x5j2.js";import{Td as h}from"../chunk-877yc341.js";import"../chunk-ydkv9e8w.js";import"../chunk-eqv7yxk7.js";import{Bg as R,Ne as n,Oe as v,tg as w,ue as a,ve as d,xg as A}from"../chunk-01tw5f26.js";import"../chunk-hh5bs656.js";import"../chunk-3csz8pfk.js";import"../chunk-95vm1de8.js";import"../chunk-cee5gq7t.js";import"../chunk-a8n9ec43.js";import"../chunk-563ksar3.js";import{cj as M}from"../chunk-n9n4qt20.js";import"../chunk-xv58jnpb.js";import"../chunk-313593t3.js";import"../chunk-86zhngpg.js";import"../chunk-attr793y.js";import"../chunk-2ery6a75.js";import"../chunk-73rzf7ys.js";import"../chunk-2x6cv37t.js";import"../chunk-z7tsh9qr.js";import"../chunk-mr3szvr3.js";import{Vk as O,Xk as z}from"../chunk-1fyn63ka.js";import"../chunk-e9z8p2fy.js";import"../chunk-g8sh9btf.js";import"../chunk-mzkzgp2j.js";import"../chunk-apga49vp.js";import"../chunk-fqqbnp0z.js";import"../chunk-jzpbwvbt.js";var N=[C,I,E,T,L,k,B,Q,D,y,_,U,f,V,F,H,b,K,q,m,$];class S{config={};providers=[];services=[];serviceInstances=[];serviceTokens=new Set;servicesBooted=!1;models=[];app=new z;boot(){if(this.models.length>0)p(...this.models);else s();this.app.config.merge(this.config),z.setInstance(this.app),this.app.registerMany([...N,...this.providers]),this.registerServices()}registerServices(){let j=this.serviceTokens;this.serviceInstances=[],this.serviceTokens=new Set,this.servicesBooted=!1;let X=new Map;for(let G of this.services){let J=typeof G==="function"?new G:G,x=J.constructor;if(!x.token)throw Error(`Service [${x.name}] is listed in \`services\` but does not declare a \`static token\`.`);let Y=X.get(x.token);if(Y)throw Error(`Services [${Y}] and [${x.name}] both declare the token "${x.token}". Tokens are the container's keys, so they must be unique.`);X.set(x.token,x.name);let Z=x;if(!j.has(x.token)&&this.app.bound(Z))throw Error(`Service [${x.name}] declares the token "${x.token}", which is already bound in the container by the framework or a provider. Binding it would replace that service everywhere, so pick a token nothing else owns.`);this.app.instance(Z,J),this.serviceInstances.push(J),this.serviceTokens.add(x.token)}}async waitForBoot(){await this.app.boot(),await this.bootServices(),l(this.app)}async bootServices(){if(this.servicesBooted)return;for(let j of this.serviceInstances)await j.boot();this.servicesBooted=!0}shutdown(j){return this.run(()=>this.app.shutdown(j))}run(j){return O.run(this.app,j)}resolve(j){return this.app.make(j)}apiRoutes(){return this.app.make(A)}viewRoutes(){return this.app.make(w)}domains(){return this.app.make(R)}queue(){return this.app.make(h)}mcpHttp(){return this.app.config.get("route.mcp.remote.enabled")===!0?this.app.make(g):null}sockets(){return this.app.config.get("route.channels")?this.app.make(u):null}globalMiddleware(j){return P(j)}destroy(){if(this.app.resolved(W))this.app.make(W).stop();if(this.app.flush(),z.getInstance()===this.app)z.setInstance(void 0);O.disable()}}function s(){if(Bun.env.NODE_ENV==="production")return;let j=M();if(j.length===0)return;console.warn(`[gemi] ${j.length} model${j.length===1?" is":"s are"} registered, but Kernel.models is empty.
3
3
  Nested relation reads resolve a model by name, so a policy on a subclass that does not own its
4
4
  `+" name is skipped inside every include \u2014 scoped at the root, "+`unscoped in an include, with nothing
5
5
  to notice it. Declaring the modules registers each class under its own name and audits the set:
@@ -1,4 +1,4 @@
1
1
  // @bun
2
- import{Ca as f}from"../chunk-kk18xqgc.js";import{Da as S}from"../chunk-ymdpt00k.js";import{fl as Q,hl as Z,il as P,jl as y,kl as U,ll as A}from"../chunk-mzkzgp2j.js";import{pl as H}from"../chunk-apga49vp.js";import"../chunk-fqqbnp0z.js";import{wl as F}from"../chunk-jzpbwvbt.js";var x="/__gemi__/health",$=Symbol.for("gemi.server.health");function V(){let z=globalThis;return z[$]??={lagMs:0,consecutiveBreaches:0,degraded:!1,timer:void 0},z[$]}function W(){let z=V(),B=Q();return{healthy:!B&&!z.degraded,shuttingDown:B,lagMs:z.lagMs,consecutiveBreaches:z.consecutiveBreaches}}function E(z,B){let I=V();I.lagMs=z,I.consecutiveBreaches=z>B.maxLagMs?I.consecutiveBreaches+1:0;let J=I.consecutiveBreaches>=B.breaches;if(J&&!I.degraded)console.warn(`[gemi] Health: degraded (event-loop lag ${Math.round(z)}ms, ${I.consecutiveBreaches} samples in a row over ${B.maxLagMs}ms).`);else if(!J&&I.degraded)console.log(`[gemi] Health: recovered (event-loop lag ${Math.round(z)}ms).`);I.degraded=J}function G(z){let B=V();if(B.timer)return;let I=performance.now()+z.intervalMs;B.timer=setInterval(()=>{let J=performance.now();E(Math.max(0,J-I),z),I=J+z.intervalMs},z.intervalMs),B.timer.unref?.()}function _(z=process.env){return{paths:D(z.GEMI_HEALTH_PATH),intervalMs:O("GEMI_HEALTH_INTERVAL_MS",z.GEMI_HEALTH_INTERVAL_MS,500),maxLagMs:O("GEMI_HEALTH_MAX_LAG_MS",z.GEMI_HEALTH_MAX_LAG_MS,1000),breaches:Math.ceil(O("GEMI_HEALTH_BREACHES",z.GEMI_HEALTH_BREACHES,3))}}function D(z){if(z===void 0||z.trim()==="")return[x];if(z.trim().toLowerCase()==="off")return[];let B=z.split(",").map((J)=>J.trim()).filter(Boolean);if(B.filter((J)=>!J.startsWith("/")).length>0)throw Error(`GEMI_HEALTH_PATH: expected comma-separated paths starting with "/", or "off"; got ${JSON.stringify(z)}.`);return B}function O(z,B,I){if(B===void 0||B.trim()==="")return I;let J=Number(B);if(Number.isFinite(J)&&J>0)return J;return console.warn(`[gemi] Ignoring ${z}="${B}": expected a positive number.`),I}function j(z,B){if(B.length===0)return z;let I=new Set(B);return async(J,K)=>{if(!B.some((b)=>J.url.includes(b))||!I.has(new URL(J.url).pathname))return z(J,K);return y(R(J.method))}}function R(z){let B={"Cache-Control":"no-store","Content-Type":"text/plain; charset=utf-8"};if(z!=="GET"&&z!=="HEAD")return new Response("Method Not Allowed",{status:405,headers:{...B,Allow:"GET, HEAD"}});let{healthy:I,shuttingDown:J}=W();return new Response(z==="HEAD"?null:I?"ok":J?"shutting down":"degraded",{status:I?200:503,headers:B})}var L=Symbol.for("gemi.server.devGeneration"),X={graceMs:1e4,providerTimeoutMs:5000};class Y{app;inFlight=0;waiters=new Set;constructor(z){this.app=z}track(z){return async(B,I)=>{this.inFlight++;try{return await z(B,I)}finally{if(this.inFlight--,this.inFlight===0)this.wake()}}}get pending(){return this.inFlight}async retire({graceMs:z,providerTimeoutMs:B}){try{await this.idle(z),await Promise.resolve().then(()=>this.app.shutdown({timeoutMs:B}))}catch(I){C(I)}}idle(z){if(this.inFlight===0)return Promise.resolve();return new Promise((B)=>{let I=()=>{clearTimeout(J),this.waiters.delete(I),B()},J=setTimeout(I,z);this.waiters.add(I)})}wake(){for(let z of this.waiters)z()}}function N(z,B=X){let I=globalThis,J=I[L];if(I[L]=z,!J||J===z||typeof J.retire!=="function")return Promise.resolve();let K=J.retire.bind(J);return Promise.resolve().then(()=>K(B)).catch(C)}function C(z){console.error("[gemi] Shutting down the application a reload replaced failed:",z)}class k{app;instrumentation;handleSignals;server;stopping;settings;constructor(z){this.app=new S({kernel:z.kernel}),this.handleSignals=z.handleSignals??!0,this.instrumentation=U(z.instrumentation??((B,I)=>I(B)))}async start(){process.env.ROOT_DIR=H();let z=Bun.env.NODE_ENV==="production",B=_();if(z)G(B);let I=j(this.instrumentation,B.paths);if(z){if(this.handleSignals)A(()=>this.stop());this.settings=Z()}try{await this.app.waitForBoot()}catch(J){if(!z)this.app.shutdown({timeoutMs:X.providerTimeoutMs});throw J}if(z){let{httpProd:J}=await import("../chunk-3e3tznxc.js");this.server=await J(this.app,I)}else{f();let{httpDev:J}=await import("../chunk-4dqfpydr.js"),K=new Y(this.app);this.server=await J(this.app,K.track(I)),N(K)}return this.server}stop(z={}){let B=this.app.sockets();return this.stopping??=P({server:this.server,closeSockets:B?()=>B.shutdown():void 0,shutdownProviders:(I)=>this.app.shutdown(I),settings:{...this.settings??Z(),...z}}),this.stopping}}export{W as liveness,Q as isShuttingDown,k as Server};
2
+ import{Ca as f}from"../chunk-kk18xqgc.js";import{Da as S}from"../chunk-ymdpt00k.js";import{fl as Q,hl as Z,il as P,jl as y,kl as U,ll as A}from"../chunk-mzkzgp2j.js";import{pl as H}from"../chunk-apga49vp.js";import"../chunk-fqqbnp0z.js";import{wl as F}from"../chunk-jzpbwvbt.js";var x="/__gemi__/health",$=Symbol.for("gemi.server.health");function V(){let z=globalThis;return z[$]??={lagMs:0,consecutiveBreaches:0,degraded:!1,timer:void 0},z[$]}function W(){let z=V(),B=Q();return{healthy:!B&&!z.degraded,shuttingDown:B,lagMs:z.lagMs,consecutiveBreaches:z.consecutiveBreaches}}function E(z,B){let I=V();I.lagMs=z,I.consecutiveBreaches=z>B.maxLagMs?I.consecutiveBreaches+1:0;let J=I.consecutiveBreaches>=B.breaches;if(J&&!I.degraded)console.warn(`[gemi] Health: degraded (event-loop lag ${Math.round(z)}ms, ${I.consecutiveBreaches} samples in a row over ${B.maxLagMs}ms).`);else if(!J&&I.degraded)console.log(`[gemi] Health: recovered (event-loop lag ${Math.round(z)}ms).`);I.degraded=J}function G(z){let B=V();if(B.timer)return;let I=performance.now()+z.intervalMs;B.timer=setInterval(()=>{let J=performance.now();E(Math.max(0,J-I),z),I=J+z.intervalMs},z.intervalMs),B.timer.unref?.()}function _(z=process.env){return{paths:D(z.GEMI_HEALTH_PATH),intervalMs:O("GEMI_HEALTH_INTERVAL_MS",z.GEMI_HEALTH_INTERVAL_MS,500),maxLagMs:O("GEMI_HEALTH_MAX_LAG_MS",z.GEMI_HEALTH_MAX_LAG_MS,1000),breaches:Math.ceil(O("GEMI_HEALTH_BREACHES",z.GEMI_HEALTH_BREACHES,3))}}function D(z){if(z===void 0||z.trim()==="")return[x];if(z.trim().toLowerCase()==="off")return[];let B=z.split(",").map((J)=>J.trim()).filter(Boolean);if(B.filter((J)=>!J.startsWith("/")).length>0)throw Error(`GEMI_HEALTH_PATH: expected comma-separated paths starting with "/", or "off"; got ${JSON.stringify(z)}.`);return B}function O(z,B,I){if(B===void 0||B.trim()==="")return I;let J=Number(B);if(Number.isFinite(J)&&J>0)return J;return console.warn(`[gemi] Ignoring ${z}="${B}": expected a positive number.`),I}function j(z,B){if(B.length===0)return z;let I=new Set(B);return async(J,K)=>{if(!B.some((b)=>J.url.includes(b))||!I.has(new URL(J.url).pathname))return z(J,K);return y(R(J.method))}}function R(z){let B={"Cache-Control":"no-store","Content-Type":"text/plain; charset=utf-8"};if(z!=="GET"&&z!=="HEAD")return new Response("Method Not Allowed",{status:405,headers:{...B,Allow:"GET, HEAD"}});let{healthy:I,shuttingDown:J}=W();return new Response(z==="HEAD"?null:I?"ok":J?"shutting down":"degraded",{status:I?200:503,headers:B})}var L=Symbol.for("gemi.server.devGeneration"),X={graceMs:1e4,providerTimeoutMs:5000};class Y{app;inFlight=0;waiters=new Set;constructor(z){this.app=z}track(z){return async(B,I)=>{this.inFlight++;try{return await z(B,I)}finally{if(this.inFlight--,this.inFlight===0)this.wake()}}}get pending(){return this.inFlight}async retire({graceMs:z,providerTimeoutMs:B}){try{await this.idle(z),await Promise.resolve().then(()=>this.app.shutdown({timeoutMs:B}))}catch(I){C(I)}}idle(z){if(this.inFlight===0)return Promise.resolve();return new Promise((B)=>{let I=()=>{clearTimeout(J),this.waiters.delete(I),B()},J=setTimeout(I,z);this.waiters.add(I)})}wake(){for(let z of this.waiters)z()}}function N(z,B=X){let I=globalThis,J=I[L];if(I[L]=z,!J||J===z||typeof J.retire!=="function")return Promise.resolve();let K=J.retire.bind(J);return Promise.resolve().then(()=>K(B)).catch(C)}function C(z){console.error("[gemi] Shutting down the application a reload replaced failed:",z)}class k{app;instrumentation;handleSignals;server;stopping;settings;constructor(z){this.app=new S({kernel:z.kernel}),this.handleSignals=z.handleSignals??!0,this.instrumentation=U(z.instrumentation??((B,I)=>I(B)))}async start(){process.env.ROOT_DIR=H();let z=Bun.env.NODE_ENV==="production",B=_();if(z)G(B);let I=j(this.instrumentation,B.paths);if(z){if(this.handleSignals)A(()=>this.stop());this.settings=Z()}try{await this.app.waitForBoot()}catch(J){if(!z)this.app.shutdown({timeoutMs:X.providerTimeoutMs});throw J}if(z){let{httpProd:J}=await import("../chunk-8vx9dws4.js");this.server=await J(this.app,I)}else{f();let{httpDev:J}=await import("../chunk-r9arr68h.js"),K=new Y(this.app);this.server=await J(this.app,K.track(I)),N(K)}return this.server}stop(z={}){let B=this.app.sockets();return this.stopping??=P({server:this.server,closeSockets:B?()=>B.shutdown():void 0,shutdownProviders:(I)=>this.app.shutdown(I),settings:{...this.settings??Z(),...z}}),this.stopping}}export{W as liveness,Q as isShuttingDown,k as Server};
3
3
 
4
4
  //# debugId=B36181B2C42D38F264756E2164756E21
@@ -1,5 +1,5 @@
1
1
  // @bun
2
- import{cb as y8}from"../chunk-fcqx2t0p.js";import{Ab as x8,Bb as D8,Cb as F8,Db as H8,Eb as f4,Fb as Y6,Gb as C,Hb as U8,Ib as O8,Jb as S8,Kb as R8,Lb as _8,Mb as f8,Nb as C8,Ob as k8,Pb as b8,Qb as T8,Rb as P8,Sb as V8,Tb as I8,Ub as v8,Vb as q8,Wb as w8,db as wZ,eb as yZ,fb as AZ,gb as hZ,hb as gZ,ib as O4,jb as EZ,kb as D4,lb as F4,mb as v1,nb as mZ,ob as cZ,pb as Y8,tb as K8,ub as G8,vb as z8,wb as X8,xb as M8,yb as L8,zb as N8}from"../chunk-r9exzwqt.js";import{Zb as R4}from"../chunk-ezn89ezm.js";import{Ad as $8,Bd as J8,Cd as Q8,nd as uZ,od as pZ,pd as dZ,qd as lZ,rd as nZ,sd as sZ,td as oZ,ud as aZ,vd as tZ,wd as rZ,xd as eZ,yd as W8,zd as Z8}from"../chunk-2b3hh9xw.js";import{Dd as iZ}from"../chunk-v9z4x5j2.js";import{Ed as FZ,Fd as HZ,Gd as UZ,Hd as OZ,Id as SZ,Jd as RZ,Kd as _Z,Ld as fZ,Md as CZ,Nd as kZ,Od as bZ,Pd as TZ,Qd as PZ,Rd as VZ,Sd as IZ,Td as vZ,Yd as qZ}from"../chunk-877yc341.js";import{Zd as B8,_d as j8}from"../chunk-ydkv9e8w.js";import"../chunk-eqv7yxk7.js";import{$f as o5,Ae as EW,Be as mW,Bf as I5,Ce as cW,Cf as v5,Cg as q1,De as uW,Df as w5,Ee as pW,Fe as dW,Ge as V0,Gf as y5,He as lW,Hf as A5,Ie as nW,If as h5,Je as iW,Jf as g5,Ke as sW,Le as oW,Lf as E5,Mf as m5,Nf as c5,Ng as BZ,Of as u5,Og as jZ,Pf as p5,Qf as d5,Rf as l5,Sf as n5,Tf as i5,Uf as s5,Zf as k,_f as i,af as J5,ag as a5,bf as Q5,bg as t5,cf as Y5,cg as r5,df as K5,dg as e5,ef as G5,ff as z5,fg as WZ,ge as t0,gg as ZZ,he as IW,hg as $Z,ie as vW,ig as JZ,je as qW,jg as QZ,le as wW,lf as O5,mf as S5,mg as YZ,nf as R5,ng as KZ,of as _5,og as GZ,pe as r0,pf as f5,qe as A0,qf as C5,re as h0,rf as k5,se as X4,sf as b5,te as yW,tf as T5,tg as zZ,vf as P5,wf as Q6,xe as AW,xf as V5,xg as XZ,ye as hW,ze as gW}from"../chunk-01tw5f26.js";import"../chunk-hh5bs656.js";import"../chunk-3csz8pfk.js";import{Ai as $5,Ci as P1,Gh as z4,Hh as Y4,Ih as M1,Vh as x4,Yh as t,_h as d,ci as K4,di as L1,ei as T1,fi as aW,gi as tW,hi as rW,ii as eW,xi as W5,yi as Z5}from"../chunk-95vm1de8.js";import"../chunk-cee5gq7t.js";import{Mi as r}from"../chunk-a8n9ec43.js";import{Ui as x5,Vi as D5,Wi as b1,Xi as F5,Yi as T0,Zi as H5,_i as U5}from"../chunk-563ksar3.js";import{ej as M5,fj as L5,gj as N5}from"../chunk-n9n4qt20.js";import"../chunk-xv58jnpb.js";import{Pj as q5}from"../chunk-313593t3.js";import{Rj as X5,Sj as B5,Tj as j5}from"../chunk-86zhngpg.js";import"../chunk-attr793y.js";import"../chunk-2ery6a75.js";import"../chunk-73rzf7ys.js";import"../chunk-2x6cv37t.js";import{Jk as MZ,Kk as LZ,Lk as NZ,Mk as xZ,Ok as DZ}from"../chunk-z7tsh9qr.js";import"../chunk-mr3szvr3.js";import{Yk as w}from"../chunk-1fyn63ka.js";import"../chunk-e9z8p2fy.js";import"../chunk-g8sh9btf.js";import"../chunk-mzkzgp2j.js";import"../chunk-apga49vp.js";import"../chunk-fqqbnp0z.js";import{wl as v0}from"../chunk-jzpbwvbt.js";import{Buffer as I0}from"buffer";class q0 extends L1{client;config;constructor(...W){super();this.config=W}async connect(){let W=await import("../chunk-hcw671mg.js");return this.client??=new W.S3Client(...this.config),{sdk:W,client:this.client}}async put(W,{signal:Z}={}){Z?.throwIfAborted();let $,J,Q,Y=process.env.BUCKET_NAME;if(W instanceof Blob)$=W,Q=`${Bun.randomUUIDv7()}.${W.type.split("/")[1].split(";")[0]}`,J=W.type;else $=W.body,Q=W.name,Y=W.bucket??Y,J=W.contentType||($ instanceof Blob||$ instanceof File?$.type:void 0);J=J||void 0;let K=$ instanceof I0?$:$ instanceof Blob||$ instanceof File?I0.from(await $.arrayBuffer()):"",{sdk:G,client:X}=await this.connect();return Z?.throwIfAborted(),await X.send(new G.PutObjectCommand({Bucket:Y,Key:Q,Body:K,ContentType:J}),{abortSignal:Z}),Q}async delete(W){let Z=typeof W==="string"?W:W.name,$=(typeof W==="string"?void 0:W.bucket)??process.env.BUCKET_NAME;if(!Z)throw Error("Object name has to be specified");let{sdk:J,client:Q}=await this.connect();try{await Q.send(new J.DeleteObjectCommand({Bucket:$,Key:Z}))}catch(Y){if(Y?.name==="NoSuchKey"||Y?.$metadata?.httpStatusCode===404)return;throw Y}}async*pages(W,{bucket:Z,signal:$}){let{sdk:J,client:Q}=await this.connect(),Y;do{$?.throwIfAborted();let K=await Q.send(new J.ListObjectsV2Command({Bucket:Z??process.env.BUCKET_NAME,Prefix:W,ContinuationToken:Y}),{abortSignal:$});yield(K.Contents??[]).map((G)=>({name:G.Key,size:G.Size??0,lastModified:G.LastModified??new Date(0)})),Y=K.IsTruncated?K.NextContinuationToken:void 0}while(Y)}async*objects(W,Z={}){for await(let $ of this.pages(W,Z))yield*$}async deletePrefix(W,Z={}){K4(W);let $=Z.bucket??process.env.BUCKET_NAME,{sdk:J,client:Q}=await this.connect(),Y=0;for await(let K of this.pages(W,{...Z,bucket:$})){if(K.length===0)continue;Z.signal?.throwIfAborted();let X=(await Q.send(new J.DeleteObjectsCommand({Bucket:$,Delete:{Objects:K.map((z)=>({Key:z.name})),Quiet:!0}}),{abortSignal:Z.signal}))?.Errors??[];if(X.length>0){let z=X[0];throw Error(`S3 could not delete ${X.length} object(s) under "${W}", e.g. "${z.Key}": ${z.Code??"unknown"} ${z.Message??""}`.trim())}Y+=K.length}return Y}async list(W){let{sdk:Z,client:$}=await this.connect();return await $.send(new Z.ListObjectsV2Command({Bucket:process.env.BUCKET_NAME,Prefix:W}))}async fetch(W,{signal:Z}={}){Z?.throwIfAborted();let $=process.env.BUCKET_NAME,J;if(typeof W==="string")J=W;else $=W.bucket??$,J=W.name;if(!J)throw Error("Object name has to be specified");let{sdk:Q,client:Y}=await this.connect();Z?.throwIfAborted();let K=await Y.send(new Q.GetObjectCommand({Bucket:$,Key:J}),{abortSignal:Z}),G=T1(K.Body.transformToWebStream(),Z);return Z?.throwIfAborted(),new Response(G,{headers:{"Content-Type":K.ContentType,"Content-Length":K.ContentLength.toString(),"Cache-Control":"private, max-age=12000, must-revalidate","Last-Modified":K.LastModified?.toUTCString()||"",ETag:K.ETag||""}})}async read(W){let Z=typeof W==="string"?{name:W}:W,$=Z.bucket??process.env.BUCKET_NAME,{name:J,range:Q=null}=Z;if(!J)throw Error("Object name has to be specified");let{sdk:Y,client:K}=await this.connect(),G;try{G=await K.send(new Y.GetObjectCommand({Bucket:$,Key:J,Range:Q?Y4(Q):void 0}))}catch(j){if(j?.name==="InvalidRange"||j?.$metadata?.httpStatusCode===416)throw new t(await this.size({name:J,bucket:$}));if(j?.name==="NoSuchKey"||j?.$metadata?.httpStatusCode===404)throw new d(J);throw j}let X=M1(G.ContentRange),z=Boolean(X)&&G.$metadata?.httpStatusCode===206,B=X?.total??G.ContentLength??0;return{body:G.Body.transformToWebStream(),start:X?.start??0,end:X?.end??B-1,total:B,partial:z,type:G.ContentType??"application/octet-stream",etag:G.ETag||void 0,lastModified:G.LastModified,name:J}}async size(W){let Z=typeof W==="string"?W:W.name,$=(typeof W==="string"?void 0:W.bucket)??process.env.BUCKET_NAME,{sdk:J,client:Q}=await this.connect();try{return(await Q.send(new J.HeadObjectCommand({Bucket:$,Key:Z}))).ContentLength??0}catch(Y){if(Y?.name==="NotFound"||Y?.$metadata?.httpStatusCode===404)throw new d(Z);throw Y}}}import{Buffer as w0}from"buffer";import{Readable as d6}from"stream";function G4(W){return W?.statusCode===404||W?.details?.errorCode==="BlobNotFound"||W?.code==="BlobNotFound"}function l6(W){return W?.statusCode===416||W?.details?.errorCode==="InvalidRange"||W?.code==="InvalidRange"}class y0 extends L1{config;serviceClientPromise=null;constructor(W={}){super();this.config=W}async serviceClient(){if(this.config.serviceClient)return this.config.serviceClient;return this.serviceClientPromise??=(async()=>{let W;try{W=await import("@azure/storage-blob")}catch{throw Error("AzureBlobDriver requires the '@azure/storage-blob' package. Install it with `bun add @azure/storage-blob`, or pass a pre-built `serviceClient`.")}let Z=this.config.connectionString??process.env.AZURE_STORAGE_CONNECTION_STRING;if(this.config.url)return new W.BlobServiceClient(this.config.url,this.config.credential);if(Z)return W.BlobServiceClient.fromConnectionString(Z);throw Error("AzureBlobDriver needs a connection string (AZURE_STORAGE_CONNECTION_STRING), a `url`, or a `serviceClient`.")})(),this.serviceClientPromise}async blob(W,Z){if(!W)throw Error("Object name has to be specified");let $=Z??this.config.container??process.env.BUCKET_NAME;if(!$)throw Error("AzureBlobDriver needs a container name, from `bucket`, the `container` config, or BUCKET_NAME.");return(await this.serviceClient()).getContainerClient($).getBlockBlobClient(W)}async put(W,{signal:Z}={}){Z?.throwIfAborted();let $,J,Q,Y;if(W instanceof Blob)$=W,Q=`${Bun.randomUUIDv7()}.${W.type.split("/")[1].split(";")[0]}`,J=W.type;else $=W.body,Q=W.name,Y=W.bucket,J=W.contentType??($ instanceof Blob||$ instanceof File?$.type:void 0);let K=$ instanceof w0?$:w0.from(await $.arrayBuffer()),G=await this.blob(Q,Y);return Z?.throwIfAborted(),await G.uploadData(K,{blobHTTPHeaders:J?{blobContentType:J}:void 0,abortSignal:Z}),Q}async*objects(W,{bucket:Z,signal:$}={}){$?.throwIfAborted();let J=Z??this.config.container??process.env.BUCKET_NAME;if(!J)throw Error("AzureBlobDriver needs a container name, from `bucket`, the `container` config, or BUCKET_NAME.");let Y=(await this.serviceClient()).getContainerClient(J);for await(let K of Y.listBlobsFlat({prefix:W}))$?.throwIfAborted(),yield{name:K.name,size:K.properties?.contentLength??0,lastModified:K.properties?.lastModified??new Date(0)}}async list(W){let Z=this.config.container??process.env.BUCKET_NAME,J=(await this.serviceClient()).getContainerClient(Z),Q=[];for await(let Y of J.listBlobsFlat({prefix:W}))Q.push(Y.name);return Q}async fetch(W,{signal:Z}={}){Z?.throwIfAborted();let $=await this.download(typeof W==="string"?{name:W}:{name:W.name,bucket:W.bucket},Z);return new Response($.body,{headers:{"Content-Type":$.type,"Content-Length":String($.total),"Cache-Control":"private, max-age=12000, must-revalidate","Last-Modified":$.lastModified?.toUTCString()??"",ETag:$.etag??""}})}async read(W){return this.download(typeof W==="string"?{name:W}:W)}async download(W,Z){let{name:$,bucket:J,range:Q=null}=W,Y=await this.blob($,J);Z?.throwIfAborted();let K,G,X=Q?.kind==="suffix"||Q?.kind==="offset"&&Q.end===null&&Q.start===0;if(Q&&X){let H=await this.size({name:$,bucket:J}),p=z4(Q,H);if(!p)throw new t(H);K=p.start,G=p.length}else if(Q?.kind==="offset")K=Q.start,G=Q.end===null?void 0:Q.end-Q.start+1;let z;try{z=await Y.download(K,G,Z?{abortSignal:Z}:void 0)}catch(H){if(l6(H))throw new t(await this.size({name:$,bucket:J}));if(G4(H))throw new d($);throw H}let B=M1(z.contentRange),j=Boolean(B),x=B?.total??z.contentLength??0,O=await n6(z);if(O instanceof ReadableStream)O=T1(O,Z);return Z?.throwIfAborted(),{body:O,start:B?.start??0,end:B?.end??x-1,total:x,partial:j,type:z.contentType??"application/octet-stream",etag:z.etag||void 0,lastModified:z.lastModified,name:$}}async size(W){let Z=typeof W==="string"?W:W.name,$=typeof W==="string"?void 0:W.bucket,J=await this.blob(Z,$);try{return(await J.getProperties()).contentLength??0}catch(Q){if(G4(Q))throw new d(Z);throw Q}}async delete(W){let Z=typeof W==="string"?W:W.name,$=typeof W==="string"?void 0:W.bucket,J=await this.blob(Z,$);try{await J.delete()}catch(Q){if(G4(Q))return;throw Q}}}async function n6(W){if(W.blobBody)return await W.blobBody;if(W.readableStreamBody)return d6.toWeb(W.readableStreamBody);return null}function i6(W){return W}var s6=`
2
+ import{cb as y8}from"../chunk-fcqx2t0p.js";import{Ab as x8,Bb as D8,Cb as F8,Db as H8,Eb as f4,Fb as Y6,Gb as C,Hb as U8,Ib as O8,Jb as S8,Kb as R8,Lb as _8,Mb as f8,Nb as C8,Ob as k8,Pb as b8,Qb as T8,Rb as P8,Sb as V8,Tb as I8,Ub as v8,Vb as q8,Wb as w8,db as wZ,eb as yZ,fb as AZ,gb as hZ,hb as gZ,ib as O4,jb as EZ,kb as D4,lb as F4,mb as v1,nb as mZ,ob as cZ,pb as Y8,tb as K8,ub as G8,vb as z8,wb as X8,xb as M8,yb as L8,zb as N8}from"../chunk-h34n0w2w.js";import{Zb as R4}from"../chunk-b4pqgz0f.js";import{Ad as $8,Bd as J8,Cd as Q8,nd as uZ,od as pZ,pd as dZ,qd as lZ,rd as nZ,sd as sZ,td as oZ,ud as aZ,vd as tZ,wd as rZ,xd as eZ,yd as W8,zd as Z8}from"../chunk-2b3hh9xw.js";import{Dd as iZ}from"../chunk-v9z4x5j2.js";import{Ed as FZ,Fd as HZ,Gd as UZ,Hd as OZ,Id as SZ,Jd as RZ,Kd as _Z,Ld as fZ,Md as CZ,Nd as kZ,Od as bZ,Pd as TZ,Qd as PZ,Rd as VZ,Sd as IZ,Td as vZ,Yd as qZ}from"../chunk-877yc341.js";import{Zd as B8,_d as j8}from"../chunk-ydkv9e8w.js";import"../chunk-eqv7yxk7.js";import{$f as o5,Ae as EW,Be as mW,Bf as I5,Ce as cW,Cf as v5,Cg as q1,De as uW,Df as w5,Ee as pW,Fe as dW,Ge as V0,Gf as y5,He as lW,Hf as A5,Ie as nW,If as h5,Je as iW,Jf as g5,Ke as sW,Le as oW,Lf as E5,Mf as m5,Nf as c5,Ng as BZ,Of as u5,Og as jZ,Pf as p5,Qf as d5,Rf as l5,Sf as n5,Tf as i5,Uf as s5,Zf as k,_f as i,af as J5,ag as a5,bf as Q5,bg as t5,cf as Y5,cg as r5,df as K5,dg as e5,ef as G5,ff as z5,fg as WZ,ge as t0,gg as ZZ,he as IW,hg as $Z,ie as vW,ig as JZ,je as qW,jg as QZ,le as wW,lf as O5,mf as S5,mg as YZ,nf as R5,ng as KZ,of as _5,og as GZ,pe as r0,pf as f5,qe as A0,qf as C5,re as h0,rf as k5,se as X4,sf as b5,te as yW,tf as T5,tg as zZ,vf as P5,wf as Q6,xe as AW,xf as V5,xg as XZ,ye as hW,ze as gW}from"../chunk-01tw5f26.js";import"../chunk-hh5bs656.js";import"../chunk-3csz8pfk.js";import{Ai as $5,Ci as P1,Gh as z4,Hh as Y4,Ih as M1,Vh as x4,Yh as t,_h as d,ci as K4,di as L1,ei as T1,fi as aW,gi as tW,hi as rW,ii as eW,xi as W5,yi as Z5}from"../chunk-95vm1de8.js";import"../chunk-cee5gq7t.js";import{Mi as r}from"../chunk-a8n9ec43.js";import{Ui as x5,Vi as D5,Wi as b1,Xi as F5,Yi as T0,Zi as H5,_i as U5}from"../chunk-563ksar3.js";import{ej as M5,fj as L5,gj as N5}from"../chunk-n9n4qt20.js";import"../chunk-xv58jnpb.js";import{Pj as q5}from"../chunk-313593t3.js";import{Rj as X5,Sj as B5,Tj as j5}from"../chunk-86zhngpg.js";import"../chunk-attr793y.js";import"../chunk-2ery6a75.js";import"../chunk-73rzf7ys.js";import"../chunk-2x6cv37t.js";import{Jk as MZ,Kk as LZ,Lk as NZ,Mk as xZ,Ok as DZ}from"../chunk-z7tsh9qr.js";import"../chunk-mr3szvr3.js";import{Yk as w}from"../chunk-1fyn63ka.js";import"../chunk-e9z8p2fy.js";import"../chunk-g8sh9btf.js";import"../chunk-mzkzgp2j.js";import"../chunk-apga49vp.js";import"../chunk-fqqbnp0z.js";import{wl as v0}from"../chunk-jzpbwvbt.js";import{Buffer as I0}from"buffer";class q0 extends L1{client;config;constructor(...W){super();this.config=W}async connect(){let W=await import("../chunk-hcw671mg.js");return this.client??=new W.S3Client(...this.config),{sdk:W,client:this.client}}async put(W,{signal:Z}={}){Z?.throwIfAborted();let $,J,Q,Y=process.env.BUCKET_NAME;if(W instanceof Blob)$=W,Q=`${Bun.randomUUIDv7()}.${W.type.split("/")[1].split(";")[0]}`,J=W.type;else $=W.body,Q=W.name,Y=W.bucket??Y,J=W.contentType||($ instanceof Blob||$ instanceof File?$.type:void 0);J=J||void 0;let K=$ instanceof I0?$:$ instanceof Blob||$ instanceof File?I0.from(await $.arrayBuffer()):"",{sdk:G,client:X}=await this.connect();return Z?.throwIfAborted(),await X.send(new G.PutObjectCommand({Bucket:Y,Key:Q,Body:K,ContentType:J}),{abortSignal:Z}),Q}async delete(W){let Z=typeof W==="string"?W:W.name,$=(typeof W==="string"?void 0:W.bucket)??process.env.BUCKET_NAME;if(!Z)throw Error("Object name has to be specified");let{sdk:J,client:Q}=await this.connect();try{await Q.send(new J.DeleteObjectCommand({Bucket:$,Key:Z}))}catch(Y){if(Y?.name==="NoSuchKey"||Y?.$metadata?.httpStatusCode===404)return;throw Y}}async*pages(W,{bucket:Z,signal:$}){let{sdk:J,client:Q}=await this.connect(),Y;do{$?.throwIfAborted();let K=await Q.send(new J.ListObjectsV2Command({Bucket:Z??process.env.BUCKET_NAME,Prefix:W,ContinuationToken:Y}),{abortSignal:$});yield(K.Contents??[]).map((G)=>({name:G.Key,size:G.Size??0,lastModified:G.LastModified??new Date(0)})),Y=K.IsTruncated?K.NextContinuationToken:void 0}while(Y)}async*objects(W,Z={}){for await(let $ of this.pages(W,Z))yield*$}async deletePrefix(W,Z={}){K4(W);let $=Z.bucket??process.env.BUCKET_NAME,{sdk:J,client:Q}=await this.connect(),Y=0;for await(let K of this.pages(W,{...Z,bucket:$})){if(K.length===0)continue;Z.signal?.throwIfAborted();let X=(await Q.send(new J.DeleteObjectsCommand({Bucket:$,Delete:{Objects:K.map((z)=>({Key:z.name})),Quiet:!0}}),{abortSignal:Z.signal}))?.Errors??[];if(X.length>0){let z=X[0];throw Error(`S3 could not delete ${X.length} object(s) under "${W}", e.g. "${z.Key}": ${z.Code??"unknown"} ${z.Message??""}`.trim())}Y+=K.length}return Y}async list(W){let{sdk:Z,client:$}=await this.connect();return await $.send(new Z.ListObjectsV2Command({Bucket:process.env.BUCKET_NAME,Prefix:W}))}async fetch(W,{signal:Z}={}){Z?.throwIfAborted();let $=process.env.BUCKET_NAME,J;if(typeof W==="string")J=W;else $=W.bucket??$,J=W.name;if(!J)throw Error("Object name has to be specified");let{sdk:Q,client:Y}=await this.connect();Z?.throwIfAborted();let K=await Y.send(new Q.GetObjectCommand({Bucket:$,Key:J}),{abortSignal:Z}),G=T1(K.Body.transformToWebStream(),Z);return Z?.throwIfAborted(),new Response(G,{headers:{"Content-Type":K.ContentType,"Content-Length":K.ContentLength.toString(),"Cache-Control":"private, max-age=12000, must-revalidate","Last-Modified":K.LastModified?.toUTCString()||"",ETag:K.ETag||""}})}async read(W){let Z=typeof W==="string"?{name:W}:W,$=Z.bucket??process.env.BUCKET_NAME,{name:J,range:Q=null}=Z;if(!J)throw Error("Object name has to be specified");let{sdk:Y,client:K}=await this.connect(),G;try{G=await K.send(new Y.GetObjectCommand({Bucket:$,Key:J,Range:Q?Y4(Q):void 0}))}catch(j){if(j?.name==="InvalidRange"||j?.$metadata?.httpStatusCode===416)throw new t(await this.size({name:J,bucket:$}));if(j?.name==="NoSuchKey"||j?.$metadata?.httpStatusCode===404)throw new d(J);throw j}let X=M1(G.ContentRange),z=Boolean(X)&&G.$metadata?.httpStatusCode===206,B=X?.total??G.ContentLength??0;return{body:G.Body.transformToWebStream(),start:X?.start??0,end:X?.end??B-1,total:B,partial:z,type:G.ContentType??"application/octet-stream",etag:G.ETag||void 0,lastModified:G.LastModified,name:J}}async size(W){let Z=typeof W==="string"?W:W.name,$=(typeof W==="string"?void 0:W.bucket)??process.env.BUCKET_NAME,{sdk:J,client:Q}=await this.connect();try{return(await Q.send(new J.HeadObjectCommand({Bucket:$,Key:Z}))).ContentLength??0}catch(Y){if(Y?.name==="NotFound"||Y?.$metadata?.httpStatusCode===404)throw new d(Z);throw Y}}}import{Buffer as w0}from"buffer";import{Readable as d6}from"stream";function G4(W){return W?.statusCode===404||W?.details?.errorCode==="BlobNotFound"||W?.code==="BlobNotFound"}function l6(W){return W?.statusCode===416||W?.details?.errorCode==="InvalidRange"||W?.code==="InvalidRange"}class y0 extends L1{config;serviceClientPromise=null;constructor(W={}){super();this.config=W}async serviceClient(){if(this.config.serviceClient)return this.config.serviceClient;return this.serviceClientPromise??=(async()=>{let W;try{W=await import("@azure/storage-blob")}catch{throw Error("AzureBlobDriver requires the '@azure/storage-blob' package. Install it with `bun add @azure/storage-blob`, or pass a pre-built `serviceClient`.")}let Z=this.config.connectionString??process.env.AZURE_STORAGE_CONNECTION_STRING;if(this.config.url)return new W.BlobServiceClient(this.config.url,this.config.credential);if(Z)return W.BlobServiceClient.fromConnectionString(Z);throw Error("AzureBlobDriver needs a connection string (AZURE_STORAGE_CONNECTION_STRING), a `url`, or a `serviceClient`.")})(),this.serviceClientPromise}async blob(W,Z){if(!W)throw Error("Object name has to be specified");let $=Z??this.config.container??process.env.BUCKET_NAME;if(!$)throw Error("AzureBlobDriver needs a container name, from `bucket`, the `container` config, or BUCKET_NAME.");return(await this.serviceClient()).getContainerClient($).getBlockBlobClient(W)}async put(W,{signal:Z}={}){Z?.throwIfAborted();let $,J,Q,Y;if(W instanceof Blob)$=W,Q=`${Bun.randomUUIDv7()}.${W.type.split("/")[1].split(";")[0]}`,J=W.type;else $=W.body,Q=W.name,Y=W.bucket,J=W.contentType??($ instanceof Blob||$ instanceof File?$.type:void 0);let K=$ instanceof w0?$:w0.from(await $.arrayBuffer()),G=await this.blob(Q,Y);return Z?.throwIfAborted(),await G.uploadData(K,{blobHTTPHeaders:J?{blobContentType:J}:void 0,abortSignal:Z}),Q}async*objects(W,{bucket:Z,signal:$}={}){$?.throwIfAborted();let J=Z??this.config.container??process.env.BUCKET_NAME;if(!J)throw Error("AzureBlobDriver needs a container name, from `bucket`, the `container` config, or BUCKET_NAME.");let Y=(await this.serviceClient()).getContainerClient(J);for await(let K of Y.listBlobsFlat({prefix:W}))$?.throwIfAborted(),yield{name:K.name,size:K.properties?.contentLength??0,lastModified:K.properties?.lastModified??new Date(0)}}async list(W){let Z=this.config.container??process.env.BUCKET_NAME,J=(await this.serviceClient()).getContainerClient(Z),Q=[];for await(let Y of J.listBlobsFlat({prefix:W}))Q.push(Y.name);return Q}async fetch(W,{signal:Z}={}){Z?.throwIfAborted();let $=await this.download(typeof W==="string"?{name:W}:{name:W.name,bucket:W.bucket},Z);return new Response($.body,{headers:{"Content-Type":$.type,"Content-Length":String($.total),"Cache-Control":"private, max-age=12000, must-revalidate","Last-Modified":$.lastModified?.toUTCString()??"",ETag:$.etag??""}})}async read(W){return this.download(typeof W==="string"?{name:W}:W)}async download(W,Z){let{name:$,bucket:J,range:Q=null}=W,Y=await this.blob($,J);Z?.throwIfAborted();let K,G,X=Q?.kind==="suffix"||Q?.kind==="offset"&&Q.end===null&&Q.start===0;if(Q&&X){let H=await this.size({name:$,bucket:J}),p=z4(Q,H);if(!p)throw new t(H);K=p.start,G=p.length}else if(Q?.kind==="offset")K=Q.start,G=Q.end===null?void 0:Q.end-Q.start+1;let z;try{z=await Y.download(K,G,Z?{abortSignal:Z}:void 0)}catch(H){if(l6(H))throw new t(await this.size({name:$,bucket:J}));if(G4(H))throw new d($);throw H}let B=M1(z.contentRange),j=Boolean(B),x=B?.total??z.contentLength??0,O=await n6(z);if(O instanceof ReadableStream)O=T1(O,Z);return Z?.throwIfAborted(),{body:O,start:B?.start??0,end:B?.end??x-1,total:x,partial:j,type:z.contentType??"application/octet-stream",etag:z.etag||void 0,lastModified:z.lastModified,name:$}}async size(W){let Z=typeof W==="string"?W:W.name,$=typeof W==="string"?void 0:W.bucket,J=await this.blob(Z,$);try{return(await J.getProperties()).contentLength??0}catch(Q){if(G4(Q))throw new d(Z);throw Q}}async delete(W){let Z=typeof W==="string"?W:W.name,$=typeof W==="string"?void 0:W.bucket,J=await this.blob(Z,$);try{await J.delete()}catch(Q){if(G4(Q))return;throw Q}}}async function n6(W){if(W.blobBody)return await W.blobBody;if(W.readableStreamBody)return d6.toWeb(W.readableStreamBody);return null}function i6(W){return W}var s6=`
3
3
  local currentKey = KEYS[1]
4
4
  local previousKey = KEYS[2]
5
5
  local limit = tonumber(ARGV[1])
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gemi",
3
- "version": "0.147.0",
3
+ "version": "0.148.0",
4
4
  "private": false,
5
5
  "license": "MIT",
6
6
  "author": "Enes Tufekci <enes@gemijs.dev>",