import * as z from "zod" import { defineAction } from "../../../automation/actions" import { getVercelApi, getVercelTeamId, vercelAccountOptions } from "../lib/api" import { VERIFIED_VERCEL_PROJECT_DOMAIN_SCHEMA, VERCEL_PROJECT_DOMAIN_PAGE_SCHEMA, VERCEL_PROJECT_DOMAIN_SCHEMA, } from "../lib/schemas" import { VERCEL_PROJECT_READ_SCOPE, VERCEL_PROJECT_DOMAIN_WRITE_REQUIREMENT, } from "../lib/scopes" const VERCEL_PROJECT_DOMAIN_SCOPE_SCHEMA = z.object({ /** Project ID or name. */ project: z.string().min(1), /** Team ID. OAuth accounts default to the installed team. */ teamId: z.string().min(1).optional(), }) /** Lists domains connected to one Vercel project. */ export const listVercelProjectDomains = defineAction( "List Vercel project domains", ) .describe("Lists a filtered page of domains connected to one project.") .account("vercel", vercelAccountOptions(VERCEL_PROJECT_READ_SCOPE)) .input( VERCEL_PROJECT_DOMAIN_SCOPE_SCHEMA.extend({ customEnvironmentId: z.string().min(1).optional(), gitBranch: z.string().min(1).optional(), limit: z.number().int().min(1).max(100).prefault(20), order: z.enum(["ASC", "DESC"]).prefault("DESC"), target: z.enum(["production", "preview"]).optional(), verified: z.boolean().optional(), }), ) .output(VERCEL_PROJECT_DOMAIN_PAGE_SCHEMA) .retry({ replaySafety: "safe" }) .handler(async ({ account, input }) => getVercelApi(account).projects.getProjectDomains({ idOrName: input.project, limit: input.limit, order: input.order, ...(input.customEnvironmentId && { customEnvironmentId: input.customEnvironmentId, }), ...(input.gitBranch && { gitBranch: input.gitBranch }), ...(input.target && { target: input.target }), ...(input.verified !== undefined && { verified: input.verified ? "true" : "false", }), ...(getVercelTeamId(account, input.teamId) && { teamId: getVercelTeamId(account, input.teamId), }), }), ) /** Gets one domain connected to a Vercel project. */ export const getVercelProjectDomain = defineAction("Get Vercel project domain") .describe("Gets one project domain and its verification state.") .account("vercel", vercelAccountOptions(VERCEL_PROJECT_READ_SCOPE)) .input( VERCEL_PROJECT_DOMAIN_SCOPE_SCHEMA.extend({ domain: z.string().min(1) }), ) .output(VERCEL_PROJECT_DOMAIN_SCHEMA) .retry({ replaySafety: "safe" }) .handler(async ({ account, input }) => getVercelApi(account).projects.getProjectDomain({ domain: input.domain, idOrName: input.project, ...(getVercelTeamId(account, input.teamId) && { teamId: getVercelTeamId(account, input.teamId), }), }), ) /** Adds a domain or redirect to one Vercel project. */ export const addVercelProjectDomain = defineAction("Add Vercel project domain") .describe("Adds a domain, branch domain, or redirect to one project.") .account( "vercel", vercelAccountOptions(VERCEL_PROJECT_DOMAIN_WRITE_REQUIREMENT), ) .input( VERCEL_PROJECT_DOMAIN_SCOPE_SCHEMA.extend({ customEnvironmentId: z.string().min(1).optional(), domain: z.string().min(1), gitBranch: z.string().min(1).optional(), redirect: z.string().min(1).nullable().optional(), redirectStatusCode: z .union([z.literal(301), z.literal(302), z.literal(307), z.literal(308)]) .nullable() .optional(), }), ) .output(VERCEL_PROJECT_DOMAIN_SCHEMA) .retry({ replaySafety: "unsafe" }) .handler(async ({ account, input }) => getVercelApi(account).projects.addProjectDomain({ idOrName: input.project, requestBody: { name: input.domain, ...(input.customEnvironmentId && { customEnvironmentId: input.customEnvironmentId, }), ...(input.gitBranch && { gitBranch: input.gitBranch }), ...(input.redirect !== undefined && { redirect: input.redirect }), ...(input.redirectStatusCode !== undefined && { redirectStatusCode: input.redirectStatusCode, }), }, ...(getVercelTeamId(account, input.teamId) && { teamId: getVercelTeamId(account, input.teamId), }), }), ) /** Updates routing for one Vercel project domain. */ export const updateVercelProjectDomain = defineAction( "Update Vercel project domain", ) .describe("Updates the branch or redirect attached to one project domain.") .account( "vercel", vercelAccountOptions(VERCEL_PROJECT_DOMAIN_WRITE_REQUIREMENT), ) .input( VERCEL_PROJECT_DOMAIN_SCOPE_SCHEMA.extend({ domain: z.string().min(1), gitBranch: z.string().min(1).nullable().optional(), redirect: z.string().min(1).nullable().optional(), redirectStatusCode: z .union([z.literal(301), z.literal(302), z.literal(307), z.literal(308)]) .nullable() .optional(), }), ) .output(VERCEL_PROJECT_DOMAIN_SCHEMA) .retry({ replaySafety: "unsafe" }) .handler(async ({ account, input }) => getVercelApi(account).projects.updateProjectDomain({ domain: input.domain, idOrName: input.project, requestBody: { ...(input.gitBranch !== undefined && { gitBranch: input.gitBranch }), ...(input.redirect !== undefined && { redirect: input.redirect }), ...(input.redirectStatusCode !== undefined && { redirectStatusCode: input.redirectStatusCode, }), }, ...(getVercelTeamId(account, input.teamId) && { teamId: getVercelTeamId(account, input.teamId), }), }), ) /** Moves one domain between Vercel projects. */ export const moveVercelProjectDomain = defineAction( "Move Vercel project domain", ) .describe("Moves one project domain and optionally changes its routing.") .account( "vercel", vercelAccountOptions(VERCEL_PROJECT_DOMAIN_WRITE_REQUIREMENT), ) .input( VERCEL_PROJECT_DOMAIN_SCOPE_SCHEMA.extend({ domain: z.string().min(1), gitBranch: z.string().min(1).nullable().optional(), redirect: z.string().min(1).nullable().optional(), redirectStatusCode: z .union([z.literal(301), z.literal(302), z.literal(307), z.literal(308)]) .nullable() .optional(), targetProjectId: z.string().min(1), }), ) .output(VERCEL_PROJECT_DOMAIN_SCHEMA) .retry({ replaySafety: "unsafe" }) .handler(async ({ account, input }) => getVercelApi(account).projects.moveProjectDomain({ domain: input.domain, idOrName: input.project, requestBody: { projectId: input.targetProjectId, ...(input.gitBranch !== undefined && { gitBranch: input.gitBranch }), ...(input.redirect !== undefined && { redirect: input.redirect }), ...(input.redirectStatusCode !== undefined && { redirectStatusCode: input.redirectStatusCode, }), }, ...(getVercelTeamId(account, input.teamId) && { teamId: getVercelTeamId(account, input.teamId), }), }), ) /** Removes a domain from one Vercel project. */ export const removeVercelProjectDomain = defineAction( "Remove Vercel project domain", ) .describe("Removes a domain and optionally its dependent redirects.") .account( "vercel", vercelAccountOptions(VERCEL_PROJECT_DOMAIN_WRITE_REQUIREMENT), ) .input( VERCEL_PROJECT_DOMAIN_SCOPE_SCHEMA.extend({ /** Domain name. */ domain: z.string().min(1), /** Also remove project domains that redirect to this domain. */ removeRedirects: z.boolean().prefault(false), }), ) .output(z.object({})) .retry({ replaySafety: "unsafe" }) .handler(async ({ account, input }) => getVercelApi(account).projects.removeProjectDomain({ domain: input.domain, idOrName: input.project, requestBody: { removeRedirects: input.removeRedirects }, ...(getVercelTeamId(account, input.teamId) && { teamId: getVercelTeamId(account, input.teamId), }), }), ) /** Rechecks ownership verification for a Vercel project domain. */ export const verifyVercelProjectDomain = defineAction( "Verify Vercel project domain", ) .describe("Rechecks the DNS ownership challenge for a project domain.") .account( "vercel", vercelAccountOptions(VERCEL_PROJECT_DOMAIN_WRITE_REQUIREMENT), ) .input( VERCEL_PROJECT_DOMAIN_SCOPE_SCHEMA.extend({ /** Domain name. */ domain: z.string().min(1), }), ) .output(VERIFIED_VERCEL_PROJECT_DOMAIN_SCHEMA) .retry({ replaySafety: "unsafe" }) .handler(async ({ account, input }) => getVercelApi(account).projects.verifyProjectDomain({ domain: input.domain, idOrName: input.project, ...(getVercelTeamId(account, input.teamId) && { teamId: getVercelTeamId(account, input.teamId), }), }), )