Uh oh!
There was an error while loading. Please reload this page.
feat(config): expose config defaults and provide sparse mapping functions - #6205
Conversation
Adds ADR 0017 pinning the design for the config defaults mapping function ahead of implementation: a pure, parameterized subtract core in @supabase/config, defaults derived from schema annotations, strict deep equality, and the remote-block baseline rule. Also seeds a root CONTEXT.md glossary with the project's config vocabulary. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ons (CLI-2155)
Adds getDefaultProjectConfig() (memoized decode of {} through the
schema, keeping annotations as the single source of truth for
defaults), subtractProjectConfig(config, baseline), and
omitDefaultValues(config), per ADR 0017. The generic subtraction walk
is extracted from io.ts's private stripDefaults so the save-time
minimal encoding and the new sparse API share one implementation.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>…y (CLI-2155) Introduces [remotes.*] blocks as config overrides for a specific persistent Supabase branch (project_id binds the block; the label is a user-chosen alias) in ADR 0017, CONTEXT.md, and the sparse.ts doc comments. Replaces the flat "not a valid complete config" framing with a split by baseline: subtracting the default config yields a valid config document that re-decodes to the same effective config under the current schema's defaults, while any other baseline yields an overlay meaningful only relative to that baseline. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…I-2155) CONTEXT.md is not a convention this codebase follows. Its only content not already defined in the ADR (base config, drift) is woven into ADR 0018's problem statement; the stale post-renumbering references (the ADR's own 0017 heading, sparse.ts and sparse.unit.test.ts pointing at ADR 0017) now say 0018. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Supabase CLI previewnpx --yes https://pkg.pr.new/supabase/cli/supabase@4c025738bd6c3502fac2f03e6249a0a64e3f9bbcPreview package for commit |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit:635c7dd81a
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
…defaults memo (CLI-2155) Review follow-ups on #6205: subtractProjectConfig/omitDefaultValues now take BaseProjectConfig (ProjectConfig without the nested remotes), so the ADR 0018 remote-block call type-checks without a cast; the memoized default config is deeply frozen so a caller mutation cannot poison the shared subtraction baseline. Both pinned by unit tests. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
…e encoded defaults (CLI-2155) Review follow-ups on #6205: - A record entry named `__proto__` (a valid function name or remote label — both smol-toml and JSON.parse produce it as an own key, and the schema decode preserves it) was silently dropped by `result[key] = value` hitting the legacy prototype setter, and `baseline[key]` read `Object.prototype` off the prototype chain. All three record walks (`subtractValue`, `mergeRemoteSubtree`, `stripFunctionRecordDefaults`) now use `Object.hasOwn` lookups and define own data properties via a shared `setOwnProperty`; a unit test pins the `__proto__` round-trip. - `io.ts`'s encoded-defaults constant is now memoized like `getDefaultProjectConfig`, so importing `@supabase/config` no longer pays a schema decode+encode at module load — making sparse.ts's lazy-memo comment actually true. - Documented that `omitDefaultValues` output is sparse at the root scope only (record-keyed entries carry materialized per-entry decoding defaults), in the docstring and ADR 0018's Negatives, and that baseline-only keys are ignored by design (absence means inherit). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit:24fab701f3
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Uh oh!
There was an error while loading. Please reload this page.
…s (CLI-2155) Review follow-up on #6205: subtractProjectConfig's advertised remote-block call shape passed a standalone-decoded `[remotes.*]` block, but decoding a sparse fragment materializes global defaults in every omitted section — where the block meant to inherit from the base config. With base `db.port = 54399` and a remote that omits `db`, the decoded block carries the global default `54322`, the overlay retains it, and writing it back flips the branch from inheriting the base's value to pinning the default. The subtraction core is unchanged; the contract is corrected: both operands must be *effective* configs, and a branch's is the raw remote subtree merged over the raw base document before decoding (the same pre-decode order `mergeRemoteSubtree` documents, precisely so remote schema defaults never leak in). ADR 0018, the docstrings, and the unit test now pin that call shape, with the base-only-override counterexample as the regression test. `BaseProjectConfig` stays, re-justified: it keeps `remotes` out of the contract so API-translated effective configs fit without a fabricated field. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…g-default-values-mapping-ced354 # Conflicts: # docs/adr/README.md
Uh oh!
There was an error while loading. Please reload this page.
supabase#6310) ## What changed Adds ADR 0019, recording the design guardrails for the `_apiResponse` escape hatch on API-sourced config values in `@supabase/config` — the raw `/v2/projects/{ref}/config` `data.attributes` object carried alongside the typed mapping so package consumers can read API fields added faster than the package publishes. The five rules it records: 1. `_apiResponse?: Record<string, unknown>` — optional, present only on API-sourced values; absence does not mean "fully mapped". 2. Lenient decode of the v2 attributes — unknown keys never fail; this is the primary protection, `_apiResponse` is the access mechanism. 3. One metadata-key rule: `$`/`_`-prefixed keys are excluded from all structural walks and encodes (extends the existing `$schema` precedent, implemented once in the shared walk core from ADR 0018). 4. Never persisted — the raw response carries HMAC'd secret digests and must not land in config files. 5. Fallback, not contract — typed fields win once a raw key graduates into the mapping; unmapped-field discovery is a registry-derived helper, not a second stored field. ## Why Discussed 2026-08-24 in the context of publishing `@supabase/config` for multiple consumers (CLI `config diff`/`pull`, Studio's config-drift work in supabase/supabase#48906, which vendors a temporary schema mirror explicitly awaiting this package). The Management API moves faster than deliberate package releases; without a designed escape hatch the package's cadence bottlenecks every service team's API velocity, and without the guardrails a naive passthrough causes phantom drift in the ADR 0018 subtraction walks and risks persisting secret digests. Note: numbered 0019 because 0018 is taken by supabase#6205 (currently in the merge queue); the README index row may need a trivial rebase once supabase#6205's 0018 row lands. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Implements CLI-2155: a stored reference of config default values and a mapping function that omits values matching them, so
config diff(CLI-2156) andconfig pull(CLI-2064) can compare sparse configs instead of full effective ones.What changed
New API in
@supabase/config(packages/config/src/sparse.ts, all pure and synchronous, operating on decodedProjectConfigvalues):getDefaultProjectConfig()— the default config, derived by decoding{}throughProjectConfigSchema(memoized). The schema's existingdefaultannotations and decoding defaults remain the single source of truth; there is no hand-maintained defaults table to drift.subtractProjectConfig(config, baseline)— returns the sparse configconfig − baseline: strict deep equality (order-sensitive arrays), sections emptied by subtraction dropped recursively. Directional, so CLI-2156 can subtract a remote block against the merged base config.omitDefaultValues(config)—subtractProjectConfigwith the default config as baseline. The result is itself a valid config document: re-decoding refills the removed defaults, yielding the same effective config under the current schema's defaults.[remotes.*]blocks (config overrides for a specific persistent Supabase branch, bound byproject_id) pass through untouched — pruning them against global defaults would silently change what a branch resolves to.Refactor:
io.tshad a privatestripDefaults/isEqualValuewalk used for writing minimal config files; that walk is now the sharedsubtractValuecore insparse.ts, consumed by both the new API and the save path, so there is one subtraction implementation in the package.Design docs: ADR 0018 (
docs/adr/0018-sparse-config-subtraction.md) records the decision, the remote-block baseline rule, what the output is depending on the baseline (defaults → a valid, effectively-equivalent config document whose meaning leans on the current defaults version; any other baseline → an overlay meaningful only relative to that baseline), and defines the working vocabulary inline (default config, sparse config, subtract, base config, remote block, drift).Reviewer notes
packages/apitypes. See the ticket comment and ADR 0018's Alternatives.subtractProjectConfiguses an overload with an untyped implementation signature rather than anascast — TypeScript can't verify that a structural walk overunknownreconstructs aDeepPartialof its input; the unit tests pin the contract.🤖 Generated with Claude Code