tinbase 0.2.2 → 0.6.0

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.
Files changed (94) hide show
  1. package/README.md +64 -31
  2. package/dist/admin/api.d.ts +8 -1
  3. package/dist/admin/api.js +94 -1
  4. package/dist/admin/api.js.map +1 -1
  5. package/dist/admin/ui.d.ts +1 -1
  6. package/dist/admin/ui.js +16 -16
  7. package/dist/auth/handler.d.ts +13 -1
  8. package/dist/auth/handler.js +173 -6
  9. package/dist/auth/handler.js.map +1 -1
  10. package/dist/auth/inbox.d.ts +31 -0
  11. package/dist/auth/inbox.js +112 -0
  12. package/dist/auth/inbox.js.map +1 -0
  13. package/dist/auth/oauth.d.ts +59 -0
  14. package/dist/auth/oauth.js +209 -0
  15. package/dist/auth/oauth.js.map +1 -0
  16. package/dist/auth/qr.d.ts +8 -0
  17. package/dist/auth/qr.js +376 -0
  18. package/dist/auth/qr.js.map +1 -0
  19. package/dist/auth/totp.d.ts +19 -0
  20. package/dist/auth/totp.js +101 -0
  21. package/dist/auth/totp.js.map +1 -0
  22. package/dist/cli.js +168 -10
  23. package/dist/cli.js.map +1 -1
  24. package/dist/cron/service.d.ts +29 -0
  25. package/dist/cron/service.js +134 -0
  26. package/dist/cron/service.js.map +1 -0
  27. package/dist/db/bootstrap.d.ts +8 -1
  28. package/dist/db/bootstrap.js +240 -1
  29. package/dist/db/bootstrap.js.map +1 -1
  30. package/dist/db/database.d.ts +24 -0
  31. package/dist/db/database.js +61 -2
  32. package/dist/db/database.js.map +1 -1
  33. package/dist/db/emulated.d.ts +12 -0
  34. package/dist/db/emulated.js +156 -0
  35. package/dist/db/emulated.js.map +1 -0
  36. package/dist/db/engine.d.ts +2 -0
  37. package/dist/db/engine.js.map +1 -1
  38. package/dist/db/inspect.d.ts +13 -0
  39. package/dist/db/inspect.js +22 -0
  40. package/dist/db/inspect.js.map +1 -0
  41. package/dist/db/pgmem-engine.d.ts +22 -0
  42. package/dist/db/pgmem-engine.js +135 -0
  43. package/dist/db/pgmem-engine.js.map +1 -0
  44. package/dist/db/schema-diff.d.ts +23 -0
  45. package/dist/db/schema-diff.js +182 -0
  46. package/dist/db/schema-diff.js.map +1 -0
  47. package/dist/functions/deno-shim.d.ts +24 -0
  48. package/dist/functions/deno-shim.js +47 -0
  49. package/dist/functions/deno-shim.js.map +1 -0
  50. package/dist/functions/handler.d.ts +3 -1
  51. package/dist/functions/handler.js.map +1 -1
  52. package/dist/gen-types.d.ts +17 -0
  53. package/dist/gen-types.js +222 -0
  54. package/dist/gen-types.js.map +1 -0
  55. package/dist/index.d.ts +20 -0
  56. package/dist/index.js +83 -15
  57. package/dist/index.js.map +1 -1
  58. package/dist/jwt.d.ts +7 -0
  59. package/dist/jwt.js.map +1 -1
  60. package/dist/log-buffer.d.ts +21 -0
  61. package/dist/log-buffer.js +20 -0
  62. package/dist/log-buffer.js.map +1 -0
  63. package/dist/node/bundle-function.d.ts +7 -0
  64. package/dist/node/bundle-function.js +90 -0
  65. package/dist/node/bundle-function.js.map +1 -0
  66. package/dist/node/db-diff.d.ts +34 -0
  67. package/dist/node/db-diff.js +82 -0
  68. package/dist/node/db-diff.js.map +1 -0
  69. package/dist/node/index.d.ts +4 -1
  70. package/dist/node/index.js +4 -1
  71. package/dist/node/index.js.map +1 -1
  72. package/dist/node/load-functions.d.ts +6 -0
  73. package/dist/node/load-functions.js +60 -8
  74. package/dist/node/load-functions.js.map +1 -1
  75. package/dist/node/load-oauth.d.ts +4 -0
  76. package/dist/node/load-oauth.js +126 -0
  77. package/dist/node/load-oauth.js.map +1 -0
  78. package/dist/node/native/engine.d.ts +1 -1
  79. package/dist/node/native/engine.js +45 -14
  80. package/dist/node/native/engine.js.map +1 -1
  81. package/dist/realtime/engine.d.ts +24 -1
  82. package/dist/realtime/engine.js +154 -2
  83. package/dist/realtime/engine.js.map +1 -1
  84. package/dist/rest/build.d.ts +5 -1
  85. package/dist/rest/build.js +17 -8
  86. package/dist/rest/build.js.map +1 -1
  87. package/dist/rest/handler.js +22 -9
  88. package/dist/rest/handler.js.map +1 -1
  89. package/dist/types.d.ts +10 -0
  90. package/dist/types.js.map +1 -1
  91. package/dist/webhooks/service.d.ts +47 -0
  92. package/dist/webhooks/service.js +86 -0
  93. package/dist/webhooks/service.js.map +1 -0
  94. package/package.json +7 -2
package/README.md CHANGED
@@ -15,7 +15,7 @@ npx tinbase start
15
15
 
16
16
  - **No Docker, no external services.** One runtime dependency: `@electric-sql/pglite`.
17
17
  - **Real Postgres semantics.** RLS policies, `auth.uid()`, triggers, FKs - it is Postgres.
18
- - **Two engines, one API.** Default is PGlite (WASM Postgres - portable, browser-ready). `--engine native` runs an embedded native Postgres instead: ~53 MB of RAM at boot, PocketBase-class footprint, zero semantic differences.
18
+ - **Three engines, one API.** Default is PGlite (WASM Postgres - portable, browser-ready). `--engine native` runs an embedded native Postgres instead: ~59 MB of RAM at boot, PocketBase-class footprint, zero semantic differences. `--engine pgmem` is an ultralight pure-JS in-memory subset for local dev / previews - see [Engines](#engines).
19
19
  - **Supabase CLI migration conventions.** Reads `supabase/migrations/*.sql` and `supabase/seed.sql`; tracks them in `supabase_migrations.schema_migrations`. Your migration files stay portable to hosted Supabase.
20
20
  - **Browser-ready core.** Every service is a pure `(Request) => Response` fetch handler. In Node it's served over HTTP; in the browser you can hand it to supabase-js as a custom `fetch` and run the whole backend in-process (PGlite already runs in the browser via IndexedDB/OPFS).
21
21
 
@@ -54,6 +54,9 @@ tinbase start # boot the server (applies pending migrations first)
54
54
  tinbase migrate # apply pending migrations and exit
55
55
  tinbase status # list applied migrations
56
56
  tinbase keys # print anon / service_role keys
57
+ tinbase gen types # print a TypeScript Database type for the schema
58
+ tinbase db reset # wipe the database + storage, re-run migrations and seed
59
+ tinbase db diff # DDL for schema changes not yet in migrations (-f <name> to save one)
57
60
 
58
61
  -p, --port <n> port (default 54321; or TINBASE_PORT / PORT env)
59
62
  --dir <path> project dir containing supabase/ (default cwd)
@@ -65,10 +68,12 @@ tinbase keys # print anon / service_role keys
65
68
 
66
69
  ### Engines
67
70
 
68
- - **wasm** (default): PGlite. Zero setup, runs anywhere Node runs - and in the browser. Costs ~350 MB RAM.
69
- - **native**: embedded native Postgres 17. First run downloads platform binaries (~12 MB, from [theseus-rs/postgresql-binaries](https://github.com/theseus-rs/postgresql-binaries), cached in `~/.cache/tinbase`), then `initdb` with memory-lean settings. ~53 MB RAM at boot. Listens only on a private unix socket (0700 dir, trust auth) - never TCP. macOS/Linux on x64/arm64; on Windows use wasm.
71
+ - **wasm** (default): PGlite. Zero setup, runs anywhere Node runs - and in the browser. Its WASM heap sits around ~575-650 MB and does not shrink under load.
72
+ - **native**: embedded native Postgres 17. First run downloads platform binaries (~12 MB, from [theseus-rs/postgresql-binaries](https://github.com/theseus-rs/postgresql-binaries), cached in `~/.cache/tinbase`), then `initdb` with memory-lean settings. ~59 MB RAM at boot. Listens only on a private unix socket (0700 dir, trust auth) - never TCP. macOS/Linux on x64/arm64; on Windows use wasm.
70
73
 
71
- Both engines run the identical bootstrap, migrations, RLS, and realtime CDC - the test suite passes on both (`TINBASE_TEST_ENGINE=native npm test`).
74
+ - **pgmem** (`--engine pgmem`): an ultralight, pure-JS, in-memory subset via [pg-mem](https://github.com/oguimbal/pg-mem) — **~3.6 MB install, no WASM**, so it's the lightest option for the browser (RapidNative local-dev / previews). Runs the REST CRUD surface, email/password auth, **edge functions, realtime (broadcast/presence + `postgres_changes`), and database webhooks**. pg-mem has no triggers or LISTEN/NOTIFY, so realtime/webhook change events are synthesized in JS by the REST layer (every write goes through it in-process). What's *not* here: **RLS** (so realtime/webhook events are delivered unfiltered, not per-subscriber), **cron**, and **pgmq** - RLS DDL in migrations is skipped, not fatal. Local-dev / preview only — never production.
75
+
76
+ The wasm and native engines run the identical bootstrap, migrations, RLS, and realtime CDC - the test suite passes on both (`TINBASE_TEST_ENGINE=native npm test`).
72
77
 
73
78
  ### Single-binary build
74
79
 
@@ -78,7 +83,7 @@ npm run build:binary # requires bun; emits dist-bin/tinbase (~57 MB)
78
83
  ./tinbase start # that's the whole deployment
79
84
  ```
80
85
 
81
- One compiled executable, no Node or npm on the target machine. It defaults to the native engine (Postgres binaries auto-download on first run, 12 MB) and serves everything - REST, Auth, Storage, Realtime WebSockets - at 44 MB of RAM at boot. Runs under Bun's runtime via a Bun-native server (`Bun.serve` + built-in WebSockets); the same CLI on Node uses the node:http server.
86
+ One compiled executable, no Node or npm on the target machine. It defaults to the native engine (Postgres binaries auto-download on first run, 12 MB) and serves everything - REST, Auth, Storage, Realtime WebSockets - at ~49 MB of RAM at boot (~66 MB under load). Runs under Bun's runtime via a Bun-native server (`Bun.serve` + built-in WebSockets); the same CLI on Node uses the node:http server.
82
87
 
83
88
  ## Embedding (Node or browser)
84
89
 
@@ -113,7 +118,10 @@ const server = await serve(backend, { port: 54321 })
113
118
  | REST (PostgREST) | `/rest/v1` | select with embedded resources (to-one, to-many, many-to-many via junction, nested, `!inner`, aliases, hints, casts, JSON paths), all common filter operators incl. `or`/`and` trees, full-text search, order/limit/offset (top-level and per-embed), `single`/`maybeSingle`, `count`, insert/bulk insert, upsert (merge/ignore), update, delete, `Prefer` handling, RPC (scalar, `setof`, void, filters on results), PostgREST-shaped errors |
114
119
  | Auth (GoTrue) | `/auth/v1` | email/password signup + sign-in, anonymous sign-in, session refresh with rotation, `getUser`, `updateUser`, sign-out, admin user CRUD (service key), GoTrue-shaped errors. JWTs are HS256 via WebCrypto; passwords are PBKDF2 |
115
120
  | Storage | `/storage/v1` | bucket CRUD, upload (raw + multipart), download, public objects, signed URLs, signed upload URLs, list with folder entries, move/copy, remove, size/MIME limits. Metadata lives in `storage.objects` with RLS enforced; bytes go through a pluggable driver (fs in Node, memory anywhere) |
116
- | Edge Functions | `/functions/v1` | `supabase.functions.invoke()` - functions are plain fetch handlers, loaded from `supabase/functions/<name>/index.{js,mjs,ts}` (default export) by the CLI or passed programmatically via `createBackend({ functions })`; each call receives the verified auth context and env keys |
121
+ | Edge Functions | `/functions/v1` | `supabase.functions.invoke()` - Supabase-style `Deno.serve(handler)` functions (with `Deno.env`) run unchanged, as do `export default` handlers; loaded from `supabase/functions/<name>/index.{ts,js,mjs}` by the CLI or passed via `createBackend({ functions })`. Web-API functions work as-is; `npm:`/`jsr:`/URL imports still need bundling |
122
+ | Queues (pgmq) | `pgmq.*` | Message queues via a pure-SQL pgmq subset (create/send/read/pop/delete/archive, visibility timeouts). Call from SQL or `supabase.schema('pgmq').rpc(...)`. No extension |
123
+ | Cron | `cron.*` | Scheduled jobs: `select cron.schedule(name, '*/5 * * * *', 'sql')` (also `'N seconds'`); an in-process scheduler runs due jobs and logs to `cron.job_run_details`. No extension |
124
+ | Database Webhooks | config | Fire HTTP requests on table INSERT/UPDATE/DELETE with Supabase's exact payload (`type`/`table`/`schema`/`record`/`old_record`). Configured via `createBackend({ webhooks })`, `backend.webhooks.register()`, or `supabase/webhooks.json`. Built on the CDC pipeline — no extension needed |
117
125
  | Studio (Admin UI) | `/_/` | A Supabase-Studio-style dashboard (React + Radix + Tailwind): Table Editor with full row CRUD, SQL editor, user management, bucket/object CRUD, and a database overview. One self-contained HTML file (works in the single binary); log in with the service_role key |
118
126
  | Realtime | `/realtime/v1` | Phoenix protocol (v1 JSON and v2 array/binary serializers), `postgres_changes` (INSERT/UPDATE/DELETE, filters) fed by triggers + `pg_notify`, broadcast (incl. binary payloads), presence. WebSocket server is a ~150-line RFC 6455 implementation - no `ws` dependency |
119
127
 
@@ -135,7 +143,8 @@ tinbase ships with a built-in dashboard at [`/_/`](http://127.0.0.1:54321/_/) -
135
143
  - **SQL Editor** - run arbitrary SQL with result grids and Postgres error details
136
144
  - **Authentication** - list, create, delete users and reset passwords
137
145
  - **Storage** - create/delete buckets, upload/delete objects, toggle public access
138
- - **Database** - stats overview and applied migrations
146
+ - **RLS Policies** - list, create, and drop policies per table
147
+ - **Database** - stats, migrations, functions, and triggers
139
148
 
140
149
  It is a React app compiled to a single self-contained HTML file, so it also works inside the single binary. Sign in with the `service_role` key printed at startup.
141
150
 
@@ -143,32 +152,49 @@ It is a React app compiled to a single self-contained HTML file, so it also work
143
152
 
144
153
  The extensions Supabase enables by default are available out of the box, so migrations that call `uuid_generate_v4()`, `gen_random_uuid()`, `crypt()`, `citext`, `pg_trgm`, and friends just work: **uuid-ossp, pgcrypto, citext, pg_trgm, ltree, hstore, fuzzystrmatch**. They live in the `extensions` schema (like hosted Supabase) and are on the search path, so both qualified and unqualified calls resolve.
145
154
 
155
+ ## Typed clients
156
+
157
+ Generate a Supabase-shaped `Database` type from the live schema, the same as `supabase gen types typescript`:
158
+
159
+ ```bash
160
+ tinbase gen types typescript > database.types.ts
161
+ ```
162
+
163
+ ```ts
164
+ import { createClient } from '@supabase/supabase-js'
165
+ import type { Database } from './database.types'
166
+ const supabase = createClient<Database>(url, anonKey) // fully typed queries
167
+ ```
168
+
169
+ Emits Tables (Row/Insert/Update/Relationships), Views, Functions, and Enums.
170
+
146
171
  ## Footprint: tinbase vs PocketBase vs Supabase local
147
172
 
148
173
  ![Memory footprint comparison](assets/footprint.svg)
149
174
 
150
175
  Measured on an Apple Silicon Mac (48 GB), macOS 15. Same workload for all three: boot with one migrated table, then 1,000 single-row inserts followed by 1,000 filtered list queries. Memory is physical footprint (`vmmap`) for native processes and the sum of `docker stats` for containers. Reproduce with [`bench/footprint.ts`](bench/footprint.ts); raw numbers in [`bench/results.json`](bench/results.json).
151
176
 
152
- | | tinbase (single binary) | tinbase (native, Node) | tinbase (wasm) | PocketBase v0.39.5 | Supabase local (CLI 2.40) |
153
- | --- | --- | --- | --- | --- | --- |
154
- | Database | real Postgres 17 + RLS | real Postgres 17 + RLS | real Postgres (PGlite) + RLS | SQLite | Postgres 17 |
155
- | Runtime memory at boot | 44 MB | 53 MB | 573 MB | 16 MB | 1,441 MB |
156
- | Runtime memory after workload | 64 MB | 96 MB | 347 MB¹ | 25 MB | 1,626 MB |
157
- | Data on disk (1k rows) | 38 MB | 38 MB | 39 MB | 7 MB | 70 MB |
158
- | Install size | 92 MB (no runtime needed) | 35 MB² | 26 MB² | 30 MB | 2,291 MB³ |
159
- | Processes | 2 (tinbase + postgres) | 2 (node + postgres) | 1 | 1 | 12 containers + Docker |
160
- | 1,000 inserts | 0.4 s | 0.5 s | 0.8 s | 0.3 s | 1.1 s |
161
- | 1,000 filtered reads | 0.4 s | 0.4 s | 0.8 s | 0.3 s | 1.0 s |
162
-
163
- ¹ PGlite's WASM instantiation peaks at boot, then the OS reclaims pages; steady state under load is ~350 MB.
164
- ² Native: unpacked Postgres 17 binaries + `dist`. Wasm: `dist` + `@electric-sql/pglite`. Both exclude the Node runtime you already have.
165
- ³ Sum of the Docker image sizes the default local stack runs, excluding Docker Desktop itself.
177
+ | | tinbase (single binary) | tinbase (native) | tinbase (pg-mem) | tinbase (wasm) | PocketBase v0.39.5 | Supabase local |
178
+ | --- | --- | --- | --- | --- | --- | --- |
179
+ | Database | real Postgres 17 + RLS | real Postgres 17 + RLS | in-memory subset¹ | real Postgres (PGlite) + RLS | SQLite | Postgres 17 |
180
+ | Runtime memory at boot | 49 MB | 59 MB | 71 MB | ~610 MB² | 15 MB | 1,441 MB |
181
+ | Runtime memory after workload | 66 MB | 100 MB | 185 MB | ~640 MB² | 24 MB | 1,626 MB |
182
+ | Data on disk (1k rows) | 39 MB | 39 MB | 0 (in-memory) | 40 MB | 7 MB | 70 MB |
183
+ | Install size | 92 MB (no runtime) | 36 MB³ | 3.6 MB³ | 27 MB³ | 30 MB | 2,291 MB⁴ |
184
+ | Processes | 2 | 2 | 1 | 1 | 1 | 12 containers + Docker |
185
+ | 1,000 inserts | 0.4 s | 0.5 s | 0.8 s | 0.8 s | 0.3 s | 1.1 s |
186
+ | 1,000 filtered reads | 0.3 s | 0.4 s | 0.8 s | 0.9 s | 0.3 s | 1.0 s |
187
+
188
+ ¹ **pg-mem** is a pure-JS in-memory subset (local dev / preview) — no RLS, cron, or pgmq (realtime/webhooks work but deliver unfiltered), but a **3.6 MB install** and pure JS (no WASM), the lightest option for the browser. See [Engines](#engines).
189
+ ² The wasm figure is essentially PGlite's WASM heap, which measures anywhere in ~575–650 MB depending on GC timing — treat it as a band, not a point. It does not shrink under load.
190
+ ³ Native: Postgres 17 binaries + `dist`. pg-mem: `dist` + `pg-mem`. Wasm: `dist` + `@electric-sql/pglite`. All exclude the Node runtime you already have.
191
+ ⁴ Sum of the Docker image sizes the default local stack runs, excluding Docker Desktop itself.
166
192
 
167
193
  **How to read this honestly:**
168
194
 
169
- - **vs Supabase local**: same SDK, same APIs, ~15-27x less memory (native engine), ~65x smaller install, 2 processes instead of a 12-container stack, and boots in ~2 s instead of a minute. That's the entire point of the project.
170
- - **vs PocketBase**: the single binary lands in PocketBase's weight class - ~2.5x the RAM, one downloadable file, no runtime prerequisite - while running *real Postgres* (RLS, jsonb, FKs, triggers) behind Supabase's exact wire APIs, so your code and migration files move to hosted Supabase unchanged. PocketBase is still the lightest option if you don't need any of that.
171
- - The wasm engine's memory is almost entirely the PGlite WASM heap; the API layers add single-digit MB. Use it where portability matters (browser, one-dependency installs); use `--engine native` on servers.
195
+ - **vs Supabase local**: same SDK, same APIs, ~16-24x less memory (native engine / single binary), ~25-65x smaller install, 2 processes instead of a 12-container stack, and boots in ~2 s instead of a minute. That's the entire point of the project.
196
+ - **vs PocketBase**: the single binary lands in PocketBase's weight class - ~2.7x the RAM (66 vs 24 MB under load), one downloadable file, no runtime prerequisite - while running *real Postgres* (RLS, jsonb, FKs, triggers) behind Supabase's exact wire APIs, so your code and migration files move to hosted Supabase unchanged. PocketBase is still the lightest option if you don't need any of that.
197
+ - The wasm engine trades memory for portability: its ~575-650 MB is PGlite's WASM heap (the API layers add single-digit MB), and it's the only engine that runs in a browser. On servers, use the native engine or single binary.
172
198
 
173
199
  ## How complete is it?
174
200
 
@@ -177,29 +203,36 @@ Rough coverage of the supabase-js SDK surface, measured against what each sub-li
177
203
  | Module | Coverage | Supported | Missing |
178
204
  | --- | --- | --- | --- |
179
205
  | Database (`postgrest-js`) | ~85% | full filter grammar, embeds (to-one/to-many/m2m/nested/`!inner`), JSON paths, upsert, count, single/maybeSingle, RPC | aggregates in select, full spread embeds, `.explain()`, `.csv()`, geojson |
180
- | Auth (`auth-js`) | ~65% | email/password, anonymous sign-in, OTP + magic links + password recovery (pluggable mailer, console default), refresh rotation, user updates, admin CRUD | OAuth providers, MFA, SSO/SAML, PKCE, phone auth |
206
+ | Auth (`auth-js`) | ~80% | email/password, anonymous sign-in, OTP + magic links + password recovery (pluggable mailer), OAuth providers (Google/GitHub presets + generic) with PKCE and identity linking, refresh rotation, user updates, admin CRUD | MFA, SSO/SAML, phone auth |
181
207
  | Storage (`storage-js`) | ~80% | buckets, upload/download, signed URLs + signed uploads, list/move/copy/remove, size/MIME limits | resumable (TUS) uploads, image transformations |
182
- | Realtime (`realtime-js`) | ~70% | postgres_changes with filters, broadcast (incl. binary), presence, v1+v2 serializers | RLS-filtered fan-out (WALRUS), private channel auth, DB-triggered broadcast |
183
- | Edge Functions (`functions-js`) | ~60% | `invoke()` with JSON/text bodies, auth context, project-dir loading | Deno runtime compat, import maps, `supabase functions deploy` |
208
+ | Realtime (`realtime-js`) | ~85% | postgres_changes with filters + **per-subscriber RLS filtering** (INSERT/UPDATE), broadcast (incl. binary), presence, v1+v2 serializers | per-row DELETE RLS, private channel auth, DB-triggered broadcast |
209
+ | Edge Functions (`functions-js`) | ~70% | `invoke()`; **Deno.serve/Deno.env-style functions run unchanged** + export-default; auth context, project-dir loading | `npm:`/`jsr:`/URL import resolution, `supabase functions deploy` |
210
+ | Type generation | ~85% | `tinbase gen types typescript` → `Database` type (Tables/Views/Functions/Enums/Relationships) | composite-type args, multi-schema output |
184
211
 
185
- **Overall: roughly 75% of the SDK surface - but ~90% of what a typical CRUD + auth + storage + realtime app actually calls.** The biggest real-world gaps are OAuth logins and edge functions.
212
+ **Overall: roughly 80% of the supabase-js SDK surface - and ~90% of what a typical CRUD + auth + storage + realtime app actually calls.**
213
+
214
+ Beyond the client SDK, the local platform features real projects depend on also work: **type generation**, **RLS** (enforced on REST, Storage, and realtime), **database webhooks**, **cron**, **queues (pgmq)**, the **Studio** dashboard, and Supabase-CLI migration conventions (`db reset` / `db diff`). The remaining gaps are OAuth logins' provider variety, the Deno edge-function runtime, and pgvector (needs an extension binary).
186
215
 
187
216
  ## Known gaps
188
217
 
189
- - `postgres_changes` does not apply RLS to fan-out (all subscribers see change events); hosted Supabase filters via WALRUS.
218
+ - `postgres_changes` applies RLS per subscriber for INSERT/UPDATE (the row is re-checked by primary key as that user). DELETE events can't be re-queried (the row is gone), so they are delivered to authenticated/service subscribers but not filtered per-row — hosted Supabase does this via WAL-level policy evaluation (WALRUS).
190
219
  - Spread embeds (`...rel(col)`) support flat column lists only; aggregate functions in `select` are not implemented.
191
- - Auth: no OAuth providers, MFA, or SSO. OTP/magic-link/recovery emails go through a pluggable `mailer` (the default just logs them to the console).
220
+ - Auth: OAuth works for any OAuth2/OIDC provider (Google & GitHub have built-in presets; configure via `TINBASE_OAUTH_<PROVIDER>_CLIENT_ID`/`_CLIENT_SECRET`). Still missing: MFA, SSO/SAML, phone auth. OTP/magic-link/recovery emails go through a pluggable `mailer` (default logs to console).
192
221
  - `pg_notify` payloads cap at ~8 kB - realtime events for larger rows arrive with `record: null` and an `errors` entry, like Supabase's "payload too large".
193
222
  - One writer at a time: PGlite is single-connection, and the native engine currently serializes requests over one connection for parity (a connection pool is a straightforward future upgrade). Fine for dev tools and small apps, not for high-concurrency production.
194
223
 
195
224
  ## Tests
196
225
 
197
- 53 integration tests + 4 realtime e2e tests run the real `@supabase/supabase-js` against the backend (REST via in-process fetch, realtime over actual WebSockets):
226
+ 120 tests run the real `@supabase/supabase-js` against the backend (REST via in-process fetch, realtime over actual WebSockets), and pass on both the wasm and native engines:
198
227
 
199
228
  ```bash
200
229
  npm test
201
230
  ```
202
231
 
232
+ ## Roadmap
233
+
234
+ tinbase aims to be a local, Docker-free replacement for `supabase start` where **almost everything just works**. The North Star, the in-scope/out-of-scope line, the current coverage table, and the phased plan live in [ROADMAP.md](ROADMAP.md).
235
+
203
236
  ## Why
204
237
 
205
238
  tinbase was built for [lifo](https://lifo.sh) - a project that maps Linux APIs into the browser - to let **Expo apps run fully in the browser with full-stack capability** (database, auth, storage, realtime, no server). It is part of [RapidNative](https://rapidnative.com). That origin drives the architecture:
@@ -1,12 +1,19 @@
1
1
  import type { Database } from '../db/database.js';
2
+ import type { LogBuffer } from '../log-buffer.js';
2
3
  import type { RequestContext } from '../types.js';
3
4
  export declare class AdminApi {
4
5
  private db;
5
- constructor(db: Database);
6
+ private logs?;
7
+ constructor(db: Database, logs?: LogBuffer | undefined);
6
8
  handle(req: Request, ctx: RequestContext, url: URL): Promise<Response>;
7
9
  private listTables;
8
10
  private runSql;
9
11
  private schemas;
10
12
  private migrations;
13
+ private listPolicies;
14
+ private createPolicy;
15
+ private dropPolicy;
16
+ private listFunctions;
17
+ private listTriggers;
11
18
  private stats;
12
19
  }
package/dist/admin/api.js CHANGED
@@ -13,8 +13,10 @@ function json(status, body) {
13
13
  }
14
14
  export class AdminApi {
15
15
  db;
16
- constructor(db) {
16
+ logs;
17
+ constructor(db, logs) {
17
18
  this.db = db;
19
+ this.logs = logs;
18
20
  }
19
21
  async handle(req, ctx, url) {
20
22
  if (ctx.role !== 'service_role') {
@@ -33,6 +35,22 @@ export class AdminApi {
33
35
  return await this.schemas();
34
36
  if (path === 'migrations' && method === 'GET')
35
37
  return await this.migrations();
38
+ if (path === 'policies' && method === 'GET')
39
+ return await this.listPolicies(url);
40
+ if (path === 'policies' && method === 'POST')
41
+ return await this.createPolicy(req);
42
+ if (path === 'policies' && method === 'DELETE')
43
+ return await this.dropPolicy(url);
44
+ if (path === 'functions' && method === 'GET')
45
+ return await this.listFunctions(url);
46
+ if (path === 'triggers' && method === 'GET')
47
+ return await this.listTriggers(url);
48
+ if (path === 'logs' && method === 'GET')
49
+ return json(200, { logs: this.logs?.list() ?? [] });
50
+ if (path === 'logs' && method === 'DELETE') {
51
+ this.logs?.clear();
52
+ return json(200, { ok: true });
53
+ }
36
54
  return json(404, { error: `unknown admin endpoint: ${path}` });
37
55
  }
38
56
  catch (e) {
@@ -96,6 +114,81 @@ export class AdminApi {
96
114
  const res = await this.db.query(`select version, name, applied_at from supabase_migrations.schema_migrations order by version`);
97
115
  return json(200, { migrations: res.rows });
98
116
  }
117
+ async listPolicies(url) {
118
+ const schema = url.searchParams.get('schema') ?? 'public';
119
+ const res = await this.db.query(`select schemaname as schema, tablename as table, policyname as name,
120
+ cmd, permissive, roles, qual as using_expr, with_check
121
+ from pg_policies where schemaname = $1
122
+ order by tablename, policyname`, [schema]);
123
+ return json(200, { policies: res.rows });
124
+ }
125
+ async createPolicy(req) {
126
+ const b = (await req.json().catch(() => ({})));
127
+ if (!b.table || !b.name)
128
+ return json(400, { error: 'table and name are required' });
129
+ const schema = b.schema ?? 'public';
130
+ const cmd = (b.command ?? 'ALL').toUpperCase();
131
+ const roles = b.roles?.trim() || 'public';
132
+ let sql = `create policy ${quoteIdent(b.name)} on ${quoteIdent(schema)}.${quoteIdent(b.table)} for ${cmd} to ${roles}`;
133
+ if (b.using?.trim())
134
+ sql += ` using (${b.using})`;
135
+ if (b.check?.trim())
136
+ sql += ` with check (${b.check})`;
137
+ try {
138
+ await this.db.query(sql);
139
+ this.db.invalidateSchemaCache();
140
+ return json(200, { ok: true });
141
+ }
142
+ catch (e) {
143
+ const pg = e;
144
+ return json(400, { error: pg.message, code: pg.code, hint: pg.hint });
145
+ }
146
+ }
147
+ async dropPolicy(url) {
148
+ const schema = url.searchParams.get('schema') ?? 'public';
149
+ const table = url.searchParams.get('table');
150
+ const name = url.searchParams.get('name');
151
+ if (!table || !name)
152
+ return json(400, { error: 'table and name are required' });
153
+ try {
154
+ await this.db.query(`drop policy ${quoteIdent(name)} on ${quoteIdent(schema)}.${quoteIdent(table)}`);
155
+ return json(200, { ok: true });
156
+ }
157
+ catch (e) {
158
+ return json(400, { error: e.message });
159
+ }
160
+ }
161
+ async listFunctions(url) {
162
+ const schema = url.searchParams.get('schema') ?? 'public';
163
+ const res = await this.db.query(`select p.proname as name,
164
+ pg_get_function_identity_arguments(p.oid) as args,
165
+ t.typname as returns, l.lanname as language,
166
+ p.prosrc as body
167
+ from pg_proc p
168
+ join pg_namespace n on n.oid = p.pronamespace
169
+ join pg_type t on t.oid = p.prorettype
170
+ join pg_language l on l.oid = p.prolang
171
+ where n.nspname = $1 and p.prokind = 'f'
172
+ order by p.proname`, [schema]);
173
+ return json(200, { functions: res.rows });
174
+ }
175
+ async listTriggers(url) {
176
+ const schema = url.searchParams.get('schema') ?? 'public';
177
+ const res = await this.db.query(`select tg.tgname as name, c.relname as table,
178
+ case when (tg.tgtype & 2) <> 0 then 'BEFORE' else 'AFTER' end as timing,
179
+ array_remove(array[
180
+ case when (tg.tgtype & 4) <> 0 then 'INSERT' end,
181
+ case when (tg.tgtype & 8) <> 0 then 'DELETE' end,
182
+ case when (tg.tgtype & 16) <> 0 then 'UPDATE' end], null) as events,
183
+ p.proname as function
184
+ from pg_trigger tg
185
+ join pg_class c on c.oid = tg.tgrelid
186
+ join pg_namespace n on n.oid = c.relnamespace
187
+ join pg_proc p on p.oid = tg.tgfoid
188
+ where n.nspname = $1 and not tg.tgisinternal
189
+ order by c.relname, tg.tgname`, [schema]);
190
+ return json(200, { triggers: res.rows });
191
+ }
99
192
  async stats() {
100
193
  const one = async (sql) => (await this.db.query(sql)).rows[0]?.n ?? 0;
101
194
  const users = await one(`select count(*)::int as n from auth.users`);
@@ -1 +1 @@
1
- {"version":3,"file":"api.js","sourceRoot":"","sources":["../../src/admin/api.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"api.js","sourceRoot":"","sources":["../../src/admin/api.ts"],"names":[],"mappings":"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"}