UNPKG

eve

Version:

Filesystem-first framework for durable backend AI agents that run anywhere.

1 lines • 3.89 kB
import{readVercelSession,writeVercelSession}from"./store.js";import{mkdir,rm,stat}from"node:fs/promises";import{isErrnoCode,isObject}from"#shared/guards.js";import{join}from"node:path";import{homedir}from"node:os";import{setTimeout}from"node:timers/promises";const VERCEL_MODEL_CLIENT_ID=`cl_HYyOPBNtFMfHhaUn9L4QPfTZz6TP47bp`,VERCEL_OAUTH_ISSUER=`https://vercel.com`,VERCEL_TEAM_HEADER=`x-vercel-ai-gateway-team`;async function authJson(e,t={},n=256e3,r=15e3){let i=AbortSignal.timeout(r),a=await fetch(e,{...t,redirect:`error`,signal:t.signal?AbortSignal.any([t.signal,i]):i}),o=a.body?.getReader(),s=``,c=new TextDecoder;if(o)try{let e=0;for(;;){let t=await o.read();if(t.done)break;if(e+=t.value.byteLength,e>n)throw Error(`Authentication response was too large. Retry /login.`);s+=c.decode(t.value,{stream:!0})}s+=c.decode()}finally{await o.cancel()}let l;try{l=JSON.parse(s)}catch{throw Error(`The provider returned an invalid authentication response. Retry /login.`)}if(!isObject(l))throw Error(`The provider returned an invalid authentication response. Retry /login.`);if(!a.ok&&typeof l.error!=`string`)throw Error(`Authentication failed (${a.status}). Retry /login.`);return l}function vercelApiJson(e,t={}){return authJson(e,t,8388608)}async function vercelOAuthEndpoints(e){let t=await authJson(`${VERCEL_OAUTH_ISSUER}/.well-known/openid-configuration`,{signal:e}),endpoint=e=>{let t=typeof e==`string`?URL.parse(e):null;if(!t||![`https://vercel.com`,`https://api.vercel.com`].includes(t.origin)||t.username||t.password)throw Error(`Vercel returned an unexpected OAuth endpoint. Retry /login.`);return t.href};return{device:endpoint(t.device_authorization_endpoint),token:endpoint(t.token_endpoint)}}function sessionFromToken(e,t){if(typeof e.error==`string`)throw Error(`Vercel login expired. Retry /login.`);if(typeof e.access_token!=`string`||typeof e.expires_in!=`number`||!Number.isFinite(e.expires_in)||e.expires_in<=0)throw Error(`Vercel did not return a usable token. Retry /login.`);let n=typeof e.refresh_token==`string`?e.refresh_token:t?.refreshToken;if(!n)throw Error(`Vercel did not return a refresh token. Retry /login.`);return{accessToken:e.access_token,refreshToken:n,expiresAt:Date.now()+e.expires_in*1e3,teamId:t?.teamId??``,teamName:t?.teamName??``}}async function resolveVercelSession(e){let t=await readVercelSession(VERCEL_MODEL_CLIENT_ID);if(!t)throw Error(`Sign in to Vercel with /login.`);if(t.expiresAt>Date.now()+6e4&&t.accessToken!==e)return t;let n=join(homedir(),`.eve`,`auth`);await mkdir(n,{recursive:!0,mode:448});let r=join(n,`vercel-refresh.lock`),i=Date.now()+35e3;for(;;)try{await mkdir(r);break}catch(e){if(!isErrnoCode(e,`EEXIST`))throw e;let t=await stat(r).catch(()=>void 0);if(t&&Date.now()-t.mtimeMs>3e5){await rm(r,{recursive:!0,force:!0});continue}if(Date.now()>i)throw Error(`Vercel credentials are busy. Close other eve sessions and retry /login.`);await setTimeout(100)}try{if(t=await readVercelSession(VERCEL_MODEL_CLIENT_ID),!t)throw Error(`Sign in to Vercel with /login.`);return t.expiresAt>Date.now()+6e4&&t.accessToken!==e?t:(t=sessionFromToken(await authJson((await vercelOAuthEndpoints()).token,{method:`POST`,body:new URLSearchParams({client_id:VERCEL_MODEL_CLIENT_ID,grant_type:`refresh_token`,refresh_token:t.refreshToken})}),t),await writeVercelSession(t,VERCEL_MODEL_CLIENT_ID),t)}finally{await rm(r,{recursive:!0,force:!0})}}async function validateVercelAccess(e,t,n){if((await authJson(`https://ai-gateway.vercel.sh/coding-agent/v1/credits?teamId=${encodeURIComponent(t)}`,{headers:{authorization:`Bearer ${e}`},signal:n})).error)throw Error(`Vercel could not authorize AI Gateway for this team. Choose another team or connection in /login.`)}export{VERCEL_MODEL_CLIENT_ID,VERCEL_OAUTH_ISSUER,VERCEL_TEAM_HEADER,authJson,resolveVercelSession,sessionFromToken,validateVercelAccess,vercelApiJson,vercelOAuthEndpoints};