Skip to content

refactor(cli): remove rawProjectConfig from ProjectContext#5281

Merged
avallete merged 5 commits into
developfrom
claude/fix-env-expressions-parsing-2QB7C
May 18, 2026
Merged

refactor(cli): remove rawProjectConfig from ProjectContext#5281
avallete merged 5 commits into
developfrom
claude/fix-env-expressions-parsing-2QB7C

Conversation

@avallete
Copy link
Copy Markdown
Member

Remove the unused rawProjectConfig field from ProjectContext and stop loading the raw project config in the project context layer.

Changes

  • Removed rawProjectConfig: Option.Option<ProjectConfig> from ProjectContextShape interface
  • Removed loadProjectConfig call from projectContextLayer — only loadProjectEnvironment is now used
  • Updated mockProjectContext test helper to remove the rawProjectConfig option parameter
  • Added unit test for projectContextLayer covering the scenario where config.toml uses env() on numeric fields (CLI-1489) and the case where no Supabase project is found

Implementation Details

The rawProjectConfig field was not being used anywhere in the codebase. By removing it, we simplify the ProjectContext service and reduce unnecessary I/O during initialization. The project context now only loads and exposes the project environment configuration, which is what consumers actually need.

https://claude.ai/code/session_01C7reiRogHr6WXQoKiEDQeW

The Bun shell's projectContextLayer eagerly decoded supabase/config.toml
through a strict Effect schema on every command boot, rejecting any
env(VAR) literal on non-string fields with ProjectConfigParseError. This
broke supabase db start (and every other legacy command that just
proxies to the Go binary) for users whose config.toml references env()
on numeric, boolean, or enum fields - despite the Go binary itself
still resolving those references correctly.

The decoded ProjectConfig was unused: cliConfigLayer only reads
projectEnv, projectHomeLayer only reads paths, and no other consumer
exists in apps/cli/src. Remove the load entirely and drop the
rawProjectConfig field from the ProjectContext shape. functions dev
keeps its own loadProjectConfig call - that surface remains tracked
under the parent issue for a proper TS-side fix.

Refs CLI-1489.
@avallete avallete requested a review from a team as a code owner May 18, 2026 17:16
claude added 2 commits May 18, 2026 17:39
Boots a real supabase subprocess against a config.toml whose numeric
port fields are written as env(VAR) references. Pre-fix, the Bun
shell crashed at layer construction with
ProjectConfigParseError: Expected number, got "env(SUPABASE_ANALYTICS_PORT)".
Post-fix, the layer skips the strict decode and the command completes
normally.

RED/GREEN locally verified via the colocated unit test (same scenario,
identical error message reproduced when the loadProjectConfig call is
restored). The e2e variant covers the full subprocess + shim path that
the customer hit through supabase/setup-cli@v1.
The Go CLI binary was renamed from `cli` to `supabase-go` during the
monorepo cutover, but .gitignore was not updated to match. Cover the
new artifact name so local builds don't produce an untracked binary.
@coveralls
Copy link
Copy Markdown

coveralls commented May 18, 2026

Coverage Report for CI Build 26051249899

Warning

No base build found for commit 8b3a1c6 on develop.
Coverage changes can't be calculated without a base build.
If a base build is processing, this comment will update automatically when it completes.

Coverage: 63.744%

Details

  • Patch coverage: No coverable lines changed in this PR.

Uncovered Changes

No uncovered changes found.

Coverage Regressions

Requires a base build to compare against. How to fix this →


Coverage Stats

Coverage Status
Relevant Lines: 15680
Covered Lines: 9995
Line Coverage: 63.74%
Coverage Strength: 7.06 hits per line

💛 - Coveralls

claude and others added 2 commits May 18, 2026 17:53
The colocated e2e test in apps/cli only exercised the next shell at the
apps/cli build artifact level. Moving the regression to apps/cli-e2e
lets it run against every CLI target (go, ts-legacy, ts-next) via the
existing CLI_HARNESS_TARGET matrix.

The test writes a supabase/config.toml with env(VAR) references on
numeric port fields, injects a 401 so no real API fixture is required,
runs secrets list, and asserts neither ProjectConfigParseError nor the
"Expected number, got \"env(...\"" message appears in output. Verified
RED on the pre-fix layer for both ts-legacy and ts-next, GREEN on the
fix. The Go target is unaffected by the bug and trivially passes.
@avallete avallete enabled auto-merge (squash) May 18, 2026 18:05
@avallete avallete merged commit a0feddb into develop May 18, 2026
17 checks passed
@avallete avallete deleted the claude/fix-env-expressions-parsing-2QB7C branch May 18, 2026 18:30
avallete pushed a commit that referenced this pull request May 20, 2026
…oval

Resolve api.ts conflict (keep auto_expose_new_tables alongside the
Effect.succeed default-key update from develop) and read the
auto_expose_new_tables flag via loadProjectConfig now that
ProjectContext no longer exposes rawProjectConfig (#5281).
Coly010 added a commit that referenced this pull request May 22, 2026
Fixes the crash when `supabase/config.toml` uses `env(VAR)` on numeric
or boolean fields (e.g. `analytics.port =
"env(SUPABASE_ANALYTICS_PORT)"`). The strict Effect Schema decode ran
immediately after raw TOML parse, with `interpolateValue` in
`project.ts` only firing post-decode via `resolveProjectValue` — so it
never got the chance to substitute the string before `Schema.Number`
rejected it.

## What changed

- **Pre-decode env() interpolation in `packages/config/src/io.ts`** —
`loadProjectConfigFile` now loads the project environment
(`.env`/`.env.local`/ambient) and runs a schema-aware walker on the
parsed document before handing it to
`Schema.decodeUnknownSync(ProjectConfigSchema)`.
- **Schema-aware walker in `packages/config/src/lib/env.ts`** —
traverses both the parsed document and `ProjectConfigSchema.ast` in
parallel. For string leaves matching `env(VAR)`: substitutes against the
env, then coerces to Number/Boolean if the schema at that path expects
one. Mirrors Go's `LoadEnvHook` + mapstructure type chain
(`apps/cli-go/pkg/config/decode_hooks.go:14-21` → subsequent string→type
conversion hooks).
- **Verbatim-on-missing semantics** — `interpolateLeafValue` in
`project.ts` no longer throws `MissingProjectEnvVarError` when the
referenced env var is unset. It returns the literal `env(VAR)` string,
matching Go parity. The `MissingProjectEnvVarError` class and re-export
are removed; `resolveProjectValue` / `resolveProjectSubtree` no longer
have a failure channel.
- **Fields declared with the `env()` schema helper opt out** via the
`x-env-deferred` marker annotation. They still require the literal
`env(VAR)` format for post-decode resolution by `resolveProjectValue` —
the walker honors the marker and leaves those paths untouched.

## Reviewer-relevant context

- **No schema-file edits.** Coercion lives entirely in the walker, so
future fields added to any of the section schemas (`db.ts`,
`analytics.ts`, `auth/*.ts`, etc.) automatically work with `env()`
references — no risk of a contributor forgetting to use a coerced
primitive at declaration time.
- **The marker annotation lives on the check, not the outer AST.**
`env() = Schema.String.check(isPattern(envRegex)).annotate({...})`
attaches metadata to the resulting Filter rather than the base String
AST, so `isDeferredEnvField` inspects both `node.annotations` and
`node.checks[].annotations`. Caught by the `@supabase/stack`
`functions.unit.test.ts` regression for `functions.<name>.env` (env()
helper at a record value position).
- **Missing-env semantics in `project.ts` are now non-failing.** Two
existing "fails when missing env var" tests in
`project.unit.test.ts:223,255` are rewritten to assert verbatim
preservation. `redactValue` already skips redaction when the value is
still an env reference (`!isEnvReference(value)`), so unresolved
literals flow through as plain strings — no Redacted wrapping on missing
secrets.
- **The next/projectContextLayer workaround (PR #5281) is left in
place.** That layer dropped the `loadProjectConfig` call entirely to
avoid the crash; reintroducing it is a follow-up refactor since the
workaround still functions correctly (it only loads env, not config).
- The existing CLI-1489 regression test at
`apps/cli/src/next/config/project-context.layer.unit.test.ts:30` is not
modified — it asserts the workaround-era behavior of
`projectContextLayer`, which is unchanged. Direct upstream regression
coverage is added in `packages/config/src/io.unit.test.ts`: numeric
coercion, boolean coercion, verbatim preservation, ambient fallback, and
decode failure when an unset var is referenced from a numeric field.

Fixes CLI-1489
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants