{"version":3,"file":"token-Iop2lapd.mjs","names":[],"sources":["../src/connect/connector.ts","../src/connect/scopes.ts","../src/connect/params.ts","../src/connect/token.ts"],"sourcesContent":["/**\n * A Vercel Connect connector name, or a resolver that returns one.\n *\n * Use a function to pick the connector dynamically — e.g. a different\n * connector per environment (`production` vs. `preview`) or per tenant.\n * It's resolved lazily, on every token request, alongside the token itself.\n */\nexport type GithubConnectorInput = string | (() => string | Promise<string>)\n\n/** Resolves a {@link GithubConnectorInput} to a connector name string. */\nexport async function resolveGithubConnector(connector: GithubConnectorInput): Promise<string> {\n  return typeof connector === 'function' ? await connector() : connector\n}\n","import { resolvePresetTools, type GithubToolPreset } from '../core/presets'\nimport { GITHUB_TOOL_CATALOG } from '../core/catalog'\nimport { ALL_GITHUB_TOOL_NAMES, type GithubToolName } from '../core/tool-names'\n\n/**\n * Vercel Connect scope strings mapped to each {@link GithubToolPreset}.\n *\n * Scopes mirror GitHub App permissions (`contents`, `pull_requests`, `issues`,\n * `discussions`, `actions`, `checks`, `statuses`, `administration`, `metadata`)\n * and must cover every read/write family a preset's tools touch, not just its\n * primary domain. Release tools fall under the `contents` permission on GitHub\n * Apps, and reaction tools under `issues`, so neither needs a scope of its own.\n *\n * Gist tools in `repo-explorer` and `maintainer` are intentionally left\n * unscoped: the Gists API only accepts GitHub App *user* access tokens, never\n * installation tokens, and Connect mints `subject: { type: 'app' }`\n * installation tokens by default. Gist calls made with an app-subject token\n * 403 regardless of requested scopes — use a `{ type: 'user' }` subject or a\n * fine-grained PAT with the \"Gists\" account permission for those tools instead.\n *\n * Notification tools in `maintainer` and `notification-inbox` are unscoped for\n * the same reason: `notifications` is an account-level GitHub App permission\n * that only applies to user access tokens, so `listNotifications` /\n * `markNotificationRead` need a PAT with the \"Notifications\" account permission.\n */\nexport const PRESET_CONNECT_SCOPES = {\n  'repo-explorer': [\n    'contents:read',\n    'metadata:read',\n    'pull_requests:read',\n    'issues:read',\n    'discussions:read',\n    'actions:read',\n    'checks:read',\n    'statuses:read',\n  ],\n  'code-review': [\n    'contents:read',\n    'metadata:read',\n    'pull_requests:read',\n    'pull_requests:write',\n    'checks:read',\n    'statuses:read',\n  ],\n  'issue-triage': [\n    'contents:read',\n    'metadata:read',\n    'issues:read',\n    'issues:write',\n  ],\n  'ci-ops': [\n    'contents:read',\n    'metadata:read',\n    'actions:read',\n    'actions:write',\n    'checks:read',\n    'statuses:read',\n  ],\n  'security-audit': [\n    'contents:read',\n    'metadata:read',\n    'pull_requests:read',\n    'issues:read',\n    'issues:write',\n    'actions:read',\n    'checks:read',\n    'statuses:read',\n  ],\n  'release-manager': [\n    'contents:read',\n    'contents:write',\n    'metadata:read',\n    'pull_requests:read',\n    'actions:read',\n    'actions:write',\n  ],\n  'discussion-moderator': [\n    'contents:read',\n    'metadata:read',\n    'issues:read',\n    'issues:write',\n    'discussions:read',\n    'discussions:write',\n  ],\n  'notification-inbox': [\n    'contents:read',\n    'metadata:read',\n    'pull_requests:read',\n    'issues:read',\n  ],\n  'pr-author': [\n    'contents:read',\n    'contents:write',\n    'metadata:read',\n    'pull_requests:read',\n    'pull_requests:write',\n  ],\n  'maintainer': [\n    'contents:read',\n    'contents:write',\n    'metadata:read',\n    'pull_requests:read',\n    'pull_requests:write',\n    'issues:read',\n    'issues:write',\n    'discussions:read',\n    'discussions:write',\n    'actions:read',\n    'actions:write',\n    'checks:read',\n    'statuses:read',\n    'administration:read',\n    'administration:write',\n  ],\n} as const satisfies Record<GithubToolPreset, readonly string[]>\n\n/** Default scopes when no preset is specified — union of all preset scopes. */\nconst ALL_CONNECT_SCOPES = [\n  ...new Set(Object.values(PRESET_CONNECT_SCOPES).flat()),\n] as string[]\n\n/** Stable scope order for tool-derived unions (tests + Connect payloads). */\nconst SCOPE_ORDER = [\n  'contents:read',\n  'contents:write',\n  'metadata:read',\n  'pull_requests:read',\n  'pull_requests:write',\n  'issues:read',\n  'issues:write',\n  'discussions:read',\n  'discussions:write',\n  'actions:read',\n  'actions:write',\n  'checks:read',\n  'statuses:read',\n  'administration:read',\n  'administration:write',\n] as const\n\n/**\n * Per-tool Connect scopes, derived from `GITHUB_TOOL_CATALOG`. Empty arrays are\n * intentional for gist and notification tools (installation tokens cannot\n * satisfy those APIs).\n */\nexport const TOOL_CONNECT_SCOPES = ALL_GITHUB_TOOL_NAMES.reduce(\n  (map, name) => {\n    map[name] = GITHUB_TOOL_CATALOG[name].connectScopes\n    return map\n  },\n  {} as Record<GithubToolName, readonly string[]>,\n)\n\nfunction orderScopes(scopes: Set<string>): string[] {\n  return SCOPE_ORDER.filter(scope => scopes.has(scope))\n}\n\n/**\n * Returns Vercel Connect scopes for a preset or combined presets.\n * Without a preset, returns the union of all preset scopes (full tool set).\n */\nexport function connectGithubScopesForPreset(\n  preset?: GithubToolPreset | GithubToolPreset[],\n): string[] {\n  if (!preset) return [...ALL_CONNECT_SCOPES]\n\n  const presets = Array.isArray(preset) ? preset : [preset]\n  return [\n    ...new Set(presets.flatMap(p => PRESET_CONNECT_SCOPES[p])),\n  ]\n}\n\n/**\n * Returns Connect scopes covering exactly the given tools.\n * Always includes `metadata:read`. Gist and notification tools contribute nothing.\n */\nexport function connectGithubScopesForTools(names: readonly GithubToolName[]): string[] {\n  const scopes = new Set<string>(['metadata:read'])\n  for (const name of names) {\n    for (const scope of TOOL_CONNECT_SCOPES[name]) {\n      scopes.add(scope)\n    }\n  }\n  return orderScopes(scopes)\n}\n\nexport type ConnectScopeSelection = {\n  preset?: GithubToolPreset | GithubToolPreset[]\n  include?: readonly GithubToolName[]\n  exclude?: readonly GithubToolName[]\n}\n\nfunction resolveSelectedToolNames({\n  preset,\n  include,\n  exclude,\n}: ConnectScopeSelection): GithubToolName[] {\n  const presetAllowed = preset ? resolvePresetTools(preset) : null\n  const includeAllowed = include ? new Set(include) : null\n  const excluded = exclude ? new Set(exclude) : null\n\n  const allowed = presetAllowed && includeAllowed\n    ? new Set([...presetAllowed, ...includeAllowed])\n    : presetAllowed ?? includeAllowed\n\n  return ALL_GITHUB_TOOL_NAMES.filter(\n    name => (!allowed || allowed.has(name)) && !excluded?.has(name),\n  )\n}\n\n/**\n * Resolves Connect scopes for the effective tool set.\n *\n * - No `include` / `exclude`: same as {@link connectGithubScopesForPreset}\n *   (omitted preset → full union, including `administration:write`).\n * - With `include` and/or `exclude`: scopes are derived from the resolved tools\n *   so a hand-picked `include` list does not mint the full admin surface.\n */\nexport function connectGithubScopesForSelection(selection: ConnectScopeSelection = {}): string[] {\n  const { preset, include, exclude } = selection\n  if (!include && !exclude) {\n    return connectGithubScopesForPreset(preset)\n  }\n  return connectGithubScopesForTools(resolveSelectedToolNames(selection))\n}\n","import type { ConnectTokenParams } from '@vercel/connect'\nimport { connectGithubScopesForSelection } from './scopes'\nimport type { ConnectGithubTokenOptions, GithubConnectParams } from './types'\n\nexport function resolveGithubConnectTokenParams(\n  options: ConnectGithubTokenOptions = {},\n): ConnectTokenParams {\n  const { preset, include, exclude, params } = options\n  const scopes = params?.scopes ?? connectGithubScopesForSelection({ preset, include, exclude })\n  return buildConnectTokenParams(scopes, params)\n}\n\nfunction buildConnectTokenParams(\n  scopes: string[],\n  params?: GithubConnectParams,\n): ConnectTokenParams {\n  const { repositories, subject, ...rest } = params ?? {}\n\n  const authorizationDetails = rest.authorizationDetails\n    ?? (repositories?.length\n      ? [{ type: 'github_app_installation' as const, repositories }]\n      : undefined)\n\n  return {\n    subject: subject ?? { type: 'app' },\n    ...rest,\n    scopes,\n    ...(authorizationDetails && { authorizationDetails }),\n  }\n}\n","import {\n  ConnectError,\n  ConnectorInstallationRequiredError,\n  getToken,\n  UserAuthorizationRequiredError,\n  type ConnectOptions,\n  type ConnectTokenParams,\n} from '@vercel/connect'\nimport { githubToolsErrors } from '../core/errors'\nimport type { GithubTokenInput } from '../core/token'\nimport { resolveGithubConnector, type GithubConnectorInput } from './connector'\nimport { resolveGithubConnectTokenParams } from './params'\nimport type { ConnectGithubTokenOptions } from './types'\n\n/**\n * Returns a lazy GitHub token provider backed by a Vercel Connect connector.\n * Scopes are derived from `preset`, or from the resolved `include`/`exclude`\n * tool set when those are set, unless overridden in `params.scopes`.\n *\n * `connector` may be a static name or a resolver function — e.g. to pick a\n * different connector per environment (production vs. preview) or tenant.\n * It's re-resolved on every call, alongside the token itself.\n */\nexport function connectGithubToken(\n  connector: GithubConnectorInput,\n  options: ConnectGithubTokenOptions = {},\n): GithubTokenInput {\n  const { connectOptions } = options\n  const tokenParams = resolveGithubConnectTokenParams(options)\n\n  return async () => {\n    try {\n      return await getToken(\n        await resolveGithubConnector(connector),\n        tokenParams,\n        resolveConnectOptions(connectOptions),\n      )\n    }\n    catch (error) {\n      throw toConnectCatalogError(error, tokenParams)\n    }\n  }\n}\n\n/**\n * Map @vercel/connect failures to catalog errors so models get the actual\n * cause (process identity, missing user connection, missing installation)\n * instead of a bare \"Not authorized\" they misread as GitHub permissions.\n */\nfunction toConnectCatalogError(error: unknown, tokenParams: ConnectTokenParams): unknown {\n  if (error instanceof UserAuthorizationRequiredError) {\n    const subjectId = tokenParams.subject.type === 'user' ? tokenParams.subject.id : tokenParams.subject.type\n    return githubToolsErrors.CONNECT_USER_NOT_CONNECTED({ subjectId, cause: error })\n  }\n  if (error instanceof ConnectorInstallationRequiredError) {\n    return githubToolsErrors.CONNECT_INSTALLATION_REQUIRED({ detail: error.message, cause: error })\n  }\n  if (error instanceof ConnectError && error.status === 403) {\n    return githubToolsErrors.CONNECT_NOT_AUTHORIZED({ detail: error.message, cause: error })\n  }\n  return error\n}\n\n/**\n * Best-effort JWT `exp` claim, in epoch seconds. Returns undefined for\n * malformed tokens — Connect then rejects them with its own error.\n */\nfunction oidcTokenExpiry(token: string): number | undefined {\n  const payload = token.split('.')[1]\n  if (!payload) return undefined\n  try {\n    const claims: unknown = JSON.parse(Buffer.from(payload, 'base64url').toString())\n    if (claims == null || typeof claims !== 'object' || !('exp' in claims)) return undefined\n    return typeof claims.exp === 'number' ? claims.exp : undefined\n  }\n  catch {\n    return undefined\n  }\n}\n\n/**\n * Prefer an explicit `vercelToken`, then `VERCEL_OIDC_TOKEN` from the environment.\n * Passing the env token into `getToken` skips `@vercel/oidc`'s project-root walk,\n * which fails inside eve/workflow snapshots that have no `.vercel` directory.\n *\n * Pinning also disables refresh, so an expired token fails loudly here instead\n * of surfacing as an opaque Connect 403 the model misreads as GitHub permissions.\n */\nfunction resolveConnectOptions(connectOptions?: ConnectOptions): ConnectOptions | undefined {\n  const vercelToken = connectOptions?.vercelToken ?? process.env.VERCEL_OIDC_TOKEN\n  if (vercelToken) {\n    const exp = oidcTokenExpiry(vercelToken)\n    if (exp !== undefined && exp * 1000 <= Date.now()) {\n      throw githubToolsErrors.OIDC_TOKEN_EXPIRED({ expiredAt: new Date(exp * 1000).toISOString() })\n    }\n  }\n  if (!vercelToken && !connectOptions) return undefined\n  return {\n    ...vercelToken ? { vercelToken } : {},\n    ...connectOptions,\n  }\n}\n\nexport type { ConnectOptions }\n"],"mappings":";;;;AAUA,eAAsB,uBAAuB,WAAkD;CAC7F,OAAO,OAAO,cAAc,aAAa,MAAM,UAAU,IAAI;AAC/D;;;;;;;;;;;;;;;;;;;;;;;;ACaA,MAAa,wBAAwB;CACnC,iBAAiB;EACf;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF;CACA,eAAe;EACb;EACA;EACA;EACA;EACA;EACA;CACF;CACA,gBAAgB;EACd;EACA;EACA;EACA;CACF;CACA,UAAU;EACR;EACA;EACA;EACA;EACA;EACA;CACF;CACA,kBAAkB;EAChB;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF;CACA,mBAAmB;EACjB;EACA;EACA;EACA;EACA;EACA;CACF;CACA,wBAAwB;EACtB;EACA;EACA;EACA;EACA;EACA;CACF;CACA,sBAAsB;EACpB;EACA;EACA;EACA;CACF;CACA,aAAa;EACX;EACA;EACA;EACA;EACA;CACF;CACA,cAAc;EACZ;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF;AACF;;AAGA,MAAM,qBAAqB,CACzB,GAAG,IAAI,IAAI,OAAO,OAAO,qBAAqB,CAAC,CAAC,KAAK,CAAC,CACxD;;AAGA,MAAM,cAAc;CAClB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;;;;;;AAOA,MAAa,sBAAsB,sBAAsB,QACtD,KAAK,SAAS;CACb,IAAI,QAAQ,oBAAoB,KAAK,CAAC;CACtC,OAAO;AACT,GACA,CAAC,CACH;AAEA,SAAS,YAAY,QAA+B;CAClD,OAAO,YAAY,QAAO,UAAS,OAAO,IAAI,KAAK,CAAC;AACtD;;;;;AAMA,SAAgB,6BACd,QACU;CACV,IAAI,CAAC,QAAQ,OAAO,CAAC,GAAG,kBAAkB;CAG1C,OAAO,CACL,GAAG,IAAI,KAFO,MAAM,QAAQ,MAAM,IAAI,SAAS,CAAC,MAAM,EAAA,CAEnC,SAAQ,MAAK,sBAAsB,EAAE,CAAC,CAC3D;AACF;;;;;AAMA,SAAgB,4BAA4B,OAA4C;CACtF,MAAM,yBAAS,IAAI,IAAY,CAAC,eAAe,CAAC;CAChD,KAAK,MAAM,QAAQ,OACjB,KAAK,MAAM,SAAS,oBAAoB,OACtC,OAAO,IAAI,KAAK;CAGpB,OAAO,YAAY,MAAM;AAC3B;AAQA,SAAS,yBAAyB,EAChC,QACA,SACA,WAC0C;CAC1C,MAAM,gBAAgB,SAAS,mBAAmB,MAAM,IAAI;CAC5D,MAAM,iBAAiB,UAAU,IAAI,IAAI,OAAO,IAAI;CACpD,MAAM,WAAW,UAAU,IAAI,IAAI,OAAO,IAAI;CAE9C,MAAM,UAAU,iBAAiB,iCAC7B,IAAI,IAAI,CAAC,GAAG,eAAe,GAAG,cAAc,CAAC,IAC7C,iBAAiB;CAErB,OAAO,sBAAsB,QAC3B,UAAS,CAAC,WAAW,QAAQ,IAAI,IAAI,MAAM,CAAC,UAAU,IAAI,IAAI,CAChE;AACF;;;;;;;;;AAUA,SAAgB,gCAAgC,YAAmC,CAAC,GAAa;CAC/F,MAAM,EAAE,QAAQ,SAAS,YAAY;CACrC,IAAI,CAAC,WAAW,CAAC,SACf,OAAO,6BAA6B,MAAM;CAE5C,OAAO,4BAA4B,yBAAyB,SAAS,CAAC;AACxE;;;AC5NA,SAAgB,gCACd,UAAqC,CAAC,GAClB;CACpB,MAAM,EAAE,QAAQ,SAAS,SAAS,WAAW;CAE7C,OAAO,wBADQ,QAAQ,UAAU,gCAAgC;EAAE;EAAQ;EAAS;CAAQ,CAAC,GACtD,MAAM;AAC/C;AAEA,SAAS,wBACP,QACA,QACoB;CACpB,MAAM,EAAE,cAAc,SAAS,GAAG,SAAS,UAAU,CAAC;CAEtD,MAAM,uBAAuB,KAAK,yBAC5B,cAAc,SACd,CAAC;EAAE,MAAM;EAAoC;CAAa,CAAC,IAC3D,KAAA;CAEN,OAAO;EACL,SAAS,WAAW,EAAE,MAAM,MAAM;EAClC,GAAG;EACH;EACA,GAAI,wBAAwB,EAAE,qBAAqB;CACrD;AACF;;;;;;;;;;;;ACNA,SAAgB,mBACd,WACA,UAAqC,CAAC,GACpB;CAClB,MAAM,EAAE,mBAAmB;CAC3B,MAAM,cAAc,gCAAgC,OAAO;CAE3D,OAAO,YAAY;EACjB,IAAI;GACF,OAAO,MAAM,SACX,MAAM,uBAAuB,SAAS,GACtC,aACA,sBAAsB,cAAc,CACtC;EACF,SACO,OAAO;GACZ,MAAM,sBAAsB,OAAO,WAAW;EAChD;CACF;AACF;;;;;;AAOA,SAAS,sBAAsB,OAAgB,aAA0C;CACvF,IAAI,iBAAiB,gCAAgC;EACnD,MAAM,YAAY,YAAY,QAAQ,SAAS,SAAS,YAAY,QAAQ,KAAK,YAAY,QAAQ;EACrG,OAAO,kBAAkB,2BAA2B;GAAE;GAAW,OAAO;EAAM,CAAC;CACjF;CACA,IAAI,iBAAiB,oCACnB,OAAO,kBAAkB,8BAA8B;EAAE,QAAQ,MAAM;EAAS,OAAO;CAAM,CAAC;CAEhG,IAAI,iBAAiB,gBAAgB,MAAM,WAAW,KACpD,OAAO,kBAAkB,uBAAuB;EAAE,QAAQ,MAAM;EAAS,OAAO;CAAM,CAAC;CAEzF,OAAO;AACT;;;;;AAMA,SAAS,gBAAgB,OAAmC;CAC1D,MAAM,UAAU,MAAM,MAAM,GAAG,CAAC,CAAC;CACjC,IAAI,CAAC,SAAS,OAAO,KAAA;CACrB,IAAI;EACF,MAAM,SAAkB,KAAK,MAAM,OAAO,KAAK,SAAS,WAAW,CAAC,CAAC,SAAS,CAAC;EAC/E,IAAI,UAAU,QAAQ,OAAO,WAAW,YAAY,EAAE,SAAS,SAAS,OAAO,KAAA;EAC/E,OAAO,OAAO,OAAO,QAAQ,WAAW,OAAO,MAAM,KAAA;CACvD,QACM;EACJ;CACF;AACF;;;;;;;;;AAUA,SAAS,sBAAsB,gBAA6D;CAC1F,MAAM,cAAc,gBAAgB,eAAe,QAAQ,IAAI;CAC/D,IAAI,aAAa;EACf,MAAM,MAAM,gBAAgB,WAAW;EACvC,IAAI,QAAQ,KAAA,KAAa,MAAM,OAAQ,KAAK,IAAI,GAC9C,MAAM,kBAAkB,mBAAmB,EAAE,4BAAW,IAAI,KAAK,MAAM,GAAI,EAAA,CAAE,YAAY,EAAE,CAAC;CAEhG;CACA,IAAI,CAAC,eAAe,CAAC,gBAAgB,OAAO,KAAA;CAC5C,OAAO;EACL,GAAG,cAAc,EAAE,YAAY,IAAI,CAAC;EACpC,GAAG;CACL;AACF"}