@flightdev/db 0.0.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/.turbo/turbo-build.log +26 -0
- package/.turbo/turbo-typecheck.log +4 -0
- package/CHANGELOG.md +7 -0
- package/LICENSE +21 -0
- package/README.md +226 -0
- package/dist/d1.d.ts +60 -0
- package/dist/d1.js +97 -0
- package/dist/index.d.ts +87 -0
- package/dist/index.js +19 -0
- package/dist/neon.d.ts +32 -0
- package/dist/neon.js +117 -0
- package/dist/postgres.d.ts +38 -0
- package/dist/postgres.js +99 -0
- package/dist/supabase.d.ts +42 -0
- package/dist/supabase.js +76 -0
- package/dist/turso.d.ts +39 -0
- package/dist/turso.js +102 -0
- package/package.json +76 -0
- package/src/ambient.d.ts +154 -0
- package/src/d1.ts +177 -0
- package/src/index.ts +140 -0
- package/src/neon.ts +164 -0
- package/src/postgres.ts +145 -0
- package/src/supabase.ts +136 -0
- package/src/turso.ts +150 -0
- package/tsconfig.json +17 -0
- package/tsup.config.ts +26 -0
package/src/supabase.ts
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @flightdev/db/supabase - Supabase Database Driver
|
|
3
|
+
*
|
|
4
|
+
* Uses @supabase/supabase-js for Supabase PostgreSQL.
|
|
5
|
+
* Includes RLS (Row Level Security) support out of the box.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```typescript
|
|
9
|
+
* import { supabase } from '@flightdev/db/supabase';
|
|
10
|
+
* import { createDb } from '@flightdev/db';
|
|
11
|
+
*
|
|
12
|
+
* const db = createDb(supabase({
|
|
13
|
+
* url: process.env.SUPABASE_URL,
|
|
14
|
+
* key: process.env.SUPABASE_ANON_KEY, // or SERVICE_ROLE_KEY for admin
|
|
15
|
+
* }));
|
|
16
|
+
*
|
|
17
|
+
* // Use Supabase's query builder
|
|
18
|
+
* const { data, error } = await db.from('users').select('*');
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
import type { DatabaseDriver, QueryResult, ExecuteResult, Transaction } from './index.js';
|
|
23
|
+
|
|
24
|
+
export interface SupabaseConfig {
|
|
25
|
+
/** Supabase project URL */
|
|
26
|
+
url: string;
|
|
27
|
+
/** Supabase API key (anon or service_role) */
|
|
28
|
+
key: string;
|
|
29
|
+
/** Optional schema (default: public) */
|
|
30
|
+
schema?: string;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Create a Supabase driver
|
|
35
|
+
*/
|
|
36
|
+
export function supabase(config: SupabaseConfig): DatabaseDriver & {
|
|
37
|
+
/** Access Supabase client directly for advanced features */
|
|
38
|
+
readonly client: any;
|
|
39
|
+
/** Query builder (Supabase style) */
|
|
40
|
+
from: (table: string) => any;
|
|
41
|
+
} {
|
|
42
|
+
let client: any = null;
|
|
43
|
+
|
|
44
|
+
async function getClient() {
|
|
45
|
+
if (!client) {
|
|
46
|
+
const { createClient } = await import('@supabase/supabase-js');
|
|
47
|
+
client = createClient(config.url, config.key, {
|
|
48
|
+
db: { schema: config.schema ?? 'public' },
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
return client;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const driver = {
|
|
55
|
+
name: 'supabase',
|
|
56
|
+
|
|
57
|
+
get client() {
|
|
58
|
+
return client;
|
|
59
|
+
},
|
|
60
|
+
|
|
61
|
+
async from(table: string) {
|
|
62
|
+
const c = await getClient();
|
|
63
|
+
return c.from(table);
|
|
64
|
+
},
|
|
65
|
+
|
|
66
|
+
async query<T = Record<string, unknown>>(sql: string, params?: unknown[]): Promise<QueryResult<T>> {
|
|
67
|
+
const c = await getClient();
|
|
68
|
+
|
|
69
|
+
// Use Supabase's RPC for raw SQL
|
|
70
|
+
// Note: This requires creating an RPC function in Supabase
|
|
71
|
+
// For simpler cases, use the query builder via .from()
|
|
72
|
+
const { data, error } = await c.rpc('flight_raw_query', {
|
|
73
|
+
query_text: sql,
|
|
74
|
+
query_params: params ?? [],
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
if (error) {
|
|
78
|
+
throw new Error(`Supabase query error: ${error.message}`);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return {
|
|
82
|
+
rows: (data ?? []) as T[],
|
|
83
|
+
rowCount: data?.length ?? 0,
|
|
84
|
+
raw: { data, error },
|
|
85
|
+
};
|
|
86
|
+
},
|
|
87
|
+
|
|
88
|
+
async execute(sql: string, params?: unknown[]): Promise<ExecuteResult> {
|
|
89
|
+
const c = await getClient();
|
|
90
|
+
|
|
91
|
+
const { data, error } = await c.rpc('flight_raw_execute', {
|
|
92
|
+
query_text: sql,
|
|
93
|
+
query_params: params ?? [],
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
if (error) {
|
|
97
|
+
throw new Error(`Supabase execute error: ${error.message}`);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return {
|
|
101
|
+
rowsAffected: data?.affected_rows ?? 0,
|
|
102
|
+
insertId: data?.insert_id,
|
|
103
|
+
raw: { data, error },
|
|
104
|
+
};
|
|
105
|
+
},
|
|
106
|
+
|
|
107
|
+
async transaction<T>(_fn: (tx: Transaction) => Promise<T>): Promise<T> {
|
|
108
|
+
// Supabase doesn't support client-side transactions
|
|
109
|
+
// Use RPC functions with SECURITY DEFINER for transactional logic
|
|
110
|
+
throw new Error(
|
|
111
|
+
'Supabase does not support client-side transactions. ' +
|
|
112
|
+
'Use RPC functions with SECURITY DEFINER for transactional operations.'
|
|
113
|
+
);
|
|
114
|
+
},
|
|
115
|
+
|
|
116
|
+
async close(): Promise<void> {
|
|
117
|
+
// Supabase client doesn't need explicit closing
|
|
118
|
+
client = null;
|
|
119
|
+
},
|
|
120
|
+
|
|
121
|
+
async ping(): Promise<boolean> {
|
|
122
|
+
try {
|
|
123
|
+
const c = await getClient();
|
|
124
|
+
const { error } = await c.from('_flight_ping').select('1').limit(1);
|
|
125
|
+
// Table might not exist, but connection works if no network error
|
|
126
|
+
return !error || error.code === 'PGRST116'; // 42P01 = table not found
|
|
127
|
+
} catch {
|
|
128
|
+
return false;
|
|
129
|
+
}
|
|
130
|
+
},
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
return driver;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
export default supabase;
|
package/src/turso.ts
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @flightdev/db/turso - Turso/SQLite Driver
|
|
3
|
+
*
|
|
4
|
+
* Uses @libsql/client for Turso cloud and local SQLite.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```typescript
|
|
8
|
+
* import { turso } from '@flightdev/db/turso';
|
|
9
|
+
* import { createDb } from '@flightdev/db';
|
|
10
|
+
*
|
|
11
|
+
* // Turso Cloud
|
|
12
|
+
* const db = createDb(turso({
|
|
13
|
+
* url: 'libsql://your-db.turso.io',
|
|
14
|
+
* authToken: process.env.TURSO_AUTH_TOKEN,
|
|
15
|
+
* }));
|
|
16
|
+
*
|
|
17
|
+
* // Local SQLite
|
|
18
|
+
* const localDb = createDb(turso({
|
|
19
|
+
* url: 'file:local.db',
|
|
20
|
+
* }));
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
import type { DatabaseDriver, QueryResult, ExecuteResult, Transaction } from './index.js';
|
|
25
|
+
|
|
26
|
+
export interface TursoConfig {
|
|
27
|
+
/** Database URL (libsql://... or file:...) */
|
|
28
|
+
url: string;
|
|
29
|
+
/** Auth token for Turso cloud */
|
|
30
|
+
authToken?: string;
|
|
31
|
+
/** Sync URL for embedded replicas */
|
|
32
|
+
syncUrl?: string;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Create a Turso/SQLite driver
|
|
37
|
+
*/
|
|
38
|
+
export function turso(config: TursoConfig): DatabaseDriver {
|
|
39
|
+
let client: any = null;
|
|
40
|
+
|
|
41
|
+
async function getClient() {
|
|
42
|
+
if (!client) {
|
|
43
|
+
const { createClient } = await import('@libsql/client');
|
|
44
|
+
client = createClient({
|
|
45
|
+
url: config.url,
|
|
46
|
+
authToken: config.authToken,
|
|
47
|
+
syncUrl: config.syncUrl,
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
return client;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return {
|
|
54
|
+
name: 'turso',
|
|
55
|
+
|
|
56
|
+
async query<T = Record<string, unknown>>(sql: string, params?: unknown[]): Promise<QueryResult<T>> {
|
|
57
|
+
const c = await getClient();
|
|
58
|
+
const result = await c.execute({ sql, args: params ?? [] });
|
|
59
|
+
|
|
60
|
+
// Convert libsql rows to plain objects
|
|
61
|
+
const rows = result.rows.map((row: any) => {
|
|
62
|
+
const obj: Record<string, unknown> = {};
|
|
63
|
+
for (const [key, value] of Object.entries(row)) {
|
|
64
|
+
obj[key] = value;
|
|
65
|
+
}
|
|
66
|
+
return obj;
|
|
67
|
+
}) as T[];
|
|
68
|
+
|
|
69
|
+
return {
|
|
70
|
+
rows,
|
|
71
|
+
rowCount: result.rows.length,
|
|
72
|
+
raw: result,
|
|
73
|
+
};
|
|
74
|
+
},
|
|
75
|
+
|
|
76
|
+
async execute(sql: string, params?: unknown[]): Promise<ExecuteResult> {
|
|
77
|
+
const c = await getClient();
|
|
78
|
+
const result = await c.execute({ sql, args: params ?? [] });
|
|
79
|
+
return {
|
|
80
|
+
rowsAffected: result.rowsAffected,
|
|
81
|
+
insertId: result.lastInsertRowid ? Number(result.lastInsertRowid) : undefined,
|
|
82
|
+
raw: result,
|
|
83
|
+
};
|
|
84
|
+
},
|
|
85
|
+
|
|
86
|
+
async transaction<T>(fn: (tx: Transaction) => Promise<T>): Promise<T> {
|
|
87
|
+
const c = await getClient();
|
|
88
|
+
const libsqlTx = await c.transaction('write');
|
|
89
|
+
|
|
90
|
+
try {
|
|
91
|
+
const tx: Transaction = {
|
|
92
|
+
async query<R = Record<string, unknown>>(sql: string, params?: unknown[]): Promise<QueryResult<R>> {
|
|
93
|
+
const result = await libsqlTx.execute({ sql, args: params ?? [] });
|
|
94
|
+
const rows = result.rows.map((row: any) => {
|
|
95
|
+
const obj: Record<string, unknown> = {};
|
|
96
|
+
for (const [key, value] of Object.entries(row)) {
|
|
97
|
+
obj[key] = value;
|
|
98
|
+
}
|
|
99
|
+
return obj;
|
|
100
|
+
}) as R[];
|
|
101
|
+
return { rows, rowCount: result.rows.length, raw: result };
|
|
102
|
+
},
|
|
103
|
+
|
|
104
|
+
async execute(sql: string, params?: unknown[]): Promise<ExecuteResult> {
|
|
105
|
+
const result = await libsqlTx.execute({ sql, args: params ?? [] });
|
|
106
|
+
return {
|
|
107
|
+
rowsAffected: result.rowsAffected,
|
|
108
|
+
insertId: result.lastInsertRowid ? Number(result.lastInsertRowid) : undefined,
|
|
109
|
+
raw: result,
|
|
110
|
+
};
|
|
111
|
+
},
|
|
112
|
+
|
|
113
|
+
async commit() {
|
|
114
|
+
await libsqlTx.commit();
|
|
115
|
+
},
|
|
116
|
+
|
|
117
|
+
async rollback() {
|
|
118
|
+
await libsqlTx.rollback();
|
|
119
|
+
},
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
const result = await fn(tx);
|
|
123
|
+
await libsqlTx.commit();
|
|
124
|
+
return result;
|
|
125
|
+
} catch (error) {
|
|
126
|
+
await libsqlTx.rollback();
|
|
127
|
+
throw error;
|
|
128
|
+
}
|
|
129
|
+
},
|
|
130
|
+
|
|
131
|
+
async close(): Promise<void> {
|
|
132
|
+
if (client) {
|
|
133
|
+
client.close();
|
|
134
|
+
client = null;
|
|
135
|
+
}
|
|
136
|
+
},
|
|
137
|
+
|
|
138
|
+
async ping(): Promise<boolean> {
|
|
139
|
+
try {
|
|
140
|
+
const c = await getClient();
|
|
141
|
+
await c.execute('SELECT 1');
|
|
142
|
+
return true;
|
|
143
|
+
} catch {
|
|
144
|
+
return false;
|
|
145
|
+
}
|
|
146
|
+
},
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
export default turso;
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "../../tsconfig.json",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"outDir": "dist",
|
|
5
|
+
"rootDir": "src",
|
|
6
|
+
"noEmit": false,
|
|
7
|
+
"noUnusedLocals": false,
|
|
8
|
+
"noUnusedParameters": false
|
|
9
|
+
},
|
|
10
|
+
"include": [
|
|
11
|
+
"src/**/*"
|
|
12
|
+
],
|
|
13
|
+
"exclude": [
|
|
14
|
+
"node_modules",
|
|
15
|
+
"dist"
|
|
16
|
+
]
|
|
17
|
+
}
|
package/tsup.config.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { defineConfig } from 'tsup';
|
|
2
|
+
|
|
3
|
+
export default defineConfig({
|
|
4
|
+
entry: [
|
|
5
|
+
'src/index.ts',
|
|
6
|
+
'src/postgres.ts',
|
|
7
|
+
'src/supabase.ts',
|
|
8
|
+
'src/turso.ts',
|
|
9
|
+
'src/neon.ts',
|
|
10
|
+
'src/d1.ts',
|
|
11
|
+
],
|
|
12
|
+
format: ['esm'],
|
|
13
|
+
dts: {
|
|
14
|
+
compilerOptions: {
|
|
15
|
+
skipLibCheck: true,
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
clean: true,
|
|
19
|
+
target: 'node20',
|
|
20
|
+
external: [
|
|
21
|
+
'pg',
|
|
22
|
+
'@supabase/supabase-js',
|
|
23
|
+
'@libsql/client',
|
|
24
|
+
'@neondatabase/serverless',
|
|
25
|
+
],
|
|
26
|
+
});
|