UNPKG

eve

Version:

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

2 lines • 3.88 kB
import{createSign}from"node:crypto";import{createLogger}from"#internal/logging.js";import{isObject}from"#shared/guards.js";const log=createLogger(`github.auth`),installationTokenCache=new Map;async function resolveGitHubAppId(e){let t=e??process.env.GITHUB_APP_ID;if(t===void 0||t===``)throw Error(`githubChannel: GITHUB_APP_ID is required.`);let n=typeof t==`function`?await t():t;return String(n)}async function resolveGitHubPrivateKey(e){let t=e??process.env.GITHUB_APP_PRIVATE_KEY;if(!t)throw Error(`githubChannel: GITHUB_APP_PRIVATE_KEY is required.`);return normalizeGitHubPrivateKey(typeof t==`function`?await t():t)}async function resolveGitHubWebhookSecret(e){let t=e??process.env.GITHUB_WEBHOOK_SECRET;if(!t)throw Error(`githubChannel: GITHUB_WEBHOOK_SECRET is required.`);return typeof t==`function`?await t():t}function createGitHubBotNameResolver(e){let t;return async()=>{if(t!==void 0)return t;let n=e.botName??e.credentials?.appSlug??process.env.GITHUB_APP_SLUG;if(n!==void 0){if(typeof n==`string`)return t=normalizeBotName(n),t;try{return t=normalizeBotName(await n()),t}catch(e){log.warn(`githubChannel: botName resolver failed; retrying on the next event`,{error:e});return}}}}function normalizeBotName(e){let t=e.trim();return t.length>0?t:void 0}function normalizeGitHubPrivateKey(e){return e.replace(/\\n/gu,` `)}async function createGitHubAppJwt(e){let t=await resolveGitHubAppId(e.appId),n=await resolveGitHubPrivateKey(e.privateKey),r=Math.floor((e.now?.getTime()??Date.now())/1e3),i={alg:`RS256`,typ:`JWT`},a={exp:r+600,iat:r-60,iss:t},o=`${base64UrlJson(i)}.${base64UrlJson(a)}`;return`${o}.${createSign(`RSA-SHA256`).update(o).sign(n,`base64url`)}`}async function resolveGitHubInstallationToken(e){let t=e.credentials?.installationToken;if(t!==void 0)return typeof t==`function`?await t():t;if(e.installationId===void 0)throw Error(`githubChannel: installationId is required for authenticated GitHub API calls.`);return createGitHubInstallationToken({api:e.api,appId:e.credentials?.appId,installationId:e.installationId,privateKey:e.credentials?.privateKey})}async function createGitHubInstallationToken(e){let t=await resolveGitHubAppId(e.appId),n=e.api?.apiBaseUrl??`https://api.github.com`,r=`${n}:${t}:${e.installationId}`,i=installationTokenCache.get(r);if(i!==void 0&&Date.now()<i.expiresAtMs-6e4)return i.token;let a=await createGitHubAppJwt({appId:t,privateKey:e.privateKey}),o=await(e.api?.fetch??fetch)(`${n}/app/installations/${e.installationId}/access_tokens`,{headers:{accept:`application/vnd.github+json`,authorization:`Bearer ${a}`,"x-github-api-version":`2022-11-28`},method:`POST`}),s=await parseJsonBody(o);if(!o.ok)throw Error(`githubChannel: create installation token failed with HTTP ${o.status}.`);if(!isObject(s)||typeof s.token!=`string`)throw Error(`githubChannel: installation token response did not include a token.`);let c=parseExpiryMs(s.expires_at);return installationTokenCache.set(r,{expiresAtMs:c,token:s.token}),s.token}function clearGitHubInstallationTokenCache(){installationTokenCache.clear()}function seedGitHubInstallationTokenForTests(e){let t=e.apiBaseUrl??`https://api.github.com`,n=e.appId??`test-app`;installationTokenCache.set(`${t}:${n}:${e.installationId}`,{expiresAtMs:Date.now()+36e5,token:e.token})}function base64UrlJson(e){return Buffer.from(JSON.stringify(e)).toString(`base64url`)}async function parseJsonBody(e){let t=await e.text();if(!t)return null;try{return JSON.parse(t)}catch{return t}}function parseExpiryMs(e){if(typeof e==`string`){let t=Date.parse(e);if(Number.isFinite(t))return t}return Date.now()+36e5}export{clearGitHubInstallationTokenCache,createGitHubAppJwt,createGitHubBotNameResolver,createGitHubInstallationToken,normalizeGitHubPrivateKey,resolveGitHubAppId,resolveGitHubInstallationToken,resolveGitHubPrivateKey,resolveGitHubWebhookSecret,seedGitHubInstallationTokenForTests};