@tursodatabase/serverless 1.1.1 → 1.1.2-pre.1
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/dist/compat/index.cjs +885 -0
- package/dist/{compat.d.ts → compat/index.d.cts} +13 -11
- package/dist/compat/index.d.ts +147 -1
- package/dist/compat/index.js +882 -1
- package/dist/index.cjs +1064 -0
- package/dist/index.d.cts +516 -0
- package/dist/index.d.ts +516 -5
- package/dist/index.js +1056 -6
- package/package.json +26 -10
- package/dist/async-lock.d.ts +0 -6
- package/dist/async-lock.js +0 -22
- package/dist/compat.js +0 -395
- package/dist/connection.d.ts +0 -197
- package/dist/connection.js +0 -312
- package/dist/error.d.ts +0 -19
- package/dist/error.js +0 -24
- package/dist/protocol.d.ts +0 -120
- package/dist/protocol.js +0 -206
- package/dist/session.d.ts +0 -93
- package/dist/session.js +0 -341
- package/dist/statement.d.ts +0 -161
- package/dist/statement.js +0 -308
package/package.json
CHANGED
|
@@ -1,26 +1,41 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tursodatabase/serverless",
|
|
3
|
-
"version": "1.1.1",
|
|
3
|
+
"version": "1.1.2-pre.1",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"main": "dist/index.
|
|
6
|
-
"
|
|
5
|
+
"main": "./dist/index.cjs",
|
|
6
|
+
"module": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
7
8
|
"files": [
|
|
8
9
|
"dist",
|
|
9
10
|
"README.md"
|
|
10
11
|
],
|
|
11
12
|
"exports": {
|
|
12
13
|
".": {
|
|
13
|
-
"import":
|
|
14
|
-
|
|
14
|
+
"import": {
|
|
15
|
+
"types": "./dist/index.d.ts",
|
|
16
|
+
"default": "./dist/index.js"
|
|
17
|
+
},
|
|
18
|
+
"require": {
|
|
19
|
+
"types": "./dist/index.d.cts",
|
|
20
|
+
"default": "./dist/index.cjs"
|
|
21
|
+
}
|
|
15
22
|
},
|
|
16
23
|
"./compat": {
|
|
17
|
-
"import":
|
|
18
|
-
|
|
19
|
-
|
|
24
|
+
"import": {
|
|
25
|
+
"types": "./dist/compat/index.d.ts",
|
|
26
|
+
"default": "./dist/compat/index.js"
|
|
27
|
+
},
|
|
28
|
+
"require": {
|
|
29
|
+
"types": "./dist/compat/index.d.cts",
|
|
30
|
+
"default": "./dist/compat/index.cjs"
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
"./package.json": "./package.json"
|
|
20
34
|
},
|
|
21
35
|
"scripts": {
|
|
22
|
-
"build": "
|
|
23
|
-
"
|
|
36
|
+
"build": "tsup",
|
|
37
|
+
"clean": "rm -rf dist",
|
|
38
|
+
"dev": "tsup --watch",
|
|
24
39
|
"test": "ava integration-tests/*.test.mjs"
|
|
25
40
|
},
|
|
26
41
|
"keywords": [],
|
|
@@ -30,6 +45,7 @@
|
|
|
30
45
|
"devDependencies": {
|
|
31
46
|
"@types/node": "^24.0.13",
|
|
32
47
|
"ava": "^6.4.1",
|
|
48
|
+
"tsup": "^8.5.1",
|
|
33
49
|
"typescript": "^5.9.2"
|
|
34
50
|
}
|
|
35
51
|
}
|
package/dist/async-lock.d.ts
DELETED
package/dist/async-lock.js
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
export class AsyncLock {
|
|
2
|
-
constructor() {
|
|
3
|
-
this.locked = false;
|
|
4
|
-
this.queue = [];
|
|
5
|
-
}
|
|
6
|
-
async acquire() {
|
|
7
|
-
if (!this.locked) {
|
|
8
|
-
this.locked = true;
|
|
9
|
-
return;
|
|
10
|
-
}
|
|
11
|
-
return new Promise(resolve => { this.queue.push(resolve); });
|
|
12
|
-
}
|
|
13
|
-
release() {
|
|
14
|
-
const next = this.queue.shift();
|
|
15
|
-
if (next) {
|
|
16
|
-
next();
|
|
17
|
-
}
|
|
18
|
-
else {
|
|
19
|
-
this.locked = false;
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
}
|
package/dist/compat.js
DELETED
|
@@ -1,395 +0,0 @@
|
|
|
1
|
-
import { Session } from './session.js';
|
|
2
|
-
import { AsyncLock } from './async-lock.js';
|
|
3
|
-
import { DatabaseError } from './error.js';
|
|
4
|
-
/**
|
|
5
|
-
* libSQL-compatible error class with error codes.
|
|
6
|
-
*/
|
|
7
|
-
export class LibsqlError extends Error {
|
|
8
|
-
constructor(message, code, extendedCode, rawCode, cause) {
|
|
9
|
-
super(message);
|
|
10
|
-
this.name = 'LibsqlError';
|
|
11
|
-
this.code = code;
|
|
12
|
-
this.extendedCode = extendedCode;
|
|
13
|
-
this.rawCode = rawCode;
|
|
14
|
-
this.cause = cause;
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
class LibSQLClient {
|
|
18
|
-
constructor(config) {
|
|
19
|
-
this.execLock = new AsyncLock();
|
|
20
|
-
this._closed = false;
|
|
21
|
-
this._defaultSafeIntegers = false;
|
|
22
|
-
this.validateConfig(config);
|
|
23
|
-
const sessionConfig = {
|
|
24
|
-
url: config.url,
|
|
25
|
-
authToken: config.authToken || '',
|
|
26
|
-
remoteEncryptionKey: config.remoteEncryptionKey
|
|
27
|
-
};
|
|
28
|
-
this.sessionConfig = sessionConfig;
|
|
29
|
-
this.session = new Session(sessionConfig);
|
|
30
|
-
}
|
|
31
|
-
validateConfig(config) {
|
|
32
|
-
// Check for unsupported config options
|
|
33
|
-
const unsupportedOptions = [];
|
|
34
|
-
if (config.encryptionKey !== undefined) {
|
|
35
|
-
unsupportedOptions.push({ key: 'encryptionKey', value: config.encryptionKey });
|
|
36
|
-
}
|
|
37
|
-
if (config.syncUrl !== undefined) {
|
|
38
|
-
unsupportedOptions.push({ key: 'syncUrl', value: config.syncUrl });
|
|
39
|
-
}
|
|
40
|
-
if (config.syncInterval !== undefined) {
|
|
41
|
-
unsupportedOptions.push({ key: 'syncInterval', value: config.syncInterval });
|
|
42
|
-
}
|
|
43
|
-
if (config.readYourWrites !== undefined) {
|
|
44
|
-
unsupportedOptions.push({ key: 'readYourWrites', value: config.readYourWrites });
|
|
45
|
-
}
|
|
46
|
-
if (config.offline !== undefined) {
|
|
47
|
-
unsupportedOptions.push({ key: 'offline', value: config.offline });
|
|
48
|
-
}
|
|
49
|
-
if (config.tls !== undefined) {
|
|
50
|
-
unsupportedOptions.push({ key: 'tls', value: config.tls });
|
|
51
|
-
}
|
|
52
|
-
if (config.intMode !== undefined) {
|
|
53
|
-
unsupportedOptions.push({ key: 'intMode', value: config.intMode });
|
|
54
|
-
}
|
|
55
|
-
if (config.fetch !== undefined) {
|
|
56
|
-
unsupportedOptions.push({ key: 'fetch', value: config.fetch });
|
|
57
|
-
}
|
|
58
|
-
if (config.concurrency !== undefined) {
|
|
59
|
-
unsupportedOptions.push({ key: 'concurrency', value: config.concurrency });
|
|
60
|
-
}
|
|
61
|
-
if (unsupportedOptions.length > 0) {
|
|
62
|
-
const optionsList = unsupportedOptions.map(opt => `'${opt.key}'`).join(', ');
|
|
63
|
-
throw new LibsqlError(`Unsupported configuration options: ${optionsList}. Only 'url', 'authToken', and 'remoteEncryptionKey' are supported in the serverless compatibility layer.`, "UNSUPPORTED_CONFIG");
|
|
64
|
-
}
|
|
65
|
-
// Validate required options
|
|
66
|
-
if (!config.url) {
|
|
67
|
-
throw new LibsqlError("Missing required 'url' configuration option", "MISSING_URL");
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
get closed() {
|
|
71
|
-
return this._closed;
|
|
72
|
-
}
|
|
73
|
-
get protocol() {
|
|
74
|
-
return "http";
|
|
75
|
-
}
|
|
76
|
-
normalizeStatement(stmt) {
|
|
77
|
-
if (typeof stmt === 'string') {
|
|
78
|
-
return { sql: stmt, args: [] };
|
|
79
|
-
}
|
|
80
|
-
const args = stmt.args || [];
|
|
81
|
-
if (Array.isArray(args)) {
|
|
82
|
-
return { sql: stmt.sql, args };
|
|
83
|
-
}
|
|
84
|
-
// Convert named args to positional args (simplified)
|
|
85
|
-
return { sql: stmt.sql, args: Object.values(args) };
|
|
86
|
-
}
|
|
87
|
-
convertResult(result) {
|
|
88
|
-
const resultSet = {
|
|
89
|
-
columns: result.columns || [],
|
|
90
|
-
columnTypes: result.columnTypes || [],
|
|
91
|
-
rows: result.rows || [],
|
|
92
|
-
rowsAffected: result.rowsAffected || 0,
|
|
93
|
-
lastInsertRowid: result.lastInsertRowid ? BigInt(result.lastInsertRowid) : undefined,
|
|
94
|
-
toJSON() {
|
|
95
|
-
return {
|
|
96
|
-
columns: this.columns,
|
|
97
|
-
columnTypes: this.columnTypes,
|
|
98
|
-
rows: this.rows,
|
|
99
|
-
rowsAffected: this.rowsAffected,
|
|
100
|
-
lastInsertRowid: this.lastInsertRowid?.toString()
|
|
101
|
-
};
|
|
102
|
-
}
|
|
103
|
-
};
|
|
104
|
-
return resultSet;
|
|
105
|
-
}
|
|
106
|
-
async execute(stmtOrSql, args) {
|
|
107
|
-
await this.execLock.acquire();
|
|
108
|
-
try {
|
|
109
|
-
if (this._closed) {
|
|
110
|
-
throw new LibsqlError("Client is closed", "CLIENT_CLOSED");
|
|
111
|
-
}
|
|
112
|
-
let normalizedStmt;
|
|
113
|
-
if (typeof stmtOrSql === 'string') {
|
|
114
|
-
const normalizedArgs = args ? (Array.isArray(args) ? args : Object.values(args)) : [];
|
|
115
|
-
normalizedStmt = { sql: stmtOrSql, args: normalizedArgs };
|
|
116
|
-
}
|
|
117
|
-
else {
|
|
118
|
-
normalizedStmt = this.normalizeStatement(stmtOrSql);
|
|
119
|
-
}
|
|
120
|
-
const result = await this.session.execute(normalizedStmt.sql, normalizedStmt.args, this._defaultSafeIntegers);
|
|
121
|
-
return this.convertResult(result);
|
|
122
|
-
}
|
|
123
|
-
catch (error) {
|
|
124
|
-
if (error instanceof LibsqlError) {
|
|
125
|
-
throw error;
|
|
126
|
-
}
|
|
127
|
-
throw mapDatabaseError(error, "EXECUTE_ERROR");
|
|
128
|
-
}
|
|
129
|
-
finally {
|
|
130
|
-
this.execLock.release();
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
async batch(stmts, mode) {
|
|
134
|
-
await this.execLock.acquire();
|
|
135
|
-
try {
|
|
136
|
-
if (this._closed) {
|
|
137
|
-
throw new LibsqlError("Client is closed", "CLIENT_CLOSED");
|
|
138
|
-
}
|
|
139
|
-
const sqlStatements = stmts.map(stmt => {
|
|
140
|
-
const normalized = this.normalizeStatement(stmt);
|
|
141
|
-
return normalized.sql; // For now, ignore args in batch
|
|
142
|
-
});
|
|
143
|
-
const result = await this.session.batch(sqlStatements);
|
|
144
|
-
// Return array of result sets (simplified - actual implementation would be more complex)
|
|
145
|
-
return [this.convertResult(result)];
|
|
146
|
-
}
|
|
147
|
-
catch (error) {
|
|
148
|
-
if (error instanceof LibsqlError) {
|
|
149
|
-
throw error;
|
|
150
|
-
}
|
|
151
|
-
throw mapDatabaseError(error, "BATCH_ERROR");
|
|
152
|
-
}
|
|
153
|
-
finally {
|
|
154
|
-
this.execLock.release();
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
async migrate(stmts) {
|
|
158
|
-
// For now, just call batch - in a real implementation this would disable foreign keys
|
|
159
|
-
return this.batch(stmts, "write");
|
|
160
|
-
}
|
|
161
|
-
modeToBeginSql(mode) {
|
|
162
|
-
switch (mode) {
|
|
163
|
-
case "write":
|
|
164
|
-
return "BEGIN IMMEDIATE";
|
|
165
|
-
case "deferred":
|
|
166
|
-
return "BEGIN DEFERRED";
|
|
167
|
-
case "read":
|
|
168
|
-
default:
|
|
169
|
-
return "BEGIN";
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
async transaction(mode) {
|
|
173
|
-
await this.execLock.acquire();
|
|
174
|
-
if (this._closed) {
|
|
175
|
-
this.execLock.release();
|
|
176
|
-
throw new LibsqlError("Client is closed", "CLIENT_CLOSED");
|
|
177
|
-
}
|
|
178
|
-
const txSession = new Session(this.sessionConfig);
|
|
179
|
-
let txClosed = false;
|
|
180
|
-
let cleanupStarted = false;
|
|
181
|
-
const ensureOpen = () => {
|
|
182
|
-
if (txClosed) {
|
|
183
|
-
throw new LibsqlError("Transaction is closed", "TRANSACTION_CLOSED");
|
|
184
|
-
}
|
|
185
|
-
};
|
|
186
|
-
const closeTx = async () => {
|
|
187
|
-
if (cleanupStarted)
|
|
188
|
-
return;
|
|
189
|
-
cleanupStarted = true;
|
|
190
|
-
txClosed = true;
|
|
191
|
-
try {
|
|
192
|
-
await txSession.close();
|
|
193
|
-
}
|
|
194
|
-
finally {
|
|
195
|
-
this.execLock.release();
|
|
196
|
-
}
|
|
197
|
-
};
|
|
198
|
-
const executeInTx = async (stmt) => {
|
|
199
|
-
ensureOpen();
|
|
200
|
-
const normalized = this.normalizeStatement(stmt);
|
|
201
|
-
try {
|
|
202
|
-
const result = await txSession.execute(normalized.sql, normalized.args, this._defaultSafeIntegers);
|
|
203
|
-
return this.convertResult(result);
|
|
204
|
-
}
|
|
205
|
-
catch (error) {
|
|
206
|
-
throw mapDatabaseError(error, "EXECUTE_ERROR");
|
|
207
|
-
}
|
|
208
|
-
};
|
|
209
|
-
try {
|
|
210
|
-
await txSession.sequence(this.modeToBeginSql(mode));
|
|
211
|
-
}
|
|
212
|
-
catch (error) {
|
|
213
|
-
await closeTx();
|
|
214
|
-
throw mapDatabaseError(error, "BEGIN_ERROR");
|
|
215
|
-
}
|
|
216
|
-
return {
|
|
217
|
-
execute: async (stmtOrSql, args) => {
|
|
218
|
-
if (typeof stmtOrSql === "string") {
|
|
219
|
-
const normalizedArgs = args ? (Array.isArray(args) ? args : Object.values(args)) : [];
|
|
220
|
-
return executeInTx({ sql: stmtOrSql, args: normalizedArgs });
|
|
221
|
-
}
|
|
222
|
-
return executeInTx(stmtOrSql);
|
|
223
|
-
},
|
|
224
|
-
batch: async (stmts) => {
|
|
225
|
-
ensureOpen();
|
|
226
|
-
const results = [];
|
|
227
|
-
for (const stmt of stmts) {
|
|
228
|
-
results.push(await executeInTx(stmt));
|
|
229
|
-
}
|
|
230
|
-
return results;
|
|
231
|
-
},
|
|
232
|
-
executeMultiple: async (sql) => {
|
|
233
|
-
ensureOpen();
|
|
234
|
-
try {
|
|
235
|
-
await txSession.sequence(sql);
|
|
236
|
-
}
|
|
237
|
-
catch (error) {
|
|
238
|
-
throw mapDatabaseError(error, "EXECUTE_MULTIPLE_ERROR");
|
|
239
|
-
}
|
|
240
|
-
},
|
|
241
|
-
commit: async () => {
|
|
242
|
-
ensureOpen();
|
|
243
|
-
try {
|
|
244
|
-
await txSession.sequence("COMMIT");
|
|
245
|
-
}
|
|
246
|
-
catch (error) {
|
|
247
|
-
throw mapDatabaseError(error, "COMMIT_ERROR");
|
|
248
|
-
}
|
|
249
|
-
finally {
|
|
250
|
-
await closeTx();
|
|
251
|
-
}
|
|
252
|
-
},
|
|
253
|
-
rollback: async () => {
|
|
254
|
-
ensureOpen();
|
|
255
|
-
try {
|
|
256
|
-
await txSession.sequence("ROLLBACK");
|
|
257
|
-
}
|
|
258
|
-
catch (error) {
|
|
259
|
-
throw mapDatabaseError(error, "ROLLBACK_ERROR");
|
|
260
|
-
}
|
|
261
|
-
finally {
|
|
262
|
-
await closeTx();
|
|
263
|
-
}
|
|
264
|
-
},
|
|
265
|
-
close: () => {
|
|
266
|
-
if (txClosed)
|
|
267
|
-
return;
|
|
268
|
-
txClosed = true;
|
|
269
|
-
void txSession.sequence("ROLLBACK")
|
|
270
|
-
.catch(() => undefined)
|
|
271
|
-
.finally(() => {
|
|
272
|
-
void closeTx();
|
|
273
|
-
});
|
|
274
|
-
},
|
|
275
|
-
get closed() {
|
|
276
|
-
return txClosed;
|
|
277
|
-
},
|
|
278
|
-
};
|
|
279
|
-
}
|
|
280
|
-
async executeMultiple(sql) {
|
|
281
|
-
await this.execLock.acquire();
|
|
282
|
-
try {
|
|
283
|
-
if (this._closed) {
|
|
284
|
-
throw new LibsqlError("Client is closed", "CLIENT_CLOSED");
|
|
285
|
-
}
|
|
286
|
-
await this.session.sequence(sql);
|
|
287
|
-
}
|
|
288
|
-
catch (error) {
|
|
289
|
-
if (error instanceof LibsqlError) {
|
|
290
|
-
throw error;
|
|
291
|
-
}
|
|
292
|
-
throw mapDatabaseError(error, "EXECUTE_MULTIPLE_ERROR");
|
|
293
|
-
}
|
|
294
|
-
finally {
|
|
295
|
-
this.execLock.release();
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
async sync() {
|
|
299
|
-
throw new LibsqlError("Sync not supported for remote databases", "NOT_SUPPORTED");
|
|
300
|
-
}
|
|
301
|
-
close() {
|
|
302
|
-
this._closed = true;
|
|
303
|
-
// Note: The libSQL client interface expects synchronous close,
|
|
304
|
-
// but our underlying session needs async close. We'll fire and forget.
|
|
305
|
-
this.session.close().catch(error => {
|
|
306
|
-
console.error('Error closing session:', error);
|
|
307
|
-
});
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
|
-
/**
|
|
311
|
-
* Create a libSQL-compatible client for Turso database access.
|
|
312
|
-
*
|
|
313
|
-
* This function provides compatibility with the standard libSQL client API
|
|
314
|
-
* while using the Turso serverless driver under the hood.
|
|
315
|
-
*
|
|
316
|
-
* @param config - Configuration object (only url and authToken are supported)
|
|
317
|
-
* @returns A Client instance compatible with libSQL API
|
|
318
|
-
* @throws LibsqlError if unsupported configuration options are provided
|
|
319
|
-
*
|
|
320
|
-
* @example
|
|
321
|
-
* ```typescript
|
|
322
|
-
* import { createClient } from "@tursodatabase/serverless/compat";
|
|
323
|
-
*
|
|
324
|
-
* const client = createClient({
|
|
325
|
-
* url: process.env.TURSO_DATABASE_URL,
|
|
326
|
-
* authToken: process.env.TURSO_AUTH_TOKEN
|
|
327
|
-
* });
|
|
328
|
-
*
|
|
329
|
-
* const result = await client.execute("SELECT * FROM users");
|
|
330
|
-
* console.log(result.rows);
|
|
331
|
-
* ```
|
|
332
|
-
*/
|
|
333
|
-
export function createClient(config) {
|
|
334
|
-
return new LibSQLClient(config);
|
|
335
|
-
}
|
|
336
|
-
// Known SQLite base error code names, used to split extended codes like
|
|
337
|
-
// "SQLITE_CONSTRAINT_PRIMARYKEY" into base ("SQLITE_CONSTRAINT") and extended.
|
|
338
|
-
const sqliteBaseErrorCodes = new Set([
|
|
339
|
-
"SQLITE_ERROR",
|
|
340
|
-
"SQLITE_INTERNAL",
|
|
341
|
-
"SQLITE_PERM",
|
|
342
|
-
"SQLITE_ABORT",
|
|
343
|
-
"SQLITE_BUSY",
|
|
344
|
-
"SQLITE_LOCKED",
|
|
345
|
-
"SQLITE_NOMEM",
|
|
346
|
-
"SQLITE_READONLY",
|
|
347
|
-
"SQLITE_INTERRUPT",
|
|
348
|
-
"SQLITE_IOERR",
|
|
349
|
-
"SQLITE_CORRUPT",
|
|
350
|
-
"SQLITE_NOTFOUND",
|
|
351
|
-
"SQLITE_FULL",
|
|
352
|
-
"SQLITE_CANTOPEN",
|
|
353
|
-
"SQLITE_PROTOCOL",
|
|
354
|
-
"SQLITE_EMPTY",
|
|
355
|
-
"SQLITE_SCHEMA",
|
|
356
|
-
"SQLITE_TOOBIG",
|
|
357
|
-
"SQLITE_CONSTRAINT",
|
|
358
|
-
"SQLITE_MISMATCH",
|
|
359
|
-
"SQLITE_MISUSE",
|
|
360
|
-
"SQLITE_NOLFS",
|
|
361
|
-
"SQLITE_AUTH",
|
|
362
|
-
"SQLITE_FORMAT",
|
|
363
|
-
"SQLITE_RANGE",
|
|
364
|
-
"SQLITE_NOTADB",
|
|
365
|
-
"SQLITE_NOTICE",
|
|
366
|
-
"SQLITE_WARNING",
|
|
367
|
-
]);
|
|
368
|
-
/**
|
|
369
|
-
* Parse a protocol error code into base and extended codes.
|
|
370
|
-
*
|
|
371
|
-
* The server may send either a base code ("SQLITE_CONSTRAINT") or an extended
|
|
372
|
-
* code ("SQLITE_CONSTRAINT_PRIMARYKEY"). This function splits them so that
|
|
373
|
-
* `code` is always the base code and `extendedCode` carries the full detail.
|
|
374
|
-
*/
|
|
375
|
-
function parseErrorCode(serverCode) {
|
|
376
|
-
if (sqliteBaseErrorCodes.has(serverCode)) {
|
|
377
|
-
return { code: serverCode };
|
|
378
|
-
}
|
|
379
|
-
// Try to find a base code prefix (e.g. "SQLITE_CONSTRAINT" in "SQLITE_CONSTRAINT_PRIMARYKEY")
|
|
380
|
-
for (const base of sqliteBaseErrorCodes) {
|
|
381
|
-
if (serverCode.startsWith(base + "_")) {
|
|
382
|
-
return { code: base, extendedCode: serverCode };
|
|
383
|
-
}
|
|
384
|
-
}
|
|
385
|
-
// Unknown code — return as-is
|
|
386
|
-
return { code: serverCode };
|
|
387
|
-
}
|
|
388
|
-
function mapDatabaseError(error, fallbackCode) {
|
|
389
|
-
if (error instanceof DatabaseError && error.code) {
|
|
390
|
-
const { code, extendedCode } = parseErrorCode(error.code);
|
|
391
|
-
return new LibsqlError(error.message, code, extendedCode, error.rawCode, error);
|
|
392
|
-
}
|
|
393
|
-
const cause = error instanceof Error ? error : undefined;
|
|
394
|
-
return new LibsqlError(error.message ?? String(error), fallbackCode, undefined, undefined, cause);
|
|
395
|
-
}
|
package/dist/connection.d.ts
DELETED
|
@@ -1,197 +0,0 @@
|
|
|
1
|
-
import { type SessionConfig } from './session.js';
|
|
2
|
-
import { Statement } from './statement.js';
|
|
3
|
-
import { type QueryOptions } from './protocol.js';
|
|
4
|
-
/**
|
|
5
|
-
* Configuration options for connecting to a Turso database.
|
|
6
|
-
*/
|
|
7
|
-
export interface Config extends SessionConfig {
|
|
8
|
-
}
|
|
9
|
-
/**
|
|
10
|
-
* A connection to a Turso database.
|
|
11
|
-
*
|
|
12
|
-
* Provides methods for executing SQL statements and managing prepared statements.
|
|
13
|
-
* Uses the SQL over HTTP protocol with streaming cursor support.
|
|
14
|
-
*
|
|
15
|
-
* ## Concurrency model
|
|
16
|
-
*
|
|
17
|
-
* A Connection is **single-stream**: it can only run one statement at a time.
|
|
18
|
-
* This is not an implementation quirk — it follows from the SQL over HTTP protocol,
|
|
19
|
-
* where each request carries a baton from the previous response to sequence operations
|
|
20
|
-
* on the server. Concurrent calls on the same connection would race on that baton
|
|
21
|
-
* and corrupt the stream. This is the same model as SQLite itself (one execution
|
|
22
|
-
* at a time per connection).
|
|
23
|
-
*
|
|
24
|
-
* If you call `execute()` while another is in flight, the call automatically
|
|
25
|
-
* waits for the previous one to finish — just like the native
|
|
26
|
-
* `@tursodatabase/database` binding.
|
|
27
|
-
*
|
|
28
|
-
* ## Parallel queries
|
|
29
|
-
*
|
|
30
|
-
* For parallelism, create multiple connections. `connect()` is cheap — it just
|
|
31
|
-
* allocates a config object. No TCP connection is opened until the first `execute()`,
|
|
32
|
-
* and the underlying `fetch()` runtime automatically pools and reuses TCP/TLS
|
|
33
|
-
* connections to the same origin.
|
|
34
|
-
*
|
|
35
|
-
* ```typescript
|
|
36
|
-
* import { connect } from "@tursodatabase/serverless";
|
|
37
|
-
*
|
|
38
|
-
* const config = { url: process.env.TURSO_URL, authToken: process.env.TURSO_TOKEN };
|
|
39
|
-
*
|
|
40
|
-
* // Option 1: one connection per parallel query
|
|
41
|
-
* const [users, orders] = await Promise.all([
|
|
42
|
-
* connect(config).execute("SELECT * FROM users WHERE active = 1"),
|
|
43
|
-
* connect(config).execute("SELECT * FROM orders WHERE status = 'pending'"),
|
|
44
|
-
* ]);
|
|
45
|
-
*
|
|
46
|
-
* // Option 2: reusable pool for repeated parallel work
|
|
47
|
-
* const pool = Array.from({ length: 4 }, () => connect(config));
|
|
48
|
-
* const results = await Promise.all(
|
|
49
|
-
* queries.map((sql, i) => pool[i % pool.length].execute(sql))
|
|
50
|
-
* );
|
|
51
|
-
* ```
|
|
52
|
-
*/
|
|
53
|
-
export declare class Connection {
|
|
54
|
-
private config;
|
|
55
|
-
private session;
|
|
56
|
-
private isOpen;
|
|
57
|
-
private defaultSafeIntegerMode;
|
|
58
|
-
private _inTransaction;
|
|
59
|
-
private execLock;
|
|
60
|
-
constructor(config: Config);
|
|
61
|
-
/**
|
|
62
|
-
* Whether the database is currently in a transaction.
|
|
63
|
-
*/
|
|
64
|
-
get inTransaction(): boolean;
|
|
65
|
-
/**
|
|
66
|
-
* Prepare a SQL statement for execution.
|
|
67
|
-
*
|
|
68
|
-
* Prepared statements created from a Connection use the same underlying session so transaction boundaries are preserved.
|
|
69
|
-
* This method fetches column metadata using the describe functionality.
|
|
70
|
-
*
|
|
71
|
-
* @param sql - The SQL statement to prepare
|
|
72
|
-
* @returns A Promise that resolves to a Statement object with column metadata
|
|
73
|
-
*
|
|
74
|
-
* @example
|
|
75
|
-
* ```typescript
|
|
76
|
-
* const stmt = await client.prepare("SELECT * FROM users WHERE id = ?");
|
|
77
|
-
* const columns = stmt.columns();
|
|
78
|
-
* const user = await stmt.get([123]);
|
|
79
|
-
* ```
|
|
80
|
-
*/
|
|
81
|
-
prepare(sql: string): Promise<Statement>;
|
|
82
|
-
/**
|
|
83
|
-
* Execute a SQL statement and return all results.
|
|
84
|
-
*
|
|
85
|
-
* @param sql - The SQL statement to execute
|
|
86
|
-
* @param args - Optional array of parameter values
|
|
87
|
-
* @returns Promise resolving to the complete result set
|
|
88
|
-
*
|
|
89
|
-
* @example
|
|
90
|
-
* ```typescript
|
|
91
|
-
* const result = await client.execute("SELECT * FROM users WHERE id = ?", [123]);
|
|
92
|
-
* console.log(result.rows);
|
|
93
|
-
* ```
|
|
94
|
-
*/
|
|
95
|
-
execute(sql: string, args?: any[], queryOptions?: QueryOptions): Promise<any>;
|
|
96
|
-
/**
|
|
97
|
-
* Execute a SQL statement and return all results.
|
|
98
|
-
*
|
|
99
|
-
* @param sql - The SQL statement to execute
|
|
100
|
-
* @returns Promise resolving to the complete result set
|
|
101
|
-
*
|
|
102
|
-
* @example
|
|
103
|
-
* ```typescript
|
|
104
|
-
* const result = await client.exec("SELECT * FROM users");
|
|
105
|
-
* console.log(result.rows);
|
|
106
|
-
* ```
|
|
107
|
-
*/
|
|
108
|
-
exec(sql: string, queryOptions?: QueryOptions): Promise<any>;
|
|
109
|
-
/**
|
|
110
|
-
* Execute multiple SQL statements in a batch.
|
|
111
|
-
*
|
|
112
|
-
* @param statements - Array of SQL statements to execute
|
|
113
|
-
* @param mode - Optional transaction mode (currently unused)
|
|
114
|
-
* @returns Promise resolving to batch execution results
|
|
115
|
-
*
|
|
116
|
-
* @example
|
|
117
|
-
* ```typescript
|
|
118
|
-
* await client.batch([
|
|
119
|
-
* "CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT)",
|
|
120
|
-
* "INSERT INTO users (name) VALUES ('Alice')",
|
|
121
|
-
* "INSERT INTO users (name) VALUES ('Bob')"
|
|
122
|
-
* ]);
|
|
123
|
-
* ```
|
|
124
|
-
*/
|
|
125
|
-
batch(statements: string[], mode?: string, queryOptions?: QueryOptions): Promise<any>;
|
|
126
|
-
/**
|
|
127
|
-
* Execute a pragma.
|
|
128
|
-
*
|
|
129
|
-
* @param pragma - The pragma to execute
|
|
130
|
-
* @returns Promise resolving to the result of the pragma
|
|
131
|
-
*/
|
|
132
|
-
pragma(pragma: string, queryOptions?: QueryOptions): Promise<any>;
|
|
133
|
-
/**
|
|
134
|
-
* Sets the default safe integers mode for all statements from this connection.
|
|
135
|
-
*
|
|
136
|
-
* @param toggle - Whether to use safe integers by default.
|
|
137
|
-
*/
|
|
138
|
-
defaultSafeIntegers(toggle?: boolean): void;
|
|
139
|
-
/**
|
|
140
|
-
* Returns a function that executes the given function in a transaction.
|
|
141
|
-
*
|
|
142
|
-
* @param fn - The function to wrap in a transaction
|
|
143
|
-
* @returns A function that will execute fn within a transaction
|
|
144
|
-
*
|
|
145
|
-
* @example
|
|
146
|
-
* ```typescript
|
|
147
|
-
* const insert = await client.prepare("INSERT INTO users (name) VALUES (?)");
|
|
148
|
-
* const insertMany = client.transaction((users) => {
|
|
149
|
-
* for (const user of users) {
|
|
150
|
-
* insert.run([user]);
|
|
151
|
-
* }
|
|
152
|
-
* });
|
|
153
|
-
*
|
|
154
|
-
* await insertMany(['Alice', 'Bob', 'Charlie']);
|
|
155
|
-
* ```
|
|
156
|
-
*/
|
|
157
|
-
transaction(fn: (...args: any[]) => any): any;
|
|
158
|
-
/**
|
|
159
|
-
* Close the connection.
|
|
160
|
-
*
|
|
161
|
-
* This sends a close request to the server to properly clean up the stream.
|
|
162
|
-
*/
|
|
163
|
-
close(): Promise<void>;
|
|
164
|
-
reconnect(): Promise<void>;
|
|
165
|
-
}
|
|
166
|
-
/**
|
|
167
|
-
* Create a new connection to a Turso database.
|
|
168
|
-
*
|
|
169
|
-
* This is a lightweight operation — it only allocates a config object. No network
|
|
170
|
-
* I/O happens until the first query. The underlying `fetch()` implementation
|
|
171
|
-
* automatically pools TCP/TLS connections to the same origin, so creating many
|
|
172
|
-
* connections is cheap.
|
|
173
|
-
*
|
|
174
|
-
* Each connection is single-stream: concurrent calls on the same connection are
|
|
175
|
-
* automatically serialized. For true parallelism, create multiple connections:
|
|
176
|
-
*
|
|
177
|
-
* ```typescript
|
|
178
|
-
* import { connect } from "@tursodatabase/serverless";
|
|
179
|
-
*
|
|
180
|
-
* const config = { url: process.env.TURSO_URL, authToken: process.env.TURSO_TOKEN };
|
|
181
|
-
*
|
|
182
|
-
* // Sequential (single connection is fine)
|
|
183
|
-
* const conn = connect(config);
|
|
184
|
-
* const a = await conn.execute("SELECT 1");
|
|
185
|
-
* const b = await conn.execute("SELECT 2");
|
|
186
|
-
*
|
|
187
|
-
* // Parallel (use separate connections)
|
|
188
|
-
* const [x, y] = await Promise.all([
|
|
189
|
-
* connect(config).execute("SELECT 1"),
|
|
190
|
-
* connect(config).execute("SELECT 2"),
|
|
191
|
-
* ]);
|
|
192
|
-
* ```
|
|
193
|
-
*
|
|
194
|
-
* @param config - Configuration object with database URL and auth token
|
|
195
|
-
* @returns A new Connection instance
|
|
196
|
-
*/
|
|
197
|
-
export declare function connect(config: Config): Connection;
|