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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
336 changes: 336 additions & 0 deletions .github/workflows/release-config.yml

Large diffs are not rendered by default.

5 changes: 3 additions & 2 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,9 @@ jobs:
run: pnpm run check:all

# Advisory only (base-vs-head diff, no acceptance artifact to gate a
# required check on) — the hard release-time gate is tracked under
# CLI-2233. `continue-on-error` flags the diff without failing the job;
# required check on) — the hard release-time gate is
# tools/config-release-gate.ts in release-config.yml (CLI-2233).
# `continue-on-error` flags the diff without failing the job;
# the tool's own fetch/unshallow fallback resolves a merge-base from
# this checkout's shallow clone, and skips the compare (exit 0) rather
# than failing when history still can't be resolved.
Expand Down
2 changes: 1 addition & 1 deletion apps/cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@
"prettier": "3.9.6",
"react": "^19.2.8",
"react-devtools-core": "^7.0.1",
"semantic-release": "^25.0.9",
"semantic-release": "catalog:",
"smol-toml": "^1.8.0",
"tldts": "catalog:",
"typescript": "catalog:",
Expand Down
49 changes: 47 additions & 2 deletions packages/config/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,9 @@ surface must update that test deliberately — it is not meant to be a silent pa
`dist/` is gitignored and rebuilt on demand — no build output is checked in. The public type
surface is instead enforced per-PR by export snapshots and purity walkers (see "Testing" below)
plus the repo-root `pnpm check:config-api` (`tools/config-api-compare.ts`), which diffs this
package's declaration output between the PR base and head commits and is advisory at PR time. A
release-time tarball diff is planned under CLI-2233 as the hard gate.
package's declaration output between the PR base and head commits and is advisory at PR time. The
hard gate is a release-time tarball diff — `tools/config-release-gate.ts`, run by the `plan` job in
`.github/workflows/release-config.yml` — see "Releases" below.

### Publishing the tarball (CLI-2234)

Expand Down Expand Up @@ -132,3 +133,47 @@ own guarantees and must stay green after any entrypoint or type-surface change:
- `scripts/json-schema-postprocess.unit.test.ts` / `scripts/build-artifacts.unit.test.ts` — the
JSON Schema post-processing `renderJsonSchema` applies (non-finite-number `anyOf` collapse,
`$id`/`title`/`description`), the second against the real generated documents.

## Releases (CLI-2233)

This package has its own release train, independent of the CLI's — a `fix:`/`feat:` commit
elsewhere in the monorepo never releases `@supabase/config`, and vice versa.

- **Path-filtered conventional commits.** `semantic-release` computes the next version from commits
scoped to `packages/config/` via `scripts/semantic-release-path-filter.ts`.
- **Tag format:** `config-v<version>` — never collides with the CLI's `v<version>` tags.
- **Stable-only, from `develop`.** No beta/alpha channel; every release publishes to npm under the
`latest` dist-tag.
- **Workflow:** `.github/workflows/release-config.yml` — a `plan` job computes the version, packs
the release tarball, and runs the type-surface gate against the declarations inside that tarball;
a human approves the `config-release` GitHub environment (reviewing the plan job's step summary:
release notes + type-surface diff); then an OIDC/provenance publish job publishes **that exact
tarball** (`npm publish <tgz> --ignore-scripts` — no rebuild, no repack, no lifecycle scripts:
the approved bytes are the published bytes).
- **`package.json`'s committed `version` (`0.1.0`) is a placeholder.** The real version is stamped
into the tarball at pack time (`npm pkg set version` in the plan job) from the computed version —
never hand-bump the committed field, and never hand-push a `config-v*` tag.
- **Local dry runs:** `scripts/release-plan.ts` runs the plan locally without publishing;
`tools/config-release-gate.ts --tarball` rehearses the type-surface gate locally.

### One-time setup (tracked under CLI-2169)

Four things must be settled before the first real publish:

1. The `config-release` GitHub environment needs required reviewers configured in repo settings. An
environment referenced by a workflow is auto-created WITHOUT protection rules — the plan job
asserts the rule exists and refuses to plan a real release until it does, so the first release
attempt fails closed rather than publishing unreviewed.
2. npm trusted publishing must be configured for the package, which requires the package to exist
first. The very first publish is a manual bootstrap — use a granular, single-package,
short-expiry token and revoke it as soon as the trusted publisher is configured (repo
`supabase/cli`, workflow `release-config.yml`, environment `config-release`).
3. Push a baseline `config-v*` tag (e.g. `config-v0.1.0`) on a `develop` commit. This is required,
not optional: with no baseline, semantic-release would cut `1.0.0` with release notes generated
from the entire monorepo history — a whole-history changelog as both the approval artifact and
the public GH release body. `scripts/release-plan.ts` refuses to plan without a baseline tag
(escape hatch: `CONFIG_RELEASE_ALLOW_NO_BASELINE=1`). This is the single exception to the
"never hand-push a `config-v*` tag" rule above.
4. Add a repository tag ruleset protecting `config-v*` (alongside `v*`), restricted to the release
App. The last `config-v*` tag is the version oracle: a stray hand-pushed tag permanently skews
versioning, and a deleted tag makes the next plan re-cut an already-published version.
86 changes: 53 additions & 33 deletions packages/config/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,44 @@ It owns:
- JSON Schema generation for both shapes, at `@supabase/config/schema.json` and
`@supabase/config/project-schema.json`

## Installing

```sh
npm install @supabase/config effect@rc
```

```ts
import { getDefaultCliConfig, toProjectConfig } from "@supabase/config";

// Project a config document onto the hosted-project subset — here the
// schema-derived default document; a real caller would load one with
// `loadCliConfig` from `@supabase/config/io` (see "Usage" below).
const projectConfig = toProjectConfig({ cliConfig: getDefaultCliConfig() });
```

This package is not yet published (`private: true`; publishing is tracked separately). Once it
is, install it alongside the peers your runtime needs.

This package requires Effect 4.x, currently only published under the `rc` dist-tag — `effect@latest`
still resolves to 3.x, which will not satisfy this package's peer range.

`effect` is a required peer dependency. `@effect/platform-bun` and `@effect/platform-node` are
optional peers — install exactly one, matching your runtime, if you use `./io` or `./effect`'s
file-IO programs:

| Consumer | Required peers |
| ---------------------------------------------- | --------------------------------- |
| Pure / browser / edge (`.` only, no file IO) | `effect` |
| Node (`./io` or `./effect`'s file-IO programs) | `effect`, `@effect/platform-node` |
| Bun (`./io` or `./effect`'s file-IO programs) | `effect`, `@effect/platform-bun` |

Under the `node`/`bun` export conditions, the matching platform peer is imported eagerly at module
load. A missing peer surfaces as a raw module-resolution error (e.g. `Cannot find package
'@effect/platform-node'`) the first time something imports `./io` or `./effect` — not a curated
message — so install the peer for your runtime before importing either subpath. The `browser`
condition is the one exception: it needs no platform peer, since it resolves to a stub that throws
its own curated error only when invoked (see "Entrypoints" below).

## Naming

- `CliConfig` — the config _document_ (`supabase/config.toml`/`.json`) — the full local superset
Expand All @@ -30,7 +68,8 @@ Use the `Cli*` prefix for the local checkout side and a bare `Project*` name for
Supabase project. Config-value helpers follow the config family regardless of their inputs
(`resolveCliConfigValue`). See
[ADR 0020](https://github.com/supabase/cli/blob/develop/docs/adr/0020-config-naming-vocabulary.md)
and [docs/cli-config-loading.md](./docs/cli-config-loading.md) for the full vocabulary.
and [docs/cli-config-loading.md](https://github.com/supabase/cli/blob/develop/packages/config/docs/cli-config-loading.md)
for the full vocabulary.

## Entrypoints

Expand Down Expand Up @@ -145,35 +184,6 @@ Every runtime and type export of the pure `.` entrypoint, grouped by category:
| -------------------------------------------------------------------------------------------------- | ---------------------------------------- |
| `edgeFunctionDenoConfigFileName` / `edgeFunctionEntrypointFileName` / `edgeFunctionsDirectoryName` | Edge Functions on-disk layout filenames. |

## Installing

This package is not yet published (`private: true`; publishing is tracked separately). Once it
is, install it alongside the peers your runtime needs:

```sh
npm install @supabase/config effect@rc
```

This package requires Effect 4.x, currently only published under the `rc` dist-tag — `effect@latest`
still resolves to 3.x, which will not satisfy this package's peer range.

`effect` is a required peer dependency. `@effect/platform-bun` and `@effect/platform-node` are
optional peers — install exactly one, matching your runtime, if you use `./io` or `./effect`'s
file-IO programs:

| Consumer | Required peers |
| ---------------------------------------------- | --------------------------------- |
| Pure / browser / edge (`.` only, no file IO) | `effect` |
| Node (`./io` or `./effect`'s file-IO programs) | `effect`, `@effect/platform-node` |
| Bun (`./io` or `./effect`'s file-IO programs) | `effect`, `@effect/platform-bun` |

Under the `node`/`bun` export conditions, the matching platform peer is imported eagerly at module
load. A missing peer surfaces as a raw module-resolution error (e.g. `Cannot find package
'@effect/platform-node'`) the first time something imports `./io` or `./effect` — not a curated
message — so install the peer for your runtime before importing either subpath. The `browser`
condition is the one exception: it needs no platform peer, since it resolves to a stub that throws
its own curated error only when invoked (see "Entrypoints" above).

## ProjectConfig: producing and validating hosted-project values

The hosted-project subset — `ProjectConfig` — and its converters live on the pure entrypoint
Expand Down Expand Up @@ -329,7 +339,10 @@ The runtime export surface of `.`, `./io`, and `./effect`, plus the two generate
artifacts (`./schema.json`, `./project-schema.json`), is this package's published contract.
`./internal` carries no such guarantee. See [AGENTS.md](https://github.com/supabase/cli/blob/develop/packages/config/AGENTS.md) for how that contract is
enforced (export-surface snapshots, purity walkers, and a base-vs-head type-surface diff advisory
at PR time — a release-time tarball diff hard gate is planned under CLI-2233).
at PR time). Releases themselves are cut by an independent pipeline: conventional commits scoped to
`packages/config/` compute the next version, published to npm under the `latest` dist-tag and
tagged `config-v<version>`, and every publish is human-approved against a type-surface diff of the
previously published version.

## Usage

Expand Down Expand Up @@ -371,9 +384,12 @@ preserve the existing format when possible and default new config files to JSON.

## Architecture Docs

- [CLI config loading](./docs/cli-config-loading.md)
- [CLI config loading](https://github.com/supabase/cli/blob/develop/packages/config/docs/cli-config-loading.md)

## Development
## Development (contributors)

This section is for contributors to the supabase/cli monorepo, not consumers of the published
package.

Repo-wide quality checks run from the repository root:

Expand All @@ -391,3 +407,7 @@ pnpm run build # Compile dist/, generate schema.json/project-schema.json
```

See [AGENTS.md](https://github.com/supabase/cli/blob/develop/packages/config/AGENTS.md) for the build pipeline and contract-enforcement details.

## License

MIT — see the bundled [LICENSE](https://github.com/supabase/cli/blob/develop/packages/config/LICENSE) file.
3 changes: 3 additions & 0 deletions packages/config/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -79,10 +79,13 @@
"devDependencies": {
"@effect/platform-bun": "catalog:",
"@effect/platform-node": "catalog:",
"@semantic-release/commit-analyzer": "^13.0.1",
"@semantic-release/release-notes-generator": "^14.1.1",
"@tsconfig/bun": "catalog:",
"@types/bun": "catalog:",
"@vitest/coverage-istanbul": "catalog:",
"effect": "catalog:",
"semantic-release": "catalog:",
"typescript": "catalog:",
"vite": "^6.0.0 || ^7.0.0 || ^8.0.0",
"vitest": "catalog:"
Expand Down
Loading
Loading