indexeddbshim 17.4.2 → 17.5.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.
Files changed (34) hide show
  1. package/dist/IDBFactory.d.ts +1 -3
  2. package/dist/IDBFactory.d.ts.map +1 -1
  3. package/dist/indexeddbshim-Key.js +1 -1
  4. package/dist/indexeddbshim-Key.min.js +1 -1
  5. package/dist/indexeddbshim-UnicodeIdentifiers-node.cjs +15 -2011
  6. package/dist/indexeddbshim-UnicodeIdentifiers-node.cjs.map +1 -1
  7. package/dist/indexeddbshim-UnicodeIdentifiers.js +6 -8
  8. package/dist/indexeddbshim-UnicodeIdentifiers.js.map +1 -1
  9. package/dist/indexeddbshim-UnicodeIdentifiers.min.js +2 -2
  10. package/dist/indexeddbshim-UnicodeIdentifiers.min.js.map +1 -1
  11. package/dist/indexeddbshim-node.cjs +15 -2011
  12. package/dist/indexeddbshim-node.cjs.map +1 -1
  13. package/dist/indexeddbshim-noninvasive.js +6 -8
  14. package/dist/indexeddbshim-noninvasive.js.map +1 -1
  15. package/dist/indexeddbshim-noninvasive.min.js +2 -2
  16. package/dist/indexeddbshim-noninvasive.min.js.map +1 -1
  17. package/dist/indexeddbshim.js +6 -8
  18. package/dist/indexeddbshim.js.map +1 -1
  19. package/dist/indexeddbshim.min.js +2 -2
  20. package/dist/indexeddbshim.min.js.map +1 -1
  21. package/dist/node-UnicodeIdentifiers.d.ts +2 -2
  22. package/dist/node-UnicodeIdentifiers.d.ts.map +1 -1
  23. package/dist/node.d.ts +2 -2
  24. package/dist/node.d.ts.map +1 -1
  25. package/dist/nodeWebSQL.d.ts +1 -1
  26. package/dist/nodeWebSQL.d.ts.map +1 -1
  27. package/package.json +4 -8
  28. package/src/IDBFactory.js +5 -7
  29. package/src/node-UnicodeIdentifiers.js +1 -1
  30. package/src/node.js +1 -1
  31. package/src/nodeWebSQL.js +5 -5
  32. package/dist/nodeSQLiteDatabase.d.ts +0 -64
  33. package/dist/nodeSQLiteDatabase.d.ts.map +0 -1
  34. package/src/nodeSQLiteDatabase.js +0 -314
@@ -1,12 +1,11 @@
1
- /*! indexeddbshim - v17.4.2 - 8/29/2026 */
1
+ /*! indexeddbshim - v17.5.0 - 8/30/2026 */
2
2
 
3
3
  'use strict';
4
4
 
5
5
  var fs$1 = require('node:fs');
6
6
  var path = require('node:path');
7
- var require$$0 = require('fs');
8
- var require$$1 = require('path');
9
- var require$$2 = require('util');
7
+ var customOpenDatabase = require('websql-configurable/custom/index.js');
8
+ var SQLiteDatabase = require('websql-configurable/lib/sqlite/SQLiteDatabase.js');
10
9
 
11
10
  /* eslint-disable no-restricted-syntax -- Instanceof checks */
12
11
  /* eslint-disable unicorn/no-this-assignment -- TS */
@@ -1567,7 +1566,7 @@ val => {
1567
1566
 
1568
1567
  // @ts-nocheck
1569
1568
 
1570
- function getDefaultExportFromCjs$1(x) {
1569
+ function getDefaultExportFromCjs(x) {
1571
1570
  return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
1572
1571
  }
1573
1572
  var regex$1;
@@ -1579,7 +1578,7 @@ function requireRegex() {
1579
1578
  return regex$1;
1580
1579
  }
1581
1580
  var regexExports = requireRegex();
1582
- var regex = /*@__PURE__*/getDefaultExportFromCjs$1(regexExports);
1581
+ var regex = /*@__PURE__*/getDefaultExportFromCjs(regexExports);
1583
1582
 
1584
1583
  /* eslint-disable new-cap -- ToString is how it is defined */
1585
1584
 
@@ -10229,9 +10228,7 @@ function triggerAnyVersionChangeAndBlockedEvents(openConnections, req, oldVersio
10229
10228
  /**
10230
10229
  * @typedef {import('websql-configurable/lib/websql/WebSQLDatabase.js').default & {
10231
10230
  * _db: {
10232
- * _db: {
10233
- * close: (errBack: (err: Error) => void) => void
10234
- * }
10231
+ * close: (errBack: (err: Error) => void) => void
10235
10232
  * }
10236
10233
  * }} DatabaseFull
10237
10234
  */
@@ -10309,7 +10306,7 @@ function closeCachedWebSQLConnections(name, cb) {
10309
10306
  return;
10310
10307
  }
10311
10308
  dbs.forEach(db => {
10312
- const sqliteDB = db._db && db._db._db;
10309
+ const sqliteDB = db._db;
10313
10310
  if (!sqliteDB || !sqliteDB.close) {
10314
10311
  remaining--;
10315
10312
  if (remaining === 0) {
@@ -10351,9 +10348,9 @@ function cleanupDatabaseResources(__openDatabase, name, escapedDatabaseName, dat
10351
10348
  databaseDeleted();
10352
10349
  return;
10353
10350
  }
10354
- const sqliteDB = latestSQLiteDBCached._db && latestSQLiteDBCached._db._db;
10351
+ const sqliteDB = latestSQLiteDBCached._db;
10355
10352
  if (!sqliteDB || !sqliteDB.close) {
10356
- console.error('The `openDatabase` implementation does not have the expected `._db._db.close` method for closing the database');
10353
+ console.error('The `openDatabase` implementation does not have the expected `._db.close` method for closing the database');
10357
10354
  return;
10358
10355
  }
10359
10356
  sqliteDB.close(
@@ -11159,7 +11156,7 @@ IDBFactory.prototype.databases = function () {
11159
11156
  let calledDbCreateError = false;
11160
11157
  // Snapshotted *now*, synchronously, at call time -- not read later
11161
11158
  // from inside the SQL query's callback below, which runs on a
11162
- // deferred macrotask (see `nodeSQLiteDatabase.js`'s `exec`) and so
11159
+ // deferred macrotask (see `websql-configurable`'s `SQLiteDatabase#exec`) and so
11163
11160
  // could otherwise race against (and lose to) an in-flight upgrade's
11164
11161
  // own commit/abort handler clearing its `pendingVersionChanges`
11165
11162
  // entry in the meantime -- which would make this method incorrectly
@@ -12970,1999 +12967,6 @@ function setGlobalVars(idb, initialConfig) {
12970
12967
  return /** @type {ShimmedObject} */IDB;
12971
12968
  }
12972
12969
 
12973
- var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
12974
-
12975
- function getDefaultExportFromCjs (x) {
12976
- return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
12977
- }
12978
-
12979
- var nextTick = {};
12980
-
12981
- var hasRequiredNextTick;
12982
- function requireNextTick() {
12983
- if (hasRequiredNextTick) return nextTick;
12984
- hasRequiredNextTick = 1;
12985
- nextTick.test = function () {
12986
- // Don't get fooled by e.g. browserify environments.
12987
- return typeof process !== 'undefined' && !process.browser;
12988
- };
12989
- nextTick.install = function (func) {
12990
- return function () {
12991
- process.nextTick(func);
12992
- };
12993
- };
12994
- return nextTick;
12995
- }
12996
-
12997
- var queueMicrotask$1 = {};
12998
-
12999
- var hasRequiredQueueMicrotask;
13000
- function requireQueueMicrotask() {
13001
- if (hasRequiredQueueMicrotask) return queueMicrotask$1;
13002
- hasRequiredQueueMicrotask = 1;
13003
- queueMicrotask$1.test = function () {
13004
- return typeof commonjsGlobal.queueMicrotask === 'function';
13005
- };
13006
- queueMicrotask$1.install = function (func) {
13007
- return function () {
13008
- commonjsGlobal.queueMicrotask(func);
13009
- };
13010
- };
13011
- return queueMicrotask$1;
13012
- }
13013
-
13014
- var mutation = {};
13015
-
13016
- var hasRequiredMutation;
13017
- function requireMutation() {
13018
- if (hasRequiredMutation) return mutation;
13019
- hasRequiredMutation = 1;
13020
- //based off rsvp https://github.com/tildeio/rsvp.js
13021
- //license https://github.com/tildeio/rsvp.js/blob/master/LICENSE
13022
- //https://github.com/tildeio/rsvp.js/blob/master/lib/rsvp/asap.js
13023
-
13024
- var Mutation = commonjsGlobal.MutationObserver || commonjsGlobal.WebKitMutationObserver;
13025
- mutation.test = function () {
13026
- return Mutation;
13027
- };
13028
- mutation.install = function (handle) {
13029
- var called = 0;
13030
- var observer = new Mutation(handle);
13031
- var element = commonjsGlobal.document.createTextNode('');
13032
- observer.observe(element, {
13033
- characterData: true
13034
- });
13035
- return function () {
13036
- element.data = called = ++called % 2;
13037
- };
13038
- };
13039
- return mutation;
13040
- }
13041
-
13042
- var messageChannel = {};
13043
-
13044
- var hasRequiredMessageChannel;
13045
- function requireMessageChannel() {
13046
- if (hasRequiredMessageChannel) return messageChannel;
13047
- hasRequiredMessageChannel = 1;
13048
- messageChannel.test = function () {
13049
- if (commonjsGlobal.setImmediate) {
13050
- // we can only get here in IE10
13051
- // which doesn't handel postMessage well
13052
- return false;
13053
- }
13054
- return typeof commonjsGlobal.MessageChannel !== 'undefined';
13055
- };
13056
- messageChannel.install = function (func) {
13057
- var channel = new commonjsGlobal.MessageChannel();
13058
- channel.port1.onmessage = func;
13059
- return function () {
13060
- channel.port2.postMessage(0);
13061
- };
13062
- };
13063
- return messageChannel;
13064
- }
13065
-
13066
- var stateChange = {};
13067
-
13068
- var hasRequiredStateChange;
13069
- function requireStateChange() {
13070
- if (hasRequiredStateChange) return stateChange;
13071
- hasRequiredStateChange = 1;
13072
- stateChange.test = function () {
13073
- return 'document' in commonjsGlobal && 'onreadystatechange' in commonjsGlobal.document.createElement('script');
13074
- };
13075
- stateChange.install = function (handle) {
13076
- return function () {
13077
- // Create a <script> element; its readystatechange event will be fired asynchronously once it is inserted
13078
- // into the document. Do so, thus queuing up the task. Remember to clean up once it's been called.
13079
- var scriptEl = commonjsGlobal.document.createElement('script');
13080
- scriptEl.onreadystatechange = function () {
13081
- handle();
13082
- scriptEl.onreadystatechange = null;
13083
- scriptEl.parentNode.removeChild(scriptEl);
13084
- scriptEl = null;
13085
- };
13086
- commonjsGlobal.document.documentElement.appendChild(scriptEl);
13087
- return handle;
13088
- };
13089
- };
13090
- return stateChange;
13091
- }
13092
-
13093
- var timeout = {};
13094
-
13095
- var hasRequiredTimeout;
13096
- function requireTimeout() {
13097
- if (hasRequiredTimeout) return timeout;
13098
- hasRequiredTimeout = 1;
13099
- timeout.test = function () {
13100
- return true;
13101
- };
13102
- timeout.install = function (t) {
13103
- return function () {
13104
- setTimeout(t, 0);
13105
- };
13106
- };
13107
- return timeout;
13108
- }
13109
-
13110
- var lib$1;
13111
- var hasRequiredLib$1;
13112
- function requireLib$1() {
13113
- if (hasRequiredLib$1) return lib$1;
13114
- hasRequiredLib$1 = 1;
13115
- var types = [requireNextTick(), requireQueueMicrotask(), requireMutation(), requireMessageChannel(), requireStateChange(), requireTimeout()];
13116
- var draining;
13117
- var currentQueue;
13118
- var queueIndex = -1;
13119
- var queue = [];
13120
- var scheduled = false;
13121
- function cleanUpNextTick() {
13122
- if (!draining || !currentQueue) {
13123
- return;
13124
- }
13125
- draining = false;
13126
- if (currentQueue.length) {
13127
- queue = currentQueue.concat(queue);
13128
- } else {
13129
- queueIndex = -1;
13130
- }
13131
- if (queue.length) {
13132
- nextTick();
13133
- }
13134
- }
13135
-
13136
- //named nextTick for less confusing stack traces
13137
- function nextTick() {
13138
- if (draining) {
13139
- return;
13140
- }
13141
- scheduled = false;
13142
- draining = true;
13143
- var len = queue.length;
13144
- var timeout = setTimeout(cleanUpNextTick);
13145
- while (len) {
13146
- currentQueue = queue;
13147
- queue = [];
13148
- while (currentQueue && ++queueIndex < len) {
13149
- currentQueue[queueIndex].run();
13150
- }
13151
- queueIndex = -1;
13152
- len = queue.length;
13153
- }
13154
- currentQueue = null;
13155
- queueIndex = -1;
13156
- draining = false;
13157
- clearTimeout(timeout);
13158
- }
13159
- var scheduleDrain;
13160
- var i = -1;
13161
- var len = types.length;
13162
- while (++i < len) {
13163
- if (types[i] && types[i].test && types[i].test()) {
13164
- scheduleDrain = types[i].install(nextTick);
13165
- break;
13166
- }
13167
- }
13168
- // v8 likes predictible objects
13169
- function Item(fun, array) {
13170
- this.fun = fun;
13171
- this.array = array;
13172
- }
13173
- Item.prototype.run = function () {
13174
- var fun = this.fun;
13175
- var array = this.array;
13176
- switch (array.length) {
13177
- case 0:
13178
- return fun();
13179
- case 1:
13180
- return fun(array[0]);
13181
- case 2:
13182
- return fun(array[0], array[1]);
13183
- case 3:
13184
- return fun(array[0], array[1], array[2]);
13185
- default:
13186
- return fun.apply(null, array);
13187
- }
13188
- };
13189
- lib$1 = immediate;
13190
- function immediate(task) {
13191
- var args = new Array(arguments.length - 1);
13192
- if (arguments.length > 1) {
13193
- for (var i = 1; i < arguments.length; i++) {
13194
- args[i - 1] = arguments[i];
13195
- }
13196
- }
13197
- queue.push(new Item(task, args));
13198
- if (!scheduled && !draining) {
13199
- scheduled = true;
13200
- scheduleDrain();
13201
- }
13202
- }
13203
- return lib$1;
13204
- }
13205
-
13206
- var libExports$1 = requireLib$1();
13207
- var immediate = /*@__PURE__*/getDefaultExportFromCjs(libExports$1);
13208
-
13209
- var tinyQueue;
13210
- var hasRequiredTinyQueue;
13211
- function requireTinyQueue() {
13212
- if (hasRequiredTinyQueue) return tinyQueue;
13213
- hasRequiredTinyQueue = 1;
13214
-
13215
- // Simple FIFO queue implementation to avoid having to do shift()
13216
- // on an array, which is slow.
13217
-
13218
- function Queue() {
13219
- this.length = 0;
13220
- }
13221
- Queue.prototype.push = function (item) {
13222
- var node = {
13223
- item: item
13224
- };
13225
- if (this.last) {
13226
- this.last = this.last.next = node;
13227
- } else {
13228
- this.last = this.first = node;
13229
- }
13230
- this.length++;
13231
- };
13232
- Queue.prototype.shift = function () {
13233
- var node = this.first;
13234
- if (node) {
13235
- this.first = node.next;
13236
- if (! --this.length) {
13237
- this.last = undefined;
13238
- }
13239
- return node.item;
13240
- }
13241
- };
13242
- Queue.prototype.slice = function (start, end) {
13243
- start = typeof start === 'undefined' ? 0 : start;
13244
- end = typeof end === 'undefined' ? Infinity : end;
13245
- var output = [];
13246
- var i = 0;
13247
- for (var node = this.first; node; node = node.next) {
13248
- if (--end < 0) {
13249
- break;
13250
- } else if (++i > start) {
13251
- output.push(node.item);
13252
- }
13253
- }
13254
- return output;
13255
- };
13256
- tinyQueue = Queue;
13257
- return tinyQueue;
13258
- }
13259
-
13260
- var tinyQueueExports = requireTinyQueue();
13261
- var Queue = /*@__PURE__*/getDefaultExportFromCjs(tinyQueueExports);
13262
-
13263
- var noopFn;
13264
- var hasRequiredNoopFn;
13265
- function requireNoopFn() {
13266
- if (hasRequiredNoopFn) return noopFn;
13267
- hasRequiredNoopFn = 1;
13268
- noopFn = function () {};
13269
- return noopFn;
13270
- }
13271
-
13272
- var noopFnExports = requireNoopFn();
13273
- var noop = /*@__PURE__*/getDefaultExportFromCjs(noopFnExports);
13274
-
13275
- /**
13276
- *
13277
- */
13278
- class WebSQLRows {
13279
- /**
13280
- * @param {unknown[]} array
13281
- */
13282
- constructor(array) {
13283
- this._array = array;
13284
- this.length = array.length;
13285
- }
13286
-
13287
- /**
13288
- * @param {number} i
13289
- */
13290
- item(i) {
13291
- return this._array[i];
13292
- }
13293
- }
13294
-
13295
- /**
13296
- *
13297
- */
13298
- class WebSQLResultSet {
13299
- /**
13300
- * @param {number} [insertId]
13301
- * @param {number} [rowsAffected]
13302
- * @param {unknown[]} [rows]
13303
- */
13304
- constructor(insertId, rowsAffected, rows) {
13305
- this.insertId = insertId;
13306
- this.rowsAffected = rowsAffected;
13307
- this.rows = new WebSQLRows(rows || []);
13308
- }
13309
- }
13310
-
13311
- /**
13312
- * These deliberately don't reuse the WebSQL spec's global
13313
- * `SQLStatementCallback`/`SQLStatementErrorCallback`/`SQLError` types:
13314
- * this library never constructs a real `SQLError` (errors here are
13315
- * always plain `Error`s coming from the underlying SQL driver), and
13316
- * `WebSQLResultSet#insertId`/`rowsAffected` are genuinely `number |
13317
- * undefined` (see `massageSQLResult` below), which the spec's
13318
- * `SQLResultSet` doesn't allow. Typing against the spec here would just
13319
- * paper over that mismatch with unsound casts.
13320
- * @typedef {(transaction: WebSQLTransaction, resultSet: WebSQLResultSet) => void} SqlCallback
13321
- * @typedef {(transaction: WebSQLTransaction, error: Error) => boolean | void} SqlErrorCallback
13322
- */
13323
-
13324
- /**
13325
- *
13326
- */
13327
- function errorUnhandled() {
13328
- return true; // a non-truthy return indicates error was handled
13329
- }
13330
-
13331
- // WebSQL has some bizarre behavior regarding insertId/rowsAffected. To try
13332
- // to match the observed behavior of Chrome/Safari as much as possible, we
13333
- // sniff the SQL message to try to massage the returned insertId/rowsAffected.
13334
- // This helps us pass the tests, although it's error-prone and should
13335
- // probably be revised.
13336
- /**
13337
- * @param {string} sql
13338
- * @param {number} [insertId]
13339
- * @param {number} [rowsAffected]
13340
- * @param {unknown[]} [rows]
13341
- */
13342
- function massageSQLResult(sql, insertId, rowsAffected, rows) {
13343
- if (/^\s*UPDATE\b/iu.test(sql)) {
13344
- // insertId is always undefined for "UPDATE" statements
13345
- insertId = undefined;
13346
- } else if (/^\s*CREATE\s+TABLE\b/iu.test(sql)) {
13347
- // WebSQL always returns an insertId of 0 for "CREATE TABLE" statements
13348
- insertId = 0;
13349
- rowsAffected = 0;
13350
- } else if (/^\s*DROP\s+TABLE\b/iu.test(sql)) {
13351
- // WebSQL always returns insertId=undefined and rowsAffected=0
13352
- // for "DROP TABLE" statements. Go figure.
13353
- insertId = undefined;
13354
- rowsAffected = 0;
13355
- } else if (!/^\s*INSERT\b/iu.test(sql)) {
13356
- // for all non-inserts (deletes, etc.) insertId is always undefined
13357
- // ¯\_(ツ)_/¯
13358
- insertId = undefined;
13359
- }
13360
- return new WebSQLResultSet(insertId, rowsAffected, rows);
13361
- }
13362
-
13363
- /**
13364
- *
13365
- */
13366
- class SQLTask {
13367
- /**
13368
- * @param {string} sql
13369
- * @param {unknown[]} args
13370
- * @param {SqlCallback} sqlCallback
13371
- * @param {SqlErrorCallback} sqlErrorCallback
13372
- */
13373
- constructor(sql, args, sqlCallback, sqlErrorCallback) {
13374
- this.sql = sql;
13375
- this.args = args;
13376
- this.sqlCallback = sqlCallback;
13377
- this.sqlErrorCallback = sqlErrorCallback;
13378
- }
13379
- }
13380
-
13381
- /**
13382
- * @param {WebSQLTransaction} self
13383
- * @param {SQLTask[]} batch
13384
- */
13385
- function runBatch(self, batch) {
13386
- /**
13387
- *
13388
- */
13389
- function onDone() {
13390
- self._running = false;
13391
- runAllSql(self);
13392
- }
13393
- const {
13394
- readOnly
13395
- } = self._task;
13396
- self._websqlDatabase._db.exec(batch, readOnly, function (err, results) {
13397
- /* c8 ignore next */
13398
- if (err || !results) {
13399
- self._error = err || new Error('exec() did not return results');
13400
- onDone();
13401
- return;
13402
- }
13403
- for (const [i, res] of results.entries()) {
13404
- const batchTask = batch[i];
13405
- if (res.error) {
13406
- if (batchTask.sqlErrorCallback(self, res.error)) {
13407
- // user didn't handle the error
13408
- self._error = res.error;
13409
- onDone();
13410
- return;
13411
- }
13412
- } else {
13413
- try {
13414
- batchTask.sqlCallback(self, massageSQLResult(batch[i].sql, res.insertId, res.rowsAffected, res.rows));
13415
- } catch (err) {
13416
- self._error = /** @type {Error} */err;
13417
- runAllSql(self);
13418
- }
13419
- }
13420
- }
13421
- onDone();
13422
- });
13423
- }
13424
-
13425
- /**
13426
- * @param {WebSQLTransaction} self
13427
- */
13428
- function runAllSql(self) {
13429
- if (self._running || self._complete) {
13430
- return;
13431
- }
13432
- if (self._error) {
13433
- self._complete = true;
13434
- self._websqlDatabase._onTransactionComplete(self._error, self);
13435
- return;
13436
- }
13437
- if (!self._sqlQueue.length) {
13438
- // Do not mark `_complete` here: the caller (via `nonstandardTransCb`,
13439
- // see `WebSQLDatabase#_onTransactionComplete`) may choose to defer the
13440
- // actual commit/rollback decision, in which case more SQL might still
13441
- // be queued via `executeSql()` later and must still be able to run.
13442
- // `_complete` is only set once that decision is actually final (see
13443
- // `_onTransactionComplete`'s `done`).
13444
- self._websqlDatabase._onTransactionComplete(self._error, self);
13445
- return;
13446
- }
13447
- self._running = true;
13448
- /** @type {SQLTask[]} */
13449
- const batch = [];
13450
- let task;
13451
- while (task = self._sqlQueue.shift()) {
13452
- batch.push(task);
13453
- }
13454
- runBatch(self, batch);
13455
- }
13456
-
13457
- /**
13458
- * @param {WebSQLTransaction} self
13459
- * @param {string} sql
13460
- * @param {unknown[]} args
13461
- * @param {SqlCallback} sqlCallback
13462
- * @param {SqlErrorCallback} sqlErrorCallback
13463
- * @param {import('../types.js').Delay} executeDelay
13464
- */
13465
- function executeSql(self, sql, args, sqlCallback, sqlErrorCallback, executeDelay) {
13466
- self._sqlQueue.push(new SQLTask(sql, args, sqlCallback, sqlErrorCallback));
13467
- if (self._runningTimeout) {
13468
- return;
13469
- }
13470
- self._runningTimeout = true;
13471
- executeDelay(function () {
13472
- self._runningTimeout = false;
13473
- runAllSql(self);
13474
- });
13475
- }
13476
-
13477
- /**
13478
- *
13479
- */
13480
- class WebSQLTransaction {
13481
- /**
13482
- * @param {import('./WebSQLDatabase.js').default} websqlDatabase
13483
- * @param {import('./WebSQLDatabase.js').TransactionTask} task
13484
- * @param {import('../types.js').Delay} [executeDelay]
13485
- */
13486
- constructor(websqlDatabase, task, executeDelay) {
13487
- this._websqlDatabase = websqlDatabase;
13488
- this._task = task;
13489
- /** @type {Error | null} */
13490
- this._error = null;
13491
- this._complete = false;
13492
- this._running = false;
13493
- this._runningTimeout = false;
13494
- this._executeDelay = executeDelay || immediate;
13495
- /** @type {import('tiny-queue').default<SQLTask>} */
13496
- this._sqlQueue = new Queue();
13497
- if (!task.readOnly) {
13498
- // A read-only task never needs a transaction wrapper for its own
13499
- // sake (reads don't need atomicity against each other) -- true
13500
- // whether or not `concurrentReaders` (see `WebSQLDatabase`) lets
13501
- // multiple read-only tasks actually run at once. This is a perf
13502
- // boost either way. A non-read-only task always still gets one, and
13503
- // always still runs with full exclusivity (see
13504
- // `WebSQLDatabase#runNextTransaction`).
13505
- this._sqlQueue.push(new SQLTask('BEGIN;', [], noop, noop));
13506
- }
13507
- }
13508
-
13509
- /**
13510
- * @param {string} sql
13511
- * @param {unknown[]} [args]
13512
- * @param {SqlCallback} [sqlCallback]
13513
- * @param {SqlErrorCallback} [sqlErrorCallback]
13514
- */
13515
- executeSql(sql, args, sqlCallback, sqlErrorCallback) {
13516
- args = Array.isArray(args) ? args : [];
13517
- sqlCallback = typeof sqlCallback === 'function' ? sqlCallback : noop;
13518
- sqlErrorCallback = typeof sqlErrorCallback === 'function' ? sqlErrorCallback : errorUnhandled;
13519
- executeSql(this, sql, args, sqlCallback, sqlErrorCallback, this._executeDelay);
13520
- }
13521
-
13522
- /**
13523
- * Not a true `#private` method: `WebSQLDatabase` calls this right after
13524
- * handing a freshly-created transaction to the caller's `txnCallback`.
13525
- */
13526
- // eslint-disable-next-line unicorn/prefer-private-class-fields -- see above
13527
- _checkDone() {
13528
- runAllSql(this);
13529
- }
13530
- }
13531
-
13532
- /**
13533
- * @typedef {(
13534
- * currentTask: TransactionTask,
13535
- * err: Error | null,
13536
- * done: (er?: Error | boolean | null) => void,
13537
- * rollback: (err: Error | boolean, cb: () => void) => void,
13538
- * commit: (cb: () => void) => void
13539
- * ) => boolean} NonstandardTransCb
13540
- */
13541
-
13542
- const ROLLBACK = [{
13543
- sql: 'ROLLBACK;',
13544
- args: []
13545
- }];
13546
- const COMMIT = [{
13547
- sql: 'END;',
13548
- args: []
13549
- }];
13550
-
13551
- /**
13552
- * V8 likes predictable objects.
13553
- */
13554
- class TransactionTask {
13555
- /**
13556
- * @param {boolean} readOnly
13557
- * @param {(trans: WebSQLTransaction) => void} txnCallback
13558
- * @param {(err: Error) => void} errorCallback
13559
- * @param {() => void} successCallback
13560
- * @param {NonstandardTransCb} [nonstandardTransCb]
13561
- */
13562
- constructor(readOnly, txnCallback, errorCallback, successCallback, nonstandardTransCb) {
13563
- this.readOnly = readOnly;
13564
- this.txnCallback = txnCallback;
13565
- this.errorCallback = errorCallback;
13566
- this.successCallback = successCallback;
13567
- this.nonstandardTransCb = nonstandardTransCb;
13568
- }
13569
- }
13570
-
13571
- /**
13572
- * The WebSQL `Database` object.
13573
- */
13574
- class WebSQLDatabase {
13575
- /**
13576
- * @param {string} dbVersion
13577
- * @param {import('../types.js').SqlDriver} db
13578
- * @param {import('../types.js').WebSQLOverrides} webSQLOverrides
13579
- */
13580
- constructor(dbVersion, db, webSQLOverrides) {
13581
- this.version = dbVersion;
13582
- this._db = db;
13583
- /** @type {import('tiny-queue').default<TransactionTask>} */
13584
- this._txnQueue = new Queue();
13585
- // Off by default: queued transactions -- read or write alike -- run
13586
- // strictly one at a time, in the order requested, per the WebSQL spec
13587
- // (see `#runNextTransaction`). When true, any number of read-only
13588
- // tasks may instead run concurrently; a non-read-only task still
13589
- // always runs with full exclusivity either way.
13590
- this._concurrentReaders = Boolean(webSQLOverrides.concurrentReaders);
13591
- /** @type {Set<TransactionTask>} */
13592
- this._activeReaders = new Set();
13593
- /** @type {TransactionTask | null} */
13594
- this._activeWriter = null;
13595
- this._transactionDelay = webSQLOverrides.transactionDelay || immediate;
13596
- this._executeDelay = webSQLOverrides.executeDelay || immediate;
13597
- }
13598
-
13599
- /**
13600
- * @param {TransactionTask} task
13601
- */
13602
- #runTransaction(task) {
13603
- const txn = new WebSQLTransaction(this, task, this._executeDelay);
13604
- this._transactionDelay(() => {
13605
- task.txnCallback(txn);
13606
- txn._checkDone();
13607
- });
13608
- }
13609
-
13610
- /**
13611
- * Starts as many queued tasks as the current lock state allows. With
13612
- * `concurrentReaders` off (the default), a task only starts once
13613
- * nothing else is active at all -- full mutual exclusion, matching the
13614
- * WebSQL spec's strict one-at-a-time, in-request-order guarantee (see
13615
- * this file's own test suite, "callback order 2"). With it on, any
13616
- * leading run of read-only tasks can all start together instead
13617
- * (concurrent reads are always fine); a non-read-only task still needs
13618
- * exclusivity regardless, so nothing past it may start until it
13619
- * finishes. Not starvation-proof in the `concurrentReaders` case -- a
13620
- * steady stream of arriving readers could in principle keep a waiting
13621
- * writer waiting indefinitely -- but that's an acceptable tradeoff over
13622
- * the added complexity of tracking arrival order across reader/writer
13623
- * kinds.
13624
- */
13625
- #runNextTransaction() {
13626
- for (;;) {
13627
- const [nextTask] = this._txnQueue.slice(0, 1);
13628
- if (!nextTask) {
13629
- return;
13630
- }
13631
- const readerMayShare = this._concurrentReaders && nextTask.readOnly;
13632
- if (readerMayShare) {
13633
- if (this._activeWriter) {
13634
- return;
13635
- }
13636
- } else if (this._activeWriter || this._activeReaders.size) {
13637
- return;
13638
- }
13639
- this._txnQueue.shift();
13640
- if (nextTask.readOnly) {
13641
- this._activeReaders.add(nextTask);
13642
- } else {
13643
- this._activeWriter = nextTask;
13644
- }
13645
- this.#runTransaction(nextTask);
13646
- }
13647
- }
13648
-
13649
- /**
13650
- * @param {boolean} readOnly
13651
- * @param {(trans: WebSQLTransaction) => void} txnCallback
13652
- * @param {(err: Error) => void} [errorCallback]
13653
- * @param {() => void} [successCallback]
13654
- * @param {NonstandardTransCb} [nonstandardTransCb]
13655
- */
13656
- #createTransaction(readOnly, txnCallback, errorCallback, successCallback, nonstandardTransCb) {
13657
- errorCallback ||= noop;
13658
- successCallback ||= noop;
13659
- if (typeof txnCallback !== 'function') {
13660
- throw new TypeError('The callback provided as parameter 1 is not a function.');
13661
- }
13662
- this._txnQueue.push(new TransactionTask(readOnly, txnCallback, errorCallback, successCallback, nonstandardTransCb));
13663
- this.#runNextTransaction();
13664
- }
13665
-
13666
- /**
13667
- * Not a true `#private` method: `WebSQLTransaction` calls this on its
13668
- * owning `WebSQLDatabase` once it's finished running its SQL queue.
13669
- * @param {Error | null} err
13670
- * @param {WebSQLTransaction} transaction
13671
- */
13672
- // eslint-disable-next-line unicorn/prefer-private-class-fields -- see above
13673
- _onTransactionComplete(err, transaction) {
13674
- const task = transaction._task;
13675
- /**
13676
- * @param {Error | boolean | null} [er]
13677
- */
13678
- const done = er => {
13679
- if (transaction) {
13680
- // Only now -- once the transaction has genuinely committed, rolled
13681
- // back, or been confirmed read-only-complete -- is it truly done.
13682
- // Marking this any earlier (e.g. as soon as its SQL queue merely
13683
- // looked empty) would permanently stop it from accepting further
13684
- // `executeSql()` calls even when `nonstandardTransCb` (below) chose
13685
- // to defer the commit/rollback decision instead of finalizing here.
13686
- transaction._complete = true;
13687
- }
13688
- if (er) {
13689
- task.errorCallback(/** @type {Error} */er);
13690
- } else {
13691
- task.successCallback();
13692
- }
13693
- if (task.readOnly) {
13694
- this._activeReaders.delete(task);
13695
- } else if (this._activeWriter === task) {
13696
- this._activeWriter = null;
13697
- }
13698
- this.#runNextTransaction();
13699
- };
13700
- /**
13701
- * @param {Error | boolean} er
13702
- * @param {() => void} [cb]
13703
- */
13704
- const rollback = (er, cb) => {
13705
- this._db.exec(ROLLBACK, false, () => {
13706
- done(er);
13707
- if (cb) {
13708
- cb();
13709
- }
13710
- });
13711
- };
13712
- /**
13713
- * @param {() => void} [cb]
13714
- */
13715
- const commit = cb => {
13716
- this._db.exec(COMMIT, false, () => {
13717
- done();
13718
- if (cb) {
13719
- cb();
13720
- }
13721
- });
13722
- };
13723
- if (task.nonstandardTransCb) {
13724
- const cont = task.nonstandardTransCb.call(this, task, err, done, rollback, commit);
13725
- if (!cont) {
13726
- return;
13727
- }
13728
- }
13729
- if (task.readOnly) {
13730
- done(err); // read-only doesn't require a transaction
13731
- } else if (err) {
13732
- rollback(err);
13733
- } else {
13734
- commit();
13735
- }
13736
- }
13737
-
13738
- /**
13739
- * @param {(trans: WebSQLTransaction) => void} txnCallback
13740
- * @param {(err: Error) => void} [errorCallback]
13741
- * @param {() => void} [successCallback]
13742
- * @param {NonstandardTransCb} [nonstandardTransCb]
13743
- */
13744
- transaction(txnCallback, errorCallback, successCallback, nonstandardTransCb) {
13745
- this.#createTransaction(false, txnCallback, errorCallback, successCallback, nonstandardTransCb);
13746
- }
13747
-
13748
- /**
13749
- * @param {(trans: WebSQLTransaction) => void} txnCallback
13750
- * @param {(err: Error) => void} [errorCallback]
13751
- * @param {() => void} [successCallback]
13752
- * @param {NonstandardTransCb} [nonstandardTransCb]
13753
- */
13754
- readTransaction(txnCallback, errorCallback, successCallback, nonstandardTransCb) {
13755
- this.#createTransaction(true, txnCallback, errorCallback, successCallback, nonstandardTransCb);
13756
- }
13757
- }
13758
-
13759
- /**
13760
- * @template Opts
13761
- * @param {import('./types.js').SqlDriverConstructor<Opts>} SQLiteDatabase
13762
- * @param {{ sqlite?: Opts, websql?: import('./types.js').WebSQLOverrides }} [opts]
13763
- */
13764
- function customOpenDatabase(SQLiteDatabase, opts) {
13765
- opts ||= {};
13766
- const sqliteOpts = opts.sqlite;
13767
- const webSQLOverrides = opts.websql || {};
13768
- const openDelay = webSQLOverrides.openDelay || immediate;
13769
-
13770
- /**
13771
- * @param {string} dbName
13772
- * @param {string} dbVersion
13773
- */
13774
- function createDb(dbName, dbVersion) {
13775
- const sqliteDatabase = new SQLiteDatabase(dbName, sqliteOpts);
13776
- return new WebSQLDatabase(dbVersion, sqliteDatabase, webSQLOverrides);
13777
- }
13778
-
13779
- /**
13780
- * @param {unknown[]} args
13781
- * @throws {Error} If fewer than 4 arguments are given.
13782
- */
13783
- function openDatabase(args) {
13784
- if (args.length < 4) {
13785
- throw new Error('Failed to execute \'openDatabase\': ' + '4 arguments required, but only ' + args.length + ' present');
13786
- }
13787
- const dbName = /** @type {string} */args[0];
13788
- const dbVersion = /** @type {string} */args[1];
13789
- // db description and size are ignored
13790
- const callback = /** @type {((db: WebSQLDatabase) => void) | undefined} */args[4];
13791
- const db = createDb(dbName, dbVersion);
13792
- if (typeof callback === 'function') {
13793
- const onOpen = callback;
13794
- openDelay(function () {
13795
- onOpen(db);
13796
- });
13797
- }
13798
- return db;
13799
- }
13800
- return (/** @type {unknown[]} */...args) => openDatabase(args);
13801
- }
13802
-
13803
- var lib = {exports: {}};
13804
-
13805
- var util = {};
13806
-
13807
- var hasRequiredUtil;
13808
- function requireUtil() {
13809
- if (hasRequiredUtil) return util;
13810
- hasRequiredUtil = 1;
13811
- util.getBooleanOption = (options, key) => {
13812
- let value = false;
13813
- if (key in options && typeof (value = options[key]) !== 'boolean') {
13814
- throw new TypeError(`Expected the "${key}" option to be a boolean`);
13815
- }
13816
- return value;
13817
- };
13818
- util.cppdb = Symbol();
13819
- util.inspect = Symbol.for('nodejs.util.inspect.custom');
13820
- return util;
13821
- }
13822
-
13823
- var sqliteError;
13824
- var hasRequiredSqliteError;
13825
- function requireSqliteError() {
13826
- if (hasRequiredSqliteError) return sqliteError;
13827
- hasRequiredSqliteError = 1;
13828
- class SqliteError extends Error {
13829
- constructor(message, code) {
13830
- if (typeof code !== 'string') {
13831
- throw new TypeError('Expected second argument to be a string');
13832
- }
13833
- super('' + message);
13834
- this.code = code;
13835
- if (typeof Error.captureStackTrace === 'function') {
13836
- Error.captureStackTrace(this, SqliteError);
13837
- }
13838
- }
13839
- }
13840
- Object.defineProperty(SqliteError.prototype, 'name', {
13841
- value: 'SqliteError',
13842
- writable: true,
13843
- enumerable: false,
13844
- configurable: true
13845
- });
13846
- sqliteError = SqliteError;
13847
- return sqliteError;
13848
- }
13849
-
13850
- var wrappers = {};
13851
-
13852
- var hasRequiredWrappers;
13853
- function requireWrappers() {
13854
- if (hasRequiredWrappers) return wrappers;
13855
- hasRequiredWrappers = 1;
13856
- const {
13857
- cppdb
13858
- } = requireUtil();
13859
- wrappers.prepare = function prepare(sql) {
13860
- return this[cppdb].prepare(sql, this, false, false);
13861
- };
13862
- wrappers.exec = function exec(sql) {
13863
- this[cppdb].exec(sql);
13864
- return this;
13865
- };
13866
- wrappers.close = function close() {
13867
- this[cppdb].close();
13868
- return this;
13869
- };
13870
- wrappers.loadExtension = function loadExtension(...args) {
13871
- this[cppdb].loadExtension(...args);
13872
- return this;
13873
- };
13874
- wrappers.defaultSafeIntegers = function defaultSafeIntegers(...args) {
13875
- this[cppdb].defaultSafeIntegers(...args);
13876
- return this;
13877
- };
13878
- wrappers.unsafeMode = function unsafeMode(...args) {
13879
- this[cppdb].unsafeMode(...args);
13880
- return this;
13881
- };
13882
- wrappers.getters = {
13883
- name: {
13884
- get: function name() {
13885
- return this[cppdb].name;
13886
- },
13887
- enumerable: true
13888
- },
13889
- open: {
13890
- get: function open() {
13891
- return this[cppdb].open;
13892
- },
13893
- enumerable: true
13894
- },
13895
- inTransaction: {
13896
- get: function inTransaction() {
13897
- return this[cppdb].inTransaction;
13898
- },
13899
- enumerable: true
13900
- },
13901
- readonly: {
13902
- get: function readonly() {
13903
- return this[cppdb].readonly;
13904
- },
13905
- enumerable: true
13906
- },
13907
- memory: {
13908
- get: function memory() {
13909
- return this[cppdb].memory;
13910
- },
13911
- enumerable: true
13912
- }
13913
- };
13914
- return wrappers;
13915
- }
13916
-
13917
- var transaction;
13918
- var hasRequiredTransaction;
13919
- function requireTransaction() {
13920
- if (hasRequiredTransaction) return transaction;
13921
- hasRequiredTransaction = 1;
13922
- const {
13923
- cppdb
13924
- } = requireUtil();
13925
- const controllers = new WeakMap();
13926
- transaction = function transaction(fn) {
13927
- if (typeof fn !== 'function') throw new TypeError('Expected first argument to be a function');
13928
- const db = this[cppdb];
13929
- const controller = getController(db, this);
13930
- const {
13931
- apply
13932
- } = Function.prototype;
13933
-
13934
- // Each version of the transaction function has these same properties
13935
- const properties = {
13936
- default: {
13937
- value: wrapTransaction(apply, fn, db, controller.default)
13938
- },
13939
- deferred: {
13940
- value: wrapTransaction(apply, fn, db, controller.deferred)
13941
- },
13942
- immediate: {
13943
- value: wrapTransaction(apply, fn, db, controller.immediate)
13944
- },
13945
- exclusive: {
13946
- value: wrapTransaction(apply, fn, db, controller.exclusive)
13947
- },
13948
- database: {
13949
- value: this,
13950
- enumerable: true
13951
- }
13952
- };
13953
- Object.defineProperties(properties.default.value, properties);
13954
- Object.defineProperties(properties.deferred.value, properties);
13955
- Object.defineProperties(properties.immediate.value, properties);
13956
- Object.defineProperties(properties.exclusive.value, properties);
13957
-
13958
- // Return the default version of the transaction function
13959
- return properties.default.value;
13960
- };
13961
-
13962
- // Return the database's cached transaction controller, or create a new one
13963
- const getController = (db, self) => {
13964
- let controller = controllers.get(db);
13965
- if (!controller) {
13966
- const shared = {
13967
- commit: db.prepare('COMMIT', self, false, false),
13968
- rollback: db.prepare('ROLLBACK', self, false, false),
13969
- savepoint: db.prepare('SAVEPOINT `\t_bs3.\t`', self, false, false),
13970
- release: db.prepare('RELEASE `\t_bs3.\t`', self, false, false),
13971
- rollbackTo: db.prepare('ROLLBACK TO `\t_bs3.\t`', self, false, false)
13972
- };
13973
- controllers.set(db, controller = {
13974
- default: Object.assign({
13975
- begin: db.prepare('BEGIN', self, false, false)
13976
- }, shared),
13977
- deferred: Object.assign({
13978
- begin: db.prepare('BEGIN DEFERRED', self, false, false)
13979
- }, shared),
13980
- immediate: Object.assign({
13981
- begin: db.prepare('BEGIN IMMEDIATE', self, false, false)
13982
- }, shared),
13983
- exclusive: Object.assign({
13984
- begin: db.prepare('BEGIN EXCLUSIVE', self, false, false)
13985
- }, shared)
13986
- });
13987
- }
13988
- return controller;
13989
- };
13990
-
13991
- // Return a new transaction function by wrapping the given function
13992
- const wrapTransaction = (apply, fn, db, {
13993
- begin,
13994
- commit,
13995
- rollback,
13996
- savepoint,
13997
- release,
13998
- rollbackTo
13999
- }) => function sqliteTransaction() {
14000
- let before, after, undo;
14001
- if (db.inTransaction) {
14002
- before = savepoint;
14003
- after = release;
14004
- undo = rollbackTo;
14005
- } else {
14006
- before = begin;
14007
- after = commit;
14008
- undo = rollback;
14009
- }
14010
- before.run();
14011
- try {
14012
- const result = apply.call(fn, this, arguments);
14013
- if (result && typeof result.then === 'function') {
14014
- throw new TypeError('Transaction function cannot return a promise');
14015
- }
14016
- after.run();
14017
- return result;
14018
- } catch (ex) {
14019
- if (db.inTransaction) {
14020
- undo.run();
14021
- if (undo !== rollback) after.run();
14022
- }
14023
- throw ex;
14024
- }
14025
- };
14026
- return transaction;
14027
- }
14028
-
14029
- var pragma;
14030
- var hasRequiredPragma;
14031
- function requirePragma() {
14032
- if (hasRequiredPragma) return pragma;
14033
- hasRequiredPragma = 1;
14034
- const {
14035
- getBooleanOption,
14036
- cppdb
14037
- } = requireUtil();
14038
- pragma = function pragma(source, options) {
14039
- if (options == null) options = {};
14040
- if (typeof source !== 'string') throw new TypeError('Expected first argument to be a string');
14041
- if (typeof options !== 'object') throw new TypeError('Expected second argument to be an options object');
14042
- const simple = getBooleanOption(options, 'simple');
14043
- const stmt = this[cppdb].prepare(`PRAGMA ${source}`, this, true, false);
14044
- return simple ? stmt.pluck().get() : stmt.all();
14045
- };
14046
- return pragma;
14047
- }
14048
-
14049
- var explain;
14050
- var hasRequiredExplain;
14051
- function requireExplain() {
14052
- if (hasRequiredExplain) return explain;
14053
- hasRequiredExplain = 1;
14054
- const {
14055
- cppdb
14056
- } = requireUtil();
14057
- explain = function explain(source) {
14058
- if (typeof source !== 'string') throw new TypeError('Expected first argument to be a string');
14059
- const stmt = this[cppdb].prepare(`EXPLAIN ${source}`, this, false, true);
14060
- return stmt.all();
14061
- };
14062
- return explain;
14063
- }
14064
-
14065
- var backup;
14066
- var hasRequiredBackup;
14067
- function requireBackup() {
14068
- if (hasRequiredBackup) return backup;
14069
- hasRequiredBackup = 1;
14070
- const fs = require$$0;
14071
- const path = require$$1;
14072
- const {
14073
- promisify
14074
- } = require$$2;
14075
- const {
14076
- cppdb
14077
- } = requireUtil();
14078
- const fsAccess = promisify(fs.access);
14079
- backup = async function backup(filename, options) {
14080
- if (options == null) options = {};
14081
-
14082
- // Validate arguments
14083
- if (typeof filename !== 'string') throw new TypeError('Expected first argument to be a string');
14084
- if (typeof options !== 'object') throw new TypeError('Expected second argument to be an options object');
14085
-
14086
- // Interpret options
14087
- filename = filename.trim();
14088
- const attachedName = 'attached' in options ? options.attached : 'main';
14089
- const handler = 'progress' in options ? options.progress : null;
14090
-
14091
- // Validate interpreted options
14092
- if (!filename) throw new TypeError('Backup filename cannot be an empty string');
14093
- if (filename === ':memory:') throw new TypeError('Invalid backup filename ":memory:"');
14094
- if (typeof attachedName !== 'string') throw new TypeError('Expected the "attached" option to be a string');
14095
- if (!attachedName) throw new TypeError('The "attached" option cannot be an empty string');
14096
- if (handler != null && typeof handler !== 'function') throw new TypeError('Expected the "progress" option to be a function');
14097
-
14098
- // Make sure the specified directory exists
14099
- await fsAccess(path.dirname(filename)).catch(() => {
14100
- throw new TypeError('Cannot save backup because the directory does not exist');
14101
- });
14102
- const isNewFile = await fsAccess(filename).then(() => false, () => true);
14103
- return runBackup(this[cppdb].backup(this, attachedName, filename, isNewFile), handler || null);
14104
- };
14105
- const runBackup = (backup, handler) => {
14106
- let rate = 0;
14107
- let useDefault = true;
14108
- return new Promise((resolve, reject) => {
14109
- setImmediate(function step() {
14110
- try {
14111
- const progress = backup.transfer(rate);
14112
- if (!progress.remainingPages) {
14113
- backup.close();
14114
- resolve(progress);
14115
- return;
14116
- }
14117
- if (useDefault) {
14118
- useDefault = false;
14119
- rate = 100;
14120
- }
14121
- if (handler) {
14122
- const ret = handler(progress);
14123
- if (ret !== undefined) {
14124
- if (typeof ret === 'number' && ret === ret) rate = Math.max(0, Math.min(0x7fffffff, Math.round(ret)));else throw new TypeError('Expected progress callback to return a number or undefined');
14125
- }
14126
- }
14127
- setImmediate(step);
14128
- } catch (err) {
14129
- backup.close();
14130
- reject(err);
14131
- }
14132
- });
14133
- });
14134
- };
14135
- return backup;
14136
- }
14137
-
14138
- var serialize;
14139
- var hasRequiredSerialize;
14140
- function requireSerialize() {
14141
- if (hasRequiredSerialize) return serialize;
14142
- hasRequiredSerialize = 1;
14143
- const {
14144
- cppdb
14145
- } = requireUtil();
14146
- serialize = function serialize(options) {
14147
- if (options == null) options = {};
14148
-
14149
- // Validate arguments
14150
- if (typeof options !== 'object') throw new TypeError('Expected first argument to be an options object');
14151
-
14152
- // Interpret and validate options
14153
- const attachedName = 'attached' in options ? options.attached : 'main';
14154
- if (typeof attachedName !== 'string') throw new TypeError('Expected the "attached" option to be a string');
14155
- if (!attachedName) throw new TypeError('The "attached" option cannot be an empty string');
14156
- return this[cppdb].serialize(attachedName);
14157
- };
14158
- return serialize;
14159
- }
14160
-
14161
- var _function;
14162
- var hasRequired_function;
14163
- function require_function() {
14164
- if (hasRequired_function) return _function;
14165
- hasRequired_function = 1;
14166
- const {
14167
- getBooleanOption,
14168
- cppdb
14169
- } = requireUtil();
14170
- _function = function defineFunction(name, options, fn) {
14171
- // Apply defaults
14172
- if (options == null) options = {};
14173
- if (typeof options === 'function') {
14174
- fn = options;
14175
- options = {};
14176
- }
14177
-
14178
- // Validate arguments
14179
- if (typeof name !== 'string') throw new TypeError('Expected first argument to be a string');
14180
- if (typeof fn !== 'function') throw new TypeError('Expected last argument to be a function');
14181
- if (typeof options !== 'object') throw new TypeError('Expected second argument to be an options object');
14182
- if (!name) throw new TypeError('User-defined function name cannot be an empty string');
14183
-
14184
- // Interpret options
14185
- const safeIntegers = 'safeIntegers' in options ? +getBooleanOption(options, 'safeIntegers') : 2;
14186
- const deterministic = getBooleanOption(options, 'deterministic');
14187
- const directOnly = getBooleanOption(options, 'directOnly');
14188
- const varargs = getBooleanOption(options, 'varargs');
14189
- let argCount = -1;
14190
-
14191
- // Determine argument count
14192
- if (!varargs) {
14193
- argCount = fn.length;
14194
- if (!Number.isInteger(argCount) || argCount < 0) throw new TypeError('Expected function.length to be a positive integer');
14195
- if (argCount > 100) throw new RangeError('User-defined functions cannot have more than 100 arguments');
14196
- }
14197
- this[cppdb].function(fn, name, argCount, safeIntegers, deterministic, directOnly);
14198
- return this;
14199
- };
14200
- return _function;
14201
- }
14202
-
14203
- var aggregate;
14204
- var hasRequiredAggregate;
14205
- function requireAggregate() {
14206
- if (hasRequiredAggregate) return aggregate;
14207
- hasRequiredAggregate = 1;
14208
- const {
14209
- getBooleanOption,
14210
- cppdb
14211
- } = requireUtil();
14212
- aggregate = function defineAggregate(name, options) {
14213
- // Validate arguments
14214
- if (typeof name !== 'string') throw new TypeError('Expected first argument to be a string');
14215
- if (typeof options !== 'object' || options === null) throw new TypeError('Expected second argument to be an options object');
14216
- if (!name) throw new TypeError('User-defined function name cannot be an empty string');
14217
-
14218
- // Interpret options
14219
- const start = 'start' in options ? options.start : null;
14220
- const step = getFunctionOption(options, 'step', true);
14221
- const inverse = getFunctionOption(options, 'inverse', false);
14222
- const result = getFunctionOption(options, 'result', false);
14223
- const safeIntegers = 'safeIntegers' in options ? +getBooleanOption(options, 'safeIntegers') : 2;
14224
- const deterministic = getBooleanOption(options, 'deterministic');
14225
- const directOnly = getBooleanOption(options, 'directOnly');
14226
- const varargs = getBooleanOption(options, 'varargs');
14227
- let argCount = -1;
14228
-
14229
- // Determine argument count
14230
- if (!varargs) {
14231
- argCount = Math.max(getLength(step), inverse ? getLength(inverse) : 0);
14232
- if (argCount > 0) argCount -= 1;
14233
- if (argCount > 100) throw new RangeError('User-defined functions cannot have more than 100 arguments');
14234
- }
14235
- this[cppdb].aggregate(start, step, inverse, result, name, argCount, safeIntegers, deterministic, directOnly);
14236
- return this;
14237
- };
14238
- const getFunctionOption = (options, key, required) => {
14239
- const value = key in options ? options[key] : null;
14240
- if (typeof value === 'function') return value;
14241
- if (value != null) throw new TypeError(`Expected the "${key}" option to be a function`);
14242
- if (required) throw new TypeError(`Missing required option "${key}"`);
14243
- return null;
14244
- };
14245
- const getLength = ({
14246
- length
14247
- }) => {
14248
- if (Number.isInteger(length) && length >= 0) return length;
14249
- throw new TypeError('Expected function.length to be a positive integer');
14250
- };
14251
- return aggregate;
14252
- }
14253
-
14254
- var table;
14255
- var hasRequiredTable;
14256
- function requireTable() {
14257
- if (hasRequiredTable) return table;
14258
- hasRequiredTable = 1;
14259
- const {
14260
- cppdb
14261
- } = requireUtil();
14262
- table = function defineTable(name, factory) {
14263
- // Validate arguments
14264
- if (typeof name !== 'string') throw new TypeError('Expected first argument to be a string');
14265
- if (!name) throw new TypeError('Virtual table module name cannot be an empty string');
14266
-
14267
- // Determine whether the module is eponymous-only or not
14268
- let eponymous = false;
14269
- if (typeof factory === 'object' && factory !== null) {
14270
- eponymous = true;
14271
- factory = defer(parseTableDefinition(factory, 'used', name));
14272
- } else {
14273
- if (typeof factory !== 'function') throw new TypeError('Expected second argument to be a function or a table definition object');
14274
- factory = wrapFactory(factory);
14275
- }
14276
- this[cppdb].table(factory, name, eponymous);
14277
- return this;
14278
- };
14279
- function wrapFactory(factory) {
14280
- return function virtualTableFactory(moduleName, databaseName, tableName, ...args) {
14281
- const thisObject = {
14282
- module: moduleName,
14283
- database: databaseName,
14284
- table: tableName
14285
- };
14286
-
14287
- // Generate a new table definition by invoking the factory
14288
- const def = apply.call(factory, thisObject, args);
14289
- if (typeof def !== 'object' || def === null) {
14290
- throw new TypeError(`Virtual table module "${moduleName}" did not return a table definition object`);
14291
- }
14292
- return parseTableDefinition(def, 'returned', moduleName);
14293
- };
14294
- }
14295
- function parseTableDefinition(def, verb, moduleName) {
14296
- // Validate required properties
14297
- if (!hasOwnProperty.call(def, 'rows')) {
14298
- throw new TypeError(`Virtual table module "${moduleName}" ${verb} a table definition without a "rows" property`);
14299
- }
14300
- if (!hasOwnProperty.call(def, 'columns')) {
14301
- throw new TypeError(`Virtual table module "${moduleName}" ${verb} a table definition without a "columns" property`);
14302
- }
14303
-
14304
- // Validate "rows" property
14305
- const rows = def.rows;
14306
- if (typeof rows !== 'function' || Object.getPrototypeOf(rows) !== GeneratorFunctionPrototype) {
14307
- throw new TypeError(`Virtual table module "${moduleName}" ${verb} a table definition with an invalid "rows" property (should be a generator function)`);
14308
- }
14309
-
14310
- // Validate "columns" property
14311
- let columns = def.columns;
14312
- if (!Array.isArray(columns) || !isStringArray(columns = [...columns])) {
14313
- throw new TypeError(`Virtual table module "${moduleName}" ${verb} a table definition with an invalid "columns" property (should be an array of strings)`);
14314
- }
14315
- if (columns.length !== new Set(columns).size) {
14316
- throw new TypeError(`Virtual table module "${moduleName}" ${verb} a table definition with duplicate column names`);
14317
- }
14318
- if (!columns.length) {
14319
- throw new RangeError(`Virtual table module "${moduleName}" ${verb} a table definition with zero columns`);
14320
- }
14321
-
14322
- // Validate "parameters" property
14323
- let parameters;
14324
- if (hasOwnProperty.call(def, 'parameters')) {
14325
- parameters = def.parameters;
14326
- if (!Array.isArray(parameters) || !isStringArray(parameters = [...parameters])) {
14327
- throw new TypeError(`Virtual table module "${moduleName}" ${verb} a table definition with an invalid "parameters" property (should be an array of strings)`);
14328
- }
14329
- } else {
14330
- parameters = inferParameters(rows);
14331
- }
14332
- if (parameters.length !== new Set(parameters).size) {
14333
- throw new TypeError(`Virtual table module "${moduleName}" ${verb} a table definition with duplicate parameter names`);
14334
- }
14335
- if (parameters.length > 32) {
14336
- throw new RangeError(`Virtual table module "${moduleName}" ${verb} a table definition with more than the maximum number of 32 parameters`);
14337
- }
14338
- for (const parameter of parameters) {
14339
- if (columns.includes(parameter)) {
14340
- throw new TypeError(`Virtual table module "${moduleName}" ${verb} a table definition with column "${parameter}" which was ambiguously defined as both a column and parameter`);
14341
- }
14342
- }
14343
-
14344
- // Validate "safeIntegers" option
14345
- let safeIntegers = 2;
14346
- if (hasOwnProperty.call(def, 'safeIntegers')) {
14347
- const bool = def.safeIntegers;
14348
- if (typeof bool !== 'boolean') {
14349
- throw new TypeError(`Virtual table module "${moduleName}" ${verb} a table definition with an invalid "safeIntegers" property (should be a boolean)`);
14350
- }
14351
- safeIntegers = +bool;
14352
- }
14353
-
14354
- // Validate "directOnly" option
14355
- let directOnly = false;
14356
- if (hasOwnProperty.call(def, 'directOnly')) {
14357
- directOnly = def.directOnly;
14358
- if (typeof directOnly !== 'boolean') {
14359
- throw new TypeError(`Virtual table module "${moduleName}" ${verb} a table definition with an invalid "directOnly" property (should be a boolean)`);
14360
- }
14361
- }
14362
-
14363
- // Generate SQL for the virtual table definition
14364
- const columnDefinitions = [...parameters.map(identifier).map(str => `${str} HIDDEN`), ...columns.map(identifier)];
14365
- return [`CREATE TABLE x(${columnDefinitions.join(', ')});`, wrapGenerator(rows, new Map(columns.map((x, i) => [x, parameters.length + i])), moduleName), parameters, safeIntegers, directOnly];
14366
- }
14367
- function wrapGenerator(generator, columnMap, moduleName) {
14368
- return function* virtualTable(...args) {
14369
- /*
14370
- We must defensively clone any buffers in the arguments, because
14371
- otherwise the generator could mutate one of them, which would cause
14372
- us to return incorrect values for hidden columns, potentially
14373
- corrupting the database.
14374
- */
14375
- const output = args.map(x => Buffer.isBuffer(x) ? Buffer.from(x) : x);
14376
- for (let i = 0; i < columnMap.size; ++i) {
14377
- output.push(null); // Fill with nulls to prevent gaps in array (v8 optimization)
14378
- }
14379
- for (const row of generator(...args)) {
14380
- if (Array.isArray(row)) {
14381
- extractRowArray(row, output, columnMap.size, moduleName);
14382
- yield output;
14383
- } else if (typeof row === 'object' && row !== null) {
14384
- extractRowObject(row, output, columnMap, moduleName);
14385
- yield output;
14386
- } else {
14387
- throw new TypeError(`Virtual table module "${moduleName}" yielded something that isn't a valid row object`);
14388
- }
14389
- }
14390
- };
14391
- }
14392
- function extractRowArray(row, output, columnCount, moduleName) {
14393
- if (row.length !== columnCount) {
14394
- throw new TypeError(`Virtual table module "${moduleName}" yielded a row with an incorrect number of columns`);
14395
- }
14396
- const offset = output.length - columnCount;
14397
- for (let i = 0; i < columnCount; ++i) {
14398
- output[i + offset] = row[i];
14399
- }
14400
- }
14401
- function extractRowObject(row, output, columnMap, moduleName) {
14402
- let count = 0;
14403
- for (const key of Object.keys(row)) {
14404
- const index = columnMap.get(key);
14405
- if (index === undefined) {
14406
- throw new TypeError(`Virtual table module "${moduleName}" yielded a row with an undeclared column "${key}"`);
14407
- }
14408
- output[index] = row[key];
14409
- count += 1;
14410
- }
14411
- if (count !== columnMap.size) {
14412
- throw new TypeError(`Virtual table module "${moduleName}" yielded a row with missing columns`);
14413
- }
14414
- }
14415
- function inferParameters({
14416
- length
14417
- }) {
14418
- if (!Number.isInteger(length) || length < 0) {
14419
- throw new TypeError('Expected function.length to be a positive integer');
14420
- }
14421
- const params = [];
14422
- for (let i = 0; i < length; ++i) {
14423
- params.push(`$${i + 1}`);
14424
- }
14425
- return params;
14426
- }
14427
- const {
14428
- hasOwnProperty
14429
- } = Object.prototype;
14430
- const {
14431
- apply
14432
- } = Function.prototype;
14433
- const GeneratorFunctionPrototype = Object.getPrototypeOf(function* () {});
14434
- const identifier = str => `"${str.replace(/"/g, '""')}"`;
14435
- const defer = x => () => x;
14436
- const isStringArray = arr => {
14437
- for (let i = 0; i < arr.length; ++i) {
14438
- if (typeof arr[i] !== 'string') return false;
14439
- }
14440
- return true;
14441
- };
14442
- return table;
14443
- }
14444
-
14445
- var inspect;
14446
- var hasRequiredInspect;
14447
- function requireInspect() {
14448
- if (hasRequiredInspect) return inspect;
14449
- hasRequiredInspect = 1;
14450
- const DatabaseInspection = function Database() {};
14451
- inspect = function inspect(depth, opts) {
14452
- return Object.assign(new DatabaseInspection(), this);
14453
- };
14454
- return inspect;
14455
- }
14456
-
14457
- var database;
14458
- var hasRequiredDatabase;
14459
- function requireDatabase() {
14460
- if (hasRequiredDatabase) return database;
14461
- hasRequiredDatabase = 1;
14462
- const fs = require$$0;
14463
- const path = require$$1;
14464
- const util = requireUtil();
14465
- const SqliteError = requireSqliteError();
14466
- database = function createDatabase(getAddon, allowNativeBinding) {
14467
- function Database(filenameGiven, options) {
14468
- if (new.target == null) {
14469
- return new Database(filenameGiven, options);
14470
- }
14471
-
14472
- // Apply defaults
14473
- let buffer;
14474
- if (Buffer.isBuffer(filenameGiven)) {
14475
- buffer = filenameGiven;
14476
- filenameGiven = ':memory:';
14477
- }
14478
- if (filenameGiven == null) filenameGiven = '';
14479
- if (options == null) options = {};
14480
-
14481
- // Validate arguments
14482
- if (typeof filenameGiven !== 'string') throw new TypeError('Expected first argument to be a string');
14483
- if (typeof options !== 'object') throw new TypeError('Expected second argument to be an options object');
14484
- if ('readOnly' in options) throw new TypeError('Misspelled option "readOnly" should be "readonly"');
14485
- if ('memory' in options) throw new TypeError('Option "memory" was removed in v7.0.0 (use ":memory:" filename instead)');
14486
-
14487
- // Interpret options
14488
- const filename = filenameGiven.trim();
14489
- const anonymous = filename === '' || filename === ':memory:';
14490
- const readonly = util.getBooleanOption(options, 'readonly');
14491
- const fileMustExist = util.getBooleanOption(options, 'fileMustExist');
14492
- const timeout = 'timeout' in options ? options.timeout : 5000;
14493
- const verbose = 'verbose' in options ? options.verbose : null;
14494
- const nativeBinding = 'nativeBinding' in options ? options.nativeBinding : null;
14495
-
14496
- // Validate interpreted options
14497
- if (readonly && anonymous && !buffer) throw new TypeError('In-memory/temporary databases cannot be readonly');
14498
- if (!Number.isInteger(timeout) || timeout < 0) throw new TypeError('Expected the "timeout" option to be a positive integer');
14499
- if (timeout > 0x7fffffff) throw new RangeError('Option "timeout" cannot be greater than 2147483647');
14500
- if (verbose != null && typeof verbose !== 'function') throw new TypeError('Expected the "verbose" option to be a function');
14501
- if (!allowNativeBinding && 'nativeBinding' in options) throw new TypeError('The "nativeBinding" option is only supported by the default better-sqlite3 entrypoint');
14502
- if (allowNativeBinding && nativeBinding != null && typeof nativeBinding !== 'string' && typeof nativeBinding !== 'object') throw new TypeError('Expected the "nativeBinding" option to be a string or addon object');
14503
-
14504
- // Load the native addon
14505
- const addon = getAddon(nativeBinding);
14506
- if (!addon.isInitialized) {
14507
- addon.initialize(SqliteError, arrayFactory, arrayAppender, rowFactory, recordFactory);
14508
- addon.isInitialized = true;
14509
- }
14510
-
14511
- // Make sure the specified directory exists
14512
- if (!anonymous && !filename.startsWith('file:') && !fs.existsSync(path.dirname(filename))) {
14513
- throw new TypeError('Cannot open database because the directory does not exist');
14514
- }
14515
- Object.defineProperties(this, {
14516
- [util.cppdb]: {
14517
- value: new addon.Database(filename, filenameGiven, anonymous, readonly, fileMustExist, timeout, verbose || null, buffer || null)
14518
- },
14519
- ...wrappers.getters
14520
- });
14521
- }
14522
- const wrappers = requireWrappers();
14523
- Database.prototype.prepare = wrappers.prepare;
14524
- Database.prototype.transaction = requireTransaction();
14525
- Database.prototype.pragma = requirePragma();
14526
- Database.prototype.explain = requireExplain();
14527
- Database.prototype.backup = requireBackup();
14528
- Database.prototype.serialize = requireSerialize();
14529
- Database.prototype.function = require_function();
14530
- Database.prototype.aggregate = requireAggregate();
14531
- Database.prototype.table = requireTable();
14532
- Database.prototype.loadExtension = wrappers.loadExtension;
14533
- Database.prototype.exec = wrappers.exec;
14534
- Database.prototype.close = wrappers.close;
14535
- Database.prototype.defaultSafeIntegers = wrappers.defaultSafeIntegers;
14536
- Database.prototype.unsafeMode = wrappers.unsafeMode;
14537
- Database.prototype[util.inspect] = requireInspect();
14538
- return Database;
14539
- };
14540
- function arrayFactory(...values) {
14541
- return values;
14542
- }
14543
- function arrayAppender(array, ...values) {
14544
- const offset = array.length;
14545
- for (let i = 0; i < values.length; ++i) {
14546
- array[offset + i] = values[i];
14547
- }
14548
- }
14549
- function rowFactory(...keys) {
14550
- if (!keys.includes('__proto__')) {
14551
- const parameters = keys.map((_, index) => `v${index}`).join(',');
14552
- const properties = keys.map((key, index) => `${JSON.stringify(key)}:v${index}`).join(',');
14553
- return Function(`return (${parameters}) => ({${properties}})`)();
14554
- }
14555
- return (...values) => {
14556
- const row = {};
14557
- for (let i = 0; i < keys.length; ++i) row[keys[i]] = values[i];
14558
- return row;
14559
- };
14560
- }
14561
- function recordFactory(value) {
14562
- return {
14563
- value,
14564
- done: false
14565
- };
14566
- }
14567
- return database;
14568
- }
14569
-
14570
- function commonjsRequire(path) {
14571
- throw new Error('Could not dynamically require "' + path + '". Please configure the dynamicRequireTargets or/and ignoreDynamicRequires option of @rollup/plugin-commonjs appropriately for this require call to work.');
14572
- }
14573
-
14574
- var binding = {exports: {}};
14575
-
14576
- var hasRequiredBinding;
14577
- function requireBinding() {
14578
- if (hasRequiredBinding) return binding.exports;
14579
- hasRequiredBinding = 1;
14580
- (function (module, exports) {
14581
-
14582
- const fs = require$$0;
14583
- const path = require$$1;
14584
- const PREBUILD_PLATFORMS = ['linux', 'darwin', 'win32'];
14585
- const PREBUILD_ARCHS = ['x64', 'arm64'];
14586
- let DEFAULT_ADDON;
14587
- function getBinding(nativeBinding) {
14588
- // If a path was provided, load the binding from the filesystem.
14589
- if (typeof nativeBinding === 'string') {
14590
- // See <https://webpack.js.org/api/module-variables/#__non_webpack_require__-webpack-specific>
14591
- const requireFunc = typeof __non_webpack_require__ === 'function' ? __non_webpack_require__ : commonjsRequire;
14592
- return requireFunc(path.resolve(nativeBinding).replace(/(\.node)?$/, '.node'));
14593
- }
14594
-
14595
- // If an object was provided, use it as the binding directly.
14596
- if (typeof nativeBinding === 'object' && nativeBinding !== null) {
14597
- return nativeBinding;
14598
- }
14599
-
14600
- // If we're using the default binding and it already exists, just return it.
14601
- if (DEFAULT_ADDON) {
14602
- return DEFAULT_ADDON;
14603
- }
14604
-
14605
- // Otherwise, try to find the binding as a prebuilt binary.
14606
- let filename = getPrebuildPath();
14607
- if (filename) {
14608
- return DEFAULT_ADDON = commonjsRequire(filename);
14609
- }
14610
-
14611
- // If no prebuilt binary was found, try the default node-gyp locations.
14612
- filename = path.join(__dirname, '..', 'build', 'Debug', 'better_sqlite3.node');
14613
- if (!fs.existsSync(filename)) {
14614
- filename = path.join(__dirname, '..', 'build', 'Release', 'better_sqlite3.node');
14615
- }
14616
- return DEFAULT_ADDON = commonjsRequire(filename);
14617
- }
14618
- function getPrebuildPath() {
14619
- if (PREBUILD_PLATFORMS.includes(process.platform) && PREBUILD_ARCHS.includes(process.arch)) {
14620
- const target = `${isLinuxMusl() ? 'linuxmusl' : process.platform}-${process.arch}`;
14621
- const filename = path.join(__dirname, '..', 'prebuilds', `${target}.node`);
14622
- if (fs.existsSync(filename)) {
14623
- return filename;
14624
- }
14625
- }
14626
- return null;
14627
- }
14628
- function isLinuxMusl() {
14629
- return process.platform === 'linux' && !process.report.getReport().header.glibcVersionRuntime;
14630
- }
14631
- exports.getBinding = getBinding;
14632
- exports.getPrebuildPath = getPrebuildPath;
14633
-
14634
- // This script is executed directly by binding.gyp to detect prebuilt binaries.
14635
- if (require.main === module) {
14636
- process.stdout.write(getPrebuildPath() ? '1' : '0');
14637
- }
14638
- })(binding, binding.exports);
14639
- return binding.exports;
14640
- }
14641
-
14642
- var hasRequiredLib;
14643
- function requireLib() {
14644
- if (hasRequiredLib) return lib.exports;
14645
- hasRequiredLib = 1;
14646
- lib.exports = requireDatabase()(requireBinding().getBinding, true);
14647
- lib.exports.SqliteError = requireSqliteError();
14648
- return lib.exports;
14649
- }
14650
-
14651
- var libExports = requireLib();
14652
- var Database = /*@__PURE__*/getDefaultExportFromCjs(libExports);
14653
-
14654
- /**
14655
- *
14656
- */
14657
- class SQLiteResult {
14658
- /**
14659
- * @param {Error|null|undefined} error
14660
- * @param {number|undefined} [insertId]
14661
- * @param {number} [rowsAffected]
14662
- * @param {object[]} [rows]
14663
- */
14664
- constructor(error, insertId, rowsAffected, rows) {
14665
- this.error = error;
14666
- this.insertId = insertId;
14667
- this.rowsAffected = rowsAffected;
14668
- this.rows = rows;
14669
- }
14670
- }
14671
- const READ_ONLY_ERROR = new Error('could not prepare statement (23 not authorized)');
14672
-
14673
- /**
14674
- * @typedef {(sql: string, duration: number) => void} SQLProfileCallback
14675
- */
14676
-
14677
- /**
14678
- * @typedef {((sql: string) => void)|undefined} SQLTraceCallback
14679
- */
14680
-
14681
- // Two separate `better-sqlite3` connections (i.e., two separate
14682
- // `SQLiteDatabase` instances) can legitimately point at the same
14683
- // underlying file at once -- e.g. an old, about-to-close IndexedDB
14684
- // connection and a newly-opened one during an upgrade. `PRAGMA
14685
- // busy_timeout` can't safely arbitrate between them here: it blocks the
14686
- // single JS thread synchronously while it retries, but the lock holder's
14687
- // own release is itself scheduled via `setImmediate` below, which can
14688
- // never fire while that retry loop is blocking the same thread -- so
14689
- // instead of waiting, a second connection's write just fails with
14690
- // "database is locked".
14691
- //
14692
- // `fileReaders`/`fileWriter` implement a simple (not starvation-proof --
14693
- // see the release loop below) reader/writer lock per file path instead:
14694
- // any number of `readonly` transactions may hold the file concurrently,
14695
- // matching what SQLite itself already natively supports (multiple
14696
- // readers never need to exclude each other, only a writer needs
14697
- // exclusivity), while a non-`readonly` transaction still waits for
14698
- // exclusive access -- no concurrent readers, no concurrent writer. A
14699
- // simple single-owner mutex (this file's prior implementation) would
14700
- // otherwise serialize even purely-concurrent-reader scenarios that
14701
- // never touch a writer at all, for no reason `better-sqlite3`/SQLite
14702
- // itself requires.
14703
- /** @type {Map<string, Set<{_db: any, _qFilePath: string}>>} */
14704
- const fileReaders = new Map();
14705
- /** @type {Map<string, {_db: any, _qFilePath: string}>} */
14706
- const fileWriter = new Map();
14707
- /** @type {Map<string, {isReader: boolean, resume: () => void}[]>} */
14708
- const fileWaiters = new Map();
14709
- const beginRe = /^\s*BEGIN\b/iu;
14710
- const endRe = /^\s*(END|COMMIT|ROLLBACK)\b/iu;
14711
-
14712
- /**
14713
- * @class
14714
- * @param {string} name
14715
- * @param {{busyTimeout?: number, trace?: (sql: string) => void, profile?: SQLProfileCallback}} [opts]
14716
- * @this {{_db: any, _qFilePath: string}}
14717
- * @returns {void}
14718
- */
14719
- function SQLiteDatabase(name, opts = {}) {
14720
- this._qFilePath = name;
14721
- /** @type {import('better-sqlite3').Database} */
14722
- const db = new Database(name);
14723
-
14724
- /** @type {SQLTraceCallback} */
14725
- // eslint-disable-next-line prefer-destructuring -- TS
14726
- let trace = opts.trace;
14727
- /** @type {SQLProfileCallback|undefined} */
14728
- // eslint-disable-next-line prefer-destructuring -- TS
14729
- let profile = opts.profile;
14730
- if (opts.busyTimeout) {
14731
- db.pragma('busy_timeout = ' + Number(opts.busyTimeout));
14732
- }
14733
-
14734
- // Kept untyped (rather than the better-sqlite3 `Database` type) since that
14735
- // type is internal to `@types/better-sqlite3` and can't be named in this
14736
- // file's emitted declaration.
14737
- this._db = /** @type {any} */{
14738
- _db: db,
14739
- /**
14740
- * Compatibility with node-sqlite3's configure API.
14741
- * @param {'busyTimeout'|'trace'|'profile'|'memoryQuota'} option
14742
- * @param {number|((sql: string, duration?: number) => void)} value
14743
- * @returns {void}
14744
- */
14745
- configure(option, value) {
14746
- if (option === 'busyTimeout') {
14747
- db.pragma('busy_timeout = ' + Number(/** @type {number} */value));
14748
- return;
14749
- }
14750
- if (option === 'trace') {
14751
- trace = /** @type {(sql: string) => void} */value;
14752
- return;
14753
- }
14754
- if (option === 'profile') {
14755
- profile = /** @type {SQLProfileCallback} */value;
14756
- return;
14757
- }
14758
- if (option === 'memoryQuota') {
14759
- const bytes = Number(value);
14760
- // `better-sqlite3` doesn't have a direct `sqlite3_quota_set` binding,
14761
- // but we can limit the max pages:
14762
- const pageSizeObj = db.pragma('page_size', {
14763
- simple: true
14764
- });
14765
- const pageSize = Number(pageSizeObj);
14766
- db.pragma('max_page_count = ' + Math.ceil(bytes / pageSize));
14767
- }
14768
- },
14769
- /**
14770
- * Compatibility with callback-oriented close semantics.
14771
- * @param {(err?: Error|null) => void} [cb]
14772
- * @returns {void}
14773
- */
14774
- close(cb) {
14775
- try {
14776
- db.close();
14777
- if (cb) {
14778
- return cb(null);
14779
- }
14780
- } catch (err) {
14781
- if (cb) {
14782
- return cb(/** @type {Error} */err);
14783
- }
14784
- }
14785
- return undefined;
14786
- },
14787
- getTrace() {
14788
- return trace;
14789
- },
14790
- getProfile() {
14791
- return profile;
14792
- }
14793
- };
14794
- }
14795
-
14796
- /**
14797
- * @param {import('better-sqlite3').Database} db
14798
- * @param {string} sql
14799
- * @param {unknown[]} args
14800
- * @returns {object[]}
14801
- */
14802
- function runSelect(db, sql, args) {
14803
- const stmt = db.prepare(sql);
14804
- return stmt.reader ? (/** @type {object[]} */stmt.all(...args)) : [];
14805
- }
14806
-
14807
- /**
14808
- * @param {import('better-sqlite3').Database} db
14809
- * @param {string} sql
14810
- * @param {unknown[]} args
14811
- * @returns {import('better-sqlite3').RunResult}
14812
- */
14813
- function runNonSelect(db, sql, args) {
14814
- const stmt = db.prepare(sql);
14815
- return stmt.run(...args);
14816
- }
14817
-
14818
- /**
14819
- * @param {{sql: string, args: unknown[]}[]} queries
14820
- * @param {boolean} readOnly
14821
- * @param {(err: Error|null, results?: SQLiteResult[]) => void} callback
14822
- * @returns {void}
14823
- */
14824
- SQLiteDatabase.prototype.exec = function exec(queries, readOnly, callback) {
14825
- // `:memory:` (SQLite/`better-sqlite3`'s own sentinel for an isolated,
14826
- // non-shared in-memory database) can never actually collide with a
14827
- // different connection -- each `new Database(':memory:')` call is
14828
- // already fully independent -- so there is nothing to serialize.
14829
- const filePath = this._qFilePath === ':memory:' ? null : this._qFilePath;
14830
- if (filePath && queries[0] && beginRe.test(queries[0].sql)) {
14831
- const activeReaders = fileReaders.get(filePath);
14832
- const hasActiveReaders = Boolean(activeReaders && activeReaders.size);
14833
- const activeWriter = fileWriter.get(filePath);
14834
- const blockedByWriter = Boolean(activeWriter && activeWriter !== this);
14835
- const blocked = blockedByWriter || !readOnly && hasActiveReaders;
14836
- if (blocked) {
14837
- const waiters = fileWaiters.get(filePath) || [];
14838
- waiters.push({
14839
- isReader: readOnly,
14840
- resume: () => this.exec(queries, readOnly, callback)
14841
- });
14842
- fileWaiters.set(filePath, waiters);
14843
- return;
14844
- }
14845
- if (readOnly) {
14846
- if (activeReaders) {
14847
- activeReaders.add(this);
14848
- } else {
14849
- fileReaders.set(filePath, new Set([this]));
14850
- }
14851
- } else {
14852
- fileWriter.set(filePath, this);
14853
- }
14854
- }
14855
- const db = this._db._db;
14856
- const len = queries.length;
14857
- const results = Array.from({
14858
- length: len
14859
- });
14860
- for (let i = 0; i < len; i++) {
14861
- const query = queries[i];
14862
- const {
14863
- sql,
14864
- args
14865
- } = query;
14866
- const isSelect = /^\s*SELECT\b/iu.test(sql);
14867
- if (readOnly && !isSelect) {
14868
- results[i] = new SQLiteResult(READ_ONLY_ERROR);
14869
- continue;
14870
- }
14871
- const trace = this._db.getTrace();
14872
- const profile = this._db.getProfile();
14873
- // eslint-disable-next-line unicorn/prefer-bigint-literals -- `0n` needs ES2020+ target for tsc
14874
- const start = profile ? process.hrtime.bigint() : BigInt(0);
14875
- try {
14876
- if (trace) {
14877
- trace(sql);
14878
- }
14879
- if (isSelect) {
14880
- const rows = runSelect(db, sql, args);
14881
- results[i] = new SQLiteResult(null, undefined, 0, rows);
14882
- } else {
14883
- const executionResult = runNonSelect(db, sql, args);
14884
- const insertId = Number(executionResult.lastInsertRowid);
14885
- results[i] = new SQLiteResult(null, insertId, executionResult.changes, []);
14886
- }
14887
- } catch (err) {
14888
- results[i] = new SQLiteResult(/** @type {Error} */err);
14889
- } finally {
14890
- if (profile) {
14891
- profile(sql, Number(process.hrtime.bigint() - start));
14892
- }
14893
- }
14894
- }
14895
- // A real macrotask (not `queueMicrotask`) so this yields properly:
14896
- // code that synchronously issues a new request from within each
14897
- // request's callback (e.g. to keep a transaction alive) would
14898
- // otherwise chain microtask to microtask forever, starving out any
14899
- // `setTimeout`-based code (including IndexedDB's own internal request
14900
- // scheduling) that never gets a turn to run. `setImmediate` (Node's
14901
- // "check" phase) still yields the same way `setTimeout(..., 0)` did,
14902
- // but runs sooner in Node's event loop.
14903
- setImmediate(() => {
14904
- // Release the file lock (if held) and hand it to the next waiting
14905
- // connection, if any, only once this transaction has genuinely
14906
- // finished -- and only here, on its own turn, so a resumed
14907
- // waiter's own `exec` call can't run reentrantly inside this one.
14908
- // Checked across the whole batch, not just `queries[0]`: when a
14909
- // transaction's `BEGIN` and its later `ROLLBACK`/`COMMIT` are both
14910
- // queued synchronously before `websql-configurable`'s async flush
14911
- // gets a turn to run (e.g. an immediate `transaction.abort()`
14912
- // inside `onupgradeneeded`), they arrive coalesced into a single
14913
- // batch/`exec()` call, with the terminal statement anywhere but
14914
- // first -- so only checking `queries[0]` would acquire the lock
14915
- // and never see the matching release, deadlocking every later
14916
- // connection to the same file.
14917
- if (filePath && queries.some(q => endRe.test(q.sql))) {
14918
- const activeReaders = fileReaders.get(filePath);
14919
- if (activeReaders) {
14920
- activeReaders.delete(this);
14921
- if (!activeReaders.size) {
14922
- fileReaders.delete(filePath);
14923
- }
14924
- }
14925
- if (fileWriter.get(filePath) === this) {
14926
- fileWriter.delete(filePath);
14927
- }
14928
- // Resume as many waiters as the lock now genuinely allows:
14929
- // any leading run of readers (concurrent reads are always
14930
- // fine), then at most one writer, since a writer needs
14931
- // exclusivity -- stop there rather than looking past it.
14932
- // Not starvation-proof: a steady stream of arriving readers
14933
- // could in principle keep a waiting writer waiting
14934
- // indefinitely, but that's an acceptable tradeoff here over
14935
- // the added complexity of tracking arrival order across
14936
- // reader/writer kinds.
14937
- const waiters = fileWaiters.get(filePath);
14938
- if (waiters) {
14939
- while (waiters.length) {
14940
- if (fileWriter.has(filePath)) {
14941
- break;
14942
- }
14943
- const next = waiters[0];
14944
- const stillHasReaders = fileReaders.get(filePath);
14945
- if (!next.isReader && stillHasReaders && stillHasReaders.size) {
14946
- break;
14947
- }
14948
- waiters.shift();
14949
- next.resume();
14950
- if (!next.isReader) {
14951
- // A writer just took exclusive ownership (inside
14952
- // `resume()`, synchronously, via the acquire
14953
- // logic above) -- nothing else may proceed now.
14954
- break;
14955
- }
14956
- }
14957
- if (!waiters.length) {
14958
- fileWaiters.delete(filePath);
14959
- }
14960
- }
14961
- }
14962
- callback(null, results);
14963
- });
14964
- };
14965
-
14966
12970
  /**
14967
12971
  * @typedef {{
14968
12972
  * _db: any,
@@ -14990,16 +12994,16 @@ function wrappedSQLiteDatabase(name) {
14990
12994
  // @ts-ignore It's ok; needed under some TS versions
14991
12995
  const db = new SQLiteDatabase(name, {});
14992
12996
  if (CFG.sqlBusyTimeout) {
14993
- db._db.configure('busyTimeout', /** @type {number} */CFG.sqlBusyTimeout); // Default is 1000
12997
+ db.configure('busyTimeout', /** @type {number} */CFG.sqlBusyTimeout); // Default is 1000
14994
12998
  }
14995
12999
  if (CFG.sqlTrace) {
14996
- db._db.configure('trace', CFG.sqlTrace);
13000
+ db.configure('trace', CFG.sqlTrace);
14997
13001
  }
14998
13002
  if (CFG.sqlProfile) {
14999
- db._db.configure('profile', CFG.sqlProfile);
13003
+ db.configure('profile', CFG.sqlProfile);
15000
13004
  }
15001
13005
  if (CFG.sqlMemoryQuota) {
15002
- db._db.configure('memoryQuota', /** @type {number} */CFG.sqlMemoryQuota);
13006
+ db.configure('memoryQuota', /** @type {number} */CFG.sqlMemoryQuota);
15003
13007
  }
15004
13008
  return db;
15005
13009
  }
@@ -15034,7 +13038,7 @@ CFG.win = {
15034
13038
  };
15035
13039
 
15036
13040
  /**
15037
- * @param {import('./setGlobalVars.js').ShimmedObject} [idb]
13041
+ * @param {typeof globalThis | Record<string, unknown>} [idb]
15038
13042
  * @param {Partial<import('./CFG.js').ConfigValues>} [initialConfig]
15039
13043
  * @returns {import('./setGlobalVars.js').ShimmedObject|Window}
15040
13044
  */