Supabase CLI. Manage postgres migrations, run Supabase locally, deploy edge functions. Postgres backups. Generating types from your database schema.
| 文件 | 最后提交记录 | 最后更新时间 |
|---|---|---|
docs(repo): add a test-audit skill with an authoring gate and an audit mode (#6890) ## Problem Nothing limits test growth, and agents write a test for nearly every change. The rules against low-value tests live as prose in the "Test quality" section of `AGENTS.md`, which agents skim past when they add or review tests. ## Change - Adds `.agents/skills/test-audit/SKILL.md`, which loads whenever a test is written, changed or reviewed. It includes: - **Authoring gate:** four questions a new test must answer before it's added. - **Level rule:** one primary test per contract, at the strongest boundary that can reach it. - **Junk-pattern checklist:** fitted to our Effect layers, handler integration tests and `runSupabase()` e2e, including real-time waits on production timeouts. - **Retention bar and regression-test rule.** - **Read-only audit mode:** a retain / fix / consolidate / delete ledger with one evidence line per mark. - "Test quality" in `AGENTS.md` points to the skill and drops the redundant-coverage bullet, which the skill now covers. - `.claude/skills/` holds one symlink per repo skill (`effect`, `test-audit`) into `.agents/skills/`, so Claude Code discovers them automatically and Codex keeps reading `.agents/skills`. `.gitignore` now ignores `.claude/*` except `.claude/skills`, and local state such as worktrees and settings stays ignored. A new skill in `.agents/skills` needs a matching symlink. | 1 天前 | |
docs(repo): add a test-audit skill with an authoring gate and an audit mode (#6890) ## Problem Nothing limits test growth, and agents write a test for nearly every change. The rules against low-value tests live as prose in the "Test quality" section of `AGENTS.md`, which agents skim past when they add or review tests. ## Change - Adds `.agents/skills/test-audit/SKILL.md`, which loads whenever a test is written, changed or reviewed. It includes: - **Authoring gate:** four questions a new test must answer before it's added. - **Level rule:** one primary test per contract, at the strongest boundary that can reach it. - **Junk-pattern checklist:** fitted to our Effect layers, handler integration tests and `runSupabase()` e2e, including real-time waits on production timeouts. - **Retention bar and regression-test rule.** - **Read-only audit mode:** a retain / fix / consolidate / delete ledger with one evidence line per mark. - "Test quality" in `AGENTS.md` points to the skill and drops the redundant-coverage bullet, which the skill now covers. - `.claude/skills/` holds one symlink per repo skill (`effect`, `test-audit`) into `.agents/skills/`, so Claude Code discovers them automatically and Codex keeps reading `.agents/skills`. `.gitignore` now ignores `.claude/*` except `.claude/skills`, and local state such as worktrees and settings stays ignored. A new skill in `.agents/skills` needs a matching symlink. | 1 天前 | |
ci(stack): retry slim pickup when a merge-queued PR holds the branch (#6957) `slim-release-published.yml` force-pushes one branch per service release line. When that branch's PR sits in the merge queue, GitHub rejects the push (GH006) and the job used to fail, dropping the planned pin until the next upstream release. On 2026-10-01 this lost edge-runtime v1.77.4-r0: the v1.77.3-r0 and v1.77.4-r0 dispatches both hit `slim-bump/edge-runtime` while #6930 was queued (restored by #6955). When a push is rejected because the branch is queued for merging, the Apply step now: - waits for the queue to merge or drop that PR, polling `isInMergeQueue` for up to 30 minutes and within the app token's lifetime; - stops processing the current plan, so no remaining item is built from the pre-merge base; - re-sends the same dispatch so a fresh run re-plans from the updated default branch, at most three times in a row (tracked by a validated `client_payload.replay` counter). The concurrency group now keeps every pending run (`queue: max`) instead of replacing the pending one, so a replay can never cancel a newer dispatch and its release-visibility wait. A failed queue lookup or dispatch, a queue that holds the branch past the deadline, an exhausted replay budget, and any other push rejection still fail the run with the manual recovery command. ADR 0026 documents the behavior. | 1 天前 | |
chore(repo): enforce commitlint scope-enum tied to turbo projects (#6496) ## What kind of change does this PR introduce? Tooling/chore — adds commitlint, tied to a fixed scope list. ## What is the current behavior? There is no commitlint or commitizen setup. PR titles must follow conventional-commits format (checked in CI by `amannn/action-semantic-pull-request`), but scopes are unrestricted free text, enforced only by human review. ## What is the new behavior? - Adds `commitlint.config.js` with a `scope-enum` rule: one scope per real turbo/pnpm workspace project (`api`, `cli`, `cli-e2e`, `cli-go`, `cli-test-helpers`, `config`, `docs`, `process-compose`, `stack` — verified against `pnpm -r list`) plus escape scopes for changes that don't map to a single project (`ci`, `repo`, `misc`, `release`). The 8 per-platform `packages/cli-{platform}` binary-wrapper packages are folded into `cli`. `release` isn't a turbo project (`tools/release` has no `package.json`) but is kept as an escape scope because `propose-release-notes.ts` genuinely commits with that scope. - Adds a local `commit-msg` git hook via husky that runs commitlint on every commit. CI checkouts skip installing this hook (`HUSKY=0` in the shared setup action) so bot-authored commits are never gated by it — scope enforcement for those stays on the PR-title CI check. - Mirrors the same scope list into the `amannn/action-semantic-pull-request` step in `lint-pull-request.yml`, so PR titles are held to the same list in CI. - Updates `.github/dependabot.yml`: the `npm` and `docker` ecosystems previously auto-generated scopes (`deps`/`deps-dev`/`docker`) that aren't in the new fixed list, which would have started failing their own PR-title check — both remapped to `misc`. The `gomod` ecosystem had no `commit-message` config at all, so it fell back to a repository-detected scope also outside the allowlist — mapped to `chore(cli-go): ` since that's precisely the project those updates belong to. `github-actions` (already `ci`) is untouched. - Documents the local commit-msg hook in `CONTRIBUTING.md`, and adds one clarifying sentence to `AGENTS.md` pointing at `commitlint.config.js` as the source of truth for allowed scopes. No commitizen/interactive prompt added — commitlint validates whatever message is typed. | 26 天前 | |
chore(repo): refresh reference repositories (#6620) Refresh the reference repository revisions so implementation work uses current upstream sources. Effect V4 now follows the canonical `Effect-TS/effect` repository on `main`, while the V3 reference explicitly follows `v3`. Advance the other references to their upstream branch tips; `effect-patterns` already points to the latest revision. Synchronize submodule URLs before installation or updates, and initialize these top-level source references without traversing upstream development dependencies. This also avoids a broken nested-submodule mapping in the latest `t3code` reference. Document how to inspect the matching Effect release tag when upstream source is ahead of the installed dependencies. | 18 天前 | |
chore(repo): exclude .repos from editor tooling and use explicit oxc config paths (#6330) ## What changed - **VSCode**: ignore `.repos/` (the vendored `effect` source checkout) in file explorer, search, and file watchers so the editor doesn't index or watch the submodule contents. - **oxc**: replace the `--disable-nested-config` flag with explicit `--config` paths (`.oxlintrc.json`, `.oxfmtrc.json`) in the Nx `lint:*`/`fmt:*` targets, and add the same explicit config paths to the oxc VSCode extension settings. ## Why `.repos` submodules were being picked up by the VSCode extensions and editor indexing. Pointing oxlint/oxfmt at explicit root configs (instead of relying on nested-config discovery) and excluding `.repos` from the editor keeps the vendored repos from being loaded at all. 🤖 Generated with [Claude Code](https://claude.com/claude-code) | 1 个月前 | |
fix(cli): name the changed setting and the fix when a saved stack rejects a config change (#6944) When `supabase start` (with `[experimental] stack`) refuses a change to a saved stack, the error now says which setting changed and what to do about it. It used to report internal paths such as `endpoints.http` with a generic suggestion. - Each rejected change is reported as the `config.toml` key, or the `SUPABASE_*` environment variable that set it, with the saved and requested values, after a lead-in saying the saved stack cannot adopt them. For example: `[db] major_version: saved 17, requested 15`, or `[api] port: saved automatic, requested 54999`. - Changes across all affected services are reported together in one error. A shared `[api] port` appears once. - The suggestion offers two ways out: revert the setting to keep the stack and its data, or run `supabase stack destroy --stack-id <id>` to recreate it. It warns that recreating deletes the local database data. The ID is used so the command targets this stack regardless of the current directory. When a change can't be reverted, such as a catalog-pinned artifact or Postgres build from a CLI upgrade, the suggestion offers only the destroy command. - JSON and stream-json errors carry the same details in structured form (`stack_changes` with service, path, key, saved and requested values, plus `recreate_command`), so agents don't have to parse prose. `stack_changes` keeps one entry per affected service, and `recreate_command` omits `--yes`, which a JSON-mode destroy requires. Port settings are now defined once in `stack-config.ts`, shared by config translation and error attribution, so a new port can't be added to one and missed in the other. The tests use the real composition planner. | 1 天前 | |
ci(stack): retry slim pickup when a merge-queued PR holds the branch (#6957) `slim-release-published.yml` force-pushes one branch per service release line. When that branch's PR sits in the merge queue, GitHub rejects the push (GH006) and the job used to fail, dropping the planned pin until the next upstream release. On 2026-10-01 this lost edge-runtime v1.77.4-r0: the v1.77.3-r0 and v1.77.4-r0 dispatches both hit `slim-bump/edge-runtime` while #6930 was queued (restored by #6955). When a push is rejected because the branch is queued for merging, the Apply step now: - waits for the queue to merge or drop that PR, polling `isInMergeQueue` for up to 30 minutes and within the app token's lifetime; - stops processing the current plan, so no remaining item is built from the pre-merge base; - re-sends the same dispatch so a fresh run re-plans from the updated default branch, at most three times in a row (tracked by a validated `client_payload.replay` counter). The concurrency group now keeps every pending run (`queue: max`) instead of replacing the pending one, so a replay can never cancel a newer dispatch and its release-visibility wait. A failed queue lookup or dispatch, a queue that holds the branch past the deadline, an exhausted replay budget, and any other push rejection still fail the run with the manual recovery command. ADR 0026 documents the behavior. | 1 天前 | |
feat(stack): pin slim artifacts by revision and make the catalog the single version table (#6883) ## Summary slim-services now publishes immutable `<upstream>-r<N>` releases (supabase/slim-services#326, #328). This PR makes the CLI consume them safely and from one place: - **Pinning.** Every slim artifact is pinned by content: the image digest, plus an archive and manifest sha256 per target. Nothing is looked up at runtime. - **One version table.** The stack catalog (`packages/stack/src/Artifacts.ts`) is the only place slim-capable service versions are written down. The new stack, legacy `supabase start`, and legacy slim mode (`SUPABASE_USE_SLIM_IMAGES`) all derive from it. - **Updates.** Upgrades and packaging hotfixes arrive as automated PRs from slim-services releases. ### Pinning - **Catalog entries.** They are now `ArtifactPin`s: - `upstreamVersion` - `revision` - `image: …:<U>-r<N>@sha256:…` - `upstreamImage`: the upstream image slim-services built from or mirrored, as recorded in the release - `natives`: sha256s per target - **Native downloads.** - The runtime `SHA256SUMS` and GHCR checksum lookups are gone. The GitHub release and S3 serve bytes only. - The manifest is hash-checked before it is parsed. - A mirror that serves the wrong bytes falls through to the next one. - The cache key is `slim-services/<svc>/<R>/<target>`, so a hotfix revision gets its own cache entry. ### One version table - **Generated Dockerfile lines.** The slim-capable `FROM` lines of `apps/cli/src/shared/services/Dockerfile`, and its Go copy, are generated from the catalog by `apps/cli/scripts/render-service-dockerfile.ts`. - The generator rewrites only those 14 lines, in place, and takes each repository from the existing line. imgproxy stays on `darthsim/imgproxy`. - Kong, `pg14`, and the job images (migra, pg_prove, pgadmin-schema-diff) are still maintained by hand or by Dependabot. - A drift test in the required `apps/cli` unit project fails when the Dockerfile and the catalog disagree. - **Postgres 13/15 and 14.** New `pg15` (generated) and `pg14` (hand-pinned) stages replace the hardcoded constants, in both the TS and the Go CLI. - Non-slim PG13/15 moves from 15.8.1.085 to the pinned 15 line. - Slim mode translates `pg15` through the catalog, like every other alias. - **Slim mode.** It now always finds its pin for the default versions. A linked project's hosted version that the catalog doesn't pin still uses the upstream image. ### Updates - **`slim-release-published.yml`** reconciles the dispatched service against every committed slim-services release. For each release line it opens, or rewrites in place: - a **hotfix** PR (`slim-hotfix/<svc>[-<line>]`), when the pinned upstream has a newer revision; - an **upgrade** PR (`slim-bump/<svc>[-<line>]`), when a newer upstream exists on that line. - **Each PR:** - pins exactly the planned release; - regenerates both Dockerfiles; - is assigned to `jgoux`. - **Mirror timing.** Before planning, the run waits (bounded) for the dispatched release to appear in the release list. Before pinning, it waits (bounded) for the S3 mirror of a new release, and a digest mismatch fails immediately. - **Trust.** Plan and apply run from one checkout of the default branch, so a re-run recomputes the plan and never applies a stale one. Every `::error ::`/`::warning ::` line uses workflow-command data encoding. The app token reaches only `git push` and `gh`: it is never written to `.git/config`, and every `bun`/`pnpm` command (the formatter runs from the locked install) runs without it. The PR lookup ignores fork PRs. Payload and release-tag values are validated against anchored patterns, and recorded image references are validated and escaped before they are written into the catalog. - **Dependabot.** It now ignores every slim-capable image, and the Dependabot-to-catalog sync (`sync-artifacts-catalog.yml`) is deleted. - **Tests.** They derive versions from the catalog, so a bump PR touches only `Artifacts.ts` and the two Dockerfiles. ### Other changes needed by the new versions - **Vector 0.58** no longer expands `${VAR}` in its config. - The recipe writes real values into its own config instead. - In caller-supplied pipelines it fills in only `LOGFLARE_URL` and `LOGFLARE_PRIVATE_ACCESS_TOKEN`. - It never enables `--dangerously-allow-env-var-interpolation`. - **Vector on legacy `supabase start`.** Vector 0.58's images don't ship `/etc/vector`, so the entrypoint creates it before writing the config. A `start.lifecycle` e2e scenario starts Vector against a real Logflare. - **`pgdelta.seam.layer.ts`** compares slim images by revision or digest, so a container on `-r0` is reported stale once the catalog moves to `-r1`. - **Three integration tests that failed under load now have coherent time budgets:** - `upload-release-assets`: the retry that must succeed had to fit in the same 500ms as the attempt that hangs on purpose. - `stack-shadow`: a real-Docker test ran under vitest's 5s default timeout. - `sweep-live-projects`: a 10s hard kill inside the test's budget. ### Docs ADR 0026 is rewritten for this model, including the tradeoffs: - slim-capable upstream and security fixes arrive only via slim-services releases; - Dependabot's cooldown no longer applies to them; - kong and `pg14` are bumped by hand; - the Deno 1 edge-runtime override stays pinned separately. `infra/cli-artifacts/README.md` is updated to match. ## Release notes - Unlinked local projects on Postgres 13 or 15 now start `supabase/postgres:15.19.0.002` instead of `15.8.1.085`. Later catalog upgrades on the 15 line move them within the same major. - `supabase start` runs the catalog's upstream versions (table below), and Storage is pinned to the `v1.79.28-r1` hotfix. ## Versions Every catalog entry pins its newest committed revision. Legacy `supabase start` now runs the same upstream versions: | Service | Catalog before → after | Legacy Dockerfile before → after | |---|---|---| | postgres 17 | `17.6.1.173` → `17.11.0.002-r0` | `17.6.1.171` → `17.11.0.002` | | postgres 15 (PG13/15) | `15.14.1.173` → `15.19.0.002-r0` | `15.8.1.085` (constant) → `15.19.0.002` | | postgrest | `v16.2` → `v16.4-r0` | `v16.3` → `v16.4` | | auth | `v2.196.0` → `v2.197.0-r0` | `v2.197.0` (unchanged) | | realtime | `v2.134.5` → `v2.140.3-r0` | `v2.135.3` → `v2.140.3` | | storage | `v1.73.0` → `v1.79.28-r1` | `v1.77.0` → `v1.79.28` | | imgproxy | `v3.8.0` → `v3.26.0-r0` | `v3.8.0` → `v3.26.0` | | edge-runtime | `v1.77.1` → `v1.77.1-r0` | `v1.77.1` (unchanged) | | studio | `2026.09.04-sha-5a67366` → `2026.09.28-sha-5e59b60-r0` | `2026.09.14-sha-4dd8a95` → `2026.09.28-sha-5e59b60` | | pgmeta | `v0.99.0` → `v0.99.0-r0` | `v0.99.0` (unchanged) | | mailpit | `v1.30.2` → `v1.31.3-r0` | `v1.30.2` → `v1.31.3` | | analytics | `v1.50.9` → `v1.50.15-r0` | `1.50.12` → `1.50.15` | | vector | `0.53.0` → `0.58.0-r0` | `0.53.0-alpine` → `0.58.0-alpine` | | pooler | `v2.9.12` → `v2.9.13-r0` | `2.9.13` (unchanged) | | 3 天前 | |
fix(cli): name the changed setting and the fix when a saved stack rejects a config change (#6944) When `supabase start` (with `[experimental] stack`) refuses a change to a saved stack, the error now says which setting changed and what to do about it. It used to report internal paths such as `endpoints.http` with a generic suggestion. - Each rejected change is reported as the `config.toml` key, or the `SUPABASE_*` environment variable that set it, with the saved and requested values, after a lead-in saying the saved stack cannot adopt them. For example: `[db] major_version: saved 17, requested 15`, or `[api] port: saved automatic, requested 54999`. - Changes across all affected services are reported together in one error. A shared `[api] port` appears once. - The suggestion offers two ways out: revert the setting to keep the stack and its data, or run `supabase stack destroy --stack-id <id>` to recreate it. It warns that recreating deletes the local database data. The ID is used so the command targets this stack regardless of the current directory. When a change can't be reverted, such as a catalog-pinned artifact or Postgres build from a CLI upgrade, the suggestion offers only the destroy command. - JSON and stream-json errors carry the same details in structured form (`stack_changes` with service, path, key, saved and requested values, plus `recreate_command`), so agents don't have to parse prose. `stack_changes` keeps one entry per affected service, and `recreate_command` omits `--yes`, which a JSON-mode destroy requires. Port settings are now defined once in `stack-config.ts`, shared by config translation and error attribution, so a new port can't be added to one and missed in the other. The tests use the real composition planner. | 1 天前 | |
feat(cli): drive gen types languages from the @supabase/typegen registry (SDK-1956) (#6822) ## Summary `gen types` no longer names its languages. `--lang` and the language-specific flags come from `@supabase/typegen`, the SDK team's language registry, which maps each language to its generator. Each registry entry either calls a generator in-process (TypeScript, Go, Python and Swift, the four bundled in `@supabase/postgrest-typegen`) or runs the language's own tool in the working directory with the introspected `GeneratorMetadata` document on stdin. `--lang dart` is the first out-of-process language: it runs `dart run supabase_typegen --output -` in the user's project. Adding a language is a pull request in `supabase/sdk` plus a bump of the one registry dependency here. ### What changed in `apps/cli/src/commands/gen/types/` - `types.languages.ts` (new): everything derived from the registry in one place. The `--lang` values, one optional Effect flag per user-facing option name (merged across the languages that declare it, with the union of their choices; a name declared with two kinds throws), the value-taking flag names for the argv scans, the documented defaults where every declaring language agrees, and `languageOptionValues`, which forwards only the values the user set so each language applies its own default. The pure functions take option specs, so the unit tests use synthetic specs rather than the registry's contents. - `types.command.ts`: `--lang` is a choice over the registry's names; the language flags are spread in from `types.languages.ts` after a collision check against the command's own flags, the global flags and Effect's built-ins. `--postgrest-v9-compat` is hidden. - `types.handler.ts`: the mutex groups, the changed-flag check and both value-flag scans include every registry language flag. `runGenerate` passes the language options plus the consumer setting `detect-one-to-one-relationships`, computed as before (`!(postgrestV9Compat || forcedV9)` on `--local`, `!postgrestV9Compat` elsewhere). Passing `--postgrest-v9-compat` prints a deprecation line on stderr before the guards run. - `types.generator.service.ts`: `GenTypesGenerateInput` carries `lang: string` and `options: OptionValues`. Two new tagged errors: `GenTypesToolNotInstalledError` (the registry's message verbatim, install hint included) and `GenTypesToolFailedError` (the tool's exit code and stderr in the message, also covering a rejected document version). - `types.generator.layer.ts`: opens the `DbConnection` session in its own scope, introspects in-process and closes the connection, then calls `findLanguage(lang).generate(metadata, declaredOptions, host)`, forwarding only the options the language declares. Registry errors map to the two new errors; anything else stays `GenTypesGenerationError`. The two tool errors never trigger the IPv4 pooler retry, since the tool runs after the connection succeeded and its stderr may name a host of its own. The registry sorts the metadata and returns complete file contents, so the layer's own sort and trailing newline are gone and output for the four existing languages is byte-identical. Out-of-process tools run in the directory the command was invoked from (`RuntimeInfo.cwd`), not the resolved Supabase workdir, so a Flutter app inside a monorepo resolves its own `supabase_typegen`. - `types.typegen-host.ts` (new): the registry `Host` on the Effect `ChildProcessSpawner`. The generator fiber owns the spawned tool through `Effect.runPromiseWith(context)` with the request's abort signal; the child runs in the directory the command was invoked from and inherits the CLI's whole environment; stdout, stderr and exit code are collected concurrently, with a signal-ended tool reported as a `null` exit code. On Windows the command is resolved through `PATH` and `PATHEXT` with the registry's `resolveWindowsCommand`, and a `.bat` or `.cmd` runs through the command interpreter with tokens holding whitespace or cmd.exe metacharacters quoted, since Flutter ships `dart` as `dart.bat`. The quoting and the script check are the registry's own `quoteForCmd` and `isWindowsScript` (supabase/sdk#231, in typegen 0.2.0), so this host and `createNodeHost` build the same line, and a token holding a double quote or a line break is refused rather than wrapped. A missing command rejects with `ENOENT`, which the registry turns into its install-hint error. `format` returns TypeScript unformatted so `oxfmt` stays out of the binary. - `SIDE_EFFECTS.md`: registry intro, the out-of-process subprocess row, two new exit-code rows, and the flag notes. Elsewhere: `error-actionability.ts` gains the `toolNotInstalled` and `toolFailed` presets and the error-tag fixture lists the two new tags; `db-target-flags.ts` and `docs-spec.tables.ts` take the language flags and their defaults from the registry instead of listing `swift-access-control` by hand; `tsconfig.types.json` keeps only the `@supabase/pg-topo` pin. `patches/@effect__platform-node-shared@4.0.0-rc.112.patch` attaches an `error` listener to a spawned child's stdin for its lifetime: the upstream sink listens only while writing and then waits for `finish` alone, so a tool that exits before reading its input turned the final flush's `EPIPE` into an uncaught exception that would have crashed the CLI. The host also feeds stdin from its own fiber rather than handing the spawner a stream, and `types.typegen-host.integration.test.ts` drives one kilobyte and four megabytes into a tool that exits at once; the small write is the one that reaches the unguarded `EPIPE` on Linux. ### Dependency `@supabase/typegen@0.2.1` from npm, pinned exactly, replaces the direct `@supabase/postgrest-typegen` dependency. The registry pins `@supabase/postgrest-typegen@0.3.0`, which compiles under this workspace's compiler options, so postgrest-typegen is type-checked from source through the registry like every other `bun`-condition package, and the `dist` types pin it used to need is gone. Both versions are excluded from the release-age policy because they were published this week. A new postgrest-typegen release reaches the CLI through a single registry bump. postgrest-typegen 0.3.1 declares `oxfmt` as an optional peer dependency and loads it only inside its default TypeScript formatter. `gen types` supplies its own identity formatter, so the compiled binary marks `oxfmt` external in `compile-options.ts` and ships without it. That one line replaces the `oxfmtStubPlugin` Bun plugin, the `oxfmt-stub.ts` module and their use in `scripts/build.ts`, `scripts/build-binary.ts` and `tools/release/local-release.ts`, all removed here. The binary is the same size as before, since the stub already kept `oxfmt` out. ### Behavior changes - `--lang` accepts `dart`. It needs the Dart SDK on `PATH` and `supabase_typegen` as a dependency of the project the command runs in; otherwise the error carries the install hint. - `--swift-access-control` accepts `private` and `package` in addition to `internal` and `public`, as the generator always did. - `--postgrest-v9-compat` is deprecated: hidden from help and docs, still honored with its `--db-url`-only rule, and it prints `Flag --postgrest-v9-compat has been deprecated, PostgREST 9 reached end of life; the flag still disables one-to-one relationship detection.` on stderr. - The four existing languages produce the same bytes as before against the databases checked, with one upstream exception: when two schemas hold an enum of the same name, postgrest-typegen 0.2.2 typed a Python column as `PublicStatus` and 0.3.0 types it as the schema-qualified `OtherStatus` and emits that alias, which is the fix for a name collision. TypeScript, Go and Swift were identical against the same database. - TypeScript output ends in one newline instead of two. The old code appended a newline after every generator regardless of what it produced, and the TypeScript template already ends in one; since typegen 0.2.1 (supabase/sdk#233, SDK-1961) the registry passes a generator's newline through instead of adding another. Go, Python and Swift are unaffected: their generators now emit the newline the CLI used to append. ### Notes for reviewers - `types.generator.integration.test.ts` runs the real generator layer against a fake `dart` on a temporary `PATH` through an empty fake database, covering the invocation directory, stdin delivery, exit codes, `ENOENT` and the rendered errors; `types.typegen-host.unit.test.ts` covers the host's result and rejection mapping and the Windows quoting; the e2e language list derives from the registry. Against a Docker Postgres with a small schema, `gen types --lang dart --db-url …` run from a Dart project and `dart run supabase_typegen --db-url …` produced byte-identical files. - The Windows path has only run against a fake spawner and filesystem; a run on a Windows machine with Flutter is still owed. Verified separately: `dart run supabase_typegen` keeps stdout clean on a cold `.dart_tool` cache, so no progress output can land in the generated file. ## Linked issue No GitHub issue; tracked in Linear as SDK-1956 (maintainer PR). Follow-up: SDK-1961 moves the trailing newline into the generators, with no change needed here when it lands. | 5 天前 | |
feat(stack): lease owners with a lock and bind session stacks to creators (#6838) ## Problem The owner's exclusivity came from binding a sticky control port. - A foreign listener on that port wedged the stack, including `destroy`. - The owner never noticed its creator dying, so throwaway stacks (CLI schema shadows, test stacks) leaked the owner, containers and port claims after a SIGKILL, crash or OOM. - Nothing checked that a client and a running owner came from compatible releases. - Owner output was discarded. ## Change - Each owner holds a per-stack SQLite lease for its lifetime. It publishes an ephemeral loopback endpoint and a per-owner bearer secret in `owner.json`, with mode 0600. - Liveness is a no-wait lease probe, so dead stacks cost no network timeouts. - The lease is re-validated against the path it locked. - The handshake compares a release derived from the stack sources and the Effect version. Builds and source runs compute the same value. `stop` and `destroy` go through a release-stable endpoint. - `lifetime: "session"` binds a stack to its creator through stdin; the owner destroys the stack when the creator exits. CLI schema shadows use it. - The owner sweeps dead owners' containers and session stacks in the same state root, holding each lease while it does. - Owner output goes to `owner.log`, and start failures include its tail. - Clients cache the owner connection per handle and drop it only when the owner is gone. Calls release their borrows in their own scope, and waiting for an owner can be interrupted. - Stack errors carry `owner-unavailable` or `release-mismatch`, so the CLI only treats a missing owner as "not running". - The owner exits explicitly once shutdown has flushed its output. - #6825's guarantees are kept in the new model: - The owner registers detached stacks under its lease, as it already did session stacks, and removes the registration if its startup fails. A failed first launch therefore leaves nothing behind. - When no owner can start because the container engine is unavailable, `destroy` removes the stack offline while holding its lease, and reports the skipped runtime cleanup. Stacks registered by develop builds from before this PR don't decode with it, because persisted stack state has no migrations and the package is unreleased. Destroy them with the build that created them, or remove `~/.supabase/stacks/<id>` and the containers labelled `com.supabase.stack=<id>`. Known gap: if an owner is SIGKILLed right after registering a stack, its registration is left behind. ## Stack Part 5 of 8 of the stack package simplification, based on #6837. Review and merge in order: 1. #6834 fix(stack): stop Postgres containers with a fast shutdown 2. #6835 fix(stack): harden readiness, port claims, and container storage 3. #6836 refactor(stack): flatten the owner process layers 4. #6837 refactor(stack): unify the database snapshot protocol across engines 5. #6838 feat(stack): lease owners with a lock and bind session stacks to creators ← this PR 6. #6839 feat(stack): ship the functions bootstrap with the package 7. #6840 refactor(stack): own composition policy and stack lookup in the package 8. #6841 feat(stack): add a testing entrypoint and derive the Promise API --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> | 5 天前 | |
chore: bump pnpm/bun/node, various cleanups (#6806) <!-- Before opening this PR, confirm the linked issue is open and carries the `open-for-contribution` label. PRs from external contributors that don't follow the workflow in CONTRIBUTING.md are closed automatically. @supabase members working from Linear tickets are exempt. --> ## Summary - bumps bun (`v1.4.1` ➡️ `v1.4.2`) - bumps `@types/bun` accordingly, which allows us to clean up our shared compilation options - bumps pnpm (`v12.4.0` ➡️ `v12.8.1`) - ~~enables the new [`autoDedupe`](https://pnpm.io/settings/dependency-resolution#autodedupe) option, which allows us to clean up a bit of config (**edit**: jk, this doesn't actually work 😔)~~ - bumps node.js (`v24.20.0` ➡️ `v24.21.0`) - bumps our mise/pnpm lockfiles accordingly - small cleanups in our `turbo.json` cache inputs (`mise.lock` makes it unnecessary to include `.bun-version` and `mise.toml` in our task inputs) - points to `.bun-version` in our stack tests --------- Co-authored-by: Julien Goux <hi@jgoux.dev> | 4 天前 | |
feat(stack): ship the functions bootstrap with the package (#6839) ## Problem The Functions recipe required every caller to pass the bundled edge-runtime main-service source. The CLI's build, the CLI's stack runtime and the package's tests each bundled the package's own `serve.main.ts` with esbuild. The full bundle was also persisted in every saved Functions creation. ## Change - Generate the bundle into a committed module with a drift test, wired into `pnpm generate`. The bundle is self-contained, so it works offline. - Make the Functions `bootstrap` input optional; the package default is never persisted. - Delete the CLI's stack bootstrap bundler, its build define, and the internal serve-main export. The legacy backend's bootstrap is untouched. ## Stack Part 6 of 8 of the stack package simplification, based on #6838. Review and merge in order: 1. #6834 fix(stack): stop Postgres containers with a fast shutdown 2. #6835 fix(stack): harden readiness, port claims, and container storage 3. #6836 refactor(stack): flatten the owner process layers 4. #6837 refactor(stack): unify the database snapshot protocol across engines 5. #6838 feat(stack): lease owners with a lock and bind session stacks to creators 6. #6839 feat(stack): ship the functions bootstrap with the package ← this PR 7. #6840 refactor(stack): own composition policy and stack lookup in the package 8. #6841 feat(stack): add a testing entrypoint and derive the Promise API --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> | 5 天前 | |
docs(repo): add a test-audit skill with an authoring gate and an audit mode (#6890) ## Problem Nothing limits test growth, and agents write a test for nearly every change. The rules against low-value tests live as prose in the "Test quality" section of `AGENTS.md`, which agents skim past when they add or review tests. ## Change - Adds `.agents/skills/test-audit/SKILL.md`, which loads whenever a test is written, changed or reviewed. It includes: - **Authoring gate:** four questions a new test must answer before it's added. - **Level rule:** one primary test per contract, at the strongest boundary that can reach it. - **Junk-pattern checklist:** fitted to our Effect layers, handler integration tests and `runSupabase()` e2e, including real-time waits on production timeouts. - **Retention bar and regression-test rule.** - **Read-only audit mode:** a retain / fix / consolidate / delete ledger with one evidence line per mark. - "Test quality" in `AGENTS.md` points to the skill and drops the redundant-coverage bullet, which the skill now covers. - `.claude/skills/` holds one symlink per repo skill (`effect`, `test-audit`) into `.agents/skills/`, so Claude Code discovers them automatically and Codex keeps reading `.agents/skills`. `.gitignore` now ignores `.claude/*` except `.claude/skills`, and local state such as worktrees and settings stays ignored. A new skill in `.agents/skills` needs a matching symlink. | 1 天前 | |
chore(repo): refresh reference repositories (#6620) Refresh the reference repository revisions so implementation work uses current upstream sources. Effect V4 now follows the canonical `Effect-TS/effect` repository on `main`, while the V3 reference explicitly follows `v3`. Advance the other references to their upstream branch tips; `effect-patterns` already points to the latest revision. Synchronize submodule URLs before installation or updates, and initialize these top-level source references without traversing upstream development dependencies. This also avoids a broken nested-submodule mapping in the latest `t3code` reference. Document how to inspect the matching Effect release tag when upstream source is ahead of the installed dependencies. | 18 天前 | |
chore: mise/pnpm/node housekeeping, enable pnpm global store (#6424) <!-- Before opening this PR, confirm the linked issue is open and carries the `open-for-contribution` label. PRs from external contributors that don't follow the workflow in CONTRIBUTING.md are closed automatically. @supabase members working from Linear tickets are exempt. --> ## Summary - upgrades mise lockfile using `mise lock --upgrade` (and bumps `mise` minimum version + github action accordingly) - upgrades `pnpm` to v12 - enables pnpm global store to speed up installation time in worktrees (and makes a few updates in our `pnpm-workspace` file so types and tests work properly) - upgrades node.js to latest v24 channel (24.18.0 => 24.20.0) - moves our node.js source-of-truth to `.node-version` — tiny and hopefully harmless change to better indicate to agents/etc. that we treat node and bun equally in this repo this PR was inspired by [these changes](https://supabase.slack.com/archives/C09PB9QMQG2/p1788257957531829) ## Checklist - [x] The PR title follows [Conventional Commits](https://www.conventionalcommits.org/) (e.g. `fix(cli): …`). - [x] Tests added or updated for the change. - [x] From the repository root, `pnpm check:all` passes; relevant package tests pass for every touched workspace, and `pnpm types:check` passes for each touched TypeScript workspace (or workspace declaring it). --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> | 30 天前 | |
feat(stack): ship the functions bootstrap with the package (#6839) ## Problem The Functions recipe required every caller to pass the bundled edge-runtime main-service source. The CLI's build, the CLI's stack runtime and the package's tests each bundled the package's own `serve.main.ts` with esbuild. The full bundle was also persisted in every saved Functions creation. ## Change - Generate the bundle into a committed module with a drift test, wired into `pnpm generate`. The bundle is self-contained, so it works offline. - Make the Functions `bootstrap` input optional; the package default is never persisted. - Delete the CLI's stack bootstrap bundler, its build define, and the internal serve-main export. The legacy backend's bootstrap is untouched. ## Stack Part 6 of 8 of the stack package simplification, based on #6838. Review and merge in order: 1. #6834 fix(stack): stop Postgres containers with a fast shutdown 2. #6835 fix(stack): harden readiness, port claims, and container storage 3. #6836 refactor(stack): flatten the owner process layers 4. #6837 refactor(stack): unify the database snapshot protocol across engines 5. #6838 feat(stack): lease owners with a lock and bind session stacks to creators 6. #6839 feat(stack): ship the functions bootstrap with the package ← this PR 7. #6840 refactor(stack): own composition policy and stack lookup in the package 8. #6841 feat(stack): add a testing entrypoint and derive the Promise API --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> | 5 天前 | |
refactor(cli): cover `shared/output` with effect lint (CLI-2561) (#6912) ## TL;DR brings the `output` area under the effect lint ## whats introduced? effect lint applied to the output layers, the output service and their tests: - `shared/output/**` allow list entry - the delayed task spinner is a fiber owned by the text layer instead of a `setTimeout`, so a task still pending when the layer closes no longer shows a spinner afterwards - `stream-json` events take their timestamp from the effect `Clock` when the line is written, same format as before - flagged `JSON.stringify` writes go through a `Schema` json encoder, same bytes out, and an unserializable payload still dies as a `TypeError` - `OutputTask.clear` is a plain effect instead of a zero arg function, so callers and mocks use `task.clear` - tests use `TestClock` instead of fake timers, a schema decoder instead of `JSON.parse`, and pin the exact `stream-json` lines ## ref: - closes: CLI-2561 | 3 天前 | |
feat(cli): add feedback add and delete commands for quick CLI feedback (#5988) ## What Adds a TS-only `supabase feedback` command family (from the [original brainstorm](https://supabase.slack.com/archives/C0BAGJBL49E/p1784320045234149)) so users — and agents — can send quick, low-friction feedback to the Supabase team without filing a GitHub issue, and revoke a submission later (e.g. an accidentally pasted secret): ```sh supabase feedback add "when I run multiple stacks in parallel I get port conflicts" # → Thanks for the feedback! # → To delete this feedback later, run: supabase feedback delete <token> supabase feedback delete 123e4567-e89b-12d3-a456-426614174000 ``` Part of [CLI-1946](https://linear.app/supabase/issue/CLI-1946); the delete command is [CLI-2188](https://linear.app/supabase/issue/CLI-2188). Scope evolved in [this thread](https://supabase.slack.com/archives/C07E5GFAHTM/p1785303671170249): `feedback add` (no `btw` alias) plus a token-based delete path, rather than full user-scoped CRUD. ## How `feedback add` works - **Message resolution**: positional args → piped stdin (non-TTY) → interactive prompt (TTY, text mode) → error. Messages starting with a dash use the `--` sentinel. Piped stdin is read in constant memory with a 64 KB cap; a read error mid-pipe discards the partial buffer rather than submitting a truncated message. Messages over the 1000-character limit are rejected client-side (counted in code points, matching Postgres `char_length`). - **Transport**: submits through the `SECURITY DEFINER` RPC `submit_interfaces_feedback` (supabase/supabase#48420) via `supabase-js` — the table has no insert grant, so the RPC is the only door and the delete token is always server-generated. The committed keys are publishable (anon) keys, safe to ship in the binary. 10s timeout. - **Delete token**: the RPC returns a uuid `delete_token` exactly once. Text mode prints it with a "to delete this later" hint (including `--project-ref <ref>` when the submission carried one, since the row can only be deleted with that ref presented); `json`/`stream-json` carry it as `delete_token` in the result payload. The CLI never persists it. - **Submission context**: CLI version, user agent, OS/arch, agent detection (`is_agent`/`agent_name` via `@vercel/detect-agent`, to support the activation analysis in AI-961), and the linked project ref. `metadata.source: "cli"` distinguishes CLI rows from the future MCP path. The access token is never sent. The persisted gotrue user id (`distinct_id` in `telemetry.json`, stamped at login) is sent as `user_id` **only** when the user is logged in and telemetry consent is granted — best-effort attribution; logged-out or opted-out runs omit it. A row submitted with a `user_id` can only be deleted by the same account. - **Project ref resolution**: `SUPABASE_PROJECT_ID` → `<workdir>/supabase/.temp/project-ref` (the file `supabase link` writes) → omitted. A malformed `SUPABASE_PROJECT_ID` fails with the shared invalid-ref error, like every other command's explicit ref. The file is read directly (not via `ProjectRefResolver`, whose prompt path needs the platform API) so feedback works logged-out; a broken or malformed ref file degrades to "unlinked". - **Environments**: the feedback backend follows the resolved profile the same way the Management API URL does. `supabase-staging`/`supabase-local` post to the persistent staging branch of the feedback project; every other profile (including YAML-file profiles) posts to the production feedback project. Connection constants live in `src/shared/feedback/feedback-client.layer.ts`. ## How `feedback delete <token>` works - **Validation**: the token must be a UUID (checked client-side to avoid PostgREST's cryptic uuid-cast error) and is lowercased before sending. - **No read, ever**: the CLI never fetches the feedback text. Deleting is harmless to the user (the row exists for Supabase's benefit), so nothing is shown first; the only request is the DELETE below. With no client reading rows, the backend's anon read path has nothing to serve and is removed in a follow-up ([CLI-2406](https://linear.app/supabase/issue/CLI-2406)). The delete policy is unchanged. - **Confirmation**: interactive text mode prompts (`Permanently delete this feedback? [y/N]`) as the guard against a mistyped or pasted token; `--yes`/`SUPABASE_YES` skips it. The prompt runs before the row's existence is known, so a wrong token gets the prompt and then the not-found error. Machine modes (`json`/`stream-json`, and `-o json`) fail loudly without `--yes` rather than deleting silently — same contract as `logout`. Both stdin and stdout must be TTYs for the prompt, so `printf 'y' | supabase feedback delete <token>` cannot confirm a delete without `--yes`. - **Deletion**: a hard `DELETE` with `Prefer: count=exact`; the CLI verifies `Content-Range` reports exactly one row. Zero rows → a friendly not-found error covering all three indistinguishable causes (wrong token, already deleted, project-ref/user-id context mismatch). Authorization is the `x-feedback-token` request header matched by RLS — the `delete_token=eq.` URL filter only satisfies PostgREST's filterless-delete rejection. `--debug` request lines redact the filter. - **Context gate**: rows submitted from a linked project also require the matching `x-feedback-project-ref` header, and rows submitted while logged in require `x-feedback-user-id`. The delete command resolves the ref as `--project-ref` → `SUPABASE_PROJECT_ID` → linked-ref file (flag and env validated, file soft) and always sends whatever resolves (extra context against a context-free row is ignored server-side). The user-id header is not consent-gated: it is functional auth context, and gating it would strand rows submitted before an opt-out. - Machine modes return an acknowledgement only: `--output-format json` gives `{ "message": "Feedback deleted." }`, `-o json` gives `{ "deleted": true }`. ## Privacy note for reviewers The feedback message, the delete token, and the `--project-ref` value go **only** to the feedback backend — never to PostHog. Message and token are positional arguments, which `extractChangedFlagNames` structurally excludes from the `flags` telemetry property; `--project-ref` is recorded by name only with its value redacted. Regression tests assert none of them appear in captured analytics events. `user_id` is sent to the feedback backend under the conditions above and is documented in `add/SIDE_EFFECTS.md`. ## Reviewer-relevant context - The shared service was reshaped from `FeedbackSubmitter` (insert-only) into `FeedbackClient` (`submit`/`delete`) in `src/shared/feedback/feedback-client.{service,layer}.ts`, and the profile→environment mapping and cli-config layer wiring were hoisted to the feedback family root (`feedback.layers.ts`, `feedback-project-ref.ts`) now that two commands share them. - `FeedbackBackendError` carries a `reason` (`response` vs `transport`) so a PostgREST rejection classifies as `apiStatus` in error telemetry while network failures stay `externalNetwork`. postgrest-js reports fetch rejections, timeouts, and aborts as an error envelope with `status: 0`, which is the discriminator. - The feedback client speaks `fetch` (supabase-js), not Effect's `HttpClient`, so `--debug` logging and `--dns-resolver https` compose at the fetch boundary (`feedbackFetch`). Along the way the shared DoH wrapper gained two fixes that apply to every command: WHATWG `Headers` instances survive the rewrite, and the request's abort signal now cancels the DoH lookup itself. - `src/shared/feedback/database.types.ts` is generated (`pnpm gen:feedback-types`, from the production project) and excluded from formatting/knip; it is marked `linguist-generated`. - The real-backend golden path (add → delete round trip against the staging branch, cleaning up its own row) is `add.live.test.ts` under the gated live project. The default e2e file only exercises subcommand routing with zero network. - The commands are registered in `docs-spec.tables.ts` (`other-commands` tag) and each has a `SIDE_EFFECTS.md`. - **Heads-up on `CommandSettings.projectId`**: it is a bare `SUPABASE_PROJECT_ID` env passthrough — it does not read `config.toml` or the linked-project file, so it is `None` in a linked project unless that env var is set. An earlier revision of this branch used it directly as "the linked project ref", which meant `project_ref` was always `null` in practice. The agent-guide row that described it as resolving project-id from `config.toml` was corrected here, since that phrasing is what made the field look project-aware. - `services.integration.test.ts` now uses an isolated temp workdir instead of `process.cwd()`, fixing machine-dependent behavior when the developer has local `supabase start` state. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> Co-authored-by: Colum Ferry <cferry09@gmail.com> | 23 天前 | |
docs(repo): add a test-audit skill with an authoring gate and an audit mode (#6890) ## Problem Nothing limits test growth, and agents write a test for nearly every change. The rules against low-value tests live as prose in the "Test quality" section of `AGENTS.md`, which agents skim past when they add or review tests. ## Change - Adds `.agents/skills/test-audit/SKILL.md`, which loads whenever a test is written, changed or reviewed. It includes: - **Authoring gate:** four questions a new test must answer before it's added. - **Level rule:** one primary test per contract, at the strongest boundary that can reach it. - **Junk-pattern checklist:** fitted to our Effect layers, handler integration tests and `runSupabase()` e2e, including real-time waits on production timeouts. - **Retention bar and regression-test rule.** - **Read-only audit mode:** a retain / fix / consolidate / delete ledger with one evidence line per mark. - "Test quality" in `AGENTS.md` points to the skill and drops the redundant-coverage bullet, which the skill now covers. - `.claude/skills/` holds one symlink per repo skill (`effect`, `test-audit`) into `.agents/skills/`, so Claude Code discovers them automatically and Codex keeps reading `.agents/skills`. `.gitignore` now ignores `.claude/*` except `.claude/skills`, and local state such as worktrees and settings stays ignored. A new skill in `.agents/skills` needs a matching symlink. | 1 天前 | |
Global architecture (#3) * first command design * first command design * test coverage setup * refactor * hello Effect * agents doc * use env from Effect * convert everything to Effect * CliConfig * construct url correctly * tests * reuse mocks * isolate code * refactor command type * docs generation * --usage convention * skills support * bump * fumadocs * bump * use new global flags API * mirror old cli reading patterns * services are fully covered now * effect patterns * process compose, the Effect way! * process-compose the Effect way * unless stopped and timeout * hook output and global shutdown timeout * feat(local): scaffold @supabase/local package Add the packages/local workspace package with package.json, tsconfig.json, and src/index.ts placeholder. Wires in workspace dependency on @supabase/process-compose and the same Effect pre-release URLs as process-compose. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat(local): add typed error definitions for local stack management Implements 5 tagged error types (BinaryNotFoundError, DownloadError, ChecksumMismatchError, StackBuildError, PortConflictError) using Effect's Data.TaggedError pattern and exports them from index.ts. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat(local): add platform detection with asset name mapping Implements PlatformInfo type, detectPlatform Effect, and pure mapping functions (postgresAssetName, postgrestAssetName, authAssetName) for resolving binary asset names per OS/arch combination. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat(local): add service definition factories for postgres, postgrest, and auth Pure factory functions that produce ServiceDef objects for process-compose. Includes TDD with vitest tests covering all four factory variants (native and Docker auth). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat(local): add StackBuilder service; refactor buildGraph to return Effect - Refactor `buildGraph` in process-compose to return `Effect.Effect<ResolvedGraph, CyclicDependencyError | MissingDependencyError>` instead of throwing - Update all callers (DependencyGraph.test.ts, Orchestrator.test.ts, Orchestrator.e2e.test.ts) to use `Effect.runSync(buildGraph(defs))` - Create `packages/local/src/StackBuilder.ts` with `StackConfig` interface and `StackBuilder` service that resolves binaries, falls back to Docker for auth, filters excluded services, and calls `buildGraph` - Create `packages/local/tests/helpers/mocks.ts` with `mockBinaryResolver` factory - Create `packages/local/src/StackBuilder.test.ts` with 3 integration tests (native binaries, docker fallback, exclude) - Export `StackBuilder` and `StackConfig` from `packages/local/src/index.ts` Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat(local): add LocalStack service with JWT generation and Orchestrator wiring Implements the main LocalStack Effect service that wires StackBuilder -> Orchestrator and exposes start/stop/restart, connection info, and HS256 JWT token generation for anon and service_role keys. Includes integration tests covering URL construction, JWT structure validation, and signature verification. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat(local): add createStack convenience API with Promise-based wrapper Wraps all Effect machinery behind a single async function for ergonomic use in tests and non-Effect code; exports Stack and CreateStackOptions types from the package index. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat(cli): add start command wired to LocalStack service Adds the `supabase start` command that will drive the local Supabase development stack. The command definition, handler, and barrel index are created following the login command pattern. A placeholder LocalStack layer is provided at the command level so all type requirements are satisfied at compile time; it will be replaced with the real LocalStack.layer(config) once config.toml parsing is wired up. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * add integration tests for start command and mockLocalStack helper Adds mockLocalStack factory to test helpers with stateful started/stopped tracking and Stream.empty for allStateChanges so tests complete without hanging. Creates three integration tests covering stack startup, info message content, and custom URL configuration. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat(local): add BinaryResolver service with download, cache, and checksum verification Also clean up knip ignoreDependencies now that packages are in use. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * docs: add @supabase/local design and implementation plan Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: address code review findings for @supabase/local - StackBuilder skips binary resolution for excluded services instead of resolving eagerly then disabling - BinaryResolver uses descriptive url field in error wrapping instead of misleading service name or hardcoded "checksum" - Start handler test covers state stream changes for 100% branch coverage Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * local package * local stack * simplify port allocation * simplify port allocation * refactor * properly handle docker shutdown for postgres * bump * detach feature * optimize probes * atom / ink integration * fix stack resource cleanup Harden stack shutdown so foreground, detached, and one-shot paths clean up child processes, Docker containers, state, and auto-managed data directories reliably across the CLI and stack layers. Made-with: Cursor * make process supervision platform-neutral Move service ownership and orphan cleanup into @supabase/process-compose so stack resources are torn down consistently across Unix and Windows without shell wrappers. Update CLI start handling, leak regressions, and internal docs to verify the new supervision model across foreground and detached flows. Made-with: Cursor * remove legacy probe and shutdown paths Tighten process-compose around the supervised ownership model so shell-style exec probes and unsupervised group-kill semantics cannot silently slip back in. Made-with: Cursor * attach is detach in disguise :) * minimize node usage * fix binary cache prewarm * symlink claude * reorganize files * refactor * avoid leaks in tests * fix regression * refactor * refactor * refactor * reorganize code * comments * reorganize files * calm down knip * bump --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> | 6 个月前 | |
refactor(cli): remove the legacy shell concept and naming prefix (#6525) ## Summary #6465 removed the `next/` shell and #6486 flattened `legacy/` into `src/`, but the two-shell world lived on in the names: every exported symbol in the CLI tree still carried the mandatory `Legacy`/`legacy`/`LEGACY` prefix, 368 files were named `legacy-*.ts`, `apps/cli/AGENTS.md` still told agents the prefix was required, and the harness, build, and release tooling still selected a "shell". This PR removes the concept end to end so `src/` reads as the one CLI it is. ### The rename (`bad664be1`) - ~3,050 identifiers lose the prefix (`LegacyBranchesCreateFlags` → `BranchesCreateFlags`, `legacyRoot` → `rootCommand`, …), together with their `Data.TaggedError` tags, `Effect.fn` span names (`legacy.branches.create` → `branches.create`), and service tags (`supabase/legacy/*` → `supabase/cli/*`). - 368 files are renamed (`legacy-foo.ts` → `foo.ts`); `src/shared/legacy/*` moves into `src/command-internal/`; `tests/helpers/legacy-mocks.ts` becomes `command-mocks.ts` because `mocks.ts` already existed. - Where a CLI-tree service collides with a same-named `src/shared/` service, the CLI-tree one is qualified with `Command` rather than getting a new shell prefix: `CommandSettings` (was `LegacyCliSettings`), `CommandCredentials`, `CommandPlatformApi`. AGENTS.md documents this and marks the pairs as slated to consolidate. Other clash-driven names: `withCommandTelemetry` (vs shared `withCommandInstrumentation`), `AccessTokenRequiredError`, `ProjectRefNotLinkedError`, `GoOutputFormat`. - Wrappers and aliases that existed only to satisfy the prefix rule are deleted instead of renamed (`functions serve` re-exports, `usesSlimRuntime`, the `formatDebugId` alias). - Three variable shadows the rename would have introduced silently (`lang`, `globalFlagValues`, `resolved`) were caught with an oxlint `no-shadow` before/after diff and renamed. Genuine product concepts keep the word: `--legacy-bundle`, legacy API keys and signing keys, the pre-profile keyring account fallback, the pre-consent `telemetry.json` format, the migra "legacy engine" vs the pg-delta "next" engine, and the pg-delta legacy-tree export. ### The rule and the framing (`442bc60b1`) - `apps/cli/AGENTS.md`: the "Mandatory `Legacy`/`legacy` prefix on all exports" section is replaced by a short "Naming" section; the header note now says the prefix and both shell trees are gone; the `next/` dual-write and "legacy-only" guidance is removed. - README, CONTRIBUTING, the lint config comment, `packages/config/docs`, `SIDE_EFFECTS.md` files and ~300 code comments drop "legacy shell"/"legacy command" wording. ### The remaining shell plumbing (`994f75685`) - Compiled binary is `dist/supabase` (was `dist/supabase-legacy`). - `@supabase/cli-test-helpers`: `createHarness(options)` — the `CLITarget`/`CLI_HARNESS_TARGET` axis (`ts-legacy`/`ts-next`) is gone from the harness, `apps/cli-e2e`, `test.yml`, and the `live-e2e.yml` matrix. The harness always uses the profile-file path, which is the one the CLI actually reads. - `runSupabase`/`spawnSupabase` drop the `entrypoint: "legacy"` option (111 call sites). - `scripts/build.ts` drops `--shell`; the `shell` input is removed from `build-cli-artifacts`, `release-shared`, `release`, `release-smoke-test`, and `publish-preview-cli-packages`, and the artifact cache keys drop the shell segment on both the producer and consumer side. - `pnpm cli-release` drops `--legacy|--next`. It was also still compiling `src/<shell>/main.ts`, a path that stopped existing in #6486, so the local release ring works again. - `pnpm dev:legacy` → `pnpm dev`, `pnpm build:legacy` → `pnpm build:binary`. - `docs/platform-command-generation.md` (a `next/`-only feature) is deleted; the `next/`-only rows are dropped from `go-cli-divergences.md`; "`undefined` in `next`"-style comments in `shared/` are reworded to describe library callers. ## Reviewer notes - **User-visible:** `--output-format json` error `code` values are the tagged-error tags, so they lose the `Legacy` prefix (e.g. `LegacyPlatformAuthRequiredError` → `AccessTokenRequiredError`). Span names lose `legacy.` and service tags move, but neither leaves the machine. - The `Command*` qualifier for the three shared/CLI service pairs is the one naming judgment call worth a look; each is a single-token rename if a different name is preferred. - `@supabase/cli-go#lint:check` fails on this branch exactly as it does on `develop` under a current local golangci-lint (gosec G115/G118); no Go source is touched here. | 25 天前 | |
refactor(cli): remove the legacy shell concept and naming prefix (#6525) ## Summary #6465 removed the `next/` shell and #6486 flattened `legacy/` into `src/`, but the two-shell world lived on in the names: every exported symbol in the CLI tree still carried the mandatory `Legacy`/`legacy`/`LEGACY` prefix, 368 files were named `legacy-*.ts`, `apps/cli/AGENTS.md` still told agents the prefix was required, and the harness, build, and release tooling still selected a "shell". This PR removes the concept end to end so `src/` reads as the one CLI it is. ### The rename (`bad664be1`) - ~3,050 identifiers lose the prefix (`LegacyBranchesCreateFlags` → `BranchesCreateFlags`, `legacyRoot` → `rootCommand`, …), together with their `Data.TaggedError` tags, `Effect.fn` span names (`legacy.branches.create` → `branches.create`), and service tags (`supabase/legacy/*` → `supabase/cli/*`). - 368 files are renamed (`legacy-foo.ts` → `foo.ts`); `src/shared/legacy/*` moves into `src/command-internal/`; `tests/helpers/legacy-mocks.ts` becomes `command-mocks.ts` because `mocks.ts` already existed. - Where a CLI-tree service collides with a same-named `src/shared/` service, the CLI-tree one is qualified with `Command` rather than getting a new shell prefix: `CommandSettings` (was `LegacyCliSettings`), `CommandCredentials`, `CommandPlatformApi`. AGENTS.md documents this and marks the pairs as slated to consolidate. Other clash-driven names: `withCommandTelemetry` (vs shared `withCommandInstrumentation`), `AccessTokenRequiredError`, `ProjectRefNotLinkedError`, `GoOutputFormat`. - Wrappers and aliases that existed only to satisfy the prefix rule are deleted instead of renamed (`functions serve` re-exports, `usesSlimRuntime`, the `formatDebugId` alias). - Three variable shadows the rename would have introduced silently (`lang`, `globalFlagValues`, `resolved`) were caught with an oxlint `no-shadow` before/after diff and renamed. Genuine product concepts keep the word: `--legacy-bundle`, legacy API keys and signing keys, the pre-profile keyring account fallback, the pre-consent `telemetry.json` format, the migra "legacy engine" vs the pg-delta "next" engine, and the pg-delta legacy-tree export. ### The rule and the framing (`442bc60b1`) - `apps/cli/AGENTS.md`: the "Mandatory `Legacy`/`legacy` prefix on all exports" section is replaced by a short "Naming" section; the header note now says the prefix and both shell trees are gone; the `next/` dual-write and "legacy-only" guidance is removed. - README, CONTRIBUTING, the lint config comment, `packages/config/docs`, `SIDE_EFFECTS.md` files and ~300 code comments drop "legacy shell"/"legacy command" wording. ### The remaining shell plumbing (`994f75685`) - Compiled binary is `dist/supabase` (was `dist/supabase-legacy`). - `@supabase/cli-test-helpers`: `createHarness(options)` — the `CLITarget`/`CLI_HARNESS_TARGET` axis (`ts-legacy`/`ts-next`) is gone from the harness, `apps/cli-e2e`, `test.yml`, and the `live-e2e.yml` matrix. The harness always uses the profile-file path, which is the one the CLI actually reads. - `runSupabase`/`spawnSupabase` drop the `entrypoint: "legacy"` option (111 call sites). - `scripts/build.ts` drops `--shell`; the `shell` input is removed from `build-cli-artifacts`, `release-shared`, `release`, `release-smoke-test`, and `publish-preview-cli-packages`, and the artifact cache keys drop the shell segment on both the producer and consumer side. - `pnpm cli-release` drops `--legacy|--next`. It was also still compiling `src/<shell>/main.ts`, a path that stopped existing in #6486, so the local release ring works again. - `pnpm dev:legacy` → `pnpm dev`, `pnpm build:legacy` → `pnpm build:binary`. - `docs/platform-command-generation.md` (a `next/`-only feature) is deleted; the `next/`-only rows are dropped from `go-cli-divergences.md`; "`undefined` in `next`"-style comments in `shared/` are reworded to describe library callers. ## Reviewer notes - **User-visible:** `--output-format json` error `code` values are the tagged-error tags, so they lose the `Legacy` prefix (e.g. `LegacyPlatformAuthRequiredError` → `AccessTokenRequiredError`). Span names lose `legacy.` and service tags move, but neither leaves the machine. - The `Command*` qualifier for the three shared/CLI service pairs is the one naming judgment call worth a look; each is a single-token rename if a different name is preferred. - `@supabase/cli-go#lint:check` fails on this branch exactly as it does on `develop` under a current local golangci-lint (gosec G115/G118); no Go source is touched here. | 25 天前 | |
chore: root-level tsconfig + esm fixes (#6656) <!-- Before opening this PR, confirm the linked issue is open and carries the `open-for-contribution` label. PRs from external contributors that don't follow the workflow in CONTRIBUTING.md are closed automatically. @supabase members working from Linear tickets are exempt. --> ## Summary noticed that our typescript LSP errors out when loading the scripts in the `tools/` directory, so this PR fixes a couple things - [x] converts our root-level package from CommonJS to ESM - [x] converts a couple root-level configuration files over to ESM - [x] modernizes our top-level `tsconfig.json` ## Checklist - [x] The PR title follows [Conventional Commits](https://www.conventionalcommits.org/) (e.g. `fix(cli): …`). - [x] From the repository root, `pnpm check:all` passes; relevant package tests pass for every touched workspace, and `pnpm types:check` passes for each touched TypeScript workspace (or workspace declaring it). | 16 天前 | |
docs(cli): modernize README and add installer (#5428) ## Summary Refreshes the root README with a cleaner, more modern first impression inspired by opencode: a centered Supabase CLI lockup, focused npm/build badges, a compact installation block, and a shorter project-start flow. Adds a first-party `install` script for curl-based installs. The script detects platform and architecture, supports version-pinned installs, verifies release checksums when available, preserves the companion `supabase-go` binary from release archives, and handles Alpine/musl installs via the published `.apk` package. Also uploads the installer as part of future GitHub Releases so release consumers can use the script as a stable artifact. | 3 个月前 | |
feat(stack): ship the functions bootstrap with the package (#6839) ## Problem The Functions recipe required every caller to pass the bundled edge-runtime main-service source. The CLI's build, the CLI's stack runtime and the package's tests each bundled the package's own `serve.main.ts` with esbuild. The full bundle was also persisted in every saved Functions creation. ## Change - Generate the bundle into a committed module with a drift test, wired into `pnpm generate`. The bundle is self-contained, so it works offline. - Make the Functions `bootstrap` input optional; the package default is never persisted. - Delete the CLI's stack bootstrap bundler, its build define, and the internal serve-main export. The legacy backend's bootstrap is untouched. ## Stack Part 6 of 8 of the stack package simplification, based on #6838. Review and merge in order: 1. #6834 fix(stack): stop Postgres containers with a fast shutdown 2. #6835 fix(stack): harden readiness, port claims, and container storage 3. #6836 refactor(stack): flatten the owner process layers 4. #6837 refactor(stack): unify the database snapshot protocol across engines 5. #6838 feat(stack): lease owners with a lock and bind session stacks to creators 6. #6839 feat(stack): ship the functions bootstrap with the package ← this PR 7. #6840 refactor(stack): own composition policy and stack lookup in the package 8. #6841 feat(stack): add a testing entrypoint and derive the Promise API --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> | 5 天前 | |
chore: bump pnpm/bun/node, various cleanups (#6806) <!-- Before opening this PR, confirm the linked issue is open and carries the `open-for-contribution` label. PRs from external contributors that don't follow the workflow in CONTRIBUTING.md are closed automatically. @supabase members working from Linear tickets are exempt. --> ## Summary - bumps bun (`v1.4.1` ➡️ `v1.4.2`) - bumps `@types/bun` accordingly, which allows us to clean up our shared compilation options - bumps pnpm (`v12.4.0` ➡️ `v12.8.1`) - ~~enables the new [`autoDedupe`](https://pnpm.io/settings/dependency-resolution#autodedupe) option, which allows us to clean up a bit of config (**edit**: jk, this doesn't actually work 😔)~~ - bumps node.js (`v24.20.0` ➡️ `v24.21.0`) - bumps our mise/pnpm lockfiles accordingly - small cleanups in our `turbo.json` cache inputs (`mise.lock` makes it unnecessary to include `.bun-version` and `mise.toml` in our task inputs) - points to `.bun-version` in our stack tests --------- Co-authored-by: Julien Goux <hi@jgoux.dev> | 4 天前 | |
chore: mise/pnpm/node housekeeping, enable pnpm global store (#6424) <!-- Before opening this PR, confirm the linked issue is open and carries the `open-for-contribution` label. PRs from external contributors that don't follow the workflow in CONTRIBUTING.md are closed automatically. @supabase members working from Linear tickets are exempt. --> ## Summary - upgrades mise lockfile using `mise lock --upgrade` (and bumps `mise` minimum version + github action accordingly) - upgrades `pnpm` to v12 - enables pnpm global store to speed up installation time in worktrees (and makes a few updates in our `pnpm-workspace` file so types and tests work properly) - upgrades node.js to latest v24 channel (24.18.0 => 24.20.0) - moves our node.js source-of-truth to `.node-version` — tiny and hopefully harmless change to better indicate to agents/etc. that we treat node and bun equally in this repo this PR was inspired by [these changes](https://supabase.slack.com/archives/C09PB9QMQG2/p1788257957531829) ## Checklist - [x] The PR title follows [Conventional Commits](https://www.conventionalcommits.org/) (e.g. `fix(cli): …`). - [x] Tests added or updated for the change. - [x] From the repository root, `pnpm check:all` passes; relevant package tests pass for every touched workspace, and `pnpm types:check` passes for each touched TypeScript workspace (or workspace declaring it). --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> | 30 天前 | |
chore: bump pnpm/bun/node, various cleanups (#6806) <!-- Before opening this PR, confirm the linked issue is open and carries the `open-for-contribution` label. PRs from external contributors that don't follow the workflow in CONTRIBUTING.md are closed automatically. @supabase members working from Linear tickets are exempt. --> ## Summary - bumps bun (`v1.4.1` ➡️ `v1.4.2`) - bumps `@types/bun` accordingly, which allows us to clean up our shared compilation options - bumps pnpm (`v12.4.0` ➡️ `v12.8.1`) - ~~enables the new [`autoDedupe`](https://pnpm.io/settings/dependency-resolution#autodedupe) option, which allows us to clean up a bit of config (**edit**: jk, this doesn't actually work 😔)~~ - bumps node.js (`v24.20.0` ➡️ `v24.21.0`) - bumps our mise/pnpm lockfiles accordingly - small cleanups in our `turbo.json` cache inputs (`mise.lock` makes it unnecessary to include `.bun-version` and `mise.toml` in our task inputs) - points to `.bun-version` in our stack tests --------- Co-authored-by: Julien Goux <hi@jgoux.dev> | 4 天前 | |
feat(cli): upgrade pg-delta to 1.0.0-alpha.56 (#6913) ## Summary **TL;DR:** The CLI now bundles `@supabase/pg-delta@1.0.0-alpha.56` and `@supabase/pg-topo@1.0.0-alpha.7`. `db diff`, `db pull`, and declarative sync pick up the engine fixes from alpha.53 through alpha.56. A partition-key type change drops and recreates the table, because Postgres rejects an in-place `ALTER` on a key column. ### Before ```mermaid flowchart LR cmd["db diff / pull / declarative sync"] --> old["pg-delta alpha.52"] old --> fail["enum cast, grants, pgmq SCHEMA, range order, and partition-key ALTER fail or churn"] ``` ### After ```mermaid flowchart LR cmd["db diff / pull / declarative sync"] --> new["pg-delta alpha.56"] new --> ok["those plans converge"] new --> drop["partition-key change drops the table"] ``` ## Why `develop` was still on `1.0.0-alpha.52`. The published alphas since then fix enum retypes through `text`, domain `NOT NULL` on PostgreSQL 17, column and identity-sequence grants, `pgmq` without a redundant `SCHEMA` clause, range-type ordering, and partition-key changes that previously failed apply. Dogfood on a linked staging project converged for push, an empty linked diff, a one-column pull, and declarative generate then sync. ## What changed - Bump `@supabase/pg-delta` from `1.0.0-alpha.52` to `1.0.0-alpha.56`. - Bump peer `@supabase/pg-topo` from `1.0.0-alpha.6` to `1.0.0-alpha.7`, which alpha.56 requires. - Point `minimumReleaseAgeExclude` at those two versions. ## Linked issue Supabase maintainer change; no public issue to close. | 3 天前 | |
feat(cli): upgrade pg-delta to 1.0.0-alpha.56 (#6913) ## Summary **TL;DR:** The CLI now bundles `@supabase/pg-delta@1.0.0-alpha.56` and `@supabase/pg-topo@1.0.0-alpha.7`. `db diff`, `db pull`, and declarative sync pick up the engine fixes from alpha.53 through alpha.56. A partition-key type change drops and recreates the table, because Postgres rejects an in-place `ALTER` on a key column. ### Before ```mermaid flowchart LR cmd["db diff / pull / declarative sync"] --> old["pg-delta alpha.52"] old --> fail["enum cast, grants, pgmq SCHEMA, range order, and partition-key ALTER fail or churn"] ``` ### After ```mermaid flowchart LR cmd["db diff / pull / declarative sync"] --> new["pg-delta alpha.56"] new --> ok["those plans converge"] new --> drop["partition-key change drops the table"] ``` ## Why `develop` was still on `1.0.0-alpha.52`. The published alphas since then fix enum retypes through `text`, domain `NOT NULL` on PostgreSQL 17, column and identity-sequence grants, `pgmq` without a redundant `SCHEMA` clause, range-type ordering, and partition-key changes that previously failed apply. Dogfood on a linked staging project converged for push, an empty linked diff, a one-column pull, and declarative generate then sync. ## What changed - Bump `@supabase/pg-delta` from `1.0.0-alpha.52` to `1.0.0-alpha.56`. - Bump peer `@supabase/pg-topo` from `1.0.0-alpha.6` to `1.0.0-alpha.7`, which alpha.56 requires. - Point `minimumReleaseAgeExclude` at those two versions. ## Linked issue Supabase maintainer change; no public issue to close. | 3 天前 | |
chore: root-level tsconfig + esm fixes (#6656) <!-- Before opening this PR, confirm the linked issue is open and carries the `open-for-contribution` label. PRs from external contributors that don't follow the workflow in CONTRIBUTING.md are closed automatically. @supabase members working from Linear tickets are exempt. --> ## Summary noticed that our typescript LSP errors out when loading the scripts in the `tools/` directory, so this PR fixes a couple things - [x] converts our root-level package from CommonJS to ESM - [x] converts a couple root-level configuration files over to ESM - [x] modernizes our top-level `tsconfig.json` ## Checklist - [x] The PR title follows [Conventional Commits](https://www.conventionalcommits.org/) (e.g. `fix(cli): …`). - [x] From the repository root, `pnpm check:all` passes; relevant package tests pass for every touched workspace, and `pnpm types:check` passes for each touched TypeScript workspace (or workspace declaring it). | 16 天前 | |
chore: bump pnpm/bun/node, various cleanups (#6806) <!-- Before opening this PR, confirm the linked issue is open and carries the `open-for-contribution` label. PRs from external contributors that don't follow the workflow in CONTRIBUTING.md are closed automatically. @supabase members working from Linear tickets are exempt. --> ## Summary - bumps bun (`v1.4.1` ➡️ `v1.4.2`) - bumps `@types/bun` accordingly, which allows us to clean up our shared compilation options - bumps pnpm (`v12.4.0` ➡️ `v12.8.1`) - ~~enables the new [`autoDedupe`](https://pnpm.io/settings/dependency-resolution#autodedupe) option, which allows us to clean up a bit of config (**edit**: jk, this doesn't actually work 😔)~~ - bumps node.js (`v24.20.0` ➡️ `v24.21.0`) - bumps our mise/pnpm lockfiles accordingly - small cleanups in our `turbo.json` cache inputs (`mise.lock` makes it unnecessary to include `.bun-version` and `mise.toml` in our task inputs) - points to `.bun-version` in our stack tests --------- Co-authored-by: Julien Goux <hi@jgoux.dev> | 4 天前 | |
feat: wrap go binary in ts for legacy cli handling (#31) ## What kind of change does this PR introduce? Chore / feat: wraps the Go CLI binary in TypeScript/Effect for the legacy shell, ships the Go binary alongside the TS build, and adds a record-and-replay e2e compatibility test suite for verifying output parity between the Go CLI and the TypeScript port. ## What is the current behavior? The legacy shell has no TypeScript command/handler layer — all CLI invocations go directly to the Go binary, with no automated way to verify that the TS port produces identical output. ## What is the new behavior? **Legacy command wrapper layer** Every Go CLI command is wrapped in an Effect CLI command tree under `src/legacy/commands/`. Each command has a `.command.ts` (flag wiring, Effect CLI definition) and a `.handler.ts` (Phase 0: proxies to Go binary via `LegacyGoProxy`; Phase 1+: native TypeScript implementation). All Go CLI persistent global flags (`--profile`, `--debug`, `--workdir`, `--output`, etc.) are declared on `legacyRoot` via `Command.withGlobalFlags` and forwarded automatically through the proxy — no per-handler changes needed. The Go binary is cross-compiled for each target platform and shipped alongside the TS SFE in the platform packages. **Record-and-replay e2e compatibility suite** A new `packages/cli-test-helpers` package provides a `createHarness`/`exec` API for spawning Go, `ts-legacy`, and `ts-next` CLI subprocesses, plus a parity comparison engine (`normalize`, `parseTable`, `assertTableParity`, `runParity`) for asserting output equivalence. A new `apps/cli-e2e` Vitest suite runs against a Bun.serve replay server. In replay mode it serves committed fixtures; in record mode it proxies to staging and writes normalised fixture pairs (tokens, UUIDs, project refs, and timestamps replaced with stable placeholders). Control-plane endpoints (`/_ctrl/requests`, `/_ctrl/error`, `/_ctrl/overrides`) enable assertions and error injection without network access. Initial fixture coverage: `projects list`, `orgs list`, `functions list`, `secrets list`, `branches list`. The default test target is `ts-legacy`, so `pnpm test` validates the TS port against committed fixtures without requiring network access or credentials. Named scripts: `pnpm test:go`, `pnpm test:legacy`, `pnpm test:next`, `pnpm record`. Fixes CLI-1287, CLI-1347, CLI-1348, CLI-1349 | 5 个月前 | |
chore: root-level tsconfig + esm fixes (#6656) <!-- Before opening this PR, confirm the linked issue is open and carries the `open-for-contribution` label. PRs from external contributors that don't follow the workflow in CONTRIBUTING.md are closed automatically. @supabase members working from Linear tickets are exempt. --> ## Summary noticed that our typescript LSP errors out when loading the scripts in the `tools/` directory, so this PR fixes a couple things - [x] converts our root-level package from CommonJS to ESM - [x] converts a couple root-level configuration files over to ESM - [x] modernizes our top-level `tsconfig.json` ## Checklist - [x] The PR title follows [Conventional Commits](https://www.conventionalcommits.org/) (e.g. `fix(cli): …`). - [x] From the repository root, `pnpm check:all` passes; relevant package tests pass for every touched workspace, and `pnpm types:check` passes for each touched TypeScript workspace (or workspace declaring it). | 16 天前 |
在本地开发,并通过终端部署到 Supabase 平台。
Supabase CLI 让 Supabase 平台在终端触手可及。运行完整本地栈,管理数据库迁移,部署 Edge Functions,生成类型,并自动化项目工作流。
安装
# YOLO
curl -fsSL https://raw.githubusercontent.com/supabase/cli/main/install | bash
# npm
npm install -D supabase # or bun/pnpm/yarn add -D supabase
npm install -D supabase@beta # beta channel
# macOS and Linux
brew install supabase/tap/supabase # always up to date
brew install supabase # official formula, may be delayed
brew install supabase/tap/supabase-beta # beta channel
# Windows
scoop bucket add supabase https://github.com/supabase/scoop-bucket.git
scoop install supabase
scoop install supabase-beta # beta channel
# Linux packages
# Download .apk, .deb, .rpm, or .pkg.tar.zst from GitHub Releases.
Linux 软件包可从发布版本获取。社区维护的软件包也可通过 pkgx 和 Nixpkgs 获取。
开始本地开发
创建一个 Supabase 工作区,并启动本地服务栈:
supabase init
supabase start
supabase status
本地栈包含 Postgres、Auth、Realtime、Storage、Edge Functions 和 Supabase API。
从模板开始:
supabase bootstrap
关联项目
将本地工作区连接到托管的 Supabase 项目:
supabase login
supabase link
管理您的数据库
创建迁移、比较数据库结构,并将变更应用到本地或已关联的项目:
supabase migration new create_profiles
supabase db diff
supabase db push
supabase db reset
部署 Edge Functions
在同一项目工作区中构建、运行并部署函数:
supabase functions new hello-world
supabase functions serve
supabase functions deploy hello-world
生成类型
从本地数据库或已关联的项目生成 TypeScript 类型:
supabase gen types --local
supabase gen types --linked
参考
在任意命令中使用 --help 以查看参数和示例:
supabase db --help
supabase functions deploy --help
开发
本仓库是一个 pnpm monorepo。正式发布的包位于 apps/cli。
pnpm install
pnpm check:all
cd apps/cli
pnpm types:check
pnpm run test:unit && pnpm run test:integration
常用源码入口:
| 路径 | 用途 |
|---|---|
apps/cli |
TypeScript/Bun CLI 包 |
apps/cli-go |
供 CLI 使用的 Go CLI 源码 |
packages/stack |
本地 Supabase 栈运行时 |
packages/config |
配置模式与生成类型 |
packages/api |
带类型的 Supabase Management API 客户端 |
全新克隆后,安装供 agent 和开发者检视的参考仓库:
pnpm repos:install
贡献
我们欢迎问题清晰、改动范围小,并且测试与面向用户的行为保持一致的 PR。
请先提交 issue,并等待维护者添加 open-for-contribution 标签后再开始工作——未关联已带标签且开放 issue 的外部 PR 将被自动关闭。完整流程参见 CONTRIBUTING.md。
在提交 PR 前,请从仓库根目录运行全仓库质量检查,
然后运行你改动过的每个工作区中相关包的测试。对于每个
改动过的 TypeScript 工作区(或任何声明了该脚本的工作区),也请运行其
pnpm types:check 脚本。例如:
# From the repository root:
pnpm check:all
# From apps/cli (a touched TypeScript workspace):
cd apps/cli
pnpm types:check
pnpm run test:unit && pnpm run test:integration
# Repeat the relevant package tests for every touched workspace; run
# pnpm types:check there too when that workspace declares the script.
PR 标题必须使用 conventional commits,例如:
fix(cli): handle linked projects without cached service versions
许可证
Supabase CLI 软件包采用 MIT 许可证发布。