import { Vercel } from "@vercel/sdk" import * as z from "zod" import type { IntegrationScopeRequirement, ResolvedIntegrationAccount, } from "../../../automation/integrations" const VERCEL_ACCESS_TOKEN_SECRET_SCHEMA = z.object({ apiKey: z.string().min(1), }) const VERCEL_OAUTH_SECRET_SCHEMA = z.object({ accessToken: z.string().min(1), configurationId: z.string().min(1), teamId: z.string().min(1).nullable(), userId: z.string().min(1), }) /** * Allows a Vercel action through OAuth or a personal access token. * * @param requiredScope - OAuth permission required by the action. */ export function vercelAccountOptions( requiredScope: IntegrationScopeRequirement, ) { return { connections: [ { connectionMethodId: "oauth", requiredScope }, { connectionMethodId: "access-token" }, ], } as const } /** Allows a Vercel action only through a personal access token. */ export function vercelAccessTokenAccountOptions() { return { connections: [{ connectionMethodId: "access-token" }], } as const } /** * Creates the official authenticated Vercel REST API client. * * @param account - Resolved Vercel account credentials. */ export function getVercelApi(account: ResolvedIntegrationAccount<"vercel">) { return new Vercel({ bearerToken: getVercelAccessToken(account) }) } /** * Uses an explicit team or the team selected during OAuth installation. * * @param account - Resolved Vercel account credentials. * @param teamId - Optional explicit team override. */ export function getVercelTeamId( account: ResolvedIntegrationAccount<"vercel">, teamId?: string, ) { if (teamId) return teamId return account.connectionMethodId === "oauth" ? (VERCEL_OAUTH_SECRET_SCHEMA.parse(account.secret).teamId ?? undefined) : undefined } /** * Requires an explicit or OAuth-installed team for team-only endpoints. * * @param account - Resolved Vercel account credentials. * @param teamId - Optional explicit team override. * @throws {Error} When neither source supplies a team ID. */ export function requireVercelTeamId( account: ResolvedIntegrationAccount<"vercel">, teamId?: string, ) { const resolvedTeamId = getVercelTeamId(account, teamId) if (!resolvedTeamId) { throw new Error( "A Vercel team ID is required when the connected account uses a personal scope.", ) } return resolvedTeamId } /** * Reads the bearer token from either supported connection secret. * * @param account - Resolved Vercel account credentials. * @throws {Error} When the account uses an unsupported connection method. */ export function getVercelAccessToken( account: ResolvedIntegrationAccount<"vercel">, ) { if (account.connectionMethodId === "oauth") { return VERCEL_OAUTH_SECRET_SCHEMA.parse(account.secret).accessToken } if (account.connectionMethodId === "access-token") { return VERCEL_ACCESS_TOKEN_SECRET_SCHEMA.parse(account.secret).apiKey } throw new Error( `Unsupported Vercel connection method: ${account.connectionMethodId}`, ) }