import type { Encodable } from "@automate.ax/codec" import type { Vercel } from "@vercel/sdk" import * as z from "zod" import { defineAction } from "../../../automation/actions" import { getVercelApi, vercelAccessTokenAccountOptions } from "../lib/api" import { defineTokenVercelSdkAction } from "../lib/action" type RollingRelease = Vercel["rollingRelease"] const VERCEL_ROLLING_RELEASE_SCOPE_SCHEMA = z.object({ /** Project ID or name. */ idOrName: z.string().min(1), /** Team ID when the project belongs to a team. */ teamId: z.string().min(1).optional(), }) /** Returns a codec-compatible schema for one typed rolling-release result. */ function rollingReleaseOutputSchema() { return z.custom() } /** Gets the rolling-release configuration for one Vercel project. */ export const getVercelRollingReleaseConfiguration = defineTokenVercelSdkAction({ description: "Gets the template used by future production rollouts.", handler: ( api, request: Parameters[0], ) => api.rollingRelease.getRollingReleaseConfig(request), name: "Get Vercel rolling release configuration", replaySafety: "safe", }) /** Updates the rolling-release configuration for one Vercel project. */ export const updateVercelRollingReleaseConfiguration = defineTokenVercelSdkAction({ description: "Enables or updates the template for future rollouts.", handler: ( api, request: Parameters[0], ) => api.rollingRelease.updateRollingReleaseConfig(request), name: "Update Vercel rolling release configuration", replaySafety: "unsafe", }) /** Deletes the rolling-release configuration for one Vercel project. */ export const deleteVercelRollingReleaseConfiguration = defineTokenVercelSdkAction({ description: "Disables rolling releases for future deployments.", handler: ( api, request: Parameters[0], ) => api.rollingRelease.deleteRollingReleaseConfig(request), name: "Delete Vercel rolling release configuration", replaySafety: "unsafe", }) /** Gets the active or most recent rolling release for one project. */ export const getVercelRollingRelease = defineTokenVercelSdkAction({ description: "Gets the active, completed, or aborted rollout for a project.", handler: (api, request: Parameters[0]) => api.rollingRelease.getRollingRelease(request), name: "Get Vercel rolling release", replaySafety: "safe", }) /** Starts a rolling release for one Vercel deployment. */ export const startVercelRollingRelease = defineAction( "Start Vercel rolling release", ) .describe("Starts a staged production rollout for one deployment.") .account("vercel", vercelAccessTokenAccountOptions()) .input( VERCEL_ROLLING_RELEASE_SCOPE_SCHEMA.extend({ /** Canary deployment entering the rollout. */ canaryDeploymentId: z.string().min(1), }), ) .output( rollingReleaseOutputSchema< Awaited> & Encodable >(), ) .retry({ replaySafety: "unsafe" }) .handler(({ account, input }) => getVercelApi(account).rollingRelease.startRollingRelease({ idOrName: input.idOrName, requestBody: { canaryDeploymentId: input.canaryDeploymentId }, ...(input.teamId && { teamId: input.teamId }), }), ) /** Advances a Vercel rolling release to its next stage. */ export const approveVercelRollingReleaseStage = defineAction( "Approve Vercel rolling release stage", ) .describe("Approves the next stage of a manual rollout.") .account("vercel", vercelAccessTokenAccountOptions()) .input( VERCEL_ROLLING_RELEASE_SCOPE_SCHEMA.extend({ /** Canary deployment advancing to the next stage. */ canaryDeploymentId: z.string().min(1), /** Zero-based stage index to activate. */ nextStageIndex: z.number().int().nonnegative(), }), ) .output( rollingReleaseOutputSchema< Awaited> & Encodable >(), ) .retry({ replaySafety: "unsafe" }) .handler(({ account, input }) => getVercelApi(account).rollingRelease.approveRollingReleaseStage({ idOrName: input.idOrName, requestBody: { canaryDeploymentId: input.canaryDeploymentId, nextStageIndex: input.nextStageIndex, }, ...(input.teamId && { teamId: input.teamId }), }), ) /** Completes a Vercel rolling release immediately. */ export const completeVercelRollingRelease = defineAction( "Complete Vercel rolling release", ) .describe("Promotes the canary to serve all production traffic.") .account("vercel", vercelAccessTokenAccountOptions()) .input( VERCEL_ROLLING_RELEASE_SCOPE_SCHEMA.extend({ /** Canary deployment promoted to all traffic. */ canaryDeploymentId: z.string().min(1), }), ) .output( rollingReleaseOutputSchema< Awaited> & Encodable >(), ) .retry({ replaySafety: "unsafe" }) .handler(({ account, input }) => getVercelApi(account).rollingRelease.completeRollingRelease({ idOrName: input.idOrName, requestBody: { canaryDeploymentId: input.canaryDeploymentId }, ...(input.teamId && { teamId: input.teamId }), }), )