1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
//! # Supabase-compatible HTTP gateway
//!
//! A Kong-shaped HTTP surface (`/rest/v1`, `/auth/v1`, ...) in front of the
//! GuardianDB [`sql`](crate::sql) engine, so that Supabase client libraries
//! (`supabase-js`, PostgREST clients, GoTrue clients) can talk to a GuardianDB
//! node with no GuardianDB-specific code. Enabled by the `supabase` feature
//! (which implies `sql`). Default builds are entirely unaffected.
//!
//! Implemented end-to-end: **REST** (PostgREST-compatible), **Auth**
//! (GoTrue-compatible), **Storage** (storage-api-compatible, bytes in a
//! replicated `bytea` table), **postgres-meta** (what Supabase Studio talks
//! to), **Realtime** (Phoenix-protocol websocket) and **GraphQL**
//! (pg_graphql-compatible schema reflection over the `public` schema). The
//! remaining Kong service (functions) returns a typed `501 Not Implemented`
//! error — never a bare 404 and never fake success.
//!
//! ## Scouted seams (Stage 0)
//!
//! Everything here is built strictly on the engine's public surface; no file
//! under `src/sql/**` or `src/relational/**` is modified.
//!
//! * [`Database<S>`](crate::sql::engine::Database) — the shared, storage-backed
//! database. Built with `Database::new(Arc<S>, name)` where `S:
//! RelationalStorage`. Backends: [`MemoryStorage`](crate::relational::MemoryStorage)
//! (tests / in-memory binary) and
//! [`GuardianRelationalStorage`](crate::sql::GuardianRelationalStorage) via
//! [`open_sql`](crate::sql::open_sql) (persistent, Iroh-replicated).
//! * [`Session<S>`](crate::sql::engine::Session) — a connection-scoped session.
//! `Session::new(Arc<Database<S>>, username)`; the `username` is the role the
//! statement runs as. We open **one session per HTTP request**, bound to the
//! request's resolved Postgres role (`anon` / `authenticated` /
//! `service_role`) — the seam an RLS-enforcement slice will hook into.
//! * SQL execution: `Session::prepare(sql) -> Prepared` then
//! `Session::execute_one(&Prepared.statement, &[SqlValue])` runs a **single**
//! parameterised statement (`$1`, `$2`, ...). This is the injection-safe path
//! we use for REST/Auth data operations. `Session::execute(sql)` runs a
//! multi-statement string (no params) — used only for the auth-schema
//! bootstrap DDL.
//! * [`ExecResult`](crate::sql::ExecResult): `Rows { fields: Vec<OutField>,
//! rows: Vec<Vec<SqlValue>> }` or `Command { tag }`. `OutField` carries the
//! column `name` and [`SqlType`](crate::relational::SqlType); rows are
//! rendered to JSON in [`rest`] via [`rest::value_to_json`].
//! * [`SqlValue`](crate::relational::SqlValue) / [`SqlType`]: value model with
//! `to_text()` / `from_text(text, ty)`. REST coerces filter/body string values
//! to the *declared column type* (read from the [`Catalog`](crate::relational::Catalog))
//! via `SqlValue::from_text`, so numeric/temporal comparisons are typed rather
//! than lexical.
//! * [`RelError`](crate::relational::RelError)`::sqlstate()` — every engine error
//! carries a PostgreSQL SQLSTATE, mapped to PostgREST/GoTrue error shapes in
//! [`error`].
//! * Crypto: `bcrypt` (from the pgcrypto work) hashes/verifies passwords;
//! `hmac` + `sha2` + `base64` (already in-tree for `sql`) implement HS256 JWTs
//! from scratch in [`jwt`] — no `jsonwebtoken` dependency added.
//!
//! ## Architecture
//!
//! ```text
//! HTTP request
//! │
//! ├─ request_id middleware (x-request-id: read or generate)
//! │
//! ├─ apikey middleware (verify `apikey` JWT against project keys,
//! │ (rest + auth only) verify optional `Authorization: Bearer`,
//! │ resolve effective Postgres role,
//! │ attach AuthContext extension)
//! │
//! ├─ /rest/v1/* → rest.rs → Session(role) → SQL → PostgREST JSON
//! ├─ /graphql/v1 → graphql.rs → Session(role) → SQL → GraphQL JSON
//! ├─ /auth/v1/* → auth.rs → Session(service_role) → auth.* tables
//! ├─ /storage/v1/* → storage.rs → Session(role) → storage.* tables (RLS)
//! ├─ /pg-meta/* → pg_meta.rs → catalog + pg_catalog views (service_role)
//! ├─ /realtime/v1/websocket → realtime.rs → Phoenix ws + change hook
//! └─ /functions → 501 typed
//! ```
//!
//! Each request opens a fresh [`Session`] bound to the resolved role. A single
//! [`SupabaseCompatProject`] is served per gateway instance (the "single-project
//! shell").
pub use SupaError;
pub use ;
pub use ;
pub use ;