Skip to content

TML-3035: a first Supabase project works first-try — RLS migrations, verify, migrate, JWKS, grants#997

Merged
wmadden-electric merged 21 commits into
mainfrom
tml-3035-supabase-launch-findings
Jul 17, 2026
Merged

TML-3035: a first Supabase project works first-try — RLS migrations, verify, migrate, JWKS, grants#997
wmadden-electric merged 21 commits into
mainfrom
tml-3035-supabase-launch-findings

Conversation

@wmadden-electric

@wmadden-electric wmadden-electric commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Here is what a first-time user of @prisma-next/extension-supabase 0.15.0 hits, installing from npm and following our own skill against a stock Supabase project — five steps, five failures:

# 1. Plan a migration for a contract with RLS policies — the generated file can't even be imported:
$ npx prisma-next migration plan --name init
$ node migrations/app/20260716T0822_init/migration.ts
SyntaxError: The requested module '@prisma-next/postgres/migration' does not provide an export named 'createRlsPolicy'

# 2. Run migrate — it demands migrations for the Supabase pack's space, and its own remediation is rejected:
$ npx prisma-next migrate --yes
PN-RUN-3000  No on-disk migrations for contract space "supabase"
             fix: prisma-next migration plan --to sha256:a6d5d037…
$ npx prisma-next migration plan --to sha256:a6d5d037…
PN-RUN-3000  Not a known contract reference: "sha256:a6d5d037…"

# 3. Verify the database — six "missing" constraints that provably exist:
$ npx prisma-next db verify
Database schema does not satisfy contract (6 failures)
  - database.auth.schema_migrations.primary-key | not-found | expects: schema_migrations_pkey  …

# 4. Bind a user, with the JWT secret the skill (and `supabase status`) point you at:
await db.asUser(jwt)
InvalidJwtError: Key for the ES256 algorithm must be one of type CryptoKey, KeyObject, or JSON Web Key.
                 Received an instance of Uint8Array

# 5. Use the documented service_role admin root:
await db.asServiceRole().supabase.orm.auth.AuthUser.select('id', 'email').all()
error: permission denied for table users   (42501)

This PR makes all five work (or fail with a remediation that works when followed verbatim), and adds the check that would have caught most of them before release: the real-Supabase acceptance suite now runs against a live supabase start stack on every PR, as a required job.

The findings come from an external agent run that built a notes app on 0.15.0; its full report is the first comment on this PR. The app's core worked — contract emit, cross-space FKs, RLS enforcement itself were all correct. Everything broken was in the surrounding surface, and none of it was visible to our own test suite. The common cause: our hermetic test shim provisioned a Supabase that no real project matches — it granted service_role privileges real Supabase withholds, and minted only HS256 tokens where current Supabase signs ES256 via JWKS. Green tests, against a database no user has.

1. Generated migrations now import, typecheck, and run (RLS contracts)

The renderer emitted RLS operations as free-function calls — enableRowLevelSecurity("public", "profile") — importing from @prisma-next/postgres/migration. Those names were never exported, and exporting them can't fix it: the underlying factories take an ExecuteRequestLowerer argument that a rendered call site has no way to supply. db init masked all of this by applying ops.json without ever importing the module.

RLS operations now render as methods on the migration base class — this.createRlsPolicy({...}) — the same pattern as createTable, lowering through the migration's stored control adapter. Two structural guards keep the whole class fixed, not just these five ops:

  • a test that renders one call of every op class, parses the emitted import statement, and asserts each imported name actually exists on the facade (plus an enumeration test that fails when a new op class isn't covered);
  • the adapter-postgres roundtrip now executes a rendered migration containing all five RLS ops via tsx and matches its ops.json — execution, not just import shape. This test is what proved the naive export-only fix wrong.

The sweep also caught a latent same-class bug: addNotNullColumn's two op classes render rawSql(...) but declared no import requirement.

2. db verify no longer false-negatives on Supabase's own tables

Against a clean Supabase database, verify reported six constraints as not-found — all on platform-internal tables (auth.schema_migrations, storage.migrations, …) — while psql showed them present with the exact expected names and columns.

Root cause: introspection read information_schema.table_constraints, whose visibility filter deliberately omits SELECT (unlike information_schema.tables/columns, which include it). On Supabase, the connecting postgres role has full privileges on most pack tables but only SELECT on the platform's internal ones — so those tables introspected as present, with columns, and zero constraints. Introspection now reads pg_catalog.pg_constraint (not privilege-filtered), keyed by table oid.

Keying by oid instead of by constraint name also fixed a known marked bug: two tables in one schema sharing an FK name used to get their columns merged (the it.fails test for it now passes and is un-marked). And a review round caught a regression the rewrite would have introduced — an FK referencing a plain CREATE UNIQUE INDEX made that index vanish from introspection — fixed with a contype filter and its own regression test.

3. migrate handles extension-pack contract spaces

The Supabase pack is an external contract space: it declares what Supabase owns so the planner emits no DDL for it, and it ships no migrations — by design. migrate didn't know that: it required an on-disk migration graph for every space, and for the pack space it printed a remediation (step 2 of the console session above) that migration plan itself rejects, because the pack's hash is a head ref, not a graph node. The user's only path forward was db init.

The model already existed: db init's aggregate planner resolves such spaces to a declared-state zero-op plan targeting the head ref. migrate now does exactly that — the space's marker advances to head inside the ordinary per-space transaction, and "Already up to date" means what it says.

The precondition is enforced, not assumed: advancing a storage hash without a migration is valid exclusively for a space whose every element is externally managed — that's the only way storage structure can be correct without a migration having changed it. A shared predicate (allStorageElementsExternal, walking the space's elements' effective control policy) guards both db init and migrate; a no-migrations extension space that declares even one managed element fails loudly instead of advancing. App spaces still require an authored graph, and their never-planned error now prints a remediation the e2e test parses and executes verbatim — a drifted fix string fails the test.

4. JWT misconfiguration gets a real error, and both signing modes are tested

Current Supabase projects sign ES256 with asymmetric keys and publish a JWKS endpoint; supabase status still prints a JWT_SECRET, so wiring jwtSecret is everyone's natural first move — and it failed with the raw jose internal in step 4 above.

asUser now detects the mismatch before verification and throws InvalidJwtError with the actual problem and fix:

Invalid JWT: token is signed with ES256 but this client is configured with jwtSecret (HS256). Current Supabase projects sign with asymmetric keys by default — configure jwksUrl (https://<project>/auth/v1/.well-known/jwks.json) instead of jwtSecret.

The reverse direction (HS256 token, jwksUrl client) gets the same treatment, and fires before any JWKS fetch. Hermetic coverage now includes the full ES256/JWKS path: an in-test P-256 keypair, a local JWKS server, and the complete asUser → role-binding → RLS-scoped-read flow.

5. The grants story is now told in the right direction

Two inversions, both traceable to the shim:

  • Real Supabase grants service_role nothing on auth.*/storage.* (only schema USAGE; only postgres holds table privileges). The documented admin root (db.asServiceRole().supabase) therefore fails out of the box — step 5 above. Our shim ran GRANT ALL ON ALL TABLES IN SCHEMA auth TO service_role, so every test passed. The shim now restores the reference fixture's real default privileges and nothing more — removing the over-grant reproduced the user's exact 42501 hermetically — and the docs state the narrow one-time grant the admin root needs: GRANT USAGE ON SCHEMA auth TO service_role; GRANT SELECT ON TABLE auth.users TO service_role;
  • Your own public tables need no grants at all. Supabase ships ALTER DEFAULT PRIVILEGES on public, so tables created by db init/migrate inherit platform-role access automatically; RLS is what protects the rows. The skill told users to run per-table grants (up to GRANT ALL) — guidance that mirrored the shim's grant block line-for-line. Inverted in the skill, and the example app no longer issues the redundant grants either.

Dropping the over-grant also unmasked a test that believed it was querying as an admin but was actually running as service_role through a leaked session variable.

6. The broken ./test/utils export is deleted, not fixed

bootstrapSupabaseShim — the skill's documented hermetic-testing entrypoint — has been exported-but-broken from npm for at least three minor versions: its SQL fixtures were never in the package's files, so every consumer install fails with ENOENT before touching a database. Nobody ever reported it, so nobody ever ran it; there is nothing to deprecate.

The subpath is removed (a breaking change, recorded in both the app-user and extension-author 0.15→0.16 upgrade instructions — the import typechecked fine before, so user code plausibly contains it). The substrate stays in-repo as setUpSupabaseMockSchema for the extension's own tests. The user-facing testing story in the skill is now Supabase's own tooling — supabase start + supabase test db (pgTAP), which tests policies and grants against the real platform defaults.

The same boundary is applied to the example app: its hermetic PGlite suites imported the internal substrate by relative path — a testing setup no user copying the example could run. Those suites moved into the extension package (against a checked-in fixture app), and examples/supabase's own test suite is now exactly what a user gets: the acceptance run against their own supabase start.

7. The class of bug is now structurally caught: a required live-Supabase CI job

Everything above shipped because the only tests were hermetic and the hermetic environment was unfaithful. The env-guarded acceptance suite (examples/supabase/test/real-supabase.acceptance.test.ts) now runs on every PR: a new supabase-acceptance job boots a stock supabase start in examples/supabase and runs the suite with the stack's real credentials — including a new flow that signs up a user through GoTrue and verifies its issued ES256 token through the project's live JWKS endpoint. It passed its first execution on this PR.

Ops follow-up: the branch ruleset (managed outside the repo) needs "Supabase Acceptance" added to its required checks.

Alternatives considered

  • Publishing the shim's fixtures instead of deleting the export (the report's suggested fix). Rejected: by the skill's own definition RLS is enforced by policies and grants, and a shim whose grants differ from real Supabase in both directions cannot faithfully test RLS — a policy suite can pass on the shim and fail in production, and vice versa. Green-locally-broken-in-prod is worse than no test; pgTAP against the real local stack is strictly better.
  • SupabaseConfigError for the algorithm mismatch (the report's suggestion). The mismatch is only observable per-token at asUser, where callers already catch InvalidJwtError (with its typed reason); config errors stay factory-time. Better ergonomics, same information.
  • A tsc pass over generated migrations in CI (the report's suggested regression test). We ship something stronger: tsx execution of rendered migrations plus the import-surface assertions — execution is the check that disproved the first version of this very fix.
  • Allowlisting supabase/setup-cli in org settings. The org restricts Actions to an allowlist, and the action's absence failed the whole CI workflow at startup (producing zero check runs — deceptively green in gh pr checks). The job instead installs the pinned CLI release binary (v2.95.4, sha256-verified against the release's checksums file), which keeps the pin real and avoids a standing org-settings dependency.
  • Splitting this into several PRs. The findings share one causal story (the fidelity gap) and one report; reviewing them together is cheaper than re-establishing that context four times.

Refs: TML-3035

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added PostgreSQL RLS migration support (enable/disable and manage RLS policies).
    • Added stricter handling for empty “all-external” spaces during migration planning.
    • Expanded end-to-end Supabase acceptance in CI, including RLS and JWKS-based auth flows.
  • Bug Fixes

    • Improved JWT error specificity for algorithm/key-source mismatches.
    • Fixed migration remediation and CLI command suggestions for never-planned scenarios.
    • Improved Postgres schema introspection to better handle restricted privileges and constraint ordering.
  • Documentation

    • Updated Supabase and upgrade guidance for JWKS/grants/testing and the removed Supabase test utility export.

The Postgres migration renderer emitted RLS ops as free-function calls
(createRlsPolicy(...), enableRowLevelSecurity(...)) importing from
@prisma-next/postgres/migration. Those symbols were never exported, so
a generated migration.ts for any RLS contract failed to import — and
exporting them cannot fix it, because the underlying op factories take
an ExecuteRequestLowerer argument the rendered call site has no way to
supply. db init masked this by applying ops.json without importing the
module.

Render RLS ops the way every other lowerer-requiring op renders: as
this.-method calls on the migration base class, which lowers through
the migration's stored control adapter. Adds the five RLS methods to
PostgresMigration (createRlsPolicy, dropRlsPolicy, renameRlsPolicy,
enableRowLevelSecurity, disableRowLevelSecurity), exports the five RLS
call classes from the op-factory-call facade, and deletes the
importRequirements() overrides on the two planner-internal NOT NULL
calls that render rawSql(...) but declared no import (same defect
class).

Regression tests: a structural test renders one call of every
op-factory-call class (a new class fails the test until covered) and
asserts every symbol the rendered module imports from the facade is
actually exported by it; a second test locks the this.-method render
shape for all five RLS ops.

Relates to TML-3035.

Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
Extends the tsx-execution roundtrip with all five RLS op kinds
(enable, createPolicy, renamePolicy, dropPolicy, disable) so the
rendered migration.ts for RLS contracts is proven to parse, typecheck
via tsx, and lower back to the exact renderOps(calls) operations. This
is the test that exposed the free-function RLS rendering defect.

Relates to TML-3035.

Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
The ./test/utils subpath (bootstrapSupabaseShim) has never been
runnable from npm: it reads test/fixtures/supabase-reference/*.sql at
runtime, and the package files list ships only dist and src, so every
external call fails with ENOENT before touching a database. No
deprecation is needed — no consumer outside the monorepo can ever have
run it.

Drop the export and its tsdown build entry. The shim stays in-repo
test tooling: the extension's own tests already import it by relative
source path, and examples/supabase now does the same instead of going
through the published subpath.

Relates to TML-3035.

Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
…formation_schema

db verify against a real Supabase instance reported the pack's own
constraints (auth.schema_migrations PK, storage.migrations PK + unique,
storage.buckets_vectors PK, storage.vector_indexes PK + FK) as
not-found while they provably exist. Mechanism:
information_schema.table_constraints hides constraints on tables where
the connecting role's only privilege is SELECT — its visibility filter
grants INSERT/UPDATE/DELETE/TRUNCATE/REFERENCES/TRIGGER but not SELECT,
while information_schema.tables and .columns do include SELECT. On real
Supabase the connecting role can only SELECT the platform's internal
tables, so introspection returned them with all columns but zero
constraints and verify flagged every declared PK/unique/FK missing.

Rewrite the PK, unique, and FK introspection queries against
pg_catalog.pg_constraint (not privilege-filtered), pairing columns via
unnest(conkey) WITH ORDINALITY and mapping confdeltype/confupdtype to
the same rule strings information_schema reported. The
constraint-backed-index exclusion in the index query moves from a
name-keyed information_schema lookup to pg_constraint.conindid, which
also fixes the long-standing P2-1 defect where two tables sharing a
constraint name merged their FK columns — the it.fails marker on
"drops the correct FK when two tables share a constraint name" now
passes and is flipped to a regular test.

Regression test reproduces the Supabase failure shape exactly: a table
owned by another role with SELECT-only granted to the connecting role
must introspect with its PK, unique, FK, and index, and verify must
report no issues.

Relates to TML-3035.

Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
…en RLS render typing

Both 0.15-to-0.16 upgrade recipes gain a change entry for the removed
@prisma-next/extension-supabase ./test/utils export: the import
typechecked but never ran from the published package (unpublished
fixtures), so the migration is deleting the import; the testing story
is Supabase's own tooling (supabase test db / pgTAP).

CreatePostgresRlsPolicyCall.renderTypeScript() annotates its hand-built
literal as PostgresRlsPolicyInput so drift from the input type fails to
compile, and the migration roundtrip policy gains a withCheck predicate
so the ifDefined serialization path executes end-to-end.

Relates to TML-3035.

Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
…m index introspection

For FK constraints, pg_constraint.conindid points at the unique index
on the REFERENCED table, and Postgres accepts FKs that reference a
plain CREATE UNIQUE INDEX with no constraint object. The
constraint-backed-index exclusion introduced with the pg_catalog
rewrite matched those rows too, hiding the referenced index from
introspection and making verify report a declared index as missing.
Restrict the exclusion to constraints that own their index
(contype p/u/x); no conrelid guard, so self-referential FKs stay
correct.

Regression test: an FK referencing a plain unique index — the index
must keep introspecting on the referenced table while constraint-backed
indexes stay excluded. Confirmed red with the filter removed.

Gate note: the prior test:packages run failed only on a 100ms-timeout
scheduling flake in @prisma-next/family-mongo (untouched package); the
suite passes in isolation (14 files / 170 tests green).

Relates to TML-3035.

Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
…tively

A Supabase-extension project has a contract space that pins a head ref
but ships zero migration packages by design (the pack's auth/storage
tables are external; it emits no DDL). migrate treated every
empty-graph space not already at its head as "never planned" and failed
PN-RUN-3000 — and its remediation was circular: it prescribed
`migration plan --to <hash>`, but full-hash contract refs only resolve
against migration-graph nodes, so the empty graph rejected the very
hash the error supplied. db init was the only path.

The model already decides this case elsewhere, in the same words: the
db-init aggregate planner resolves empty-graph extension spaces via a
declared-state zero-op plan ("every real case is an all-external
extension space (e.g. Supabase's auth/storage)"), and check-integrity
codifies "when a space ships no migrations, the planner emits no DDL
for it — the database is treated as already at the declared state".
migrate now mirrors that: an empty-graph EXTENSION space resolves
declaratively (marker advances to its head ref, zero operations, inside
the per-space transaction), with the same invariant guard db init
applies; the never-planned failure remains for the APP space, where an
authored graph is genuinely required. The "Already up to date"
short-circuit now counts a marker advance as pending work so a
declared-state resolution actually executes.

The remaining never-planned remediation is now runnable verbatim: the
fix prescribes `prisma-next migration plan --name <slug>` (the bare
form targets the working contract — the same contract the app head ref
is synthesized from) instead of a `--to <hash>` the empty graph cannot
resolve. The e2e test executes the printed commands literally and
migrate succeeds afterwards.

Relates to TML-3035.

Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
… in a typed error

Current Supabase projects sign ES256 via JWKS by default, while
`supabase status` still prints a JWT_SECRET that only fits legacy HS256
projects. A user wiring that secret in got a raw jose internal at
asUser ("Key for the ES256 algorithm must be one of type CryptoKey...
Received an instance of Uint8Array") that never names the problem.

verifyJwt now decodes the token header before verification and raises
InvalidJwtError (the error asUser callers already catch) when the
algorithm cannot match the configured key material, in both directions:
an asymmetric token (ES*/RS*/PS*/EdDSA) against jwtSecret says to
configure jwksUrl (https://<project>/auth/v1/.well-known/jwks.json);
an HS* token against jwksUrl says a legacy project needs jwtSecret.
The jwks-side check fires before any JWKS fetch.

Relates to TML-3035.

Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
…es; ES256/JWKS coverage

bootstrapSupabaseShim granted service_role ALL on auth.*/storage.* and
anon/authenticated SELECT — privileges a real Supabase withholds. The
reference fixture already carries the real GRANT / ALTER DEFAULT
PRIVILEGES statements verbatim (including default privileges for the
postgres role, which tests connect as), so the shim now restores the
fixture and adds nothing: its job is fidelity to a fresh
`supabase db reset`. A shim more permissive than production let tests
pass that fail on a real project (findings sections 6 and 8).

Fallout lands where the docs point users: tests exercising the
`.supabase` admin root issue the narrow grant in their own setup
(GRANT USAGE ON SCHEMA auth TO service_role; GRANT SELECT ON TABLE
auth.users TO service_role — refresh_tokens/sessions for the tests
reading those tables). The skeleton cascade test gains a RESET ROLE
before its platform-admin delete: the shared PGlite session keeps the
session-level role GUC a role-bound runtime set, and the over-grant had
been masking that leak. The real-Supabase acceptance harness does not
touch the admin root, so it needs no grant.

ES256/JWKS coverage: the RLS role-binding suite gains a hermetic test
that generates a P-256 keypair, serves a JWKS from a local HTTP server,
and proves the full asUser path (ES256 verify via jwksUrl, then role
binding and RLS-scoped reads) — the default configuration of a current
Supabase project.

Relates to TML-3035.

Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
The prisma-next-supabase skill and package README described a Supabase
that no longer exists: they led with jwtSecret (current projects sign
ES256 via JWKS), claimed service_role holds grants on auth./storage.
(a real project grants it nothing there), told users to grant roles
access to their own public tables (Supabase default privileges already
cover them), and documented the deleted test/utils shim as the testing
path. Rewritten: jwksUrl-first JWT guidance with the legacy-HS256
demotion, the narrow one-time service_role grant for admin reads,
inverted grants guidance, and an RLS testing story built on supabase
start + supabase test db (pgTAP).

Refs: TML-3035
Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
The fidelity class of bug (TML-3035 findings sections 5/6/8) shipped
because nothing exercised the extension against real Supabase defaults:
the acceptance harness was env-guarded and never ran in CI. New
supabase-acceptance job in ci.yml: supabase start in examples/supabase
(minimal stock supabase/config.toml added), credentials exported from
supabase status, then the acceptance suite. Follows the sibling jobs
exactly — plain pull_request/merge_group triggers, per-step inert-diff
skip (any packages/** or examples/** change is non-inert, so
extension-supabase, examples/supabase, and postgres target/adapter
changes always run it), setup composite + Turbo cache,
supabase/setup-cli pinned by SHA.

The harness itself now exercises the stack real signing config: a new
test signs up a user through GoTrue and verifies its issued token
(ES256 on a current stack) through the project
/auth/v1/.well-known/jwks.json endpoint, gated on
SUPABASE_URL/SUPABASE_ANON_KEY. The three existing flows keep
self-minted HS256 tokens using the JWT secret the stack provides. The
manual per-table public.profile grants are gone — a stock project
covers app tables via default privileges (findings section 7) — along
with the stale comment claiming the shim fabricates grants. README
updated to the CI-run story.

Branch protection note: the job is in the required workflow (CI (PR))
following the sibling pattern; the ruleset that marks jobs required is
managed outside the repo and needs "Supabase Acceptance" added.

Relates to TML-3035.

Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
…e RLS fixture

The restored Supabase reference fixture carries the platform default
privileges for the postgres role, so tables dbInit creates in public
already grant anon/authenticated/service_role — the per-table GRANTs in
applyGrantsFixture duplicated that and modelled the inverted guidance
findings section 7 corrected. Only the PGlite WAL-schema accommodation
remains.

Relates to TML-3035.

Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
…ed-index test

tsc-based typecheck flagged the untyped introspect() result (the
descriptor-typed adapter returns the wide schema-IR node); cast to
PostgresDatabaseSchemaNode like the sibling introspection tests.

Relates to TML-3035.

Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
The owner-scoped assertion was count(*) >= 0 — vacuously true. Seed an
auth user + profile and assert exact counts for both roles.

Refs: TML-3035
Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
…restoreSupabaseReference

bootstrapSupabaseShim had become a thin wrapper over
restoreSupabaseReference, and the READMEs already describe the
substrate by the inner name. Delete the wrapper (no alias kept): the
fixture module test/fixtures/supabase-reference/restore.ts is THE
entrypoint, its header absorbs the wrapper docs (fidelity contract,
narrow-grant guidance), and every in-repo caller imports
restoreSupabaseReference — extension tests directly, examples/supabase
through its renamed test/supabase-reference.ts bridge. The historical
mentions of bootstrapSupabaseShim in the 0.14-to-0.15 and 0.15-to-0.16
upgrade instructions stay: they describe the removed 0.15 export as it
appears in user code.

Relates to TML-3035.

Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
@wmadden-electric
wmadden-electric requested a review from a team as a code owner July 16, 2026 13:03
@wmadden-electric

Copy link
Copy Markdown
Contributor Author

Prisma Next 0.15.0 + Supabase — findings from building an app

Verbatim report from an external agent run that installed prisma-next 0.15.0 and @prisma-next/extension-supabase from npm, followed the prisma-next-supabase skill, and built a working RLS notes app against a real Supabase project. Received 2026-07-16.

Seven defects found while building a working notes app on @prisma-next/extension-supabase, following the prisma-next-supabase skill. Every one is reproduced below with verbatim output.

The app itself works and is in this repo: contract → db init → RLS enforced by Postgres across anon / authenticated / service_role. The problems are in the surrounding surface — publishing, migrations, verification, and the skill's accuracy about real Supabase projects.

One theme worth reading first. The extension's testing story rests entirely on bootstrapSupabaseShim, and it fails in two independent ways that together explain most of what follows.

  • It doesn't run outside the monorepo (§1): its SQL fixtures aren't published, so no consumer can execute the documented hermetic path at all.
  • Where it does run, it provisions a Supabase that a real project doesn't match. It grants service_role privileges on auth.* that real Supabase withholds (§6), and it only mints HS256 tokens, while current Supabase signs ES256 via JWKS (§5).

So the suite passes green against a database that is both more permissive and differently configured than any real project, and a user following the skill hits §5 and §6 on first contact. Raising the shim's fidelity — or adding one acceptance test against a real Supabase — would have caught both, and is worth more than patching the individual symptoms.

Environment

prisma-next 0.15.0
@prisma-next/extension-supabase 0.15.0
@prisma-next/postgres 0.15.0
Supabase CLI 2.95.4 (local stack, supabase start)
Postgres 17.6
Node v24.13.0
Pack contract hash sha256:a6d5d037670d66b5016dfde8577ec89f693e97dc4601d8cde41bbb6082f99de6

Reproduction repo: the external agent's directory. src/prisma/contract.prisma is a two-model contract (Profile, Note) with a cross-space FK to supabase:auth.AuthUser, @@rls on both models, and seven policy_* blocks. Nothing exotic.


1. bootstrapSupabaseShim cannot run when installed from npm — files omits its fixtures

Severity: high. This is the skill's documented hermetic-testing path, and it is broken for every consumer outside the monorepo.

test/utils.mjs resolves and reads test/fixtures/supabase-reference/{roles,schema}.sql at runtime. The published package ships only dist and src:

$ node -p "require('@prisma-next/extension-supabase/package.json').files"
[ 'dist', 'src' ]

Reproduce:

import { bootstrapSupabaseShim } from '@prisma-next/extension-supabase/test/utils';
await bootstrapSupabaseShim({ query: async () => {} });
ENOENT: no such file or directory, open
'.../node_modules/@prisma-next/extension-supabase/test/fixtures/supabase-reference/roles.sql'

The failure is dependency-free — it happens before any database call, so a fake client is enough to show it.

Note the irony: restore.ts's own comment explains that resolveFixtureDir() uses a package.json self-reference specifically so it "survives bundling" into dist/test/utils.mjs. The resolution strategy is correct; the files just never ship.

Fix: add test/fixtures (or at minimum the two .sql files) to files in the extension's package.json. Regression test: install the packed tarball into a scratch dir and call bootstrapSupabaseShim — a monorepo-internal test cannot catch this, because the fixtures are on disk there regardless.


2. migration plan generates a migration.ts that cannot be imported (RLS contracts)

Severity: high. This makes prisma-next migrate unusable for any contract using RLS — i.e. every Supabase contract.

prisma-next migration plan emitted migrations/app/<ts>_migration/migration.ts importing two symbols that @prisma-next/postgres/migration does not export:

import {
  Migration, MigrationCLI, col,
  createRlsPolicy,          // <- not exported
  enableRowLevelSecurity,   // <- not exported
  fn, lit, primaryKey,
} from '@prisma-next/postgres/migration';
$ node -e "import('@prisma-next/postgres/migration').then(m => console.log(Object.keys(m).filter(k => /rls|policy|row/i.test(k))))"
[]

$ node migrations/app/20260716T0822_migration/migration.ts
SyntaxError: The requested module '@prisma-next/postgres/migration' does not provide an export named 'createRlsPolicy'

The file carries a #!/usr/bin/env -S node shebang, so it is meant to be executable. It is also what migrate replays.

npx tsc --noEmit reports the same thing statically, which suggests the generated output is not typechecked in CI:

migrations/app/20260716T0822_migration/migration.ts(8,3): error TS2305:
  Module '"@prisma-next/postgres/migration"' has no exported member 'createRlsPolicy'.
migrations/app/20260716T0822_migration/migration.ts(9,3): error TS2305:
  Module '"@prisma-next/postgres/migration"' has no exported member 'enableRowLevelSecurity'.

db init is unaffected because it applies ops.json rather than importing the generated module — which is why the app in the reproduction repo works, and why this defect is easy to miss.

Either the renderer emits names that no longer exist (renamed/never landed), or the façade forgot to re-export them. Worth checking which, since the fix differs.

Regression test: typecheck (or import) the generated migration.ts for a contract containing @@rls + policy_*. Any fixture with RLS would have caught this at build time.


3. migrate prints a remediation that its own CLI rejects

Severity: medium (correctness of guidance; the user is left with no path forward).

Preconditions: a database not yet signed (fresh, or after supabase db reset), with the app migration present on disk. The supabase extension space has a head ref but no migration bundles — expected, since the pack is external and emits no DDL.

$ npx prisma-next migrate --yes
{
  "ok": false,
  "code": "PN-RUN-3000",
  "summary": "No on-disk migrations for contract space \"supabase\"",
  "why": "migrate is replay-only: every contract space must have an authored migration graph on disk.
          Space \"supabase\" has no migrations under `migrations/supabase/` but its head ref targets
          \"sha256:a6d5d037...\".",
  "fix": "Plan the missing edge, then apply it:
          1. prisma-next migration plan --to sha256:a6d5d037... --name <slug>
          2. prisma-next migrate --to sha256:a6d5d037...",
  "meta": { "spaceId": "supabase", "kind": "neverPlanned", "code": "MIGRATION.PATH_UNREACHABLE" }
}

Following step 1 verbatim, with the exact hash from the error:

$ npx prisma-next migration plan --to sha256:a6d5d037... --name supabase-baseline --yes
{
  "ok": false,
  "code": "PN-RUN-3000",
  "summary": "Not a known contract reference: \"sha256:a6d5d037...\"",
  "why": "No contract matching \"sha256:a6d5d037...\" exists in the migration graph or refs index."
}

The hash the error tells you to pass is the hash the next command says it has never heard of. It is in migrations/supabase/refs/head.json and is the pack's own contract, so "not known" is itself questionable.

Underlying question: should an external space ever require an authored migration graph? It has no DDL to replay. If the answer is no, migrate should skip such spaces and finding 3 disappears. If yes, there must be a command that actually creates that edge — today there appears to be none, and db init is the only way forward.


4. db verify reports 6 false negatives against the pack's own tables

Severity: medium. db verify never returns ok: true against a real Supabase project, which makes it useless as a deploy check.

After a clean supabase db reset + prisma-next db init:

$ npx prisma-next db verify
summary: Database schema does not satisfy contract (6 failures)
  - database.auth.schema_migrations.primary-key                                    | not-found | expects: schema_migrations_pkey
  - database.storage.buckets_vectors.primary-key                                   | not-found | expects: buckets_vectors_pkey
  - database.storage.migrations.primary-key                                        | not-found | expects: migrations_pkey
  - database.storage.migrations.unique:name                                        | not-found | expects: migrations_name_key
  - database.storage.vector_indexes.primary-key                                    | not-found | expects: vector_indexes_pkey
  - database.storage.vector_indexes.foreign-key:bucket_id->storage.buckets_vectors(id) | not-found | expects: vector_indexes_bucket_id_fkey

Every one of those constraints exists, with the expected name and the expected columns:

$ psql -c "SELECT con.conrelid::regclass AS tbl, con.conname, con.contype,
             (SELECT string_agg(a.attname, ',' ORDER BY k.ord)
              FROM unnest(con.conkey) WITH ORDINALITY k(attnum, ord)
              JOIN pg_attribute a ON a.attrelid = con.conrelid AND a.attnum = k.attnum) AS cols
           FROM pg_constraint con
           WHERE con.conname IN ('schema_migrations_pkey','buckets_vectors_pkey','migrations_pkey',
                                 'migrations_name_key','vector_indexes_pkey','vector_indexes_bucket_id_fkey')
           ORDER BY 1;"

             tbl              |            conname            | contype |   cols
------------------------------+-------------------------------+---------+-----------
 auth.schema_migrations       | schema_migrations_pkey        | p       | version
 storage.buckets_vectors      | buckets_vectors_pkey          | p       | id
 storage.migrations           | migrations_pkey               | p       | id
 storage.migrations           | migrations_name_key           | u       | name
 storage.vector_indexes       | vector_indexes_pkey           | p       | id
 storage.vector_indexes       | vector_indexes_bucket_id_fkey | f       | bucket_id

Compare against the reported expected payloads — {columns:["version"], name:"schema_migrations_pkey"}, {columns:["id"], name:"buckets_vectors_pkey"}, etc. They match exactly. So this is an introspection or matching bug, not schema drift.

All 6 are in the pack's namespaces (auth, storage). The app's own tables (public.profile, public.note) verify clean, and other pack tables with PKs (e.g. auth.users) verify fine — so introspection of auth/storage broadly works. Something is specific to these 4 tables.

One lead, offered tentatively — not confirmed by the reporter. Constraint names are unique per-table in Postgres, not per-schema, and both failing names are duplicated across schemas in a Supabase database:

 _realtime.schema_migrations   | schema_migrations_pkey
 auth.schema_migrations        | schema_migrations_pkey   <- reported not-found
 realtime.schema_migrations    | schema_migrations_pkey
 storage.migrations            | migrations_pkey          <- reported not-found
 supabase_functions.migrations | migrations_pkey

If introspection keys constraints by name (or name+table) without the schema, these collide and the loser reports not-found. This does not explain buckets_vectors / vector_indexes, whose names are unique — so either there are two causes, or the real one is something else. Treat as a starting point, not a diagnosis.


5. The skill leads with jwtSecret, but current Supabase signs ES256 via JWKS

Severity: high (documentation/skill correctness — this is the first thing a new user hits).

The skill's db.ts workflow, its checklist, and its .env guidance all centre on jwtSecret: process.env['SUPABASE_JWT_SECRET']. jwksUrl is mentioned only as an alternative ("xor jwksUrl").

Current Supabase projects sign with asymmetric keys by default. On a stock supabase start (CLI 2.95.4), GoTrue issues:

{"alg":"ES256","kid":"b81269f1-21d8-4f2e-b719-c2240a840d90","typ":"JWT"}

and publishes /auth/v1/.well-known/jwks.json (kty: EC, crv: P-256). supabase status still prints a JWT_SECRET, so the obvious move is to wire it in exactly as the skill shows. Doing so fails at asUser:

InvalidJwtError: Key for the ES256 algorithm must be one of type CryptoKey, KeyObject, or JSON Web Key.
                 Received an instance of Uint8Array

That message is a jose internal leaking through. It never says "this project uses asymmetric signing keys — use jwksUrl instead of jwtSecret", which is the actual problem and the actual fix. A user following the skill verbatim lands here with no route out.

Fixes, in priority order:

  1. Skill: lead with jwksUrl as the default for current projects; demote jwtSecret to "legacy HS256 projects". Update the checklist and .env guidance to match.
  2. Runtime: detect the alg/key-type mismatch and raise an actionable SupabaseConfigError"token is ES256 but jwtSecret is configured; asymmetric projects need jwksUrl".
  3. Shim: the hermetic fixture only exercises self-signed HS256 tokens ("Test JWTs are self-signed HS256 tokens using the same secret the factory gets"), so no test covers the default configuration of a current Supabase project. Add ES256/JWKS coverage.

Workaround used by the reporter — their db.ts prefers JWKS and falls back:

function jwtKeySource(): { jwksUrl: string } | { jwtSecret: string } {
  const jwksUrl = process.env['SUPABASE_JWKS_URL'];
  if (jwksUrl) return { jwksUrl };
  const jwtSecret = process.env['SUPABASE_JWT_SECRET'];
  if (jwtSecret) return { jwtSecret };
  throw new Error('Set SUPABASE_JWKS_URL (asymmetric) or SUPABASE_JWT_SECRET (legacy HS256), not both.');
}

6. service_role has no grants on auth.* — the db.supabase admin root fails out of the box

Severity: high (documentation + feature that does not work as described on a real project).

The skill states this as a design invariant:

Admin access to auth.* / storage.* is a secondary root on service_role only. […]
service_role is the one role with grants on those schemas over a direct connection.

On a real Supabase project it does not have those grants. On a fresh supabase db reset:

$ psql -tAc "SELECT 'usage_on_auth_schema=' || has_schema_privilege('service_role','auth','USAGE')
          || '  select_on_auth_users=' || has_table_privilege('service_role','auth.users','SELECT');"
usage_on_auth_schema=true  select_on_auth_users=false

service_role can enter the schema but cannot read the table. Only postgres holds privileges on auth.users — the full result, no service_role row exists:

$ psql -c "SELECT grantee, privilege_type FROM information_schema.role_table_grants
           WHERE table_schema='auth' AND table_name='users' ORDER BY grantee;"
 grantee  | privilege_type
----------+----------------
 postgres | INSERT
 postgres | SELECT
 postgres | UPDATE
 postgres | DELETE
 postgres | TRUNCATE
 postgres | REFERENCES
 postgres | TRIGGER
(7 rows)

So the documented admin read fails:

await db.asServiceRole().supabase.orm.auth.AuthUser.select('id', 'email').all();
error: permission denied for table users   (sqlState 42501)
hint:  Grant the required privileges to the current role with: GRANT SELECT ON auth.users TO service_role;

Why the tests don't catch it: bootstrapSupabaseShim grants exactly what real Supabase withholds —

await client.query("GRANT ALL ON ALL TABLES IN SCHEMA auth TO service_role");
await client.query("GRANT ALL ON ALL TABLES IN SCHEMA storage TO service_role");

The hermetic tests therefore pass against a database that is strictly more permissive than any real project. This is the clearest instance of the fidelity gap in the opening theme.

Fixes: correct the skill's claim (service_role needs an explicit grant; the pack does not provision one); state the grant users must run; and either make the shim match real Supabase's default privileges, or add an acceptance test against a real project that would have caught it.

Workaround used by the reporter, deliberately narrow:

GRANT USAGE ON SCHEMA auth TO service_role;
GRANT SELECT ON TABLE auth.users TO service_role;

7. Skill overstates the grants needed for your own tables (inverse of §6)

Severity: low (documentation; sends users to do unnecessary, over-broad work).

The skill says:

After your first migration creates a table, grant the roles access once (Supabase's own
dashboard-created tables get grants automatically; Prisma-Next-created tables do not)

Tables created in public inherit Supabase's ALTER DEFAULT PRIVILEGES, regardless of who creates them. After prisma-next db init, with no manual grants run:

 table_name |    grantee    |                          privs
------------+---------------+---------------------------------------------------------
 note       | anon          | DELETE,INSERT,REFERENCES,SELECT,TRIGGER,TRUNCATE,UPDATE
 note       | authenticated | DELETE,INSERT,REFERENCES,SELECT,TRIGGER,TRUNCATE,UPDATE
 note       | service_role  | DELETE,INSERT,REFERENCES,SELECT,TRIGGER,TRUNCATE,UPDATE
 profile    | anon          | ...same...

RLS is what protects these rows, which is the intended Supabase model. The skill's Workflow — Grants section is unnecessary for public tables, and its GRANT ALL … TO service_role suggestion is broader than anything required.

The genuinely required grant is the opposite one: auth.* for service_role (§6). The skill has the two cases backwards.


Suggested triage order

# Finding Severity Shape of fix
2 Generated migration.ts can't import → migrate broken for all RLS contracts High Export the symbols, or fix the renderer; typecheck generated output in CI
5 Skill leads with jwtSecret; current Supabase is ES256/JWKS High Skill rewrite + actionable runtime error + ES256 test coverage
6 service_role lacks auth.* grants; .supabase root fails High Correct the skill; align shim with real defaults
1 Shim's fixtures unpublished → hermetic tests impossible from npm High Add test/fixtures to files; test against packed tarball
3 migrate's remediation is circular for external spaces Medium Skip external spaces, or provide a command that plans the edge
4 db verify false negatives on pack tables Medium Fix constraint introspection/matching
7 Grants guidance inverted Low Skill edit

What worked

Worth recording, since the above is all negative:

  • contract emit accepted the cross-space FK, @@rls, and all seven policy_* blocks first try, with no iteration.
  • The planner emitted REFERENCES "auth"."users"("id") and zero DDL against auth/storage — exactly as documented.
  • db init applied tables, FK, ENABLE ROW LEVEL SECURITY, and every policy correctly, and the emitted SQL matched the contract's intent verbatim.
  • Role binding works, and RLS enforcement is genuinely correct: anon sees only published rows, owners see their own, service_role bypasses, cross-owner UPDATE matches 0 rows, WITH CHECK rejects forged ownership.
  • The role-first design (no db.orm until a role is bound) is a good call and reads well at the call site.
  • Error envelopes are excellent where correct — PN-RUN-3000 with why/fix/meta made §3 diagnosable in one shot. The problem there was the content of fix, not the format.

Addendum (operator decision, 2026-07-16)

Supersedes §1's suggested fix and sharpens the theme:

  • §1 becomes "delete", not "fix". bootstrapSupabaseShim has been exported-but-broken for at least three minor versions; no external user can ever have run it, and nobody reported it. There is nothing to deprecate: drop ./test/utils from exports, keep the shim internal for the extension's own tests. Do not publish the fixtures.
  • The user-facing testing story is Supabase's own tooling. supabase test db runs pgTAP against the local containers, alongside supabase start / db reset. pgTAP fits exactly what users would test ("assert anon cannot see this row"), and users already run the CLI for local dev. Rewrite the skill's "Testing without a Supabase project" section accordingly.
  • The disqualifying argument is the skill's own text: "RLS is enforced by policies and grants." The shim's grants differ from real Supabase in both directions, so it cannot faithfully test RLS — the only reason a user would reach for it. Green-locally-broken-in-prod is worse than no test. The shim's world also got written down as guidance (the skill's grant advice mirrors the shim's ALTER DEFAULT PRIVILEGES line-for-line), so the shim actively produced §6/§7.
  • §8 (new finding): the fidelity blind spot is PN's, not just the user's. Un-exporting the shim fixes the user-facing story but not the pipeline that shipped §5/§6: internal tests still run against unfaithful grants and HS256-only tokens, and the real-Supabase acceptance harness (examples/supabase/test/real-supabase.acceptance.test.ts) is env-guarded and does not run in CI. Making that acceptance run non-optional is what actually catches this class of bug.

@coderabbitai

coderabbitai Bot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

This PR adds live Supabase acceptance CI, migrates Supabase tests to internal fixtures, improves JWT mismatch errors, updates empty-space migration behavior, adds PostgreSQL catalog introspection, and changes PostgreSQL RLS migration rendering to object-based instance calls.

Changes

Supabase runtime and acceptance

Layer / File(s) Summary
Live acceptance harness
.github/workflows/ci.yml, examples/supabase/*
CI starts a local Supabase stack, exports credentials, and runs real acceptance tests covering RLS and GoTrue/JWKS flows.
Fixture and package migration
packages/3-extensions/supabase/*
Tests use internal mock-schema fixtures; the published test/utils export is removed and related fixtures/configuration are updated.
JWT validation
packages/3-extensions/supabase/src/runtime/supabase.ts, test/supabase-facade.test.ts
JWT algorithm/key-source mismatches produce specific InvalidJwtError messages before cryptographic verification.

Migration planning

Layer / File(s) Summary
Empty-space planning and remediation
packages/1-framework/3-tooling/{cli,migration}/**, test/integration/test/cli.migrate-external-space.e2e.test.ts
All-external empty extension spaces advance markers with zero operations; never-planned app spaces emit executable name-only remediation commands.

PostgreSQL introspection and RLS rendering

Layer / File(s) Summary
Catalog introspection
packages/3-targets/6-adapters/postgres/**
Constraint and index queries use pg_catalog, preserving composite ordering and supporting restricted-privilege introspection.
RLS migration rendering
packages/3-targets/3-targets/postgres/**
RLS operations are wrapped by PostgresMigration and rendered as this.* calls with object arguments, with expanded validation coverage.

Estimated code review effort: 5 (Critical) | ~120 minutes

Sequence Diagram(s)

sequenceDiagram
  participant CI
  participant SupabaseCLI
  participant AcceptanceTest
  participant SupabaseRuntime
  CI->>SupabaseCLI: Start local Supabase stack
  SupabaseCLI-->>CI: Return database and JWT credentials
  CI->>AcceptanceTest: Run real-Supabase acceptance suite
  AcceptanceTest->>SupabaseRuntime: Configure JWKS and validate user JWT
  SupabaseRuntime-->>AcceptanceTest: Apply RLS-scoped user query
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title matches the PR’s main Supabase fixes, covering RLS migrations, migrate/verify behavior, JWKS auth, and grants.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch tml-3035-supabase-launch-findings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@pkg-pr-new

pkg-pr-new Bot commented Jul 16, 2026

Copy link
Copy Markdown

Open in StackBlitz

@prisma-next/extension-author-tools

npm i https://pkg.pr.new/@prisma-next/extension-author-tools@997

@prisma-next/mongo-runtime

npm i https://pkg.pr.new/@prisma-next/mongo-runtime@997

@prisma-next/family-mongo

npm i https://pkg.pr.new/@prisma-next/family-mongo@997

@prisma-next/sql-runtime

npm i https://pkg.pr.new/@prisma-next/sql-runtime@997

@prisma-next/family-sql

npm i https://pkg.pr.new/@prisma-next/family-sql@997

@prisma-next/extension-arktype-json

npm i https://pkg.pr.new/@prisma-next/extension-arktype-json@997

@prisma-next/middleware-cache

npm i https://pkg.pr.new/@prisma-next/middleware-cache@997

@prisma-next/mongo

npm i https://pkg.pr.new/@prisma-next/mongo@997

@prisma-next/extension-paradedb

npm i https://pkg.pr.new/@prisma-next/extension-paradedb@997

@prisma-next/extension-pgvector

npm i https://pkg.pr.new/@prisma-next/extension-pgvector@997

@prisma-next/extension-postgis

npm i https://pkg.pr.new/@prisma-next/extension-postgis@997

@prisma-next/postgres

npm i https://pkg.pr.new/@prisma-next/postgres@997

@prisma-next/sql-orm-client

npm i https://pkg.pr.new/@prisma-next/sql-orm-client@997

@prisma-next/sqlite

npm i https://pkg.pr.new/@prisma-next/sqlite@997

@prisma-next/extension-supabase

npm i https://pkg.pr.new/@prisma-next/extension-supabase@997

@prisma-next/target-mongo

npm i https://pkg.pr.new/@prisma-next/target-mongo@997

@prisma-next/adapter-mongo

npm i https://pkg.pr.new/@prisma-next/adapter-mongo@997

@prisma-next/driver-mongo

npm i https://pkg.pr.new/@prisma-next/driver-mongo@997

@prisma-next/contract

npm i https://pkg.pr.new/@prisma-next/contract@997

@prisma-next/utils

npm i https://pkg.pr.new/@prisma-next/utils@997

@prisma-next/config

npm i https://pkg.pr.new/@prisma-next/config@997

@prisma-next/errors

npm i https://pkg.pr.new/@prisma-next/errors@997

@prisma-next/framework-components

npm i https://pkg.pr.new/@prisma-next/framework-components@997

@prisma-next/operations

npm i https://pkg.pr.new/@prisma-next/operations@997

@prisma-next/ts-render

npm i https://pkg.pr.new/@prisma-next/ts-render@997

@prisma-next/contract-authoring

npm i https://pkg.pr.new/@prisma-next/contract-authoring@997

@prisma-next/ids

npm i https://pkg.pr.new/@prisma-next/ids@997

@prisma-next/psl-parser

npm i https://pkg.pr.new/@prisma-next/psl-parser@997

@prisma-next/psl-printer

npm i https://pkg.pr.new/@prisma-next/psl-printer@997

@prisma-next/cli

npm i https://pkg.pr.new/@prisma-next/cli@997

@prisma-next/cli-telemetry

npm i https://pkg.pr.new/@prisma-next/cli-telemetry@997

@prisma-next/config-loader

npm i https://pkg.pr.new/@prisma-next/config-loader@997

@prisma-next/emitter

npm i https://pkg.pr.new/@prisma-next/emitter@997

@prisma-next/language-server

npm i https://pkg.pr.new/@prisma-next/language-server@997

@prisma-next/migration-tools

npm i https://pkg.pr.new/@prisma-next/migration-tools@997

prisma-next

npm i https://pkg.pr.new/prisma-next@997

@prisma-next/vite-plugin-contract-emit

npm i https://pkg.pr.new/@prisma-next/vite-plugin-contract-emit@997

@prisma-next/mongo-codec

npm i https://pkg.pr.new/@prisma-next/mongo-codec@997

@prisma-next/mongo-contract

npm i https://pkg.pr.new/@prisma-next/mongo-contract@997

@prisma-next/mongo-value

npm i https://pkg.pr.new/@prisma-next/mongo-value@997

@prisma-next/mongo-contract-psl

npm i https://pkg.pr.new/@prisma-next/mongo-contract-psl@997

@prisma-next/mongo-contract-ts

npm i https://pkg.pr.new/@prisma-next/mongo-contract-ts@997

@prisma-next/mongo-emitter

npm i https://pkg.pr.new/@prisma-next/mongo-emitter@997

@prisma-next/mongo-schema-ir

npm i https://pkg.pr.new/@prisma-next/mongo-schema-ir@997

@prisma-next/mongo-query-ast

npm i https://pkg.pr.new/@prisma-next/mongo-query-ast@997

@prisma-next/mongo-orm

npm i https://pkg.pr.new/@prisma-next/mongo-orm@997

@prisma-next/mongo-query-builder

npm i https://pkg.pr.new/@prisma-next/mongo-query-builder@997

@prisma-next/mongo-lowering

npm i https://pkg.pr.new/@prisma-next/mongo-lowering@997

@prisma-next/mongo-wire

npm i https://pkg.pr.new/@prisma-next/mongo-wire@997

@prisma-next/sql-contract

npm i https://pkg.pr.new/@prisma-next/sql-contract@997

@prisma-next/sql-errors

npm i https://pkg.pr.new/@prisma-next/sql-errors@997

@prisma-next/sql-operations

npm i https://pkg.pr.new/@prisma-next/sql-operations@997

@prisma-next/sql-schema-ir

npm i https://pkg.pr.new/@prisma-next/sql-schema-ir@997

@prisma-next/sql-contract-psl

npm i https://pkg.pr.new/@prisma-next/sql-contract-psl@997

@prisma-next/sql-contract-ts

npm i https://pkg.pr.new/@prisma-next/sql-contract-ts@997

@prisma-next/sql-contract-emitter

npm i https://pkg.pr.new/@prisma-next/sql-contract-emitter@997

@prisma-next/sql-lane-query-builder

npm i https://pkg.pr.new/@prisma-next/sql-lane-query-builder@997

@prisma-next/sql-relational-core

npm i https://pkg.pr.new/@prisma-next/sql-relational-core@997

@prisma-next/sql-builder

npm i https://pkg.pr.new/@prisma-next/sql-builder@997

@prisma-next/target-postgres

npm i https://pkg.pr.new/@prisma-next/target-postgres@997

@prisma-next/target-sqlite

npm i https://pkg.pr.new/@prisma-next/target-sqlite@997

@prisma-next/adapter-postgres

npm i https://pkg.pr.new/@prisma-next/adapter-postgres@997

@prisma-next/adapter-sqlite

npm i https://pkg.pr.new/@prisma-next/adapter-sqlite@997

@prisma-next/driver-postgres

npm i https://pkg.pr.new/@prisma-next/driver-postgres@997

@prisma-next/driver-sqlite

npm i https://pkg.pr.new/@prisma-next/driver-sqlite@997

commit: a8d92c7

@github-actions

Copy link
Copy Markdown

size-limit report 📦

Path Size
postgres / no-emit 158.95 KB (-0.02% 🔽)
postgres / emit 132.46 KB (-0.04% 🔽)
mongo / no-emit 98.71 KB (0%)
mongo / emit 89.43 KB (0%)
cf-worker / no-emit 185.12 KB (-0.02% 🔽)
cf-worker / emit 155.88 KB (-0.02% 🔽)

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (2)
skills/prisma-next-supabase/SKILL.md (1)

134-136: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Ensure strict TypeScript safety in configuration snippet.

In TypeScript strict mode, process.env['XYZ'] is inferred as string | undefined, but url and jwksUrl require a string. Consider appending the non-null assertion operator (!) to match the exact snippet pattern used in packages/3-extensions/supabase/README.md.

💡 Proposed consistency fix
-  url: process.env['DATABASE_URL'],        // direct Postgres connection — see pitfalls
-  jwksUrl: process.env['SUPABASE_JWKS_URL'], // https://<project-ref>.supabase.co/auth/v1/.well-known/jwks.json
+  url: process.env['DATABASE_URL']!,        // direct Postgres connection — see pitfalls
+  jwksUrl: process.env['SUPABASE_JWKS_URL']!, // https://<project-ref>.supabase.co/auth/v1/.well-known/jwks.json
   // Legacy HS256 projects use jwtSecret: process.env['SUPABASE_JWT_SECRET'] instead — exactly one of the two.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@skills/prisma-next-supabase/SKILL.md` around lines 134 - 136, Update the
configuration snippet’s process.env values for url and jwksUrl to use non-null
assertions, matching the established pattern in the Supabase README and
satisfying strict TypeScript string requirements.
examples/supabase/test/supabase-reference.ts (1)

1-2: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Avoid re-exporting files.

As per coding guidelines, do not re-export from one file in another unless it is located within an exports/ folder. Consider importing restoreSupabaseReference directly in the consumer test files and removing this intermediate module.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@examples/supabase/test/supabase-reference.ts` around lines 1 - 2, Remove the
intermediate re-export of restoreSupabaseReference from supabase-reference.ts,
and update consumer test files to import restoreSupabaseReference directly from
its fixture module. Keep re-exports limited to files within an exports/ folder.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@examples/supabase/README.md`:
- Around line 49-53: Update the environment-variable setup in the README example
to export DATABASE_URL, SUPABASE_JWT_SECRET, SUPABASE_URL, and SUPABASE_ANON_KEY
before invoking pnpm test, ensuring the acceptance tests receive the credentials
and do not silently skip.

In `@examples/supabase/test/rls-role-binding.integration.test.ts`:
- Around line 365-387: Move the supabase<Contract>() client creation into an
outer try/finally that owns JWKS server cleanup, so failures during client
initialization still execute jwksServer.close(). Preserve the existing
db.close() cleanup for successfully created clients, while ensuring the server
is closed exactly once across both success and failure paths.

In `@packages/1-framework/3-tooling/cli/src/control-api/operations/migrate.ts`:
- Around line 408-436: The non-app zero-operation path must only apply to
extensions whose contract is explicitly all-external. In migrate.ts, update the
extension handling around the existing isAppSpace check and
buildAtHeadResolution call to validate the extension contract first, returning
the existing missing-graph unsatisfiable result for managed extensions while
preserving declarative advancement for all-external ones. In
packages/1-framework/3-tooling/cli/test/control-api/migrate-plan-space-path.test.ts
lines 44-77, change the fixture to explicitly represent an all-external
extension and add coverage confirming a managed extension is rejected.

In `@test/integration/test/cli.migrate-external-space.e2e.test.ts`:
- Around line 199-228: Strengthen the remediation assertions around
errorJson.fix by validating the complete expected remediation text, including
all commands, flags, and configuration. Parse or extract the suggested plan and
migrate commands from fix, substitute the slug, and pass those derived arguments
to runMigrationPlan and runMigrate instead of hardcoding them, while preserving
the existing success assertions.

---

Nitpick comments:
In `@examples/supabase/test/supabase-reference.ts`:
- Around line 1-2: Remove the intermediate re-export of restoreSupabaseReference
from supabase-reference.ts, and update consumer test files to import
restoreSupabaseReference directly from its fixture module. Keep re-exports
limited to files within an exports/ folder.

In `@skills/prisma-next-supabase/SKILL.md`:
- Around line 134-136: Update the configuration snippet’s process.env values for
url and jwksUrl to use non-null assertions, matching the established pattern in
the Supabase README and satisfying strict TypeScript string requirements.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

Run ID: f85e3d1a-8058-453b-9f1c-05504131433a

📥 Commits

Reviewing files that changed from the base of the PR and between 696473f and 0201f07.

📒 Files selected for processing (49)
  • .github/workflows/ci.yml
  • examples/supabase/README.md
  • examples/supabase/supabase/.gitignore
  • examples/supabase/supabase/config.toml
  • examples/supabase/test/explicit-namespace-query.integration.test.ts
  • examples/supabase/test/native-enum-session.integration.test.ts
  • examples/supabase/test/real-supabase.acceptance.test.ts
  • examples/supabase/test/rls-role-binding.integration.test.ts
  • examples/supabase/test/skeleton.integration.test.ts
  • examples/supabase/test/supabase-bootstrap.ts
  • examples/supabase/test/supabase-reference.ts
  • packages/1-framework/3-tooling/cli/src/control-api/operations/migrate.ts
  • packages/1-framework/3-tooling/cli/src/utils/cli-errors.ts
  • packages/1-framework/3-tooling/cli/test/cli-errors.test.ts
  • packages/1-framework/3-tooling/cli/test/control-api/migrate-plan-space-path.test.ts
  • packages/3-extensions/supabase/README.md
  • packages/3-extensions/supabase/package.json
  • packages/3-extensions/supabase/src/runtime/supabase.ts
  • packages/3-extensions/supabase/test/brownfield-infer.integration.test.ts
  • packages/3-extensions/supabase/test/classification.e2e.test.ts
  • packages/3-extensions/supabase/test/cross-contract-fk.integration.test.ts
  • packages/3-extensions/supabase/test/fixtures/supabase-reference/restore.ts
  • packages/3-extensions/supabase/test/infer-cross-space-fk.integration.test.ts
  • packages/3-extensions/supabase/test/roles-verify.integration.test.ts
  • packages/3-extensions/supabase/test/service-role-refresh-tokens.integration.test.ts
  • packages/3-extensions/supabase/test/supabase-bootstrap.ts
  • packages/3-extensions/supabase/test/supabase-facade.test.ts
  • packages/3-extensions/supabase/tsdown.config.ts
  • packages/3-targets/3-targets/postgres/src/core/migrations/op-factory-call.ts
  • packages/3-targets/3-targets/postgres/src/core/migrations/postgres-migration.ts
  • packages/3-targets/3-targets/postgres/src/exports/op-factory-call.ts
  • packages/3-targets/3-targets/postgres/test/migrations/op-factory-call.lowering.test.ts
  • packages/3-targets/3-targets/postgres/test/migrations/render-typescript.test.ts
  • packages/3-targets/3-targets/postgres/test/migrations/rls-disable-rename-ops.test.ts
  • packages/3-targets/6-adapters/postgres/src/core/control-adapter.ts
  • packages/3-targets/6-adapters/postgres/test/control-adapter.defaults.test.ts
  • packages/3-targets/6-adapters/postgres/test/control-adapter.test.ts
  • packages/3-targets/6-adapters/postgres/test/migrations/introspect-fk-referenced-unique-index.integration.test.ts
  • packages/3-targets/6-adapters/postgres/test/migrations/introspect-select-only-privileges.integration.test.ts
  • packages/3-targets/6-adapters/postgres/test/migrations/planner.reconciliation.integration.test.ts
  • packages/3-targets/6-adapters/postgres/test/migrations/render-typescript.roundtrip.test.ts
  • skills/extension-author/prisma-next-extension-upgrade/upgrades/0.15-to-0.16/instructions.md
  • skills/prisma-next-contract/SKILL.md
  • skills/prisma-next-supabase/SKILL.md
  • skills/upgrade/prisma-next-upgrade/upgrades/0.15-to-0.16/instructions.md
  • test/integration/test/cli.migrate-external-space.e2e.test.ts
  • test/integration/test/contract-space-fixture/external-space.ts
  • test/integration/test/fixtures/cli/cli-e2e-test-app/fixtures/migrate-external-space/contract.ts
  • test/integration/test/fixtures/cli/cli-e2e-test-app/fixtures/migrate-external-space/prisma-next.config.with-db.ts
💤 Files with no reviewable changes (4)
  • examples/supabase/test/supabase-bootstrap.ts
  • packages/3-extensions/supabase/test/supabase-bootstrap.ts
  • packages/3-extensions/supabase/package.json
  • packages/3-extensions/supabase/tsdown.config.ts

Comment thread examples/supabase/README.md Outdated
Comment thread test/integration/test/cli.migrate-external-space.e2e.test.ts
…li isn't org-allowlisted

The org restricts workflow actions to an allowlist and supabase/setup-cli
is not on it, so the CI (PR) workflow hit startup_failure and ran no jobs
at all. Replace the action step with a direct install: download the
pinned v2.95.4 linux_amd64 release tarball, verify its sha256 against the
release's published checksums file (hard-coded so the pin is real), and
put the binary on PATH. Bumping the CLI is a two-line change (version +
sha). Everything else in the job is unchanged.

Relates to TML-3035.

Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
@wmadden-electric wmadden-electric changed the title TML-3035: fix the Supabase first-contact defects from the field report TML-3035: a first Supabase project works first-try — RLS migrations, verify, migrate, JWKS, grants Jul 17, 2026

@wmadden wmadden left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Preemptive approve

Comment thread .github/workflows/ci.yml
Comment thread examples/supabase/test/supabase-reference.ts Outdated
…tension — examples model only public API

examples/ are user-facing, and the example hermetic lane imported the
monorepo-internal test substrate through a relative path into the
extension package — unresolvable for anyone who copies the example out
of the repo. The four hermetic suites (rls-role-binding, skeleton,
explicit-namespace-query, native-enum-session) plus the no-policy /
renamed-policy variant fixtures move into
packages/3-extensions/supabase/test/, alongside the eight sibling
suites that already use the substrate directly. They exercise the same
contract via a new test fixture app (test/fixtures/example-app: the
example contract shape plus db/session-queries helpers); test names
and assertions are unchanged. The fixture contracts stay
pipeline-emitted: the package gains an emit script wired into the root
fixtures:emit (regen verified drift-free), and the extension vitest
config takes over the PGlite crash mitigations (execArgv + CI retry).

examples/supabase now ships exactly what a user can run: the
real-Supabase acceptance suite (skip-guarded without a stack) and the
compile-only type test. Its README run snippet also becomes a single
command with inline env vars — the previous shape set the variables as
standalone assignments that never reached pnpm test, so the suite
silently skipped. The JWKS test (at its new home) closes its local
HTTP server even when client creation rejects, so a failed
supabase() call cannot leak the listener.

Relates to TML-3035.

Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
… migrations

The declared-state resolution (advance a space marker to its head with
zero operations) keyed on graph emptiness — plus extension-ness on the
migrate path. The real precondition is the property those checks
assumed: every element the space declares is externally managed
(control policy external, ADR 224). Only then can the storage structure
be correct without a migration having produced it; an extension that
declares a managed element but ships no migration graph is an
authoring bug and must fail loudly, not silently advance.

New shared predicate allStorageElementsExternal (migration-tools
aggregate) walks elementCoordinates over the composed contract storage
and resolves each element via effectiveControlPolicy (element control,
then the contract defaultControlPolicy). Both consumers now guard on
it: the db-init aggregate planner (declared-state branch fails
extensionPathUnreachable) and the CLI migrate planSpacePath (falls
through to never-planned, whose wording now names the enforced rule).
Comments that stated "every real case is an all-external space" as an
assumption now describe the check.

Red-first at both layers: an empty-graph space with one managed
element fails loudly (db-init: extensionPathUnreachable; migrate:
never-planned), while the all-external shape (the Supabase case, now
declared via defaultControlPolicy on the e2e fixture) still advances
exactly as before.

Relates to TML-3035.

Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
The "remediation runs verbatim" e2e asserted two substrings of the fix
and then executed independently hard-coded commands, so a drifted
remediation could keep passing. It now asserts the exact numbered
command list and derives each executed argv from the printed text
itself (substituting the <slug> placeholder; harness plumbing like
--config/--json appended), tolerating only incidental whitespace.

Relates to TML-3035.

Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
…aseMockSchema

restoreSupabaseReference was opaque about what callers get: a test
database set up with the mock Supabase schema (the reference fixture:
schemas, tables, roles, real default privileges). Rename the function
and its module (test/fixtures/supabase-reference/set-up-mock-schema.ts)
and update every caller and the README bullet; no alias kept. The
fixture directory name is unchanged.

Also serializes the extension vitest run (pool forks, one worker,
per-file isolation kept for the pg-mocking facade test): the suite now
hosts the moved reference-restoring integration tests, and parallel
PGlite databases made the heaviest WASM restore crash-prone locally.

Relates to TML-3035.

Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/3-extensions/supabase/test/fixtures/supabase-reference/set-up-mock-schema.ts (1)

64-77: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Guarantee session cleanup when fixture replay fails.

If either SQL query rejects after changing row_security or search_path, RESET ALL is skipped and the caller-owned client remains contaminated.

Proposed fix
-  await client.query(rolesSql);
-  await client.query(schemaSql);
+  try {
+    await client.query(rolesSql);
+    await client.query(schemaSql);
+  } finally {
+    await client.query('RESET ALL');
+  }
 
   // pg_dump's preamble includes session-local `SET`s ...
-  await client.query('RESET ALL');
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@packages/3-extensions/supabase/test/fixtures/supabase-reference/set-up-mock-schema.ts`
around lines 64 - 77, Ensure the fixture setup around rolesSql and schemaSql
always executes RESET ALL even when either client.query call rejects. Wrap the
replay queries in cleanup-safe control flow, preserving the original query error
while guaranteeing session settings are reset on every exit path.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In
`@packages/3-extensions/supabase/test/fixtures/supabase-reference/set-up-mock-schema.ts`:
- Around line 64-77: Ensure the fixture setup around rolesSql and schemaSql
always executes RESET ALL even when either client.query call rejects. Wrap the
replay queries in cleanup-safe control flow, preserving the original query error
while guaranteeing session settings are reset on every exit path.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

Run ID: c0e9b8c7-26f5-4042-a958-1fc1e1ef356b

📥 Commits

Reviewing files that changed from the base of the PR and between 0201f07 and 92643e9.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (44)
  • .github/workflows/ci.yml
  • examples/supabase/README.md
  • examples/supabase/package.json
  • examples/supabase/test/real-supabase.acceptance.test.ts
  • examples/supabase/vitest.config.ts
  • package.json
  • packages/1-framework/3-tooling/cli/src/control-api/operations/migrate.ts
  • packages/1-framework/3-tooling/cli/test/control-api/migrate-plan-space-path.test.ts
  • packages/1-framework/3-tooling/migration/src/aggregate/all-external.ts
  • packages/1-framework/3-tooling/migration/src/aggregate/planner.ts
  • packages/1-framework/3-tooling/migration/src/exports/aggregate.ts
  • packages/1-framework/3-tooling/migration/test/aggregate/planner.test.ts
  • packages/3-extensions/supabase/README.md
  • packages/3-extensions/supabase/package.json
  • packages/3-extensions/supabase/scripts/generate-contract.ts
  • packages/3-extensions/supabase/test/brownfield-infer.integration.test.ts
  • packages/3-extensions/supabase/test/classification.e2e.test.ts
  • packages/3-extensions/supabase/test/cross-contract-fk.integration.test.ts
  • packages/3-extensions/supabase/test/explicit-namespace-query.integration.test.ts
  • packages/3-extensions/supabase/test/fixtures/example-app.config.ts
  • packages/3-extensions/supabase/test/fixtures/example-app/contract.d.ts
  • packages/3-extensions/supabase/test/fixtures/example-app/contract.json
  • packages/3-extensions/supabase/test/fixtures/example-app/contract.prisma
  • packages/3-extensions/supabase/test/fixtures/example-app/db.ts
  • packages/3-extensions/supabase/test/fixtures/example-app/session-queries.ts
  • packages/3-extensions/supabase/test/fixtures/no-policy.config.ts
  • packages/3-extensions/supabase/test/fixtures/no-policy/contract.d.ts
  • packages/3-extensions/supabase/test/fixtures/no-policy/contract.json
  • packages/3-extensions/supabase/test/fixtures/no-policy/contract.prisma
  • packages/3-extensions/supabase/test/fixtures/renamed-policy.config.ts
  • packages/3-extensions/supabase/test/fixtures/renamed-policy/contract.d.ts
  • packages/3-extensions/supabase/test/fixtures/renamed-policy/contract.json
  • packages/3-extensions/supabase/test/fixtures/renamed-policy/contract.prisma
  • packages/3-extensions/supabase/test/fixtures/supabase-reference/set-up-mock-schema.ts
  • packages/3-extensions/supabase/test/infer-cross-space-fk.integration.test.ts
  • packages/3-extensions/supabase/test/native-enum-session.integration.test.ts
  • packages/3-extensions/supabase/test/reference-fixture-verify.integration.test.ts
  • packages/3-extensions/supabase/test/rls-role-binding.integration.test.ts
  • packages/3-extensions/supabase/test/roles-verify.integration.test.ts
  • packages/3-extensions/supabase/test/service-role-refresh-tokens.integration.test.ts
  • packages/3-extensions/supabase/test/skeleton.integration.test.ts
  • packages/3-extensions/supabase/vitest.config.ts
  • test/integration/test/cli.migrate-external-space.e2e.test.ts
  • test/integration/test/contract-space-fixture/external-space.ts
💤 Files with no reviewable changes (1)
  • examples/supabase/vitest.config.ts
🚧 Files skipped from review as they are similar to previous changes (7)
  • packages/3-extensions/supabase/test/brownfield-infer.integration.test.ts
  • packages/1-framework/3-tooling/cli/test/control-api/migrate-plan-space-path.test.ts
  • .github/workflows/ci.yml
  • test/integration/test/cli.migrate-external-space.e2e.test.ts
  • test/integration/test/contract-space-fixture/external-space.ts
  • packages/1-framework/3-tooling/cli/src/control-api/operations/migrate.ts
  • examples/supabase/test/real-supabase.acceptance.test.ts

…c lane

The hermetic PGlite suites moved to the extension package; the example
tests only against a live supabase start stack.

Refs: TML-3035
Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
@wmadden-electric
wmadden-electric added this pull request to the merge queue Jul 17, 2026
Merged via the queue into main with commit 0df4f7a Jul 17, 2026
22 checks passed
@wmadden-electric
wmadden-electric deleted the tml-3035-supabase-launch-findings branch July 17, 2026 07:12
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.

2 participants