Commit 3a34e7c
TML-2503: Supabase-internal namespaces via a secondary db.supabase root (slice D) (#845)
## Linked issue
Refs [TML-2503](https://linear.app/prisma-company/issue/TML-2503). Slice
D of extension-supabase (slice A merged in #839). Slice contract:
`projects/extension-supabase/slices/d-service-role-internal-namespaces/spec.md`;
design in decision **C15**.
## At a glance
```ts
const admin = db.asServiceRole();
admin.sql.public.profile… // primary root (app contract) — unchanged
admin.supabase.sql.auth.users.select({ … }) // secondary root (extension contract)
admin.supabase.orm.auth.AuthUser.find({ … })
db.asAnon().supabase // ✗ not on the type — service_role only
```
## Decision
Admin access to Supabase-internal tables (`auth.*`, `storage.*`) is
exposed as a **separate secondary root** `db.asServiceRole().supabase` —
**not** by merging the extension contract into the app contract (a first
attempt did that; rejected in review). The `.supabase` facet is the
extension contract's **own intact** `ExecutionContext` + a second
`SupabaseRuntimeImpl` bound to it, **sharing the app runtime's
driver/pool + the `service_role` session**, with marker-verification off
(the `external` extension contract owns no app-space marker).
`asServiceRole().sql`/`.orm` stay app-contract-only; `asUser`/`asAnon`
are unchanged (no `.supabase`).
## Why a separate root, not a merge
The runtime is **contract-bound by `storageHash`**:
`SqlFamilyAdapter.validatePlan` asserts `plan.meta.storageHash ===
context.contract.storage.storageHash`. A plan built against the
extension contract carries the extension's hash and can't run on the app
runtime — so the two roots are genuinely separate (own context + own
runtime), sharing only the driver/pool. Merging two `Contract`s also
breaks codec-registry uniqueness and the marker check. Two intact
contexts/runtimes sharing one pool is the ADR 230 pattern.
## Behavior changes & evidence
- `db.asServiceRole().supabase.{sql,orm}` query the extension contract;
`asServiceRole().sql`/`.orm` are app-only; `asUser`/`asAnon` have no
`.supabase`. Impl:
`packages/3-extensions/supabase/src/runtime/supabase.ts`
(`SupabaseInternalDb`, `ServiceRoleDb`, `buildExtensionContract`,
`extContext`/`extRuntime`). Evidence:
`examples/supabase/test/explicit-namespace-query.integration.test.ts`
(reads `auth.users` via `.supabase.sql` **and** `.orm`; SQL targets
`"auth"."users"`; `current_setting('role') = 'service_role'`) +
`service-role-namespaces.test-d.ts` (type-level: secondary root carries
`auth`/`storage`; primary root + `asAnon`/`asUser` do not).
## Reviewer notes
- **Independent opus review: APPROVE-WITH-NITS** — confirmed one shared
pool (no double-close), `service_role` binding intact on the ext path,
marker-verify correctly scoped (ext off, app on), no `auth.*` leak to
anon/user, per-contract `validatePlan`. The one acted nit (doc comment
explaining `SupabaseInternalDb` omits `transaction`) is applied.
- This single commit **replaces an earlier merge approach**
(force-pushed away) — the diff is the net secondary-root design.
- `ext-contract-type.ts` is a no-`as` type alias naming the extension
`Contract` distinctly from the framework `Contract` (keeps `lint:casts`
delta 0).
- **v1 limitation (documented):** no single `transaction` spanning the
app root and `.supabase` (separate runtimes, unpinned connections). The
principled fix — a `Runtime` bound to the **aggregate contract** — is
recorded as future direction in C15 + `deferred.md`.
## Testing performed
`pnpm exec turbo run typecheck test lint --filter
@prisma-next/example-supabase --filter @prisma-next/extension-supabase`
— green (example suite 9 tests, incl. the `.supabase` sql+orm reads).
`pnpm lint:casts` delta 0; `pnpm lint:deps` clean. CI re-running on
push.
## Skill update
n/a — the only user-facing surface change (the
`asServiceRole().supabase` admin root) is documented in decision C15 +
`overview.md`; no CLI/config/error-code change.
## Checklist
- [x] All commits are signed off (`git commit -s`).
- [x] I read CONTRIBUTING.md and the change is scoped to one logical
concern.
- [x] Tests are updated (integration + type-level).
- [x] PR title is Linear-prefixed.
- [x] **Skill update** filled in.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Added an additive `db.asServiceRole().supabase` admin root that
enables service-role access to Supabase internal namespaces (e.g.,
`auth`, `storage`) via `.sql` and `.orm`, while keeping the primary
`asServiceRole()` surface restricted to `public`.
* **Tests**
* Added integration coverage for internal-namespace reads, emitted SQL
targeting, and role-scoped execution for both app and internal surfaces.
* Added compile-time typing checks for `service_role`, `anon`, and
user/JWT namespace visibility.
* **Documentation**
* Updated upgrade instructions to describe the new secondary `.supabase`
surface and related exported types.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
---------
Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>1 parent d987376 commit 3a34e7c
12 files changed
Lines changed: 508 additions & 22 deletions
File tree
- examples/supabase/test
- packages/3-extensions/supabase/src
- exports
- runtime
- projects
- extension-supabase
- slices/d-service-role-internal-namespaces
- supabase-integration
- skills
- extension-author/prisma-next-extension-upgrade/upgrades/0.14-to-0.15
- upgrade/prisma-next-upgrade/upgrades/0.14-to-0.15
Lines changed: 236 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
| 199 | + | |
| 200 | + | |
| 201 | + | |
| 202 | + | |
| 203 | + | |
| 204 | + | |
| 205 | + | |
| 206 | + | |
| 207 | + | |
| 208 | + | |
| 209 | + | |
| 210 | + | |
| 211 | + | |
| 212 | + | |
| 213 | + | |
| 214 | + | |
| 215 | + | |
| 216 | + | |
| 217 | + | |
| 218 | + | |
| 219 | + | |
| 220 | + | |
| 221 | + | |
| 222 | + | |
| 223 | + | |
| 224 | + | |
| 225 | + | |
| 226 | + | |
| 227 | + | |
| 228 | + | |
| 229 | + | |
| 230 | + | |
| 231 | + | |
| 232 | + | |
| 233 | + | |
| 234 | + | |
| 235 | + | |
| 236 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
4 | 4 | | |
5 | 5 | | |
6 | 6 | | |
| 7 | + | |
7 | 8 | | |
| 9 | + | |
8 | 10 | | |
9 | 11 | | |
10 | 12 | | |
| |||
Lines changed: 9 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
0 commit comments