@supabase/lite 0.9.0 → 0.9.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/FEATURES.md +176 -0
- package/LIMITATIONS.md +9 -6
- package/PATTERNS.md +66 -6
- package/README.md +16 -8
- package/STATUS.md +33 -20
- package/dist/{Connection-ZWTDByQ5.d.ts → Connection-f_d5HhQ0.d.ts} +301 -293
- package/dist/cli/index.js +127 -124
- package/dist/cli/lib.d.ts +1 -12
- package/dist/cli/lib.js +44 -39
- package/dist/db/fallback.d.ts +1 -1
- package/dist/db/postgres/PostgresConnection.js +18 -18
- package/dist/db/postgres/pglite/PgliteConnection.js +17 -17
- package/dist/index.d.ts +116 -40
- package/dist/index.js +181 -73
- package/dist/static/.vite/manifest.json +34 -2
- package/dist/static/assets/InterVariable-Dx4kXJAl.woff2 +0 -0
- package/dist/static/assets/InterVariable-Italic-DpCbqKDY.woff2 +0 -0
- package/dist/static/assets/SourceCodePro-Variable-BP8Zz55n.woff2 +0 -0
- package/dist/static/assets/SourceCodePro-Variable-Italic-eALmlzX7.woff2 +0 -0
- package/dist/static/assets/main-BY4iigay.css +1 -0
- package/dist/static/assets/main-BnQ-v4V9.js +199 -0
- package/dist/static/assets/manrope-latin-ext-wght-normal-Ch3YOpNY.woff2 +0 -0
- package/dist/static/assets/manrope-latin-wght-normal-DHIcAJRg.woff2 +0 -0
- package/dist/vite/index.d.ts +627 -31
- package/dist/vite/index.js +2 -2
- package/docs/auth/email.mdx +214 -0
- package/docs/auth/not-supported.mdx +57 -0
- package/docs/auth/overview.mdx +52 -0
- package/docs/auth/supported-flows.mdx +120 -0
- package/docs/cli/overview.mdx +112 -0
- package/docs/cli/telemetry.mdx +34 -0
- package/docs/compatibility.mdx +115 -0
- package/docs/database/backends.mdx +118 -0
- package/docs/database/data-api.mdx +90 -0
- package/docs/database/functions-triggers.mdx +93 -0
- package/docs/database/migrations.mdx +95 -0
- package/docs/database/overview.mdx +66 -0
- package/docs/database/postgres-sqlite-translation.mdx +130 -0
- package/docs/database/rls.mdx +161 -0
- package/docs/database/schemas.mdx +58 -0
- package/docs/index.mdx +49 -0
- package/docs/integrations/embedded.mdx +100 -0
- package/docs/integrations/frameworks.mdx +83 -0
- package/docs/integrations/vite.mdx +87 -0
- package/docs/llms.txt +52 -0
- package/docs/other/edge-functions.mdx +34 -0
- package/docs/other/realtime.mdx +22 -0
- package/docs/quickstart.mdx +150 -0
- package/docs/running.mdx +127 -0
- package/docs/storage/adapters.mdx +75 -0
- package/docs/storage/limitations.mdx +21 -0
- package/docs/storage/overview.mdx +88 -0
- package/docs/upgrade.mdx +108 -0
- package/package.json +5 -1
- package/skills/supalite/SKILL.md +6 -4
- package/dist/static/assets/main-1bwWb_1q.js +0 -40996
- package/dist/static/assets/main-BDsRycsc.css +0 -4045
- package/dist/static/fonts/CustomFont-Black.woff2 +0 -0
- package/dist/static/fonts/CustomFont-BlackItalic.woff2 +0 -0
- package/dist/static/fonts/CustomFont-Bold.woff2 +0 -0
- package/dist/static/fonts/CustomFont-BoldItalic.woff2 +0 -0
- package/dist/static/fonts/CustomFont-Book.woff2 +0 -0
- package/dist/static/fonts/CustomFont-BookItalic.woff2 +0 -0
- package/dist/static/fonts/CustomFont-Medium.woff2 +0 -0
package/FEATURES.md
ADDED
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
# Feature Parity
|
|
2
|
+
|
|
3
|
+
Capability-level view of how @supabase/lite maps to Supabase. [STATUS.md](https://github.com/supabase-community/lite/blob/HEAD/STATUS.md) is the per-method API matrix; this document groups features into capabilities and, for anything not yet supported, adds two columns: an **Effort** estimate and the **Blocker** reason.
|
|
4
|
+
|
|
5
|
+
Compatibility is measured from the `@supabase/supabase-js` surface; direct Postgres wire-protocol access is not a target.
|
|
6
|
+
|
|
7
|
+
## Legend
|
|
8
|
+
|
|
9
|
+
Status (same icons as [STATUS.md](https://github.com/supabase-community/lite/blob/HEAD/STATUS.md)):
|
|
10
|
+
|
|
11
|
+
| Icon | Meaning |
|
|
12
|
+
|------|---------|
|
|
13
|
+
| ✅ | Supported end-to-end |
|
|
14
|
+
| ⚠️ | Partial, works with caveats |
|
|
15
|
+
| 🔄 | Planned / not built yet |
|
|
16
|
+
| ❌ | Not feasible on this path |
|
|
17
|
+
| ⚫ | N/A (client-side only, or no backend needed) |
|
|
18
|
+
|
|
19
|
+
For rows that are not fully ✅, two columns estimate the cost of closing the gap.
|
|
20
|
+
|
|
21
|
+
**Effort** (T-shirt size, relative engineering cost):
|
|
22
|
+
|
|
23
|
+
| Size | Rough meaning |
|
|
24
|
+
|------|---------------|
|
|
25
|
+
| `S` | Small, self-contained change |
|
|
26
|
+
| `M` | A feature's worth of work |
|
|
27
|
+
| `L` | Large, multi-part or new subsystem |
|
|
28
|
+
| `XL` | Major subsystem or new runtime |
|
|
29
|
+
|
|
30
|
+
**Blocker** (why it isn't trivial):
|
|
31
|
+
|
|
32
|
+
| Blocker | Meaning |
|
|
33
|
+
|---------|---------|
|
|
34
|
+
| `platform-limited` | SQLite lacks the primitive (range types, stored procedures, logical replication); any emulation is partial/lossy |
|
|
35
|
+
| `extension-required` | Needs an extension not loadable across all targets (e.g. pgvector / sqlite-vec, full REGEXP) |
|
|
36
|
+
| `external-service` | Needs an outside dependency (SMTP, SMS provider, OAuth provider apps) |
|
|
37
|
+
|
|
38
|
+
`-` marks not-applicable: both columns on ✅ rows, and the Blocker column on planned features with no hard blocker (just ordinary backlog work).
|
|
39
|
+
|
|
40
|
+
> **The SQLite vs Postgres split matters.** @supabase/lite runs on SQLite backends (`node:sqlite`, `bun:sqlite`, WASM, Cloudflare D1/DO) and on Postgres backends (PGlite, PostgreSQL, Supabase Cloud). Many "not feasible on SQLite" features work natively on the Postgres path. The Data tables below carry both columns; Auth and Storage are backend services that behave the same across drivers. One exception: on the Cloudflare 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 auth-code/state reuse. All other backends, including Durable Objects, are fully transactional.
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## Data API (PostgREST)
|
|
45
|
+
|
|
46
|
+
CRUD, filtering, embedding, and RLS over your tables. This is the most complete surface. Method-level detail and per-operator notes live in [STATUS.md → Database API](https://github.com/supabase-community/lite/blob/HEAD/STATUS.md#database-api-postgrest-compatible).
|
|
47
|
+
|
|
48
|
+
| Capability | SQLite | Postgres | Effort | Blocker | Notes |
|
|
49
|
+
|------------|:------:|:--------:|:------:|:-------:|-------|
|
|
50
|
+
| select / insert / update / delete / upsert | ✅ | ✅ | - | - | Batch ops, `ON CONFLICT`, `RETURNING` |
|
|
51
|
+
| Comparison filters (eq, neq, gt/gte/lt/lte, in, is, …) | ✅ | ✅ | - | - | 10/10 |
|
|
52
|
+
| Pattern matching (like, ilike, + quantified) | ✅ | ✅ | - | - | 6/6 |
|
|
53
|
+
| Ordering, limit, range/offset, single/maybeSingle | ✅ | ✅ | - | - | NULLS FIRST/LAST |
|
|
54
|
+
| Logical (or, and, not, match, filter) | ✅ | ✅ | - | - | |
|
|
55
|
+
| JSON path (`->`, `->>`) in select/order/where | ✅ | ✅ | - | - | |
|
|
56
|
+
| Resource embedding (FK joins, `!inner`, spreads, nested, aggregates) | ✅ | ✅ | - | - | |
|
|
57
|
+
| Embedding through views (view→base-table FK tracing) | ⚠️ | ⚠️ | `M` | `platform-limited` | Simple updatable views resolve embeds via their base-table FKs on both paths. Postgres path additionally supports: **materialized views** (introspected via `pg_matviews`/`relkind 'm'` and treated as routable relations with derived FKs) and **multi-level recursive view-of-view** (column maps composed transitively to the ultimate physical base via a fixpoint loop with a depth-16 cap and cycle guard). Not yet traced on either path: complex views (CTE, GROUP BY, subselect-in-FROM, JOINs), and same-name relation collisions across two exposed schemas. See [STATUS.md](https://github.com/supabase-community/lite/blob/HEAD/STATUS.md#database-api-postgrest-compatible) / [LIMITATIONS.md](https://github.com/supabase-community/lite/blob/HEAD/LIMITATIONS.md). |
|
|
58
|
+
| Bulk ops & `Prefer` headers (representation, merge/ignore-duplicates, max-affected) | ✅ | ✅ | - | - | |
|
|
59
|
+
| RLS enforcement (`auth.uid()`/`role()`/`jwt()`, permissive/restrictive, per-command, roles) | ✅ | ✅ | - | - | App-layer rewrite on SQLite; native on Postgres. On `sqlite-postgres`, `lite start` restores or fully rebuilds runtime metadata from authoritative recorded migration SQL, validates it against live structure, and fails with a reset hint on invalid history or drift. See [STATUS.md](https://github.com/supabase-community/lite/blob/HEAD/STATUS.md#row-level-security-rls). |
|
|
60
|
+
| CSV input/output (`csv()`) | ✅ | ✅ | - | - | Via `text/csv` Accept/Content-Type |
|
|
61
|
+
| Response utilities (`abortSignal`, `setHeader`, `throwOnError`, `maxAffected`) | ✅ | ✅ | - | - | |
|
|
62
|
+
| CORS / `OPTIONS` preflight | ✅ | ✅ | - | - | Server-wide on `/auth`, `/rest`, `/storage`; preflight answered before auth, origin `*`, exposes `Content-Range`. |
|
|
63
|
+
| PostgreSQL extension declarations | ⚠️ | ⚠️ | `XL` | `extension-required` | SQLite treats `plpgsql`, `pgcrypto`, and `uuid-ossp` declarations plus their declarative schema/drop reconciliation as compatibility no-ops; unsupported creates and mutations fail during translation. PGlite runs only its configured extensions; PostgreSQL delegates to the server. See [STATUS.md](https://github.com/supabase-community/lite/blob/HEAD/STATUS.md#extension-statements). |
|
|
64
|
+
| Full-text search (fts/plfts/phfts/wfts) | ⚠️ | ✅ | `L` | `platform-limited` | SQLite uses a LIKE-based lexeme approximation, not FTS5 ranking or tsvector semantics. See [STATUS.md](https://github.com/supabase-community/lite/blob/HEAD/STATUS.md#full-text-search). |
|
|
65
|
+
| Regex (`regexMatch`/`regexIMatch`) | ⚠️ | ✅ | `M` | `extension-required` | Only simple anchored/literal patterns today. Full regex needs a registered `REGEXP` function, available on `node:`/`bun:sqlite` but not WASM/D1. See [STATUS.md](https://github.com/supabase-community/lite/blob/HEAD/STATUS.md#regex). |
|
|
66
|
+
| Array/JSON containment (`contains`, `containedBy`, `overlaps`) | ⚠️ | ✅ | `M` | `platform-limited` | Scalar arrays + shallow objects work via `json_each`/`json_extract`; arrays-of-objects and nested objects do not. See [STATUS.md](https://github.com/supabase-community/lite/blob/HEAD/STATUS.md#array--json-filters). |
|
|
67
|
+
| Custom domain types / data representations | ⚠️ | ⚠️ | `M` | `platform-limited` | Postgres: domain columns with `CAST(… AS json)` render via that cast on reads/`RETURNING`, and JSON values mutated **into** a domain (epoch/base64/decimal) are converted; sessions run in UTC by default (configurable). SQLite: built-in shims for the known data-rep types. Remaining gap: domain formatting through cross-relation embeds. See [STATUS.md](https://github.com/supabase-community/lite/blob/HEAD/STATUS.md#translated-field-types). |
|
|
68
|
+
| `explain()` | ⚠️ | ⚠️ | `M` | `-` | Returns compiled SQL, not a real query plan. |
|
|
69
|
+
| OpenAPI / schema spec at `/rest/v1/` | ⚠️ | ⚠️ | `M` | `-` | A mock spec is served; not generated from live schema. |
|
|
70
|
+
| `count=planned` / `count=estimated` | ⚠️ | ⚠️ | `S` | `-` | Parsed but treated as exact on SQLite. |
|
|
71
|
+
| Quantified comparisons (`eq(any)`, `gt(all)`, …) | 🔄 | ✅ | `M` | `-` | No SQLite array type, but emulatable by expanding to `OR`/`AND` chains over the literal list. |
|
|
72
|
+
| Embedded dotted-path filters (`.eq('rel.col', v)`) | 🔄 | ✅ | `M` | `-` | Not rewritten into the embedded subquery on SQLite. Workaround in [STATUS.md](https://github.com/supabase-community/lite/blob/HEAD/STATUS.md#embedded-filters). |
|
|
73
|
+
| `rpc()` (stored procedures) | ❌ | ✅ | `XL` | `platform-limited` | Postgres RPC depends on `CREATE FUNCTION … LANGUAGE sql/plpgsql`. SQLite has no stored-procedure model, and the project deliberately avoids a parallel JS-function registry. Use an HTTP endpoint, or a Postgres driver. Supports PostgREST function response control: `response.status`/`response.headers` GUCs override the HTTP status/headers (invalid → PGRST112/PGRST111), GET/HEAD calls run in a read-only transaction (a mutating function raises 25006 → 405), and `request.method`/`path`/`headers` GUCs are injected for functions that read the HTTP context. A function returning a media-type **domain** (e.g. `returns "text/plain"`/`"image/png"`/`"*/*"`) and matched by the request `Accept` emits the raw scalar (text or bytes) with that `Content-Type` instead of JSON; the `response.headers` GUC can override the Content-Type. Gap: table custom-aggregate media handlers. |
|
|
74
|
+
| Computed columns & relationships (PostgREST) | ❌ | ✅ | `L` | `platform-limited` | Postgres: function-based computed columns `fn(row)→scalar` (select + filter, incl. FTS) and computed relationships `fn(row)→[SETOF] table` (embed with no FK, incl. FK/o2o override, self-joins, nested, and on `SETOF` RPC results). Resolved from introspected `pg_proc` metadata, schema-scoped. SQLite has no stored functions. Gap: computed columns on an RPC result (`*_on_rpc`). |
|
|
75
|
+
| Composite-type columns (`CREATE TYPE … AS (…)`) | ❌ | ✅ | `M` | `platform-limited` | Postgres: composite-field access in select/order/filter (`->`/`->>` → `(col).field`) and composite columns rendered as JSON objects (`to_jsonb`) on reads and `RETURNING`. SQLite has no composite types (spec fixtures store the column as JSON there). |
|
|
76
|
+
| Partitioned tables (declarative partitioning) | ❌ | ✅ | `M` | `platform-limited` | Postgres: the partitioned parent is queryable; individual partitions are hidden from the relation cache like PostgREST — direct access → 404, embedding a partition → no-relationship error with a "did you mean '<parent>'" hint. SQLite has no partitioning. |
|
|
77
|
+
| Range operators (`rangeGt`, `rangeAdjacent`, …) | ❌ | ✅ | `XL` | `platform-limited` | No range types in SQLite. |
|
|
78
|
+
| `schema()` (multi-schema) | ❌ | ✅ | `L` | `platform-limited` | SQLite is single-schema. |
|
|
79
|
+
| `geojson()` | ❌ | ❌ | `XL` | `extension-required` | Needs SpatiaLite (SQLite) or PostGIS (Postgres). |
|
|
80
|
+
| `rollback()` (Prefer tx-rollback) | ❌ | ❌ | `S` | `-` | PostgREST-specific; not implemented on either path. |
|
|
81
|
+
| Vector / semantic search (`pgvector`) | ❌ | ❌ | `XL` | `extension-required` | Hosted/CLI Supabase ships `pgvector`; lite does not. `sqlite-vec` is a loadable extension unavailable on WASM/D1, and the PGlite/`postgres` drivers here don't enable `pgvector`. Point users at hosted Supabase for embeddings. |
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
## Auth (GoTrue)
|
|
86
|
+
|
|
87
|
+
GoTrue-compatible endpoints at `/auth/v1/*`, backed by `app/src/auth/`. Email/password, OTP, sessions, RLS auth context, and OAuth sign-in (`github`/`google`) are solid; other OAuth providers, admin, and MFA are the main gaps. Method list in [STATUS.md → Auth API](https://github.com/supabase-community/lite/blob/HEAD/STATUS.md#auth-api-gotrue-compatible).
|
|
88
|
+
|
|
89
|
+
| Capability | Status | Effort | Blocker | Notes |
|
|
90
|
+
|------------|:------:|:------:|:-------:|-------|
|
|
91
|
+
| Email + password sign-up / sign-in | ✅ | - | - | bcrypt, optional metadata, confirmation flow |
|
|
92
|
+
| Magic link / email OTP (`signInWithOtp`, `verifyOtp`) | ✅ | - | - | signup, magiclink, recovery, email_change, reauthentication; numeric code + `token_hash` both verify against the DB (durable on Workers), `otp_expiry`/`otp_length` honored |
|
|
93
|
+
| JWT issuance, refresh-token rotation, sessions | ✅ | - | - | Revocation, reuse handling, timebox/inactivity expiry |
|
|
94
|
+
| Password recovery (`recover`, `resend`, `reauthenticate`) | ✅ | - | - | |
|
|
95
|
+
| `getUser` / `updateUser` (metadata, password, email change) | ✅ | - | - | Secure email change (`double_confirm_changes=true`) is ⚠️ partial: spec-compatible (confirms from the current mailbox before finalizing) but not GoTrue's full two-mailbox flow. See [LIMITATIONS.md](https://github.com/supabase-community/lite/blob/HEAD/LIMITATIONS.md#auth-shipped-with-caveats). |
|
|
96
|
+
| RLS auth context (`auth.uid()`, `auth.role()`, `auth.jwt()`) | ✅ | - | - | Shared with the Data API |
|
|
97
|
+
| API keys (`sb_publishable_*` → `anon`, `sb_secret_*` → `service_role`) | ✅ | - | - | Enforced on `/rest/v1` and `/auth/v1` when `auth.publishable_key`/`auth.secret_key` are configured; legacy JWT-as-apikey not supported. See [STATUS.md](https://github.com/supabase-community/lite/blob/HEAD/STATUS.md#api-keys). |
|
|
98
|
+
| Local admin mode (keyless local requests run as `service_role`) | ✅ | - | - | On by default for loopback `lite dev`/`lite start` and Vite dev listeners. `--host [host]` or an exposed Vite host defaults it off; opt in with `--admin` / `supalite({ admin: true })`. Elevation requires keyless + same-origin + loopback socket + loopback hostname. See [STATUS.md](https://github.com/supabase-community/lite/blob/HEAD/STATUS.md#api-keys). |
|
|
99
|
+
| Email delivery (default templates + customization) | ✅ | - | - | Supabase-styled default HTML, `site_url`-based verify links, GET `/auth/v1/verify` redirect. Override subject + HTML per type via `auth.email.template.<type>.content_path` (GoTrue `{{ .ConfirmationURL }}` etc.). |
|
|
100
|
+
| Email driver (SMTP / provider) | ✅ | - | - | `SmtpEmailDriver` (via Nodemailer) auto-selects when `[auth.email.smtp] enabled = true` in `config.toml` (e.g. pointing at Mailpit or a real SMTP server); `Resend`/`SES`/`Sendmail` remain available via `options.drivers.email`. Default without config or explicit driver is `ConsoleEmailDriver`. `SmtpEmailDriver` requires Node or Bun; not supported on Cloudflare Workers or in the browser. |
|
|
101
|
+
| OAuth / social providers + PKCE (`signInWithOAuth`, `exchangeCodeForSession`) | ⚠️ | `S` per provider | `external-service` | `github` and `google` implemented: authorization-code (PKCE) and implicit flows, automatic account linking. Other configured providers (incl. `apple`) return "not yet implemented"; each is roughly `S` effort, gated on registering a provider app. |
|
|
102
|
+
| Anonymous sign-in (`signInAnonymously`) | 🔄 | `S` | `-` | Create a credential-less user + session. |
|
|
103
|
+
| Admin user API (create/list/get/update/delete, generateLink, signOut) | 🔄 | `M` | `-` | Mostly CRUD over `auth.users`; ~69 skipped spec cases. |
|
|
104
|
+
| Identity linking (`linkIdentity` / `unlinkIdentity`) | 🔄 | `M` | `-` | Automatic linking on OAuth sign-in (verified-email match) already works; the explicit link/unlink API is still planned. Unlink is `S`. |
|
|
105
|
+
| Phone / SMS OTP | 🔄 | `M` | `external-service` | Needs an SMS provider (e.g. Twilio). |
|
|
106
|
+
| MFA / TOTP (enroll, challenge, verify) | 🔄 | `M` | `-` | TOTP via a library (e.g. otplib) + QR; AAL tracking. |
|
|
107
|
+
| `getClaims()` / JWKS verification | 🔄 | `M` | `-` | Fetch + cache JWKS, asymmetric verify. |
|
|
108
|
+
| OIDC ID-token sign-in (`signInWithIdToken`) | 🔄 | `M` | `-` | Validate provider ID token + nonce; lighter than full OAuth handshake. |
|
|
109
|
+
| WebAuthn / passkeys (`mfa.webauthn.*`) | 🔄 | `XL` | `-` | FIDO2/CTAP2 registration + assertion ceremonies; credential storage, signature verification. |
|
|
110
|
+
| OAuth 2.1 authorization server + client admin | 🔄 | `L` | `-` | Lite acting as an OAuth provider: authorization endpoint + client management. |
|
|
111
|
+
| Web3 sign-in (`signInWithWeb3`, SIWE/SIWS) | 🔄 | `L` | `-` | Wallet message + signature verification. |
|
|
112
|
+
| SAML / SSO (`signInWithSSO`) | 🔄 | `XL` | `-` | Enterprise SSO: XML signing, IdP metadata exchange, assertion validation. |
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## Storage
|
|
117
|
+
|
|
118
|
+
storage-api-compatible endpoints at `/storage/v1/*` (`app/src/storage/`), with pluggable filesystem and S3 backends, Sharp/Cloudflare image transforms, and Storage-table RLS across every database backend. Currently gated behind `EXPERIMENTAL_STORAGE`. Detail in [STATUS.md → Storage API](https://github.com/supabase-community/lite/blob/HEAD/STATUS.md#storage-api).
|
|
119
|
+
|
|
120
|
+
| Capability | Status | Effort | Blocker | Notes |
|
|
121
|
+
|------------|:------:|:------:|:-------:|-------|
|
|
122
|
+
| Bucket CRUD (create, list, get, update, delete, empty) | ✅ | - | - | Public/private, file-size limits, allowed MIME types |
|
|
123
|
+
| Object CRUD (upload, replace, download, list, move, copy, remove, info, exists) | ✅ | - | - | Multipart, upsert via `x-upsert`, range requests |
|
|
124
|
+
| Public buckets & public URLs | ✅ | - | - | |
|
|
125
|
+
| Signed URLs (download, batch, upload) | ✅ | - | - | JWT-signed, configurable TTL |
|
|
126
|
+
| Image transformations (resize, format, quality) | ✅ | - | - | Sharp (buffer) and Cloudflare (URL) adapters |
|
|
127
|
+
| Storage backends | ✅ | - | - | Filesystem + S3-compatible (AWS S3, MinIO, R2) |
|
|
128
|
+
| Role-based access (service_role / anon / authenticated gating) | ✅ | - | - | Verified JWT/API-key claims are shared with the Data API; invalid bearer JWTs return 401 on protected operations, retrieval routes still serve public objects, and `service_role` bypasses RLS. |
|
|
129
|
+
| RLS policies on storage tables | ✅ | - | - | Native on Postgres/PGlite and translated on SQLite, including custom JWT roles, ownership, full route-operation context and helpers, serving-only public bypass, signed exceptions, and canonical Storage path helpers. SQLite fails closed for system Storage tables omitted from runtime metadata; `storage` is not exposed through PostgREST by default. |
|
|
130
|
+
| `/status` health endpoint | ✅ | - | - | Returns 200 without auth. |
|
|
131
|
+
| Bucket-list query params (`search`/`limit`/`offset`) | 🔄 | `S` | `-` | |
|
|
132
|
+
| TUS resumable uploads | 🔄 | `L` | `-` | `POST/PATCH/HEAD /upload/resumable`; spec cases exist, endpoints don't. |
|
|
133
|
+
| S3-compatible protocol paths (`/s3/`) | 🔄 | `L` | `-` | |
|
|
134
|
+
| Webhooks (ObjectCreated/ObjectRemoved) | 🔄 | `M` | `-` | |
|
|
135
|
+
|
|
136
|
+
---
|
|
137
|
+
|
|
138
|
+
## Edge Functions
|
|
139
|
+
|
|
140
|
+
Planned, not started. Only config schemas exist (`app/src/config/functions.ts`, `app/src/config/edge_runtime.ts`): per-function `enabled`, `verify_jwt`, `import_map`, `entrypoint`, and runtime `policy`/`inspector_port`. No `/functions/v1/*` routes, no runtime.
|
|
141
|
+
|
|
142
|
+
The client surface is small: `@supabase/functions-js` is essentially one method, `invoke(name, opts)` (plus `constructor`/`setAuth`). The cost is almost entirely server-side, and splits into two layers. **Request/response plumbing** (routing, auth injection, body/content-type handling, streaming, region headers, error classification) is ordinary HTTP work. **The runtime** (executing user TypeScript) is the hard part. Supabase uses a custom Rust/Deno `edge-runtime` with V8 isolates and a main/user worker model. Lite's path is a Web-API-compatible runtime adapter so you can plug in whichever executor fits the host (`vm`/`vm2`/`sval`, dynamic workers, Bun, Deno). This likely depends on Supabase Workers landing, since that runtime targets Node.js.
|
|
143
|
+
|
|
144
|
+
| Capability | Status | Effort | Blocker | Notes |
|
|
145
|
+
|------------|:------:|:------:|:-------:|-------|
|
|
146
|
+
| Invoke routing (`/functions/v1/{name}`), auth + `apikey` injection | 🔄 | `M` | `-` | Proxy mode: forward to an external runtime; reuses existing Hono server + auth. |
|
|
147
|
+
| Per-function JWT verification (`verify_jwt`) | 🔄 | `S` | `-` | Config schema + auth system already exist. |
|
|
148
|
+
| Body / Content-Type handling + response dispatch | 🔄 | `M` | `-` | json / blob / text / formData; auto Content-Type detection. |
|
|
149
|
+
| Streaming responses (SSE passthrough) | 🔄 | `M` | `-` | Return the raw `Response` for `text/event-stream`. |
|
|
150
|
+
| Region routing (`x-region` / `forceFunctionRegion`) | 🔄 | `S` | `-` | Header + query passthrough; no real multi-region locally. |
|
|
151
|
+
| Pluggable runtime (execute user code) | 🔄 | `XL` | `platform-limited` | Web-API-compatible runtime adapter with pluggable executors (`vm`/`vm2`/`sval`, dynamic workers, Bun, Deno) + worker lifecycle (`oneshot`/`per_worker`). Likely depends on Supabase Workers (Node.js-targeted) landing. |
|
|
152
|
+
| Local `functions serve` (dev) + file-watch reload | 🔄 | `L` | `platform-limited` | Depends on the runtime above. |
|
|
153
|
+
| Deployment / management API (deploy, list, get, update, delete, body) | 🔄 | `L` | `-` | ESZip bundling + function registry; lite needs its own tracking (SQLite/config). |
|
|
154
|
+
| Secrets / env injection (`Deno.env`) | 🔄 | `S` | `-` | Inject `SUPABASE_URL`/keys + user secrets. |
|
|
155
|
+
| Database Webhooks (`supabase_functions.hooks`, `http_request` trigger) | 🔄 | `M` | `platform-limited` | Distinct feature: in Postgres, row triggers fire HTTP via `pg_net`. Lite can hook the same events at the app layer (mutations flow through the Data API) and fetch out, avoiding `pg_net`. Caveat: misses out-of-band direct DB writes. |
|
|
156
|
+
|
|
157
|
+
---
|
|
158
|
+
|
|
159
|
+
## Realtime
|
|
160
|
+
|
|
161
|
+
Planned, not started. Only a config schema exists (`app/src/config/realtime.ts`: `enabled`, `ip_version`, `max_header_length`). No WebSocket server, no channels.
|
|
162
|
+
|
|
163
|
+
The `@supabase/realtime-js` surface is one channel abstraction (`supabase.channel(...).on(...).subscribe()`) carrying three feature families. **Broadcast** and **Presence** are pure pub/sub over a WebSocket and don't touch the database, so they're tractable once the socket transport exists. **Postgres Changes** is the harder one: Supabase streams it from Postgres logical replication (WAL), which SQLite does not have. Rather than reach for an extension, lite can capture changes at the app layer: every mutation flows through the Data API, so change events can be emitted from there without DB triggers or replication. The tradeoff is that this only sees writes made through lite, not out-of-band writes straight to the database.
|
|
164
|
+
|
|
165
|
+
| Capability | Status | Effort | Blocker | Notes |
|
|
166
|
+
|------------|:------:|:------:|:-------:|-------|
|
|
167
|
+
| WebSocket transport + channel protocol (`/realtime/v1`) | 🔄 | `M` | `-` | Foundation: socket server, Phoenix-style channel join/leave, heartbeat. |
|
|
168
|
+
| Broadcast (ephemeral pub/sub messages) | 🔄 | `M` | `-` | Independent of the database; fan-out to channel subscribers. |
|
|
169
|
+
| Presence (track / sync / join / leave state) | 🔄 | `M` | `-` | Built on the same channel + a per-channel state CRDT. |
|
|
170
|
+
| Channel authorization (private channels / RLS) | 🔄 | `M` | `-` | Reuse the existing RLS engine + JWT to gate join and message access. |
|
|
171
|
+
| Postgres Changes / CDC (`postgres_changes` on INSERT/UPDATE/DELETE) | 🔄 | `L` | `platform-limited` | No SQLite logical replication. Capture changes at the app layer (all mutations flow through the Data API), avoiding extensions and DB triggers. Caveat: only catches writes made through lite, not out-of-band direct DB writes. |
|
|
172
|
+
| Broadcast-from-database (`realtime.broadcast_changes`) | 🔄 | `L` | `platform-limited` | Same app-layer change capture as CDC; emits broadcast messages from row changes. |
|
|
173
|
+
|
|
174
|
+
---
|
|
175
|
+
|
|
176
|
+
> Maintenance: update this file alongside [STATUS.md](https://github.com/supabase-community/lite/blob/HEAD/STATUS.md) whenever feature support changes. Statuses here must agree with STATUS.md; this doc only adds the effort/blocker lens, it never overrides a support verdict. See [AGENTS.md](https://github.com/supabase-community/lite/blob/HEAD/AGENTS.md).
|
package/LIMITATIONS.md
CHANGED
|
@@ -6,12 +6,14 @@ Anchors below point to the corresponding STATUS.md section. If a limitation here
|
|
|
6
6
|
|
|
7
7
|
## SQL / DDL (SQLite path)
|
|
8
8
|
|
|
9
|
+
- Extension declarations are no-ops only for `plpgsql`, `pgcrypto`, and `uuid-ossp`; schema moves and drops for those names are ignored for declarative convergence, while unsupported names and other mutations fail. Only the documented PL/pgSQL trigger subset and UUID v4 defaults are emulated. See [Extension Statements](https://github.com/supabase-community/lite/blob/HEAD/STATUS.md#extension-statements).
|
|
9
10
|
- `DEFAULT auth.uid()` (and `auth.role()`, `auth.email()`, `auth.jwt()`) on columns → not supported. Drop the default, pass `user_id` from the client, rely on RLS `WITH CHECK`. See [Column Defaults](https://github.com/supabase-community/lite/blob/HEAD/STATUS.md#column-defaults).
|
|
10
11
|
- 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
12
|
- 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
13
|
- `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
14
|
- `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
15
|
- 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).
|
|
16
|
+
- `ALTER TYPE ... ADD VALUE` / `RENAME VALUE` (enum value changes) → not supported; the error names the type and operation. Recreate the type with all values, or use a manual migration. See [Translated Field Types](https://github.com/supabase-community/lite/blob/HEAD/STATUS.md#translated-field-types).
|
|
15
17
|
|
|
16
18
|
## supabase-js (SQLite path)
|
|
17
19
|
|
|
@@ -39,12 +41,13 @@ Anchors below point to the corresponding STATUS.md section. If a limitation here
|
|
|
39
41
|
## Runtime / dev
|
|
40
42
|
|
|
41
43
|
- `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).
|
|
42
|
-
-
|
|
43
|
-
- `lite start`
|
|
44
|
-
- `supabase/.temp/.
|
|
45
|
-
- **Admin mode is on by default
|
|
46
|
-
- Admin mode never elevates `/auth/v1`, cross-origin requests, requests from a non-loopback socket, or requests for a non-loopback hostname
|
|
44
|
+
- Run only one backend per project: never combine `lite dev`, `lite start`, or the Vite plugin against the same SQLite file. See [When to use what](https://github.com/supabase-community/lite/blob/HEAD/README.md#when-to-use-what).
|
|
45
|
+
- `lite start` is migration-only: it ignores migration files and `schemas/*.sql`, rebuilding metadata from recorded applied SQL. Invalid history or live structural drift requires `lite db reset`; declarative-only live changes therefore cannot be recovered by `start`. See [RLS](https://github.com/supabase-community/lite/blob/HEAD/STATUS.md#row-level-security-rls).
|
|
46
|
+
- `supabase/.temp/.runtime-metadata-cache.json` is disposable: missing, corrupt, stale, or tampered caches rebuild automatically when applied history matches the live structure. Only `sqlite-postgres` uses it. See [RLS](https://github.com/supabase-community/lite/blob/HEAD/STATUS.md#row-level-security-rls).
|
|
47
|
+
- **Admin mode is on by default only on loopback listeners.** `lite dev`/`lite start` bind `127.0.0.1`; `--host [host]` exposes/selects an address and defaults admin off unless `--admin` is explicit. Vite does the same for non-loopback hosts. Credentialed requests are unaffected. See [API Keys](https://github.com/supabase-community/lite/blob/HEAD/STATUS.md#api-keys).
|
|
48
|
+
- Admin mode never elevates `/auth/v1`, cross-origin requests, requests from a non-loopback socket, or requests for a non-loopback hostname. Public tunnels can make remote traffic appear loopback, so always use `--no-admin` when forwarding the port. Embedders get the hostname check unless their adapter supplies `AppRequestContext.peerAddress`.
|
|
47
49
|
- 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).
|
|
50
|
+
- The protected `storage` schema is not exposed through `/rest/v1` by default. Use `supabase.storage`; adding `storage` to `api.schemas` intentionally enables direct metadata endpoints. See [Storage API](https://github.com/supabase-community/lite/blob/HEAD/STATUS.md#storage-api).
|
|
48
51
|
|
|
49
52
|
## Postgres backends (pglite, postgres)
|
|
50
53
|
|
|
@@ -61,7 +64,7 @@ Common ways code goes wrong against supalite. The fix for each is the correspond
|
|
|
61
64
|
- Don't put `DEFAULT auth.uid()` on a column. Drop the default; pass `user_id` from the client; let RLS `WITH CHECK` enforce ownership.
|
|
62
65
|
- Don't call `rpc()` on the SQLite path. Run a regular HTTP endpoint, or switch the driver to `pglite` / `postgres` in `config.toml`.
|
|
63
66
|
- 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.
|
|
64
|
-
- Don't run `lite dev
|
|
67
|
+
- Don't run more than one of `lite dev`, `lite start`, or the Vite plugin for a project — they race one SQLite database even when ports differ.
|
|
65
68
|
- 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
69
|
- 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
70
|
- 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.
|
package/PATTERNS.md
CHANGED
|
@@ -36,26 +36,86 @@ await supabase.from("<thing>").insert({
|
|
|
36
36
|
});
|
|
37
37
|
```
|
|
38
38
|
|
|
39
|
+
## Per-user Storage ownership and folders
|
|
40
|
+
|
|
41
|
+
Uploads made with a verified JWT carrying a `sub` claim set both `storage.objects.owner_id` and the legacy `owner` field from that claim; `service_role` uploads remain ownerless. Custom string roles are preserved, so policies such as `TO manager` work when the database role and grants are configured. Use `owner_id` for per-user policies:
|
|
42
|
+
|
|
43
|
+
```sql
|
|
44
|
+
create policy "read own avatars"
|
|
45
|
+
on storage.objects for select to authenticated
|
|
46
|
+
using (bucket_id = 'avatars' and owner_id = auth.uid()::text);
|
|
47
|
+
|
|
48
|
+
create policy "upload own avatars"
|
|
49
|
+
on storage.objects for insert to authenticated
|
|
50
|
+
with check (bucket_id = 'avatars' and owner_id = auth.uid()::text);
|
|
51
|
+
|
|
52
|
+
create policy "update own avatars"
|
|
53
|
+
on storage.objects for update to authenticated
|
|
54
|
+
using (bucket_id = 'avatars' and owner_id = auth.uid()::text)
|
|
55
|
+
with check (bucket_id = 'avatars' and owner_id = auth.uid()::text);
|
|
56
|
+
|
|
57
|
+
create policy "delete own avatars"
|
|
58
|
+
on storage.objects for delete to authenticated
|
|
59
|
+
using (bucket_id = 'avatars' and owner_id = auth.uid()::text);
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
For a bucket laid out as `<user-id>/<filename>`, scope uploads to the caller's first folder:
|
|
63
|
+
|
|
64
|
+
```sql
|
|
65
|
+
create policy "upload to own avatar folder"
|
|
66
|
+
on storage.objects for insert to authenticated
|
|
67
|
+
with check (
|
|
68
|
+
bucket_id = 'avatars'
|
|
69
|
+
and (storage.foldername(name))[1] = auth.uid()::text
|
|
70
|
+
);
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
The indexed `storage.foldername()` form uses PostgreSQL's one-based indexing and works on SQLite, PGlite, and PostgreSQL. The upstream `storage.filename()` and `storage.extension()` helpers work across the same backends.
|
|
74
|
+
|
|
75
|
+
Use the operation helpers when one SQL command backs multiple Storage actions. This policy permits downloads without exposing the same objects through list:
|
|
76
|
+
|
|
77
|
+
```sql
|
|
78
|
+
create policy "download avatars without listing"
|
|
79
|
+
on storage.objects for select to authenticated
|
|
80
|
+
using (
|
|
81
|
+
bucket_id = 'avatars'
|
|
82
|
+
and storage.allow_any_operation(array[
|
|
83
|
+
'object.get_authenticated',
|
|
84
|
+
'object.get_authenticated_info'
|
|
85
|
+
])
|
|
86
|
+
);
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
`storage.operation()` returns the complete route identifier, such as `storage.object.upload`. `storage.allow_only_operation()` and `storage.allow_any_operation()` accept operation names with or without the `storage.` prefix. Public buckets bypass RLS only when serving objects through `GET`, `HEAD`, and info. Keep `SELECT` policies for listing, signing, copy sources, and move sources, plus mutation policies for uploads, deletes, moves, and copies.
|
|
90
|
+
|
|
39
91
|
## Verifying RLS policies locally
|
|
40
92
|
|
|
41
|
-
Local admin mode is on by default
|
|
93
|
+
Local admin mode is on by default for loopback `lite dev`, `lite start`, and Vite dev listeners. A request with **no** credential then 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
94
|
|
|
43
95
|
```bash
|
|
44
96
|
# anon: what a logged-out visitor sees
|
|
45
97
|
curl -H "apikey: $SUPABASE_PUBLISHABLE_KEY" \
|
|
46
|
-
"http://
|
|
98
|
+
"http://127.0.0.1:54321/rest/v1/<thing>?select=*"
|
|
47
99
|
|
|
48
100
|
# authenticated: the apikey is required IN ADDITION to the user JWT
|
|
49
101
|
JWT=$(curl -s -H "apikey: $SUPABASE_PUBLISHABLE_KEY" \
|
|
50
102
|
-H 'Content-Type: application/json' \
|
|
51
103
|
-d '{"email":"a@b.co","password":"secret123"}' \
|
|
52
|
-
"http://
|
|
104
|
+
"http://127.0.0.1:54321/auth/v1/token?grant_type=password" | jq -r .access_token)
|
|
53
105
|
|
|
54
106
|
curl -H "apikey: $SUPABASE_PUBLISHABLE_KEY" -H "Authorization: Bearer $JWT" \
|
|
55
|
-
"http://
|
|
107
|
+
"http://127.0.0.1:54321/rest/v1/<thing>?select=*"
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
`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 })`); keyless requests are not elevated and normal auth rules apply.
|
|
111
|
+
|
|
112
|
+
For a container, mobile device, or LAN client, expose the listener without exposing admin mode:
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
lite dev --host --no-admin
|
|
56
116
|
```
|
|
57
117
|
|
|
58
|
-
`
|
|
118
|
+
Bare `--host` has the same auth behavior but warns so the implicit admin shutdown is visible. `--host --admin` is only for direct trusted-network access: remote peers still require credentials, and a public tunnel can erase the peer boundary.
|
|
59
119
|
|
|
60
120
|
## Filtering an embedded resource (SQLite path)
|
|
61
121
|
|
|
@@ -103,7 +163,7 @@ The canonical Vite recipe:
|
|
|
103
163
|
```
|
|
104
164
|
6. `bun run dev`.
|
|
105
165
|
|
|
106
|
-
Same-process, same origin, hot-reload on schema changes.
|
|
166
|
+
Same-process, same origin, hot-reload on schema changes. This plugin is the project's only backend process: do **not** run `lite dev` or `lite start` alongside it.
|
|
107
167
|
|
|
108
168
|
## `updated_at` timestamps via trigger
|
|
109
169
|
|
package/README.md
CHANGED
|
@@ -24,6 +24,7 @@ If you're an agent working on a supalite project, read these first:
|
|
|
24
24
|
|
|
25
25
|
- [`LIMITATIONS.md`](https://github.com/supabase-community/lite/blob/HEAD/LIMITATIONS.md) — what's unsupported / partial, plus anti-patterns. Token-efficient cheat sheet.
|
|
26
26
|
- [`PATTERNS.md`](https://github.com/supabase-community/lite/blob/HEAD/PATTERNS.md) — canonical recipes (per-user RLS, embedded filter workarounds, custom server logic, Vite cold start, triggers).
|
|
27
|
+
- The full product documentation, shipped in the package at `node_modules/@supabase/lite/docs/` (index: `llms.txt`) and published at [docs.lite.dev](https://docs.lite.dev).
|
|
27
28
|
|
|
28
29
|
The npm package ships a [`supalite` skill](https://github.com/supabase-community/lite/blob/HEAD/skills/supalite/SKILL.md). After `npm install`, link it into your agent's skills dir so the cold-start checklist, routing rule, and limitation pointers trigger automatically:
|
|
29
30
|
|
|
@@ -73,14 +74,14 @@ lite init # scaffold supabase/ directory
|
|
|
73
74
|
lite dev # start server with schema hot-reload
|
|
74
75
|
```
|
|
75
76
|
|
|
76
|
-
The API is now running at `http://
|
|
77
|
+
The API is now running at `http://127.0.0.1:54321`. Point `@supabase/supabase-js` at it:
|
|
77
78
|
|
|
78
79
|
`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
80
|
|
|
80
81
|
```typescript
|
|
81
82
|
import { createClient } from "@supabase/supabase-js";
|
|
82
83
|
|
|
83
|
-
const supabase = createClient("http://
|
|
84
|
+
const supabase = createClient("http://127.0.0.1:54321", "<sb_publishable_...>");
|
|
84
85
|
const { data } = await supabase.from("todos").select("*");
|
|
85
86
|
```
|
|
86
87
|
|
|
@@ -98,7 +99,7 @@ Edit `supabase/schemas/schema.sql` and the dev server re-applies the schema auto
|
|
|
98
99
|
| Non-Vite app, want auto schema-reload | `lite dev` | Separate process. Watches `schemas/*.sql`, re-applies on change. |
|
|
99
100
|
| Non-Vite app, manual control / CI / prod-like | `lite start` | Separate process. No watch, no auto-migrate. |
|
|
100
101
|
|
|
101
|
-
>
|
|
102
|
+
> Run only one backend per project. Never run `lite dev` and `lite start` together, or either command alongside the Vite plugin: they would race migrations and schema reconciliation against the same SQLite file.
|
|
102
103
|
|
|
103
104
|
Known limitations across all paths: see [LIMITATIONS.md](https://github.com/supabase-community/lite/blob/HEAD/LIMITATIONS.md). Canonical recipes: see [PATTERNS.md](https://github.com/supabase-community/lite/blob/HEAD/PATTERNS.md).
|
|
104
105
|
|
|
@@ -122,6 +123,8 @@ to show details like the config file and database location on stderr.
|
|
|
122
123
|
| `generate-keys` | (Re)generate the publishable/secret API key pair, upsert `.env` |
|
|
123
124
|
| `dev` | Start server + watch `schemas/*.sql`, auto-apply on change |
|
|
124
125
|
| `start` | Start server (no watch, no auto-migrate) |
|
|
126
|
+
|
|
127
|
+
`lite dev` and `lite start` bind `127.0.0.1` by default. Pass `--host` to listen on all interfaces, matching Vite's flag, or `--host <address>` to choose one explicitly. An exposed listener defaults admin mode off; add `--admin` only when peer-scoped local Studio access is intentional.
|
|
125
128
|
| `db schema` | Print current DB schema; `--diff` compares vs `schemas/*.sql` |
|
|
126
129
|
| `db diff` | Emit a new pg-DDL migration from the declarative schema diff |
|
|
127
130
|
| `db translate` | Translate Postgres SQL to this project's backend dialect (arg or stdin) |
|
|
@@ -274,18 +277,23 @@ Lost or rotating keys: `lite generate-keys` mints a fresh pair and upserts `.env
|
|
|
274
277
|
|
|
275
278
|
### Admin mode (local only)
|
|
276
279
|
|
|
277
|
-
`lite dev`, `lite start`, and
|
|
280
|
+
`lite dev`, `lite start`, and a loopback-bound 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
281
|
|
|
279
282
|
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
283
|
|
|
281
284
|
```bash
|
|
282
|
-
lite start --no-admin #
|
|
285
|
+
lite start --no-admin # loopback server, admin explicitly off
|
|
286
|
+
lite start --host # all interfaces, admin defaults off and warns
|
|
287
|
+
lite start --host --no-admin # all interfaces, explicit/silent admin opt-out
|
|
288
|
+
lite start --host --admin # all interfaces, local peers may use admin
|
|
283
289
|
```
|
|
284
290
|
```ts
|
|
285
291
|
supalite({ admin: false }) # off for the Vite dev server
|
|
286
292
|
```
|
|
287
293
|
|
|
288
|
-
|
|
294
|
+
On a loopback CLI listener, precedence is explicit flag > `options.server.admin` in `config.toml` > the on-by-default launcher value. A non-loopback `--host` forces admin off unless `--admin` is present, so config cannot silently re-enable it. Vite follows the same rule: an exposed Vite host requires `supalite({ admin: true })`; preview and embedded `App` instances remain off by default.
|
|
295
|
+
|
|
296
|
+
A sandbox or tunnel may publish even a loopback listener and make remote traffic appear local. Use `--no-admin` whenever another system forwards the port publicly; locality is not an authentication mechanism across a proxy.
|
|
289
297
|
|
|
290
298
|
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
299
|
|
|
@@ -327,7 +335,7 @@ lite db diff -f tweak # diff schemas/ against applied migrations, emit
|
|
|
327
335
|
lite db reset # drop everything, replay migrations, run seed
|
|
328
336
|
```
|
|
329
337
|
|
|
330
|
-
Migrations and declarative schemas coexist: `lite dev` and the Vite plugin apply pending migrations on boot, then run the declarative diff.
|
|
338
|
+
Migrations and declarative schemas coexist: `lite dev` and the Vite plugin apply pending migrations on boot, then run the declarative diff. `lite start` is migration-only: the ordered SQL recorded in `supabase_migrations.schema_migrations` is authoritative, so pending, edited, deleted, or declarative files do not change runtime metadata until their SQL is applied and recorded. On `sqlite-postgres`, deleting `supabase/.temp/.runtime-metadata-cache.json` is safe; startup rebuilds it from applied history and asks for `lite db reset` only when that history is invalid or does not match the live structure.
|
|
331
339
|
|
|
332
340
|
---
|
|
333
341
|
|
|
@@ -340,7 +348,7 @@ Two ways to get a client:
|
|
|
340
348
|
```typescript
|
|
341
349
|
import { createClient } from "@supabase/supabase-js";
|
|
342
350
|
|
|
343
|
-
const client = createClient("http://
|
|
351
|
+
const client = createClient("http://127.0.0.1:54321", "<anon-key>");
|
|
344
352
|
|
|
345
353
|
// database
|
|
346
354
|
const { data } = await client.from("todos").select("*");
|