@supabase/lite 0.8.0 → 0.8.1-next.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LIMITATIONS.md +17 -4
- package/PATTERNS.md +22 -1
- package/README.md +50 -6
- package/STATUS.md +49 -23
- package/dist/{Connection-D9UUTsjg.d.ts → Connection-ZWTDByQ5.d.ts} +27 -0
- package/dist/cli/index.js +177 -139
- package/dist/cli/lib.d.ts +59 -6
- package/dist/cli/lib.js +48 -45
- package/dist/db/bun/index.d.ts +1 -0
- package/dist/db/bun/index.js +2 -2
- package/dist/db/fallback.d.ts +1 -1
- package/dist/db/node/index.d.ts +1 -0
- package/dist/db/node/index.js +2 -2
- package/dist/db/postgres/pglite/PgliteConnection.js +22 -22
- package/dist/db/workerd/index.d.ts +2 -0
- package/dist/db/workerd/index.js +2 -2
- package/dist/{index-xv_pDjEt.d.ts → index-DKO3OQpz.d.ts} +42 -0
- package/dist/index.d.ts +403 -484
- package/dist/index.js +99 -67
- package/dist/static/.vite/manifest.json +2 -2
- package/dist/static/assets/{main-DO_xnvTw.js → main-1bwWb_1q.js} +100 -17
- package/dist/static/assets/{main-BITGMylP.css → main-BDsRycsc.css} +39 -0
- package/dist/vite/index.d.ts +326 -479
- package/dist/vite/index.js +2 -2
- package/package.json +7 -5
- package/skills/supalite/SKILL.md +1 -1
package/LIMITATIONS.md
CHANGED
|
@@ -10,7 +10,7 @@ Anchors below point to the corresponding STATUS.md section. If a limitation here
|
|
|
10
10
|
- Subquery `WITH CHECK` on `INSERT` (`user_id IN (SELECT …)`, `EXISTS (…)`) → throws. Denormalise the owning column. See [RLS known limitations](https://github.com/supabase-community/lite/blob/HEAD/STATUS.md#row-level-security-rls).
|
|
11
11
|
- Scalar functions outside the allow-list in `DEFAULT` or `CHECK` (`trim`, `btrim`, `length`, `lower`, `upper`, …) → `Function call "<name>" not supported`. Use literals or move the check to the app layer. See [Column Defaults](https://github.com/supabase-community/lite/blob/HEAD/STATUS.md#column-defaults) and [CHECK constraint functions](https://github.com/supabase-community/lite/blob/HEAD/STATUS.md#check-constraint-functions).
|
|
12
12
|
- `nextval` / `currval`, `clock_timestamp`, `txid_current`, user-defined functions → not supported. See [Column Defaults](https://github.com/supabase-community/lite/blob/HEAD/STATUS.md#column-defaults).
|
|
13
|
-
- `FORCE ROW LEVEL SECURITY` →
|
|
13
|
+
- `FORCE ROW LEVEL SECURITY` / `NO FORCE` → accepted and ignored (no table-owner exemption to toggle). See [RLS known limitations](https://github.com/supabase-community/lite/blob/HEAD/STATUS.md#row-level-security-rls).
|
|
14
14
|
- PL/pgSQL `DECLARE`, `IF`, `LOOP`, `RAISE`, variables → not supported in trigger bodies. See [PL/pgSQL Trigger Functions](https://github.com/supabase-community/lite/blob/HEAD/STATUS.md#plpgsql-trigger-functions).
|
|
15
15
|
|
|
16
16
|
## supabase-js (SQLite path)
|
|
@@ -26,15 +26,25 @@ Anchors below point to the corresponding STATUS.md section. If a limitation here
|
|
|
26
26
|
## Auth (shipped with caveats)
|
|
27
27
|
|
|
28
28
|
- `double_confirm_changes = true` (secure email change) is spec-compatible but **not** GoTrue's full two-mailbox flow: it finalizes from the current-email confirmation only, so it does not require the new mailbox to also confirm. It still prevents a session thief from changing the email using only a mailbox they control. See [Auth email delivery & templates](https://github.com/supabase-community/lite/blob/HEAD/docs/src/content/docs/auth/email.mdx).
|
|
29
|
+
- OAuth / social sign-in (`signInWithOAuth`, `exchangeCodeForSession`) only implements `github` and `google`. Enabling any other configured provider (including `apple`) returns "provider ... is not yet implemented". Automatic account linking on a verified-email match works; manual `linkIdentity()`/`unlinkIdentity()` do not. On the D1 backend, multi-statement Auth transaction spans (OAuth callback/token writes, email-change and other OTP verification) run best-effort without a wrapping transaction (D1 has no callback transaction API; single-statement guards still prevent code/state reuse) — all other backends are fully transactional. See [Auth API: Implemented](https://github.com/supabase-community/lite/blob/HEAD/STATUS.md#auth-api-gotrue-compatible).
|
|
30
|
+
- Legacy JWT-as-apikey (`ANON_KEY`/`SERVICE_ROLE_KEY` HS256) → not supported. Use the opaque `sb_publishable_*`/`sb_secret_*` keys instead. See [API Keys](https://github.com/supabase-community/lite/blob/HEAD/STATUS.md#api-keys).
|
|
31
|
+
- API key enforcement is opt-in: with no `auth.publishable_key`/`auth.secret_key` configured, `/rest/v1` and `/auth/v1` accept any/no `apikey` (unchanged old behavior). See [API Keys](https://github.com/supabase-community/lite/blob/HEAD/STATUS.md#api-keys).
|
|
32
|
+
- A key passed only via `Authorization` (no `apikey` header/query param) → 401. Use `apikey` header or `?apikey=` query param. See [API Keys](https://github.com/supabase-community/lite/blob/HEAD/STATUS.md#api-keys).
|
|
33
|
+
- No local mailbox UI: `[auth.email.smtp] enabled = true` sends real mail via `SmtpEmailDriver` (Nodemailer; e.g. to Mailpit/Inbucket at `localhost:1025`), but there is no built-in mailbox web UI to browse those messages — use the SMTP server's own UI. `[inbucket]` config is still parsed but not acted on: no local Inbucket-compatible service is started. The default `ConsoleEmailDriver` prints emails (To/Subject/text) to the console instead. `SmtpEmailDriver` requires Node or Bun; it is not supported on Cloudflare Workers or in the browser. See [Auth email delivery & templates](https://github.com/supabase-community/lite/blob/HEAD/STATUS.md#auth-api-gotrue-compatible).
|
|
29
34
|
|
|
30
35
|
## Auth (planned, not yet shipped)
|
|
31
36
|
|
|
32
|
-
- OAuth, anonymous sign-in, identity linking, admin API, MFA → planned. See [Auth API: Planned](https://github.com/supabase-community/lite/blob/HEAD/STATUS.md#-planned).
|
|
37
|
+
- Other OAuth providers (Apple and the rest of the 18-provider config surface), anonymous sign-in, manual identity linking, admin API, MFA → planned. See [Auth API: Planned](https://github.com/supabase-community/lite/blob/HEAD/STATUS.md#-planned).
|
|
33
38
|
|
|
34
39
|
## Runtime / dev
|
|
35
40
|
|
|
36
|
-
- `vite preview` does **not**
|
|
41
|
+
- `vite preview` mounts the API and runs boot migrations, but does **not** watch schemas and never enables admin mode (it simulates production). `vite build` and standalone production servers do not mount the API at all. See [Vite plugin scope](https://github.com/supabase-community/lite/blob/HEAD/STATUS.md#vite-plugin-scope).
|
|
37
42
|
- Do not run `lite dev` (or `lite start`) alongside the Vite plugin — both bind the API and collide. See [When to use what](https://github.com/supabase-community/lite/blob/HEAD/README.md#when-to-use-what).
|
|
43
|
+
- `lite start` runs the imperative (migrations) workflow. Develop a declarative project (`supabase/schemas/*.sql`) with `lite dev` or the Vite plugin, and ship it by generating a migration: `lite db diff -f <name>` then `lite db reset`. `lite start` works on a declarative project while the cache written by the last `lite dev` run is valid; without a valid cache it is always refused, with no exceptions — it never re-derives RLS from schema files it did not apply, and never substitutes migration-only metadata for them. `lite db diff -f <name>` followed by `lite db reset` is the transition that makes the migration history authoritative, and after it `lite start` boots again. `lite migration up` is not that transition: it is non-destructive, so the generated migration re-creates objects the declarative apply already created and fails against the live development database. `lite db reset` is the related gotcha: it is destructive and replays migrations only, so anything `schemas/*.sql` describes that you never captured with `lite db diff -f` — tables and RLS policies alike — is simply not in the reset database. See [RLS](https://github.com/supabase-community/lite/blob/HEAD/STATUS.md#row-level-security-rls).
|
|
44
|
+
- `supabase/.temp/.deparse-cache.json` is safe to delete: it is regenerated on the next apply/translate, and a boot that cannot rebuild it fails closed (refuses to serve), never open. Only `sqlite-postgres` uses it. See [RLS](https://github.com/supabase-community/lite/blob/HEAD/STATUS.md#row-level-security-rls).
|
|
45
|
+
- **Admin mode is on by default locally.** `lite dev`, `lite start`, and the Vite dev server serve *keyless* `/rest/v1` (+ `/storage/v1` on the CLI) requests as `service_role`, so those requests bypass RLS. Credentialed requests are unaffected. Disable with `--no-admin` / `supalite({ admin: false })`. See [API Keys](https://github.com/supabase-community/lite/blob/HEAD/STATUS.md#api-keys).
|
|
46
|
+
- Admin mode never elevates `/auth/v1`, cross-origin requests, requests from a non-loopback socket, or requests for a non-loopback hostname (DNS rebinding) — so it is not a way to reach a dev server from another machine or from a hostile page. Embedders get the hostname check only, so set `options.server.admin` on a loopback-bound server or not at all.
|
|
47
|
+
- The Vite plugin mounts `/rest/v1` but not `/storage/v1`, so admin mode covers storage on the CLI only unless you add the prefix. See [Vite plugin scope](https://github.com/supabase-community/lite/blob/HEAD/STATUS.md#vite-plugin-scope).
|
|
38
48
|
|
|
39
49
|
## Postgres backends (pglite, postgres)
|
|
40
50
|
|
|
@@ -52,5 +62,8 @@ Common ways code goes wrong against supalite. The fix for each is the correspond
|
|
|
52
62
|
- Don't call `rpc()` on the SQLite path. Run a regular HTTP endpoint, or switch the driver to `pglite` / `postgres` in `config.toml`.
|
|
53
63
|
- Don't use embedded dotted-path filters (`.eq('rel.col', v)`) on SQLite. Filter the FK column on the parent, or fetch matching ids first.
|
|
54
64
|
- Don't run `lite dev` or `lite start` next to the Vite plugin — port collision.
|
|
55
|
-
- Don't
|
|
65
|
+
- Don't `lite db reset` then `lite start` on a declarative project and expect your schema to be there. Reset is destructive and replays migrations only, adopting that state (RLS included) as the authoritative one — run `lite db diff -f <name>` first so the declarative schema exists as a migration.
|
|
66
|
+
- Don't test RLS with a keyless request while admin mode is on — it runs as `service_role` and sees everything. Send `apikey: $PUBLISHABLE_KEY` (for `anon`), plus `Authorization: Bearer $USER_JWT` for `authenticated`, or start with `--no-admin`.
|
|
67
|
+
- Don't send only `Authorization: Bearer $USER_JWT` and expect `authenticated` RLS. With keys configured that's a 401 — the `apikey` is required as well.
|
|
68
|
+
- Don't rely on `vite preview` for a production-like surface beyond the API mount: it skips schema watching and admin mode, but it is still a dev tool. Use `lite start` or a real backend for non-dev environments.
|
|
56
69
|
- Don't reach for `trim` / `length` / `lower` inside `CHECK` constraints on SQLite — use literal/operator comparisons.
|
package/PATTERNS.md
CHANGED
|
@@ -36,6 +36,27 @@ await supabase.from("<thing>").insert({
|
|
|
36
36
|
});
|
|
37
37
|
```
|
|
38
38
|
|
|
39
|
+
## Verifying RLS policies locally
|
|
40
|
+
|
|
41
|
+
Local admin mode is on by default (`lite dev`, `lite start`, Vite dev server), and a request with **no** credential runs as `service_role` — so a bare `curl` sees every row and proves nothing about your policies. Always test with a credential; those requests are never elevated and behave exactly as they will in production.
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
# anon: what a logged-out visitor sees
|
|
45
|
+
curl -H "apikey: $SUPABASE_PUBLISHABLE_KEY" \
|
|
46
|
+
"http://localhost:54321/rest/v1/<thing>?select=*"
|
|
47
|
+
|
|
48
|
+
# authenticated: the apikey is required IN ADDITION to the user JWT
|
|
49
|
+
JWT=$(curl -s -H "apikey: $SUPABASE_PUBLISHABLE_KEY" \
|
|
50
|
+
-H 'Content-Type: application/json' \
|
|
51
|
+
-d '{"email":"a@b.co","password":"secret123"}' \
|
|
52
|
+
"http://localhost:54321/auth/v1/token?grant_type=password" | jq -r .access_token)
|
|
53
|
+
|
|
54
|
+
curl -H "apikey: $SUPABASE_PUBLISHABLE_KEY" -H "Authorization: Bearer $JWT" \
|
|
55
|
+
"http://localhost:54321/rest/v1/<thing>?select=*"
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
`Authorization` alone is a 401 — opaque keys are only read from `apikey`, matching upstream. supabase-js sends both automatically, so app code needs no special handling. To take admin mode out of the picture entirely, start with `--no-admin` (or `supalite({ admin: false })`) and every request will require a key.
|
|
59
|
+
|
|
39
60
|
## Filtering an embedded resource (SQLite path)
|
|
40
61
|
|
|
41
62
|
Dotted-path filters (`.eq('rel.col', v)`) are not supported on SQLite. Two options:
|
|
@@ -78,7 +99,7 @@ The canonical Vite recipe:
|
|
|
78
99
|
5. `src/lib/supabase.ts`:
|
|
79
100
|
```ts
|
|
80
101
|
import { createClient } from "@supabase/supabase-js";
|
|
81
|
-
export const supabase = createClient(window.location.origin, "
|
|
102
|
+
export const supabase = createClient(window.location.origin, "<sb_publishable_...>");
|
|
82
103
|
```
|
|
83
104
|
6. `bun run dev`.
|
|
84
105
|
|
package/README.md
CHANGED
|
@@ -14,7 +14,7 @@ Supalite targets AI builders who want quick, cheap prototypes today with a clear
|
|
|
14
14
|
|
|
15
15
|
**Scope:** Both declarative schema (`supabase/schemas/*.sql`) and imperative Postgres migrations (`supabase/migrations/*.sql`, Supabase-CLI compatible) are supported. See [Migrations](#migrations). Advanced Postgres-specific column types (ranges, arrays of composites, and similar) are not available.
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
Correctness is checked against an internal spec suite derived from the upstream PostgREST and GoTrue test suites: ~2,400 Data API and ~500 Auth cases, replayed against every backend with zero failures. Together with the repo's own suite that's ~32k assertions. See [Testing](https://github.com/supabase-community/lite/blob/HEAD/STATUS.md#testing) for current pass rates and skips.
|
|
18
18
|
|
|
19
19
|
---
|
|
20
20
|
|
|
@@ -49,7 +49,7 @@ For a per-capability parity view with effort estimates and feasibility notes for
|
|
|
49
49
|
|-------------------------|--------|--------------------------------------------------------------------|
|
|
50
50
|
| [Databases](https://github.com/supabase-community/lite/blob/HEAD/STATUS.md#database-support) | ✅ | `bun:sqlite`, `node:sqlite`, sqlite-wasm, Cloudflare D1 + DO, PGlite, PostgreSQL |
|
|
51
51
|
| [Data API (PostgREST)](https://github.com/supabase-community/lite/blob/HEAD/STATUS.md#database-api-postgrest-compatible) | ✅ | 53/74 supabase-js methods on SQLite: `from`, `select`, `insert`, `update`, `delete`, `upsert`, `eq`, `neq`, `gt`, `gte`, `lt`, `lte`, `in`, `notIn`, `is`, `isDistinct`, `like`, `ilike`, `likeAllOf`, `likeAnyOf`, `ilikeAllOf`, `ilikeAnyOf`, `match`, `or`, `not`, `filter`, `order`, `limit`, `range`, `single`, `maybeSingle`, `csv`, `abortSignal`, `setHeader`, `throwOnError`, `maxAffected`, `returns`, `overrideTypes`, plus full resource embedding (FK joins, `!inner`, spreads, nested, aggregates). Partial: `contains`, `containedBy`, `overlaps`, `textSearch` (LIKE-based lexeme approximation), `regexMatch`/`regexIMatch` (simple anchored patterns). `rpc` not supported on SQLite. 72/74 on Postgres. |
|
|
52
|
-
| [Auth API (GoTrue)](https://github.com/supabase-community/lite/blob/HEAD/STATUS.md#auth-api-gotrue-compatible) | ✅ |
|
|
52
|
+
| [Auth API (GoTrue)](https://github.com/supabase-community/lite/blob/HEAD/STATUS.md#auth-api-gotrue-compatible) | ✅ | 23/63 supabase-js methods (13 backend + 10 client-side helpers): `signUp`, `signInWithPassword`, `signInWithOtp`, `verifyOtp`, `refreshSession`, `signOut`, `getUser`, `updateUser`, `resetPasswordForEmail`, `resend`, `reauthenticate`, `signInWithOAuth`, `exchangeCodeForSession`. OAuth covers `github`/`google` only (PKCE + implicit, automatic account linking); other providers (incl. Apple), anonymous sign-in, manual identity linking, admin API, and MFA planned. |
|
|
53
53
|
| [Storage API](https://github.com/supabase-community/lite/blob/HEAD/STATUS.md#storage-api-compatible) | 🧪 | 20/20 supabase-js methods: `upload`, `download`, `list`, `remove`, `move`, `copy`, `info`, `exists`, `update`, `getPublicUrl`, `createSignedUrl`, `createSignedUrls`, `createSignedUploadUrl`, `uploadToSignedUrl`, `listBuckets`, `getBucket`, `createBucket`, `updateBucket`, `deleteBucket`, `emptyBucket`. Role-based access + RLS pending. <br />⚠️ Gated behind `EXPERIMENTAL_STORAGE`. |
|
|
54
54
|
| Realtime | 🔄 | Coming soon |
|
|
55
55
|
| Edge Functions | 🔄 | Coming soon |
|
|
@@ -75,14 +75,16 @@ lite dev # start server with schema hot-reload
|
|
|
75
75
|
|
|
76
76
|
The API is now running at `http://localhost:54321`. Point `@supabase/supabase-js` at it:
|
|
77
77
|
|
|
78
|
+
`lite init` also generates any missing publishable/secret API key(s) into root `.env` (per-variable, never overwrites an existing one) and prints them:
|
|
79
|
+
|
|
78
80
|
```typescript
|
|
79
81
|
import { createClient } from "@supabase/supabase-js";
|
|
80
82
|
|
|
81
|
-
const supabase = createClient("http://localhost:54321", "
|
|
83
|
+
const supabase = createClient("http://localhost:54321", "<sb_publishable_...>");
|
|
82
84
|
const { data } = await supabase.from("todos").select("*");
|
|
83
85
|
```
|
|
84
86
|
|
|
85
|
-
>
|
|
87
|
+
> Use the printed `sb_publishable_*` key as the anon key. If no keys are configured, any/no `apikey` is accepted (old behavior) — see [API keys](#api-keys).
|
|
86
88
|
|
|
87
89
|
Edit `supabase/schemas/schema.sql` and the dev server re-applies the schema automatically.
|
|
88
90
|
|
|
@@ -116,7 +118,8 @@ to show details like the config file and database location on stderr.
|
|
|
116
118
|
|
|
117
119
|
| Command | Description |
|
|
118
120
|
|------------------|---------------------------------------------------------------|
|
|
119
|
-
| `init` | Scaffold `supabase/` (config, schema, seed, data dir)
|
|
121
|
+
| `init` | Scaffold `supabase/` (config, schema, seed, data dir); generates any missing API key(s) into `.env` |
|
|
122
|
+
| `generate-keys` | (Re)generate the publishable/secret API key pair, upsert `.env` |
|
|
120
123
|
| `dev` | Start server + watch `schemas/*.sql`, auto-apply on change |
|
|
121
124
|
| `start` | Start server (no watch, no auto-migrate) |
|
|
122
125
|
| `db schema` | Print current DB schema; `--diff` compares vs `schemas/*.sql` |
|
|
@@ -148,6 +151,7 @@ lite db translate "alter table public.todos add column done boolean" | lite db q
|
|
|
148
151
|
echo "select * from todos" | lite db query # pipe a one-off statement in
|
|
149
152
|
lite upgrade --dry-run # rehearsal plus SQLite shim audit
|
|
150
153
|
lite upgrade --dry-run --json # machine-readable shim audit output
|
|
154
|
+
lite generate-keys # (re)generate the API key pair, upsert .env
|
|
151
155
|
```
|
|
152
156
|
|
|
153
157
|
Upgrade targets:
|
|
@@ -251,6 +255,8 @@ enabled = true
|
|
|
251
255
|
jwt_secret = "dev-secret-change-me"
|
|
252
256
|
jwt_expiry = 3600
|
|
253
257
|
enable_signup = true
|
|
258
|
+
publishable_key = "env(SUPABASE_PUBLISHABLE_KEY)"
|
|
259
|
+
secret_key = "env(SUPABASE_SECRET_KEY)"
|
|
254
260
|
|
|
255
261
|
[auth.email]
|
|
256
262
|
enable_confirmations = false
|
|
@@ -258,6 +264,44 @@ enable_confirmations = false
|
|
|
258
264
|
|
|
259
265
|
> **`auth.jwt_secret`**: if omitted, auth falls back to the insecure placeholder `"unsafe-secret-change-me"` so local dev doesn't break. Always set your own for anything beyond throwaway local use.
|
|
260
266
|
|
|
267
|
+
### API keys
|
|
268
|
+
|
|
269
|
+
`lite init` generates a `sb_publishable_*`/`sb_secret_*` key pair into root `.env` (`SUPABASE_PUBLISHABLE_KEY`/`SUPABASE_SECRET_KEY`) and wires `auth.publishable_key`/`auth.secret_key` to reference them via `env(VAR)`, same field names as the upstream `supabase` CLI. It's per-variable: only whichever key is actually missing gets (re)generated — an existing `SUPABASE_PUBLISHABLE_KEY` or `SUPABASE_SECRET_KEY` is never overwritten. `lite start`/`lite dev` print the resolved keys under the server URL.
|
|
270
|
+
|
|
271
|
+
Enforcement kicks in once at least one key is configured: `sb_publishable_*` authenticates as `anon`, `sb_secret_*` as `service_role` (bypasses RLS, including on SQLite). An unconfigured key simply never matches. With no keys configured at all, `/rest/v1` and `/auth/v1` keep the old behavior (any/no `apikey` accepted). Keys must be sent via the `apikey` header or `?apikey=` query param — supabase-js does this automatically — a key sent only via `Authorization` is rejected. A real user session JWT in `Authorization` always outranks the API key. `/storage/v1` is transform-only (like upstream self-hosted Kong): it never 401s on a missing/invalid key, so public/signed/S3-presigned URLs stay keyless, but a secret key still satisfies storage's own authed routes as `service_role`. Legacy JWT-as-apikey (`ANON_KEY`/`SERVICE_ROLE_KEY` HS256) is not supported.
|
|
272
|
+
|
|
273
|
+
Lost or rotating keys: `lite generate-keys` mints a fresh pair and upserts `.env`.
|
|
274
|
+
|
|
275
|
+
### Admin mode (local only)
|
|
276
|
+
|
|
277
|
+
`lite dev`, `lite start`, and the Vite dev server run with admin mode **on**. A request carrying no credential at all — no `apikey`, no `Authorization` — on `/rest/v1` (and `/storage/v1` on the CLI) is served as `service_role`. That's what lets the built-in studio read and edit any table without a secret key shipping to the browser, mirroring self-hosted Supabase Studio where the server holds the key.
|
|
278
|
+
|
|
279
|
+
Elevation additionally requires the request to be same-origin (or carry no `Origin`), to arrive on a loopback socket, and to name a loopback host. Both locality checks are needed: the socket peer stops a machine on your network from spoofing `Host: localhost`, and the hostname stops DNS rebinding, where a hostile page re-resolves its own domain to `127.0.0.1` so the socket is genuinely loopback. `/auth/v1` is never elevated, and the Vite plugin only mounts `/rest/v1`.
|
|
280
|
+
|
|
281
|
+
```bash
|
|
282
|
+
lite start --no-admin # off: keyless requests are no longer elevated
|
|
283
|
+
```
|
|
284
|
+
```ts
|
|
285
|
+
supalite({ admin: false }) # off for the Vite dev server
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
Precedence is explicit flag > `options.server.admin` in `config.toml` > launcher default, so a config file can opt a project out but can never re-enable admin after `--no-admin`. Off by default when embedding `App` yourself and in `vite preview`.
|
|
289
|
+
|
|
290
|
+
Because keyless requests skip RLS, test policies with a credential: `apikey: $PUBLISHABLE_KEY` for `anon`, and that **plus** `Authorization: Bearer $USER_JWT` for `authenticated`. A bearer token alone is a 401.
|
|
291
|
+
|
|
292
|
+
Embedding the `App` class directly: `app.getClient()` defaults to the configured publishable key (override via `{ apikey }`). Disable enforcement entirely with `options.server.apiKeys: false`, or supply your own key→role mapping via `options.server.apiKeys.resolver`:
|
|
293
|
+
|
|
294
|
+
```ts
|
|
295
|
+
new App({
|
|
296
|
+
connection,
|
|
297
|
+
options: {
|
|
298
|
+
server: {
|
|
299
|
+
apiKeys: { resolver: async (key) => key === myKey ? { type: "secret", claims: { role: "service_role" } } : null },
|
|
300
|
+
},
|
|
301
|
+
},
|
|
302
|
+
});
|
|
303
|
+
```
|
|
304
|
+
|
|
261
305
|
---
|
|
262
306
|
|
|
263
307
|
## Writing schemas
|
|
@@ -318,7 +362,7 @@ const client = app.getClient();
|
|
|
318
362
|
const { data } = await client.from("todos").select("*");
|
|
319
363
|
```
|
|
320
364
|
|
|
321
|
-
Queries route through `app.fetch` internally. Same API, no HTTP round trip.
|
|
365
|
+
Queries route through `app.fetch` internally. Same API, no HTTP round trip. `getClient()` defaults to the configured `auth.publishable_key` (override with `getClient({ apikey })`).
|
|
322
366
|
|
|
323
367
|
---
|
|
324
368
|
|
package/STATUS.md
CHANGED
|
@@ -239,11 +239,13 @@ Each supported behavior is regression-covered against both backends in [`app/tes
|
|
|
239
239
|
|-----------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|
240
240
|
| Subquery `WITH CHECK` on `INSERT` | `WITH CHECK` expressions containing subqueries (e.g. `user_id IN (SELECT ...)`, `EXISTS (...)`) cannot be evaluated in-memory. Currently throws an error. **Workaround:** denormalise the authorising column (e.g. `user_id` onto the child table) and use `auth.uid() = user_id`. See [WITH CHECK subqueries](https://github.com/supabase-community/lite/blob/HEAD/internal/docs/limitations/rls-with-check-subqueries.md). |
|
|
241
241
|
| `UPSERT` applies `INSERT` policies only | Postgres applies `UPDATE` policies on conflict; supalite applies `INSERT WITH CHECK` to all upsert rows since conflict resolution is unknown pre-execution. |
|
|
242
|
-
| `FORCE ROW LEVEL SECURITY` |
|
|
242
|
+
| `FORCE ROW LEVEL SECURITY` | Accepted and ignored (`FORCE` / `NO FORCE`): there is no table-owner exemption to toggle. As on Postgres, `FORCE` alone does not enable RLS. |
|
|
243
243
|
| `RETURNING` + `SELECT` policy | Postgres errors if `RETURNING` references rows not visible to `SELECT` policy. Not checked. |
|
|
244
244
|
|
|
245
245
|
📖 See [`internal/docs/postgres/rls.md`](https://github.com/supabase-community/lite/blob/HEAD/internal/docs/postgres/rls.md) for the full RLS reference and behavior matrix.
|
|
246
246
|
|
|
247
|
+
**SQLite metadata persistence (`sqlite-postgres`):** Policies live in translation metadata, not in the database file, so a command that never migrates would otherwise boot with RLS off. Every declarative schema translation, every `lite db reset`, and every migration apply in a migrations-only project writes the full deparse info to `supabase/.temp/.deparse-cache.json`. `lite start` restores that cache, verified against the migration-history fingerprint, the schema hash, member-level payload validation, and a cross-check that its RLS table list still covers everything the applied migration history enabled RLS on. When the cache is missing or stale, a migrations-only project recalculates from the applied migration history (never from unapplied migration files). A declarative project (`supabase/schemas/*.sql`) is instead refused outright, with no exceptions: `lite start` serves the migrations workflow and never applies schema files, so without a valid cache it exits with non-interactive recovery instructions rather than guessing. `lite db diff -f <name>` then `lite db reset` is the transition that establishes migration authority — the generated migration carries the schema's `ENABLE ROW LEVEL SECURITY` / `CREATE POLICY` statements, and `db reset` is destructive, so afterwards the migration-derived metadata describes the fresh database exactly and is always persisted. That is what makes the recovery loop terminate. A non-destructive `lite migration up` never persists over a declarative project's snapshot, because it cannot know what the live database still carries from a declarative apply. RLS metadata also follows the table lifecycle: an `ALTER TABLE ... RENAME TO` carries enforcement and its policies to the new name, and a `DROP TABLE` (even followed by a `CREATE TABLE` of the same name) drops them, matching Postgres. Embedded/programmatic use falls back to a per-table deny backstop. The cache file is safe to delete — it is regenerated by the next apply, and a boot that cannot rebuild it fails closed, never open. `pglite` / `postgres` (native RLS) and the bare `sqlite` driver are unaffected. See [LIMITATIONS.md](https://github.com/supabase-community/lite/blob/HEAD/LIMITATIONS.md) for the declarative-project workflow.
|
|
248
|
+
|
|
247
249
|
**PGlite / PostgreSQL auto-setup:** When any table has `ENABLE ROW LEVEL SECURITY`, supalite creates `anon`, `authenticated`, and `service_role` roles (if missing; `service_role` uses `BYPASSRLS`) and grants default privileges on all tables and sequences in the relevant schemas. No manual `CREATE ROLE` or `GRANT` statements needed for these built-in roles.
|
|
248
250
|
|
|
249
251
|
### PL/pgSQL Trigger Functions
|
|
@@ -488,6 +490,8 @@ Run `bun run test:spec:analyze` (or `:sqlite-postgres`, `:pglite`, `:postgres`)
|
|
|
488
490
|
|
|
489
491
|
Backend implementation in `app/src/auth/`. GoTrue-compatible HTTP endpoints at `/auth/v1/*`.
|
|
490
492
|
|
|
493
|
+
Auth behaves identically across database backends, with one caveat: on Cloudflare D1, multi-statement Auth transaction spans (OAuth callback/token writes, email-change and other OTP verification) run best-effort without a wrapping transaction — D1 has no callback transaction API, so errors propagate but prior writes persist. Single-statement atomic guards (conditional `UPDATE`/`DELETE` with rowcount checks) still prevent auth-code/state/token reuse on D1. All other backends, including Durable Objects, are fully transactional.
|
|
494
|
+
|
|
491
495
|
### ✅ Implemented
|
|
492
496
|
|
|
493
497
|
| Method | Endpoint | Notes |
|
|
@@ -503,6 +507,8 @@ Backend implementation in `app/src/auth/`. GoTrue-compatible HTTP endpoints at `
|
|
|
503
507
|
| `recover()` | `POST /recover` | Password reset email |
|
|
504
508
|
| `resend()` | `POST /resend` | Resend confirmation / email change |
|
|
505
509
|
| `reauthenticate()` | `GET /reauthenticate` | Request reauthentication nonce |
|
|
510
|
+
| `signInWithOAuth()` | `GET /authorize` | `github` and `google` providers; authorization-code (PKCE) and implicit flows |
|
|
511
|
+
| `exchangeCodeForSession()` | `GET`/`POST /callback`, `POST /token?grant_type=pkce` | PKCE code exchange; automatic account linking on verified-email match; other configured providers (incl. `apple`) return "provider ... is not yet implemented" |
|
|
506
512
|
|
|
507
513
|
Supporting infrastructure:
|
|
508
514
|
|
|
@@ -513,16 +519,35 @@ Supporting infrastructure:
|
|
|
513
519
|
- Configurable email signup, confirmations, and secure/insecure email change. Note: `double_confirm_changes=true` is spec-compatible (finalizes from the current-email confirmation, delivered to the current address) but does not implement GoTrue's full two-mailbox confirmation. See [LIMITATIONS.md](https://github.com/supabase-community/lite/blob/HEAD/LIMITATIONS.md#auth-shipped-with-caveats).
|
|
514
520
|
- Mailer integration (confirmation, recovery, magic link, email change, reauthentication)
|
|
515
521
|
- Default Supabase-styled email templates with `site_url`-based verify links; per-type overrides via `auth.email.template.<type>.{subject,content_path}` (GoTrue `{{ .ConfirmationURL }}` etc. variables)
|
|
516
|
-
- Email drivers `Resend` / `AWS SES` / `Sendmail` (injected via `options.drivers.email
|
|
522
|
+
- Email drivers `Resend` / `AWS SES` / `Sendmail` / `SMTP` (injected via `options.drivers.email`, or auto-selected for SMTP when `[auth.email.smtp] enabled = true`); `SMTP` sends via Nodemailer and requires Node or Bun (not Workers/browser); default `ConsoleEmailDriver` is a console mail catcher — prints To/Subject + the text body (including OTP codes and verification links) to the console instead of delivering
|
|
523
|
+
|
|
524
|
+
### API Keys
|
|
525
|
+
|
|
526
|
+
Opaque `sb_publishable_*` / `sb_secret_*` keys, matching Supabase's current key format. Generated per project (never hardcoded); configured via `auth.publishable_key` / `auth.secret_key` in `config.toml` (same field names as upstream `supabase` CLI), values sourced from root `.env` (`SUPABASE_PUBLISHABLE_KEY` / `SUPABASE_SECRET_KEY`) via `env(VAR)`.
|
|
527
|
+
|
|
528
|
+
| Behavior | Status | Notes |
|
|
529
|
+
|----------|--------|-------|
|
|
530
|
+
| `sb_publishable_*` → `anon`, `sb_secret_*` → `service_role` | ✅ | Enforced on `/rest/v1` and `/auth/v1` only when keys are configured; unconfigured projects keep the old behavior (any/no `apikey` accepted) |
|
|
531
|
+
| Auth exemptions (`/verify`, `callback`, `authorize`, `oauth`, `sso/saml`, `.well-known`, `scim`) | ✅ | Mirrors upstream's gateway exemption list |
|
|
532
|
+
| Key source: `apikey` header or `?apikey=` query param | ✅ | A key in `Authorization` alone is rejected (401), matching upstream self-hosted conformance |
|
|
533
|
+
| Real user session JWT in `Authorization` | ✅ | Always outranks the API key |
|
|
534
|
+
| `/storage/v1` | ⚠️ | Transform-only, like upstream self-hosted Kong: keys map to roles when present, but a missing/invalid key never 401s at the gateway (public objects, signed URLs, S3 presigned flows stay keyless). Storage's own route auth still applies; a secret key satisfies storage's authed routes as `service_role` (including bypassing RLS-equivalent checks on SQLite) |
|
|
535
|
+
| Secret key + browser `User-Agent` (`Mozilla/5.0`) | ✅ | Rejected (401), mirrors the hosted gateway's browser guard |
|
|
536
|
+
| OpenAPI root (`GET /rest/v1/`) | ✅ | Requires the secret key: publishable → 403, secret → 200, mirroring upstream's admin-only ACL on that route (LITE-35) |
|
|
537
|
+
| Local admin mode (`options.server.admin`) | ✅ | Local-dev only. A request with **no** credential (no `apikey` header/query, no `Authorization`) on `/rest/v1` or `/storage/v1` is served as `service_role`, so a browser studio can do admin work without a secret key reaching the browser. Also requires same-origin (or no `Origin`), a loopback **socket peer**, and a loopback **hostname** — both halves: the peer check stops a LAN client spoofing `Host: localhost`, the hostname check stops DNS rebinding (where the socket really is loopback but `Host`/`Origin` are the attacker's domain). `/auth/v1` is never elevated. On by default for `lite dev`, `lite start` (`--no-admin` to disable) and the Vite dev server (`/rest/v1` only there — the plugin doesn't mount `/storage/v1`); off for `vite preview` and for embedders. Precedence: explicit flag > `options.server.admin` in config > launcher default. Credentialed requests are unaffected, so `anon`/`authenticated` RLS stays testable (LITE-309) |
|
|
538
|
+
| Secrets redacted from `/_system/config` / `/_system/info` | ✅ | `auth.secret_key` and `auth.jwt_secret` are masked in both responses |
|
|
539
|
+
| Legacy JWT-as-apikey (`ANON_KEY`/`SERVICE_ROLE_KEY` HS256) | ❌ | Not supported |
|
|
540
|
+
| `options.server.apiKeys: false` | ✅ | Disables enforcement entirely (embedders) |
|
|
541
|
+
| `options.server.apiKeys.resolver` | ✅ | Custom resolver override (embedders) |
|
|
542
|
+
|
|
543
|
+
CLI: `lite init` generates whichever key(s) are missing into root `.env` (per-variable — an existing key is never overwritten) and prints them; `lite generate-keys` (re)generates the whole pair and upserts `.env`; `lite start`/`lite dev` print the resolved keys under the server URL, or a hint that none are configured. `app.getClient()` defaults to the configured publishable key (override via `{ apikey }`).
|
|
517
544
|
|
|
518
545
|
### 🔄 Planned
|
|
519
546
|
|
|
520
547
|
| Method | Notes |
|
|
521
548
|
|-----------------------------|---------------------------------------------------------------|
|
|
522
|
-
| `signInWithOAuth()` | Config schema exists, major providers (Google, GitHub, Apple) |
|
|
523
|
-
| `exchangeCodeForSession()` | PKCE flow for OAuth |
|
|
524
549
|
| `signInAnonymously()` | Create anonymous session |
|
|
525
|
-
| `linkIdentity()` |
|
|
550
|
+
| `linkIdentity()` | Manual link of an OAuth identity to an existing user (automatic linking on OAuth sign-in already works) |
|
|
526
551
|
| `unlinkIdentity()` | Remove linked identity |
|
|
527
552
|
| `admin.createUser()` | Direct user creation (skip confirmation) |
|
|
528
553
|
| `admin.listUsers()` | Paginated user list |
|
|
@@ -583,21 +608,20 @@ These methods exist in `@supabase/supabase-js` but are client-side concerns, not
|
|
|
583
608
|
|
|
584
609
|
| Status | Count |
|
|
585
610
|
|-------------------|-------|
|
|
586
|
-
| ✅ Implemented |
|
|
587
|
-
| 🔄 Planned |
|
|
611
|
+
| ✅ Implemented | 13 |
|
|
612
|
+
| 🔄 Planned | 13 |
|
|
588
613
|
| ⚫ Not Planned | 27 |
|
|
589
614
|
| ⚫ Client-side N/A | 10 |
|
|
590
615
|
|
|
591
616
|
### Auth spec: SQLite skip breakdown
|
|
592
617
|
|
|
593
|
-
The
|
|
618
|
+
The 223 cases skipped against the supabase-spec Auth corpus break down by deferred feature. Generated by `cd app && bun run test:spec:auth:analyze:sqlite` (writes `.context/auth-analysis-sqlite.json`). The 24 `oauth_redirect.json` cases now pass, closing the `oauth` category; they cover github/google authorize redirects, provider config validation, PKCE parameter persistence/validation, and callback error handling. The corpus has no successful provider callback and no `/token?grant_type=pkce` exchange, so that coverage lives in the focused mock-provider tests in `app/test/auth/oauth-*.test.ts` (implicit and PKCE round-trips, account linking, concurrency).
|
|
594
619
|
|
|
595
620
|
| Category | Skipped | Why |
|
|
596
621
|
|---------------------------------|--------:|--------------------------------------------------------------------|
|
|
597
622
|
| `admin_api` | 69 | `/admin/*` endpoints (createUser, listUsers, generateLink, etc.) |
|
|
598
623
|
| `mfa` | 44 | TOTP/WebAuthn enroll/challenge/verify |
|
|
599
624
|
| `non_runnable_spec_placeholder` | 29 | Upstream rows with `expected.status: null`; see `app/test/supabase-spec/auth/NON_RUNNABLE_PLACEHOLDERS.md` |
|
|
600
|
-
| `oauth` | 24 | OAuth2/PKCE provider flows |
|
|
601
625
|
| `phone_sms` | 23 | Phone signup / SMS OTP |
|
|
602
626
|
| `saml_sso` | 18 | SAML / SSO |
|
|
603
627
|
| `session_admin` | 12 | Admin session management |
|
|
@@ -657,7 +681,7 @@ Backend implementation in `app/src/storage/`. HTTP endpoints at `/storage/v1/*`.
|
|
|
657
681
|
| Feature | Notes |
|
|
658
682
|
|--------------------------------|------------------------------------------------------------|
|
|
659
683
|
| `/status` health endpoint | Oracle returns 200 with no auth |
|
|
660
|
-
| Role-based access control |
|
|
684
|
+
| Role-based access control | API keys now resolve `service_role`/`anon`/`authenticated` for storage's route-level auth (see [API Keys](#api-keys)); no per-object RLS policies yet |
|
|
661
685
|
| RLS policies on storage tables | Per-user object access via row-level security |
|
|
662
686
|
| Bucket list query params | `?search=`, `?limit=`, `?offset=` on `GET /bucket` |
|
|
663
687
|
| S3-compatible protocol | `PUT/GET/DELETE` via S3 API paths (`/s3/`) |
|
|
@@ -708,8 +732,9 @@ Default command output is pipe-friendly: no global banner, and config/database-l
|
|
|
708
732
|
|
|
709
733
|
| Command | Status | Notes |
|
|
710
734
|
|-----------|--------|--------------------------------------------------------------------|
|
|
711
|
-
| `init` | ✅ | Scaffolds API, migration/seed paths, and auth defaults; flags differ upstream |
|
|
712
|
-
| `start` | ✅ | In-process; no Docker stack flags (`-x`, `--ignore-health-check`)
|
|
735
|
+
| `init` | ✅ | Scaffolds API, migration/seed paths, and auth defaults; generates any missing publishable/secret API key(s) into root `.env` (per-variable, never overwrites an existing one); flags differ upstream |
|
|
736
|
+
| `start` | ✅ | In-process; prints resolved API keys under the server URL; no Docker stack flags (`-x`, `--ignore-health-check`). Never migrates; the entry point for the migrations workflow. On `sqlite-postgres` it restores/recalculates RLS metadata first and refuses to boot if it cannot (see [RLS](#row-level-security-rls)) |
|
|
737
|
+
| `generate-keys` | ✅ | `[lite]`: (re)generates the publishable/secret API key pair and upserts root `.env` |
|
|
713
738
|
| `status` | 🧪 | `[experimental]` `[lite]`: shows linked project metadata |
|
|
714
739
|
| `login` | 🧪 | `[experimental]` Email/password against supalite cloud |
|
|
715
740
|
| `logout` | 🧪 | `[experimental]` Parity |
|
|
@@ -736,7 +761,7 @@ Default command output is pipe-friendly: no global banner, and config/database-l
|
|
|
736
761
|
| `db query` | ✅ | Renamed from top-level `exec`; supports `--remote`, `--config`, and stdin |
|
|
737
762
|
| `db schema` | ✅ | `[lite]`: moved from top-level; `--diff` and `--sql` modes |
|
|
738
763
|
| `db push` | 🔄 | Not registered; use `lite cloud deploy` |
|
|
739
|
-
| `db reset` | ✅ | Replays migrations + seed; does not apply declarative schema_paths
|
|
764
|
+
| `db reset` | ✅ | Replays migrations + seed; does not apply declarative schema_paths; clears `supabase/.temp` caches and always rewrites the deparse cache from the replayed migrations — the reset is destructive, so migration state (RLS included) becomes the authoritative state, and declarative schemas are only in the database if you generated a migration from them first (`lite db diff -f <name>`) |
|
|
740
765
|
| `db pull`, `db dump`, `db lint`, `db advisors` | 🔄 | Not registered |
|
|
741
766
|
| `db start` | 🚫 | Not applicable; in-process, no separate DB start |
|
|
742
767
|
|
|
@@ -796,7 +821,7 @@ Mirrors upstream behavior documented in [`internal/docs/cli/environment.md`](htt
|
|
|
796
821
|
|
|
797
822
|
| Status | Count |
|
|
798
823
|
|-----------------------------|-------|
|
|
799
|
-
| ✅ Implemented |
|
|
824
|
+
| ✅ Implemented | 26 |
|
|
800
825
|
| 🔄 Planned (not registered) | 14 |
|
|
801
826
|
| 🚫 Not Applicable | 7 |
|
|
802
827
|
|
|
@@ -817,7 +842,8 @@ Mirrors upstream behavior documented in [`internal/docs/cli/environment.md`](htt
|
|
|
817
842
|
### Vite plugin scope
|
|
818
843
|
|
|
819
844
|
- **Active during `vite` / `vite dev` and `vite preview`.** `vite dev` watches `schemas/*.sql` for hot-reload; `vite preview` mounts the API and runs boot migrations but does **not** watch schemas (it simulates production). `vite build` and any standalone production server do **not** mount the API — use a real backend (`lite start`, hosted Supabase, or equivalent) there.
|
|
820
|
-
- **Same-process by design.** The plugin mounts `/auth/v1`, `/rest/v1`, and `/_system` on the Vite dev server. Do not run `lite dev` or `lite start` alongside — both bind the API and will collide on port.
|
|
845
|
+
- **Same-process by design.** The plugin mounts `/auth/v1`, `/rest/v1`, and `/_system` on the Vite dev server. `/storage/v1` is not mounted by default — add it to `prefixes` if you need it. Do not run `lite dev` or `lite start` alongside — both bind the API and will collide on port.
|
|
846
|
+
- **Admin mode on in dev, never in preview.** `vite`/`vite dev` default to `admin: true` (keyless same-origin loopback `/rest/v1` requests run as `service_role`); `configurePreviewServer` forces it off. Override with `supalite({ admin: false })`. See [API Keys](#api-keys).
|
|
821
847
|
- **Env-var injection.** The plugin's `config()` hook injects `VITE_SUPABASE_URL` (the current origin) and a dev `VITE_SUPABASE_ANON_KEY`, so `createClient(import.meta.env.VITE_SUPABASE_URL, import.meta.env.VITE_SUPABASE_ANON_KEY)` works with no `.env`. A user-provided `.env` overrides either value.
|
|
822
848
|
|
|
823
849
|
---
|
|
@@ -840,9 +866,9 @@ See [UPGRADE.md](https://github.com/supabase-community/lite/blob/HEAD/UPGRADE.md
|
|
|
840
866
|
|
|
841
867
|
| Test Suite | Passing | Skipped | Failed | Assertions | Files |
|
|
842
868
|
|------------|-------------------|-------------|-----------------|-------------------|----------------|
|
|
843
|
-
| App | **2,
|
|
844
|
-
| App (vitest: node + browser + D1 + DO + KV) | **
|
|
845
|
-
| Repo | **3,
|
|
869
|
+
| App | **2,939 passing** | 486 skipped | 0 failed | 19,345 assertions | 204 test files |
|
|
870
|
+
| App (vitest: node + browser + D1 + DO + KV) | **65 passing** | 0 skipped | 0 failed | — | 5 test files |
|
|
871
|
+
| Repo | **3,967 passing** | 540 skipped | 0 failed | 33,127 assertions | 209 test files |
|
|
846
872
|
|
|
847
873
|
Latest `cd app && bun test`, `cd app && bun run vitest`, and root `bun test --recursive` completed with zero failures.
|
|
848
874
|
|
|
@@ -859,10 +885,10 @@ Auth supabase-spec status (`cd app && bun run test:spec:auth`):
|
|
|
859
885
|
|
|
860
886
|
| Backend | Total | Passing | Pass % | Skipped | Skip % | Failed |
|
|
861
887
|
|---------|------:|--------:|-------:|--------:|-------:|-------:|
|
|
862
|
-
| Postgres | 488 | **
|
|
863
|
-
| PGlite | 488 | **
|
|
864
|
-
| SQLite | 488 | **
|
|
865
|
-
| SQLite-Postgres | 488 | **
|
|
888
|
+
| Postgres | 488 | **265** | 54.3% | 223 | 45.7% | 0 |
|
|
889
|
+
| PGlite | 488 | **265** | 54.3% | 223 | 45.7% | 0 |
|
|
890
|
+
| SQLite | 488 | **265** | 54.3% | 223 | 45.7% | 0 |
|
|
891
|
+
| SQLite-Postgres | 488 | **265** | 54.3% | 223 | 45.7% | 0 |
|
|
866
892
|
|
|
867
893
|
### Methodology
|
|
868
894
|
|
|
@@ -870,7 +896,7 @@ Feature status tables above are validated by ported test suites run against both
|
|
|
870
896
|
|
|
871
897
|
**PostgREST (Database API):** 501 test cases extracted from the upstream [PostgREST Haskell test suite](https://github.com/PostgREST/postgrest) into JSON specs (`packages/postgrest-test-suite/`). Verified by running against real PostgREST and PostgreSQL via Docker. All 501 pass against vendor. The same suite runs against lite's implementation on four backends (`postgres`, `pglite`, `sqlite`, `sqlite-postgres`), with skips documented per dialect for known incompatibilities (JSON operators, range types, full-text search locale differences). Run `bun run test:spec:status` in `app/` to regenerate the baseline table. `sqlite-postgres` exercises the deparser path end users hit with `driver: "sqlite-postgres"`.
|
|
872
898
|
|
|
873
|
-
**Auth (GoTrue):** 51 test cases across 12 spec files (`packages/gotrue-test-suite/`) covering
|
|
899
|
+
**Auth (GoTrue):** 51 test cases across 12 spec files (`packages/gotrue-test-suite/`) covering the 11 pre-OAuth implemented endpoints; the OAuth `/authorize` and `/callback` endpoints are covered by the supabase-spec cases below, and the PKCE token exchange (`/token?grant_type=pkce`) is covered solely by the focused integration tests in `app/test/auth/oauth-*.test.ts`. Verified by running against the vendor GoTrue Docker image (v2.186.0) with PostgreSQL + Inbucket (email trap). The same suite runs against lite's auth implementation on both SQLite and PostgreSQL. The upstream `supabase-spec` Auth JSON cases also run against lite's SQLite auth implementation under `app/test/supabase-spec/auth/`; the baseline now unskips passing email/password/refresh/user, error-shape, health/settings/JWKS, response-shape, email side-effect, logout/reauthenticate DB-change, magic-link, email OTP/verify token, refresh rotation, session lifecycle, short JWT-expiry, non-phone config-variant, recovery password-change, duplicate-signup/form-token response-shape, and OAuth redirect (github/google authorize, callback error handling, PKCE challenge persistence/validation) cases. The upstream corpus contains no `/token?grant_type=pkce` case, so PKCE code redemption is covered only by `app/test/auth/oauth-flow.test.ts` (authorize -> callback -> token round-trips, verifier mismatch, replay) and `app/test/auth/oauth-concurrency.test.ts` (concurrent redemption races). Remaining Auth skips are hard-scoped product areas (admin API, MFA, phone/SMS, SAML/SSO, anonymous, manual identity linking) or non-runnable upstream placeholder rows documented in `app/test/supabase-spec/auth/NON_RUNNABLE_PLACEHOLDERS.md`; there are no current addressable Auth skips. Run `bun run test:spec:auth:analyze` in `app/` to execute all Auth JSON cases and group current mismatch signatures.
|
|
874
900
|
|
|
875
901
|
Both test suites are reusable packages exposing `definePostgrestTests()` and `defineAuthTests()`. They accept either a URL (for vendor) or a fetch handler (for direct in-process testing).
|
|
876
902
|
|
|
@@ -528,6 +528,18 @@ interface PlanStep {
|
|
|
528
528
|
sql: string;
|
|
529
529
|
description?: string;
|
|
530
530
|
type?: PlanStepType;
|
|
531
|
+
/**
|
|
532
|
+
* Commit the current transaction and begin a new one before running this
|
|
533
|
+
* step. Set where the planner requires a commit boundary — a statement whose
|
|
534
|
+
* effect is unusable until its transaction commits, e.g. `ALTER TYPE … ADD
|
|
535
|
+
* VALUE` followed by anything that uses the new value.
|
|
536
|
+
*
|
|
537
|
+
* Execution metadata lives on the step (rather than alongside the plan) so it
|
|
538
|
+
* survives cloning and JSON round-trips of a `PlanResult`.
|
|
539
|
+
*/
|
|
540
|
+
newTransaction?: boolean;
|
|
541
|
+
/** Run this step outside a transaction entirely (e.g. `CREATE INDEX CONCURRENTLY`). */
|
|
542
|
+
nonTransactional?: boolean;
|
|
531
543
|
}
|
|
532
544
|
interface DataLossWarning {
|
|
533
545
|
table: string;
|
|
@@ -640,6 +652,21 @@ declare abstract class Connection<Driver = unknown, DB = any, Config extends ICo
|
|
|
640
652
|
useCache?: boolean;
|
|
641
653
|
}): Promise<IntrospectResult>;
|
|
642
654
|
transaction(_statements: string[], _opts?: TransactionOptions): Promise<void>;
|
|
655
|
+
/**
|
|
656
|
+
* Callback-based transaction API for application code (e.g. AuthRepository)
|
|
657
|
+
* that needs atomicity across several kysely operations without hand-rolling
|
|
658
|
+
* BEGIN/COMMIT/ROLLBACK. `fn` is handed a kysely instance bound to the
|
|
659
|
+
* transaction — use it (not `this.kysely`) for every operation that must
|
|
660
|
+
* participate.
|
|
661
|
+
*
|
|
662
|
+
* Default implementation issues a real BEGIN/COMMIT/ROLLBACK via kysely's
|
|
663
|
+
* `transaction().execute()`, appropriate for backends where `sql\`BEGIN\``
|
|
664
|
+
* is meaningful (base sqlite drivers, Postgres). Durable Objects storage
|
|
665
|
+
* has no such thing — `DoSqliteConnection` overrides this to use
|
|
666
|
+
* `storage.transaction()` instead, running `fn` against the *same* kysely
|
|
667
|
+
* instance (see that class for why).
|
|
668
|
+
*/
|
|
669
|
+
runInTransaction<T>(fn: (trx: Kysely<DB>) => Promise<T>): Promise<T>;
|
|
643
670
|
abstract close(): Promise<void>;
|
|
644
671
|
createMigrator(_desiredSchema: string): ConnectionMigrator;
|
|
645
672
|
onPostgrestAST(ast: AnyAST, _vars?: VarsContext): Promise<AnyAST>;
|