From c26b014aed88633d8d59642633ad7d93ec35a982 Mon Sep 17 00:00:00 2001 From: Ben Ashton Date: Tue, 2 Mar 2021 01:10:13 -0800 Subject: [PATCH] Initial commit --- .gitignore | 2 + lib/pawsqlite-websql-adapter.js | 444 ++++++++++++ lib/pawsqlite-websql-adapter.js.map | 1 + package-lock.json | 1030 +++++++++++++++++++++++++++ package.json | 20 + src/database_wrapper.mjs | 30 + src/log.mjs | 14 + src/response_wrapper.mjs | 8 + src/result_mapper.mjs | 22 + src/transaction_manager.mjs | 156 ++++ src/websql_adapter.mjs | 41 ++ src/websql_adapter_error.mjs | 9 + webpack.config.js | 18 + 13 files changed, 1795 insertions(+) create mode 100644 .gitignore create mode 100644 lib/pawsqlite-websql-adapter.js create mode 100644 lib/pawsqlite-websql-adapter.js.map create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 src/database_wrapper.mjs create mode 100644 src/log.mjs create mode 100644 src/response_wrapper.mjs create mode 100644 src/result_mapper.mjs create mode 100644 src/transaction_manager.mjs create mode 100644 src/websql_adapter.mjs create mode 100644 src/websql_adapter_error.mjs create mode 100644 webpack.config.js diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..eac252d --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +node_modules +.jshintrc \ No newline at end of file diff --git a/lib/pawsqlite-websql-adapter.js b/lib/pawsqlite-websql-adapter.js new file mode 100644 index 0000000..224e706 --- /dev/null +++ b/lib/pawsqlite-websql-adapter.js @@ -0,0 +1,444 @@ +/******/ (() => { // webpackBootstrap +/******/ "use strict"; +/******/ var __webpack_modules__ = ({ + +/***/ "./src/database_wrapper.mjs": +/*!**********************************!*\ + !*** ./src/database_wrapper.mjs ***! + \**********************************/ +/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => { + +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ "DatabaseWrapper": () => (/* binding */ DatabaseWrapper) +/* harmony export */ }); +/* harmony import */ var _transaction_manager_mjs__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./transaction_manager.mjs */ "./src/transaction_manager.mjs"); + + + +class DatabaseWrapper { + constructor(dbName, version) { + this.name = dbName; + this.db = openDatabase(this.name, version, "", 5 * 1024 * 1024); + this.transManager = new _transaction_manager_mjs__WEBPACK_IMPORTED_MODULE_0__.TransactionManager(this.db); + } + + sql(sql, ...args) { + const reg = /^\s*(BEGIN|END|COMMIT|ROLLBACK)(?:[^A-Z]|$)/i; + const match = reg.exec(sql); + if (match) { + const statement = match[1].toUpperCase(); + + switch(statement) { + case "BEGIN": + return this.transManager.begin(); + case "END": + case "COMMIT": + return this.transManager.commit(); + case "ROLLBACK": + return this.transManager.rollback(); + } + } else { + return this.transManager.sql(sql, args); + } + } +} + +/***/ }), + +/***/ "./src/log.mjs": +/*!*********************!*\ + !*** ./src/log.mjs ***! + \*********************/ +/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => { + +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ "log": () => (/* binding */ log), +/* harmony export */ "enableDebug": () => (/* binding */ enableDebug) +/* harmony export */ }); +let DEBUG = false; + +function log(...args) { + if (DEBUG) { + console.log(...args); + } +} + +function enableDebug(active) { + DEBUG = !!active; + log("PawSQLite-WebSQL-Adapter: debugging " + ( + DEBUG ? "enabled" : "disabled") + ); +} + +/***/ }), + +/***/ "./src/response_wrapper.mjs": +/*!**********************************!*\ + !*** ./src/response_wrapper.mjs ***! + \**********************************/ +/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => { + +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ "ResponseWrapper": () => (/* binding */ ResponseWrapper) +/* harmony export */ }); +const ResponseWrapper = { + success: (obj = {}) => ({ + success: true, + ...obj + }) +}; + + + + +/***/ }), + +/***/ "./src/result_mapper.mjs": +/*!*******************************!*\ + !*** ./src/result_mapper.mjs ***! + \*******************************/ +/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => { + +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ "mapResult": () => (/* binding */ mapResult) +/* harmony export */ }); +function mapResult(originalResult) { + const newResult = {}; + if (!originalResult) { + return newResult; + } + + try { + newResult.insertId = originalResult.insertId; + } catch (e) {} + + newResult.rowsAffected = originalResult.rowsAffected; + + if ("rows" in originalResult) { + newResult.rows = []; + + for (let i = 0; i < originalResult.rows.length; i++) { + newResult.rows.push(originalResult.rows.item(i)); + } + } + + return newResult; +} + +/***/ }), + +/***/ "./src/transaction_manager.mjs": +/*!*************************************!*\ + !*** ./src/transaction_manager.mjs ***! + \*************************************/ +/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => { + +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ "TransactionManager": () => (/* binding */ TransactionManager) +/* harmony export */ }); +/* harmony import */ var _websql_adapter_error_mjs__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./websql_adapter_error.mjs */ "./src/websql_adapter_error.mjs"); +/* harmony import */ var _result_mapper_mjs__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./result_mapper.mjs */ "./src/result_mapper.mjs"); +/* harmony import */ var _log_mjs__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./log.mjs */ "./src/log.mjs"); + + + + + +class Task { + constructor(job, startsTransaction=false, endsTransaction=false) { + this._job = job; + + if (startsTransaction && endsTransaction) { + throw new Error("Task cannot start and end a transaction."); + } + + this.startsTransaction = startsTransaction; + this.endsTransaction = endsTransaction; + + this.result = new Promise ((resolve, reject) => { + this._resolve = resolve; + this._reject = reject; + }); + } + + run(tx) { + return this._job(tx).then((result) => { + this._resolve(result); + return result; + }, (e) => { + this._reject(e); + }); + } +} + + +class TransactionManager { + constructor(db) { + this.db = db; + + this._txCount = 0; + this._tasks = []; + this._processing = false; + } + + begin() { + return this._addTask(new Task((tx) => { + return new Promise((resolve, reject) => { + if (tx) { + reject(new _websql_adapter_error_mjs__WEBPACK_IMPORTED_MODULE_0__.WebSQLAdapterError("BEGIN called with an active " + + "transaction. This should not happen")); + return; + } + this.db.transaction((tx) => { + resolve(tx); + }); + }); + }, true)).then(() => (0,_result_mapper_mjs__WEBPACK_IMPORTED_MODULE_1__.mapResult)()); + } + + sql(sql, args = []) { + return this._addTask(new Task((tx) => { + return this._executeSql(tx, sql, args); + })); + } + + commit() { + return this._addTask(new Task((tx) => { + return Promise.resolve((0,_result_mapper_mjs__WEBPACK_IMPORTED_MODULE_1__.mapResult)()); + }, false, true)); + } + + rollback() { + // Hack to manually cause rollback: + // Intentionally cause an error with rollbackOnError set to true + return this._addTask(new Task((tx) => { + return this._executeSql(tx, "", [], true).catch(() => (0,_result_mapper_mjs__WEBPACK_IMPORTED_MODULE_1__.mapResult)()); + }, false, true)); + } + + + async _process() { + if (this._processing) { + return; + } + this._processing = true; + + let tx = null; + let keepaliveCount = 0; + + while (true) { + const tasks = this._tasks; + this._tasks = []; + + + if (tasks.length) { + const promises = []; + + for (const task of tasks) { + const promise = task.run(tx); + + if (task.startsTransaction) { + tx = await promise; + this._txCount++; + } else { + if (task.endsTransaction) { + tx = null; + keepaliveCount = 0; + } + + promises.push(promise); + } + } + + await Promise.all(promises); + } else { + if (tx) { + await this._nop(tx); + keepaliveCount++; + if (keepaliveCount % 5000 === 0) { + (0,_log_mjs__WEBPACK_IMPORTED_MODULE_2__.log)(`Transaction: ${ this._txCount } Keepalive: #${ keepaliveCount }`); + } + } else { + break; + } + } + } + + this._processing = false; + } + + + _addTask(task) { + this._tasks.push(task); + this._process(); + return task.result; + } + + + _executeSql(tx, sql, sqlArgs = [], rollbackOnError = false) { + return new Promise((resolve, reject) => { + if (!tx) { + reject(new _websql_adapter_error_mjs__WEBPACK_IMPORTED_MODULE_0__.WebSQLAdapterError("No transaction. This should not be " + + " possible")); + return; + } + tx.executeSql(sql, sqlArgs, (tx, result) => { + resolve((0,_result_mapper_mjs__WEBPACK_IMPORTED_MODULE_1__.mapResult)(result)); + }, (tx, e) => { + reject(_websql_adapter_error_mjs__WEBPACK_IMPORTED_MODULE_0__.WebSQLAdapterError.from(e)); + return rollbackOnError; + }); + }); + } + + _nop(tx) { + return this._executeSql(tx, "SELECT 1"); + } +} + +/***/ }), + +/***/ "./src/websql_adapter_error.mjs": +/*!**************************************!*\ + !*** ./src/websql_adapter_error.mjs ***! + \**************************************/ +/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => { + +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ "WebSQLAdapterError": () => (/* binding */ WebSQLAdapterError) +/* harmony export */ }); +class WebSQLAdapterError extends Error { + static from(e) { + let message = ""; + if (e && e.message) { + message = e.message; + } + return new WebSQLAdapterError(message); + } +} + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The module cache +/******/ var __webpack_module_cache__ = {}; +/******/ +/******/ // The require function +/******/ function __webpack_require__(moduleId) { +/******/ // Check if module is in cache +/******/ if(__webpack_module_cache__[moduleId]) { +/******/ return __webpack_module_cache__[moduleId].exports; +/******/ } +/******/ // Create a new module (and put it into the cache) +/******/ var module = __webpack_module_cache__[moduleId] = { +/******/ // no module.id needed +/******/ // no module.loaded needed +/******/ exports: {} +/******/ }; +/******/ +/******/ // Execute the module function +/******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__); +/******/ +/******/ // Return the exports of the module +/******/ return module.exports; +/******/ } +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/define property getters */ +/******/ (() => { +/******/ // define getter functions for harmony exports +/******/ __webpack_require__.d = (exports, definition) => { +/******/ for(var key in definition) { +/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) { +/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] }); +/******/ } +/******/ } +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/hasOwnProperty shorthand */ +/******/ (() => { +/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)) +/******/ })(); +/******/ +/******/ /* webpack/runtime/make namespace object */ +/******/ (() => { +/******/ // define __esModule on exports +/******/ __webpack_require__.r = (exports) => { +/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { +/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); +/******/ } +/******/ Object.defineProperty(exports, '__esModule', { value: true }); +/******/ }; +/******/ })(); +/******/ +/************************************************************************/ +var __webpack_exports__ = {}; +// This entry need to be wrapped in an IIFE because it need to be isolated against other modules in the chunk. +(() => { +/*!********************************!*\ + !*** ./src/websql_adapter.mjs ***! + \********************************/ +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ "WebSQLAdapter": () => (/* binding */ WebSQLAdapter) +/* harmony export */ }); +/* harmony import */ var _websql_adapter_error_mjs__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./websql_adapter_error.mjs */ "./src/websql_adapter_error.mjs"); +/* harmony import */ var _database_wrapper_mjs__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./database_wrapper.mjs */ "./src/database_wrapper.mjs"); +/* harmony import */ var _response_wrapper_mjs__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./response_wrapper.mjs */ "./src/response_wrapper.mjs"); +/* harmony import */ var _log_mjs__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./log.mjs */ "./src/log.mjs"); + + + + + +const databases = new Map(); + +const WebSQLAdapter = { + open: async (dbName) => { + const version = "1.0"; + + if (!databases.has(dbName)) { + databases.set(dbName, new _database_wrapper_mjs__WEBPACK_IMPORTED_MODULE_1__.DatabaseWrapper(dbName, version)); + } + + return _response_wrapper_mjs__WEBPACK_IMPORTED_MODULE_2__.ResponseWrapper.success({ version }); + }, + + close: async (dbName) => { + databases.delete(dbName); + return _response_wrapper_mjs__WEBPACK_IMPORTED_MODULE_2__.ResponseWrapper.success(); + }, + + sql: async (dbName, sql, ...args) => { + (0,_log_mjs__WEBPACK_IMPORTED_MODULE_3__.log)(sql); + + const db = databases.get(dbName); + if (!db) { + throw new _websql_adapter_error_mjs__WEBPACK_IMPORTED_MODULE_0__.WebSQLAdapterError("Database not open"); + } + + const result = await db.sql(sql, ...args); + return _response_wrapper_mjs__WEBPACK_IMPORTED_MODULE_2__.ResponseWrapper.success(result); + }, + + delete: async (dbName) => { + throw new _websql_adapter_error_mjs__WEBPACK_IMPORTED_MODULE_0__.WebSQLAdapterError("Delete not implemented"); + }, + + debug: _log_mjs__WEBPACK_IMPORTED_MODULE_3__.enableDebug +}; + +})(); + +module.exports["pawsqlite-websql-adapter"] = __webpack_exports__.default; +/******/ })() +; +//# sourceMappingURL=pawsqlite-websql-adapter.js.map \ No newline at end of file diff --git a/lib/pawsqlite-websql-adapter.js.map b/lib/pawsqlite-websql-adapter.js.map new file mode 100644 index 0000000..df411b6 --- /dev/null +++ b/lib/pawsqlite-websql-adapter.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["webpack://pawsqlite-websql-adapter/./src/database_wrapper.mjs","webpack://pawsqlite-websql-adapter/./src/log.mjs","webpack://pawsqlite-websql-adapter/./src/response_wrapper.mjs","webpack://pawsqlite-websql-adapter/./src/result_mapper.mjs","webpack://pawsqlite-websql-adapter/./src/transaction_manager.mjs","webpack://pawsqlite-websql-adapter/./src/websql_adapter_error.mjs","webpack://pawsqlite-websql-adapter/webpack/bootstrap","webpack://pawsqlite-websql-adapter/webpack/runtime/define property getters","webpack://pawsqlite-websql-adapter/webpack/runtime/hasOwnProperty shorthand","webpack://pawsqlite-websql-adapter/webpack/runtime/make namespace object","webpack://pawsqlite-websql-adapter/./src/websql_adapter.mjs"],"names":[],"mappings":";;;;;;;;;;;;;;;AAA+D;;;AAGxD;AACP;AACA;AACA;AACA,4BAA4B,wEAAkB;AAC9C;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA,C;;;;;;;;;;;;;;;AC7BA;;AAEO;AACP;AACA;AACA,G;AACA;;AAEO;AACP;AACA;AACA;AACA;AACA,C;;;;;;;;;;;;;;ACbO;AACP,oBAAoB;AACpB;AACA;AACA,GAAG;AACH;;;;;;;;;;;;;;;;;ACLO;AACP;AACA;AACA;AACA;;AAEA;AACA;AACA,GAAG;;AAEH;;AAEA;AACA;;AAEA,mBAAmB,gCAAgC;AACnD;AACA;AACA;;AAEA;AACA,C;;;;;;;;;;;;;;;;;ACrBgE;AAChB;AAChB;;;AAGhC;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,KAAK;AACL;;AAEA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA,KAAK;AACL;AACA;;;AAGO;AACP;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,qBAAqB,yEAAkB;AACvC;AACA;AACA;AACA;AACA;AACA,SAAS;AACT,OAAO;AACP,KAAK,oBAAoB,6DAAS;AAClC;;AAEA;AACA;AACA;AACA,KAAK;AACL;;AAEA;AACA;AACA,6BAA6B,6DAAS;AACtC,KAAK;AACL;;AAEA;AACA;AACA;AACA;AACA,4DAA4D,6DAAS;AACrE,KAAK;AACL;;;AAGA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;;AAGA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,WAAW;AACX;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA,OAAO;AACP;AACA;AACA;AACA;AACA,YAAY,6CAAG,iBAAiB,gBAAgB,eAAe,iBAAiB;AAChF;AACA,SAAS;AACT;AACA;AACA;AACA;;AAEA;AACA;;;AAGA;AACA;AACA;AACA;AACA;;;AAGA;AACA;AACA;AACA,mBAAmB,yEAAkB;AACrC;AACA;AACA;AACA;AACA,gBAAgB,6DAAS;AACzB,OAAO;AACP,eAAe,8EAAuB;AACtC;AACA,OAAO;AACP,KAAK;AACL;;AAEA;AACA;AACA;AACA,C;;;;;;;;;;;;;;AC3JO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA,C;;;;;;UCRA;UACA;;UAEA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;;UAEA;UACA;;UAEA;UACA;UACA;;;;;WCrBA;WACA;WACA;WACA;WACA,wCAAwC,yCAAyC;WACjF;WACA;WACA,E;;;;;WCPA,wF;;;;;WCAA;WACA;WACA;WACA,sDAAsD,kBAAkB;WACxE;WACA,+CAA+C,cAAc;WAC7D,E;;;;;;;;;;;;;;;;;;ACNgE;AACP;AACA;AACZ;;AAE7C;;AAEO;AACP;AACA;;AAEA;AACA,gCAAgC,kEAAe;AAC/C;;AAEA,WAAW,0EAAuB,EAAE,UAAU;AAC9C,GAAG;;AAEH;AACA;AACA,WAAW,0EAAuB;AAClC,GAAG;;AAEH;AACA,IAAI,6CAAG;;AAEP;AACA;AACA,gBAAgB,yEAAkB;AAClC;;AAEA;AACA,WAAW,0EAAuB;AAClC,GAAG;;AAEH;AACA,cAAc,yEAAkB;AAChC,GAAG;;AAEH,SAAS,iDAAW;AACpB","file":"pawsqlite-websql-adapter.js","sourcesContent":["import { TransactionManager } from \"./transaction_manager.mjs\";\n\n\nexport class DatabaseWrapper {\n constructor(dbName, version) {\n this.name = dbName;\n this.db = openDatabase(this.name, version, \"\", 5 * 1024 * 1024);\n this.transManager = new TransactionManager(this.db);\n }\n\n sql(sql, ...args) {\n const reg = /^\\s*(BEGIN|END|COMMIT|ROLLBACK)(?:[^A-Z]|$)/i;\n const match = reg.exec(sql);\n if (match) {\n const statement = match[1].toUpperCase();\n\n switch(statement) {\n case \"BEGIN\":\n return this.transManager.begin();\n case \"END\":\n case \"COMMIT\":\n return this.transManager.commit();\n case \"ROLLBACK\":\n return this.transManager.rollback();\n }\n } else {\n return this.transManager.sql(sql, args);\n }\n }\n}","let DEBUG = false;\n\nexport function log(...args) {\n if (DEBUG) {\n console.log(...args);\n } \n}\n\nexport function enableDebug(active) {\n DEBUG = !!active;\n log(\"PawSQLite-WebSQL-Adapter: debugging \" + (\n DEBUG ? \"enabled\" : \"disabled\")\n );\n}","export const ResponseWrapper = {\n success: (obj = {}) => ({\n success: true,\n ...obj\n })\n};\n\n\n","export function mapResult(originalResult) {\n const newResult = {};\n if (!originalResult) {\n return newResult;\n }\n\n try {\n newResult.insertId = originalResult.insertId;\n } catch (e) {}\n\n newResult.rowsAffected = originalResult.rowsAffected;\n\n if (\"rows\" in originalResult) {\n newResult.rows = [];\n\n for (let i = 0; i < originalResult.rows.length; i++) {\n newResult.rows.push(originalResult.rows.item(i));\n }\n }\n\n return newResult;\n}","import { WebSQLAdapterError } from \"./websql_adapter_error.mjs\";\nimport { mapResult } from \"./result_mapper.mjs\";\nimport { log } from \"./log.mjs\";\n\n\nclass Task {\n constructor(job, startsTransaction=false, endsTransaction=false) {\n this._job = job;\n\n if (startsTransaction && endsTransaction) {\n throw new Error(\"Task cannot start and end a transaction.\");\n }\n\n this.startsTransaction = startsTransaction;\n this.endsTransaction = endsTransaction;\n\n this.result = new Promise ((resolve, reject) => {\n this._resolve = resolve;\n this._reject = reject;\n });\n }\n\n run(tx) {\n return this._job(tx).then((result) => {\n this._resolve(result);\n return result;\n }, (e) => {\n this._reject(e);\n });\n }\n}\n\n\nexport class TransactionManager {\n constructor(db) {\n this.db = db;\n\n this._txCount = 0;\n this._tasks = [];\n this._processing = false;\n }\n\n begin() {\n return this._addTask(new Task((tx) => {\n return new Promise((resolve, reject) => {\n if (tx) {\n reject(new WebSQLAdapterError(\"BEGIN called with an active \" +\n \"transaction. This should not happen\"));\n return;\n }\n this.db.transaction((tx) => {\n resolve(tx);\n });\n });\n }, true)).then(() => mapResult());\n }\n\n sql(sql, args = []) {\n return this._addTask(new Task((tx) => {\n return this._executeSql(tx, sql, args);\n }));\n }\n\n commit() {\n return this._addTask(new Task((tx) => {\n return Promise.resolve(mapResult());\n }, false, true));\n }\n\n rollback() {\n // Hack to manually cause rollback:\n // Intentionally cause an error with rollbackOnError set to true\n return this._addTask(new Task((tx) => {\n return this._executeSql(tx, \"\", [], true).catch(() => mapResult());\n }, false, true));\n }\n\n\n async _process() {\n if (this._processing) {\n return;\n }\n this._processing = true;\n\n let tx = null;\n let keepaliveCount = 0;\n\n while (true) {\n const tasks = this._tasks;\n this._tasks = [];\n\n\n if (tasks.length) {\n const promises = [];\n\n for (const task of tasks) {\n const promise = task.run(tx);\n\n if (task.startsTransaction) {\n tx = await promise;\n this._txCount++;\n } else {\n if (task.endsTransaction) {\n tx = null;\n keepaliveCount = 0;\n }\n\n promises.push(promise);\n }\n }\n\n await Promise.all(promises);\n } else {\n if (tx) {\n await this._nop(tx);\n keepaliveCount++;\n if (keepaliveCount % 5000 === 0) {\n log(`Transaction: ${ this._txCount } Keepalive: #${ keepaliveCount }`);\n }\n } else {\n break;\n }\n }\n }\n\n this._processing = false;\n }\n\n\n _addTask(task) {\n this._tasks.push(task);\n this._process();\n return task.result;\n }\n\n\n _executeSql(tx, sql, sqlArgs = [], rollbackOnError = false) {\n return new Promise((resolve, reject) => {\n if (!tx) {\n reject(new WebSQLAdapterError(\"No transaction. This should not be \" +\n \" possible\"));\n return;\n }\n tx.executeSql(sql, sqlArgs, (tx, result) => {\n resolve(mapResult(result));\n }, (tx, e) => {\n reject(WebSQLAdapterError.from(e));\n return rollbackOnError;\n });\n });\n }\n\n _nop(tx) {\n return this._executeSql(tx, \"SELECT 1\");\n }\n}","export class WebSQLAdapterError extends Error {\n static from(e) {\n let message = \"\";\n if (e && e.message) {\n message = e.message;\n }\n return new WebSQLAdapterError(message);\n }\n}","// The module cache\nvar __webpack_module_cache__ = {};\n\n// The require function\nfunction __webpack_require__(moduleId) {\n\t// Check if module is in cache\n\tif(__webpack_module_cache__[moduleId]) {\n\t\treturn __webpack_module_cache__[moduleId].exports;\n\t}\n\t// Create a new module (and put it into the cache)\n\tvar module = __webpack_module_cache__[moduleId] = {\n\t\t// no module.id needed\n\t\t// no module.loaded needed\n\t\texports: {}\n\t};\n\n\t// Execute the module function\n\t__webpack_modules__[moduleId](module, module.exports, __webpack_require__);\n\n\t// Return the exports of the module\n\treturn module.exports;\n}\n\n","// define getter functions for harmony exports\n__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n\t\tif(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n\t\t\tObject.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n\t\t}\n\t}\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","// define __esModule on exports\n__webpack_require__.r = (exports) => {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","import { WebSQLAdapterError } from \"./websql_adapter_error.mjs\";\nimport { DatabaseWrapper } from \"./database_wrapper.mjs\";\nimport { ResponseWrapper } from \"./response_wrapper.mjs\";\nimport { enableDebug, log } from \"./log.mjs\";\n\nconst databases = new Map();\n\nexport const WebSQLAdapter = {\n open: async (dbName) => {\n const version = \"1.0\";\n\n if (!databases.has(dbName)) {\n databases.set(dbName, new DatabaseWrapper(dbName, version));\n }\n\n return ResponseWrapper.success({ version });\n },\n\n close: async (dbName) => {\n databases.delete(dbName);\n return ResponseWrapper.success();\n },\n\n sql: async (dbName, sql, ...args) => {\n log(sql);\n\n const db = databases.get(dbName);\n if (!db) {\n throw new WebSQLAdapterError(\"Database not open\");\n }\n\n const result = await db.sql(sql, ...args);\n return ResponseWrapper.success(result);\n },\n\n delete: async (dbName) => {\n throw new WebSQLAdapterError(\"Delete not implemented\");\n },\n\n debug: enableDebug\n};\n"],"sourceRoot":""} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..7833d82 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,1030 @@ +{ + "name": "pawsqlite-websql-adapter", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@discoveryjs/json-ext": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.2.tgz", + "integrity": "sha512-HyYEUDeIj5rRQU2Hk5HTB2uHsbRQpF70nvMhVzi+VJR0X+xNEhjPui4/kBf3VeH/wqD28PT4sVOm8qqLjBrSZg==", + "dev": true + }, + "@types/eslint": { + "version": "7.2.6", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-7.2.6.tgz", + "integrity": "sha512-I+1sYH+NPQ3/tVqCeUSBwTE/0heyvtXqpIopUUArlBm0Kpocb8FbMa3AZ/ASKIFpN3rnEx932TTXDbt9OXsNDw==", + "dev": true, + "requires": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "@types/eslint-scope": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.0.tgz", + "integrity": "sha512-O/ql2+rrCUe2W2rs7wMR+GqPRcgB6UiqN5RhrR5xruFlY7l9YLMn0ZkDzjoHLeiFkR8MCQZVudUuuvQ2BLC9Qw==", + "dev": true, + "requires": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, + "@types/estree": { + "version": "0.0.46", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.46.tgz", + "integrity": "sha512-laIjwTQaD+5DukBZaygQ79K1Z0jb1bPEMRrkXSLjtCcZm+abyp5YbrqpSLzD42FwWW6gK/aS4NYpJ804nG2brg==", + "dev": true + }, + "@types/json-schema": { + "version": "7.0.7", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.7.tgz", + "integrity": "sha512-cxWFQVseBm6O9Gbw1IWb8r6OS4OhSt3hPZLkFApLjM8TEXROBuQGLAH2i2gZpcXdLBIrpXuTDhH7Vbm1iXmNGA==", + "dev": true + }, + "@types/node": { + "version": "14.14.31", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.31.tgz", + "integrity": "sha512-vFHy/ezP5qI0rFgJ7aQnjDXwAMrG0KqqIH7tQG5PPv3BWBayOPIQNBjVc/P6hhdZfMx51REc6tfDNXHUio893g==", + "dev": true + }, + "@webassemblyjs/ast": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.0.tgz", + "integrity": "sha512-kX2W49LWsbthrmIRMbQZuQDhGtjyqXfEmmHyEi4XWnSZtPmxY0+3anPIzsnRb45VH/J55zlOfWvZuY47aJZTJg==", + "dev": true, + "requires": { + "@webassemblyjs/helper-numbers": "1.11.0", + "@webassemblyjs/helper-wasm-bytecode": "1.11.0" + } + }, + "@webassemblyjs/floating-point-hex-parser": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.0.tgz", + "integrity": "sha512-Q/aVYs/VnPDVYvsCBL/gSgwmfjeCb4LW8+TMrO3cSzJImgv8lxxEPM2JA5jMrivE7LSz3V+PFqtMbls3m1exDA==", + "dev": true + }, + "@webassemblyjs/helper-api-error": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.0.tgz", + "integrity": "sha512-baT/va95eXiXb2QflSx95QGT5ClzWpGaa8L7JnJbgzoYeaA27FCvuBXU758l+KXWRndEmUXjP0Q5fibhavIn8w==", + "dev": true + }, + "@webassemblyjs/helper-buffer": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.0.tgz", + "integrity": "sha512-u9HPBEl4DS+vA8qLQdEQ6N/eJQ7gT7aNvMIo8AAWvAl/xMrcOSiI2M0MAnMCy3jIFke7bEee/JwdX1nUpCtdyA==", + "dev": true + }, + "@webassemblyjs/helper-numbers": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.0.tgz", + "integrity": "sha512-DhRQKelIj01s5IgdsOJMKLppI+4zpmcMQ3XboFPLwCpSNH6Hqo1ritgHgD0nqHeSYqofA6aBN/NmXuGjM1jEfQ==", + "dev": true, + "requires": { + "@webassemblyjs/floating-point-hex-parser": "1.11.0", + "@webassemblyjs/helper-api-error": "1.11.0", + "@xtuc/long": "4.2.2" + } + }, + "@webassemblyjs/helper-wasm-bytecode": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.0.tgz", + "integrity": "sha512-MbmhvxXExm542tWREgSFnOVo07fDpsBJg3sIl6fSp9xuu75eGz5lz31q7wTLffwL3Za7XNRCMZy210+tnsUSEA==", + "dev": true + }, + "@webassemblyjs/helper-wasm-section": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.0.tgz", + "integrity": "sha512-3Eb88hcbfY/FCukrg6i3EH8H2UsD7x8Vy47iVJrP967A9JGqgBVL9aH71SETPx1JrGsOUVLo0c7vMCN22ytJew==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.11.0", + "@webassemblyjs/helper-buffer": "1.11.0", + "@webassemblyjs/helper-wasm-bytecode": "1.11.0", + "@webassemblyjs/wasm-gen": "1.11.0" + } + }, + "@webassemblyjs/ieee754": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.0.tgz", + "integrity": "sha512-KXzOqpcYQwAfeQ6WbF6HXo+0udBNmw0iXDmEK5sFlmQdmND+tr773Ti8/5T/M6Tl/413ArSJErATd8In3B+WBA==", + "dev": true, + "requires": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "@webassemblyjs/leb128": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.0.tgz", + "integrity": "sha512-aqbsHa1mSQAbeeNcl38un6qVY++hh8OpCOzxhixSYgbRfNWcxJNJQwe2rezK9XEcssJbbWIkblaJRwGMS9zp+g==", + "dev": true, + "requires": { + "@xtuc/long": "4.2.2" + } + }, + "@webassemblyjs/utf8": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.0.tgz", + "integrity": "sha512-A/lclGxH6SpSLSyFowMzO/+aDEPU4hvEiooCMXQPcQFPPJaYcPQNKGOCLUySJsYJ4trbpr+Fs08n4jelkVTGVw==", + "dev": true + }, + "@webassemblyjs/wasm-edit": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.0.tgz", + "integrity": "sha512-JHQ0damXy0G6J9ucyKVXO2j08JVJ2ntkdJlq1UTiUrIgfGMmA7Ik5VdC/L8hBK46kVJgujkBIoMtT8yVr+yVOQ==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.11.0", + "@webassemblyjs/helper-buffer": "1.11.0", + "@webassemblyjs/helper-wasm-bytecode": "1.11.0", + "@webassemblyjs/helper-wasm-section": "1.11.0", + "@webassemblyjs/wasm-gen": "1.11.0", + "@webassemblyjs/wasm-opt": "1.11.0", + "@webassemblyjs/wasm-parser": "1.11.0", + "@webassemblyjs/wast-printer": "1.11.0" + } + }, + "@webassemblyjs/wasm-gen": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.0.tgz", + "integrity": "sha512-BEUv1aj0WptCZ9kIS30th5ILASUnAPEvE3tVMTrItnZRT9tXCLW2LEXT8ezLw59rqPP9klh9LPmpU+WmRQmCPQ==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.11.0", + "@webassemblyjs/helper-wasm-bytecode": "1.11.0", + "@webassemblyjs/ieee754": "1.11.0", + "@webassemblyjs/leb128": "1.11.0", + "@webassemblyjs/utf8": "1.11.0" + } + }, + "@webassemblyjs/wasm-opt": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.0.tgz", + "integrity": "sha512-tHUSP5F4ywyh3hZ0+fDQuWxKx3mJiPeFufg+9gwTpYp324mPCQgnuVKwzLTZVqj0duRDovnPaZqDwoyhIO8kYg==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.11.0", + "@webassemblyjs/helper-buffer": "1.11.0", + "@webassemblyjs/wasm-gen": "1.11.0", + "@webassemblyjs/wasm-parser": "1.11.0" + } + }, + "@webassemblyjs/wasm-parser": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.0.tgz", + "integrity": "sha512-6L285Sgu9gphrcpDXINvm0M9BskznnzJTE7gYkjDbxET28shDqp27wpruyx3C2S/dvEwiigBwLA1cz7lNUi0kw==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.11.0", + "@webassemblyjs/helper-api-error": "1.11.0", + "@webassemblyjs/helper-wasm-bytecode": "1.11.0", + "@webassemblyjs/ieee754": "1.11.0", + "@webassemblyjs/leb128": "1.11.0", + "@webassemblyjs/utf8": "1.11.0" + } + }, + "@webassemblyjs/wast-printer": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.0.tgz", + "integrity": "sha512-Fg5OX46pRdTgB7rKIUojkh9vXaVN6sGYCnEiJN1GYkb0RPwShZXp6KTDqmoMdQPKhcroOXh3fEzmkWmCYaKYhQ==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.11.0", + "@xtuc/long": "4.2.2" + } + }, + "@webpack-cli/configtest": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-1.0.1.tgz", + "integrity": "sha512-B+4uBUYhpzDXmwuo3V9yBH6cISwxEI4J+NO5ggDaGEEHb0osY/R7MzeKc0bHURXQuZjMM4qD+bSJCKIuI3eNBQ==", + "dev": true + }, + "@webpack-cli/info": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-1.2.2.tgz", + "integrity": "sha512-5U9kUJHnwU+FhKH4PWGZuBC1hTEPYyxGSL5jjoBI96Gx8qcYJGOikpiIpFoTq8mmgX3im2zAo2wanv/alD74KQ==", + "dev": true, + "requires": { + "envinfo": "^7.7.3" + } + }, + "@webpack-cli/serve": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.3.0.tgz", + "integrity": "sha512-k2p2VrONcYVX1wRRrf0f3X2VGltLWcv+JzXRBDmvCxGlCeESx4OXw91TsWeKOkp784uNoVQo313vxJFHXPPwfw==", + "dev": true + }, + "@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "dev": true + }, + "@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "dev": true + }, + "acorn": { + "version": "8.0.5", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.0.5.tgz", + "integrity": "sha512-v+DieK/HJkJOpFBETDJioequtc3PfxsWMaxIdIwujtF7FEV/MAyDQLlm6/zPvr7Mix07mLh6ccVwIsloceodlg==", + "dev": true + }, + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true + }, + "ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true + }, + "browserslist": { + "version": "4.16.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.16.3.tgz", + "integrity": "sha512-vIyhWmIkULaq04Gt93txdh+j02yX/JzlyhLYbV3YQCn/zvES3JnY7TifHHvvr1w5hTDluNKMkV05cs4vy8Q7sw==", + "dev": true, + "requires": { + "caniuse-lite": "^1.0.30001181", + "colorette": "^1.2.1", + "electron-to-chromium": "^1.3.649", + "escalade": "^3.1.1", + "node-releases": "^1.1.70" + } + }, + "buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", + "dev": true + }, + "caniuse-lite": { + "version": "1.0.30001192", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001192.tgz", + "integrity": "sha512-63OrUnwJj5T1rUmoyqYTdRWBqFFxZFlyZnRRjDR8NSUQFB6A+j/uBORU/SyJ5WzDLg4SPiZH40hQCBNdZ/jmAw==", + "dev": true + }, + "chrome-trace-event": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.2.tgz", + "integrity": "sha512-9e/zx1jw7B4CO+c/RXoCsfg/x1AfUBioy4owYH0bJprEYAx5hRFLRhWBqHAG57D0ZM4H7vxbP7bPe0VwhQRYDQ==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + }, + "clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + } + }, + "colorette": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.2.tgz", + "integrity": "sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w==", + "dev": true + }, + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "electron-to-chromium": { + "version": "1.3.677", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.677.tgz", + "integrity": "sha512-Tcmk+oKQgpjcM+KYanlkd76ZtpzalkpUULnlJDP6vjHtR7UU564IM9Qv5DxqHZNBQjzXm6mkn7Y8bw2OoE3FmQ==", + "dev": true + }, + "enhanced-resolve": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.7.0.tgz", + "integrity": "sha512-6njwt/NsZFUKhM6j9U8hzVyD4E4r0x7NQzhTCbcWOJ0IQjNSAoalWmb0AE51Wn+fwan5qVESWi7t2ToBxs9vrw==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + } + }, + "enquirer": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", + "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", + "dev": true, + "requires": { + "ansi-colors": "^4.1.1" + } + }, + "envinfo": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.7.4.tgz", + "integrity": "sha512-TQXTYFVVwwluWSFis6K2XKxgrD22jEv0FTuLCQI+OjH7rn93+iY0fSSFM5lrSxFY+H1+B0/cvvlamr3UsBivdQ==", + "dev": true + }, + "es-module-lexer": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.4.0.tgz", + "integrity": "sha512-iuEGihqqhKWFgh72Q/Jtch7V2t/ft8w8IPP2aEN8ArYKO+IWyo6hsi96hCdgyeEDQIV3InhYQ9BlwUFPGXrbEQ==", + "dev": true + }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true + }, + "eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + } + }, + "esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "requires": { + "estraverse": "^5.2.0" + }, + "dependencies": { + "estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "dev": true + } + } + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + }, + "events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true + }, + "execa": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.0.0.tgz", + "integrity": "sha512-ov6w/2LCiuyO4RLYGdpFGjkcs0wMTgGE8PrkTHikeUy5iJekXyPIKUjifk5CsE0pt7sMCrMZ3YNqoCj6idQOnQ==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + } + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "fastest-levenshtein": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.12.tgz", + "integrity": "sha512-On2N+BpYJ15xIC974QNVuYGMOlEVt4s0EOI3wwMqOmK1fdDY+FN/zltPV8vosq4ad4c/gJ1KHScUn/6AWIgiow==", + "dev": true + }, + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "get-stream": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.0.tgz", + "integrity": "sha512-A1B3Bh1UmL0bidM/YX2NsCOTnGJePL9rO/M+Mw3m9f2gUpfokS0hi5Eah0WSUEWZdZhIZtMjkIYS7mDfOqNHbg==", + "dev": true + }, + "glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "dev": true + }, + "graceful-fs": { + "version": "4.2.6", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", + "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==", + "dev": true + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true + }, + "import-local": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.0.2.tgz", + "integrity": "sha512-vjL3+w0oulAVZ0hBHnxa/Nm5TAurf9YLQJDhqRZyqb+VKGOB6LU8t9H1Nr5CIo16vh9XfJTOoHwU0B71S557gA==", + "dev": true, + "requires": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + } + }, + "interpret": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz", + "integrity": "sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==", + "dev": true + }, + "is-core-module": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.2.0.tgz", + "integrity": "sha512-XRAfAdyyY5F5cOXn7hYQDqh2Xmii+DEfIcQGxK/uNwMHhIkPWO0g8msXcbzLe+MpGoR951MlqM/2iIlU4vKDdQ==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, + "is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, + "is-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", + "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==", + "dev": true + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + }, + "jest-worker": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz", + "integrity": "sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==", + "dev": true, + "requires": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^7.0.0" + } + }, + "json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "dev": true + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true + }, + "loader-runner": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.2.0.tgz", + "integrity": "sha512-92+huvxMvYlMzMt0iIOukcwYBFpkYJdpl2xsZ7LrlayO7E8SOv+JJUEK17B/dJIHAOLMfh2dZZ/Y18WgmGtYNw==", + "dev": true + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "mime-db": { + "version": "1.46.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.46.0.tgz", + "integrity": "sha512-svXaP8UQRZ5K7or+ZmfNhg2xX3yKDMUzqadsSqi4NCH/KomcH75MAMYAGVlvXn4+b/xOPhS3I2uHKRUzvjY7BQ==", + "dev": true + }, + "mime-types": { + "version": "2.1.29", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.29.tgz", + "integrity": "sha512-Y/jMt/S5sR9OaqteJtslsFZKWOIIqMACsJSiHghlCAyhf7jfVYjKBmLiX8OgpWeW+fjJ2b+Az69aPFPkUOY6xQ==", + "dev": true, + "requires": { + "mime-db": "1.46.0" + } + }, + "mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true + }, + "neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true + }, + "node-releases": { + "version": "1.1.71", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.71.tgz", + "integrity": "sha512-zR6HoT6LrLCRBwukmrVbHv0EpEQjksO6GmFcZQQuCAy139BEsoVKPYnf3jongYW83fAa1torLGYwxxky/p28sg==", + "dev": true + }, + "npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "requires": { + "path-key": "^3.0.0" + } + }, + "onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "requires": { + "mimic-fn": "^2.1.0" + } + }, + "p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "requires": { + "yocto-queue": "^0.1.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + }, + "dependencies": { + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + } + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, + "path-parse": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", + "dev": true + }, + "pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "requires": { + "find-up": "^4.0.0" + } + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true + }, + "randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "requires": { + "safe-buffer": "^5.1.0" + } + }, + "rechoir": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.7.0.tgz", + "integrity": "sha512-ADsDEH2bvbjltXEP+hTIAmeFekTFK0V2BTxMkok6qILyAJEXV0AFfoWcAq4yfll5VdIMd/RVXq0lR+wQi5ZU3Q==", + "dev": true, + "requires": { + "resolve": "^1.9.0" + } + }, + "resolve": { + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", + "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", + "dev": true, + "requires": { + "is-core-module": "^2.2.0", + "path-parse": "^1.0.6" + } + }, + "resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "requires": { + "resolve-from": "^5.0.0" + } + }, + "resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true + }, + "schema-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.0.0.tgz", + "integrity": "sha512-6D82/xSzO094ajanoOSbe4YvXWMfn2A//8Y1+MUqFAJul5Bs+yn36xbK9OtNDcRVSBJ9jjeoXftM6CfztsjOAA==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.6", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + } + }, + "serialize-javascript": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-5.0.1.tgz", + "integrity": "sha512-SaaNal9imEO737H2c05Og0/8LUXG7EnsZyMa8MzkmuHoELfT6txuj0cMqRj6zfPKnmQ1yasR4PCJc8x+M4JSPA==", + "dev": true, + "requires": { + "randombytes": "^2.1.0" + } + }, + "shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dev": true, + "requires": { + "kind-of": "^6.0.2" + } + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, + "signal-exit": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", + "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==", + "dev": true + }, + "source-list-map": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz", + "integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "source-map-support": { + "version": "0.5.19", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", + "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "tapable": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.0.tgz", + "integrity": "sha512-FBk4IesMV1rBxX2tfiK8RAmogtWn53puLOQlvO8XuwlgxcYbP4mVPS9Ph4aeamSyyVjOl24aYWAuc8U5kCVwMw==", + "dev": true + }, + "terser": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.6.0.tgz", + "integrity": "sha512-vyqLMoqadC1uR0vywqOZzriDYzgEkNJFK4q9GeyOBHIbiECHiWLKcWfbQWAUaPfxkjDhapSlZB9f7fkMrvkVjA==", + "dev": true, + "requires": { + "commander": "^2.20.0", + "source-map": "~0.7.2", + "source-map-support": "~0.5.19" + }, + "dependencies": { + "source-map": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", + "dev": true + } + } + }, + "terser-webpack-plugin": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.1.1.tgz", + "integrity": "sha512-5XNNXZiR8YO6X6KhSGXfY0QrGrCRlSwAEjIIrlRQR4W8nP69TaJUlh3bkuac6zzgspiGPfKEHcY295MMVExl5Q==", + "dev": true, + "requires": { + "jest-worker": "^26.6.2", + "p-limit": "^3.1.0", + "schema-utils": "^3.0.0", + "serialize-javascript": "^5.0.1", + "source-map": "^0.6.1", + "terser": "^5.5.1" + } + }, + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "v8-compile-cache": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.2.0.tgz", + "integrity": "sha512-gTpR5XQNKFwOd4clxfnhaqvfqMpqEwr4tOtCyz4MtYZX2JYhfr1JvBFKdS+7K/9rfpZR3VLX+YWBbKoxCgS43Q==", + "dev": true + }, + "watchpack": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.1.1.tgz", + "integrity": "sha512-Oo7LXCmc1eE1AjyuSBmtC3+Wy4HcV8PxWh2kP6fOl8yTlNS7r0K9l1ao2lrrUza7V39Y3D/BbJgY8VeSlc5JKw==", + "dev": true, + "requires": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + } + }, + "webpack": { + "version": "5.24.2", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.24.2.tgz", + "integrity": "sha512-uxxKYEY4kMNjP+D2Y+8aw5Vd7ar4pMuKCNemxV26ysr1nk0YDiQTylg9U3VZIdkmI0YHa0uC8ABxL+uGxGWWJg==", + "dev": true, + "requires": { + "@types/eslint-scope": "^3.7.0", + "@types/estree": "^0.0.46", + "@webassemblyjs/ast": "1.11.0", + "@webassemblyjs/wasm-edit": "1.11.0", + "@webassemblyjs/wasm-parser": "1.11.0", + "acorn": "^8.0.4", + "browserslist": "^4.14.5", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.7.0", + "es-module-lexer": "^0.4.0", + "eslint-scope": "^5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.4", + "json-parse-better-errors": "^1.0.2", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^3.0.0", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.1.1", + "watchpack": "^2.0.0", + "webpack-sources": "^2.1.1" + } + }, + "webpack-cli": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.5.0.tgz", + "integrity": "sha512-wXg/ef6Ibstl2f50mnkcHblRPN/P9J4Nlod5Hg9HGFgSeF8rsqDGHJeVe4aR26q9l62TUJi6vmvC2Qz96YJw1Q==", + "dev": true, + "requires": { + "@discoveryjs/json-ext": "^0.5.0", + "@webpack-cli/configtest": "^1.0.1", + "@webpack-cli/info": "^1.2.2", + "@webpack-cli/serve": "^1.3.0", + "colorette": "^1.2.1", + "commander": "^7.0.0", + "enquirer": "^2.3.6", + "execa": "^5.0.0", + "fastest-levenshtein": "^1.0.12", + "import-local": "^3.0.2", + "interpret": "^2.2.0", + "rechoir": "^0.7.0", + "v8-compile-cache": "^2.2.0", + "webpack-merge": "^5.7.3" + }, + "dependencies": { + "commander": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.1.0.tgz", + "integrity": "sha512-pRxBna3MJe6HKnBGsDyMv8ETbptw3axEdYHoqNh7gu5oDcew8fs0xnivZGm06Ogk8zGAJ9VX+OPEr2GXEQK4dg==", + "dev": true + } + } + }, + "webpack-merge": { + "version": "5.7.3", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.7.3.tgz", + "integrity": "sha512-6/JUQv0ELQ1igjGDzHkXbVDRxkfA57Zw7PfiupdLFJYrgFqY5ZP8xxbpp2lU3EPwYx89ht5Z/aDkD40hFCm5AA==", + "dev": true, + "requires": { + "clone-deep": "^4.0.1", + "wildcard": "^2.0.0" + } + }, + "webpack-sources": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-2.2.0.tgz", + "integrity": "sha512-bQsA24JLwcnWGArOKUxYKhX3Mz/nK1Xf6hxullKERyktjNMC4x8koOeaDNTA2fEJ09BdWLbM/iTW0ithREUP0w==", + "dev": true, + "requires": { + "source-list-map": "^2.0.1", + "source-map": "^0.6.1" + } + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "wildcard": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.0.tgz", + "integrity": "sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw==", + "dev": true + }, + "yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..14a3d3d --- /dev/null +++ b/package.json @@ -0,0 +1,20 @@ +{ + "name": "pawsqlite-websql-adapter", + "version": "1.0.0", + "description": "A WebSQL Adapter for PawSQLite", + "main": "./lib/pawsqlite-websql-adapter.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "build": "webpack" + }, + "repository": { + "type": "git", + "url": "https://git.n0m.org/n0m/PawSQLite-WebSQL-Adapter.git" + }, + "author": "Ben Ashton", + "license": "MIT", + "devDependencies": { + "webpack": "5.x", + "webpack-cli": "4.x" + } +} diff --git a/src/database_wrapper.mjs b/src/database_wrapper.mjs new file mode 100644 index 0000000..de3e043 --- /dev/null +++ b/src/database_wrapper.mjs @@ -0,0 +1,30 @@ +import { TransactionManager } from "./transaction_manager.mjs"; + + +export class DatabaseWrapper { + constructor(dbName, version) { + this.name = dbName; + this.db = openDatabase(this.name, version, "", 5 * 1024 * 1024); + this.transManager = new TransactionManager(this.db); + } + + sql(sql, ...args) { + const reg = /^\s*(BEGIN|END|COMMIT|ROLLBACK)(?:[^A-Z]|$)/i; + const match = reg.exec(sql); + if (match) { + const statement = match[1].toUpperCase(); + + switch(statement) { + case "BEGIN": + return this.transManager.begin(); + case "END": + case "COMMIT": + return this.transManager.commit(); + case "ROLLBACK": + return this.transManager.rollback(); + } + } else { + return this.transManager.sql(sql, args); + } + } +} \ No newline at end of file diff --git a/src/log.mjs b/src/log.mjs new file mode 100644 index 0000000..37197d3 --- /dev/null +++ b/src/log.mjs @@ -0,0 +1,14 @@ +let DEBUG = false; + +export function log(...args) { + if (DEBUG) { + console.log(...args); + } +} + +export function enableDebug(active) { + DEBUG = !!active; + log("PawSQLite-WebSQL-Adapter: debugging " + ( + DEBUG ? "enabled" : "disabled") + ); +} \ No newline at end of file diff --git a/src/response_wrapper.mjs b/src/response_wrapper.mjs new file mode 100644 index 0000000..7e224e0 --- /dev/null +++ b/src/response_wrapper.mjs @@ -0,0 +1,8 @@ +export const ResponseWrapper = { + success: (obj = {}) => ({ + success: true, + ...obj + }) +}; + + diff --git a/src/result_mapper.mjs b/src/result_mapper.mjs new file mode 100644 index 0000000..214fbe0 --- /dev/null +++ b/src/result_mapper.mjs @@ -0,0 +1,22 @@ +export function mapResult(originalResult) { + const newResult = {}; + if (!originalResult) { + return newResult; + } + + try { + newResult.insertId = originalResult.insertId; + } catch (e) {} + + newResult.rowsAffected = originalResult.rowsAffected; + + if ("rows" in originalResult) { + newResult.rows = []; + + for (let i = 0; i < originalResult.rows.length; i++) { + newResult.rows.push(originalResult.rows.item(i)); + } + } + + return newResult; +} \ No newline at end of file diff --git a/src/transaction_manager.mjs b/src/transaction_manager.mjs new file mode 100644 index 0000000..a176a19 --- /dev/null +++ b/src/transaction_manager.mjs @@ -0,0 +1,156 @@ +import { WebSQLAdapterError } from "./websql_adapter_error.mjs"; +import { mapResult } from "./result_mapper.mjs"; +import { log } from "./log.mjs"; + + +class Task { + constructor(job, startsTransaction=false, endsTransaction=false) { + this._job = job; + + if (startsTransaction && endsTransaction) { + throw new Error("Task cannot start and end a transaction."); + } + + this.startsTransaction = startsTransaction; + this.endsTransaction = endsTransaction; + + this.result = new Promise ((resolve, reject) => { + this._resolve = resolve; + this._reject = reject; + }); + } + + run(tx) { + return this._job(tx).then((result) => { + this._resolve(result); + return result; + }, (e) => { + this._reject(e); + }); + } +} + + +export class TransactionManager { + constructor(db) { + this.db = db; + + this._txCount = 0; + this._tasks = []; + this._processing = false; + } + + begin() { + return this._addTask(new Task((tx) => { + return new Promise((resolve, reject) => { + if (tx) { + reject(new WebSQLAdapterError("BEGIN called with an active " + + "transaction. This should not happen")); + return; + } + this.db.transaction((tx) => { + resolve(tx); + }); + }); + }, true)).then(() => mapResult()); + } + + sql(sql, args = []) { + return this._addTask(new Task((tx) => { + return this._executeSql(tx, sql, args); + })); + } + + commit() { + return this._addTask(new Task((tx) => { + return Promise.resolve(mapResult()); + }, false, true)); + } + + rollback() { + // Hack to manually cause rollback: + // Intentionally cause an error with rollbackOnError set to true + return this._addTask(new Task((tx) => { + return this._executeSql(tx, "", [], true).catch(() => mapResult()); + }, false, true)); + } + + + async _process() { + if (this._processing) { + return; + } + this._processing = true; + + let tx = null; + let keepaliveCount = 0; + + while (true) { + const tasks = this._tasks; + this._tasks = []; + + + if (tasks.length) { + const promises = []; + + for (const task of tasks) { + const promise = task.run(tx); + + if (task.startsTransaction) { + tx = await promise; + this._txCount++; + } else { + if (task.endsTransaction) { + tx = null; + keepaliveCount = 0; + } + + promises.push(promise); + } + } + + await Promise.all(promises); + } else { + if (tx) { + await this._nop(tx); + keepaliveCount++; + if (keepaliveCount % 5000 === 0) { + log(`Transaction: ${ this._txCount } Keepalive: #${ keepaliveCount }`); + } + } else { + break; + } + } + } + + this._processing = false; + } + + + _addTask(task) { + this._tasks.push(task); + this._process(); + return task.result; + } + + + _executeSql(tx, sql, sqlArgs = [], rollbackOnError = false) { + return new Promise((resolve, reject) => { + if (!tx) { + reject(new WebSQLAdapterError("No transaction. This should not be " + + " possible")); + return; + } + tx.executeSql(sql, sqlArgs, (tx, result) => { + resolve(mapResult(result)); + }, (tx, e) => { + reject(WebSQLAdapterError.from(e)); + return rollbackOnError; + }); + }); + } + + _nop(tx) { + return this._executeSql(tx, "SELECT 1"); + } +} \ No newline at end of file diff --git a/src/websql_adapter.mjs b/src/websql_adapter.mjs new file mode 100644 index 0000000..3ca0443 --- /dev/null +++ b/src/websql_adapter.mjs @@ -0,0 +1,41 @@ +import { WebSQLAdapterError } from "./websql_adapter_error.mjs"; +import { DatabaseWrapper } from "./database_wrapper.mjs"; +import { ResponseWrapper } from "./response_wrapper.mjs"; +import { enableDebug, log } from "./log.mjs"; + +const databases = new Map(); + +export const WebSQLAdapter = { + open: async (dbName) => { + const version = "1.0"; + + if (!databases.has(dbName)) { + databases.set(dbName, new DatabaseWrapper(dbName, version)); + } + + return ResponseWrapper.success({ version }); + }, + + close: async (dbName) => { + databases.delete(dbName); + return ResponseWrapper.success(); + }, + + sql: async (dbName, sql, ...args) => { + log(sql); + + const db = databases.get(dbName); + if (!db) { + throw new WebSQLAdapterError("Database not open"); + } + + const result = await db.sql(sql, ...args); + return ResponseWrapper.success(result); + }, + + delete: async (dbName) => { + throw new WebSQLAdapterError("Delete not implemented"); + }, + + debug: enableDebug +}; diff --git a/src/websql_adapter_error.mjs b/src/websql_adapter_error.mjs new file mode 100644 index 0000000..27f5730 --- /dev/null +++ b/src/websql_adapter_error.mjs @@ -0,0 +1,9 @@ +export class WebSQLAdapterError extends Error { + static from(e) { + let message = ""; + if (e && e.message) { + message = e.message; + } + return new WebSQLAdapterError(message); + } +} \ No newline at end of file diff --git a/webpack.config.js b/webpack.config.js new file mode 100644 index 0000000..9490f28 --- /dev/null +++ b/webpack.config.js @@ -0,0 +1,18 @@ +var webpack = require('webpack'); +var libraryName = 'pawsqlite-websql-adapter'; +var outputFile = libraryName + '.js'; + +var config = { + mode: 'development', + entry: __dirname + '/src/websql_adapter.mjs', + devtool: 'source-map', + output: { + path: __dirname + '/lib', + filename: outputFile, + library: libraryName, + libraryExport: 'default', + libraryTarget: 'commonjs2', + } +}; + +module.exports = config; \ No newline at end of file