@codefusion-cc/previews
v0.1.2
Published
A Worker Preview per pull request with its own D1 database: names from the branch, the database created and deleted with it, and the Wrangler configs that point the Preview at it, from CI
Downloads
822
Maintainers
Readme
@codefusion-cc/previews
A Worker Preview for every pull request, with a D1
database only that branch uses. The Preview is named after the branch (feat/login → feat-login), served at
https://feat-login.<your domain>, keeps its data across pushes to the branch, and is deleted with its database
when the pull request closes. Durable Objects need nothing from this package: Cloudflare gives each Preview its own
namespace and storage. An app whose Previews share its other resources, with no database of their own, uses it
without one (below).
Names
A branch of one word or <word>/<kebab-case words> in lowercase, up to 63 characters and not ending in - and 8 hex
digits (fix/login-redirect, staging), is named as it reads, with - for /. Any other branch could read like
another one (feat/a_b and feat/a-b, Feat/Login and feat/login, two long names alike in their first 63
characters), so its name is cut to 54 characters and ends in 8 hex digits of the whole branch: feat/a_b →
feat-a-b-0f5815d8. A database name that would pass D1's 63 characters is marked the same way. So two branches never
share a Preview or a database, and closing one never deletes another's; a branch gets the same name on every push.
Before 0.1.1 every branch was named as it reads and a long database name was cut: a branch in the conventional form
keeps its Preview, and its database unless <prefix>-<name> is past 63 characters; any other branch gets new ones on
its next push. What it no longer uses stays until deleted by hand (the old name may be another branch's too).
npm install -D @codefusion-cc/previewsThe Wrangler config
The previews block names the placeholder database ID 00000000-0000-0000-0000-000000000000; each branch gets its
own in its place. Anything else that differs per branch, such as the Preview's own origin, gets a placeholder too.
{
"name": "myapp",
"account_id": "…",
"routes": [{ "pattern": "myapp.example.com", "custom_domain": true, "previews_enabled": true }],
"previews": {
"vars": { "APP_ORIGIN": "https://preview-origin.invalid" },
"d1_databases": [
{ "binding": "DB", "database_name": "myapp-previews", "database_id": "00000000-0000-0000-0000-000000000000", "migrations_dir": "migrations" }
]
}
}Git ignores the two generated files, wrangler.preview.generated.jsonc and wrangler.preview-db.generated.jsonc.
In CI
# Pull requests from this repository only: forks get no Cloudflare token.
preview:
if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository
concurrency: { group: 'preview-${{ github.head_ref }}', cancel-in-progress: true }
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
HEAD_REF: ${{ github.head_ref }}
steps:
# …checkout, install, build
- id: branch
run: >-
npx codefusion-previews up "$HEAD_REF" --database-prefix myapp-preview
--set 'https://preview-origin.invalid=https://{name}.myapp.example.com' >> "$GITHUB_OUTPUT"
- run: npx wrangler d1 migrations apply DB --remote -c wrangler.preview-db.generated.jsonc
- id: upload
run: |
npx wrangler preview -c wrangler.preview.generated.jsonc --name "${{ steps.branch.outputs.name }}"
npx codefusion-previews url "$HEAD_REF" --domain myapp.example.com >> "$GITHUB_OUTPUT"And when the pull request closes:
on: { pull_request: { types: [closed] } }
# …
- run: npx codefusion-previews down "$HEAD_REF" --database-prefix myapp-preview| Command | Does | Prints |
| --- | --- | --- |
| up <branch> | Creates the branch database unless it exists, writes both configs next to --config | name=, database= |
| url <branch> | Asks Cloudflare for the Preview's address, else builds it from --domain | url= |
| down <branch> | Deletes the Preview and the branch database, where they exist | name=, database= |
Options: --config (default wrangler.jsonc), --database-prefix (for up and down when the config names the
placeholder database; keeps the app's branch databases apart from its others), --set <placeholder>=<template> (repeatable; {name}, {database_id} and
{database_name} stand for this Preview's), --domain, --binding (default DB) and --migrations-dir (default
migrations) for the database config. The account and Worker come from the config's top-level account_id and
name. CLOUDFLARE_API_TOKEN needs Workers Scripts and D1 edit.
A placeholder the config no longer contains stops up with an error, before it makes a database, rather than
deploying a Preview pointed at the wrong resource. A branch with no letters or digits cannot name a Preview and is refused before any call.
Without a database
An app whose previews block names no placeholder database leaves out --database-prefix: up makes no database,
fills in only {name} in its --set templates, writes wrangler.preview.generated.jsonc alone and prints name=;
down deletes the Preview alone. A config that names the placeholder database still needs the prefix for both, so a
cleanup that forgot it never leaves the branches' databases behind, and a {database_id} or {database_name}
template without one is refused.
- id: branch
run: npx codefusion-previews up "$HEAD_REF" --set 'https://preview-origin.invalid=https://{name}.myapp.example.com' >> "$GITHUB_OUTPUT"
- run: npx wrangler preview -c wrangler.preview.generated.jsonc --name "${{ steps.branch.outputs.name }}"In code
The same steps for other tools: previewName, databaseName, substitute, configValue, previewsApi (the
Cloudflare calls, given a token, account, Worker and optionally fetch), openPreview, previewUrl and
closePreview. A failed Cloudflare call throws a CloudflareError naming the method, path and status, never the
token; a 404 means there is nothing there.
