supabase-worker-previews 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -37,18 +37,18 @@ flowchart LR
37
37
  preview -- "previews.vars" --> shareddb[("Shared Preview database<br/>persistent branch 'preview'")]
38
38
  pr["PR changes supabase/<br/>or has label isolated-db"] --> integ["Supabase GitHub integration"]
39
39
  integ --> prdb[("The PR's own database")]
40
- pr --> action["GitHub Actions: swp pr"]
40
+ pr --> action["GitHub Actions: pr command"]
41
41
  action -- "SUPABASE_OVERRIDE secret" --> preview
42
42
  preview -. "PRs with their own database" .-> prdb
43
- action -- "swp check reads<br/>/.well-known/supabase-preview" --> preview
43
+ action -- "check reads<br/>/.well-known/supabase-preview" --> preview
44
44
  ```
45
45
 
46
- `swp` adds no infrastructure. Cloudflare builds the Previews and Supabase makes and migrates the databases. `swp` connects the two:
46
+ It adds no infrastructure. Cloudflare builds the Previews and Supabase makes and migrates the databases; this package connects the two:
47
47
 
48
48
  1. **Every Preview starts on the shared Preview database**, a persistent Supabase branch that tracks your trunk. Its public URL and key live in your wrangler config's `previews.vars`.
49
- 2. **A PR that changes the schema gets its own database.** The Supabase GitHub integration creates it; `swp pr` points the PR's Preview at it with one secret, `SUPABASE_OVERRIDE`.
49
+ 2. **A PR that changes the schema gets its own database.** The Supabase GitHub integration creates it; the `pr` command points the PR's Preview at it with one secret, `SUPABASE_OVERRIDE`.
50
50
  3. **The Worker reads its Supabase settings per request.** `withSupabasePreviews()` applies the override and injects the public config into each HTML page, so no build-time `VITE_SUPABASE_URL` pins a database into the bundle.
51
- 4. **`swp check` asks the Preview which database it serves** and fails the PR unless it is the right one.
51
+ 4. **`check` asks the Preview which database it serves** and fails the PR unless it is the right one.
52
52
 
53
53
  New to Worker Previews or Supabase branching? [Concepts](docs/concepts.md) explains both in five minutes.
54
54
 
@@ -58,14 +58,14 @@ You need a Worker deployed by Workers Builds from a GitHub repo, wrangler 4.135.
58
58
 
59
59
  ```bash
60
60
  npm install --save-dev supabase-worker-previews
61
- npx swp init --project-ref <production project ref>
61
+ npx supabase-worker-previews init --project-ref <production project ref>
62
62
  ```
63
63
 
64
- `init` writes `swp.config.json`, a grants migration and the PR workflow, and prints the rest. Then:
64
+ `init` writes `supabase-worker-previews.json`, a grants migration and the PR workflow, and prints the rest. Then:
65
65
 
66
66
  1. Connect the Supabase GitHub integration (automatic branching on, deploy to production off).
67
67
  2. Add a `previews` block to your wrangler config.
68
- 3. `npx swp shared` creates the shared Preview database and prints its `previews.vars`.
68
+ 3. `npx supabase-worker-previews shared` creates the shared Preview database and prints its `previews.vars`.
69
69
  4. Wrap the Worker:
70
70
 
71
71
  ```ts
@@ -77,47 +77,49 @@ npx swp init --project-ref <production project ref>
77
77
 
78
78
  and create the browser client from `readPublicConfig()`.
79
79
 
80
- 5. Turn on Preview builds in Workers Builds, add three Actions secrets, run `npx swp doctor`, and open a PR.
80
+ 5. Turn on Preview builds in Workers Builds, add three Actions secrets, run `npx supabase-worker-previews doctor`, and open a PR.
81
81
 
82
82
  The **[full quickstart](docs/quickstart.md)** walks through every step with the dashboard settings and the output to expect. For a complete working project, see [`examples/hono-notes`](examples/hono-notes).
83
83
 
84
84
  ## Commands
85
85
 
86
- | Group | Command | Does |
87
- | -------------- | ------------ | ------------------------------------------------------------------------------------ |
88
- | **Set up** | `swp init` | Scaffold `swp.config.json`, the grants migration and the workflow (never overwrites) |
89
- | | `swp doctor` | Check the whole setup, offline and (with a token) against Supabase |
90
- | | `swp shared` | Create or repair the shared Preview database; prints its `previews.vars` |
91
- | **Per branch** | `swp up` | Give a branch's Preview its own database |
92
- | | `swp check` | Fail unless the Preview serves the right database |
93
- | | `swp down` | Delete a branch's Preview and its own database |
94
- | **In CI** | `swp pr` | All of the above for a `pull_request` workflow, plus the PR comment and deployment |
95
- | | `swp prune` | List leftovers of deleted branches and closed PRs; delete them with `--yes` |
86
+ Run each one as `npx supabase-worker-previews <command>`, or from an npm script.
96
87
 
97
- `swp <command> --help` shows one command's flags and examples, and `swp --version` prints the version. Flags, environment variables, every `swp.config.json` field and the GitHub Action inputs are in the [configuration reference](docs/configuration.md).
88
+ | Group | Command | Does |
89
+ | -------------- | -------- | -------------------------------------------------------------------------------------------------- |
90
+ | **Set up** | `init` | Scaffold `supabase-worker-previews.json`, the grants migration and the workflow (never overwrites) |
91
+ | | `doctor` | Check the whole setup, offline and (with a token) against Supabase |
92
+ | | `shared` | Create or repair the shared Preview database; prints its `previews.vars` |
93
+ | **Per branch** | `up` | Give a branch's Preview its own database |
94
+ | | `check` | Fail unless the Preview serves the right database |
95
+ | | `down` | Delete a branch's Preview and its own database |
96
+ | **In CI** | `pr` | All of the above for a `pull_request` workflow, plus the PR comment and deployment |
97
+ | | `prune` | List leftovers of deleted branches and closed PRs; delete them with `--yes` |
98
+
99
+ `<command> --help` shows one command's flags and examples, and `--version` prints the version. Flags, environment variables, every `supabase-worker-previews.json` field and the GitHub Action inputs are in the [configuration reference](docs/configuration.md).
98
100
 
99
101
  ## Safety
100
102
 
101
- - `swp` never writes to, repoints or deletes the production project, and never deletes a persistent branch.
102
- - `swp check` fails the first time a Preview serves production, with no retry.
103
- - `swp doctor` fails if `previews.vars` names production or holds a secret.
104
- - `swp prune` only lists until you pass `--yes`, and every command that changes something takes `--dry-run`.
103
+ - It never writes to, repoints or deletes the production project, and never deletes a persistent branch.
104
+ - `check` fails the first time a Preview serves production, with no retry.
105
+ - `doctor` fails if `previews.vars` names production or holds a secret.
106
+ - `prune` only lists until you pass `--yes`, and every command that changes something takes `--dry-run`.
105
107
 
106
- [Security](docs/security.md) covers what `swp` can touch and what each token can reach.
108
+ [Security](docs/security.md) covers what the CLI can touch and what each token can reach.
107
109
 
108
110
  ## Docs
109
111
 
110
- | Page | For |
111
- | ------------------------------------------ | ------------------------------------------------------------------ |
112
- | [Concepts](docs/concepts.md) | Worker Previews, Supabase branches, and how `swp` joins them |
113
- | [Quickstart](docs/quickstart.md) | From an existing Worker to the first working PR Preview |
114
- | [Frameworks](docs/README.md#frameworks) | TanStack Start, Hono, React Router v7, Astro |
115
- | [Troubleshooting](docs/troubleshooting.md) | Symptoms, causes and fixes |
116
- | [How it works](docs/how-it-works.md) | Every moving part and why it is built that way |
117
- | [Configuration](docs/configuration.md) | Commands, flags, `swp.config.json`, the GitHub Action, the runtime |
118
- | [Tokens](docs/tokens.md) | Least-privilege Cloudflare, Supabase and GitHub credentials |
119
- | [Security](docs/security.md) | What `swp` can touch, what is public, what is secret |
120
- | [Compared with Vercel](docs/vs-vercel.md) | When Vercel and its Supabase integration are the better fit |
112
+ | Page | For |
113
+ | ------------------------------------------ | -------------------------------------------------------------------------------- |
114
+ | [Concepts](docs/concepts.md) | Worker Previews, Supabase branches, and how this package joins them |
115
+ | [Quickstart](docs/quickstart.md) | From an existing Worker to the first working PR Preview |
116
+ | [Frameworks](docs/README.md#frameworks) | TanStack Start, Hono, React Router v7, Astro |
117
+ | [Troubleshooting](docs/troubleshooting.md) | Symptoms, causes and fixes |
118
+ | [How it works](docs/how-it-works.md) | Every moving part and why it is built that way |
119
+ | [Configuration](docs/configuration.md) | Commands, flags, `supabase-worker-previews.json`, the GitHub Action, the runtime |
120
+ | [Tokens](docs/tokens.md) | Least-privilege Cloudflare, Supabase and GitHub credentials |
121
+ | [Security](docs/security.md) | What the CLI can touch, what is public, what is secret |
122
+ | [Compared with Vercel](docs/vs-vercel.md) | When Vercel and its Supabase integration are the better fit |
121
123
 
122
124
  The full index is [docs/README.md](docs/README.md).
123
125
 
package/dist/cli.js CHANGED
@@ -2,7 +2,7 @@
2
2
  import { execFileSync } from "node:child_process";
3
3
  import { existsSync } from "node:fs";
4
4
  import { CloudflareApi } from "./cloudflare.js";
5
- import { loadConfig, migrationFiles } from "./config.js";
5
+ import { CONFIG_FILE, configFileIn, DOTENV_FILE, LEGACY_CONFIG_FILE, LEGACY_DOTENV_FILE, loadConfig, migrationFiles, } from "./config.js";
6
6
  import { check, down, shared, up } from "./commands/branches.js";
7
7
  import { doctor, formatReport } from "./commands/doctor.js";
8
8
  import { init } from "./commands/init.js";
@@ -64,12 +64,14 @@ async function main(argv) {
64
64
  return 0;
65
65
  }
66
66
  if (invocation.kind === "error") {
67
- console.error(`${errStyle.red("swp:")} ${invocation.message}`);
67
+ console.error(`${errStyle.red("supabase-worker-previews:")} ${invocation.message}`);
68
68
  return 2;
69
69
  }
70
70
  const { command, flags } = invocation;
71
71
  const dryRun = flags["dry-run"] === true;
72
- const envFile = str(flags.dotenv) ?? (existsSync(".env.swp") ? ".env.swp" : undefined);
72
+ const envFile = str(flags.dotenv) ?? [DOTENV_FILE, LEGACY_DOTENV_FILE].find((f) => existsSync(f));
73
+ if (envFile === LEGACY_DOTENV_FILE)
74
+ console.error(errStyle.yellow(`Loading ${LEGACY_DOTENV_FILE}; rename it to ${DOTENV_FILE}.`));
73
75
  if (envFile) {
74
76
  if (!existsSync(envFile))
75
77
  throw new Error(`--dotenv ${envFile}: no such file`);
@@ -98,6 +100,8 @@ async function main(argv) {
98
100
  console.log(report.text);
99
101
  return report.pass ? 0 : 1;
100
102
  }
103
+ if (configFileIn() === LEGACY_CONFIG_FILE)
104
+ console.error(errStyle.yellow(`Reading ${LEGACY_CONFIG_FILE}; rename it to ${CONFIG_FILE}.`));
101
105
  const config = loadConfig(overrides);
102
106
  const prNum = prNumber(flags.pr);
103
107
  const event = command === "pr" ? readEvent() : undefined;
@@ -147,6 +151,6 @@ async function main(argv) {
147
151
  return 0;
148
152
  }
149
153
  main(process.argv.slice(2)).then((code) => process.exit(code), (err) => {
150
- console.error(`${errStyle.red("swp:")} ${formatError(err)}`);
154
+ console.error(`${errStyle.red("supabase-worker-previews:")} ${formatError(err)}`);
151
155
  process.exit(1);
152
156
  });
@@ -17,7 +17,7 @@ export type Deps = {
17
17
  export declare function branchFor(gitBranch: string, deps: Deps): Promise<Branch | undefined>;
18
18
  /** The Preview a git branch deploys to: named after the branch, or `pr-<number>` when configured. */
19
19
  export declare function previewKey(gitBranch: string, config: Config, pr?: number): string;
20
- /** A branch `swp` may delete: never production, the shared database, the trunk's or a persistent one. */
20
+ /** A branch `supabase-worker-previews` may delete: never production, the shared database, the trunk's or a persistent one. */
21
21
  export declare function isDisposable(branch: Branch, config: Config): boolean;
22
22
  /** Never repoint, write to or delete the production project through a branch record. */
23
23
  export declare function assertIsolated(branch: Branch, parent: string): void;
@@ -19,7 +19,7 @@ export function previewKey(gitBranch, config, pr) {
19
19
  throw new Error(`previewName is "pr", so pass the PR number (--pr <n>)`);
20
20
  return `pr-${pr}`;
21
21
  }
22
- /** A branch `swp` may delete: never production, the shared database, the trunk's or a persistent one. */
22
+ /** A branch `supabase-worker-previews` may delete: never production, the shared database, the trunk's or a persistent one. */
23
23
  export function isDisposable(branch, config) {
24
24
  return (!branch.is_default &&
25
25
  !branch.persistent &&
@@ -59,7 +59,7 @@ export async function shared(deps) {
59
59
  }
60
60
  if (!branches.some((b) => b.is_default))
61
61
  throw new Error(`Branching is not enabled on ${parent}. Connect the repo in the Supabase dashboard ` +
62
- "(project settings, Integrations, GitHub, automatic branching on), then run swp shared again.");
62
+ "(project settings, Integrations, GitHub, automatic branching on), then run supabase-worker-previews shared again.");
63
63
  let branch = branches.find((b) => b.name === config.sharedBranch);
64
64
  if (!branch) {
65
65
  branch = await supabase.createBranch(parent, {
@@ -1,6 +1,6 @@
1
1
  import { existsSync, readdirSync, readFileSync } from "node:fs";
2
2
  import { join } from "node:path";
3
- import { CONFIG_DEFAULTS, defined, loadConfig, migrationFiles, migrationsDir, readWranglerConfig, } from "../config.js";
3
+ import { CONFIG_DEFAULTS, CONFIG_FILE, configFileIn, defined, DOTENV_FILE, LEGACY_CONFIG_FILE, LEGACY_DOTENV_FILE, loadConfig, migrationFiles, migrationsDir, readWranglerConfig, } from "../config.js";
4
4
  import { TOKENS_URL } from "../http.js";
5
5
  import { projectRefOf } from "../runtime.js";
6
6
  import { makeStyle } from "../style.js";
@@ -37,7 +37,7 @@ export function checkLocal(config, cwd = process.cwd()) {
37
37
  const ok = (message) => out.push({ level: "ok", message });
38
38
  const warn = (message, fix) => out.push({ level: "warn", message, fix });
39
39
  const error = (message, fix) => out.push({ level: "error", message, fix });
40
- const shared = "Run `swp shared` and paste the values it prints into previews.vars.";
40
+ const shared = "Run `supabase-worker-previews shared` and paste the values it prints into previews.vars.";
41
41
  const version = installedWranglerVersion(cwd);
42
42
  if (!version)
43
43
  warn("wrangler is not installed in this project", "npm install --save-dev wrangler@latest (4.135.0 or later)");
@@ -47,11 +47,11 @@ export function checkLocal(config, cwd = process.cwd()) {
47
47
  ok(`wrangler ${version}`);
48
48
  const wrangler = readWranglerConfig(cwd);
49
49
  if (!wrangler)
50
- error("no wrangler.jsonc, wrangler.json or wrangler.toml here", "Run swp doctor in the Worker's directory.");
50
+ error("no wrangler.jsonc, wrangler.json or wrangler.toml here", "Run supabase-worker-previews doctor in the Worker's directory.");
51
51
  else {
52
52
  const previews = wrangler.json.previews;
53
53
  if (!previews)
54
- error(`${wrangler.file} has no "previews" block, so Previews get no Supabase settings`, 'Add "previews": { "vars": {} }, redeclaring every binding the Worker uses, then run `swp shared` for the vars.');
54
+ error(`${wrangler.file} has no "previews" block, so Previews get no Supabase settings`, 'Add "previews": { "vars": {} }, redeclaring every binding the Worker uses, then run `supabase-worker-previews shared` for the vars.');
55
55
  else {
56
56
  const vars = (previews.vars ?? {});
57
57
  const url = typeof vars.SUPABASE_URL === "string" ? vars.SUPABASE_URL : undefined;
@@ -63,7 +63,7 @@ export function checkLocal(config, cwd = process.cwd()) {
63
63
  ok(`previews.vars uses ${projectRefOf(url) ?? url}`);
64
64
  for (const name of SECRET_NAMES)
65
65
  if (name in vars)
66
- error(`previews.vars holds ${name}; secrets belong in the Preview base config`, `Remove ${name} from previews.vars (swp stores it as a secret), and rotate the key if it was committed.`);
66
+ error(`previews.vars holds ${name}; secrets belong in the Preview base config`, `Remove ${name} from previews.vars (supabase-worker-previews stores it as a secret), and rotate the key if it was committed.`);
67
67
  for (const key of BINDING_KEYS) {
68
68
  if (!(key in wrangler.json) || key in previews)
69
69
  continue;
@@ -81,13 +81,13 @@ export function checkLocal(config, cwd = process.cwd()) {
81
81
  }
82
82
  const migrations = migrationFiles(config, cwd);
83
83
  if (!migrations.length)
84
- warn(`no migrations in ${migrationsDir(config)}`, 'Commit your migrations there, or set "supabaseDir" in swp.config.json.');
84
+ warn(`no migrations in ${migrationsDir(config)}`, 'Commit your migrations there, or set "supabaseDir" in supabase-worker-previews.json.');
85
85
  else {
86
86
  const first = readFileSync(join(cwd, migrationsDir(config), migrations[0]), "utf8");
87
87
  if (hasDefaultPrivileges(first))
88
88
  ok(`${migrations[0]} grants the API roles default privileges`);
89
89
  else
90
- error(`the first migration (${migrations[0]}) does not grant default privileges; branch databases will 403`, "Run `swp init` to add the grants migration before it.");
90
+ error(`the first migration (${migrations[0]}) does not grant default privileges; branch databases will 403`, "Run `supabase-worker-previews init` to add the grants migration before it.");
91
91
  }
92
92
  const toml = join(cwd, config.supabaseDir, "config.toml");
93
93
  if (existsSync(toml)) {
@@ -110,7 +110,7 @@ export async function checkRemote(config, supabase, cwd = process.cwd()) {
110
110
  level: "error",
111
111
  message: `cannot read project ${parent}: ${err.message}`,
112
112
  ...(status === 404 && {
113
- fix: `Check "supabaseProjectRef" in swp.config.json, and that SUPABASE_ACCESS_TOKEN can reach that project.`,
113
+ fix: `Check "supabaseProjectRef" in supabase-worker-previews.json, and that SUPABASE_ACCESS_TOKEN can reach that project.`,
114
114
  }),
115
115
  },
116
116
  ];
@@ -142,7 +142,7 @@ export async function checkRemote(config, supabase, cwd = process.cwd()) {
142
142
  out.push({
143
143
  level: "error",
144
144
  message: `no "${config.sharedBranch}" branch, the shared Preview database`,
145
- fix: "Run `swp shared` to create it.",
145
+ fix: "Run `supabase-worker-previews shared` to create it.",
146
146
  });
147
147
  return out;
148
148
  }
@@ -150,19 +150,19 @@ export async function checkRemote(config, supabase, cwd = process.cwd()) {
150
150
  out.push({
151
151
  level: "error",
152
152
  message: `"${config.sharedBranch}" is the production project itself`,
153
- fix: 'Set "sharedBranch" in swp.config.json to another name, then run `swp shared`.',
153
+ fix: 'Set "sharedBranch" in supabase-worker-previews.json to another name, then run `supabase-worker-previews shared`.',
154
154
  });
155
155
  if (!shared.persistent)
156
156
  out.push({
157
157
  level: "warn",
158
158
  message: `"${config.sharedBranch}" is not persistent`,
159
- fix: "Run `swp shared` to make it persistent.",
159
+ fix: "Run `supabase-worker-previews shared` to make it persistent.",
160
160
  });
161
161
  if (shared.git_branch !== config.trunk)
162
162
  out.push({
163
163
  level: "error",
164
164
  message: `"${config.sharedBranch}" tracks ${shared.git_branch ?? "no git branch"}, not ${config.trunk}`,
165
- fix: `Run \`swp shared\` to point it at ${config.trunk}.`,
165
+ fix: `Run \`supabase-worker-previews shared\` to point it at ${config.trunk}.`,
166
166
  });
167
167
  const vars = readWranglerConfig(cwd)?.json.previews
168
168
  ?.vars;
@@ -171,7 +171,7 @@ export async function checkRemote(config, supabase, cwd = process.cwd()) {
171
171
  out.push({
172
172
  level: "error",
173
173
  message: `previews.vars uses ${varsRef}, but "${config.sharedBranch}" is ${shared.project_ref}`,
174
- fix: "Run `swp shared` and paste the values it prints into previews.vars.",
174
+ fix: "Run `supabase-worker-previews shared` and paste the values it prints into previews.vars.",
175
175
  });
176
176
  else if (varsRef)
177
177
  out.push({
@@ -230,6 +230,18 @@ export async function doctor(overrides, supabase, cwd = process.cwd()) {
230
230
  const local = { title: "Local files", findings: [] };
231
231
  const online = { title: "Supabase (online)", findings: [] };
232
232
  let config;
233
+ if (configFileIn(cwd) === LEGACY_CONFIG_FILE)
234
+ local.findings.push({
235
+ level: "warn",
236
+ message: `${LEGACY_CONFIG_FILE} is the name from before 0.2.0`,
237
+ fix: `Rename it to ${CONFIG_FILE}; the old name is still read for now.`,
238
+ });
239
+ if (existsSync(join(cwd, LEGACY_DOTENV_FILE)) && !existsSync(join(cwd, DOTENV_FILE)))
240
+ local.findings.push({
241
+ level: "warn",
242
+ message: `${LEGACY_DOTENV_FILE} is the name from before 0.2.0`,
243
+ fix: `Rename it to ${DOTENV_FILE}, and update .gitignore; the old name is still loaded for now.`,
244
+ });
233
245
  try {
234
246
  config = loadConfig(overrides, cwd);
235
247
  }
@@ -246,7 +258,7 @@ export async function doctor(overrides, supabase, cwd = process.cwd()) {
246
258
  online.skipped = "skipped until the config above is fixed";
247
259
  else if (!supabase)
248
260
  online.skipped =
249
- "skipped: SUPABASE_ACCESS_TOKEN is not set. Add it to .env.swp to also check branching, " +
261
+ "skipped: SUPABASE_ACCESS_TOKEN is not set. Add it to .env.supabase-worker-previews to also check branching, " +
250
262
  `the shared database and the GitHub integration (${TOKENS_URL}).`;
251
263
  else {
252
264
  online.title = `Supabase (online, project ${config.supabaseProjectRef})`;
@@ -281,7 +293,7 @@ export function formatReport(sections, s = makeStyle(false)) {
281
293
  const plural = (n, word) => `${n} ${word}${n === 1 ? "" : "s"}`;
282
294
  const skipped = sections.some((section) => section.skipped) ? " (online checks skipped)" : "";
283
295
  lines.push("", errors
284
- ? s.red(`${plural(errors, "error")}, ${plural(warnings, "warning")}${skipped}. Fix the errors and run swp doctor again.`)
296
+ ? s.red(`${plural(errors, "error")}, ${plural(warnings, "warning")}${skipped}. Fix the errors and run supabase-worker-previews doctor again.`)
285
297
  : warnings
286
298
  ? s.yellow(`No errors, ${plural(warnings, "warning")}${skipped}.`)
287
299
  : s.green(`All checks passed${skipped}.`));
@@ -1,8 +1,8 @@
1
1
  import { execFileSync } from "node:child_process";
2
2
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
3
- import { dirname, join } from "node:path";
3
+ import { basename, dirname, join } from "node:path";
4
4
  import { fileURLToPath } from "node:url";
5
- import { CONFIG_FILE, migrationFiles, migrationsDir, PLACEHOLDER_REF, readWranglerConfig, WRANGLER_FILES, } from "../config.js";
5
+ import { CONFIG_FILE, configFileIn, migrationFiles, migrationsDir, PLACEHOLDER_REF, readWranglerConfig, WRANGLER_FILES, } from "../config.js";
6
6
  import { QUICKSTART_URL, TOKENS_URL } from "../http.js";
7
7
  import { hasDefaultPrivileges } from "./doctor.js";
8
8
  const TEMPLATES = join(dirname(fileURLToPath(import.meta.url)), "..", "..", "templates");
@@ -49,9 +49,9 @@ export function init(options = {}, cwd = process.cwd()) {
49
49
  const log = options.log ?? console.log;
50
50
  const wrangler = readWranglerConfig(cwd);
51
51
  if (!wrangler)
52
- throw new Error(`No ${WRANGLER_FILES.join(", ")} in this directory. Run swp init in the Worker's directory.`);
52
+ throw new Error(`No ${WRANGLER_FILES.join(", ")} in this directory. Run supabase-worker-previews init in the Worker's directory.`);
53
53
  if (!wrangler.name)
54
- throw new Error(`${wrangler.file} has no "name". Add the Worker's name, then run swp init again.`);
54
+ throw new Error(`${wrangler.file} has no "name". Add the Worker's name, then run supabase-worker-previews init again.`);
55
55
  const write = (path, content) => {
56
56
  if (options.dryRun)
57
57
  return;
@@ -60,11 +60,11 @@ export function init(options = {}, cwd = process.cwd()) {
60
60
  };
61
61
  if (options.dryRun)
62
62
  log("Dry run: nothing is written.\n");
63
- const configPath = join(cwd, CONFIG_FILE);
63
+ const configPath = join(cwd, configFileIn(cwd));
64
64
  let needsRef;
65
65
  if (existsSync(configPath)) {
66
66
  needsRef = !hasProjectRef(readFileSync(configPath, "utf8"));
67
- log(`- ${CONFIG_FILE} exists, left alone`);
67
+ log(`- ${basename(configPath)} exists, left alone`);
68
68
  }
69
69
  else {
70
70
  const linked = linkedProjectRef(cwd);
@@ -104,7 +104,7 @@ export function init(options = {}, cwd = process.cwd()) {
104
104
  log(`+ ${WORKFLOW}`);
105
105
  log(options.action
106
106
  ? " It uses the published action, mattruby/supabase-worker-previews@v0."
107
- : " It runs the installed swp (npx swp pr); `swp init --action` writes one that uses the published action.");
107
+ : " It runs `npx supabase-worker-previews pr`; `npx supabase-worker-previews init --action` writes one that uses the published action instead.");
108
108
  }
109
109
  const steps = [
110
110
  ...(needsRef
@@ -117,15 +117,15 @@ export function init(options = {}, cwd = process.cwd()) {
117
117
  ...(wrangler.json.previews
118
118
  ? []
119
119
  : [`Add a "previews" block to ${wrangler.file}, redeclaring every binding the Worker uses.`]),
120
- "Put SUPABASE_ACCESS_TOKEN, CLOUDFLARE_API_TOKEN and CLOUDFLARE_ACCOUNT_ID in .env.swp\n" +
120
+ "Put SUPABASE_ACCESS_TOKEN, CLOUDFLARE_API_TOKEN and CLOUDFLARE_ACCOUNT_ID in .env.supabase-worker-previews\n" +
121
121
  `(git-ignore it; scopes: ${TOKENS_URL}),\n` +
122
- "then run `npx swp shared` and paste the previews.vars it prints.",
122
+ "then run `npx supabase-worker-previews shared` and paste the previews.vars it prints.",
123
123
  "Wrap the Worker's default export:\n" +
124
124
  ' import { withSupabasePreviews } from "supabase-worker-previews";\n' +
125
125
  " export default withSupabasePreviews(app);",
126
126
  "Workers Builds: turn on non-production branch builds, deploy command `npx wrangler preview`.",
127
127
  "GitHub repo, Settings, Secrets and variables, Actions: add the same three tokens.",
128
- "Run `npx swp doctor` until it passes, then commit and open a PR.",
128
+ "Run `npx supabase-worker-previews doctor` until it passes, then commit and open a PR.",
129
129
  ];
130
130
  log(`\nNext, by hand (the full guide: ${QUICKSTART_URL}):`);
131
131
  steps.forEach((step, i) => log(` ${i + 1}. ${step.replace(/\n/g, "\n ")}`));
@@ -4,10 +4,10 @@ import { apiErrorMessage } from "../http.js";
4
4
  import { check, down, release, up } from "./branches.js";
5
5
  export function readEvent(path = process.env.GITHUB_EVENT_PATH) {
6
6
  if (!path)
7
- throw new Error("GITHUB_EVENT_PATH is not set: `swp pr` runs inside a pull_request workflow. To try one branch here, use `swp up` or `swp check`.");
7
+ throw new Error("GITHUB_EVENT_PATH is not set: `supabase-worker-previews pr` runs inside a pull_request workflow. To try one branch here, use `supabase-worker-previews up` or `supabase-worker-previews check`.");
8
8
  const event = JSON.parse(readFileSync(path, "utf8"));
9
9
  if (!event.pull_request)
10
- throw new Error("`swp pr` needs a pull_request event");
10
+ throw new Error("`supabase-worker-previews pr` needs a pull_request event");
11
11
  return event;
12
12
  }
13
13
  export const PR_ENV = [
@@ -25,14 +25,14 @@ export function skipReason(event, env = process.env) {
25
25
  if (head !== undefined && head?.full_name !== event.repository.full_name)
26
26
  return {
27
27
  level: "notice",
28
- message: `swp pr skipped PR #${event.number}: it comes from ${head ? `the fork ${head.full_name}` : "a deleted fork"}, and GitHub Actions gives fork PRs no secrets`,
28
+ message: `supabase-worker-previews pr skipped PR #${event.number}: it comes from ${head ? `the fork ${head.full_name}` : "a deleted fork"}, and GitHub Actions gives fork PRs no secrets`,
29
29
  };
30
30
  const missing = PR_ENV.filter((name) => !env[name]);
31
31
  if (missing.length) {
32
32
  const bot = env.GITHUB_ACTOR?.endsWith("[bot]") ?? false;
33
33
  return {
34
34
  level: bot ? "warning" : "error",
35
- message: `swp pr ${bot ? "skipped" : "cannot check"} PR #${event.number}: ${missing.join(", ")} ${missing.length === 1 ? "is" : "are"} empty; add ${missing.length === 1 ? "it" : "them"} to the repository's Actions secrets`,
35
+ message: `supabase-worker-previews pr ${bot ? "skipped" : "cannot check"} PR #${event.number}: ${missing.join(", ")} ${missing.length === 1 ? "is" : "are"} empty; add ${missing.length === 1 ? "it" : "them"} to the repository's Actions secrets`,
36
36
  };
37
37
  }
38
38
  return null;
package/dist/config.d.ts CHANGED
@@ -1,6 +1,12 @@
1
- export declare const CONFIG_FILE = "swp.config.json";
1
+ export declare const CONFIG_FILE = "supabase-worker-previews.json";
2
+ /** The name before 0.2.0, still read when the current one is absent. */
3
+ export declare const LEGACY_CONFIG_FILE = "swp.config.json";
4
+ export declare const DOTENV_FILE = ".env.supabase-worker-previews";
5
+ export declare const LEGACY_DOTENV_FILE = ".env.swp";
6
+ /** The config file to read in `cwd`: the current name, else the legacy one if only that exists. */
7
+ export declare function configFileIn(cwd?: string): string;
2
8
  export declare const WRANGLER_FILES: string[];
3
- /** What `swp init` writes when it cannot find the project ref. */
9
+ /** What `supabase-worker-previews init` writes when it cannot find the project ref. */
4
10
  export declare const PLACEHOLDER_REF = "<production project ref>";
5
11
  export type Config = {
6
12
  /** Worker name; defaults to `name` in the wrangler config. */
@@ -22,9 +28,9 @@ export type Config = {
22
28
  previewName: "branch" | "pr";
23
29
  /** Which Supabase API keys to hand a Preview when a project has both kinds. */
24
30
  apiKeys: "legacy" | "new";
25
- /** `swp pr` keeps one status comment on the PR. Default true. */
31
+ /** `supabase-worker-previews pr` keeps one status comment on the PR. Default true. */
26
32
  prComment?: boolean;
27
- /** `swp pr` records a GitHub deployment for the PR head. Default true. */
33
+ /** `supabase-worker-previews pr` records a GitHub deployment for the PR head. Default true. */
28
34
  githubDeployments?: boolean;
29
35
  /** GitHub environment of those deployments, shared by every PR; `{branch}` makes one per branch. Default "Preview". */
30
36
  deploymentEnvironment?: string;
package/dist/config.js CHANGED
@@ -1,11 +1,21 @@
1
1
  import { existsSync, readdirSync, readFileSync } from "node:fs";
2
- import { join } from "node:path";
2
+ import { basename, join } from "node:path";
3
3
  import { parse as parseToml } from "smol-toml";
4
4
  import { parseJsonc } from "./jsonc.js";
5
5
  import { didYouMean } from "./suggest.js";
6
- export const CONFIG_FILE = "swp.config.json";
6
+ export const CONFIG_FILE = "supabase-worker-previews.json";
7
+ /** The name before 0.2.0, still read when the current one is absent. */
8
+ export const LEGACY_CONFIG_FILE = "swp.config.json";
9
+ export const DOTENV_FILE = ".env.supabase-worker-previews";
10
+ export const LEGACY_DOTENV_FILE = ".env.swp";
11
+ /** The config file to read in `cwd`: the current name, else the legacy one if only that exists. */
12
+ export function configFileIn(cwd = process.cwd()) {
13
+ return !existsSync(join(cwd, CONFIG_FILE)) && existsSync(join(cwd, LEGACY_CONFIG_FILE))
14
+ ? LEGACY_CONFIG_FILE
15
+ : CONFIG_FILE;
16
+ }
7
17
  export const WRANGLER_FILES = ["wrangler.jsonc", "wrangler.json", "wrangler.toml"];
8
- /** What `swp init` writes when it cannot find the project ref. */
18
+ /** What `supabase-worker-previews init` writes when it cannot find the project ref. */
9
19
  export const PLACEHOLDER_REF = "<production project ref>";
10
20
  export const CONFIG_DEFAULTS = {
11
21
  trunk: "main",
@@ -48,44 +58,46 @@ export function readWranglerConfig(cwd = process.cwd()) {
48
58
  return { file, json, name: typeof json.name === "string" ? json.name : undefined };
49
59
  }
50
60
  export function loadConfig(overrides = {}, cwd = process.cwd()) {
51
- const path = join(cwd, CONFIG_FILE);
61
+ const name = configFileIn(cwd);
62
+ const path = join(cwd, name);
52
63
  const exists = existsSync(path);
53
64
  const file = exists ? readConfigFile(path) : {};
54
65
  const wrangler = readWranglerConfig(cwd);
55
66
  const merged = { ...CONFIG_DEFAULTS, worker: wrangler?.name, ...file, ...defined(overrides) };
56
67
  if (!merged.supabaseProjectRef)
57
68
  throw new Error(exists
58
- ? `Set "supabaseProjectRef" (the production project) in ${CONFIG_FILE}`
59
- : `No ${CONFIG_FILE} in this directory. Run \`swp init\` first, or pass --project-ref <ref>.`);
69
+ ? `Set "supabaseProjectRef" (the production project) in ${name}`
70
+ : `No ${name} in this directory. Run \`supabase-worker-previews init\` first, or pass --project-ref <ref>.`);
60
71
  if (merged.supabaseProjectRef === PLACEHOLDER_REF)
61
- throw new Error(`"supabaseProjectRef" in ${CONFIG_FILE} is still ${PLACEHOLDER_REF}. ` +
72
+ throw new Error(`"supabaseProjectRef" in ${name} is still ${PLACEHOLDER_REF}. ` +
62
73
  "Set it to the production project's ref, the <ref> in https://<ref>.supabase.co.");
63
74
  if (!merged.worker)
64
75
  throw new Error(wrangler
65
- ? `${wrangler.file} has no "name"; add the Worker's name there or "worker" in ${CONFIG_FILE}`
66
- : `No ${WRANGLER_FILES.join(", ")} in this directory. Run swp in the Worker's directory, or set "worker" in ${CONFIG_FILE}.`);
76
+ ? `${wrangler.file} has no "name"; add the Worker's name there or "worker" in ${name}`
77
+ : `No ${WRANGLER_FILES.join(", ")} in this directory. Run supabase-worker-previews in the Worker's directory, or set "worker" in ${name}.`);
67
78
  for (const [key, allowed] of Object.entries(CHOICES)) {
68
79
  const value = merged[key];
69
80
  if (!allowed.includes(value))
70
- throw new Error(`"${key}" in ${CONFIG_FILE} must be ${allowed.map((a) => `"${a}"`).join(" or ")}`);
81
+ throw new Error(`"${key}" in ${name} must be ${allowed.map((a) => `"${a}"`).join(" or ")}`);
71
82
  }
72
83
  return merged;
73
84
  }
74
85
  function readConfigFile(path) {
86
+ const name = basename(path);
75
87
  let json;
76
88
  try {
77
89
  json = JSON.parse(readFileSync(path, "utf8"));
78
90
  }
79
91
  catch (err) {
80
- throw new Error(`Cannot parse ${CONFIG_FILE}: ${err.message}`, { cause: err });
92
+ throw new Error(`Cannot parse ${name}: ${err.message}`, { cause: err });
81
93
  }
82
94
  if (!json || typeof json !== "object" || Array.isArray(json))
83
- throw new Error(`${CONFIG_FILE} must hold a JSON object`);
95
+ throw new Error(`${name} must hold a JSON object`);
84
96
  for (const key of Object.keys(json)) {
85
97
  if (KEYS.includes(key))
86
98
  continue;
87
99
  const guess = didYouMean(key, KEYS);
88
- throw new Error(`Unknown key "${key}" in ${CONFIG_FILE}.${guess ? ` Did you mean "${guess}"?` : ""} See the README for the keys.`);
100
+ throw new Error(`Unknown key "${key}" in ${name}.${guess ? ` Did you mean "${guess}"?` : ""} See the README for the keys.`);
89
101
  }
90
102
  return json;
91
103
  }
@@ -29,7 +29,7 @@ export type FeedbackDeps = Deps & {
29
29
  clock?: () => Date;
30
30
  };
31
31
  /**
32
- * The PR comment and GitHub deployment for one `swp pr` run. Any GitHub API
32
+ * The PR comment and GitHub deployment for one `supabase-worker-previews pr` run. Any GitHub API
33
33
  * failure becomes a warning; only the wrapped database work decides the job.
34
34
  */
35
35
  export declare class Feedback {
package/dist/feedback.js CHANGED
@@ -44,7 +44,7 @@ export function warning(message) {
44
44
  return `::warning::${message.replace(/%/g, "%25").replace(/\r/g, "%0D").replace(/\n/g, "%0A")}`;
45
45
  }
46
46
  /**
47
- * The PR comment and GitHub deployment for one `swp pr` run. Any GitHub API
47
+ * The PR comment and GitHub deployment for one `supabase-worker-previews pr` run. Any GitHub API
48
48
  * failure becomes a warning; only the wrapped database work decides the job.
49
49
  */
50
50
  export class Feedback {
package/dist/run.d.ts CHANGED
@@ -12,7 +12,7 @@ export type Runner = {
12
12
  export declare function makeRunner(dryRun: boolean, log?: (line: string) => void): Runner;
13
13
  /**
14
14
  * `--flag value`, `--flag=value` and bare `--flag`. A flag in `booleans` never
15
- * takes the next argument, so `swp --dry-run up` keeps `up` as the command.
15
+ * takes the next argument, so `supabase-worker-previews --dry-run up` keeps `up` as the command.
16
16
  */
17
17
  export declare function parseArgs(argv: string[], booleans?: ReadonlySet<string>): {
18
18
  positional: string[];
package/dist/run.js CHANGED
@@ -29,7 +29,7 @@ export function makeRunner(dryRun, log = console.log) {
29
29
  }
30
30
  /**
31
31
  * `--flag value`, `--flag=value` and bare `--flag`. A flag in `booleans` never
32
- * takes the next argument, so `swp --dry-run up` keeps `up` as the command.
32
+ * takes the next argument, so `supabase-worker-previews --dry-run up` keeps `up` as the command.
33
33
  */
34
34
  export function parseArgs(argv, booleans = new Set()) {
35
35
  const positional = [];
package/dist/runtime.d.ts CHANGED
@@ -50,7 +50,7 @@ type EnvOf<H> = H extends {
50
50
  /**
51
51
  * Wraps a Worker's default export. Every handler sees the override applied;
52
52
  * `fetch` also injects the public config and answers the identity route that
53
- * `swp check` reads.
53
+ * `supabase-worker-previews check` reads.
54
54
  */
55
55
  export declare function withSupabasePreviews<H extends object, E extends object = EnvOf<H>>(handler: H & Handler, options?: PreviewOptions): H;
56
56
  export {};
package/dist/runtime.js CHANGED
@@ -96,7 +96,7 @@ function envOrProcessEnv(env) {
96
96
  /**
97
97
  * Wraps a Worker's default export. Every handler sees the override applied;
98
98
  * `fetch` also injects the public config and answers the identity route that
99
- * `swp check` reads.
99
+ * `supabase-worker-previews check` reads.
100
100
  */
101
101
  export function withSupabasePreviews(handler, options = {}) {
102
102
  const { globalName = DEFAULT_GLOBAL, inject = true, identity = true } = options;
package/dist/supabase.js CHANGED
@@ -148,7 +148,7 @@ export function explainCreateBranchError(ref, name, err) {
148
148
  advice = `The organization's plan does not allow persistent branches${upgrade}.`;
149
149
  else if (gate?.feature === "branching_limit" ||
150
150
  /branch(es|ing)?[ _]limit|(maximum|max|too many)[\w ]* branches/i.test(err.body))
151
- advice = `Project ${ref} has reached its branch limit. Delete branches you no longer need (\`swp prune\` lists leftovers) or raise the limit${upgrade}.`;
151
+ advice = `Project ${ref} has reached its branch limit. Delete branches you no longer need (\`supabase-worker-previews prune\` lists leftovers) or raise the limit${upgrade}.`;
152
152
  else if (gate)
153
153
  advice = `The organization's plan does not include ${gate.feature ?? "this feature"}${upgrade}.`;
154
154
  else if (err.status === 401)
package/dist/usage.js CHANGED
@@ -9,10 +9,22 @@ const TOKENS = ["SUPABASE_ACCESS_TOKEN", "CLOUDFLARE_API_TOKEN", "CLOUDFLARE_ACC
9
9
  const WITH_GITHUB = [...TOKENS, "GITHUB_TOKEN"];
10
10
  const DRY_RUN = { name: "dry-run", help: "Print the plan; change nothing" };
11
11
  const OVERRIDES = [
12
- { name: "dotenv", value: "<path>", help: "Load tokens from this file (default: .env.swp when present)" },
12
+ {
13
+ name: "dotenv",
14
+ value: "<path>",
15
+ help: "Load tokens from this file (default: .env.supabase-worker-previews when present)",
16
+ },
13
17
  { name: "worker", value: "<name>", help: 'Worker name (default: "name" in the wrangler config)' },
14
- { name: "project-ref", value: "<ref>", help: "Production project ref (default: swp.config.json)" },
15
- { name: "trunk", value: "<branch>", help: "Branch the shared database tracks (default: swp.config.json)" },
18
+ {
19
+ name: "project-ref",
20
+ value: "<ref>",
21
+ help: "Production project ref (default: supabase-worker-previews.json)",
22
+ },
23
+ {
24
+ name: "trunk",
25
+ value: "<branch>",
26
+ help: "Branch the shared database tracks (default: supabase-worker-previews.json)",
27
+ },
16
28
  ];
17
29
  const BRANCH = [
18
30
  { name: "branch", value: "<b>", help: "Git branch (default: the current one, or the CI branch)" },
@@ -27,8 +39,8 @@ export const COMMANDS = [
27
39
  name: "init",
28
40
  group: "Set up",
29
41
  args: "[--project-ref <ref>] [--trunk <branch>] [--action]",
30
- summary: "Scaffold swp.config.json, the grants migration and the PR workflow",
31
- details: "Writes swp.config.json, a first migration that grants the API roles default privileges, and\n" +
42
+ summary: "Scaffold supabase-worker-previews.json, the grants migration and the PR workflow",
43
+ details: "Writes supabase-worker-previews.json, a first migration that grants the API roles default privileges, and\n" +
32
44
  ".github/workflows/supabase-previews.yml. Never overwrites a file; run it again safely.",
33
45
  flags: [
34
46
  { name: "project-ref", value: "<ref>", help: "Production project ref (default: from `supabase link`)" },
@@ -37,12 +49,18 @@ export const COMMANDS = [
37
49
  value: "<branch>",
38
50
  help: "Branch the shared database tracks (default: origin/HEAD, else main)",
39
51
  },
40
- { name: "action", help: "Write a workflow that uses the published GitHub Action instead of npx swp" },
52
+ {
53
+ name: "action",
54
+ help: "Write a workflow that uses the published GitHub Action instead of npx supabase-worker-previews",
55
+ },
41
56
  { ...DRY_RUN, help: "Print what it would write; write nothing" },
42
57
  ],
43
58
  env: [],
44
59
  dryRunEnv: [],
45
- examples: ["swp init --project-ref abcdefghijklmnopqrst", "swp init --action"],
60
+ examples: [
61
+ "supabase-worker-previews init --project-ref abcdefghijklmnopqrst",
62
+ "supabase-worker-previews init --action",
63
+ ],
46
64
  },
47
65
  {
48
66
  name: "doctor",
@@ -55,7 +73,7 @@ export const COMMANDS = [
55
73
  flags: OVERRIDES,
56
74
  env: [],
57
75
  dryRunEnv: [],
58
- examples: ["swp doctor"],
76
+ examples: ["supabase-worker-previews doctor"],
59
77
  },
60
78
  {
61
79
  name: "shared",
@@ -68,7 +86,7 @@ export const COMMANDS = [
68
86
  flags: [DRY_RUN, ...OVERRIDES],
69
87
  env: TOKENS,
70
88
  dryRunEnv: ["SUPABASE_ACCESS_TOKEN"],
71
- examples: ["swp shared --dry-run", "swp shared"],
89
+ examples: ["supabase-worker-previews shared --dry-run", "supabase-worker-previews shared"],
72
90
  },
73
91
  {
74
92
  name: "up",
@@ -80,7 +98,7 @@ export const COMMANDS = [
80
98
  flags: [...BRANCH, DRY_RUN, ...OVERRIDES],
81
99
  env: TOKENS,
82
100
  dryRunEnv: [],
83
- examples: ["swp up --branch feat/notes --dry-run"],
101
+ examples: ["supabase-worker-previews up --branch feat/notes --dry-run"],
84
102
  },
85
103
  {
86
104
  name: "check",
@@ -97,7 +115,7 @@ export const COMMANDS = [
97
115
  ],
98
116
  env: TOKENS,
99
117
  dryRunEnv: [],
100
- examples: ["swp check --branch feat/notes --isolated"],
118
+ examples: ["supabase-worker-previews check --branch feat/notes --isolated"],
101
119
  },
102
120
  {
103
121
  name: "down",
@@ -108,7 +126,7 @@ export const COMMANDS = [
108
126
  flags: [...BRANCH, DRY_RUN, ...OVERRIDES],
109
127
  env: TOKENS,
110
128
  dryRunEnv: TOKENS,
111
- examples: ["swp down --branch feat/notes --dry-run"],
129
+ examples: ["supabase-worker-previews down --branch feat/notes --dry-run"],
112
130
  },
113
131
  {
114
132
  name: "pr",
@@ -126,7 +144,7 @@ export const COMMANDS = [
126
144
  ],
127
145
  env: WITH_GITHUB,
128
146
  dryRunEnv: WITH_GITHUB,
129
- examples: ["swp pr"],
147
+ examples: ["supabase-worker-previews pr"],
130
148
  },
131
149
  {
132
150
  name: "prune",
@@ -146,7 +164,7 @@ export const COMMANDS = [
146
164
  ],
147
165
  env: WITH_GITHUB,
148
166
  dryRunEnv: WITH_GITHUB,
149
- examples: ["swp prune", "swp prune --yes"],
167
+ examples: ["supabase-worker-previews prune", "supabase-worker-previews prune --yes"],
150
168
  },
151
169
  ];
152
170
  const ALL_FLAGS = [...COMMANDS.flatMap((c) => c.flags), ...HELP];
@@ -172,9 +190,9 @@ export function mainHelp(s = makeStyle(false)) {
172
190
  ...COMMANDS.filter((c) => c.group === group).map((c) => ` ${s.cyan(c.name.padEnd(width))} ${c.summary}`),
173
191
  ]);
174
192
  return [
175
- `${s.bold("swp")} ${version()}: branch previews for Cloudflare Workers on Supabase branching`,
193
+ `${s.bold("supabase-worker-previews")} ${version()}: branch previews for Cloudflare Workers on Supabase branching`,
176
194
  "",
177
- `${s.bold("Usage:")} swp <command> [flags]`,
195
+ `${s.bold("Usage:")} supabase-worker-previews <command> [flags]`,
178
196
  ...groups,
179
197
  "",
180
198
  s.bold("Common flags"),
@@ -185,18 +203,18 @@ export function mainHelp(s = makeStyle(false)) {
185
203
  ` Where to get them: ${TOKENS_URL}`,
186
204
  "",
187
205
  s.bold("Examples"),
188
- " npx swp init --project-ref abcdefghijklmnopqrst",
189
- " npx swp doctor",
190
- " npx swp shared --dry-run",
206
+ " npx supabase-worker-previews init --project-ref abcdefghijklmnopqrst",
207
+ " npx supabase-worker-previews doctor",
208
+ " npx supabase-worker-previews shared --dry-run",
191
209
  "",
192
- `Run ${s.cyan("swp <command> --help")} for one command. Docs: ${DOCS_URL}`,
210
+ `Run ${s.cyan("supabase-worker-previews <command> --help")} for one command. Docs: ${DOCS_URL}`,
193
211
  ].join("\n");
194
212
  }
195
213
  export function commandHelp(c, s = makeStyle(false)) {
196
214
  return [
197
- `${s.bold(`swp ${c.name}`)}: ${c.summary.charAt(0).toLowerCase()}${c.summary.slice(1)}`,
215
+ `${s.bold(`supabase-worker-previews ${c.name}`)}: ${c.summary.charAt(0).toLowerCase()}${c.summary.slice(1)}`,
198
216
  "",
199
- `${s.bold("Usage:")} swp ${c.name}${c.args ? ` ${c.args}` : ""}`,
217
+ `${s.bold("Usage:")} supabase-worker-previews ${c.name}${c.args ? ` ${c.args}` : ""}`,
200
218
  "",
201
219
  c.details,
202
220
  "",
@@ -256,11 +274,11 @@ function unknownCommand(name) {
256
274
  const guess = didYouMean(name, COMMANDS.map((c) => c.name));
257
275
  return {
258
276
  kind: "error",
259
- message: `Unknown command "${name}".${guess ? ` Did you mean "swp ${guess}"?` : ""}\nRun swp --help to see every command.`,
277
+ message: `Unknown command "${name}".${guess ? ` Did you mean "supabase-worker-previews ${guess}"?` : ""}\nRun supabase-worker-previews --help to see every command.`,
260
278
  };
261
279
  }
262
280
  function usageError(message, name) {
263
- return { kind: "error", message: `${message}\nRun swp ${name} --help for its usage.` };
281
+ return { kind: "error", message: `${message}\nRun supabase-worker-previews ${name} --help for its usage.` };
264
282
  }
265
283
  const ENV_SOURCES = {
266
284
  SUPABASE_ACCESS_TOKEN: "https://supabase.com/dashboard/account/tokens (organization-scoped)",
@@ -278,11 +296,11 @@ export function missingEnvMessage(name, dryRun, env = process.env) {
278
296
  return [
279
297
  `${name}${dryRun ? " --dry-run" : ""} needs ${missing.length === 1 ? "this variable" : "these variables"}, not set:`,
280
298
  ...missing.map((v) => ` ${v.padEnd(width)} ${ENV_SOURCES[v]}`),
281
- `Put ${missing.length === 1 ? "it" : "them"} in .env.swp (git-ignore it) or the environment. Scopes: ${TOKENS_URL}`,
299
+ `Put ${missing.length === 1 ? "it" : "them"} in .env.supabase-worker-previews (git-ignore it) or the environment. Scopes: ${TOKENS_URL}`,
282
300
  ].join("\n");
283
301
  }
284
302
  /** One line for the user: the message, and for a network failure the host and the system error. */
285
- export function formatError(err, debug = !!process.env.SWP_DEBUG) {
303
+ export function formatError(err, debug = !!(process.env.SUPABASE_WORKER_PREVIEWS_DEBUG || process.env.SWP_DEBUG)) {
286
304
  if (!(err instanceof Error))
287
305
  return String(err);
288
306
  if (debug && err.stack)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "supabase-worker-previews",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Branch previews for Cloudflare Workers on Supabase branching: every git branch gets a Worker Preview, and every PR that changes the schema gets its own Supabase database.",
5
5
  "license": "MIT",
6
6
  "author": "Matt Ruby",
@@ -34,7 +34,7 @@
34
34
  "node": ">=22.0.0"
35
35
  },
36
36
  "bin": {
37
- "swp": "dist/cli.js"
37
+ "supabase-worker-previews": "dist/cli.js"
38
38
  },
39
39
  "main": "./dist/runtime.js",
40
40
  "types": "./dist/runtime.d.ts",
@@ -1,7 +1,7 @@
1
1
  name: Preview database
2
2
 
3
3
  # The same job as supabase-previews.yml, through the published action. It runs
4
- # the project's installed swp when there is one, else downloads the package.
4
+ # the project's installed supabase-worker-previews when there is one, else downloads the package.
5
5
 
6
6
  on:
7
7
  pull_request:
@@ -30,7 +30,7 @@ jobs:
30
30
  node-version: 24
31
31
  cache: npm
32
32
  - run: npm ci --no-audit --no-fund
33
- - run: npx swp pr
33
+ - run: npx supabase-worker-previews pr
34
34
  env:
35
35
  GITHUB_TOKEN: ${{ github.token }}
36
36
  SUPABASE_ACCESS_TOKEN: ${{ secrets.SUPABASE_ACCESS_TOKEN }}