@ohos-ports/libsql-client 0.18.0-beta.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.
@@ -0,0 +1,720 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ var __importDefault = (this && this.__importDefault) || function (mod) {
17
+ return (mod && mod.__esModule) ? mod : { "default": mod };
18
+ };
19
+ Object.defineProperty(exports, "__esModule", { value: true });
20
+ exports.Sqlite3Transaction = exports.Sqlite3Client = exports.ConnectionPool = exports._createClient = exports.createClient = void 0;
21
+ const libsql_1 = __importDefault(require("@ohos-ports/libsql"));
22
+ const node_buffer_1 = require("node:buffer");
23
+ const api_1 = require("@libsql/core/api");
24
+ const config_1 = require("@libsql/core/config");
25
+ const util_1 = require("@libsql/core/util");
26
+ __exportStar(require("@libsql/core/api"), exports);
27
+ function createClient(config) {
28
+ return _createClient((0, config_1.expandConfig)(config, true));
29
+ }
30
+ exports.createClient = createClient;
31
+ /** @private */
32
+ function _createClient(config) {
33
+ if (config.scheme !== "file") {
34
+ throw new api_1.LibsqlError(`URL scheme ${JSON.stringify(config.scheme + ":")} is not supported by the local sqlite3 client. ` +
35
+ `For more information, please read ${util_1.supportedUrlLink}`, "URL_SCHEME_NOT_SUPPORTED");
36
+ }
37
+ const authority = config.authority;
38
+ if (authority !== undefined) {
39
+ const host = authority.host.toLowerCase();
40
+ if (host !== "" && host !== "localhost") {
41
+ throw new api_1.LibsqlError(`Invalid host in file URL: ${JSON.stringify(authority.host)}. ` +
42
+ 'A "file:" URL with an absolute path should start with one slash ("file:/absolute/path.db") ' +
43
+ 'or with three slashes ("file:///absolute/path.db"). ' +
44
+ `For more information, please read ${util_1.supportedUrlLink}`, "URL_INVALID");
45
+ }
46
+ if (authority.port !== undefined) {
47
+ throw new api_1.LibsqlError("File URL cannot have a port", "URL_INVALID");
48
+ }
49
+ if (authority.userinfo !== undefined) {
50
+ throw new api_1.LibsqlError("File URL cannot have username and password", "URL_INVALID");
51
+ }
52
+ }
53
+ let isInMemory = (0, config_1.isInMemoryConfig)(config);
54
+ if (isInMemory && config.syncUrl) {
55
+ throw new api_1.LibsqlError(`Embedded replica must use file for local db but URI with in-memory mode were provided instead: ${config.path}`, "URL_INVALID");
56
+ }
57
+ let path = config.path;
58
+ if (isInMemory) {
59
+ // note: we should prepend file scheme in order for SQLite3 to recognize :memory: connection query parameters
60
+ path = `${config.scheme}:${config.path}`;
61
+ }
62
+ // An in-memory database exists only on the connection that opened it, so a
63
+ // second connection would be a second, empty database rather than another
64
+ // way into the same one. Each connection to an embedded replica carries
65
+ // its own sync state. Both are therefore single-connection databases.
66
+ const maxConnections = isInMemory || config.syncUrl ? 1 : Math.max(1, config.concurrency);
67
+ const options = {
68
+ authToken: config.authToken,
69
+ encryptionKey: config.encryptionKey,
70
+ remoteEncryptionKey: config.remoteEncryptionKey,
71
+ syncUrl: config.syncUrl,
72
+ syncPeriod: config.syncInterval,
73
+ readYourWrites: config.readYourWrites,
74
+ offline: config.offline,
75
+ timeout: config.timeout,
76
+ };
77
+ const pool = new ConnectionPool(path, options, maxConnections);
78
+ // fail fast if the database cannot be opened at all
79
+ const db = pool.acquireSync();
80
+ try {
81
+ executeStmt(db, "SELECT 1 AS checkThatTheDatabaseCanBeOpened", config.intMode);
82
+ }
83
+ catch (e) {
84
+ pool.close();
85
+ throw e;
86
+ }
87
+ pool.release(db);
88
+ return new Sqlite3Client(pool, config.intMode);
89
+ }
90
+ exports._createClient = _createClient;
91
+ /**
92
+ * A client owns a small pool of connections to one database, in the same way
93
+ * that a remote client owns a set of hrana streams: every client operation
94
+ * borrows one for the duration of the call, and a transaction borrows one for
95
+ * its lifetime and gives it back on commit, rollback or close. Nothing is
96
+ * shared between an open transaction and the rest of the client.
97
+ *
98
+ * @private
99
+ */
100
+ class ConnectionPool {
101
+ #path;
102
+ #options;
103
+ #maxConnections;
104
+ #idle;
105
+ #borrowed;
106
+ // the subset of `#borrowed` held by an open transaction
107
+ #heldByTransaction;
108
+ #waiters;
109
+ #closed;
110
+ constructor(path, options, maxConnections) {
111
+ this.#path = path;
112
+ this.#options = options;
113
+ this.#maxConnections = maxConnections;
114
+ this.#idle = [];
115
+ this.#borrowed = new Set();
116
+ this.#heldByTransaction = new Set();
117
+ this.#waiters = [];
118
+ this.#closed = false;
119
+ }
120
+ // Borrows a connection, opening one if the pool is below its limit and
121
+ // waiting for a release if it is not.
122
+ //
123
+ // Every borrow but a transaction's is a short synchronous call that
124
+ // returns the connection before the caller sees it again, so waiting for
125
+ // one is safe. A transaction holds its connection until the caller commits
126
+ // or rolls back, so if transactions hold every connection there is nothing
127
+ // to wait for - the caller has to act first. Say so instead of hanging.
128
+ acquire(forTransaction = false) {
129
+ if (!this.#closed && this.#atLimit()) {
130
+ if (this.#heldByTransaction.size >= this.#maxConnections) {
131
+ return Promise.reject(new api_1.LibsqlError(this.#maxConnections === 1
132
+ ? "This client has a single connection, which an open transaction is holding. " +
133
+ "In-memory databases and embedded replicas cannot have more than one. " +
134
+ "Commit or roll back the transaction before using the client again."
135
+ : `All ${this.#maxConnections} of this client's connections are held by open transactions. ` +
136
+ "Commit or roll back one before using the client again, or raise `concurrency`.", "TRANSACTION_ACTIVE"));
137
+ }
138
+ return new Promise((resolve, reject) => this.#waiters.push({
139
+ resolve: (db) => {
140
+ if (forTransaction) {
141
+ this.#heldByTransaction.add(db);
142
+ }
143
+ resolve(db);
144
+ },
145
+ reject,
146
+ }));
147
+ }
148
+ try {
149
+ return Promise.resolve(this.acquireSync(forTransaction));
150
+ }
151
+ catch (e) {
152
+ return Promise.reject(e);
153
+ }
154
+ }
155
+ // Borrows a connection without waiting. Only valid when the pool cannot be
156
+ // at its limit yet, which is why it is used for the initial probe.
157
+ acquireSync(forTransaction = false) {
158
+ this.#checkNotClosed();
159
+ const idle = this.#idle.pop();
160
+ const db = idle ?? new libsql_1.default(this.#path, this.#options);
161
+ this.#borrowed.add(db);
162
+ if (forTransaction) {
163
+ this.#heldByTransaction.add(db);
164
+ }
165
+ return db;
166
+ }
167
+ // Returns a borrowed connection to the pool, handing it straight to a
168
+ // waiter if there is one.
169
+ release(db) {
170
+ this.#borrowed.delete(db);
171
+ this.#heldByTransaction.delete(db);
172
+ // A connection must never go back into the pool mid-transaction, or
173
+ // the next borrower would silently inherit it.
174
+ if (db.open && db.inTransaction) {
175
+ try {
176
+ db.prepare("ROLLBACK").run();
177
+ }
178
+ catch {
179
+ // the connection is unusable; drop it rather than reuse it
180
+ closeQuietly(db);
181
+ return;
182
+ }
183
+ }
184
+ if (this.#closed || !db.open) {
185
+ closeQuietly(db);
186
+ return;
187
+ }
188
+ const waiter = this.#waiters.shift();
189
+ if (waiter !== undefined) {
190
+ this.#borrowed.add(db);
191
+ waiter.resolve(db);
192
+ }
193
+ else {
194
+ this.#idle.push(db);
195
+ }
196
+ }
197
+ close() {
198
+ this.#closed = true;
199
+ for (const db of this.#idle) {
200
+ closeQuietly(db);
201
+ }
202
+ this.#idle = [];
203
+ for (const db of this.#borrowed) {
204
+ closeQuietly(db);
205
+ }
206
+ this.#borrowed.clear();
207
+ this.#heldByTransaction.clear();
208
+ // Anything still queued will never be served now. Reject it: dropping
209
+ // the callbacks would leave those operations pending forever.
210
+ const waiters = this.#waiters;
211
+ this.#waiters = [];
212
+ for (const waiter of waiters) {
213
+ waiter.reject(new api_1.LibsqlError("The client is closed", "CLIENT_CLOSED"));
214
+ }
215
+ }
216
+ reopen() {
217
+ this.close();
218
+ this.#closed = false;
219
+ }
220
+ #atLimit() {
221
+ return (this.#idle.length === 0 &&
222
+ this.#borrowed.size >= this.#maxConnections);
223
+ }
224
+ #checkNotClosed() {
225
+ if (this.#closed) {
226
+ throw new api_1.LibsqlError("The client is closed", "CLIENT_CLOSED");
227
+ }
228
+ }
229
+ }
230
+ exports.ConnectionPool = ConnectionPool;
231
+ function closeQuietly(db) {
232
+ try {
233
+ if (db.open) {
234
+ db.close();
235
+ }
236
+ }
237
+ catch {
238
+ // nothing useful to do while tearing down
239
+ }
240
+ }
241
+ class Sqlite3Client {
242
+ #pool;
243
+ #intMode;
244
+ closed;
245
+ protocol;
246
+ /** @private */
247
+ constructor(pool, intMode) {
248
+ this.#pool = pool;
249
+ this.#intMode = intMode;
250
+ this.closed = false;
251
+ this.protocol = "file";
252
+ }
253
+ async execute(stmtOrSql, args) {
254
+ let stmt;
255
+ if (typeof stmtOrSql === "string") {
256
+ stmt = {
257
+ sql: stmtOrSql,
258
+ args: args || [],
259
+ };
260
+ }
261
+ else {
262
+ stmt = stmtOrSql;
263
+ }
264
+ this.#checkNotClosed();
265
+ const db = await this.#pool.acquire();
266
+ try {
267
+ this.#checkUsable(db);
268
+ return executeStmt(db, stmt, this.#intMode);
269
+ }
270
+ finally {
271
+ this.#pool.release(db);
272
+ }
273
+ }
274
+ async batch(stmts, mode = "deferred") {
275
+ this.#checkNotClosed();
276
+ const db = await this.#pool.acquire();
277
+ try {
278
+ this.#checkUsable(db);
279
+ executeStmt(db, (0, util_1.transactionModeToBegin)(mode), this.#intMode);
280
+ const resultSets = [];
281
+ for (let i = 0; i < stmts.length; i++) {
282
+ try {
283
+ if (!db.inTransaction) {
284
+ throw new api_1.LibsqlBatchError("The transaction has been rolled back", i, "TRANSACTION_CLOSED");
285
+ }
286
+ const stmt = stmts[i];
287
+ const normalizedStmt = Array.isArray(stmt)
288
+ ? { sql: stmt[0], args: stmt[1] || [] }
289
+ : stmt;
290
+ resultSets.push(executeStmt(db, normalizedStmt, this.#intMode));
291
+ }
292
+ catch (e) {
293
+ if (e instanceof api_1.LibsqlBatchError) {
294
+ throw e;
295
+ }
296
+ if (e instanceof api_1.LibsqlError) {
297
+ throw new api_1.LibsqlBatchError(e.message, i, e.code, e.extendedCode, e.rawCode, e.cause instanceof Error ? e.cause : undefined);
298
+ }
299
+ throw e;
300
+ }
301
+ }
302
+ executeStmt(db, "COMMIT", this.#intMode);
303
+ return resultSets;
304
+ }
305
+ finally {
306
+ // `release` rolls back anything still open before reuse
307
+ this.#pool.release(db);
308
+ }
309
+ }
310
+ async migrate(stmts) {
311
+ this.#checkNotClosed();
312
+ const db = await this.#pool.acquire();
313
+ try {
314
+ this.#checkUsable(db);
315
+ executeStmt(db, "PRAGMA foreign_keys=off", this.#intMode);
316
+ executeStmt(db, (0, util_1.transactionModeToBegin)("deferred"), this.#intMode);
317
+ const resultSets = [];
318
+ for (let i = 0; i < stmts.length; i++) {
319
+ try {
320
+ if (!db.inTransaction) {
321
+ throw new api_1.LibsqlBatchError("The transaction has been rolled back", i, "TRANSACTION_CLOSED");
322
+ }
323
+ resultSets.push(executeStmt(db, stmts[i], this.#intMode));
324
+ }
325
+ catch (e) {
326
+ if (e instanceof api_1.LibsqlBatchError) {
327
+ throw e;
328
+ }
329
+ if (e instanceof api_1.LibsqlError) {
330
+ throw new api_1.LibsqlBatchError(e.message, i, e.code, e.extendedCode, e.rawCode, e.cause instanceof Error ? e.cause : undefined);
331
+ }
332
+ throw e;
333
+ }
334
+ }
335
+ executeStmt(db, "COMMIT", this.#intMode);
336
+ return resultSets;
337
+ }
338
+ finally {
339
+ if (db.inTransaction) {
340
+ executeStmt(db, "ROLLBACK", this.#intMode);
341
+ }
342
+ executeStmt(db, "PRAGMA foreign_keys=on", this.#intMode);
343
+ this.#pool.release(db);
344
+ }
345
+ }
346
+ async transaction(mode = "write") {
347
+ this.#checkNotClosed();
348
+ const db = await this.#pool.acquire(true);
349
+ try {
350
+ this.#checkUsable(db);
351
+ executeStmt(db, (0, util_1.transactionModeToBegin)(mode), this.#intMode);
352
+ }
353
+ catch (e) {
354
+ this.#pool.release(db);
355
+ throw e;
356
+ }
357
+ // The transaction owns this connection until it settles, exactly as an
358
+ // `HttpTransaction` owns its stream.
359
+ return new Sqlite3Transaction(db, this.#intMode, (used) => this.#pool.release(used));
360
+ }
361
+ async executeMultiple(sql) {
362
+ this.#checkNotClosed();
363
+ const db = await this.#pool.acquire();
364
+ try {
365
+ this.#checkUsable(db);
366
+ return executeMultiple(db, sql);
367
+ }
368
+ finally {
369
+ // `release` rolls back a transaction `sql` left open
370
+ this.#pool.release(db);
371
+ }
372
+ }
373
+ async sync() {
374
+ this.#checkNotClosed();
375
+ const db = await this.#pool.acquire();
376
+ try {
377
+ this.#checkUsable(db);
378
+ const rep = await db.sync();
379
+ return {
380
+ frames_synced: rep.frames_synced,
381
+ frame_no: rep.frame_no,
382
+ };
383
+ }
384
+ finally {
385
+ this.#pool.release(db);
386
+ }
387
+ }
388
+ async reconnect() {
389
+ this.#pool.reopen();
390
+ this.closed = false;
391
+ }
392
+ close() {
393
+ this.closed = true;
394
+ this.#pool.close();
395
+ }
396
+ #checkNotClosed() {
397
+ if (this.closed) {
398
+ throw new api_1.LibsqlError("The client is closed", "CLIENT_CLOSED");
399
+ }
400
+ }
401
+ // `close()` and `reconnect()` are synchronous and can land between a
402
+ // borrow and the work it was borrowed for, closing the connection under an
403
+ // operation that is already holding one. Without this the operation
404
+ // reaches libsql with a closed handle and fails with a raw TypeError.
405
+ #checkUsable(db) {
406
+ this.#checkNotClosed();
407
+ if (!db.open) {
408
+ throw new api_1.LibsqlError("The connection was closed while this operation was in flight", "CLIENT_CLOSED");
409
+ }
410
+ }
411
+ }
412
+ exports.Sqlite3Client = Sqlite3Client;
413
+ class Sqlite3Transaction {
414
+ // null once the connection has been returned to the pool
415
+ #database;
416
+ #intMode;
417
+ #release;
418
+ /** @private */
419
+ constructor(database, intMode, release) {
420
+ this.#database = database;
421
+ this.#intMode = intMode;
422
+ this.#release = release;
423
+ }
424
+ // Returns the connection to the pool. Idempotent, so every exit path can
425
+ // call it without checking whether another already did.
426
+ #settle() {
427
+ const db = this.#database;
428
+ if (db === null) {
429
+ return;
430
+ }
431
+ this.#database = null;
432
+ this.#release(db);
433
+ }
434
+ #getDatabase() {
435
+ this.#checkNotClosed();
436
+ return this.#database;
437
+ }
438
+ async execute(stmtOrSql, args) {
439
+ let stmt;
440
+ if (typeof stmtOrSql === "string") {
441
+ stmt = {
442
+ sql: stmtOrSql,
443
+ args: args || [],
444
+ };
445
+ }
446
+ else {
447
+ stmt = stmtOrSql;
448
+ }
449
+ return executeStmt(this.#getDatabase(), stmt, this.#intMode);
450
+ }
451
+ async batch(stmts) {
452
+ const resultSets = [];
453
+ for (let i = 0; i < stmts.length; i++) {
454
+ try {
455
+ const db = this.#getDatabase();
456
+ const stmt = stmts[i];
457
+ const normalizedStmt = Array.isArray(stmt)
458
+ ? { sql: stmt[0], args: stmt[1] || [] }
459
+ : stmt;
460
+ resultSets.push(executeStmt(db, normalizedStmt, this.#intMode));
461
+ }
462
+ catch (e) {
463
+ if (e instanceof api_1.LibsqlBatchError) {
464
+ throw e;
465
+ }
466
+ if (e instanceof api_1.LibsqlError) {
467
+ throw new api_1.LibsqlBatchError(e.message, i, e.code, e.extendedCode, e.rawCode, e.cause instanceof Error ? e.cause : undefined);
468
+ }
469
+ throw e;
470
+ }
471
+ }
472
+ return resultSets;
473
+ }
474
+ async executeMultiple(sql) {
475
+ return executeMultiple(this.#getDatabase(), sql);
476
+ }
477
+ async rollback() {
478
+ const db = this.#database;
479
+ if (db === null || !db.open) {
480
+ this.#settle();
481
+ return;
482
+ }
483
+ try {
484
+ this.#checkNotClosed();
485
+ executeStmt(db, "ROLLBACK", this.#intMode);
486
+ }
487
+ finally {
488
+ this.#settle();
489
+ }
490
+ }
491
+ async commit() {
492
+ try {
493
+ executeStmt(this.#getDatabase(), "COMMIT", this.#intMode);
494
+ }
495
+ finally {
496
+ this.#settle();
497
+ }
498
+ }
499
+ close() {
500
+ const db = this.#database;
501
+ if (db === null) {
502
+ return;
503
+ }
504
+ try {
505
+ // `client.close()` may have closed this connection already, and
506
+ // reading `inTransaction` on a closed database aborts the process.
507
+ if (db.open && db.inTransaction) {
508
+ executeStmt(db, "ROLLBACK", this.#intMode);
509
+ }
510
+ }
511
+ finally {
512
+ this.#settle();
513
+ }
514
+ }
515
+ get closed() {
516
+ const db = this.#database;
517
+ if (db === null || !db.open) {
518
+ return true;
519
+ }
520
+ return !db.inTransaction;
521
+ }
522
+ #checkNotClosed() {
523
+ if (this.closed) {
524
+ throw new api_1.LibsqlError("The transaction is closed", "TRANSACTION_CLOSED");
525
+ }
526
+ }
527
+ }
528
+ exports.Sqlite3Transaction = Sqlite3Transaction;
529
+ function executeStmt(db, stmt, intMode) {
530
+ let sql;
531
+ let args;
532
+ if (typeof stmt === "string") {
533
+ sql = stmt;
534
+ args = [];
535
+ }
536
+ else {
537
+ sql = stmt.sql;
538
+ if (Array.isArray(stmt.args)) {
539
+ args = stmt.args.map((value) => valueToSql(value, intMode));
540
+ }
541
+ else {
542
+ args = {};
543
+ for (const name in stmt.args) {
544
+ const argName = name[0] === "@" || name[0] === "$" || name[0] === ":"
545
+ ? name.substring(1)
546
+ : name;
547
+ args[argName] = valueToSql(stmt.args[name], intMode);
548
+ }
549
+ }
550
+ }
551
+ try {
552
+ const sqlStmt = db.prepare(sql);
553
+ sqlStmt.safeIntegers(true);
554
+ let returnsData = true;
555
+ try {
556
+ sqlStmt.raw(true);
557
+ }
558
+ catch {
559
+ // raw() throws an exception if the statement does not return data
560
+ returnsData = false;
561
+ }
562
+ if (returnsData) {
563
+ const columns = Array.from(sqlStmt.columns().map((col) => col.name));
564
+ const columnTypes = Array.from(sqlStmt.columns().map((col) => col.type ?? ""));
565
+ const rows = sqlStmt.all(args).map((sqlRow) => {
566
+ return rowFromSql(sqlRow, columns, intMode);
567
+ });
568
+ // TODO: can we get this info from better-sqlite3?
569
+ const rowsAffected = 0;
570
+ const lastInsertRowid = undefined;
571
+ return new util_1.ResultSetImpl(columns, columnTypes, rows, rowsAffected, lastInsertRowid);
572
+ }
573
+ else {
574
+ const info = sqlStmt.run(args);
575
+ const rowsAffected = info.changes;
576
+ const lastInsertRowid = BigInt(info.lastInsertRowid);
577
+ return new util_1.ResultSetImpl([], [], [], rowsAffected, lastInsertRowid);
578
+ }
579
+ }
580
+ catch (e) {
581
+ throw mapSqliteError(e);
582
+ }
583
+ }
584
+ function rowFromSql(sqlRow, columns, intMode) {
585
+ const row = {};
586
+ // make sure that the "length" property is not enumerable
587
+ Object.defineProperty(row, "length", { value: sqlRow.length });
588
+ for (let i = 0; i < sqlRow.length; ++i) {
589
+ const value = valueFromSql(sqlRow[i], intMode);
590
+ Object.defineProperty(row, i, { value });
591
+ const column = columns[i];
592
+ if (!Object.hasOwn(row, column)) {
593
+ Object.defineProperty(row, column, {
594
+ value,
595
+ enumerable: true,
596
+ configurable: true,
597
+ writable: true,
598
+ });
599
+ }
600
+ }
601
+ return row;
602
+ }
603
+ function valueFromSql(sqlValue, intMode) {
604
+ if (typeof sqlValue === "bigint") {
605
+ if (intMode === "number") {
606
+ if (sqlValue < minSafeBigint || sqlValue > maxSafeBigint) {
607
+ throw new RangeError("Received integer which cannot be safely represented as a JavaScript number");
608
+ }
609
+ return Number(sqlValue);
610
+ }
611
+ else if (intMode === "bigint") {
612
+ return sqlValue;
613
+ }
614
+ else if (intMode === "string") {
615
+ return "" + sqlValue;
616
+ }
617
+ else {
618
+ throw new Error("Invalid value for IntMode");
619
+ }
620
+ }
621
+ else if (sqlValue instanceof node_buffer_1.Buffer) {
622
+ return sqlValue.buffer;
623
+ }
624
+ return sqlValue;
625
+ }
626
+ const minSafeBigint = -9007199254740991n;
627
+ const maxSafeBigint = 9007199254740991n;
628
+ function valueToSql(value, intMode) {
629
+ if (typeof value === "number") {
630
+ if (!Number.isFinite(value)) {
631
+ throw new RangeError("Only finite numbers (not Infinity or NaN) can be passed as arguments");
632
+ }
633
+ return value;
634
+ }
635
+ else if (typeof value === "bigint") {
636
+ if (value < minInteger || value > maxInteger) {
637
+ throw new RangeError("bigint is too large to be represented as a 64-bit integer and passed as argument");
638
+ }
639
+ return value;
640
+ }
641
+ else if (typeof value === "boolean") {
642
+ switch (intMode) {
643
+ case "bigint":
644
+ return value ? 1n : 0n;
645
+ case "string":
646
+ return value ? "1" : "0";
647
+ default:
648
+ return value ? 1 : 0;
649
+ }
650
+ }
651
+ else if (value instanceof ArrayBuffer) {
652
+ return node_buffer_1.Buffer.from(value);
653
+ }
654
+ else if (value instanceof Date) {
655
+ return value.valueOf();
656
+ }
657
+ else if (value === undefined) {
658
+ throw new TypeError("undefined cannot be passed as argument to the database");
659
+ }
660
+ else {
661
+ return value;
662
+ }
663
+ }
664
+ const minInteger = -9223372036854775808n;
665
+ const maxInteger = 9223372036854775807n;
666
+ function executeMultiple(db, sql) {
667
+ try {
668
+ db.exec(sql);
669
+ }
670
+ catch (e) {
671
+ throw mapSqliteError(e);
672
+ }
673
+ }
674
+ function mapSqliteError(e) {
675
+ if (e instanceof libsql_1.default.SqliteError) {
676
+ const extendedCode = e.code;
677
+ const code = mapToBaseCode(e.rawCode);
678
+ return new api_1.LibsqlError(e.message, code, extendedCode, e.rawCode, e);
679
+ }
680
+ return e;
681
+ }
682
+ // Map SQLite raw error code to base error code string.
683
+ // Extended error codes are (base | (extended << 8)), so base = rawCode & 0xFF
684
+ function mapToBaseCode(rawCode) {
685
+ if (rawCode === undefined) {
686
+ return "SQLITE_UNKNOWN";
687
+ }
688
+ const baseCode = rawCode & 0xff;
689
+ return (sqliteErrorCodes[baseCode] ?? `SQLITE_UNKNOWN_${baseCode.toString()}`);
690
+ }
691
+ const sqliteErrorCodes = {
692
+ 1: "SQLITE_ERROR",
693
+ 2: "SQLITE_INTERNAL",
694
+ 3: "SQLITE_PERM",
695
+ 4: "SQLITE_ABORT",
696
+ 5: "SQLITE_BUSY",
697
+ 6: "SQLITE_LOCKED",
698
+ 7: "SQLITE_NOMEM",
699
+ 8: "SQLITE_READONLY",
700
+ 9: "SQLITE_INTERRUPT",
701
+ 10: "SQLITE_IOERR",
702
+ 11: "SQLITE_CORRUPT",
703
+ 12: "SQLITE_NOTFOUND",
704
+ 13: "SQLITE_FULL",
705
+ 14: "SQLITE_CANTOPEN",
706
+ 15: "SQLITE_PROTOCOL",
707
+ 16: "SQLITE_EMPTY",
708
+ 17: "SQLITE_SCHEMA",
709
+ 18: "SQLITE_TOOBIG",
710
+ 19: "SQLITE_CONSTRAINT",
711
+ 20: "SQLITE_MISMATCH",
712
+ 21: "SQLITE_MISUSE",
713
+ 22: "SQLITE_NOLFS",
714
+ 23: "SQLITE_AUTH",
715
+ 24: "SQLITE_FORMAT",
716
+ 25: "SQLITE_RANGE",
717
+ 26: "SQLITE_NOTADB",
718
+ 27: "SQLITE_NOTICE",
719
+ 28: "SQLITE_WARNING",
720
+ };