Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
147 changes: 147 additions & 0 deletions packages/alchemy/src/Cloudflare/Workers/Worker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,73 @@ export interface WorkerRouteConfig {
zone?: ZoneReference;
}

/**
* Versioning configuration for a Worker deploy — controls Worker
* [versions and gradual deployments](https://developers.cloudflare.com/workers/configuration/versions-and-deployments/).
*
* Two modes, selected by {@link parent}:
*
* - **Version worker** (`parent` set): instead of creating its own script,
* this Worker uploads an immutable *version* to the referenced parent
* Worker's script. With `traffic: 0` (the default) the parent's live
* deployment is untouched and the version is reachable only at its
* preview URL (`<version-prefix>-<name>.<subdomain>.workers.dev`) —
* the PR-preview use case. With `traffic > 0` the version becomes a
* canary taking that percentage of the parent's traffic.
* - **Gradual rollout** (`parent` omitted): when this Worker deploys
* itself, the newly uploaded version receives {@link traffic} percent
* and the currently-live version keeps the remainder, instead of the
* default 100% cutover.
*/
export interface WorkerVersionOptions {
/**
* The Worker that owns the script this version is uploaded to. Accepts a
* Worker reference — typically `yield* Cloudflare.Worker.ref(id, { stage,
* stack })` for a Worker deployed in another stage/stack, or a
* locally-declared Worker — or a literal script name as an escape hatch.
*
* When set, this resource does not create a script of its own: it
* uploads a version (code + bindings + compatibility settings) to the
* parent's script. Script-level settings apply immediately to *all*
* versions of the parent, so they cannot be set on a version worker —
* `name`, `assets`, `namespace`, `crons`, `domain`, `routes`, `tags`,
* `logpush`, `observability`, `placement`, `limits`, and `subdomain` are
* rejected, as are locally-hosted Durable Object or Workflow classes
* (their migrations would mutate the parent).
*
* Changing the parent replaces the resource (a version belongs to
* exactly one script).
*/
parent?: string | Worker;
/**
* Percentage of traffic (0–100) the newly uploaded version receives; the
* currently-live version keeps the remainder. Cloudflare deployments
* split between at most two versions, so one canary can be active per
* script at a time.
*
* With {@link parent} set, defaults to `0`: the version is
* preview-URL-only and the parent's live deployment is untouched.
* Without `parent`, defaults to `100` (today's full cutover); `0` means
* "upload the version without deploying it" (the equivalent of
* `wrangler versions upload`).
*
* Note that a subsequent full deploy of the parent (or of this Worker
* itself, at the default 100) resets traffic to 100% of its own new
* version.
*/
traffic?: number;
/**
* Human-readable annotation attached to the uploaded version, shown in
* the Cloudflare dashboard and `wrangler versions list`.
*/
message?: string;
/**
* Machine-readable tag annotation attached to the uploaded version
* (e.g. a git commit SHA or PR number).
*/
tag?: string;
}

export interface WorkerProps<
Bindings extends WorkerBindingProps = any,
Assets extends WorkerAssetsConfig | undefined =
Expand Down Expand Up @@ -349,6 +416,14 @@ export interface WorkerProps<
* @see https://developers.cloudflare.com/cloudflare-for-platforms/workers-for-platforms/
*/
namespace?: string | DispatchNamespace;
/**
* Worker versions & gradual deployments. Set `version.parent` to upload
* this Worker as a preview/canary *version* of another Worker's script
* instead of creating its own; set `version.traffic` below 100 to
* gradually roll out a deploy of this Worker's own script. See
* {@link WorkerVersionOptions}.
*/
version?: WorkerVersionOptions;
/**
* Whether to enable a workers.dev URL for this worker
* @default true
Expand Down Expand Up @@ -653,6 +728,28 @@ export type Worker<Bindings extends WorkerBindings = any> = Resource<
domains: string[];
routes: { id: string; pattern: string; zoneId: string }[];
crons: string[];
/**
* The parent script name this Worker uploads versions to, when this
* resource is a version worker (`version.parent` set). `undefined` for
* a Worker that owns its own script — including one deploying with a
* gradual rollout. This is the discriminator `read`/`delete` use to
* avoid treating the parent's script as this resource's own.
*/
versionOf?: string | undefined;
/**
* The id of the version uploaded by the most recent deploy. Only set
* when versioning is in play: always for a version worker
* (`version.parent`), and for a self-owned Worker when a gradual
* rollout (`version.traffic` < 100) deployed via the versions API.
*/
versionId?: string | undefined;
/**
* The id of the deployment created by the most recent deploy, when the
* deploy created one through the deployments API (a version with
* `traffic > 0`). Preview-only versions (`traffic: 0`) have no
* deployment.
*/
deploymentId?: string | undefined;
hash?: {
assets: string | undefined;
bundle: string | undefined;
Expand Down Expand Up @@ -947,6 +1044,56 @@ export type Worker<Bindings extends WorkerBindings = any> = Resource<
* }
* ```
*
* @section Versions & Gradual Deployments
* The `version` prop maps Cloudflare's
* [versions and gradual deployments](https://developers.cloudflare.com/workers/configuration/versions-and-deployments/)
* onto Alchemy stages. A Worker with `version.parent` set uploads an
* immutable *version* to the parent Worker's script instead of creating its
* own — by default with no traffic, reachable only at its preview URL
* (`worker.url`), which is the PR-preview workflow. Give it `traffic` to
* run it as a canary, or use `version.traffic` on a normal Worker to roll
* out its own deploys gradually.
*
* A version carries code, bindings, and compatibility settings. Script-level
* settings (routes, domains, crons, tags, observability, …) belong to the
* parent and are rejected on version workers, as are locally-hosted Durable
* Object or Workflow classes. Preview URLs require the parent's workers.dev
* subdomain to be enabled (the default).
*
* @example PR preview: a version of another stage's Worker
* ```typescript
* // The staging stage deploys the real Worker; a PR stage uploads its
* // code as a zero-traffic version of staging's script and gets back a
* // preview URL.
* const parent = yield* Cloudflare.Worker.ref("MyWorker", {
* stage: "staging",
* });
* const preview = yield* Cloudflare.Worker("MyWorker", {
* main: "./src/worker.ts",
* version: { parent, message: `PR #${process.env.PR_NUMBER}` },
* });
* // preview.url -> https://<version-prefix>-<name>.<subdomain>.workers.dev
* ```
*
* @example Canary: send 10% of the parent's traffic to a version
* ```typescript
* const parent = yield* Cloudflare.Worker.ref("MyWorker", { stage: "prod" });
* yield* Cloudflare.Worker("MyWorker", {
* main: "./src/worker.ts",
* version: { parent, traffic: 10 },
* });
* ```
*
* @example Gradual rollout of a Worker's own deploy
* ```typescript
* // The new version takes 25% of traffic; the previously-live version
* // keeps 75%. Bump traffic (or remove the prop) and re-deploy to promote.
* yield* Cloudflare.Worker("MyWorker", {
* main: "./src/worker.ts",
* version: { traffic: 25 },
* });
* ```
*
* @section Observability
* Cloudflare Workers Observability is on by default — `logs.enabled` and
* `logs.invocationLogs` are turned on if you don't pass an `observability`
Expand Down
Loading
Loading