tinbase 0.1.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.
- package/LICENSE +21 -0
- package/README.md +185 -0
- package/assets/logo.svg +18 -0
- package/dist/auth/handler.d.ts +43 -0
- package/dist/auth/handler.js +291 -0
- package/dist/auth/handler.js.map +1 -0
- package/dist/auth/password.d.ts +3 -0
- package/dist/auth/password.js +40 -0
- package/dist/auth/password.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +181 -0
- package/dist/cli.js.map +1 -0
- package/dist/db/bootstrap.d.ts +6 -0
- package/dist/db/bootstrap.js +213 -0
- package/dist/db/bootstrap.js.map +1 -0
- package/dist/db/database.d.ts +83 -0
- package/dist/db/database.js +270 -0
- package/dist/db/database.js.map +1 -0
- package/dist/db/engine.d.ts +30 -0
- package/dist/db/engine.js +28 -0
- package/dist/db/engine.js.map +1 -0
- package/dist/db/pglite-engine.d.ts +3 -0
- package/dist/db/pglite-engine.js +39 -0
- package/dist/db/pglite-engine.js.map +1 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.js +145 -0
- package/dist/index.js.map +1 -0
- package/dist/jwt.d.ts +20 -0
- package/dist/jwt.js +72 -0
- package/dist/jwt.js.map +1 -0
- package/dist/node/bun-server.d.ts +8 -0
- package/dist/node/bun-server.js +41 -0
- package/dist/node/bun-server.js.map +1 -0
- package/dist/node/fs-driver.d.ts +11 -0
- package/dist/node/fs-driver.js +39 -0
- package/dist/node/fs-driver.js.map +1 -0
- package/dist/node/index.d.ts +7 -0
- package/dist/node/index.js +8 -0
- package/dist/node/index.js.map +1 -0
- package/dist/node/native/engine.d.ts +13 -0
- package/dist/node/native/engine.js +186 -0
- package/dist/node/native/engine.js.map +1 -0
- package/dist/node/native/wire.d.ts +38 -0
- package/dist/node/native/wire.js +345 -0
- package/dist/node/native/wire.js.map +1 -0
- package/dist/node/project.d.ts +6 -0
- package/dist/node/project.js +29 -0
- package/dist/node/project.js.map +1 -0
- package/dist/node/server-shared.d.ts +6 -0
- package/dist/node/server-shared.js +2 -0
- package/dist/node/server-shared.js.map +1 -0
- package/dist/node/server.d.ts +14 -0
- package/dist/node/server.js +83 -0
- package/dist/node/server.js.map +1 -0
- package/dist/node/ws.d.ts +8 -0
- package/dist/node/ws.js +165 -0
- package/dist/node/ws.js.map +1 -0
- package/dist/realtime/engine.d.ts +53 -0
- package/dist/realtime/engine.js +437 -0
- package/dist/realtime/engine.js.map +1 -0
- package/dist/rest/build.d.ts +53 -0
- package/dist/rest/build.js +505 -0
- package/dist/rest/build.js.map +1 -0
- package/dist/rest/errors.d.ts +2 -0
- package/dist/rest/errors.js +48 -0
- package/dist/rest/errors.js.map +1 -0
- package/dist/rest/handler.d.ts +11 -0
- package/dist/rest/handler.js +332 -0
- package/dist/rest/handler.js.map +1 -0
- package/dist/rest/parse.d.ts +69 -0
- package/dist/rest/parse.js +261 -0
- package/dist/rest/parse.js.map +1 -0
- package/dist/storage/driver.d.ts +9 -0
- package/dist/storage/driver.js +18 -0
- package/dist/storage/driver.js.map +1 -0
- package/dist/storage/handler.d.ts +49 -0
- package/dist/storage/handler.js +534 -0
- package/dist/storage/handler.js.map +1 -0
- package/dist/types.d.ts +51 -0
- package/dist/types.js +11 -0
- package/dist/types.js.map +1 -0
- package/package.json +59 -0
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
import { BOOTSTRAP_SQL } from './bootstrap.js';
|
|
2
|
+
import { createPgliteEngine } from './pglite-engine.js';
|
|
3
|
+
export class Database {
|
|
4
|
+
engine;
|
|
5
|
+
schemaCache = new Map();
|
|
6
|
+
fnCache = new Map();
|
|
7
|
+
cdcListeners = new Set();
|
|
8
|
+
cdcStarted = false;
|
|
9
|
+
constructor(engine) {
|
|
10
|
+
this.engine = engine;
|
|
11
|
+
}
|
|
12
|
+
/** Create a Database on PGlite (default) or any custom DbEngine. */
|
|
13
|
+
static async create(dataDirOrEngine) {
|
|
14
|
+
const engine = dataDirOrEngine && typeof dataDirOrEngine === 'object'
|
|
15
|
+
? dataDirOrEngine
|
|
16
|
+
: await createPgliteEngine(dataDirOrEngine);
|
|
17
|
+
await engine.exec(BOOTSTRAP_SQL);
|
|
18
|
+
return new Database(engine);
|
|
19
|
+
}
|
|
20
|
+
/** Superuser query — used by auth/storage internals and introspection. */
|
|
21
|
+
query(sql, params) {
|
|
22
|
+
return this.engine.query(sql, params);
|
|
23
|
+
}
|
|
24
|
+
exec(sql) {
|
|
25
|
+
return this.engine.exec(sql);
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Run `fn` inside a transaction with the request's Postgres role and JWT
|
|
29
|
+
* claims applied via SET LOCAL — this is what makes RLS behave exactly
|
|
30
|
+
* like hosted Supabase.
|
|
31
|
+
*/
|
|
32
|
+
async withContext(ctx, fn) {
|
|
33
|
+
return this.engine.transaction(async (tx) => {
|
|
34
|
+
await tx.query(`select set_config('role', $1, true),
|
|
35
|
+
set_config('request.jwt.claims', $2, true)`, [ctx.role, ctx.claims ? JSON.stringify(ctx.claims) : '']);
|
|
36
|
+
return fn((sql, params) => tx.query(sql, params));
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
// ── Migrations (Supabase CLI conventions) ────────────────────────────
|
|
40
|
+
async runMigrations(migrations, seedSql) {
|
|
41
|
+
const applied = [];
|
|
42
|
+
const sorted = [...migrations].sort((a, b) => a.name.localeCompare(b.name));
|
|
43
|
+
for (const m of sorted) {
|
|
44
|
+
const version = m.name.match(/^(\d+)/)?.[1] ?? m.name;
|
|
45
|
+
const seen = await this.engine.query(`select 1 from supabase_migrations.schema_migrations where version = $1`, [version]);
|
|
46
|
+
if (seen.rows.length > 0)
|
|
47
|
+
continue;
|
|
48
|
+
await this.engine.transaction(async (tx) => {
|
|
49
|
+
await tx.exec(m.sql);
|
|
50
|
+
await tx.query(`insert into supabase_migrations.schema_migrations (version, name, statements)
|
|
51
|
+
values ($1, $2, $3)`, [version, m.name, [m.sql]]);
|
|
52
|
+
});
|
|
53
|
+
applied.push(m.name);
|
|
54
|
+
}
|
|
55
|
+
if (seedSql) {
|
|
56
|
+
const hash = await sha256Hex(seedSql);
|
|
57
|
+
const seen = await this.engine.query(`select 1 from supabase_migrations.seed_files where path = 'supabase/seed.sql' and hash = $1`, [hash]);
|
|
58
|
+
if (seen.rows.length === 0) {
|
|
59
|
+
await this.engine.transaction(async (tx) => {
|
|
60
|
+
await tx.exec(seedSql);
|
|
61
|
+
await tx.query(`insert into supabase_migrations.seed_files (path, hash) values ('supabase/seed.sql', $1)
|
|
62
|
+
on conflict (path) do update set hash = excluded.hash, applied_at = now()`, [hash]);
|
|
63
|
+
});
|
|
64
|
+
applied.push('seed.sql');
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
if (applied.length > 0)
|
|
68
|
+
this.invalidateSchemaCache();
|
|
69
|
+
return applied;
|
|
70
|
+
}
|
|
71
|
+
async listAppliedMigrations() {
|
|
72
|
+
const res = await this.engine.query(`select version, name from supabase_migrations.schema_migrations order by version`);
|
|
73
|
+
return res.rows;
|
|
74
|
+
}
|
|
75
|
+
// ── Introspection ────────────────────────────────────────────────────
|
|
76
|
+
invalidateSchemaCache() {
|
|
77
|
+
this.schemaCache.clear();
|
|
78
|
+
this.fnCache.clear();
|
|
79
|
+
}
|
|
80
|
+
async getSchemaInfo(schema) {
|
|
81
|
+
const cached = this.schemaCache.get(schema);
|
|
82
|
+
if (cached)
|
|
83
|
+
return cached;
|
|
84
|
+
const cols = await this.engine.query(`select table_name, column_name, udt_name, is_nullable,
|
|
85
|
+
column_default is not null as has_default
|
|
86
|
+
from information_schema.columns
|
|
87
|
+
where table_schema = $1
|
|
88
|
+
order by ordinal_position`, [schema]);
|
|
89
|
+
const pks = await this.engine.query(`select kcu.table_name, kcu.column_name
|
|
90
|
+
from information_schema.table_constraints tc
|
|
91
|
+
join information_schema.key_column_usage kcu
|
|
92
|
+
on kcu.constraint_name = tc.constraint_name
|
|
93
|
+
and kcu.constraint_schema = tc.constraint_schema
|
|
94
|
+
where tc.constraint_type = 'PRIMARY KEY' and tc.table_schema = $1`, [schema]);
|
|
95
|
+
const fks = await this.engine.query(`select
|
|
96
|
+
tc.constraint_name,
|
|
97
|
+
tc.table_schema as src_schema, tc.table_name as src_table,
|
|
98
|
+
kcu.column_name as src_column,
|
|
99
|
+
ccu.table_schema as tgt_schema, ccu.table_name as tgt_table,
|
|
100
|
+
ccu.column_name as tgt_column,
|
|
101
|
+
kcu.ordinal_position as ordinal
|
|
102
|
+
from information_schema.table_constraints tc
|
|
103
|
+
join information_schema.key_column_usage kcu
|
|
104
|
+
on kcu.constraint_name = tc.constraint_name
|
|
105
|
+
and kcu.constraint_schema = tc.constraint_schema
|
|
106
|
+
join information_schema.constraint_column_usage ccu
|
|
107
|
+
on ccu.constraint_name = tc.constraint_name
|
|
108
|
+
and ccu.constraint_schema = tc.constraint_schema
|
|
109
|
+
where tc.constraint_type = 'FOREIGN KEY'
|
|
110
|
+
and (tc.table_schema = $1 or ccu.table_schema = $1)
|
|
111
|
+
order by tc.constraint_name, kcu.ordinal_position`, [schema]);
|
|
112
|
+
const pkSet = new Map();
|
|
113
|
+
for (const pk of pks.rows) {
|
|
114
|
+
if (!pkSet.has(pk.table_name))
|
|
115
|
+
pkSet.set(pk.table_name, new Set());
|
|
116
|
+
pkSet.get(pk.table_name).add(pk.column_name);
|
|
117
|
+
}
|
|
118
|
+
const tables = new Map();
|
|
119
|
+
for (const c of cols.rows) {
|
|
120
|
+
if (!tables.has(c.table_name)) {
|
|
121
|
+
tables.set(c.table_name, {
|
|
122
|
+
schema,
|
|
123
|
+
name: c.table_name,
|
|
124
|
+
columns: [],
|
|
125
|
+
primaryKey: [...(pkSet.get(c.table_name) ?? [])],
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
tables.get(c.table_name).columns.push({
|
|
129
|
+
name: c.column_name,
|
|
130
|
+
udtName: c.udt_name,
|
|
131
|
+
isNullable: c.is_nullable === 'YES',
|
|
132
|
+
hasDefault: c.has_default,
|
|
133
|
+
isPrimaryKey: pkSet.get(c.table_name)?.has(c.column_name) ?? false,
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
const fkMap = new Map();
|
|
137
|
+
for (const fk of fks.rows) {
|
|
138
|
+
let entry = fkMap.get(fk.constraint_name);
|
|
139
|
+
if (!entry) {
|
|
140
|
+
entry = {
|
|
141
|
+
constraintName: fk.constraint_name,
|
|
142
|
+
srcSchema: fk.src_schema,
|
|
143
|
+
srcTable: fk.src_table,
|
|
144
|
+
srcColumns: [],
|
|
145
|
+
tgtSchema: fk.tgt_schema,
|
|
146
|
+
tgtTable: fk.tgt_table,
|
|
147
|
+
tgtColumns: [],
|
|
148
|
+
};
|
|
149
|
+
fkMap.set(fk.constraint_name, entry);
|
|
150
|
+
}
|
|
151
|
+
if (!entry.srcColumns.includes(fk.src_column))
|
|
152
|
+
entry.srcColumns.push(fk.src_column);
|
|
153
|
+
if (!entry.tgtColumns.includes(fk.tgt_column))
|
|
154
|
+
entry.tgtColumns.push(fk.tgt_column);
|
|
155
|
+
}
|
|
156
|
+
const info = { tables, foreignKeys: [...fkMap.values()] };
|
|
157
|
+
this.schemaCache.set(schema, info);
|
|
158
|
+
return info;
|
|
159
|
+
}
|
|
160
|
+
async getFunctions(schema, name) {
|
|
161
|
+
const key = `${schema}.${name}`;
|
|
162
|
+
const cached = this.fnCache.get(key);
|
|
163
|
+
if (cached)
|
|
164
|
+
return cached;
|
|
165
|
+
const res = await this.engine.query(`select p.proname as name, p.proretset as returns_set,
|
|
166
|
+
t.typname as return_type, t.typtype as return_typtype,
|
|
167
|
+
pg_get_function_identity_arguments(p.oid) as identity_args
|
|
168
|
+
from pg_proc p
|
|
169
|
+
join pg_namespace n on n.oid = p.pronamespace
|
|
170
|
+
join pg_type t on t.oid = p.prorettype
|
|
171
|
+
where n.nspname = $1 and p.proname = $2`, [schema, name]);
|
|
172
|
+
const fns = res.rows.map((r) => ({
|
|
173
|
+
schema,
|
|
174
|
+
name: r.name,
|
|
175
|
+
returnsSet: r.returns_set,
|
|
176
|
+
returnType: r.return_type,
|
|
177
|
+
returnTypType: r.return_typtype,
|
|
178
|
+
args: parseIdentityArgs(r.identity_args),
|
|
179
|
+
}));
|
|
180
|
+
this.fnCache.set(key, fns);
|
|
181
|
+
return fns;
|
|
182
|
+
}
|
|
183
|
+
// ── Realtime CDC ─────────────────────────────────────────────────────
|
|
184
|
+
async ensureCdcTrigger(schema, table) {
|
|
185
|
+
const s = quoteIdent(schema);
|
|
186
|
+
const t = quoteIdent(table);
|
|
187
|
+
await this.engine.exec(`
|
|
188
|
+
do $$ begin
|
|
189
|
+
if not exists (
|
|
190
|
+
select from pg_trigger tg
|
|
191
|
+
join pg_class c on c.oid = tg.tgrelid
|
|
192
|
+
join pg_namespace n on n.oid = c.relnamespace
|
|
193
|
+
where tg.tgname = 'tinbase_cdc'
|
|
194
|
+
and n.nspname = ${quoteLiteral(schema)}
|
|
195
|
+
and c.relname = ${quoteLiteral(table)}
|
|
196
|
+
) then
|
|
197
|
+
create trigger tinbase_cdc
|
|
198
|
+
after insert or update or delete on ${s}.${t}
|
|
199
|
+
for each row execute function tinbase.cdc_notify();
|
|
200
|
+
end if;
|
|
201
|
+
end $$;
|
|
202
|
+
`);
|
|
203
|
+
}
|
|
204
|
+
async onCdcEvent(cb) {
|
|
205
|
+
this.cdcListeners.add(cb);
|
|
206
|
+
if (!this.cdcStarted) {
|
|
207
|
+
this.cdcStarted = true;
|
|
208
|
+
await this.engine.listen('tinbase_cdc', (payload) => {
|
|
209
|
+
try {
|
|
210
|
+
const event = JSON.parse(payload);
|
|
211
|
+
for (const listener of this.cdcListeners)
|
|
212
|
+
listener(event);
|
|
213
|
+
}
|
|
214
|
+
catch {
|
|
215
|
+
// malformed payload — drop
|
|
216
|
+
}
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
return () => this.cdcListeners.delete(cb);
|
|
220
|
+
}
|
|
221
|
+
async close() {
|
|
222
|
+
await this.engine.close();
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
/** Parse pg_get_function_identity_arguments output: "a integer, b text[]". */
|
|
226
|
+
function parseIdentityArgs(identity) {
|
|
227
|
+
if (!identity.trim())
|
|
228
|
+
return [];
|
|
229
|
+
const parts = [];
|
|
230
|
+
let depth = 0;
|
|
231
|
+
let current = '';
|
|
232
|
+
for (const ch of identity) {
|
|
233
|
+
if (ch === '(')
|
|
234
|
+
depth++;
|
|
235
|
+
if (ch === ')')
|
|
236
|
+
depth--;
|
|
237
|
+
if (ch === ',' && depth === 0) {
|
|
238
|
+
parts.push(current);
|
|
239
|
+
current = '';
|
|
240
|
+
}
|
|
241
|
+
else {
|
|
242
|
+
current += ch;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
if (current.trim())
|
|
246
|
+
parts.push(current);
|
|
247
|
+
return parts.map((part) => {
|
|
248
|
+
const tokens = part.trim().split(/\s+/);
|
|
249
|
+
while (tokens.length > 1 && ['IN', 'OUT', 'INOUT', 'VARIADIC'].includes(tokens[0])) {
|
|
250
|
+
tokens.shift();
|
|
251
|
+
}
|
|
252
|
+
if (tokens.length === 1)
|
|
253
|
+
return { name: '', type: tokens[0] };
|
|
254
|
+
const name = tokens[0].replace(/^"|"$/g, '');
|
|
255
|
+
return { name, type: tokens.slice(1).join(' ') };
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
export function quoteIdent(name) {
|
|
259
|
+
if (name.includes('\0'))
|
|
260
|
+
throw new Error('invalid identifier');
|
|
261
|
+
return `"${name.replaceAll('"', '""')}"`;
|
|
262
|
+
}
|
|
263
|
+
export function quoteLiteral(value) {
|
|
264
|
+
return `'${value.replaceAll("'", "''")}'`;
|
|
265
|
+
}
|
|
266
|
+
async function sha256Hex(text) {
|
|
267
|
+
const digest = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(text));
|
|
268
|
+
return [...new Uint8Array(digest)].map((b) => b.toString(16).padStart(2, '0')).join('');
|
|
269
|
+
}
|
|
270
|
+
//# sourceMappingURL=database.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"database.js","sourceRoot":"","sources":["../../src/db/database.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Database engine abstraction. Two implementations:
|
|
3
|
+
* - PGlite (WASM Postgres) — portable, runs in the browser; heavier RAM.
|
|
4
|
+
* - Native embedded Postgres (Node only) — PocketBase-class footprint.
|
|
5
|
+
* The rest of tinbase only talks to this interface.
|
|
6
|
+
*/
|
|
7
|
+
export interface EngineResults<T = any> {
|
|
8
|
+
rows: T[];
|
|
9
|
+
affectedRows?: number;
|
|
10
|
+
}
|
|
11
|
+
export interface EngineTx {
|
|
12
|
+
query<T = any>(sql: string, params?: unknown[]): Promise<EngineResults<T>>;
|
|
13
|
+
exec(sql: string): Promise<void>;
|
|
14
|
+
}
|
|
15
|
+
export interface DbEngine {
|
|
16
|
+
query<T = any>(sql: string, params?: unknown[]): Promise<EngineResults<T>>;
|
|
17
|
+
/** Run multiple SQL statements (no params). */
|
|
18
|
+
exec(sql: string): Promise<void>;
|
|
19
|
+
/** Serialized transaction — implementations must guarantee mutual exclusion. */
|
|
20
|
+
transaction<T>(fn: (tx: EngineTx) => Promise<T>): Promise<T>;
|
|
21
|
+
/** Subscribe to pg_notify on a channel. Returns unsubscribe. */
|
|
22
|
+
listen(channel: string, cb: (payload: string) => void): Promise<() => void>;
|
|
23
|
+
close(): Promise<void>;
|
|
24
|
+
}
|
|
25
|
+
/** Simple async mutex for engines that serialize over one connection. */
|
|
26
|
+
export declare class Mutex {
|
|
27
|
+
private tail;
|
|
28
|
+
lock(): Promise<() => void>;
|
|
29
|
+
run<T>(fn: () => Promise<T>): Promise<T>;
|
|
30
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Database engine abstraction. Two implementations:
|
|
3
|
+
* - PGlite (WASM Postgres) — portable, runs in the browser; heavier RAM.
|
|
4
|
+
* - Native embedded Postgres (Node only) — PocketBase-class footprint.
|
|
5
|
+
* The rest of tinbase only talks to this interface.
|
|
6
|
+
*/
|
|
7
|
+
/** Simple async mutex for engines that serialize over one connection. */
|
|
8
|
+
export class Mutex {
|
|
9
|
+
tail = Promise.resolve();
|
|
10
|
+
async lock() {
|
|
11
|
+
let release;
|
|
12
|
+
const next = new Promise((r) => (release = r));
|
|
13
|
+
const prev = this.tail;
|
|
14
|
+
this.tail = this.tail.then(() => next);
|
|
15
|
+
await prev;
|
|
16
|
+
return release;
|
|
17
|
+
}
|
|
18
|
+
async run(fn) {
|
|
19
|
+
const release = await this.lock();
|
|
20
|
+
try {
|
|
21
|
+
return await fn();
|
|
22
|
+
}
|
|
23
|
+
finally {
|
|
24
|
+
release();
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=engine.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engine.js","sourceRoot":"","sources":["../../src/db/engine.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAuBH,yEAAyE;AACzE,MAAM,OAAO,KAAK;IACR,IAAI,GAAkB,OAAO,CAAC,OAAO,EAAE,CAAA;IAE/C,KAAK,CAAC,IAAI;QACR,IAAI,OAAoB,CAAA;QACxB,MAAM,IAAI,GAAG,IAAI,OAAO,CAAO,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC,CAAA;QACpD,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAA;QACtB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAA;QACtC,MAAM,IAAI,CAAA;QACV,OAAO,OAAO,CAAA;IAChB,CAAC;IAED,KAAK,CAAC,GAAG,CAAI,EAAoB;QAC/B,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,IAAI,EAAE,CAAA;QACjC,IAAI,CAAC;YACH,OAAO,MAAM,EAAE,EAAE,CAAA;QACnB,CAAC;gBAAS,CAAC;YACT,OAAO,EAAE,CAAA;QACX,CAAC;IACH,CAAC;CACF"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
export async function createPgliteEngine(dataDir) {
|
|
2
|
+
let PGlite;
|
|
3
|
+
try {
|
|
4
|
+
;
|
|
5
|
+
({ PGlite } = await import('@electric-sql/pglite'));
|
|
6
|
+
}
|
|
7
|
+
catch {
|
|
8
|
+
throw new Error('the PGlite (wasm) engine is not available in this build — run with --engine native');
|
|
9
|
+
}
|
|
10
|
+
const pg = dataDir ? new PGlite(dataDir) : new PGlite();
|
|
11
|
+
await pg.waitReady;
|
|
12
|
+
return {
|
|
13
|
+
async query(sql, params) {
|
|
14
|
+
const res = await pg.query(sql, params);
|
|
15
|
+
return { rows: res.rows, affectedRows: res.affectedRows };
|
|
16
|
+
},
|
|
17
|
+
async exec(sql) {
|
|
18
|
+
await pg.exec(sql);
|
|
19
|
+
},
|
|
20
|
+
transaction(fn) {
|
|
21
|
+
return pg.transaction(async (tx) => {
|
|
22
|
+
return fn({
|
|
23
|
+
async query(sql, params) {
|
|
24
|
+
const res = await tx.query(sql, params);
|
|
25
|
+
return { rows: res.rows, affectedRows: res.affectedRows };
|
|
26
|
+
},
|
|
27
|
+
async exec(sql) {
|
|
28
|
+
await tx.exec(sql);
|
|
29
|
+
},
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
},
|
|
33
|
+
async listen(channel, cb) {
|
|
34
|
+
return pg.listen(channel, cb);
|
|
35
|
+
},
|
|
36
|
+
close: () => pg.close(),
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=pglite-engine.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pglite-engine.js","sourceRoot":"","sources":["../../src/db/pglite-engine.ts"],"names":[],"mappings":"AAGA,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,OAAgB;IACvD,IAAI,MAAM,CAAA;IACV,IAAI,CAAC;QACH,CAAC;QAAA,CAAC,EAAE,MAAM,EAAE,GAAG,MAAM,MAAM,CAAC,sBAAsB,CAAC,CAAC,CAAA;IACtD,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,KAAK,CACb,oFAAoF,CACrF,CAAA;IACH,CAAC;IACD,MAAM,EAAE,GAAG,OAAO,CAAC,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,MAAM,EAAE,CAAA;IACvD,MAAM,EAAE,CAAC,SAAS,CAAA;IAElB,OAAO;QACL,KAAK,CAAC,KAAK,CAAI,GAAW,EAAE,MAAkB;YAC5C,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC,KAAK,CAAI,GAAG,EAAE,MAAM,CAAC,CAAA;YAC1C,OAAO,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,YAAY,EAAE,GAAG,CAAC,YAAY,EAAE,CAAA;QAC3D,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,GAAW;YACpB,MAAM,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;QACpB,CAAC;QACD,WAAW,CAAI,EAAgC;YAC7C,OAAO,EAAE,CAAC,WAAW,CAAC,KAAK,EAAE,EAAE,EAAE,EAAE;gBACjC,OAAO,EAAE,CAAC;oBACR,KAAK,CAAC,KAAK,CAAI,GAAW,EAAE,MAAkB;wBAC5C,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC,KAAK,CAAI,GAAG,EAAE,MAAM,CAAC,CAAA;wBAC1C,OAAO,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,YAAY,EAAE,GAAG,CAAC,YAAY,EAAE,CAAA;oBAC3D,CAAC;oBACD,KAAK,CAAC,IAAI,CAAC,GAAW;wBACpB,MAAM,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;oBACpB,CAAC;iBACF,CAAC,CAAA;YACJ,CAAC,CAAe,CAAA;QAClB,CAAC;QACD,KAAK,CAAC,MAAM,CAAC,OAAe,EAAE,EAA6B;YACzD,OAAO,EAAE,CAAC,MAAM,CAAC,OAAO,EAAE,EAAE,CAAC,CAAA;QAC/B,CAAC;QACD,KAAK,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC,KAAK,EAAE;KACxB,CAAA;AACH,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { Database } from './db/database.js';
|
|
2
|
+
import { RealtimeEngine } from './realtime/engine.js';
|
|
3
|
+
import { type BackendConfig, type MigrationFile } from './types.js';
|
|
4
|
+
export * from './types.js';
|
|
5
|
+
export { Database } from './db/database.js';
|
|
6
|
+
export { MemoryStorageDriver } from './storage/driver.js';
|
|
7
|
+
export { RealtimeEngine, type RealtimeSocketLike } from './realtime/engine.js';
|
|
8
|
+
export { signJwt, verifyJwt, decodeJwt } from './jwt.js';
|
|
9
|
+
export interface TinbaseBackend {
|
|
10
|
+
/** The whole backend as a fetch handler. Pass to supabase-js as global.fetch for in-process use. */
|
|
11
|
+
fetch: (req: Request) => Promise<Response>;
|
|
12
|
+
db: Database;
|
|
13
|
+
realtime: RealtimeEngine;
|
|
14
|
+
/** JWT for the anon role — use as supabase-js's supabaseKey. */
|
|
15
|
+
anonKey: string;
|
|
16
|
+
/** JWT for the service_role — bypasses RLS. */
|
|
17
|
+
serviceRoleKey: string;
|
|
18
|
+
jwtSecret: string;
|
|
19
|
+
/** Apply additional migrations at runtime. */
|
|
20
|
+
migrate: (migrations: MigrationFile[], seedSql?: string) => Promise<string[]>;
|
|
21
|
+
close: () => Promise<void>;
|
|
22
|
+
}
|
|
23
|
+
export declare function createBackend(config?: BackendConfig): Promise<TinbaseBackend>;
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* tinbase — a pure-JS, Docker-free Supabase backend on PGlite that speaks
|
|
3
|
+
* the same wire protocols as hosted Supabase, so the official supabase-js
|
|
4
|
+
* SDK works unchanged.
|
|
5
|
+
*
|
|
6
|
+
* The core is a fetch handler (Request → Response): serve it over HTTP in
|
|
7
|
+
* Node, or call it in-process in the browser by passing it as supabase-js's
|
|
8
|
+
* `global.fetch`.
|
|
9
|
+
*/
|
|
10
|
+
import { AuthHandler } from './auth/handler.js';
|
|
11
|
+
import { Database } from './db/database.js';
|
|
12
|
+
import { signJwt, verifyJwt } from './jwt.js';
|
|
13
|
+
import { RealtimeEngine } from './realtime/engine.js';
|
|
14
|
+
import { RestHandler } from './rest/handler.js';
|
|
15
|
+
import { MemoryStorageDriver } from './storage/driver.js';
|
|
16
|
+
import { StorageHandler } from './storage/handler.js';
|
|
17
|
+
import { DEFAULT_JWT_SECRET } from './types.js';
|
|
18
|
+
export * from './types.js';
|
|
19
|
+
export { Database } from './db/database.js';
|
|
20
|
+
export { MemoryStorageDriver } from './storage/driver.js';
|
|
21
|
+
export { RealtimeEngine } from './realtime/engine.js';
|
|
22
|
+
export { signJwt, verifyJwt, decodeJwt } from './jwt.js';
|
|
23
|
+
const CORS_HEADERS = {
|
|
24
|
+
'access-control-allow-origin': '*',
|
|
25
|
+
'access-control-allow-methods': 'GET, POST, PUT, PATCH, DELETE, OPTIONS, HEAD',
|
|
26
|
+
'access-control-allow-headers': 'authorization, apikey, content-type, prefer, accept, accept-profile, content-profile, range, x-upsert, x-client-info, x-supabase-api-version, cache-control',
|
|
27
|
+
'access-control-expose-headers': 'content-range, range-unit, content-profile',
|
|
28
|
+
'access-control-max-age': '86400',
|
|
29
|
+
};
|
|
30
|
+
export async function createBackend(config = {}) {
|
|
31
|
+
const jwtSecret = config.jwtSecret ?? DEFAULT_JWT_SECRET;
|
|
32
|
+
const siteUrl = config.siteUrl ?? 'http://localhost:54321';
|
|
33
|
+
const jwtExpiry = config.jwtExpiry ?? 3600;
|
|
34
|
+
const db = await Database.create(config.engine ?? config.dataDir);
|
|
35
|
+
if (config.migrations?.length || config.seedSql) {
|
|
36
|
+
const applied = await db.runMigrations(config.migrations ?? [], config.seedSql);
|
|
37
|
+
if (applied.length > 0)
|
|
38
|
+
config.log?.(`applied migrations: ${applied.join(', ')}`);
|
|
39
|
+
}
|
|
40
|
+
const now = Math.floor(Date.now() / 1000);
|
|
41
|
+
const tenYears = 10 * 365 * 24 * 3600;
|
|
42
|
+
const anonKey = await signJwt({ iss: 'supabase', ref: 'tinbase', role: 'anon', iat: now, exp: now + tenYears }, jwtSecret);
|
|
43
|
+
const serviceRoleKey = await signJwt({ iss: 'supabase', ref: 'tinbase', role: 'service_role', iat: now, exp: now + tenYears }, jwtSecret);
|
|
44
|
+
const rest = new RestHandler(db);
|
|
45
|
+
const auth = new AuthHandler(db, { jwtSecret, siteUrl, jwtExpiry });
|
|
46
|
+
const storage = new StorageHandler(db, config.storageDriver ?? new MemoryStorageDriver(), { jwtSecret });
|
|
47
|
+
const realtime = new RealtimeEngine(db);
|
|
48
|
+
await realtime.start();
|
|
49
|
+
async function resolveContext(req, url) {
|
|
50
|
+
const authz = req.headers.get('authorization');
|
|
51
|
+
const bearer = authz?.toLowerCase().startsWith('bearer ') ? authz.slice(7) : null;
|
|
52
|
+
const token = bearer ?? req.headers.get('apikey') ?? url.searchParams.get('apikey');
|
|
53
|
+
if (!token) {
|
|
54
|
+
return withCors(new Response(JSON.stringify({ message: 'No API key found in request', hint: 'No `apikey` request header or url param was found.' }), {
|
|
55
|
+
status: 401,
|
|
56
|
+
headers: { 'content-type': 'application/json' },
|
|
57
|
+
}));
|
|
58
|
+
}
|
|
59
|
+
const claims = await verifyJwt(token, jwtSecret);
|
|
60
|
+
if (!claims) {
|
|
61
|
+
return withCors(new Response(JSON.stringify({ message: 'Invalid API key' }), {
|
|
62
|
+
status: 401,
|
|
63
|
+
headers: { 'content-type': 'application/json' },
|
|
64
|
+
}));
|
|
65
|
+
}
|
|
66
|
+
const role = typeof claims.role === 'string' ? claims.role : 'anon';
|
|
67
|
+
if (!['anon', 'authenticated', 'service_role'].includes(role)) {
|
|
68
|
+
return withCors(new Response(JSON.stringify({ message: `Invalid role: ${role}` }), {
|
|
69
|
+
status: 401,
|
|
70
|
+
headers: { 'content-type': 'application/json' },
|
|
71
|
+
}));
|
|
72
|
+
}
|
|
73
|
+
return { role, claims };
|
|
74
|
+
}
|
|
75
|
+
async function handle(req) {
|
|
76
|
+
const url = new URL(req.url);
|
|
77
|
+
const path = url.pathname;
|
|
78
|
+
if (req.method === 'OPTIONS') {
|
|
79
|
+
return new Response(null, { status: 204, headers: CORS_HEADERS });
|
|
80
|
+
}
|
|
81
|
+
if (path === '/' || path === '/health') {
|
|
82
|
+
return withCors(new Response(JSON.stringify({ name: 'tinbase', status: 'healthy' }), {
|
|
83
|
+
status: 200,
|
|
84
|
+
headers: { 'content-type': 'application/json' },
|
|
85
|
+
}));
|
|
86
|
+
}
|
|
87
|
+
// public endpoints that skip apikey checks
|
|
88
|
+
if (path.startsWith('/storage/v1/object/public/') || path.startsWith('/storage/v1/object/sign/')) {
|
|
89
|
+
if (req.method === 'GET' || req.method === 'HEAD') {
|
|
90
|
+
return withCors(await storage.handle(req, { role: 'anon', claims: null }, url));
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
if (path.startsWith('/auth/v1/')) {
|
|
94
|
+
// GoTrue validates the apikey header, but user JWTs ride Authorization
|
|
95
|
+
const apikey = req.headers.get('apikey') ?? url.searchParams.get('apikey');
|
|
96
|
+
if (!apikey || !(await verifyJwt(apikey, jwtSecret))) {
|
|
97
|
+
return withCors(new Response(JSON.stringify({ message: 'No API key found in request' }), {
|
|
98
|
+
status: 401,
|
|
99
|
+
headers: { 'content-type': 'application/json' },
|
|
100
|
+
}));
|
|
101
|
+
}
|
|
102
|
+
const keyClaims = await verifyJwt(apikey, jwtSecret);
|
|
103
|
+
const ctx = { role: String(keyClaims?.role ?? 'anon'), claims: keyClaims };
|
|
104
|
+
return withCors(await auth.handle(req, ctx, url));
|
|
105
|
+
}
|
|
106
|
+
const ctx = await resolveContext(req, url);
|
|
107
|
+
if (ctx instanceof Response)
|
|
108
|
+
return ctx;
|
|
109
|
+
if (path.startsWith('/rest/v1'))
|
|
110
|
+
return withCors(await rest.handle(req, ctx, url));
|
|
111
|
+
if (path.startsWith('/storage/v1'))
|
|
112
|
+
return withCors(await storage.handle(req, ctx, url));
|
|
113
|
+
if (path.startsWith('/realtime/v1')) {
|
|
114
|
+
return withCors(new Response(JSON.stringify({ message: 'Realtime requires a WebSocket connection' }), {
|
|
115
|
+
status: 426,
|
|
116
|
+
headers: { 'content-type': 'application/json' },
|
|
117
|
+
}));
|
|
118
|
+
}
|
|
119
|
+
return withCors(new Response(JSON.stringify({ message: `Unknown endpoint: ${path}` }), {
|
|
120
|
+
status: 404,
|
|
121
|
+
headers: { 'content-type': 'application/json' },
|
|
122
|
+
}));
|
|
123
|
+
}
|
|
124
|
+
return {
|
|
125
|
+
fetch: handle,
|
|
126
|
+
db,
|
|
127
|
+
realtime,
|
|
128
|
+
anonKey,
|
|
129
|
+
serviceRoleKey,
|
|
130
|
+
jwtSecret,
|
|
131
|
+
migrate: (migrations, seedSql) => db.runMigrations(migrations, seedSql),
|
|
132
|
+
close: async () => {
|
|
133
|
+
realtime.stop();
|
|
134
|
+
await db.close();
|
|
135
|
+
},
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
function withCors(res) {
|
|
139
|
+
for (const [k, v] of Object.entries(CORS_HEADERS)) {
|
|
140
|
+
if (!res.headers.has(k))
|
|
141
|
+
res.headers.set(k, v);
|
|
142
|
+
}
|
|
143
|
+
return res;
|
|
144
|
+
}
|
|
145
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/jwt.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal HS256 JWT implementation on WebCrypto.
|
|
3
|
+
* Works in Node (>=18) and browsers — no dependencies.
|
|
4
|
+
*/
|
|
5
|
+
export interface JwtClaims {
|
|
6
|
+
[key: string]: unknown;
|
|
7
|
+
sub?: string;
|
|
8
|
+
role?: string;
|
|
9
|
+
exp?: number;
|
|
10
|
+
iat?: number;
|
|
11
|
+
iss?: string;
|
|
12
|
+
aud?: string;
|
|
13
|
+
email?: string;
|
|
14
|
+
}
|
|
15
|
+
export declare function signJwt(claims: JwtClaims, secret: string): Promise<string>;
|
|
16
|
+
/** Verifies signature and expiry. Returns claims, or null when invalid. */
|
|
17
|
+
export declare function verifyJwt(token: string, secret: string): Promise<JwtClaims | null>;
|
|
18
|
+
/** Decode without verification (for introspection/debugging only). */
|
|
19
|
+
export declare function decodeJwt(token: string): JwtClaims | null;
|
|
20
|
+
export declare function randomToken(bytes?: number): string;
|