diff --git a/.changeset/docs-external-vercel-auth.md b/.changeset/docs-external-vercel-auth.md new file mode 100644 index 0000000000..144996bf03 --- /dev/null +++ b/.changeset/docs-external-vercel-auth.md @@ -0,0 +1,4 @@ +--- +--- + +Document authenticating the Vercel World from outside a deployment (local scripts and CI) with a Vercel auth token. diff --git a/docs/content/docs/v4/api-reference/workflow-api/get-hook-by-token.mdx b/docs/content/docs/v4/api-reference/workflow-api/get-hook-by-token.mdx index 1448c48f3e..0e18d23faf 100644 --- a/docs/content/docs/v4/api-reference/workflow-api/get-hook-by-token.mdx +++ b/docs/content/docs/v4/api-reference/workflow-api/get-hook-by-token.mdx @@ -122,7 +122,11 @@ import { getHookByToken, resumeHook } from "workflow/api"; export async function POST(request: Request) { const { token, data } = await request.json(); - const expectedEnv = process.env.VERCEL_ENV || "development"; + // On Vercel the platform sets these: `VERCEL_TARGET_ENV` carries a custom + // environment's slug, where `VERCEL_ENV` reports `preview`. Running against + // the Local World, hooks are recorded as `local`. + const expectedEnv = + process.env.VERCEL_TARGET_ENV ?? process.env.VERCEL_ENV ?? "local"; try { const hook = await getHookByToken(token); // [!code highlight] diff --git a/docs/content/docs/v5/api-reference/workflow-api/get-hook-by-token.mdx b/docs/content/docs/v5/api-reference/workflow-api/get-hook-by-token.mdx index 82638ae989..0c4aee6cfc 100644 --- a/docs/content/docs/v5/api-reference/workflow-api/get-hook-by-token.mdx +++ b/docs/content/docs/v5/api-reference/workflow-api/get-hook-by-token.mdx @@ -124,7 +124,11 @@ import { getHookByToken, resumeHook } from "workflow/api"; export async function POST(request: Request) { const { token, data } = await request.json(); - const expectedEnv = process.env.VERCEL_ENV || "development"; + // On Vercel the platform sets these: `VERCEL_TARGET_ENV` carries a custom + // environment's slug, where `VERCEL_ENV` reports `preview`. Running against + // the Local World, hooks are recorded as `local`. + const expectedEnv = + process.env.VERCEL_TARGET_ENV ?? process.env.VERCEL_ENV ?? "local"; try { const hook = await getHookByToken(token); // [!code highlight] diff --git a/docs/content/docs/v5/configuration/cli-and-web-ui.mdx b/docs/content/docs/v5/configuration/cli-and-web-ui.mdx index 6694e487ca..4ca56d59fe 100644 --- a/docs/content/docs/v5/configuration/cli-and-web-ui.mdx +++ b/docs/content/docs/v5/configuration/cli-and-web-ui.mdx @@ -12,6 +12,8 @@ The `workflow` CLI uses flags first, then environment variables, then defaults o Vercel project and auth settings can often be inferred from `.vercel/project.json` and your Vercel CLI login. +Whichever way they are resolved, the CLI ends up building a Vercel World from an auth token plus a project ID, team ID, and environment — the same four values any external client needs. Set them explicitly when there is no interactive `vercel login` to infer from, or when writing your own script instead of using the CLI; see [Connecting from outside a deployment](/worlds/vercel#connecting-from-outside-a-deployment). + ## Target backend ### `--backend` / `-b` @@ -49,7 +51,7 @@ Vercel project and auth settings can often be inferred from `.vercel/project.jso - Environment variable: `WORKFLOW_VERCEL_ENV` - Default: `production` - Vercel environment for `--backend vercel`. -- Accepts `production` or `preview`. +- Accepts `production`, `preview`, or a custom environment's slug. ## Web UI diff --git a/docs/content/docs/v5/configuration/worlds.mdx b/docs/content/docs/v5/configuration/worlds.mdx index 72487e4a1f..8a43d1d8f5 100644 --- a/docs/content/docs/v5/configuration/worlds.mdx +++ b/docs/content/docs/v5/configuration/worlds.mdx @@ -192,6 +192,8 @@ The Vercel World is configured automatically inside Vercel deployments. The plat Most applications should not set `WORKFLOW_VERCEL_*` variables on Vercel. They configure tooling that talks to a Vercel Workflow project from outside a deployment, such as the `workflow` CLI, the web UI, CI, or tests. The runtime warns if these variables are set in a deployed Vercel function because they do not control runtime configuration there. +The entries below are the individual knobs. For a walkthrough of authenticating a local script or a CI job with a Vercel auth token — which variables are needed together, and how to pass them to the World factory — see [Connecting from outside a deployment](/worlds/vercel#connecting-from-outside-a-deployment). + Platform-provided values such as `VERCEL_DEPLOYMENT_ID`, `VERCEL_PROJECT_ID`, and `VERCEL_DEPLOYMENT_KEY` are read by the runtime inside Vercel deployments. Do not set them yourself. ### `token` @@ -200,13 +202,14 @@ Platform-provided values such as `VERCEL_DEPLOYMENT_ID`, `VERCEL_PROJECT_ID`, an - CLI flag: `--authToken` - Default: inferred when possible - Vercel API token for external tooling. Keep it secret. +- Only meaningful alongside `projectConfig.projectId` and `projectConfig.teamId` — set all three together. Supplying both IDs but no token throws rather than failing later with a `401`. ### `projectConfig.environment` - Environment variable: `WORKFLOW_VERCEL_ENV` - CLI flag: `--env` or `-e` - Default: `production` -- Vercel environment targeted by tooling. Accepts `production` or `preview`. +- Vercel environment targeted by tooling. Accepts `production`, `preview`, or a custom environment's **slug** — configure the slug, not the environment's ID. ### `projectConfig.projectId` diff --git a/docs/content/worlds/v4/vercel.mdx b/docs/content/worlds/v4/vercel.mdx index f2352126d9..83c36c42d6 100644 --- a/docs/content/worlds/v4/vercel.mdx +++ b/docs/content/worlds/v4/vercel.mdx @@ -28,7 +28,7 @@ That's it. Vercel automatically: - Selects the Vercel World backend - Configures authentication using OIDC tokens - Provisions storage and queuing infrastructure -- Isolates data per environment (production, preview, development) +- Isolates data per environment (production, preview, and any custom environments) @@ -92,6 +92,137 @@ npx workflow inspect runs \ Learn more in the [Observability](/docs/observability) documentation. +## Connecting from outside a deployment + +Inside a Vercel deployment there is nothing to authenticate: the platform injects a per-request OIDC token and the Vercel World uses it automatically. A process that is *not* a deployment has no such token — a script on your laptop, a CI job driving end-to-end tests against a preview, a one-off backfill. Those clients authenticate with a **Vercel auth token** instead. Vercel checks that token against your team and project permissions, and attributes the request to the environment you name. + + + Do not reuse the `VERCEL_OIDC_TOKEN` that `vercel env pull` writes into + `.env.local` as your Workflow credential. It is a local artifact of your + linked project, not a credential for the Workflow API: requests made with it + are attributed to the environment carried in the token itself, not to the + `production` or `preview` data you mean to reach. Authenticate with a Vercel + auth token instead. A pulled OIDC token is still the right thing for + [bypassing deployment + protection](https://vercel.com/docs/deployment-protection/methods-to-bypass-deployment-protection/trusted-sources) + when your script has to fetch a protected preview URL; that is a separate + credential from the one that talks to the Workflow API. + + +### Environment variables + +These four values are what an external client needs. The names are the convention shared by the `workflow` CLI, the web UI, and Workflow's own CI: + +| Variable | Value | Notes | +| --- | --- | --- | +| `WORKFLOW_VERCEL_AUTH_TOKEN` | Vercel auth token | Keep it secret. Create one under [account settings → tokens](https://vercel.com/account/tokens), scoped to the team that owns the project. | +| `WORKFLOW_VERCEL_TEAM` | Vercel team ID (`team_...`) | Required. Set it together with the token and the project ID. | +| `WORKFLOW_VERCEL_PROJECT` | Vercel project ID (`prj_...`) | Required. Set it together with the token and the team ID. | +| `WORKFLOW_VERCEL_ENV` | `production`, `preview`, or a custom environment's slug | Defaults to `production`. See [`WORKFLOW_VERCEL_ENV`](#workflow_vercel_env). | + +Both IDs are in `.vercel/project.json` after `vercel link` — `projectId` is the project, `orgId` the team or user that owns it — or on the project's settings page. + +Three more are situational: + +- `VERCEL_DEPLOYMENT_ID` — required to **start** runs, not to read them. See [Starting runs](#starting-runs-from-outside-a-deployment). +- `WORKFLOW_VERCEL_PROJECT_NAME` — the project slug, used only to build dashboard links. +- `VERCEL_TOKEN` — a fallback the World reads for the Vercel API calls it makes alongside your Workflow requests (fetching a run's encryption key, resolving `deploymentId: "latest"`). A client that passes `token` explicitly, as below, already covers those calls and does not need it. + +For a custom environment, set `WORKFLOW_VERCEL_ENV` to the environment's **slug**, not its ID. + + + The Workflow SDK does not read `WORKFLOW_VERCEL_*` from the environment on + your behalf — the runtime's own `createWorld()` deliberately ignores them, so + that a stray variable on a deployed project cannot redirect a live + application. Read them in your own code and pass them to the World factory, + as below. Setting them on a deployed Vercel project has no effect on runtime + configuration, and the runtime warns when it sees them there. + + +### Wiring it up in a script + +Build the Vercel World with an explicit config and install it with [`setWorld()`](/docs/api-reference/workflow-runtime/set-world) before the first `workflow/api` call: + +{/*@skip-typecheck: incomplete code sample*/} + +```typescript title="scripts/start-run.ts" lineNumbers +import { start } from "workflow/api"; +import { setWorld } from "workflow/runtime"; +import { createVercelWorld } from "@workflow/world-vercel"; +import { myWorkflow } from "../workflows/my-workflow"; + +setWorld( + createVercelWorld({ + token: process.env.WORKFLOW_VERCEL_AUTH_TOKEN, // [!code highlight] + projectConfig: { + projectId: process.env.WORKFLOW_VERCEL_PROJECT, // [!code highlight] + teamId: process.env.WORKFLOW_VERCEL_TEAM, // [!code highlight] + environment: process.env.WORKFLOW_VERCEL_ENV, // [!code highlight] + }, + }) +); + +const run = await start(myWorkflow, ["input"]); +console.log(run.runId); +``` + +Supply `token`, `projectId`, and `teamId` together. Setting the two IDs without a token fails immediately, with a message naming the missing token, rather than surfacing later as an opaque `401`. + +The same token authorizes the per-run key fetch that decrypts run and step data, so reads come back as values rather than opaque bytes — see [Encryption](/docs/how-it-works/encryption). + +This is exactly what the `workflow` CLI does under the hood. It resolves the same four values — from `--authToken` / `--project` / `--team` / `--env`, then the `WORKFLOW_VERCEL_*` variables, then `.vercel/project.json` and your `vercel login` credentials — and constructs the World with them. Passing them explicitly is the non-interactive equivalent of being logged in and linked. + +### Starting runs from outside a deployment + +[`start()`](/docs/api-reference/workflow-api/start) has to name a deployment, because a run executes the code of the deployment that created it. Inside a deployment that is the current one; outside, there is nothing to infer, so set `VERCEL_DEPLOYMENT_ID` to the deployment whose code should run the workflow: + +```bash +# `vercel inspect` prints the dpl_... ID for a deployment URL +vercel inspect https://my-app-abc123.vercel.app +``` + +Reads such as [`getRun()`](/docs/api-reference/workflow-api/get-run) do not need it. `start(..., { deploymentId: "latest" })` does: it resolves the newest deployment sharing that deployment's environment, so it needs one to start from. + + + Keep `WORKFLOW_VERCEL_ENV` and the environment of the deployment named by + `VERCEL_DEPLOYMENT_ID` aligned. The run is created in the environment you + authenticate as, but executes the code of the deployment you name — a run + whose two halves land in different environments will not execute as + expected. + + +### In CI + +Wait for the deployment under test, then hand its ID to the test step alongside the four auth variables. This is how Workflow's own end-to-end suite authenticates against its preview and production deployments: + +```yaml title=".github/workflows/e2e.yml" lineNumbers +jobs: + e2e: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Wait for the Vercel deployment + id: deployment + uses: vercel/wait-for-deployment-action@0e2b0c5c5cce31f1648108aeec56467187aca037 + with: + project-slug: my-app + environment: ${{ github.ref == 'refs/heads/main' && 'production' || 'preview' }} + + - name: Run end-to-end tests + run: pnpm test:e2e + env: + WORKFLOW_VERCEL_AUTH_TOKEN: ${{ secrets.VERCEL_TOKEN }} + WORKFLOW_VERCEL_TEAM: team_xxxxxxxxxxxxxxxx + WORKFLOW_VERCEL_PROJECT: prj_xxxxxxxxxxxxxxxx + WORKFLOW_VERCEL_ENV: ${{ github.ref == 'refs/heads/main' && 'production' || 'preview' }} + VERCEL_DEPLOYMENT_ID: ${{ steps.deployment.outputs.deployment-id }} +``` + +Store the token as an encrypted secret and derive `WORKFLOW_VERCEL_ENV` from the branch, so a pull request run never authenticates as `production`. + +If the deployment is behind deployment protection, the job also needs a way to reach its URL. Grant the workflow `id-token: write` and mint a short-lived OIDC token from the runner for the `x-vercel-trusted-oidc-idp-token` header; that credential is for [Trusted Sources](https://vercel.com/docs/deployment-protection/methods-to-bypass-deployment-protection/trusted-sources) only and is separate from the Vercel auth token above. + ## Testing & Compatibility @@ -100,9 +231,11 @@ Learn more in the [Observability](/docs/observability) documentation. The Vercel World requires no configuration when deployed to Vercel. For advanced use cases, you can override settings programmatically via `createVercelWorld()`. +The `WORKFLOW_VERCEL_*` variables below configure tooling that talks to a Vercel Workflow project from outside a deployment. For the task-oriented version — which ones a local script or CI job needs, and how to hand them to the SDK — see [Connecting from outside a deployment](#connecting-from-outside-a-deployment). + ### `WORKFLOW_VERCEL_ENV` -The Vercel environment to use. Options: `production`, `preview`, `development`. Automatically detected. +The Vercel environment to use. Options: `production`, `preview`, or a custom environment's slug. Default: `production`. See [Environment variables](#environment-variables) for how a custom environment is resolved. ### `WORKFLOW_VERCEL_AUTH_TOKEN` @@ -134,6 +267,8 @@ Because it routes each run's flow invocations through a dedicated `maxConcurrenc ### Programmatic configuration +`createVercelWorld()` accepts explicit API configuration. It does not read `WORKFLOW_VERCEL_*` automatically, so pass the environment values yourself. `projectId` and `teamId` are IDs, not slugs. To install the result as the World your app uses, see [Wiring it up in a script](#wiring-it-up-in-a-script). + {/*@skip-typecheck: incomplete code sample*/} ```typescript title="workflow.config.ts" lineNumbers @@ -141,10 +276,9 @@ import { createVercelWorld } from "@workflow/world-vercel"; const world = createVercelWorld({ token: process.env.WORKFLOW_VERCEL_AUTH_TOKEN, - baseUrl: "https://api.vercel.com/v1/workflow", projectConfig: { - projectId: "my-project", - teamId: "my-team", + projectId: "prj_...", + teamId: "team_...", environment: "production", }, }); @@ -197,6 +331,6 @@ The Vercel World uses Vercel's infrastructure for workflow execution: - **Storage** - Workflow data is stored in Vercel's cloud with automatic replication and [end-to-end encryption](/docs/how-it-works/encryption) - **Queuing** - Steps are distributed across serverless functions via [Vercel Queues](https://vercel.com/docs/queues) with automatic retries and [consumer function security](#consumer-function-security) -- **Authentication** - OIDC tokens provide secure, automatic authentication +- **Authentication** - OIDC tokens provide secure, automatic authentication inside deployments; clients outside one authenticate with a [Vercel auth token](#connecting-from-outside-a-deployment) For more details, see the [Vercel Workflow documentation](https://vercel.com/docs/workflows). diff --git a/docs/content/worlds/v5/vercel.mdx b/docs/content/worlds/v5/vercel.mdx index ac96611222..3056106f42 100644 --- a/docs/content/worlds/v5/vercel.mdx +++ b/docs/content/worlds/v5/vercel.mdx @@ -28,7 +28,7 @@ That's it. Vercel automatically: - Selects the Vercel World backend - Configures authentication using OIDC tokens - Provisions storage and queuing infrastructure -- Isolates data per environment (production, preview, development) +- Isolates data per environment (production, preview, and any custom environments) @@ -128,6 +128,139 @@ npx workflow inspect runs \ Learn more in the [Observability](/docs/observability) documentation. +## Connecting from outside a deployment + +Inside a Vercel deployment there is nothing to authenticate: the platform injects a per-request OIDC token and the Vercel World uses it automatically. A process that is *not* a deployment has no such token — a script on your laptop, a CI job driving end-to-end tests against a preview, a one-off backfill. Those clients authenticate with a **Vercel auth token** instead. Vercel checks that token against your team and project permissions, and attributes the request to the environment you name. + + + Do not reuse the `VERCEL_OIDC_TOKEN` that `vercel env pull` writes into + `.env.local` as your Workflow credential. It is a local artifact of your + linked project, not a credential for the Workflow API: requests made with it + are attributed to the environment carried in the token itself, not to the + `production` or `preview` data you mean to reach. Authenticate with a Vercel + auth token instead. A pulled OIDC token is still the right thing for + [bypassing deployment + protection](https://vercel.com/docs/deployment-protection/methods-to-bypass-deployment-protection/trusted-sources) + when your script has to fetch a protected preview URL; that is a separate + credential from the one that talks to the Workflow API. + + +### Environment variables + +These four values are what an external client needs. The names are the convention shared by the `workflow` CLI, the web UI, and Workflow's own CI: + +| Variable | Value | Notes | +| --- | --- | --- | +| `WORKFLOW_VERCEL_AUTH_TOKEN` | Vercel auth token | Keep it secret. Create one under [account settings → tokens](https://vercel.com/account/tokens), scoped to the team that owns the project. | +| `WORKFLOW_VERCEL_TEAM` | Vercel team ID (`team_...`) | Required. Set it together with the token and the project ID. | +| `WORKFLOW_VERCEL_PROJECT` | Vercel project ID (`prj_...`) | Required. Set it together with the token and the team ID. | +| `WORKFLOW_VERCEL_ENV` | `production`, `preview`, or a custom environment's slug | Defaults to `production`. See [`WORKFLOW_VERCEL_ENV`](#workflow_vercel_env). | + +Both IDs are in `.vercel/project.json` after `vercel link` — `projectId` is the project, `orgId` the team or user that owns it — or on the project's settings page. + +Three more are situational: + +- `VERCEL_DEPLOYMENT_ID` — required to **start** runs, not to read them. See [Starting runs](#starting-runs-from-outside-a-deployment). +- `WORKFLOW_VERCEL_PROJECT_NAME` — the project slug, used only to build dashboard links. +- `VERCEL_TOKEN` — a fallback the World reads for the Vercel API calls it makes alongside your Workflow requests (fetching a run's encryption key, resolving `deploymentId: "latest"`). A client that passes `token` explicitly, as below, already covers those calls and does not need it. + +For a custom environment, set `WORKFLOW_VERCEL_ENV` to the environment's **slug**, not its ID — the slug is what the consuming deployment compares against. + + + The Workflow SDK does not read `WORKFLOW_VERCEL_*` from the environment on + your behalf — the runtime's own `createWorld()` deliberately ignores them, so + that a stray variable on a deployed project cannot redirect a live + application. Read them in your own code and pass them to the World factory, + as below. Setting them on a deployed Vercel project has no effect on runtime + configuration, and the runtime warns when it sees them there. + + +### Wiring it up in a script + +Build the Vercel World with an explicit config and install it with [`setWorld()`](/docs/api-reference/workflow-runtime/set-world) before the first `workflow/api` call: + +{/*@skip-typecheck: incomplete code sample*/} + +```typescript title="scripts/start-run.ts" lineNumbers +import { start } from "workflow/api"; +import { setWorld } from "workflow/runtime"; +import { createWorld } from "@workflow/world-vercel"; +import { myWorkflow } from "../workflows/my-workflow"; + +setWorld( + createWorld({ + token: process.env.WORKFLOW_VERCEL_AUTH_TOKEN, // [!code highlight] + projectConfig: { + projectId: process.env.WORKFLOW_VERCEL_PROJECT, // [!code highlight] + teamId: process.env.WORKFLOW_VERCEL_TEAM, // [!code highlight] + environment: process.env.WORKFLOW_VERCEL_ENV, // [!code highlight] + }, + }) +); + +const run = await start(myWorkflow, ["input"]); +console.log(run.runId); +``` + +Supply `token`, `projectId`, and `teamId` together. Setting the two IDs without a token fails immediately, with a message naming the missing token, rather than surfacing later as an opaque `401`. + +The same token authorizes the per-run key fetch that decrypts run and step data, so reads come back as values rather than opaque bytes — see [Encryption](/docs/how-it-works/encryption). + +This is exactly what the `workflow` CLI does under the hood. It resolves the same four values — from `--authToken` / `--project` / `--team` / `--env`, then the `WORKFLOW_VERCEL_*` variables, then `.vercel/project.json` and your `vercel login` credentials — and constructs the World with them. Passing them explicitly is the non-interactive equivalent of being logged in and linked. + +### Starting runs from outside a deployment + +[`start()`](/docs/api-reference/workflow-api/start) has to name a deployment, because a run executes the code of the deployment that created it. Inside a deployment that is the current one; outside, there is nothing to infer, so set `VERCEL_DEPLOYMENT_ID` to the deployment whose code should run the workflow: + +```bash +# `vercel inspect` prints the dpl_... ID for a deployment URL +vercel inspect https://my-app-abc123.vercel.app +``` + +Reads such as [`getRun()`](/docs/api-reference/workflow-api/get-run) do not need it. `start(..., { deploymentId: "latest" })` does: it resolves the newest deployment sharing that deployment's environment, so it needs one to start from. + + + The environment you authenticate as and the deployment you target must + agree. A client that creates a run in `preview` but points it at a + production deployment creates a run that never executes: environments are + isolated from each other, so a deployment refuses work created in a + different one. If a run stays `pending` and the deployment logs a refusal + naming two environments, check `WORKFLOW_VERCEL_ENV` against the environment + of the deployment in `VERCEL_DEPLOYMENT_ID`. + + +### In CI + +Wait for the deployment under test, then hand its ID to the test step alongside the four auth variables. This is how Workflow's own end-to-end suite authenticates against its preview and production deployments: + +```yaml title=".github/workflows/e2e.yml" lineNumbers +jobs: + e2e: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Wait for the Vercel deployment + id: deployment + uses: vercel/wait-for-deployment-action@0e2b0c5c5cce31f1648108aeec56467187aca037 + with: + project-slug: my-app + environment: ${{ github.ref == 'refs/heads/main' && 'production' || 'preview' }} + + - name: Run end-to-end tests + run: pnpm test:e2e + env: + WORKFLOW_VERCEL_AUTH_TOKEN: ${{ secrets.VERCEL_TOKEN }} + WORKFLOW_VERCEL_TEAM: team_xxxxxxxxxxxxxxxx + WORKFLOW_VERCEL_PROJECT: prj_xxxxxxxxxxxxxxxx + WORKFLOW_VERCEL_ENV: ${{ github.ref == 'refs/heads/main' && 'production' || 'preview' }} + VERCEL_DEPLOYMENT_ID: ${{ steps.deployment.outputs.deployment-id }} +``` + +Store the token as an encrypted secret and derive `WORKFLOW_VERCEL_ENV` from the branch, so a pull request run never authenticates as `production`. + +If the deployment is behind deployment protection, the job also needs a way to reach its URL. Grant the workflow `id-token: write` and mint a short-lived OIDC token from the runner for the `x-vercel-trusted-oidc-idp-token` header; that credential is for [Trusted Sources](https://vercel.com/docs/deployment-protection/methods-to-bypass-deployment-protection/trusted-sources) only and is separate from the Vercel auth token above. + ## Testing & Compatibility @@ -142,9 +275,11 @@ Most users never need to set the `WORKFLOW_VERCEL_*` variables below. They are o For example, you might set them when running `workflow inspect runs --backend vercel` from CI without an interactive `vercel login`, or when running tests against a specific preview deployment. In normal local development, the CLI infers these values from your `.vercel` directory and Vercel CLI login. In a deployed Vercel function, these variables have no effect on runtime configuration, and the runtime warns if they are set there. +For the task-oriented version of this — which variables a local script or CI job needs, and how to hand them to the SDK — see [Connecting from outside a deployment](#connecting-from-outside-a-deployment). + ### `WORKFLOW_VERCEL_ENV` -The Vercel environment to target. Options: `production`, `preview`. Default: `production`. +The Vercel environment to target. Options: `production`, `preview`, or a custom environment's slug. Default: `production`. See [Environment variables](#environment-variables) for how a custom environment is resolved. ### `WORKFLOW_VERCEL_AUTH_TOKEN` @@ -216,7 +351,7 @@ The WebSocket handshake is itself a span, `workflow.events.ws.connect`, so the c ### Programmatic configuration -`createWorld()` accepts explicit API configuration. It does not read `WORKFLOW_VERCEL_*` automatically, so pass the environment values yourself when you want a configured World module: +`createWorld()` accepts explicit API configuration. It does not read `WORKFLOW_VERCEL_*` automatically, so pass the environment values yourself when you want a configured World module. To configure a client at the point of use instead of through `WORKFLOW_TARGET_WORLD`, see [Wiring it up in a script](#wiring-it-up-in-a-script). {/*@skip-typecheck: incomplete code sample*/} @@ -284,6 +419,6 @@ The Vercel World uses Vercel's infrastructure for workflow execution: - **Storage** - Workflow data is stored in Vercel's cloud with automatic replication and [end-to-end encryption](/docs/how-it-works/encryption) - **Queuing** - Steps are distributed across serverless functions via [Vercel Queues](https://vercel.com/docs/queues) with automatic retries and [consumer function security](#consumer-function-security) -- **Authentication** - OIDC tokens provide secure, automatic authentication +- **Authentication** - OIDC tokens provide secure, automatic authentication inside deployments; clients outside one authenticate with a [Vercel auth token](#connecting-from-outside-a-deployment) For more details, see the [Vercel Workflow documentation](https://vercel.com/docs/workflows).