/******/ (() => { // webpackBootstrap /******/ var __webpack_modules__ = ({ /***/ 100: /***/ ((module) => { module.exports = {} /***/ }), /***/ 159: /***/ ((module) => { /** * Utility functions that need to be reimplemented for each environment. * This is the version for the browser & React-Native * @module customUtilsBrowser * @private */ /** * Taken from the crypto-browserify module * https://github.com/dominictarr/crypto-browserify * NOTE: Math.random() does not guarantee "cryptographic quality" but we actually don't need it * @param {number} size in bytes * @return {Array} */ const randomBytes = size => { const bytes = new Array(size) for (let i = 0, r; i < size; i++) { if ((i & 0x03) === 0) r = Math.random() * 0x100000000 bytes[i] = r >>> ((i & 0x03) << 3) & 0xff } return bytes } /** * Taken from the base64-js module * https://github.com/beatgammit/base64-js/ * @param {Array} uint8 * @return {string} */ const byteArrayToBase64 = uint8 => { const lookup = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' const extraBytes = uint8.length % 3 // if we have 1 byte left, pad 2 bytes let output = '' let temp const tripletToBase64 = num => lookup[num >> 18 & 0x3F] + lookup[num >> 12 & 0x3F] + lookup[num >> 6 & 0x3F] + lookup[num & 0x3F] // go through the array every three bytes, we'll deal with trailing stuff later for (let i = 0, length = uint8.length - extraBytes; i < length; i += 3) { temp = (uint8[i] << 16) + (uint8[i + 1] << 8) + (uint8[i + 2]) output += tripletToBase64(temp) } // pad the end with zeros, but make sure to not forget the extra bytes if (extraBytes === 1) { temp = uint8[uint8.length - 1] output += lookup[temp >> 2] output += lookup[(temp << 4) & 0x3F] output += '==' } else if (extraBytes === 2) { temp = (uint8[uint8.length - 2] << 8) + (uint8[uint8.length - 1]) output += lookup[temp >> 10] output += lookup[(temp >> 4) & 0x3F] output += lookup[(temp << 2) & 0x3F] output += '=' } return output } /** * Return a random alphanumerical string of length len * There is a very small probability (less than 1/1,000,000) for the length to be less than len * (il the base64 conversion yields too many pluses and slashes) but * that's not an issue here * The probability of a collision is extremely small (need 3*10^12 documents to have one chance in a million of a collision) * See http://en.wikipedia.org/wiki/Birthday_problem * @param {number} len * @return {string} * @alias module:customUtilsNode.uid */ const uid = len => byteArrayToBase64(randomBytes(Math.ceil(Math.max(8, len * 2)))).replace(/[+/]/g, '').slice(0, len) module.exports.uid = uid /***/ }), /***/ 909: /***/ ((module, __unused_webpack_exports, __webpack_require__) => { /** * Way data is stored for this database * * This version is the browser version and uses [localforage]{@link https://github.com/localForage/localForage} which chooses the best option depending on user browser (IndexedDB then WebSQL then localStorage). * @module storageBrowser * @see module:storage * @see module:storageReactNative * @private */ const localforage = __webpack_require__(483) // Configure localforage to display NeDB name for now. Would be a good idea to let user use his own app name const store = localforage.createInstance({ name: 'NeDB', storeName: 'nedbdata' }) /** * Returns Promise if file exists. * * @param {string} file * @return {Promise} * @async * @alias module:storageBrowser.existsAsync */ const existsAsync = async file => { try { const value = await store.getItem(file) if (value !== null) return true // Even if value is undefined, localforage returns null return false } catch (error) { return false } } /** * Moves the item from one path to another. * @param {string} oldPath * @param {string} newPath * @return {Promise} * @alias module:storageBrowser.renameAsync * @async */ const renameAsync = async (oldPath, newPath) => { try { const value = await store.getItem(oldPath) if (value === null) await store.removeItem(newPath) else { await store.setItem(newPath, value) await store.removeItem(oldPath) } } catch (err) { console.warn('An error happened while renaming, skip') } } /** * Saves the item at given path. * @param {string} file * @param {string} data * @param {object} [options] * @return {Promise} * @alias module:storageBrowser.writeFileAsync * @async */ const writeFileAsync = async (file, data, options) => { // Options do not matter in browser setup try { await store.setItem(file, data) } catch (error) { console.warn('An error happened while writing, skip') } } /** * Append to the item at given path. * @function * @param {string} filename * @param {string} toAppend * @param {object} [options] * @return {Promise} * @alias module:storageBrowser.appendFileAsync * @async */ const appendFileAsync = async (filename, toAppend, options) => { // Options do not matter in browser setup try { const contents = (await store.getItem(filename)) || '' await store.setItem(filename, contents + toAppend) } catch (error) { console.warn('An error happened appending to file writing, skip') } } /** * Read data at given path. * @function * @param {string} filename * @param {object} [options] * @return {Promise} * @alias module:storageBrowser.readFileAsync * @async */ const readFileAsync = async (filename, options) => { try { return (await store.getItem(filename)) || '' } catch (error) { console.warn('An error happened while reading, skip') return '' } } /** * Async version of {@link module:storageBrowser.unlink}. * @function * @param {string} filename * @return {Promise} * @async * @alias module:storageBrowser.unlink */ const unlinkAsync = async filename => { try { await store.removeItem(filename) } catch (error) { console.warn('An error happened while unlinking, skip') } } /** * Shim for {@link module:storage.mkdirAsync}, nothing to do, no directories will be used on the browser. * @function * @param {string} path * @param {object} [options] * @return {Promise} * @alias module:storageBrowser.mkdirAsync * @async */ const mkdirAsync = (path, options) => Promise.resolve() /** * Shim for {@link module:storage.ensureParentDirectoryExistsAsync}, nothing to do, no directories will be used on the browser. * @function * @param {string} file * @param {number} [mode] * @return {Promise} * @alias module:storageBrowser.ensureParentDirectoryExistsAsync * @async */ const ensureParentDirectoryExistsAsync = async (file, mode) => Promise.resolve() /** * Shim for {@link module:storage.ensureDatafileIntegrityAsync}, nothing to do, no data corruption possible in the browser. * @param {string} filename * @return {Promise} * @alias module:storageBrowser.ensureDatafileIntegrityAsync */ const ensureDatafileIntegrityAsync = (filename) => Promise.resolve() /** * Fully write or rewrite the datafile, immune to crashes during the write operation (data will not be lost) * * @param {string} filename * @param {string[]} lines * @return {Promise} * @alias module:storageBrowser.crashSafeWriteFileLinesAsync */ const crashSafeWriteFileLinesAsync = async (filename, lines) => { lines.push('') // Add final new line await writeFileAsync(filename, lines.join('\n')) } // Interface module.exports.existsAsync = existsAsync module.exports.renameAsync = renameAsync module.exports.writeFileAsync = writeFileAsync module.exports.crashSafeWriteFileLinesAsync = crashSafeWriteFileLinesAsync module.exports.appendFileAsync = appendFileAsync module.exports.readFileAsync = readFileAsync module.exports.unlinkAsync = unlinkAsync module.exports.mkdirAsync = mkdirAsync module.exports.ensureDatafileIntegrityAsync = ensureDatafileIntegrityAsync module.exports.ensureParentDirectoryExistsAsync = ensureParentDirectoryExistsAsync /***/ }), /***/ 578: /***/ ((module, __unused_webpack_exports, __webpack_require__) => { const model = __webpack_require__(118) const { callbackify } = __webpack_require__(539) /** * Has a callback * @callback Cursor~mapFn * @param {document[]} res * @return {*|Promise<*>} */ /** * Manage access to data, be it to find, update or remove it. * * It extends `Promise` so that its methods (which return `this`) are chainable & awaitable. * @extends Promise */ class Cursor { /** * Create a new cursor for this collection. * @param {Datastore} db - The datastore this cursor is bound to * @param {query} query - The query this cursor will operate on * @param {Cursor~mapFn} [mapFn] - Handler to be executed after cursor has found the results and before the callback passed to find/findOne/update/remove */ constructor (db, query, mapFn) { /** * @protected * @type {Datastore} */ this.db = db /** * @protected * @type {query} */ this.query = query || {} /** * The handler to be executed after cursor has found the results. * @type {Cursor~mapFn} * @protected */ if (mapFn) this.mapFn = mapFn /** * @see Cursor#limit * @type {undefined|number} * @private */ this._limit = undefined /** * @see Cursor#skip * @type {undefined|number} * @private */ this._skip = undefined /** * @see Cursor#sort * @type {undefined|Object.} * @private */ this._sort = undefined /** * @see Cursor#projection * @type {undefined|Object.} * @private */ this._projection = undefined } /** * Set a limit to the number of results for the given Cursor. * @param {Number} limit * @return {Cursor} the same instance of Cursor, (useful for chaining). */ limit (limit) { this._limit = limit return this } /** * Skip a number of results for the given Cursor. * @param {Number} skip * @return {Cursor} the same instance of Cursor, (useful for chaining). */ skip (skip) { this._skip = skip return this } /** * Sort results of the query for the given Cursor. * @param {Object.} sortQuery - sortQuery is { field: order }, field can use the dot-notation, order is 1 for ascending and -1 for descending * @return {Cursor} the same instance of Cursor, (useful for chaining). */ sort (sortQuery) { this._sort = sortQuery return this } /** * Add the use of a projection to the given Cursor. * @param {Object.} projection - MongoDB-style projection. {} means take all fields. Then it's { key1: 1, key2: 1 } to take only key1 and key2 * { key1: 0, key2: 0 } to omit only key1 and key2. Except _id, you can't mix takes and omits. * @return {Cursor} the same instance of Cursor, (useful for chaining). */ projection (projection) { this._projection = projection return this } /** * Apply the projection. * * This is an internal function. You should use {@link Cursor#execAsync} or {@link Cursor#exec}. * @param {document[]} candidates * @return {document[]} * @private */ _project (candidates) { const res = [] let action if (this._projection === undefined || Object.keys(this._projection).length === 0) { return candidates } const keepId = this._projection._id !== 0 const { _id, ...rest } = this._projection this._projection = rest // Check for consistency const keys = Object.keys(this._projection) keys.forEach(k => { if (action !== undefined && this._projection[k] !== action) throw new Error('Can\'t both keep and omit fields except for _id') action = this._projection[k] }) // Do the actual projection candidates.forEach(candidate => { let toPush if (action === 1) { // pick-type projection toPush = { $set: {} } keys.forEach(k => { toPush.$set[k] = model.getDotValue(candidate, k) if (toPush.$set[k] === undefined) delete toPush.$set[k] }) toPush = model.modify({}, toPush) } else { // omit-type projection toPush = { $unset: {} } keys.forEach(k => { toPush.$unset[k] = true }) toPush = model.modify(candidate, toPush) } if (keepId) toPush._id = candidate._id else delete toPush._id res.push(toPush) }) return res } /** * Get all matching elements * Will return pointers to matched elements (shallow copies), returning full copies is the role of find or findOne * This is an internal function, use execAsync which uses the executor * @return {document[]|Promise<*>} * @private */ async _execAsync () { let res = [] let added = 0 let skipped = 0 const candidates = await this.db._getCandidatesAsync(this.query) for (const candidate of candidates) { if (model.match(candidate, this.query)) { // If a sort is defined, wait for the results to be sorted before applying limit and skip if (!this._sort) { if (this._skip && this._skip > skipped) skipped += 1 else { res.push(candidate) added += 1 if (this._limit && this._limit <= added) break } } else res.push(candidate) } } // Apply all sorts if (this._sort) { // Sorting const criteria = Object.entries(this._sort).map(([key, direction]) => ({ key, direction })) res.sort((a, b) => { for (const criterion of criteria) { const compare = criterion.direction * model.compareThings(model.getDotValue(a, criterion.key), model.getDotValue(b, criterion.key), this.db.compareStrings) if (compare !== 0) return compare } return 0 }) // Applying limit and skip const limit = this._limit || res.length const skip = this._skip || 0 res = res.slice(skip, skip + limit) } // Apply projection res = this._project(res) if (this.mapFn) return this.mapFn(res) return res } /** * @callback Cursor~execCallback * @param {Error} err * @param {document[]|*} res If a mapFn was given to the Cursor, then the type of this parameter is the one returned by the mapFn. */ /** * Callback version of {@link Cursor#exec}. * @param {Cursor~execCallback} _callback * @see Cursor#execAsync */ exec (_callback) { callbackify(() => this.execAsync())(_callback) } /** * Get all matching elements. * Will return pointers to matched elements (shallow copies), returning full copies is the role of {@link Datastore#findAsync} or {@link Datastore#findOneAsync}. * @return {Promise} * @async */ execAsync () { return this.db.executor.pushAsync(() => this._execAsync()) } then (onFulfilled, onRejected) { return this.execAsync().then(onFulfilled, onRejected) } catch (onRejected) { return this.execAsync().catch(onRejected) } finally (onFinally) { return this.execAsync().finally(onFinally) } } // Interface module.exports = Cursor /***/ }), /***/ 797: /***/ ((module, __unused_webpack_exports, __webpack_require__) => { const { EventEmitter } = __webpack_require__(187) const { callbackify, deprecate } = __webpack_require__(539) const Cursor = __webpack_require__(578) const customUtils = __webpack_require__(159) const Executor = __webpack_require__(196) const Index = __webpack_require__(98) const model = __webpack_require__(118) const Persistence = __webpack_require__(328) const { isDate, pick, filterIndexNames } = __webpack_require__(988) /** * Callback with no parameter * @callback NoParamCallback * @param {?Error} err */ /** * String comparison function. * ``` * if (a < b) return -1 * if (a > b) return 1 * return 0 * ``` * @callback compareStrings * @param {string} a * @param {string} b * @return {number} */ /** * Callback that returns an Array of documents. * @callback MultipleDocumentsCallback * @param {?Error} err * @param {?document[]} docs */ /** * Callback that returns a single document. * @callback SingleDocumentCallback * @param {?Error} err * @param {?document} docs */ /** * Generic async function. * @callback AsyncFunction * @param {...*} args * @return {Promise<*>} */ /** * Callback with generic parameters. * @callback GenericCallback * @param {?Error} err * @param {...*} args */ /** * Compaction event. Happens when the Datastore's Persistence has been compacted. * It happens when calling {@link Datastore#compactDatafileAsync}, which is called periodically if you have called * {@link Datastore#setAutocompactionInterval}. * * @event Datastore#event:"compaction.done" * @type {undefined} */ /** * Generic document in NeDB. * It consists of an Object with anything you want inside. * @typedef document * @property {?string} [_id] Internal `_id` of the document, which can be `null` or undefined at some points (when not * inserted yet for example). * @type {object} */ /** * Nedb query. * * Each key of a query references a field name, which can use the dot-notation to reference subfields inside nested * documents, arrays, arrays of subdocuments and to match a specific element of an array. * * Each value of a query can be one of the following: * - `string`: matches all documents which have this string as value for the referenced field name * - `number`: matches all documents which have this number as value for the referenced field name * - `Regexp`: matches all documents which have a value that matches the given `Regexp` for the referenced field name * - `object`: matches all documents which have this object as deep-value for the referenced field name * - Comparison operators: the syntax is `{ field: { $op: value } }` where `$op` is any comparison operator: * - `$lt`, `$lte`: less than, less than or equal * - `$gt`, `$gte`: greater than, greater than or equal * - `$in`: member of. `value` must be an array of values * - `$ne`, `$nin`: not equal, not a member of * - `$exists`: checks whether the document posses the property `field`. `value` should be true or false * - `$regex`: checks whether a string is matched by the regular expression. Contrary to MongoDB, the use of * `$options` with `$regex` is not supported, because it doesn't give you more power than regex flags. Basic * queries are more readable so only use the `$regex` operator when you need to use another operator with it * - `$size`: if the referenced filed is an Array, matches on the size of the array * - `$elemMatch`: matches if at least one array element matches the sub-query entirely * - Logical operators: You can combine queries using logical operators: * - For `$or` and `$and`, the syntax is `{ $op: [query1, query2, ...] }`. * - For `$not`, the syntax is `{ $not: query }` * - For `$where`, the syntax is: * ``` * { $where: function () { * // object is 'this' * // return a boolean * } } * ``` * @typedef query * @type {Object.} */ /** * Nedb projection. * * You can give `find` and `findOne` an optional second argument, `projections`. * The syntax is the same as MongoDB: `{ a: 1, b: 1 }` to return only the `a` * and `b` fields, `{ a: 0, b: 0 }` to omit these two fields. You cannot use both * modes at the time, except for `_id` which is by default always returned and * which you can choose to omit. You can project on nested documents. * * To reference subfields, you can use the dot-notation. * * @typedef projection * @type {Object.} */ /** * The `beforeDeserialization` and `afterDeserialization` callbacks are hooks which are executed respectively before * parsing each document and after stringifying them. They can be used for example to encrypt the Datastore. * The `beforeDeserialization` should revert what `afterDeserialization` has done. * @callback serializationHook * @param {string} x * @return {string} */ /** * @external EventEmitter * @see http://nodejs.org/api/events.html */ /** * @class * @classdesc The `Datastore` class is the main class of NeDB. * @extends external:EventEmitter * @emits Datastore#event:"compaction.done" * @typicalname NeDB */ class Datastore extends EventEmitter { /** * Create a new collection, either persistent or in-memory. * * If you use a persistent datastore without the `autoload` option, you need to call {@link Datastore#loadDatabase} or * {@link Datastore#loadDatabaseAsync} manually. This function fetches the data from datafile and prepares the database. * **Don't forget it!** If you use a persistent datastore, no command (insert, find, update, remove) will be executed * before it is called, so make sure to call it yourself or use the `autoload` option. * * Also, if loading fails, all commands registered to the {@link Datastore#executor} afterwards will not be executed. * They will be registered and executed, in sequence, only after a successful loading. * * @param {object|string} options Can be an object or a string. If options is a string, the behavior is the same as in * v0.6: it will be interpreted as `options.filename`. **Giving a string is deprecated, and will be removed in the * next major version.** * @param {string} [options.filename = null] Path to the file where the data is persisted. If left blank, the datastore is * automatically considered in-memory only. It cannot end with a `~` which is used in the temporary files NeDB uses to * perform crash-safe writes. Not used if `options.inMemoryOnly` is `true`. * @param {boolean} [options.inMemoryOnly = false] If set to true, no data will be written in storage. This option has * priority over `options.filename`. * @param {object} [options.modes] Permissions to use for FS. Only used for Node.js storage module. Will not work on Windows. * @param {number} [options.modes.fileMode = 0o644] Permissions to use for database files * @param {number} [options.modes.dirMode = 0o755] Permissions to use for database directories * @param {boolean} [options.timestampData = false] If set to true, createdAt and updatedAt will be created and * populated automatically (if not specified by user) * @param {boolean} [options.autoload = false] If used, the database will automatically be loaded from the datafile * upon creation (you don't need to call `loadDatabase`). Any command issued before load is finished is buffered and * will be executed when load is done. When autoloading is done, you can either use the `onload` callback, or you can * use `this.autoloadPromise` which resolves (or rejects) when autloading is done. * @param {NoParamCallback} [options.onload] If you use autoloading, this is the handler called after the `loadDatabase`. It * takes one `error` argument. If you use autoloading without specifying this handler, and an error happens during * load, an error will be thrown. * @param {serializationHook} [options.beforeDeserialization] Hook you can use to transform data after it was serialized and * before it is written to disk. Can be used for example to encrypt data before writing database to disk. This * function takes a string as parameter (one line of an NeDB data file) and outputs the transformed string, **which * must absolutely not contain a `\n` character** (or data will be lost). * @param {serializationHook} [options.afterSerialization] Inverse of `afterSerialization`. Make sure to include both and not * just one, or you risk data loss. For the same reason, make sure both functions are inverses of one another. Some * failsafe mechanisms are in place to prevent data loss if you misuse the serialization hooks: NeDB checks that never * one is declared without the other, and checks that they are reverse of one another by testing on random strings of * various lengths. In addition, if too much data is detected as corrupt, NeDB will refuse to start as it could mean * you're not using the deserialization hook corresponding to the serialization hook used before. * @param {number} [options.corruptAlertThreshold = 0.1] Between 0 and 1, defaults to 10%. NeDB will refuse to start * if more than this percentage of the datafile is corrupt. 0 means you don't tolerate any corruption, 1 means you * don't care. * @param {compareStrings} [options.compareStrings] If specified, it overrides default string comparison which is not * well adapted to non-US characters in particular accented letters. Native `localCompare` will most of the time be * the right choice. * @param {boolean} [options.testSerializationHooks=true] Whether to test the serialization hooks or not, * might be CPU-intensive */ constructor (options) { super() let filename // Retrocompatibility with v0.6 and before if (typeof options === 'string') { deprecate(() => { filename = options this.inMemoryOnly = false // Default }, '@seald-io/nedb: Giving a string to the Datastore constructor is deprecated and will be removed in the next major version. Please use an options object with an argument \'filename\'.')() } else { options = options || {} filename = options.filename /** * Determines if the `Datastore` keeps data in-memory, or if it saves it in storage. Is not read after * instanciation. * @type {boolean} * @protected */ this.inMemoryOnly = options.inMemoryOnly || false /** * Determines if the `Datastore` should autoload the database upon instantiation. Is not read after instanciation. * @type {boolean} * @protected */ this.autoload = options.autoload || false /** * Determines if the `Datastore` should add `createdAt` and `updatedAt` fields automatically if not set by the user. * @type {boolean} * @protected */ this.timestampData = options.timestampData || false } // Determine whether in memory or persistent if (!filename || typeof filename !== 'string' || filename.length === 0) { /** * If null, it means `inMemoryOnly` is `true`. The `filename` is the name given to the storage module. Is not read * after instanciation. * @type {?string} * @protected */ this.filename = null this.inMemoryOnly = true } else { this.filename = filename } // String comparison function /** * Overrides default string comparison which is not well adapted to non-US characters in particular accented * letters. Native `localCompare` will most of the time be the right choice * @type {compareStrings} * @function * @protected */ this.compareStrings = options.compareStrings // Persistence handling /** * The `Persistence` instance for this `Datastore`. * @type {Persistence} */ this.persistence = new Persistence({ db: this, afterSerialization: options.afterSerialization, beforeDeserialization: options.beforeDeserialization, corruptAlertThreshold: options.corruptAlertThreshold, modes: options.modes, testSerializationHooks: options.testSerializationHooks }) // This new executor is ready if we don't use persistence // If we do, it will only be ready once loadDatabase is called /** * The `Executor` instance for this `Datastore`. It is used in all methods exposed by the {@link Datastore}, * any {@link Cursor} produced by the `Datastore` and by {@link Datastore#compactDatafileAsync} to ensure operations * are performed sequentially in the database. * @type {Executor} * @protected */ this.executor = new Executor() if (this.inMemoryOnly) this.executor.ready = true /** * Indexed by field name, dot notation can be used. * _id is always indexed and since _ids are generated randomly the underlying binary search tree is always well-balanced * @type {Object.} * @protected */ this.indexes = {} this.indexes._id = new Index({ fieldName: '_id', unique: true }) /** * Stores the time to live (TTL) of the indexes created. The key represents the field name, the value the number of * seconds after which data with this index field should be removed. * @type {Object.} * @protected */ this.ttlIndexes = {} // Queue a load of the database right away and call the onload handler // By default (no onload handler), if there is an error there, no operation will be possible so warn the user by throwing an exception if (this.autoload) { /** * A Promise that resolves when the autoload has finished. * * The onload callback is not awaited by this Promise, it is started immediately after that. * @type {?Promise} */ this.autoloadPromise = this.loadDatabaseAsync() this.autoloadPromise .then(() => { if (options.onload) options.onload() }, err => { if (options.onload) options.onload(err) else throw err }) } else this.autoloadPromise = null /** * Interval if {@link Datastore#setAutocompactionInterval} was called. * @private * @type {null|number} */ this._autocompactionIntervalId = null } /** * Queue a compaction/rewrite of the datafile. * It works by rewriting the database file, and compacts it since the cache always contains only the number of * documents in the collection while the data file is append-only so it may grow larger. * * @async */ compactDatafileAsync () { return this.executor.pushAsync(() => this.persistence.persistCachedDatabaseAsync()) } /** * Callback version of {@link Datastore#compactDatafileAsync}. * @param {NoParamCallback} [callback = () => {}] * @see Datastore#compactDatafileAsync */ compactDatafile (callback) { const promise = this.compactDatafileAsync() if (typeof callback === 'function') callbackify(() => promise)(callback) } /** * Set automatic compaction every `interval` ms * @param {Number} interval in milliseconds, with an enforced minimum of 5000 milliseconds */ setAutocompactionInterval (interval) { const minInterval = 5000 if (Number.isNaN(Number(interval))) throw new Error('Interval must be a non-NaN number') const realInterval = Math.max(Number(interval), minInterval) this.stopAutocompaction() this._autocompactionIntervalId = setInterval(() => { this.compactDatafile() }, realInterval) } /** * Stop autocompaction (do nothing if automatic compaction was not running) */ stopAutocompaction () { if (this._autocompactionIntervalId) { clearInterval(this._autocompactionIntervalId) this._autocompactionIntervalId = null } } /** * Callback version of {@link Datastore#loadDatabaseAsync}. * @param {NoParamCallback} [callback] * @see Datastore#loadDatabaseAsync */ loadDatabase (callback) { const promise = this.loadDatabaseAsync() if (typeof callback === 'function') callbackify(() => promise)(callback) } /** * Stops auto-compaction, finishes all queued operations, drops the database both in memory and in storage. * **WARNING**: it is not recommended re-using an instance of NeDB if its database has been dropped, it is * preferable to instantiate a new one. * @async * @return {Promise} */ dropDatabaseAsync () { return this.persistence.dropDatabaseAsync() // the executor is exceptionally used by Persistence } /** * Callback version of {@link Datastore#dropDatabaseAsync}. * @param {NoParamCallback} [callback] * @see Datastore#dropDatabaseAsync */ dropDatabase (callback) { const promise = this.dropDatabaseAsync() if (typeof callback === 'function') callbackify(() => promise)(callback) } /** * Load the database from the datafile, and trigger the execution of buffered commands if any. * @async * @return {Promise} */ loadDatabaseAsync () { return this.executor.pushAsync(() => this.persistence.loadDatabaseAsync(), true) } /** * Get an array of all the data in the database. * @return {document[]} */ getAllData () { return this.indexes._id.getAll() } /** * Reset all currently defined indexes. * @param {?document|?document[]} [newData] * @private */ _resetIndexes (newData) { for (const index of Object.values(this.indexes)) { index.reset(newData) } } /** * Callback version of {@link Datastore#ensureIndex}. * @param {object} options * @param {string|string[]} options.fieldName * @param {boolean} [options.unique = false] * @param {boolean} [options.sparse = false] * @param {number} [options.expireAfterSeconds] * @param {NoParamCallback} [callback] * @see Datastore#ensureIndex */ ensureIndex (options = {}, callback) { const promise = this.ensureIndexAsync(options) // to make sure the synchronous part of ensureIndexAsync is executed synchronously if (typeof callback === 'function') callbackify(() => promise)(callback) } /** * Ensure an index is kept for this field. Same parameters as lib/indexes * This function acts synchronously on the indexes, however the persistence of the indexes is deferred with the * executor. * @param {object} options * @param {string|string[]} options.fieldName Name of the field to index. Use the dot notation to index a field in a nested * document. For a compound index, use an array of field names. Using a comma in a field name is not permitted. * @param {boolean} [options.unique = false] Enforce field uniqueness. Note that a unique index will raise an error * if you try to index two documents for which the field is not defined. * @param {boolean} [options.sparse = false] Don't index documents for which the field is not defined. Use this option * along with "unique" if you want to accept multiple documents for which it is not defined. * @param {number} [options.expireAfterSeconds] - If set, the created index is a TTL (time to live) index, that will * automatically remove documents when the system date becomes larger than the date on the indexed field plus * `expireAfterSeconds`. Documents where the indexed field is not specified or not a `Date` object are ignored. * @return {Promise} */ async ensureIndexAsync (options = {}) { if (!options.fieldName) { const err = new Error('Cannot create an index without a fieldName') err.missingFieldName = true throw err } const _fields = [].concat(options.fieldName).sort() if (_fields.some(field => field.includes(','))) { throw new Error('Cannot use comma in index fieldName') } const _options = { ...options, fieldName: _fields.join(',') } if (this.indexes[_options.fieldName]) return this.indexes[_options.fieldName] = new Index(_options) if (options.expireAfterSeconds !== undefined) this.ttlIndexes[_options.fieldName] = _options.expireAfterSeconds // With this implementation index creation is not necessary to ensure TTL but we stick with MongoDB's API here try { this.indexes[_options.fieldName].insert(this.getAllData()) } catch (e) { delete this.indexes[_options.fieldName] throw e } // We may want to force all options to be persisted including defaults, not just the ones passed the index creation function await this.executor.pushAsync(() => this.persistence.persistNewStateAsync([{ $$indexCreated: _options }]), true) } /** * Callback version of {@link Datastore#removeIndexAsync}. * @param {string} fieldName * @param {NoParamCallback} [callback] * @see Datastore#removeIndexAsync */ removeIndex (fieldName, callback = () => {}) { const promise = this.removeIndexAsync(fieldName) callbackify(() => promise)(callback) } /** * Remove an index. * @param {string} fieldName Field name of the index to remove. Use the dot notation to remove an index referring to a * field in a nested document. * @return {Promise} * @see Datastore#removeIndex */ async removeIndexAsync (fieldName) { delete this.indexes[fieldName] await this.executor.pushAsync(() => this.persistence.persistNewStateAsync([{ $$indexRemoved: fieldName }]), true) } /** * Add one or several document(s) to all indexes. * * This is an internal function. * @param {document} doc * @private */ _addToIndexes (doc) { let failingIndex let error const keys = Object.keys(this.indexes) for (let i = 0; i < keys.length; i += 1) { try { this.indexes[keys[i]].insert(doc) } catch (e) { failingIndex = i error = e break } } // If an error happened, we need to rollback the insert on all other indexes if (error) { for (let i = 0; i < failingIndex; i += 1) { this.indexes[keys[i]].remove(doc) } throw error } } /** * Remove one or several document(s) from all indexes. * * This is an internal function. * @param {document} doc * @private */ _removeFromIndexes (doc) { for (const index of Object.values(this.indexes)) { index.remove(doc) } } /** * Update one or several documents in all indexes. * * To update multiple documents, oldDoc must be an array of { oldDoc, newDoc } pairs. * * If one update violates a constraint, all changes are rolled back. * * This is an internal function. * @param {document|Array.<{oldDoc: document, newDoc: document}>} oldDoc Document to update, or an `Array` of * `{oldDoc, newDoc}` pairs. * @param {document} [newDoc] Document to replace the oldDoc with. If the first argument is an `Array` of * `{oldDoc, newDoc}` pairs, this second argument is ignored. * @private */ _updateIndexes (oldDoc, newDoc) { let failingIndex let error const keys = Object.keys(this.indexes) for (let i = 0; i < keys.length; i += 1) { try { this.indexes[keys[i]].update(oldDoc, newDoc) } catch (e) { failingIndex = i error = e break } } // If an error happened, we need to rollback the update on all other indexes if (error) { for (let i = 0; i < failingIndex; i += 1) { this.indexes[keys[i]].revertUpdate(oldDoc, newDoc) } throw error } } /** * Get all candidate documents matching the query, regardless of their expiry status. * @param {query} query * @return {document[]} * * @private */ _getRawCandidates (query) { const indexNames = Object.keys(this.indexes) // STEP 1: get candidates list by checking indexes from most to least frequent usecase // For a basic match let usableQuery usableQuery = Object.entries(query) .filter(filterIndexNames(indexNames)) .pop() if (usableQuery) return this.indexes[usableQuery[0]].getMatching(usableQuery[1]) // For a compound match const compoundQueryKeys = indexNames .filter(indexName => indexName.indexOf(',') !== -1) .map(indexName => indexName.split(',')) .filter(subIndexNames => Object.entries(query) .filter(filterIndexNames(subIndexNames)).length === subIndexNames.length ) if (compoundQueryKeys.length > 0) return this.indexes[compoundQueryKeys[0]].getMatching(pick(query, compoundQueryKeys[0])) // For a $in match usableQuery = Object.entries(query) .filter(([k, v]) => !!(query[k] && Object.prototype.hasOwnProperty.call(query[k], '$in')) && indexNames.includes(k) ) .pop() if (usableQuery) return this.indexes[usableQuery[0]].getMatching(usableQuery[1].$in) // For a comparison match usableQuery = Object.entries(query) .filter(([k, v]) => !!(query[k] && (Object.prototype.hasOwnProperty.call(query[k], '$lt') || Object.prototype.hasOwnProperty.call(query[k], '$lte') || Object.prototype.hasOwnProperty.call(query[k], '$gt') || Object.prototype.hasOwnProperty.call(query[k], '$gte'))) && indexNames.includes(k) ) .pop() if (usableQuery) return this.indexes[usableQuery[0]].getBetweenBounds(usableQuery[1]) // By default, return all the DB data return this.getAllData() } /** * Return the list of candidates for a given query * Crude implementation for now, we return the candidates given by the first usable index if any * We try the following query types, in this order: basic match, $in match, comparison match * One way to make it better would be to enable the use of multiple indexes if the first usable index * returns too much data. I may do it in the future. * * Returned candidates will be scanned to find and remove all expired documents * * This is an internal function. * @param {query} query * @param {boolean} [dontExpireStaleDocs = false] If true don't remove stale docs. Useful for the remove function * which shouldn't be impacted by expirations. * @return {Promise} candidates * @private */ async _getCandidatesAsync (query, dontExpireStaleDocs = false) { const validDocs = [] // STEP 1: get candidates list by checking indexes from most to least frequent usecase const docs = this._getRawCandidates(query) // STEP 2: remove all expired documents if (!dontExpireStaleDocs) { const expiredDocsIds = [] const ttlIndexesFieldNames = Object.keys(this.ttlIndexes) docs.forEach(doc => { if (ttlIndexesFieldNames.every(i => !(doc[i] !== undefined && isDate(doc[i]) && Date.now() > doc[i].getTime() + this.ttlIndexes[i] * 1000))) validDocs.push(doc) else expiredDocsIds.push(doc._id) }) for (const _id of expiredDocsIds) { await this._removeAsync({ _id }, {}) } } else validDocs.push(...docs) return validDocs } /** * Insert a new document * This is an internal function, use {@link Datastore#insertAsync} which has the same signature. * @param {document|document[]} newDoc * @return {Promise} * @private */ async _insertAsync (newDoc) { const preparedDoc = this._prepareDocumentForInsertion(newDoc) this._insertInCache(preparedDoc) await this.persistence.persistNewStateAsync(Array.isArray(preparedDoc) ? preparedDoc : [preparedDoc]) return model.deepCopy(preparedDoc) } /** * Create a new _id that's not already in use * @return {string} id * @private */ _createNewId () { let attemptId = customUtils.uid(16) // Try as many times as needed to get an unused _id. As explained in customUtils, the probability of this ever happening is extremely small, so this is O(1) if (this.indexes._id.getMatching(attemptId).length > 0) attemptId = this._createNewId() return attemptId } /** * Prepare a document (or array of documents) to be inserted in a database * Meaning adds _id and timestamps if necessary on a copy of newDoc to avoid any side effect on user input * @param {document|document[]} newDoc document, or Array of documents, to prepare * @return {document|document[]} prepared document, or Array of prepared documents * @private */ _prepareDocumentForInsertion (newDoc) { let preparedDoc if (Array.isArray(newDoc)) { preparedDoc = [] newDoc.forEach(doc => { preparedDoc.push(this._prepareDocumentForInsertion(doc)) }) } else { preparedDoc = model.deepCopy(newDoc) if (preparedDoc._id === undefined) preparedDoc._id = this._createNewId() const now = new Date() if (this.timestampData && preparedDoc.createdAt === undefined) preparedDoc.createdAt = now if (this.timestampData && preparedDoc.updatedAt === undefined) preparedDoc.updatedAt = now model.checkObject(preparedDoc) } return preparedDoc } /** * If newDoc is an array of documents, this will insert all documents in the cache * @param {document|document[]} preparedDoc * @private */ _insertInCache (preparedDoc) { if (Array.isArray(preparedDoc)) this._insertMultipleDocsInCache(preparedDoc) else this._addToIndexes(preparedDoc) } /** * If one insertion fails (e.g. because of a unique constraint), roll back all previous * inserts and throws the error * @param {document[]} preparedDocs * @private */ _insertMultipleDocsInCache (preparedDocs) { let failingIndex let error for (let i = 0; i < preparedDocs.length; i += 1) { try { this._addToIndexes(preparedDocs[i]) } catch (e) { error = e failingIndex = i break } } if (error) { for (let i = 0; i < failingIndex; i += 1) { this._removeFromIndexes(preparedDocs[i]) } throw error } } /** * Callback version of {@link Datastore#insertAsync}. * @param {document|document[]} newDoc * @param {SingleDocumentCallback|MultipleDocumentsCallback} [callback] * @see Datastore#insertAsync */ insert (newDoc, callback) { const promise = this.insertAsync(newDoc) if (typeof callback === 'function') callbackify(() => promise)(callback) } /** * Insert a new document, or new documents. * @param {document|document[]} newDoc Document or array of documents to insert. * @return {Promise} The document(s) inserted. * @async */ insertAsync (newDoc) { return this.executor.pushAsync(() => this._insertAsync(newDoc)) } /** * Callback for {@link Datastore#countCallback}. * @callback Datastore~countCallback * @param {?Error} err * @param {?number} count */ /** * Callback-version of {@link Datastore#countAsync}. * @param {query} query * @param {Datastore~countCallback} [callback] * @return {Cursor|undefined} * @see Datastore#countAsync */ count (query, callback) { const cursor = this.countAsync(query) if (typeof callback === 'function') callbackify(cursor.execAsync.bind(cursor))(callback) else return cursor } /** * Count all documents matching the query. * @param {query} query MongoDB-style query * @return {Cursor} count * @async */ countAsync (query) { return new Cursor(this, query, docs => docs.length) } /** * Callback version of {@link Datastore#findAsync}. * @param {query} query * @param {projection|MultipleDocumentsCallback} [projection = {}] * @param {MultipleDocumentsCallback} [callback] * @return {Cursor|undefined} * @see Datastore#findAsync */ find (query, projection, callback) { if (arguments.length === 1) { projection = {} // callback is undefined, will return a cursor } else if (arguments.length === 2) { if (typeof projection === 'function') { callback = projection projection = {} } // If not assume projection is an object and callback undefined } const cursor = this.findAsync(query, projection) if (typeof callback === 'function') callbackify(cursor.execAsync.bind(cursor))(callback) else return cursor } /** * Find all documents matching the query. * We return the {@link Cursor} that the user can either `await` directly or use to can {@link Cursor#limit} or * {@link Cursor#skip} before. * @param {query} query MongoDB-style query * @param {projection} [projection = {}] MongoDB-style projection * @return {Cursor} * @async */ findAsync (query, projection = {}) { const cursor = new Cursor(this, query, docs => docs.map(doc => model.deepCopy(doc))) cursor.projection(projection) return cursor } /** * @callback Datastore~findOneCallback * @param {?Error} err * @param {document} doc */ /** * Callback version of {@link Datastore#findOneAsync}. * @param {query} query * @param {projection|SingleDocumentCallback} [projection = {}] * @param {SingleDocumentCallback} [callback] * @return {Cursor|undefined} * @see Datastore#findOneAsync */ findOne (query, projection, callback) { if (arguments.length === 1) { projection = {} // callback is undefined, will return a cursor } else if (arguments.length === 2) { if (typeof projection === 'function') { callback = projection projection = {} } // If not assume projection is an object and callback undefined } const cursor = this.findOneAsync(query, projection) if (typeof callback === 'function') callbackify(cursor.execAsync.bind(cursor))(callback) else return cursor } /** * Find one document matching the query. * We return the {@link Cursor} that the user can either `await` directly or use to can {@link Cursor#skip} before. * @param {query} query MongoDB-style query * @param {projection} projection MongoDB-style projection * @return {Cursor} */ findOneAsync (query, projection = {}) { const cursor = new Cursor(this, query, docs => docs.length === 1 ? model.deepCopy(docs[0]) : null) cursor.projection(projection).limit(1) return cursor } /** * See {@link Datastore#updateAsync} return type for the definition of the callback parameters. * * **WARNING:** Prior to 3.0.0, `upsert` was either `true` of falsy (but not `false`), it is now always a boolean. * `affectedDocuments` could be `undefined` when `returnUpdatedDocs` was `false`, it is now `null` in these cases. * * **WARNING:** Prior to 1.8.0, the `upsert` argument was not given, it was impossible for the developer to determine * during a `{ multi: false, returnUpdatedDocs: true, upsert: true }` update if it inserted a document or just updated * it. * * @callback Datastore~updateCallback * @param {?Error} err * @param {number} numAffected * @param {?document[]|?document} affectedDocuments * @param {boolean} upsert * @see {Datastore#updateAsync} */ /** * Version without the using {@link Datastore~executor} of {@link Datastore#updateAsync}, use it instead. * * @param {query} query * @param {document|update} update * @param {Object} options * @param {boolean} [options.multi = false] * @param {boolean} [options.upsert = false] * @param {boolean} [options.returnUpdatedDocs = false] * @return {Promise<{numAffected: number, affectedDocuments: document[]|document|null, upsert: boolean}>} * @private * @see Datastore#updateAsync */ async _updateAsync (query, update, options) { const multi = options.multi !== undefined ? options.multi : false const upsert = options.upsert !== undefined ? options.upsert : false // If upsert option is set, check whether we need to insert the doc if (upsert) { const cursor = new Cursor(this, query) // Need to use an internal function not tied to the executor to avoid deadlock const docs = await cursor.limit(1)._execAsync() if (docs.length !== 1) { let toBeInserted try { model.checkObject(update) // updateQuery is a simple object with no modifier, use it as the document to insert toBeInserted = update } catch (e) { // updateQuery contains modifiers, use the find query as the base, // strip it from all operators and update it according to updateQuery toBeInserted = model.modify(model.deepCopy(query, true), update) } const newDoc = await this._insertAsync(toBeInserted) return { numAffected: 1, affectedDocuments: newDoc, upsert: true } } } // Perform the update let numReplaced = 0 let modifiedDoc const modifications = [] let createdAt const candidates = await this._getCandidatesAsync(query) // Preparing update (if an error is thrown here neither the datafile nor // the in-memory indexes are affected) for (const candidate of candidates) { if (model.match(candidate, query) && (multi || numReplaced === 0)) { numReplaced += 1 if (this.timestampData) { createdAt = candidate.createdAt } modifiedDoc = model.modify(candidate, update) if (this.timestampData) { modifiedDoc.createdAt = createdAt modifiedDoc.updatedAt = new Date() } modifications.push({ oldDoc: candidate, newDoc: modifiedDoc }) } } // Change the docs in memory this._updateIndexes(modifications) // Update the datafile const updatedDocs = modifications.map(x => x.newDoc) await this.persistence.persistNewStateAsync(updatedDocs) if (!options.returnUpdatedDocs) return { numAffected: numReplaced, upsert: false, affectedDocuments: null } else { let updatedDocsDC = [] updatedDocs.forEach(doc => { updatedDocsDC.push(model.deepCopy(doc)) }) if (!multi) updatedDocsDC = updatedDocsDC[0] return { numAffected: numReplaced, affectedDocuments: updatedDocsDC, upsert: false } } } /** * Callback version of {@link Datastore#updateAsync}. * @param {query} query * @param {document|*} update * @param {Object|Datastore~updateCallback} [options|] * @param {boolean} [options.multi = false] * @param {boolean} [options.upsert = false] * @param {boolean} [options.returnUpdatedDocs = false] * @param {Datastore~updateCallback} [callback] * @see Datastore#updateAsync * */ update (query, update, options, callback) { if (typeof options === 'function') { callback = options options = {} } const _callback = (err, res = {}) => { if (callback) callback(err, res.numAffected, res.affectedDocuments, res.upsert) } callbackify((query, update, options) => this.updateAsync(query, update, options))(query, update, options, _callback) } /** * Update all docs matching query. * @param {query} query is the same kind of finding query you use with `find` and `findOne`. * @param {document|*} update specifies how the documents should be modified. It is either a new document or a * set of modifiers (you cannot use both together, it doesn't make sense!). Using a new document will replace the * matched docs. Using a set of modifiers will create the fields they need to modify if they don't exist, and you can * apply them to subdocs. Available field modifiers are `$set` to change a field's value, `$unset` to delete a field, * `$inc` to increment a field's value and `$min`/`$max` to change field's value, only if provided value is * less/greater than current value. To work on arrays, you have `$push`, `$pop`, `$addToSet`, `$pull`, and the special * `$each` and `$slice`. * @param {Object} [options = {}] Optional options * @param {boolean} [options.multi = false] If true, can update multiple documents * @param {boolean} [options.upsert = false] If true, can insert a new document corresponding to the `update` rules if * your `query` doesn't match anything. If your `update` is a simple object with no modifiers, it is the inserted * document. In the other case, the `query` is stripped from all operator recursively, and the `update` is applied to * it. * @param {boolean} [options.returnUpdatedDocs = false] (not Mongo-DB compatible) If true and update is not an upsert, * will return the array of documents matched by the find query and updated. Updated documents will be returned even * if the update did not actually modify them. * @return {Promise<{numAffected: number, affectedDocuments: document[]|document|null, upsert: boolean}>} * - `upsert` is `true` if and only if the update did insert a document, **cannot be true if `options.upsert !== true`**. * - `numAffected` is the number of documents affected by the update or insertion (if `options.multi` is `false` or `options.upsert` is `true`, cannot exceed `1`); * - `affectedDocuments` can be one of the following: * - If `upsert` is `true`, the inserted document; * - If `options.returnUpdatedDocs` is `false`, `null`; * - If `options.returnUpdatedDocs` is `true`: * - If `options.multi` is `false`, the updated document; * - If `options.multi` is `true`, the array of updated documents. * @async */ updateAsync (query, update, options = {}) { return this.executor.pushAsync(() => this._updateAsync(query, update, options)) } /** * @callback Datastore~removeCallback * @param {?Error} err * @param {?number} numRemoved */ /** * Internal version without using the {@link Datastore#executor} of {@link Datastore#removeAsync}, use it instead. * * @param {query} query * @param {object} [options] * @param {boolean} [options.multi = false] * @return {Promise} * @private * @see Datastore#removeAsync */ async _removeAsync (query, options = {}) { const multi = options.multi !== undefined ? options.multi : false const candidates = await this._getCandidatesAsync(query, true) const removedDocs = [] let numRemoved = 0 candidates.forEach(d => { if (model.match(d, query) && (multi || numRemoved === 0)) { numRemoved += 1 removedDocs.push({ $$deleted: true, _id: d._id }) this._removeFromIndexes(d) } }) await this.persistence.persistNewStateAsync(removedDocs) return numRemoved } /** * Callback version of {@link Datastore#removeAsync}. * @param {query} query * @param {object|Datastore~removeCallback} [options={}] * @param {boolean} [options.multi = false] * @param {Datastore~removeCallback} [cb = () => {}] * @see Datastore#removeAsync */ remove (query, options, cb) { if (typeof options === 'function') { cb = options options = {} } const callback = cb || (() => {}) callbackify((query, options) => this.removeAsync(query, options))(query, options, callback) } /** * Remove all docs matching the query. * @param {query} query MongoDB-style query * @param {object} [options={}] Optional options * @param {boolean} [options.multi = false] If true, can update multiple documents * @return {Promise} How many documents were removed * @async */ removeAsync (query, options = {}) { return this.executor.pushAsync(() => this._removeAsync(query, options)) } } module.exports = Datastore /***/ }), /***/ 196: /***/ ((module, __unused_webpack_exports, __webpack_require__) => { const Waterfall = __webpack_require__(496) /** * Executes operations sequentially. * Has an option for a buffer that can be triggered afterwards. * @private */ class Executor { /** * Instantiates a new Executor. */ constructor () { /** * If this.ready is `false`, then every task pushed will be buffered until this.processBuffer is called. * @type {boolean} * @private */ this.ready = false /** * The main queue * @type {Waterfall} * @private */ this.queue = new Waterfall() /** * The buffer queue * @type {Waterfall} * @private */ this.buffer = null /** * Method to trigger the buffer processing. * * Do not be use directly, use `this.processBuffer` instead. * @function * @private */ this._triggerBuffer = null this.resetBuffer() } /** * If executor is ready, queue task (and process it immediately if executor was idle) * If not, buffer task for later processing * @param {AsyncFunction} task Function to execute * @param {boolean} [forceQueuing = false] Optional (defaults to false) force executor to queue task even if it is not ready * @return {Promise<*>} * @async * @see Executor#push */ pushAsync (task, forceQueuing = false) { if (this.ready || forceQueuing) return this.queue.waterfall(task)() else return this.buffer.waterfall(task)() } /** * Queue all tasks in buffer (in the same order they came in) * Automatically sets executor as ready */ processBuffer () { this.ready = true this._triggerBuffer() this.queue.waterfall(() => this.buffer.guardian) } /** * Removes all tasks queued up in the buffer */ resetBuffer () { this.buffer = new Waterfall() this.buffer.chain(new Promise(resolve => { this._triggerBuffer = resolve })) if (this.ready) this._triggerBuffer() } } // Interface module.exports = Executor /***/ }), /***/ 98: /***/ ((module, __unused_webpack_exports, __webpack_require__) => { const BinarySearchTree = (__webpack_require__(908).AVLTree) const model = __webpack_require__(118) const { uniq, isDate } = __webpack_require__(988) /** * Two indexed pointers are equal if they point to the same place * @param {*} a * @param {*} b * @return {boolean} * @private */ const checkValueEquality = (a, b) => a === b /** * Type-aware projection * @param {*} elt * @return {string|*} * @private */ const projectForUnique = elt => { if (elt === null) return '$null' if (typeof elt === 'string') return '$string' + elt if (typeof elt === 'boolean') return '$boolean' + elt if (typeof elt === 'number') return '$number' + elt if (isDate(elt)) return '$date' + elt.getTime() return elt // Arrays and objects, will check for pointer equality } /** * Indexes on field names, with atomic operations and which can optionally enforce a unique constraint or allow indexed * fields to be undefined * @private */ class Index { /** * Create a new index * All methods on an index guarantee that either the whole operation was successful and the index changed * or the operation was unsuccessful and an error is thrown while the index is unchanged * @param {object} options * @param {string} options.fieldName On which field should the index apply, can use dot notation to index on sub fields, can use comma-separated notation to use compound indexes * @param {boolean} [options.unique = false] Enforces a unique constraint * @param {boolean} [options.sparse = false] Allows a sparse index (we can have documents for which fieldName is `undefined`) */ constructor (options) { /** * On which field the index applies to, can use dot notation to index on sub fields, can use comma-separated notation to use compound indexes. * @type {string} */ this.fieldName = options.fieldName if (typeof this.fieldName !== 'string') throw new Error('fieldName must be a string') /** * Internal property which is an Array representing the fieldName split with `,`, useful only for compound indexes. * @type {string[]} * @private */ this._fields = this.fieldName.split(',') /** * Defines if the index enforces a unique constraint for this index. * @type {boolean} */ this.unique = options.unique || false /** * Defines if we can have documents for which fieldName is `undefined` * @type {boolean} */ this.sparse = options.sparse || false /** * Options object given to the underlying BinarySearchTree. * @type {{unique: boolean, checkValueEquality: (function(*, *): boolean), compareKeys: ((function(*, *, compareStrings): (number|number))|*)}} */ this.treeOptions = { unique: this.unique, compareKeys: model.compareThings, checkValueEquality } /** * Underlying BinarySearchTree for this index. Uses an AVLTree for optimization. * @type {AVLTree} */ this.tree = new BinarySearchTree(this.treeOptions) } /** * Reset an index * @param {?document|?document[]} [newData] Data to initialize the index with. If an error is thrown during * insertion, the index is not modified. */ reset (newData) { this.tree = new BinarySearchTree(this.treeOptions) if (newData) this.insert(newData) } /** * Insert a new document in the index * If an array is passed, we insert all its elements (if one insertion fails the index is not modified) * O(log(n)) * @param {document|document[]} doc The document, or array of documents, to insert. */ insert (doc) { let keys let failingIndex let error if (Array.isArray(doc)) { this.insertMultipleDocs(doc) return } const key = model.getDotValues(doc, this._fields) // We don't index documents that don't contain the field if the index is sparse if ((key === undefined || (typeof key === 'object' && key !== null && Object.values(key).every(el => el === undefined))) && this.sparse) return if (!Array.isArray(key)) this.tree.insert(key, doc) else { // If an insert fails due to a unique constraint, roll back all inserts before it keys = uniq(key, projectForUnique) for (let i = 0; i < keys.length; i += 1) { try { this.tree.insert(keys[i], doc) } catch (e) { error = e failingIndex = i break } } if (error) { for (let i = 0; i < failingIndex; i += 1) { this.tree.delete(keys[i], doc) } throw error } } } /** * Insert an array of documents in the index * If a constraint is violated, the changes should be rolled back and an error thrown * @param {document[]} docs Array of documents to insert. * @private */ insertMultipleDocs (docs) { let error let failingIndex for (let i = 0; i < docs.length; i += 1) { try { this.insert(docs[i]) } catch (e) { error = e failingIndex = i break } } if (error) { for (let i = 0; i < failingIndex; i += 1) { this.remove(docs[i]) } throw error } } /** * Removes a document from the index. * If an array is passed, we remove all its elements * The remove operation is safe with regards to the 'unique' constraint * O(log(n)) * @param {document[]|document} doc The document, or Array of documents, to remove. */ remove (doc) { if (Array.isArray(doc)) { doc.forEach(d => { this.remove(d) }) return } const key = model.getDotValues(doc, this._fields) if (key === undefined && this.sparse) return if (!Array.isArray(key)) { this.tree.delete(key, doc) } else { uniq(key, projectForUnique).forEach(_key => { this.tree.delete(_key, doc) }) } } /** * Update a document in the index * If a constraint is violated, changes are rolled back and an error thrown * Naive implementation, still in O(log(n)) * @param {document|Array.<{oldDoc: document, newDoc: document}>} oldDoc Document to update, or an `Array` of * `{oldDoc, newDoc}` pairs. * @param {document} [newDoc] Document to replace the oldDoc with. If the first argument is an `Array` of * `{oldDoc, newDoc}` pairs, this second argument is ignored. */ update (oldDoc, newDoc) { if (Array.isArray(oldDoc)) { this.updateMultipleDocs(oldDoc) return } this.remove(oldDoc) try { this.insert(newDoc) } catch (e) { this.insert(oldDoc) throw e } } /** * Update multiple documents in the index * If a constraint is violated, the changes need to be rolled back * and an error thrown * @param {Array.<{oldDoc: document, newDoc: document}>} pairs * * @private */ updateMultipleDocs (pairs) { let failingIndex let error for (let i = 0; i < pairs.length; i += 1) { this.remove(pairs[i].oldDoc) } for (let i = 0; i < pairs.length; i += 1) { try { this.insert(pairs[i].newDoc) } catch (e) { error = e failingIndex = i break } } // If an error was raised, roll back changes in the inverse order if (error) { for (let i = 0; i < failingIndex; i += 1) { this.remove(pairs[i].newDoc) } for (let i = 0; i < pairs.length; i += 1) { this.insert(pairs[i].oldDoc) } throw error } } /** * Revert an update * @param {document|Array.<{oldDoc: document, newDoc: document}>} oldDoc Document to revert to, or an `Array` of `{oldDoc, newDoc}` pairs. * @param {document} [newDoc] Document to revert from. If the first argument is an Array of {oldDoc, newDoc}, this second argument is ignored. */ revertUpdate (oldDoc, newDoc) { const revert = [] if (!Array.isArray(oldDoc)) this.update(newDoc, oldDoc) else { oldDoc.forEach(pair => { revert.push({ oldDoc: pair.newDoc, newDoc: pair.oldDoc }) }) this.update(revert) } } /** * Get all documents in index whose key match value (if it is a Thing) or one of the elements of value (if it is an array of Things) * @param {Array.<*>|*} value Value to match the key against * @return {document[]} */ getMatching (value) { if (!Array.isArray(value)) return this.tree.search(value) else { const _res = {} const res = [] value.forEach(v => { this.getMatching(v).forEach(doc => { _res[doc._id] = doc }) }) Object.keys(_res).forEach(_id => { res.push(_res[_id]) }) return res } } /** * Get all documents in index whose key is between bounds are they are defined by query * Documents are sorted by key * @param {object} query An object with at least one matcher among $gt, $gte, $lt, $lte. * @param {*} [query.$gt] Greater than matcher. * @param {*} [query.$gte] Greater than or equal matcher. * @param {*} [query.$lt] Lower than matcher. * @param {*} [query.$lte] Lower than or equal matcher. * @return {document[]} */ getBetweenBounds (query) { return this.tree.betweenBounds(query) } /** * Get all elements in the index * @return {document[]} */ getAll () { const res = [] this.tree.executeOnEveryNode(node => { res.push(...node.data) }) return res } } // Interface module.exports = Index /***/ }), /***/ 118: /***/ ((module, __unused_webpack_exports, __webpack_require__) => { /** * Handle models (i.e. docs) * Serialization/deserialization * Copying * Querying, update * @module model * @private */ const { uniq, isDate, isRegExp } = __webpack_require__(988) /** * Check a key, throw an error if the key is non valid * @param {string} k key * @param {document} v value, needed to treat the Date edge case * Non-treatable edge cases here: if part of the object if of the form { $$date: number } or { $$deleted: true } * Its serialized-then-deserialized version it will transformed into a Date object * But you really need to want it to trigger such behaviour, even when warned not to use '$' at the beginning of the field names... * @private */ const checkKey = (k, v) => { if (typeof k === 'number') k = k.toString() if ( k[0] === '$' && !(k === '$$date' && typeof v === 'number') && !(k === '$$deleted' && v === true) && !(k === '$$indexCreated') && !(k === '$$indexRemoved') ) throw new Error('Field names cannot begin with the $ character') if (k.indexOf('.') !== -1) throw new Error('Field names cannot contain a .') } /** * Check a DB object and throw an error if it's not valid * Works by applying the above checkKey function to all fields recursively * @param {document|document[]} obj * @alias module:model.checkObject */ const checkObject = obj => { if (Array.isArray(obj)) { obj.forEach(o => { checkObject(o) }) } if (typeof obj === 'object' && obj !== null) { for (const k in obj) { if (Object.prototype.hasOwnProperty.call(obj, k)) { checkKey(k, obj[k]) checkObject(obj[k]) } } } } /** * Serialize an object to be persisted to a one-line string * For serialization/deserialization, we use the native JSON parser and not eval or Function * That gives us less freedom but data entered in the database may come from users * so eval and the like are not safe * Accepted primitive types: Number, String, Boolean, Date, null * Accepted secondary types: Objects, Arrays * @param {document} obj * @return {string} * @alias module:model.serialize */ const serialize = obj => { return JSON.stringify(obj, function (k, v) { checkKey(k, v) if (v === undefined) return undefined if (v === null) return null // Hackish way of checking if object is Date (this way it works between execution contexts in node-webkit). // We can't use value directly because for dates it is already string in this function (date.toJSON was already called), so we use this if (typeof this[k].getTime === 'function') return { $$date: this[k].getTime() } return v }) } /** * From a one-line representation of an object generate by the serialize function * Return the object itself * @param {string} rawData * @return {document} * @alias module:model.deserialize */ const deserialize = rawData => JSON.parse(rawData, function (k, v) { if (k === '$$date') return new Date(v) if ( typeof v === 'string' || typeof v === 'number' || typeof v === 'boolean' || v === null ) return v if (v && v.$$date) return v.$$date return v }) /** * Deep copy a DB object * The optional strictKeys flag (defaulting to false) indicates whether to copy everything or only fields * where the keys are valid, i.e. don't begin with $ and don't contain a . * @param {?document} obj * @param {boolean} [strictKeys=false] * @return {?document} * @alias module:modelel:(.*) */ function deepCopy (obj, strictKeys) { if ( typeof obj === 'boolean' || typeof obj === 'number' || typeof obj === 'string' || obj === null || (isDate(obj)) ) return obj if (Array.isArray(obj)) return obj.map(o => deepCopy(o, strictKeys)) if (typeof obj === 'object') { const res = {} for (const k in obj) { if ( Object.prototype.hasOwnProperty.call(obj, k) && (!strictKeys || (k[0] !== '$' && k.indexOf('.') === -1)) ) { res[k] = deepCopy(obj[k], strictKeys) } } return res } return undefined // For now everything else is undefined. We should probably throw an error instead } /** * Tells if an object is a primitive type or a "real" object * Arrays are considered primitive * @param {*} obj * @return {boolean} * @alias module:modelel:(.*) */ const isPrimitiveType = obj => ( typeof obj === 'boolean' || typeof obj === 'number' || typeof obj === 'string' || obj === null || isDate(obj) || Array.isArray(obj) ) /** * Utility functions for comparing things * Assumes type checking was already done (a and b already have the same type) * compareNSB works for numbers, strings and booleans * @param {number|string|boolean} a * @param {number|string|boolean} b * @return {number} 0 if a == b, 1 i a > b, -1 if a < b * @private */ const compareNSB = (a, b) => { if (a < b) return -1 if (a > b) return 1 return 0 } /** * Utility function for comparing array * Assumes type checking was already done (a and b already have the same type) * compareNSB works for numbers, strings and booleans * @param {Array} a * @param {Array} b * @return {number} 0 if arrays have the same length and all elements equal one another. Else either 1 or -1. * @private */ const compareArrays = (a, b) => { const minLength = Math.min(a.length, b.length) for (let i = 0; i < minLength; i += 1) { const comp = compareThings(a[i], b[i]) if (comp !== 0) return comp } // Common section was identical, longest one wins return compareNSB(a.length, b.length) } /** * Compare { things U undefined } * Things are defined as any native types (string, number, boolean, null, date) and objects * We need to compare with undefined as it will be used in indexes * In the case of objects and arrays, we deep-compare * If two objects dont have the same type, the (arbitrary) type hierarchy is: undefined, null, number, strings, boolean, dates, arrays, objects * Return -1 if a < b, 1 if a > b and 0 if a = b (note that equality here is NOT the same as defined in areThingsEqual!) * @param {*} a * @param {*} b * @param {compareStrings} [_compareStrings] String comparing function, returning -1, 0 or 1, overriding default string comparison (useful for languages with accented letters) * @return {number} * @alias module:model.compareThings */ const compareThings = (a, b, _compareStrings) => { const compareStrings = _compareStrings || compareNSB // undefined if (a === undefined) return b === undefined ? 0 : -1 if (b === undefined) return 1 // no need to test if a === undefined // null if (a === null) return b === null ? 0 : -1 if (b === null) return 1 // no need to test if a === null // Numbers if (typeof a === 'number') return typeof b === 'number' ? compareNSB(a, b) : -1 if (typeof b === 'number') return typeof a === 'number' ? compareNSB(a, b) : 1 // Strings if (typeof a === 'string') return typeof b === 'string' ? compareStrings(a, b) : -1 if (typeof b === 'string') return typeof a === 'string' ? compareStrings(a, b) : 1 // Booleans if (typeof a === 'boolean') return typeof b === 'boolean' ? compareNSB(a, b) : -1 if (typeof b === 'boolean') return typeof a === 'boolean' ? compareNSB(a, b) : 1 // Dates if (isDate(a)) return isDate(b) ? compareNSB(a.getTime(), b.getTime()) : -1 if (isDate(b)) return isDate(a) ? compareNSB(a.getTime(), b.getTime()) : 1 // Arrays (first element is most significant and so on) if (Array.isArray(a)) return Array.isArray(b) ? compareArrays(a, b) : -1 if (Array.isArray(b)) return Array.isArray(a) ? compareArrays(a, b) : 1 // Objects const aKeys = Object.keys(a).sort() const bKeys = Object.keys(b).sort() for (let i = 0; i < Math.min(aKeys.length, bKeys.length); i += 1) { const comp = compareThings(a[aKeys[i]], b[bKeys[i]]) if (comp !== 0) return comp } return compareNSB(aKeys.length, bKeys.length) } // ============================================================== // Updating documents // ============================================================== /** * @callback modifierFunction * The signature of modifier functions is as follows * Their structure is always the same: recursively follow the dot notation while creating * the nested documents if needed, then apply the "last step modifier" * @param {Object} obj The model to modify * @param {String} field Can contain dots, in that case that means we will set a subfield recursively * @param {document} value */ /** * Create the complete modifier function * @param {modifierFunction} lastStepModifierFunction a lastStepModifierFunction * @param {boolean} [unset = false] Bad looking specific fix, needs to be generalized modifiers that behave like $unset are implemented * @return {modifierFunction} * @private */ const createModifierFunction = (lastStepModifierFunction, unset = false) => (obj, field, value) => { const func = (obj, field, value) => { const fieldParts = typeof field === 'string' ? field.split('.') : field if (fieldParts.length === 1) lastStepModifierFunction(obj, field, value) else { if (obj[fieldParts[0]] === undefined) { if (unset) return obj[fieldParts[0]] = {} } func(obj[fieldParts[0]], fieldParts.slice(1), value) } } return func(obj, field, value) } const $addToSetPartial = (obj, field, value) => { // Create the array if it doesn't exist if (!Object.prototype.hasOwnProperty.call(obj, field)) { obj[field] = [] } if (!Array.isArray(obj[field])) throw new Error('Can\'t $addToSet an element on non-array values') if (value !== null && typeof value === 'object' && value.$each) { if (Object.keys(value).length > 1) throw new Error('Can\'t use another field in conjunction with $each') if (!Array.isArray(value.$each)) throw new Error('$each requires an array value') value.$each.forEach(v => { $addToSetPartial(obj, field, v) }) } else { let addToSet = true obj[field].forEach(v => { if (compareThings(v, value) === 0) addToSet = false }) if (addToSet) obj[field].push(value) } } /** * @enum {modifierFunction} */ const modifierFunctions = { /** * Set a field to a new value */ $set: createModifierFunction((obj, field, value) => { obj[field] = value }), /** * Unset a field */ $unset: createModifierFunction((obj, field, value) => { delete obj[field] }, true), /** * Updates the value of the field, only if specified field is smaller than the current value of the field */ $min: createModifierFunction((obj, field, value) => { if (typeof obj[field] === 'undefined') obj[field] = value else if (value < obj[field]) obj[field] = value }), /** * Updates the value of the field, only if specified field is greater than the current value of the field */ $max: createModifierFunction((obj, field, value) => { if (typeof obj[field] === 'undefined') obj[field] = value else if (value > obj[field]) obj[field] = value }), /** * Increment a numeric field's value */ $inc: createModifierFunction((obj, field, value) => { if (typeof value !== 'number') throw new Error(`${value} must be a number`) if (typeof obj[field] !== 'number') { if (!Object.prototype.hasOwnProperty.call(obj, field)) obj[field] = value else throw new Error('Don\'t use the $inc modifier on non-number fields') } else obj[field] += value }), /** * Removes all instances of a value from an existing array */ $pull: createModifierFunction((obj, field, value) => { if (!Array.isArray(obj[field])) throw new Error('Can\'t $pull an element from non-array values') const arr = obj[field] for (let i = arr.length - 1; i >= 0; i -= 1) { if (match(arr[i], value)) arr.splice(i, 1) } }), /** * Remove the first or last element of an array */ $pop: createModifierFunction((obj, field, value) => { if (!Array.isArray(obj[field])) throw new Error('Can\'t $pop an element from non-array values') if (typeof value !== 'number') throw new Error(`${value} isn't an integer, can't use it with $pop`) if (value === 0) return if (value > 0) obj[field] = obj[field].slice(0, obj[field].length - 1) else obj[field] = obj[field].slice(1) }), /** * Add an element to an array field only if it is not already in it * No modification if the element is already in the array * Note that it doesn't check whether the original array contains duplicates */ $addToSet: createModifierFunction($addToSetPartial), /** * Push an element to the end of an array field * Optional modifier $each instead of value to push several values * Optional modifier $slice to slice the resulting array, see https://docs.mongodb.org/manual/reference/operator/update/slice/ * Difference with MongoDB: if $slice is specified and not $each, we act as if value is an empty array */ $push: createModifierFunction((obj, field, value) => { // Create the array if it doesn't exist if (!Object.prototype.hasOwnProperty.call(obj, field)) obj[field] = [] if (!Array.isArray(obj[field])) throw new Error('Can\'t $push an element on non-array values') if ( value !== null && typeof value === 'object' && value.$slice && value.$each === undefined ) value.$each = [] if (value !== null && typeof value === 'object' && value.$each) { if ( Object.keys(value).length >= 3 || (Object.keys(value).length === 2 && value.$slice === undefined) ) throw new Error('Can only use $slice in cunjunction with $each when $push to array') if (!Array.isArray(value.$each)) throw new Error('$each requires an array value') value.$each.forEach(v => { obj[field].push(v) }) if (value.$slice === undefined || typeof value.$slice !== 'number') return if (value.$slice === 0) obj[field] = [] else { let start let end const n = obj[field].length if (value.$slice < 0) { start = Math.max(0, n + value.$slice) end = n } else if (value.$slice > 0) { start = 0 end = Math.min(n, value.$slice) } obj[field] = obj[field].slice(start, end) } } else { obj[field].push(value) } }) } /** * Modify a DB object according to an update query * @param {document} obj * @param {query} updateQuery * @return {document} * @alias module:model.modify */ const modify = (obj, updateQuery) => { const keys = Object.keys(updateQuery) const firstChars = keys.map(item => item[0]) const dollarFirstChars = firstChars.filter(c => c === '$') let newDoc let modifiers if (keys.indexOf('_id') !== -1 && updateQuery._id !== obj._id) throw new Error('You cannot change a document\'s _id') if (dollarFirstChars.length !== 0 && dollarFirstChars.length !== firstChars.length) throw new Error('You cannot mix modifiers and normal fields') if (dollarFirstChars.length === 0) { // Simply replace the object with the update query contents newDoc = deepCopy(updateQuery) newDoc._id = obj._id } else { // Apply modifiers modifiers = uniq(keys) newDoc = deepCopy(obj) modifiers.forEach(m => { if (!modifierFunctions[m]) throw new Error(`Unknown modifier ${m}`) // Can't rely on Object.keys throwing on non objects since ES6 // Not 100% satisfying as non objects can be interpreted as objects but no false negatives so we can live with it if (typeof updateQuery[m] !== 'object') throw new Error(`Modifier ${m}'s argument must be an object`) const keys = Object.keys(updateQuery[m]) keys.forEach(k => { modifierFunctions[m](newDoc, k, updateQuery[m][k]) }) }) } // Check result is valid and return it checkObject(newDoc) if (obj._id !== newDoc._id) throw new Error('You can\'t change a document\'s _id') return newDoc } // ============================================================== // Finding documents // ============================================================== /** * Get a value from object with dot notation * @param {object} obj * @param {string} field * @return {*} * @alias module:model.getDotValue */ const getDotValue = (obj, field) => { const fieldParts = typeof field === 'string' ? field.split('.') : field if (!obj) return undefined // field cannot be empty so that means we should return undefined so that nothing can match if (fieldParts.length === 0) return obj if (fieldParts.length === 1) return obj[fieldParts[0]] if (Array.isArray(obj[fieldParts[0]])) { // If the next field is an integer, return only this item of the array const i = parseInt(fieldParts[1], 10) if (typeof i === 'number' && !isNaN(i)) return getDotValue(obj[fieldParts[0]][i], fieldParts.slice(2)) // Return the array of values return obj[fieldParts[0]].map(el => getDotValue(el, fieldParts.slice(1))) } else return getDotValue(obj[fieldParts[0]], fieldParts.slice(1)) } /** * Get dot values for either a bunch of fields or just one. */ const getDotValues = (obj, fields) => { if (!Array.isArray(fields)) throw new Error('fields must be an Array') if (fields.length > 1) { const key = {} for (const field of fields) { key[field] = getDotValue(obj, field) } return key } else return getDotValue(obj, fields[0]) } /** * Check whether 'things' are equal * Things are defined as any native types (string, number, boolean, null, date) and objects * In the case of object, we check deep equality * Returns true if they are, false otherwise * @param {*} a * @param {*} a * @return {boolean} * @alias module:model.areThingsEqual */ const areThingsEqual = (a, b) => { // Strings, booleans, numbers, null if ( a === null || typeof a === 'string' || typeof a === 'boolean' || typeof a === 'number' || b === null || typeof b === 'string' || typeof b === 'boolean' || typeof b === 'number' ) return a === b // Dates if (isDate(a) || isDate(b)) return isDate(a) && isDate(b) && a.getTime() === b.getTime() // Arrays (no match since arrays are used as a $in) // undefined (no match since they mean field doesn't exist and can't be serialized) if ( (!(Array.isArray(a) && Array.isArray(b)) && (Array.isArray(a) || Array.isArray(b))) || a === undefined || b === undefined ) return false // General objects (check for deep equality) // a and b should be objects at this point let aKeys let bKeys try { aKeys = Object.keys(a) bKeys = Object.keys(b) } catch (e) { return false } if (aKeys.length !== bKeys.length) return false for (const el of aKeys) { if (bKeys.indexOf(el) === -1) return false if (!areThingsEqual(a[el], b[el])) return false } return true } /** * Check that two values are comparable * @param {*} a * @param {*} a * @return {boolean} * @private */ const areComparable = (a, b) => { if ( typeof a !== 'string' && typeof a !== 'number' && !isDate(a) && typeof b !== 'string' && typeof b !== 'number' && !isDate(b) ) return false if (typeof a !== typeof b) return false return true } /** * @callback comparisonOperator * Arithmetic and comparison operators * @param {*} a Value in the object * @param {*} b Value in the query * @return {boolean} */ /** * @enum {comparisonOperator} */ const comparisonFunctions = { /** Lower than */ $lt: (a, b) => areComparable(a, b) && a < b, /** Lower than or equals */ $lte: (a, b) => areComparable(a, b) && a <= b, /** Greater than */ $gt: (a, b) => areComparable(a, b) && a > b, /** Greater than or equals */ $gte: (a, b) => areComparable(a, b) && a >= b, /** Does not equal */ $ne: (a, b) => a === undefined || !areThingsEqual(a, b), /** Is in Array */ $in: (a, b) => { if (!Array.isArray(b)) throw new Error('$in operator called with a non-array') for (const el of b) { if (areThingsEqual(a, el)) return true } return false }, /** Is not in Array */ $nin: (a, b) => { if (!Array.isArray(b)) throw new Error('$nin operator called with a non-array') return !comparisonFunctions.$in(a, b) }, /** Matches Regexp */ $regex: (a, b) => { if (!isRegExp(b)) throw new Error('$regex operator called with non regular expression') if (typeof a !== 'string') return false else return b.test(a) }, /** Returns true if field exists */ $exists: (a, b) => { // This will be true for all values of stat except false, null, undefined and 0 // That's strange behaviour (we should only use true/false) but that's the way Mongo does it... if (b || b === '') b = true else b = false if (a === undefined) return !b else return b }, /** Specific to Arrays, returns true if a length equals b */ $size: (a, b) => { if (!Array.isArray(a)) return false if (b % 1 !== 0) throw new Error('$size operator called without an integer') return a.length === b }, /** Specific to Arrays, returns true if some elements of a match the query b */ $elemMatch: (a, b) => { if (!Array.isArray(a)) return false return a.some(el => match(el, b)) } } const arrayComparisonFunctions = { $size: true, $elemMatch: true } /** * @enum */ const logicalOperators = { /** * Match any of the subqueries * @param {document} obj * @param {query[]} query * @return {boolean} */ $or: (obj, query) => { if (!Array.isArray(query)) throw new Error('$or operator used without an array') for (let i = 0; i < query.length; i += 1) { if (match(obj, query[i])) return true } return false }, /** * Match all of the subqueries * @param {document} obj * @param {query[]} query * @return {boolean} */ $and: (obj, query) => { if (!Array.isArray(query)) throw new Error('$and operator used without an array') for (let i = 0; i < query.length; i += 1) { if (!match(obj, query[i])) return false } return true }, /** * Inverted match of the query * @param {document} obj * @param {query} query * @return {boolean} */ $not: (obj, query) => !match(obj, query), /** * @callback whereCallback * @param {document} obj * @return {boolean} */ /** * Use a function to match * @param {document} obj * @param {whereCallback} fn * @return {boolean} */ $where: (obj, fn) => { if (typeof fn !== 'function') throw new Error('$where operator used without a function') const result = fn.call(obj) if (typeof result !== 'boolean') throw new Error('$where function must return boolean') return result } } /** * Tell if a given document matches a query * @param {document} obj Document to check * @param {query} query * @return {boolean} * @alias module:model.match */ const match = (obj, query) => { // Primitive query against a primitive type // This is a bit of a hack since we construct an object with an arbitrary key only to dereference it later // But I don't have time for a cleaner implementation now if (isPrimitiveType(obj) || isPrimitiveType(query)) return matchQueryPart({ needAKey: obj }, 'needAKey', query) // Normal query for (const queryKey in query) { if (Object.prototype.hasOwnProperty.call(query, queryKey)) { const queryValue = query[queryKey] if (queryKey[0] === '$') { if (!logicalOperators[queryKey]) throw new Error(`Unknown logical operator ${queryKey}`) if (!logicalOperators[queryKey](obj, queryValue)) return false } else if (!matchQueryPart(obj, queryKey, queryValue)) return false } } return true } /** * Match an object against a specific { key: value } part of a query * if the treatObjAsValue flag is set, don't try to match every part separately, but the array as a whole * @param {object} obj * @param {string} queryKey * @param {*} queryValue * @param {boolean} [treatObjAsValue=false] * @return {boolean} * @private */ function matchQueryPart (obj, queryKey, queryValue, treatObjAsValue) { const objValue = getDotValue(obj, queryKey) // Check if the value is an array if we don't force a treatment as value if (Array.isArray(objValue) && !treatObjAsValue) { // If the queryValue is an array, try to perform an exact match if (Array.isArray(queryValue)) return matchQueryPart(obj, queryKey, queryValue, true) // Check if we are using an array-specific comparison function if (queryValue !== null && typeof queryValue === 'object' && !isRegExp(queryValue)) { for (const key in queryValue) { if (Object.prototype.hasOwnProperty.call(queryValue, key) && arrayComparisonFunctions[key]) { return matchQueryPart(obj, queryKey, queryValue, true) } } } // If not, treat it as an array of { obj, query } where there needs to be at least one match for (const el of objValue) { if (matchQueryPart({ k: el }, 'k', queryValue)) return true // k here could be any string } return false } // queryValue is an actual object. Determine whether it contains comparison operators // or only normal fields. Mixed objects are not allowed if (queryValue !== null && typeof queryValue === 'object' && !isRegExp(queryValue) && !Array.isArray(queryValue)) { const keys = Object.keys(queryValue) const firstChars = keys.map(item => item[0]) const dollarFirstChars = firstChars.filter(c => c === '$') if (dollarFirstChars.length !== 0 && dollarFirstChars.length !== firstChars.length) throw new Error('You cannot mix operators and normal fields') // queryValue is an object of this form: { $comparisonOperator1: value1, ... } if (dollarFirstChars.length > 0) { for (const key of keys) { if (!comparisonFunctions[key]) throw new Error(`Unknown comparison function ${key}`) if (!comparisonFunctions[key](objValue, queryValue[key])) return false } return true } } // Using regular expressions with basic querying if (isRegExp(queryValue)) return comparisonFunctions.$regex(objValue, queryValue) // queryValue is either a native value or a normal object // Basic matching is possible return areThingsEqual(objValue, queryValue) } // Interface module.exports.serialize = serialize module.exports.deserialize = deserialize module.exports.deepCopy = deepCopy module.exports.checkObject = checkObject module.exports.isPrimitiveType = isPrimitiveType module.exports.modify = modify module.exports.getDotValue = getDotValue module.exports.getDotValues = getDotValues module.exports.match = match module.exports.areThingsEqual = areThingsEqual module.exports.compareThings = compareThings /***/ }), /***/ 328: /***/ ((module, __unused_webpack_exports, __webpack_require__) => { const { deprecate } = __webpack_require__(539) const byline = __webpack_require__(100) const customUtils = __webpack_require__(159) const Index = __webpack_require__(98) const model = __webpack_require__(118) const storage = __webpack_require__(909) const DEFAULT_DIR_MODE = 0o755 const DEFAULT_FILE_MODE = 0o644 /** * Under the hood, NeDB's persistence uses an append-only format, meaning that all * updates and deletes actually result in lines added at the end of the datafile, * for performance reasons. The database is automatically compacted (i.e. put back * in the one-line-per-document format) every time you load each database within * your application. * * Persistence handles the compaction exposed in the Datastore {@link Datastore#compactDatafileAsync}, * {@link Datastore#setAutocompactionInterval}. * * Since version 3.0.0, using {@link Datastore.persistence} methods manually is deprecated. * * Compaction takes a bit of time (not too much: 130ms for 50k * records on a typical development machine) and no other operation can happen when * it does, so most projects actually don't need to use it. * * Compaction will also immediately remove any documents whose data line has become * corrupted, assuming that the total percentage of all corrupted documents in that * database still falls below the specified `corruptAlertThreshold` option's value. * * Durability works similarly to major databases: compaction forces the OS to * physically flush data to disk, while appends to the data file do not (the OS is * responsible for flushing the data). That guarantees that a server crash can * never cause complete data loss, while preserving performance. The worst that can * happen is a crash between two syncs, causing a loss of all data between the two * syncs. Usually syncs are 30 seconds appart so that's at most 30 seconds of * data. [This post by Antirez on Redis persistence](http://oldblog.antirez.com/post/redis-persistence-demystified.html) * explains this in more details, NeDB being very close to Redis AOF persistence * with `appendfsync` option set to `no`. */ class Persistence { /** * Create a new Persistence object for database options.db * @param {Datastore} options.db * @param {Number} [options.corruptAlertThreshold] Optional, threshold after which an alert is thrown if too much data is corrupt * @param {serializationHook} [options.beforeDeserialization] Hook you can use to transform data after it was serialized and before it is written to disk. * @param {serializationHook} [options.afterSerialization] Inverse of `afterSerialization`. * @param {object} [options.modes] Modes to use for FS permissions. Will not work on Windows. * @param {number} [options.modes.fileMode=0o644] Mode to use for files. * @param {number} [options.modes.dirMode=0o755] Mode to use for directories. * @param {boolean} [options.testSerializationHooks=true] Whether to test the serialization hooks or not, might be CPU-intensive */ constructor (options) { this.db = options.db this.inMemoryOnly = this.db.inMemoryOnly this.filename = this.db.filename this.corruptAlertThreshold = options.corruptAlertThreshold !== undefined ? options.corruptAlertThreshold : 0.1 this.modes = options.modes !== undefined ? options.modes : { fileMode: DEFAULT_FILE_MODE, dirMode: DEFAULT_DIR_MODE } if (this.modes.fileMode === undefined) this.modes.fileMode = DEFAULT_FILE_MODE if (this.modes.dirMode === undefined) this.modes.dirMode = DEFAULT_DIR_MODE if ( !this.inMemoryOnly && this.filename && this.filename.charAt(this.filename.length - 1) === '~' ) throw new Error('The datafile name can\'t end with a ~, which is reserved for crash safe backup files') // After serialization and before deserialization hooks with some basic sanity checks if ( options.afterSerialization && !options.beforeDeserialization ) throw new Error('Serialization hook defined but deserialization hook undefined, cautiously refusing to start NeDB to prevent dataloss') if ( !options.afterSerialization && options.beforeDeserialization ) throw new Error('Serialization hook undefined but deserialization hook defined, cautiously refusing to start NeDB to prevent dataloss') this.afterSerialization = options.afterSerialization || (s => s) this.beforeDeserialization = options.beforeDeserialization || (s => s) if (options.testSerializationHooks === undefined || options.testSerializationHooks) { for (let i = 1; i < 30; i += 1) { for (let j = 0; j < 10; j += 1) { const randomString = customUtils.uid(i) if (this.beforeDeserialization(this.afterSerialization(randomString)) !== randomString) { throw new Error('beforeDeserialization is not the reverse of afterSerialization, cautiously refusing to start NeDB to prevent dataloss') } } } } } /** * Internal version without using the {@link Datastore#executor} of {@link Datastore#compactDatafileAsync}, use it instead. * @return {Promise} * @private */ async persistCachedDatabaseAsync () { const lines = [] if (this.inMemoryOnly) return this.db.getAllData().forEach(doc => { lines.push(this.afterSerialization(model.serialize(doc))) }) Object.keys(this.db.indexes).forEach(fieldName => { if (fieldName !== '_id') { // The special _id index is managed by datastore.js, the others need to be persisted lines.push(this.afterSerialization(model.serialize({ $$indexCreated: { fieldName: this.db.indexes[fieldName].fieldName, unique: this.db.indexes[fieldName].unique, sparse: this.db.indexes[fieldName].sparse } }))) } }) await storage.crashSafeWriteFileLinesAsync(this.filename, lines, this.modes) this.db.emit('compaction.done') } /** * @see Datastore#compactDatafile * @deprecated * @param {NoParamCallback} [callback = () => {}] * @see Persistence#compactDatafileAsync */ compactDatafile (callback) { deprecate(_callback => this.db.compactDatafile(_callback), '@seald-io/nedb: calling Datastore#persistence#compactDatafile is deprecated, please use Datastore#compactDatafile, it will be removed in the next major version.')(callback) } /** * @see Datastore#setAutocompactionInterval * @deprecated */ setAutocompactionInterval (interval) { deprecate(_interval => this.db.setAutocompactionInterval(_interval), '@seald-io/nedb: calling Datastore#persistence#setAutocompactionInterval is deprecated, please use Datastore#setAutocompactionInterval, it will be removed in the next major version.')(interval) } /** * @see Datastore#stopAutocompaction * @deprecated */ stopAutocompaction () { deprecate(() => this.db.stopAutocompaction(), '@seald-io/nedb: calling Datastore#persistence#stopAutocompaction is deprecated, please use Datastore#stopAutocompaction, it will be removed in the next major version.')() } /** * Persist new state for the given newDocs (can be insertion, update or removal) * Use an append-only format * * Do not use directly, it should only used by a {@link Datastore} instance. * @param {document[]} newDocs Can be empty if no doc was updated/removed * @return {Promise} * @private */ async persistNewStateAsync (newDocs) { let toPersist = '' // In-memory only datastore if (this.inMemoryOnly) return newDocs.forEach(doc => { toPersist += this.afterSerialization(model.serialize(doc)) + '\n' }) if (toPersist.length === 0) return await storage.appendFileAsync(this.filename, toPersist, { encoding: 'utf8', mode: this.modes.fileMode }) } /** * @typedef rawIndex * @property {string} fieldName * @property {boolean} [unique] * @property {boolean} [sparse] */ /** * From a database's raw data, return the corresponding machine understandable collection. * * Do not use directly, it should only used by a {@link Datastore} instance. * @param {string} rawData database file * @return {{data: document[], indexes: Object.}} * @private */ treatRawData (rawData) { const data = rawData.split('\n') const dataById = {} const indexes = {} let dataLength = data.length // Last line of every data file is usually blank so not really corrupt let corruptItems = 0 for (const datum of data) { if (datum === '') { dataLength--; continue } try { const doc = model.deserialize(this.beforeDeserialization(datum)) if (doc._id) { if (doc.$$deleted === true) delete dataById[doc._id] else dataById[doc._id] = doc } else if (doc.$$indexCreated && doc.$$indexCreated.fieldName != null) indexes[doc.$$indexCreated.fieldName] = doc.$$indexCreated else if (typeof doc.$$indexRemoved === 'string') delete indexes[doc.$$indexRemoved] } catch (e) { corruptItems += 1 } } // A bit lenient on corruption if (dataLength > 0) { const corruptionRate = corruptItems / dataLength if (corruptionRate > this.corruptAlertThreshold) { const error = new Error(`${Math.floor(100 * corruptionRate)}% of the data file is corrupt, more than given corruptAlertThreshold (${Math.floor(100 * this.corruptAlertThreshold)}%). Cautiously refusing to start NeDB to prevent dataloss.`) error.corruptionRate = corruptionRate error.corruptItems = corruptItems error.dataLength = dataLength throw error } } const tdata = Object.values(dataById) return { data: tdata, indexes } } /** * From a database's raw data stream, return the corresponding machine understandable collection * Is only used by a {@link Datastore} instance. * * Is only used in the Node.js version, since [React-Native]{@link module:storageReactNative} & * [browser]{@link module:storageBrowser} storage modules don't provide an equivalent of * {@link module:storage.readFileStream}. * * Do not use directly, it should only used by a {@link Datastore} instance. * @param {Readable} rawStream * @return {Promise<{data: document[], indexes: Object.}>} * @async * @private */ treatRawStreamAsync (rawStream) { return new Promise((resolve, reject) => { const dataById = {} const indexes = {} let corruptItems = 0 const lineStream = byline(rawStream) let dataLength = 0 lineStream.on('data', (line) => { if (line === '') return try { const doc = model.deserialize(this.beforeDeserialization(line)) if (doc._id) { if (doc.$$deleted === true) delete dataById[doc._id] else dataById[doc._id] = doc } else if (doc.$$indexCreated && doc.$$indexCreated.fieldName != null) indexes[doc.$$indexCreated.fieldName] = doc.$$indexCreated else if (typeof doc.$$indexRemoved === 'string') delete indexes[doc.$$indexRemoved] } catch (e) { corruptItems += 1 } dataLength++ }) lineStream.on('end', () => { // A bit lenient on corruption if (dataLength > 0) { const corruptionRate = corruptItems / dataLength if (corruptionRate > this.corruptAlertThreshold) { const error = new Error(`${Math.floor(100 * corruptionRate)}% of the data file is corrupt, more than given corruptAlertThreshold (${Math.floor(100 * this.corruptAlertThreshold)}%). Cautiously refusing to start NeDB to prevent dataloss.`) error.corruptionRate = corruptionRate error.corruptItems = corruptItems error.dataLength = dataLength reject(error, null) return } } const data = Object.values(dataById) resolve({ data, indexes }) }) lineStream.on('error', function (err) { reject(err, null) }) }) } /** * Load the database * 1) Create all indexes * 2) Insert all data * 3) Compact the database * * This means pulling data out of the data file or creating it if it doesn't exist * Also, all data is persisted right away, which has the effect of compacting the database file * This operation is very quick at startup for a big collection (60ms for ~10k docs) * * Do not use directly as it does not use the [Executor]{@link Datastore.executor}, use {@link Datastore#loadDatabaseAsync} instead. * @return {Promise} * @private */ async loadDatabaseAsync () { this.db._resetIndexes() // In-memory only datastore if (this.inMemoryOnly) return await Persistence.ensureParentDirectoryExistsAsync(this.filename, this.modes.dirMode) await storage.ensureDatafileIntegrityAsync(this.filename, this.modes.fileMode) let treatedData if (storage.readFileStream) { // Server side const fileStream = storage.readFileStream(this.filename, { encoding: 'utf8', mode: this.modes.fileMode }) treatedData = await this.treatRawStreamAsync(fileStream) } else { // Browser const rawData = await storage.readFileAsync(this.filename, { encoding: 'utf8', mode: this.modes.fileMode }) treatedData = this.treatRawData(rawData) } // Recreate all indexes in the datafile Object.keys(treatedData.indexes).forEach(key => { this.db.indexes[key] = new Index(treatedData.indexes[key]) }) // Fill cached database (i.e. all indexes) with data try { this.db._resetIndexes(treatedData.data) } catch (e) { this.db._resetIndexes() // Rollback any index which didn't fail throw e } await this.db.persistence.persistCachedDatabaseAsync() this.db.executor.processBuffer() } /** * See {@link Datastore#dropDatabaseAsync}. This function uses {@link Datastore#executor} internally. Decorating this * function with an {@link Executor#pushAsync} will result in a deadlock. * @return {Promise} * @private * @see Datastore#dropDatabaseAsync */ async dropDatabaseAsync () { this.db.stopAutocompaction() // stop autocompaction this.db.executor.ready = false // prevent queuing new tasks this.db.executor.resetBuffer() // remove pending buffered tasks await this.db.executor.queue.guardian // wait for the ongoing tasks to end // remove indexes (which means remove data from memory) this.db.indexes = {} // add back _id index, otherwise it will fail this.db.indexes._id = new Index({ fieldName: '_id', unique: true }) // reset TTL on indexes this.db.ttlIndexes = {} // remove datastore file if (!this.db.inMemoryOnly) { await this.db.executor.pushAsync(async () => { if (await storage.existsAsync(this.filename)) await storage.unlinkAsync(this.filename) }, true) } } /** * Check if a directory stat and create it on the fly if it is not the case. * @param {string} dir * @param {number} [mode=0o777] * @return {Promise} * @private */ static async ensureParentDirectoryExistsAsync (dir, mode = DEFAULT_DIR_MODE) { return storage.ensureParentDirectoryExistsAsync(dir, mode) } } // Interface module.exports = Persistence /***/ }), /***/ 988: /***/ ((module) => { /** * Utility functions for all environments. * This replaces the underscore dependency. * * @module utils * @private */ /** * @callback IterateeFunction * @param {*} arg * @return {*} */ /** * Produces a duplicate-free version of the array, using === to test object equality. In particular only the first * occurrence of each value is kept. If you want to compute unique items based on a transformation, pass an iteratee * function. * * Heavily inspired by {@link https://underscorejs.org/#uniq}. * @param {Array} array * @param {IterateeFunction} [iteratee] transformation applied to every element before checking for duplicates. This will not * transform the items in the result. * @return {Array} * @alias module:utils.uniq */ const uniq = (array, iteratee) => { if (iteratee) return [...(new Map(array.map(x => [iteratee(x), x]))).values()] else return [...new Set(array)] } /** * Returns true if arg is an Object. Note that JavaScript arrays and functions are objects, while (normal) strings * and numbers are not. * * Heavily inspired by {@link https://underscorejs.org/#isObject}. * @param {*} arg * @return {boolean} */ const isObject = arg => typeof arg === 'object' && arg !== null /** * Returns true if d is a Date. * * Heavily inspired by {@link https://underscorejs.org/#isDate}. * @param {*} d * @return {boolean} * @alias module:utils.isDate */ const isDate = d => isObject(d) && Object.prototype.toString.call(d) === '[object Date]' /** * Returns true if re is a RegExp. * * Heavily inspired by {@link https://underscorejs.org/#isRegExp}. * @param {*} re * @return {boolean} * @alias module:utils.isRegExp */ const isRegExp = re => isObject(re) && Object.prototype.toString.call(re) === '[object RegExp]' /** * Return a copy of the object filtered using the given keys. * * @param {object} object * @param {string[]} keys * @return {object} */ const pick = (object, keys) => { return keys.reduce((obj, key) => { if (object && Object.prototype.hasOwnProperty.call(object, key)) { obj[key] = object[key] } return obj }, {}) } const filterIndexNames = (indexNames) => ([k, v]) => !!(typeof v === 'string' || typeof v === 'number' || typeof v === 'boolean' || isDate(v) || v === null) && indexNames.includes(k) module.exports.uniq = uniq module.exports.isDate = isDate module.exports.isRegExp = isRegExp module.exports.pick = pick module.exports.filterIndexNames = filterIndexNames /***/ }), /***/ 496: /***/ ((module) => { /** * Responsible for sequentially executing actions on the database * @private */ class Waterfall { /** * Instantiate a new Waterfall. */ constructor () { /** * This is the internal Promise object which resolves when all the tasks of the `Waterfall` are done. * * It will change any time `this.waterfall` is called. * * @type {Promise} */ this.guardian = Promise.resolve() } /** * * @param {AsyncFunction} func * @return {AsyncFunction} */ waterfall (func) { return (...args) => { this.guardian = this.guardian.then(() => { return func(...args) .then(result => ({ error: false, result }), result => ({ error: true, result })) }) return this.guardian.then(({ error, result }) => { if (error) return Promise.reject(result) else return Promise.resolve(result) }) } } /** * Shorthand for chaining a promise to the Waterfall * @param {Promise} promise * @return {Promise} */ chain (promise) { return this.waterfall(() => promise)() } } module.exports = Waterfall /***/ }), /***/ 908: /***/ ((module, __unused_webpack_exports, __webpack_require__) => { /* unused reexport */ __webpack_require__(902) module.exports.AVLTree = __webpack_require__(522) /***/ }), /***/ 522: /***/ ((module, __unused_webpack_exports, __webpack_require__) => { /** * Self-balancing binary search tree using the AVL implementation */ const BinarySearchTree = __webpack_require__(902) const customUtils = __webpack_require__(639) class AVLTree { /** * Constructor * We can't use a direct pointer to the root node (as in the simple binary search tree) * as the root will change during tree rotations * @param {Boolean} options.unique Whether to enforce a 'unique' constraint on the key or not * @param {Function} options.compareKeys Initialize this BST's compareKeys */ constructor (options) { this.tree = new _AVLTree(options) } checkIsAVLT () { this.tree.checkIsAVLT() } // Insert in the internal tree, update the pointer to the root if needed insert (key, value) { const newTree = this.tree.insert(key, value) // If newTree is undefined, that means its structure was not modified if (newTree) { this.tree = newTree } } // Delete a value delete (key, value) { const newTree = this.tree.delete(key, value) // If newTree is undefined, that means its structure was not modified if (newTree) { this.tree = newTree } } } class _AVLTree extends BinarySearchTree { /** * Constructor of the internal AVLTree * @param {Object} options Optional * @param {Boolean} options.unique Whether to enforce a 'unique' constraint on the key or not * @param {Key} options.key Initialize this BST's key with key * @param {Value} options.value Initialize this BST's data with [value] * @param {Function} options.compareKeys Initialize this BST's compareKeys */ constructor (options) { super() options = options || {} this.left = null this.right = null this.parent = options.parent !== undefined ? options.parent : null if (Object.prototype.hasOwnProperty.call(options, 'key')) this.key = options.key this.data = Object.prototype.hasOwnProperty.call(options, 'value') ? [options.value] : [] this.unique = options.unique || false this.compareKeys = options.compareKeys || customUtils.defaultCompareKeysFunction this.checkValueEquality = options.checkValueEquality || customUtils.defaultCheckValueEquality } /** * Check the recorded height is correct for every node * Throws if one height doesn't match */ checkHeightCorrect () { if (!Object.prototype.hasOwnProperty.call(this, 'key')) { return } // Empty tree if (this.left && this.left.height === undefined) { throw new Error('Undefined height for node ' + this.left.key) } if (this.right && this.right.height === undefined) { throw new Error('Undefined height for node ' + this.right.key) } if (this.height === undefined) { throw new Error('Undefined height for node ' + this.key) } const leftH = this.left ? this.left.height : 0 const rightH = this.right ? this.right.height : 0 if (this.height !== 1 + Math.max(leftH, rightH)) { throw new Error('Height constraint failed for node ' + this.key) } if (this.left) { this.left.checkHeightCorrect() } if (this.right) { this.right.checkHeightCorrect() } } /** * Return the balance factor */ balanceFactor () { const leftH = this.left ? this.left.height : 0 const rightH = this.right ? this.right.height : 0 return leftH - rightH } /** * Check that the balance factors are all between -1 and 1 */ checkBalanceFactors () { if (Math.abs(this.balanceFactor()) > 1) { throw new Error('Tree is unbalanced at node ' + this.key) } if (this.left) { this.left.checkBalanceFactors() } if (this.right) { this.right.checkBalanceFactors() } } /** * When checking if the BST conditions are met, also check that the heights are correct * and the tree is balanced */ checkIsAVLT () { super.checkIsBST() this.checkHeightCorrect() this.checkBalanceFactors() } /** * Perform a right rotation of the tree if possible * and return the root of the resulting tree * The resulting tree's nodes' heights are also updated */ rightRotation () { const q = this const p = this.left if (!p) return q // No change const b = p.right // Alter tree structure if (q.parent) { p.parent = q.parent if (q.parent.left === q) q.parent.left = p else q.parent.right = p } else { p.parent = null } p.right = q q.parent = p q.left = b if (b) { b.parent = q } // Update heights const ah = p.left ? p.left.height : 0 const bh = b ? b.height : 0 const ch = q.right ? q.right.height : 0 q.height = Math.max(bh, ch) + 1 p.height = Math.max(ah, q.height) + 1 return p } /** * Perform a left rotation of the tree if possible * and return the root of the resulting tree * The resulting tree's nodes' heights are also updated */ leftRotation () { const p = this const q = this.right if (!q) { return this } // No change const b = q.left // Alter tree structure if (p.parent) { q.parent = p.parent if (p.parent.left === p) p.parent.left = q else p.parent.right = q } else { q.parent = null } q.left = p p.parent = q p.right = b if (b) { b.parent = p } // Update heights const ah = p.left ? p.left.height : 0 const bh = b ? b.height : 0 const ch = q.right ? q.right.height : 0 p.height = Math.max(ah, bh) + 1 q.height = Math.max(ch, p.height) + 1 return q } /** * Modify the tree if its right subtree is too small compared to the left * Return the new root if any */ rightTooSmall () { if (this.balanceFactor() <= 1) return this // Right is not too small, don't change if (this.left.balanceFactor() < 0) this.left.leftRotation() return this.rightRotation() } /** * Modify the tree if its left subtree is too small compared to the right * Return the new root if any */ leftTooSmall () { if (this.balanceFactor() >= -1) { return this } // Left is not too small, don't change if (this.right.balanceFactor() > 0) this.right.rightRotation() return this.leftRotation() } /** * Rebalance the tree along the given path. The path is given reversed (as he was calculated * in the insert and delete functions). * Returns the new root of the tree * Of course, the first element of the path must be the root of the tree */ rebalanceAlongPath (path) { let newRoot = this let rotated let i if (!Object.prototype.hasOwnProperty.call(this, 'key')) { delete this.height return this } // Empty tree // Rebalance the tree and update all heights for (i = path.length - 1; i >= 0; i -= 1) { path[i].height = 1 + Math.max(path[i].left ? path[i].left.height : 0, path[i].right ? path[i].right.height : 0) if (path[i].balanceFactor() > 1) { rotated = path[i].rightTooSmall() if (i === 0) newRoot = rotated } if (path[i].balanceFactor() < -1) { rotated = path[i].leftTooSmall() if (i === 0) newRoot = rotated } } return newRoot } /** * Insert a key, value pair in the tree while maintaining the AVL tree height constraint * Return a pointer to the root node, which may have changed */ insert (key, value) { const insertPath = [] let currentNode = this // Empty tree, insert as root if (!Object.prototype.hasOwnProperty.call(this, 'key')) { this.key = key this.data.push(value) this.height = 1 return this } // Insert new leaf at the right place while (true) { // Same key: no change in the tree structure if (currentNode.compareKeys(currentNode.key, key) === 0) { if (currentNode.unique) { const err = new Error(`Can't insert key ${JSON.stringify(key)}, it violates the unique constraint`) err.key = key err.errorType = 'uniqueViolated' throw err } else currentNode.data.push(value) return this } insertPath.push(currentNode) if (currentNode.compareKeys(key, currentNode.key) < 0) { if (!currentNode.left) { insertPath.push(currentNode.createLeftChild({ key: key, value: value })) break } else currentNode = currentNode.left } else { if (!currentNode.right) { insertPath.push(currentNode.createRightChild({ key: key, value: value })) break } else currentNode = currentNode.right } } return this.rebalanceAlongPath(insertPath) } /** * Delete a key or just a value and return the new root of the tree * @param {Key} key * @param {Value} value Optional. If not set, the whole key is deleted. If set, only this value is deleted */ delete (key, value) { const newData = [] let replaceWith let currentNode = this const deletePath = [] if (!Object.prototype.hasOwnProperty.call(this, 'key')) return this // Empty tree // Either no match is found and the function will return from within the loop // Or a match is found and deletePath will contain the path from the root to the node to delete after the loop while (true) { if (currentNode.compareKeys(key, currentNode.key) === 0) { break } deletePath.push(currentNode) if (currentNode.compareKeys(key, currentNode.key) < 0) { if (currentNode.left) { currentNode = currentNode.left } else return this // Key not found, no modification } else { // currentNode.compareKeys(key, currentNode.key) is > 0 if (currentNode.right) { currentNode = currentNode.right } else return this // Key not found, no modification } } // Delete only a value (no tree modification) if (currentNode.data.length > 1 && value !== undefined) { currentNode.data.forEach(function (d) { if (!currentNode.checkValueEquality(d, value)) newData.push(d) }) currentNode.data = newData return this } // Delete a whole node // Leaf if (!currentNode.left && !currentNode.right) { if (currentNode === this) { // This leaf is also the root delete currentNode.key currentNode.data = [] delete currentNode.height return this } else { if (currentNode.parent.left === currentNode) currentNode.parent.left = null else currentNode.parent.right = null return this.rebalanceAlongPath(deletePath) } } // Node with only one child if (!currentNode.left || !currentNode.right) { replaceWith = currentNode.left ? currentNode.left : currentNode.right if (currentNode === this) { // This node is also the root replaceWith.parent = null return replaceWith // height of replaceWith is necessarily 1 because the tree was balanced before deletion } else { if (currentNode.parent.left === currentNode) { currentNode.parent.left = replaceWith replaceWith.parent = currentNode.parent } else { currentNode.parent.right = replaceWith replaceWith.parent = currentNode.parent } return this.rebalanceAlongPath(deletePath) } } // Node with two children // Use the in-order predecessor (no need to randomize since we actively rebalance) deletePath.push(currentNode) replaceWith = currentNode.left // Special case: the in-order predecessor is right below the node to delete if (!replaceWith.right) { currentNode.key = replaceWith.key currentNode.data = replaceWith.data currentNode.left = replaceWith.left if (replaceWith.left) { replaceWith.left.parent = currentNode } return this.rebalanceAlongPath(deletePath) } // After this loop, replaceWith is the right-most leaf in the left subtree // and deletePath the path from the root (inclusive) to replaceWith (exclusive) while (true) { if (replaceWith.right) { deletePath.push(replaceWith) replaceWith = replaceWith.right } else break } currentNode.key = replaceWith.key currentNode.data = replaceWith.data replaceWith.parent.right = replaceWith.left if (replaceWith.left) replaceWith.left.parent = replaceWith.parent return this.rebalanceAlongPath(deletePath) } } /** * Keep a pointer to the internal tree constructor for testing purposes */ AVLTree._AVLTree = _AVLTree; /** * Other functions we want to use on an AVLTree as if it were the internal _AVLTree */ ['getNumberOfKeys', 'search', 'betweenBounds', 'prettyPrint', 'executeOnEveryNode'].forEach(function (fn) { AVLTree.prototype[fn] = function () { return this.tree[fn].apply(this.tree, arguments) } }) // Interface module.exports = AVLTree /***/ }), /***/ 902: /***/ ((module, __unused_webpack_exports, __webpack_require__) => { /** * Simple binary search tree */ const customUtils = __webpack_require__(639) class BinarySearchTree { /** * Constructor * @param {Object} options Optional * @param {Boolean} options.unique Whether to enforce a 'unique' constraint on the key or not * @param {Key} options.key Initialize this BST's key with key * @param {Value} options.value Initialize this BST's data with [value] * @param {Function} options.compareKeys Initialize this BST's compareKeys */ constructor (options) { options = options || {} this.left = null this.right = null this.parent = options.parent !== undefined ? options.parent : null if (Object.prototype.hasOwnProperty.call(options, 'key')) { this.key = options.key } this.data = Object.prototype.hasOwnProperty.call(options, 'value') ? [options.value] : [] this.unique = options.unique || false this.compareKeys = options.compareKeys || customUtils.defaultCompareKeysFunction this.checkValueEquality = options.checkValueEquality || customUtils.defaultCheckValueEquality } /** * Get the descendant with max key */ getMaxKeyDescendant () { if (this.right) return this.right.getMaxKeyDescendant() else return this } /** * Get the maximum key */ getMaxKey () { return this.getMaxKeyDescendant().key } /** * Get the descendant with min key */ getMinKeyDescendant () { if (this.left) return this.left.getMinKeyDescendant() else return this } /** * Get the minimum key */ getMinKey () { return this.getMinKeyDescendant().key } /** * Check that all nodes (incl. leaves) fullfil condition given by fn * test is a function passed every (key, data) and which throws if the condition is not met */ checkAllNodesFullfillCondition (test) { if (!Object.prototype.hasOwnProperty.call(this, 'key')) return test(this.key, this.data) if (this.left) this.left.checkAllNodesFullfillCondition(test) if (this.right) this.right.checkAllNodesFullfillCondition(test) } /** * Check that the core BST properties on node ordering are verified * Throw if they aren't */ checkNodeOrdering () { if (!Object.prototype.hasOwnProperty.call(this, 'key')) return if (this.left) { this.left.checkAllNodesFullfillCondition(k => { if (this.compareKeys(k, this.key) >= 0) throw new Error(`Tree with root ${this.key} is not a binary search tree`) }) this.left.checkNodeOrdering() } if (this.right) { this.right.checkAllNodesFullfillCondition(k => { if (this.compareKeys(k, this.key) <= 0) throw new Error(`Tree with root ${this.key} is not a binary search tree`) }) this.right.checkNodeOrdering() } } /** * Check that all pointers are coherent in this tree */ checkInternalPointers () { if (this.left) { if (this.left.parent !== this) throw new Error(`Parent pointer broken for key ${this.key}`) this.left.checkInternalPointers() } if (this.right) { if (this.right.parent !== this) throw new Error(`Parent pointer broken for key ${this.key}`) this.right.checkInternalPointers() } } /** * Check that a tree is a BST as defined here (node ordering and pointer references) */ checkIsBST () { this.checkNodeOrdering() this.checkInternalPointers() if (this.parent) throw new Error("The root shouldn't have a parent") } /** * Get number of keys inserted */ getNumberOfKeys () { let res if (!Object.prototype.hasOwnProperty.call(this, 'key')) return 0 res = 1 if (this.left) res += this.left.getNumberOfKeys() if (this.right) res += this.right.getNumberOfKeys() return res } /** * Create a BST similar (i.e. same options except for key and value) to the current one * Use the same constructor (i.e. BinarySearchTree, AVLTree etc) * @param {Object} options see constructor */ createSimilar (options) { options = options || {} options.unique = this.unique options.compareKeys = this.compareKeys options.checkValueEquality = this.checkValueEquality return new this.constructor(options) } /** * Create the left child of this BST and return it */ createLeftChild (options) { const leftChild = this.createSimilar(options) leftChild.parent = this this.left = leftChild return leftChild } /** * Create the right child of this BST and return it */ createRightChild (options) { const rightChild = this.createSimilar(options) rightChild.parent = this this.right = rightChild return rightChild } /** * Insert a new element */ insert (key, value) { // Empty tree, insert as root if (!Object.prototype.hasOwnProperty.call(this, 'key')) { this.key = key this.data.push(value) return } // Same key as root if (this.compareKeys(this.key, key) === 0) { if (this.unique) { const err = new Error(`Can't insert key ${JSON.stringify(key)}, it violates the unique constraint`) err.key = key err.errorType = 'uniqueViolated' throw err } else this.data.push(value) return } if (this.compareKeys(key, this.key) < 0) { // Insert in left subtree if (this.left) this.left.insert(key, value) else this.createLeftChild({ key: key, value: value }) } else { // Insert in right subtree if (this.right) this.right.insert(key, value) else this.createRightChild({ key: key, value: value }) } } /** * Search for all data corresponding to a key */ search (key) { if (!Object.prototype.hasOwnProperty.call(this, 'key')) return [] if (this.compareKeys(this.key, key) === 0) return this.data if (this.compareKeys(key, this.key) < 0) { if (this.left) return this.left.search(key) else return [] } else { if (this.right) return this.right.search(key) else return [] } } /** * Return a function that tells whether a given key matches a lower bound */ getLowerBoundMatcher (query) { // No lower bound if (!Object.prototype.hasOwnProperty.call(query, '$gt') && !Object.prototype.hasOwnProperty.call(query, '$gte')) return () => true if (Object.prototype.hasOwnProperty.call(query, '$gt') && Object.prototype.hasOwnProperty.call(query, '$gte')) { if (this.compareKeys(query.$gte, query.$gt) === 0) return key => this.compareKeys(key, query.$gt) > 0 if (this.compareKeys(query.$gte, query.$gt) > 0) return key => this.compareKeys(key, query.$gte) >= 0 else return key => this.compareKeys(key, query.$gt) > 0 } if (Object.prototype.hasOwnProperty.call(query, '$gt')) return key => this.compareKeys(key, query.$gt) > 0 else return key => this.compareKeys(key, query.$gte) >= 0 } /** * Return a function that tells whether a given key matches an upper bound */ getUpperBoundMatcher (query) { // No lower bound if (!Object.prototype.hasOwnProperty.call(query, '$lt') && !Object.prototype.hasOwnProperty.call(query, '$lte')) return () => true if (Object.prototype.hasOwnProperty.call(query, '$lt') && Object.prototype.hasOwnProperty.call(query, '$lte')) { if (this.compareKeys(query.$lte, query.$lt) === 0) return key => this.compareKeys(key, query.$lt) < 0 if (this.compareKeys(query.$lte, query.$lt) < 0) return key => this.compareKeys(key, query.$lte) <= 0 else return key => this.compareKeys(key, query.$lt) < 0 } if (Object.prototype.hasOwnProperty.call(query, '$lt')) return key => this.compareKeys(key, query.$lt) < 0 else return key => this.compareKeys(key, query.$lte) <= 0 } /** * Get all data for a key between bounds * Return it in key order * @param {Object} query Mongo-style query where keys are $lt, $lte, $gt or $gte (other keys are not considered) * @param {Functions} lbm/ubm matching functions calculated at the first recursive step */ betweenBounds (query, lbm, ubm) { const res = [] if (!Object.prototype.hasOwnProperty.call(this, 'key')) return [] // Empty tree lbm = lbm || this.getLowerBoundMatcher(query) ubm = ubm || this.getUpperBoundMatcher(query) if (lbm(this.key) && this.left) append(res, this.left.betweenBounds(query, lbm, ubm)) if (lbm(this.key) && ubm(this.key)) append(res, this.data) if (ubm(this.key) && this.right) append(res, this.right.betweenBounds(query, lbm, ubm)) return res } /** * Delete the current node if it is a leaf * Return true if it was deleted */ deleteIfLeaf () { if (this.left || this.right) return false // The leaf is itself a root if (!this.parent) { delete this.key this.data = [] return true } if (this.parent.left === this) this.parent.left = null else this.parent.right = null return true } /** * Delete the current node if it has only one child * Return true if it was deleted */ deleteIfOnlyOneChild () { let child if (this.left && !this.right) child = this.left if (!this.left && this.right) child = this.right if (!child) return false // Root if (!this.parent) { this.key = child.key this.data = child.data this.left = null if (child.left) { this.left = child.left child.left.parent = this } this.right = null if (child.right) { this.right = child.right child.right.parent = this } return true } if (this.parent.left === this) { this.parent.left = child child.parent = this.parent } else { this.parent.right = child child.parent = this.parent } return true } /** * Delete a key or just a value * @param {Key} key * @param {Value} value Optional. If not set, the whole key is deleted. If set, only this value is deleted */ delete (key, value) { const newData = [] let replaceWith if (!Object.prototype.hasOwnProperty.call(this, 'key')) return if (this.compareKeys(key, this.key) < 0) { if (this.left) this.left.delete(key, value) return } if (this.compareKeys(key, this.key) > 0) { if (this.right) this.right.delete(key, value) return } if (!this.compareKeys(key, this.key) === 0) return // Delete only a value if (this.data.length > 1 && value !== undefined) { this.data.forEach(d => { if (!this.checkValueEquality(d, value)) newData.push(d) }) this.data = newData return } // Delete the whole node if (this.deleteIfLeaf()) return if (this.deleteIfOnlyOneChild()) return // We are in the case where the node to delete has two children if (Math.random() >= 0.5) { // Randomize replacement to avoid unbalancing the tree too much // Use the in-order predecessor replaceWith = this.left.getMaxKeyDescendant() this.key = replaceWith.key this.data = replaceWith.data if (this === replaceWith.parent) { // Special case this.left = replaceWith.left if (replaceWith.left) replaceWith.left.parent = replaceWith.parent } else { replaceWith.parent.right = replaceWith.left if (replaceWith.left) replaceWith.left.parent = replaceWith.parent } } else { // Use the in-order successor replaceWith = this.right.getMinKeyDescendant() this.key = replaceWith.key this.data = replaceWith.data if (this === replaceWith.parent) { // Special case this.right = replaceWith.right if (replaceWith.right) replaceWith.right.parent = replaceWith.parent } else { replaceWith.parent.left = replaceWith.right if (replaceWith.right) replaceWith.right.parent = replaceWith.parent } } } /** * Execute a function on every node of the tree, in key order * @param {Function} fn Signature: node. Most useful will probably be node.key and node.data */ executeOnEveryNode (fn) { if (this.left) this.left.executeOnEveryNode(fn) fn(this) if (this.right) this.right.executeOnEveryNode(fn) } /** * Pretty print a tree * @param {Boolean} printData To print the nodes' data along with the key */ prettyPrint (printData, spacing) { spacing = spacing || '' console.log(`${spacing}* ${this.key}`) if (printData) console.log(`${spacing}* ${this.data}`) if (!this.left && !this.right) return if (this.left) this.left.prettyPrint(printData, `${spacing} `) else console.log(`${spacing} *`) if (this.right) this.right.prettyPrint(printData, `${spacing} `) else console.log(`${spacing} *`) } } // ================================ // Methods used to test the tree // ================================ // ============================================ // Methods used to actually work on the tree // ============================================ // Append all elements in toAppend to array function append (array, toAppend) { for (let i = 0; i < toAppend.length; i += 1) { array.push(toAppend[i]) } } // Interface module.exports = BinarySearchTree /***/ }), /***/ 639: /***/ ((module) => { /** * Return an array with the numbers from 0 to n-1, in a random order */ const getRandomArray = n => { if (n === 0) return [] if (n === 1) return [0] const res = getRandomArray(n - 1) const next = Math.floor(Math.random() * n) res.splice(next, 0, n - 1) // Add n-1 at a random position in the array return res } module.exports.getRandomArray = getRandomArray /* * Default compareKeys function will work for numbers, strings and dates */ const defaultCompareKeysFunction = (a, b) => { if (a < b) return -1 if (a > b) return 1 if (a === b) return 0 const err = new Error("Couldn't compare elements") err.a = a err.b = b throw err } module.exports.defaultCompareKeysFunction = defaultCompareKeysFunction /** * Check whether two values are equal (used in non-unique deletion) */ const defaultCheckValueEquality = (a, b) => a === b module.exports.defaultCheckValueEquality = defaultCheckValueEquality /***/ }), /***/ 924: /***/ ((module, __unused_webpack_exports, __webpack_require__) => { "use strict"; var GetIntrinsic = __webpack_require__(210); var callBind = __webpack_require__(559); var $indexOf = callBind(GetIntrinsic('String.prototype.indexOf')); module.exports = function callBoundIntrinsic(name, allowMissing) { var intrinsic = GetIntrinsic(name, !!allowMissing); if (typeof intrinsic === 'function' && $indexOf(name, '.prototype.') > -1) { return callBind(intrinsic); } return intrinsic; }; /***/ }), /***/ 559: /***/ ((module, __unused_webpack_exports, __webpack_require__) => { "use strict"; var bind = __webpack_require__(612); var GetIntrinsic = __webpack_require__(210); var $apply = GetIntrinsic('%Function.prototype.apply%'); var $call = GetIntrinsic('%Function.prototype.call%'); var $reflectApply = GetIntrinsic('%Reflect.apply%', true) || bind.call($call, $apply); var $gOPD = GetIntrinsic('%Object.getOwnPropertyDescriptor%', true); var $defineProperty = GetIntrinsic('%Object.defineProperty%', true); var $max = GetIntrinsic('%Math.max%'); if ($defineProperty) { try { $defineProperty({}, 'a', { value: 1 }); } catch (e) { // IE 8 has a broken defineProperty $defineProperty = null; } } module.exports = function callBind(originalFunction) { var func = $reflectApply(bind, $call, arguments); if ($gOPD && $defineProperty) { var desc = $gOPD(func, 'length'); if (desc.configurable) { // original length, plus the receiver, minus any additional arguments (after the receiver) $defineProperty( func, 'length', { value: 1 + $max(0, originalFunction.length - (arguments.length - 1)) } ); } } return func; }; var applyBind = function applyBind() { return $reflectApply(bind, $apply, arguments); }; if ($defineProperty) { $defineProperty(module.exports, 'apply', { value: applyBind }); } else { module.exports.apply = applyBind; } /***/ }), /***/ 187: /***/ ((module) => { "use strict"; // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the // "Software"), to deal in the Software without restriction, including // without limitation the rights to use, copy, modify, merge, publish, // distribute, sublicense, and/or sell copies of the Software, and to permit // persons to whom the Software is furnished to do so, subject to the // following conditions: // // The above copyright notice and this permission notice shall be included // in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE // USE OR OTHER DEALINGS IN THE SOFTWARE. var R = typeof Reflect === 'object' ? Reflect : null var ReflectApply = R && typeof R.apply === 'function' ? R.apply : function ReflectApply(target, receiver, args) { return Function.prototype.apply.call(target, receiver, args); } var ReflectOwnKeys if (R && typeof R.ownKeys === 'function') { ReflectOwnKeys = R.ownKeys } else if (Object.getOwnPropertySymbols) { ReflectOwnKeys = function ReflectOwnKeys(target) { return Object.getOwnPropertyNames(target) .concat(Object.getOwnPropertySymbols(target)); }; } else { ReflectOwnKeys = function ReflectOwnKeys(target) { return Object.getOwnPropertyNames(target); }; } function ProcessEmitWarning(warning) { if (console && console.warn) console.warn(warning); } var NumberIsNaN = Number.isNaN || function NumberIsNaN(value) { return value !== value; } function EventEmitter() { EventEmitter.init.call(this); } module.exports = EventEmitter; module.exports.once = once; // Backwards-compat with node 0.10.x EventEmitter.EventEmitter = EventEmitter; EventEmitter.prototype._events = undefined; EventEmitter.prototype._eventsCount = 0; EventEmitter.prototype._maxListeners = undefined; // By default EventEmitters will print a warning if more than 10 listeners are // added to it. This is a useful default which helps finding memory leaks. var defaultMaxListeners = 10; function checkListener(listener) { if (typeof listener !== 'function') { throw new TypeError('The "listener" argument must be of type Function. Received type ' + typeof listener); } } Object.defineProperty(EventEmitter, 'defaultMaxListeners', { enumerable: true, get: function() { return defaultMaxListeners; }, set: function(arg) { if (typeof arg !== 'number' || arg < 0 || NumberIsNaN(arg)) { throw new RangeError('The value of "defaultMaxListeners" is out of range. It must be a non-negative number. Received ' + arg + '.'); } defaultMaxListeners = arg; } }); EventEmitter.init = function() { if (this._events === undefined || this._events === Object.getPrototypeOf(this)._events) { this._events = Object.create(null); this._eventsCount = 0; } this._maxListeners = this._maxListeners || undefined; }; // Obviously not all Emitters should be limited to 10. This function allows // that to be increased. Set to zero for unlimited. EventEmitter.prototype.setMaxListeners = function setMaxListeners(n) { if (typeof n !== 'number' || n < 0 || NumberIsNaN(n)) { throw new RangeError('The value of "n" is out of range. It must be a non-negative number. Received ' + n + '.'); } this._maxListeners = n; return this; }; function _getMaxListeners(that) { if (that._maxListeners === undefined) return EventEmitter.defaultMaxListeners; return that._maxListeners; } EventEmitter.prototype.getMaxListeners = function getMaxListeners() { return _getMaxListeners(this); }; EventEmitter.prototype.emit = function emit(type) { var args = []; for (var i = 1; i < arguments.length; i++) args.push(arguments[i]); var doError = (type === 'error'); var events = this._events; if (events !== undefined) doError = (doError && events.error === undefined); else if (!doError) return false; // If there is no 'error' event listener then throw. if (doError) { var er; if (args.length > 0) er = args[0]; if (er instanceof Error) { // Note: The comments on the `throw` lines are intentional, they show // up in Node's output if this results in an unhandled exception. throw er; // Unhandled 'error' event } // At least give some kind of context to the user var err = new Error('Unhandled error.' + (er ? ' (' + er.message + ')' : '')); err.context = er; throw err; // Unhandled 'error' event } var handler = events[type]; if (handler === undefined) return false; if (typeof handler === 'function') { ReflectApply(handler, this, args); } else { var len = handler.length; var listeners = arrayClone(handler, len); for (var i = 0; i < len; ++i) ReflectApply(listeners[i], this, args); } return true; }; function _addListener(target, type, listener, prepend) { var m; var events; var existing; checkListener(listener); events = target._events; if (events === undefined) { events = target._events = Object.create(null); target._eventsCount = 0; } else { // To avoid recursion in the case that type === "newListener"! Before // adding it to the listeners, first emit "newListener". if (events.newListener !== undefined) { target.emit('newListener', type, listener.listener ? listener.listener : listener); // Re-assign `events` because a newListener handler could have caused the // this._events to be assigned to a new object events = target._events; } existing = events[type]; } if (existing === undefined) { // Optimize the case of one listener. Don't need the extra array object. existing = events[type] = listener; ++target._eventsCount; } else { if (typeof existing === 'function') { // Adding the second element, need to change to array. existing = events[type] = prepend ? [listener, existing] : [existing, listener]; // If we've already got an array, just append. } else if (prepend) { existing.unshift(listener); } else { existing.push(listener); } // Check for listener leak m = _getMaxListeners(target); if (m > 0 && existing.length > m && !existing.warned) { existing.warned = true; // No error code for this since it is a Warning // eslint-disable-next-line no-restricted-syntax var w = new Error('Possible EventEmitter memory leak detected. ' + existing.length + ' ' + String(type) + ' listeners ' + 'added. Use emitter.setMaxListeners() to ' + 'increase limit'); w.name = 'MaxListenersExceededWarning'; w.emitter = target; w.type = type; w.count = existing.length; ProcessEmitWarning(w); } } return target; } EventEmitter.prototype.addListener = function addListener(type, listener) { return _addListener(this, type, listener, false); }; EventEmitter.prototype.on = EventEmitter.prototype.addListener; EventEmitter.prototype.prependListener = function prependListener(type, listener) { return _addListener(this, type, listener, true); }; function onceWrapper() { if (!this.fired) { this.target.removeListener(this.type, this.wrapFn); this.fired = true; if (arguments.length === 0) return this.listener.call(this.target); return this.listener.apply(this.target, arguments); } } function _onceWrap(target, type, listener) { var state = { fired: false, wrapFn: undefined, target: target, type: type, listener: listener }; var wrapped = onceWrapper.bind(state); wrapped.listener = listener; state.wrapFn = wrapped; return wrapped; } EventEmitter.prototype.once = function once(type, listener) { checkListener(listener); this.on(type, _onceWrap(this, type, listener)); return this; }; EventEmitter.prototype.prependOnceListener = function prependOnceListener(type, listener) { checkListener(listener); this.prependListener(type, _onceWrap(this, type, listener)); return this; }; // Emits a 'removeListener' event if and only if the listener was removed. EventEmitter.prototype.removeListener = function removeListener(type, listener) { var list, events, position, i, originalListener; checkListener(listener); events = this._events; if (events === undefined) return this; list = events[type]; if (list === undefined) return this; if (list === listener || list.listener === listener) { if (--this._eventsCount === 0) this._events = Object.create(null); else { delete events[type]; if (events.removeListener) this.emit('removeListener', type, list.listener || listener); } } else if (typeof list !== 'function') { position = -1; for (i = list.length - 1; i >= 0; i--) { if (list[i] === listener || list[i].listener === listener) { originalListener = list[i].listener; position = i; break; } } if (position < 0) return this; if (position === 0) list.shift(); else { spliceOne(list, position); } if (list.length === 1) events[type] = list[0]; if (events.removeListener !== undefined) this.emit('removeListener', type, originalListener || listener); } return this; }; EventEmitter.prototype.off = EventEmitter.prototype.removeListener; EventEmitter.prototype.removeAllListeners = function removeAllListeners(type) { var listeners, events, i; events = this._events; if (events === undefined) return this; // not listening for removeListener, no need to emit if (events.removeListener === undefined) { if (arguments.length === 0) { this._events = Object.create(null); this._eventsCount = 0; } else if (events[type] !== undefined) { if (--this._eventsCount === 0) this._events = Object.create(null); else delete events[type]; } return this; } // emit removeListener for all listeners on all events if (arguments.length === 0) { var keys = Object.keys(events); var key; for (i = 0; i < keys.length; ++i) { key = keys[i]; if (key === 'removeListener') continue; this.removeAllListeners(key); } this.removeAllListeners('removeListener'); this._events = Object.create(null); this._eventsCount = 0; return this; } listeners = events[type]; if (typeof listeners === 'function') { this.removeListener(type, listeners); } else if (listeners !== undefined) { // LIFO order for (i = listeners.length - 1; i >= 0; i--) { this.removeListener(type, listeners[i]); } } return this; }; function _listeners(target, type, unwrap) { var events = target._events; if (events === undefined) return []; var evlistener = events[type]; if (evlistener === undefined) return []; if (typeof evlistener === 'function') return unwrap ? [evlistener.listener || evlistener] : [evlistener]; return unwrap ? unwrapListeners(evlistener) : arrayClone(evlistener, evlistener.length); } EventEmitter.prototype.listeners = function listeners(type) { return _listeners(this, type, true); }; EventEmitter.prototype.rawListeners = function rawListeners(type) { return _listeners(this, type, false); }; EventEmitter.listenerCount = function(emitter, type) { if (typeof emitter.listenerCount === 'function') { return emitter.listenerCount(type); } else { return listenerCount.call(emitter, type); } }; EventEmitter.prototype.listenerCount = listenerCount; function listenerCount(type) { var events = this._events; if (events !== undefined) { var evlistener = events[type]; if (typeof evlistener === 'function') { return 1; } else if (evlistener !== undefined) { return evlistener.length; } } return 0; } EventEmitter.prototype.eventNames = function eventNames() { return this._eventsCount > 0 ? ReflectOwnKeys(this._events) : []; }; function arrayClone(arr, n) { var copy = new Array(n); for (var i = 0; i < n; ++i) copy[i] = arr[i]; return copy; } function spliceOne(list, index) { for (; index + 1 < list.length; index++) list[index] = list[index + 1]; list.pop(); } function unwrapListeners(arr) { var ret = new Array(arr.length); for (var i = 0; i < ret.length; ++i) { ret[i] = arr[i].listener || arr[i]; } return ret; } function once(emitter, name) { return new Promise(function (resolve, reject) { function errorListener(err) { emitter.removeListener(name, resolver); reject(err); } function resolver() { if (typeof emitter.removeListener === 'function') { emitter.removeListener('error', errorListener); } resolve([].slice.call(arguments)); }; eventTargetAgnosticAddListener(emitter, name, resolver, { once: true }); if (name !== 'error') { addErrorHandlerIfEventEmitter(emitter, errorListener, { once: true }); } }); } function addErrorHandlerIfEventEmitter(emitter, handler, flags) { if (typeof emitter.on === 'function') { eventTargetAgnosticAddListener(emitter, 'error', handler, flags); } } function eventTargetAgnosticAddListener(emitter, name, listener, flags) { if (typeof emitter.on === 'function') { if (flags.once) { emitter.once(name, listener); } else { emitter.on(name, listener); } } else if (typeof emitter.addEventListener === 'function') { // EventTarget does not have `error` event semantics like Node // EventEmitters, we do not listen for `error` events here. emitter.addEventListener(name, function wrapListener(arg) { // IE does not have builtin `{ once: true }` support so we // have to do it manually. if (flags.once) { emitter.removeEventListener(name, wrapListener); } listener(arg); }); } else { throw new TypeError('The "emitter" argument must be of type EventEmitter. Received type ' + typeof emitter); } } /***/ }), /***/ 29: /***/ ((module, __unused_webpack_exports, __webpack_require__) => { "use strict"; var isCallable = __webpack_require__(320); var toStr = Object.prototype.toString; var hasOwnProperty = Object.prototype.hasOwnProperty; var forEachArray = function forEachArray(array, iterator, receiver) { for (var i = 0, len = array.length; i < len; i++) { if (hasOwnProperty.call(array, i)) { if (receiver == null) { iterator(array[i], i, array); } else { iterator.call(receiver, array[i], i, array); } } } }; var forEachString = function forEachString(string, iterator, receiver) { for (var i = 0, len = string.length; i < len; i++) { // no such thing as a sparse string. if (receiver == null) { iterator(string.charAt(i), i, string); } else { iterator.call(receiver, string.charAt(i), i, string); } } }; var forEachObject = function forEachObject(object, iterator, receiver) { for (var k in object) { if (hasOwnProperty.call(object, k)) { if (receiver == null) { iterator(object[k], k, object); } else { iterator.call(receiver, object[k], k, object); } } } }; var forEach = function forEach(list, iterator, thisArg) { if (!isCallable(iterator)) { throw new TypeError('iterator must be a function'); } var receiver; if (arguments.length >= 3) { receiver = thisArg; } if (toStr.call(list) === '[object Array]') { forEachArray(list, iterator, receiver); } else if (typeof list === 'string') { forEachString(list, iterator, receiver); } else { forEachObject(list, iterator, receiver); } }; module.exports = forEach; /***/ }), /***/ 648: /***/ ((module) => { "use strict"; /* eslint no-invalid-this: 1 */ var ERROR_MESSAGE = 'Function.prototype.bind called on incompatible '; var slice = Array.prototype.slice; var toStr = Object.prototype.toString; var funcType = '[object Function]'; module.exports = function bind(that) { var target = this; if (typeof target !== 'function' || toStr.call(target) !== funcType) { throw new TypeError(ERROR_MESSAGE + target); } var args = slice.call(arguments, 1); var bound; var binder = function () { if (this instanceof bound) { var result = target.apply( this, args.concat(slice.call(arguments)) ); if (Object(result) === result) { return result; } return this; } else { return target.apply( that, args.concat(slice.call(arguments)) ); } }; var boundLength = Math.max(0, target.length - args.length); var boundArgs = []; for (var i = 0; i < boundLength; i++) { boundArgs.push('$' + i); } bound = Function('binder', 'return function (' + boundArgs.join(',') + '){ return binder.apply(this,arguments); }')(binder); if (target.prototype) { var Empty = function Empty() {}; Empty.prototype = target.prototype; bound.prototype = new Empty(); Empty.prototype = null; } return bound; }; /***/ }), /***/ 612: /***/ ((module, __unused_webpack_exports, __webpack_require__) => { "use strict"; var implementation = __webpack_require__(648); module.exports = Function.prototype.bind || implementation; /***/ }), /***/ 210: /***/ ((module, __unused_webpack_exports, __webpack_require__) => { "use strict"; var undefined; var $SyntaxError = SyntaxError; var $Function = Function; var $TypeError = TypeError; // eslint-disable-next-line consistent-return var getEvalledConstructor = function (expressionSyntax) { try { return $Function('"use strict"; return (' + expressionSyntax + ').constructor;')(); } catch (e) {} }; var $gOPD = Object.getOwnPropertyDescriptor; if ($gOPD) { try { $gOPD({}, ''); } catch (e) { $gOPD = null; // this is IE 8, which has a broken gOPD } } var throwTypeError = function () { throw new $TypeError(); }; var ThrowTypeError = $gOPD ? (function () { try { // eslint-disable-next-line no-unused-expressions, no-caller, no-restricted-properties arguments.callee; // IE 8 does not throw here return throwTypeError; } catch (calleeThrows) { try { // IE 8 throws on Object.getOwnPropertyDescriptor(arguments, '') return $gOPD(arguments, 'callee').get; } catch (gOPDthrows) { return throwTypeError; } } }()) : throwTypeError; var hasSymbols = __webpack_require__(405)(); var getProto = Object.getPrototypeOf || function (x) { return x.__proto__; }; // eslint-disable-line no-proto var needsEval = {}; var TypedArray = typeof Uint8Array === 'undefined' ? undefined : getProto(Uint8Array); var INTRINSICS = { '%AggregateError%': typeof AggregateError === 'undefined' ? undefined : AggregateError, '%Array%': Array, '%ArrayBuffer%': typeof ArrayBuffer === 'undefined' ? undefined : ArrayBuffer, '%ArrayIteratorPrototype%': hasSymbols ? getProto([][Symbol.iterator]()) : undefined, '%AsyncFromSyncIteratorPrototype%': undefined, '%AsyncFunction%': needsEval, '%AsyncGenerator%': needsEval, '%AsyncGeneratorFunction%': needsEval, '%AsyncIteratorPrototype%': needsEval, '%Atomics%': typeof Atomics === 'undefined' ? undefined : Atomics, '%BigInt%': typeof BigInt === 'undefined' ? undefined : BigInt, '%BigInt64Array%': typeof BigInt64Array === 'undefined' ? undefined : BigInt64Array, '%BigUint64Array%': typeof BigUint64Array === 'undefined' ? undefined : BigUint64Array, '%Boolean%': Boolean, '%DataView%': typeof DataView === 'undefined' ? undefined : DataView, '%Date%': Date, '%decodeURI%': decodeURI, '%decodeURIComponent%': decodeURIComponent, '%encodeURI%': encodeURI, '%encodeURIComponent%': encodeURIComponent, '%Error%': Error, '%eval%': eval, // eslint-disable-line no-eval '%EvalError%': EvalError, '%Float32Array%': typeof Float32Array === 'undefined' ? undefined : Float32Array, '%Float64Array%': typeof Float64Array === 'undefined' ? undefined : Float64Array, '%FinalizationRegistry%': typeof FinalizationRegistry === 'undefined' ? undefined : FinalizationRegistry, '%Function%': $Function, '%GeneratorFunction%': needsEval, '%Int8Array%': typeof Int8Array === 'undefined' ? undefined : Int8Array, '%Int16Array%': typeof Int16Array === 'undefined' ? undefined : Int16Array, '%Int32Array%': typeof Int32Array === 'undefined' ? undefined : Int32Array, '%isFinite%': isFinite, '%isNaN%': isNaN, '%IteratorPrototype%': hasSymbols ? getProto(getProto([][Symbol.iterator]())) : undefined, '%JSON%': typeof JSON === 'object' ? JSON : undefined, '%Map%': typeof Map === 'undefined' ? undefined : Map, '%MapIteratorPrototype%': typeof Map === 'undefined' || !hasSymbols ? undefined : getProto(new Map()[Symbol.iterator]()), '%Math%': Math, '%Number%': Number, '%Object%': Object, '%parseFloat%': parseFloat, '%parseInt%': parseInt, '%Promise%': typeof Promise === 'undefined' ? undefined : Promise, '%Proxy%': typeof Proxy === 'undefined' ? undefined : Proxy, '%RangeError%': RangeError, '%ReferenceError%': ReferenceError, '%Reflect%': typeof Reflect === 'undefined' ? undefined : Reflect, '%RegExp%': RegExp, '%Set%': typeof Set === 'undefined' ? undefined : Set, '%SetIteratorPrototype%': typeof Set === 'undefined' || !hasSymbols ? undefined : getProto(new Set()[Symbol.iterator]()), '%SharedArrayBuffer%': typeof SharedArrayBuffer === 'undefined' ? undefined : SharedArrayBuffer, '%String%': String, '%StringIteratorPrototype%': hasSymbols ? getProto(''[Symbol.iterator]()) : undefined, '%Symbol%': hasSymbols ? Symbol : undefined, '%SyntaxError%': $SyntaxError, '%ThrowTypeError%': ThrowTypeError, '%TypedArray%': TypedArray, '%TypeError%': $TypeError, '%Uint8Array%': typeof Uint8Array === 'undefined' ? undefined : Uint8Array, '%Uint8ClampedArray%': typeof Uint8ClampedArray === 'undefined' ? undefined : Uint8ClampedArray, '%Uint16Array%': typeof Uint16Array === 'undefined' ? undefined : Uint16Array, '%Uint32Array%': typeof Uint32Array === 'undefined' ? undefined : Uint32Array, '%URIError%': URIError, '%WeakMap%': typeof WeakMap === 'undefined' ? undefined : WeakMap, '%WeakRef%': typeof WeakRef === 'undefined' ? undefined : WeakRef, '%WeakSet%': typeof WeakSet === 'undefined' ? undefined : WeakSet }; try { null.error; // eslint-disable-line no-unused-expressions } catch (e) { // https://github.com/tc39/proposal-shadowrealm/pull/384#issuecomment-1364264229 var errorProto = getProto(getProto(e)); INTRINSICS['%Error.prototype%'] = errorProto; } var doEval = function doEval(name) { var value; if (name === '%AsyncFunction%') { value = getEvalledConstructor('async function () {}'); } else if (name === '%GeneratorFunction%') { value = getEvalledConstructor('function* () {}'); } else if (name === '%AsyncGeneratorFunction%') { value = getEvalledConstructor('async function* () {}'); } else if (name === '%AsyncGenerator%') { var fn = doEval('%AsyncGeneratorFunction%'); if (fn) { value = fn.prototype; } } else if (name === '%AsyncIteratorPrototype%') { var gen = doEval('%AsyncGenerator%'); if (gen) { value = getProto(gen.prototype); } } INTRINSICS[name] = value; return value; }; var LEGACY_ALIASES = { '%ArrayBufferPrototype%': ['ArrayBuffer', 'prototype'], '%ArrayPrototype%': ['Array', 'prototype'], '%ArrayProto_entries%': ['Array', 'prototype', 'entries'], '%ArrayProto_forEach%': ['Array', 'prototype', 'forEach'], '%ArrayProto_keys%': ['Array', 'prototype', 'keys'], '%ArrayProto_values%': ['Array', 'prototype', 'values'], '%AsyncFunctionPrototype%': ['AsyncFunction', 'prototype'], '%AsyncGenerator%': ['AsyncGeneratorFunction', 'prototype'], '%AsyncGeneratorPrototype%': ['AsyncGeneratorFunction', 'prototype', 'prototype'], '%BooleanPrototype%': ['Boolean', 'prototype'], '%DataViewPrototype%': ['DataView', 'prototype'], '%DatePrototype%': ['Date', 'prototype'], '%ErrorPrototype%': ['Error', 'prototype'], '%EvalErrorPrototype%': ['EvalError', 'prototype'], '%Float32ArrayPrototype%': ['Float32Array', 'prototype'], '%Float64ArrayPrototype%': ['Float64Array', 'prototype'], '%FunctionPrototype%': ['Function', 'prototype'], '%Generator%': ['GeneratorFunction', 'prototype'], '%GeneratorPrototype%': ['GeneratorFunction', 'prototype', 'prototype'], '%Int8ArrayPrototype%': ['Int8Array', 'prototype'], '%Int16ArrayPrototype%': ['Int16Array', 'prototype'], '%Int32ArrayPrototype%': ['Int32Array', 'prototype'], '%JSONParse%': ['JSON', 'parse'], '%JSONStringify%': ['JSON', 'stringify'], '%MapPrototype%': ['Map', 'prototype'], '%NumberPrototype%': ['Number', 'prototype'], '%ObjectPrototype%': ['Object', 'prototype'], '%ObjProto_toString%': ['Object', 'prototype', 'toString'], '%ObjProto_valueOf%': ['Object', 'prototype', 'valueOf'], '%PromisePrototype%': ['Promise', 'prototype'], '%PromiseProto_then%': ['Promise', 'prototype', 'then'], '%Promise_all%': ['Promise', 'all'], '%Promise_reject%': ['Promise', 'reject'], '%Promise_resolve%': ['Promise', 'resolve'], '%RangeErrorPrototype%': ['RangeError', 'prototype'], '%ReferenceErrorPrototype%': ['ReferenceError', 'prototype'], '%RegExpPrototype%': ['RegExp', 'prototype'], '%SetPrototype%': ['Set', 'prototype'], '%SharedArrayBufferPrototype%': ['SharedArrayBuffer', 'prototype'], '%StringPrototype%': ['String', 'prototype'], '%SymbolPrototype%': ['Symbol', 'prototype'], '%SyntaxErrorPrototype%': ['SyntaxError', 'prototype'], '%TypedArrayPrototype%': ['TypedArray', 'prototype'], '%TypeErrorPrototype%': ['TypeError', 'prototype'], '%Uint8ArrayPrototype%': ['Uint8Array', 'prototype'], '%Uint8ClampedArrayPrototype%': ['Uint8ClampedArray', 'prototype'], '%Uint16ArrayPrototype%': ['Uint16Array', 'prototype'], '%Uint32ArrayPrototype%': ['Uint32Array', 'prototype'], '%URIErrorPrototype%': ['URIError', 'prototype'], '%WeakMapPrototype%': ['WeakMap', 'prototype'], '%WeakSetPrototype%': ['WeakSet', 'prototype'] }; var bind = __webpack_require__(612); var hasOwn = __webpack_require__(642); var $concat = bind.call(Function.call, Array.prototype.concat); var $spliceApply = bind.call(Function.apply, Array.prototype.splice); var $replace = bind.call(Function.call, String.prototype.replace); var $strSlice = bind.call(Function.call, String.prototype.slice); var $exec = bind.call(Function.call, RegExp.prototype.exec); /* adapted from https://github.com/lodash/lodash/blob/4.17.15/dist/lodash.js#L6735-L6744 */ var rePropName = /[^%.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|%$))/g; var reEscapeChar = /\\(\\)?/g; /** Used to match backslashes in property paths. */ var stringToPath = function stringToPath(string) { var first = $strSlice(string, 0, 1); var last = $strSlice(string, -1); if (first === '%' && last !== '%') { throw new $SyntaxError('invalid intrinsic syntax, expected closing `%`'); } else if (last === '%' && first !== '%') { throw new $SyntaxError('invalid intrinsic syntax, expected opening `%`'); } var result = []; $replace(string, rePropName, function (match, number, quote, subString) { result[result.length] = quote ? $replace(subString, reEscapeChar, '$1') : number || match; }); return result; }; /* end adaptation */ var getBaseIntrinsic = function getBaseIntrinsic(name, allowMissing) { var intrinsicName = name; var alias; if (hasOwn(LEGACY_ALIASES, intrinsicName)) { alias = LEGACY_ALIASES[intrinsicName]; intrinsicName = '%' + alias[0] + '%'; } if (hasOwn(INTRINSICS, intrinsicName)) { var value = INTRINSICS[intrinsicName]; if (value === needsEval) { value = doEval(intrinsicName); } if (typeof value === 'undefined' && !allowMissing) { throw new $TypeError('intrinsic ' + name + ' exists, but is not available. Please file an issue!'); } return { alias: alias, name: intrinsicName, value: value }; } throw new $SyntaxError('intrinsic ' + name + ' does not exist!'); }; module.exports = function GetIntrinsic(name, allowMissing) { if (typeof name !== 'string' || name.length === 0) { throw new $TypeError('intrinsic name must be a non-empty string'); } if (arguments.length > 1 && typeof allowMissing !== 'boolean') { throw new $TypeError('"allowMissing" argument must be a boolean'); } if ($exec(/^%?[^%]*%?$/, name) === null) { throw new $SyntaxError('`%` may not be present anywhere but at the beginning and end of the intrinsic name'); } var parts = stringToPath(name); var intrinsicBaseName = parts.length > 0 ? parts[0] : ''; var intrinsic = getBaseIntrinsic('%' + intrinsicBaseName + '%', allowMissing); var intrinsicRealName = intrinsic.name; var value = intrinsic.value; var skipFurtherCaching = false; var alias = intrinsic.alias; if (alias) { intrinsicBaseName = alias[0]; $spliceApply(parts, $concat([0, 1], alias)); } for (var i = 1, isOwn = true; i < parts.length; i += 1) { var part = parts[i]; var first = $strSlice(part, 0, 1); var last = $strSlice(part, -1); if ( ( (first === '"' || first === "'" || first === '`') || (last === '"' || last === "'" || last === '`') ) && first !== last ) { throw new $SyntaxError('property names with quotes must have matching quotes'); } if (part === 'constructor' || !isOwn) { skipFurtherCaching = true; } intrinsicBaseName += '.' + part; intrinsicRealName = '%' + intrinsicBaseName + '%'; if (hasOwn(INTRINSICS, intrinsicRealName)) { value = INTRINSICS[intrinsicRealName]; } else if (value != null) { if (!(part in value)) { if (!allowMissing) { throw new $TypeError('base intrinsic for ' + name + ' exists, but the property is not available.'); } return void undefined; } if ($gOPD && (i + 1) >= parts.length) { var desc = $gOPD(value, part); isOwn = !!desc; // By convention, when a data property is converted to an accessor // property to emulate a data property that does not suffer from // the override mistake, that accessor's getter is marked with // an `originalValue` property. Here, when we detect this, we // uphold the illusion by pretending to see that original data // property, i.e., returning the value rather than the getter // itself. if (isOwn && 'get' in desc && !('originalValue' in desc.get)) { value = desc.get; } else { value = value[part]; } } else { isOwn = hasOwn(value, part); value = value[part]; } if (isOwn && !skipFurtherCaching) { INTRINSICS[intrinsicRealName] = value; } } } return value; }; /***/ }), /***/ 296: /***/ ((module, __unused_webpack_exports, __webpack_require__) => { "use strict"; var GetIntrinsic = __webpack_require__(210); var $gOPD = GetIntrinsic('%Object.getOwnPropertyDescriptor%', true); if ($gOPD) { try { $gOPD([], 'length'); } catch (e) { // IE 8 has a broken gOPD $gOPD = null; } } module.exports = $gOPD; /***/ }), /***/ 405: /***/ ((module, __unused_webpack_exports, __webpack_require__) => { "use strict"; var origSymbol = typeof Symbol !== 'undefined' && Symbol; var hasSymbolSham = __webpack_require__(419); module.exports = function hasNativeSymbols() { if (typeof origSymbol !== 'function') { return false; } if (typeof Symbol !== 'function') { return false; } if (typeof origSymbol('foo') !== 'symbol') { return false; } if (typeof Symbol('bar') !== 'symbol') { return false; } return hasSymbolSham(); }; /***/ }), /***/ 419: /***/ ((module) => { "use strict"; /* eslint complexity: [2, 18], max-statements: [2, 33] */ module.exports = function hasSymbols() { if (typeof Symbol !== 'function' || typeof Object.getOwnPropertySymbols !== 'function') { return false; } if (typeof Symbol.iterator === 'symbol') { return true; } var obj = {}; var sym = Symbol('test'); var symObj = Object(sym); if (typeof sym === 'string') { return false; } if (Object.prototype.toString.call(sym) !== '[object Symbol]') { return false; } if (Object.prototype.toString.call(symObj) !== '[object Symbol]') { return false; } // temp disabled per https://github.com/ljharb/object.assign/issues/17 // if (sym instanceof Symbol) { return false; } // temp disabled per https://github.com/WebReflection/get-own-property-symbols/issues/4 // if (!(symObj instanceof Symbol)) { return false; } // if (typeof Symbol.prototype.toString !== 'function') { return false; } // if (String(sym) !== Symbol.prototype.toString.call(sym)) { return false; } var symVal = 42; obj[sym] = symVal; for (sym in obj) { return false; } // eslint-disable-line no-restricted-syntax, no-unreachable-loop if (typeof Object.keys === 'function' && Object.keys(obj).length !== 0) { return false; } if (typeof Object.getOwnPropertyNames === 'function' && Object.getOwnPropertyNames(obj).length !== 0) { return false; } var syms = Object.getOwnPropertySymbols(obj); if (syms.length !== 1 || syms[0] !== sym) { return false; } if (!Object.prototype.propertyIsEnumerable.call(obj, sym)) { return false; } if (typeof Object.getOwnPropertyDescriptor === 'function') { var descriptor = Object.getOwnPropertyDescriptor(obj, sym); if (descriptor.value !== symVal || descriptor.enumerable !== true) { return false; } } return true; }; /***/ }), /***/ 410: /***/ ((module, __unused_webpack_exports, __webpack_require__) => { "use strict"; var hasSymbols = __webpack_require__(419); module.exports = function hasToStringTagShams() { return hasSymbols() && !!Symbol.toStringTag; }; /***/ }), /***/ 642: /***/ ((module, __unused_webpack_exports, __webpack_require__) => { "use strict"; var bind = __webpack_require__(612); module.exports = bind.call(Function.call, Object.prototype.hasOwnProperty); /***/ }), /***/ 717: /***/ ((module) => { if (typeof Object.create === 'function') { // implementation from standard node.js 'util' module module.exports = function inherits(ctor, superCtor) { if (superCtor) { ctor.super_ = superCtor ctor.prototype = Object.create(superCtor.prototype, { constructor: { value: ctor, enumerable: false, writable: true, configurable: true } }) } }; } else { // old school shim for old browsers module.exports = function inherits(ctor, superCtor) { if (superCtor) { ctor.super_ = superCtor var TempCtor = function () {} TempCtor.prototype = superCtor.prototype ctor.prototype = new TempCtor() ctor.prototype.constructor = ctor } } } /***/ }), /***/ 584: /***/ ((module, __unused_webpack_exports, __webpack_require__) => { "use strict"; var hasToStringTag = __webpack_require__(410)(); var callBound = __webpack_require__(924); var $toString = callBound('Object.prototype.toString'); var isStandardArguments = function isArguments(value) { if (hasToStringTag && value && typeof value === 'object' && Symbol.toStringTag in value) { return false; } return $toString(value) === '[object Arguments]'; }; var isLegacyArguments = function isArguments(value) { if (isStandardArguments(value)) { return true; } return value !== null && typeof value === 'object' && typeof value.length === 'number' && value.length >= 0 && $toString(value) !== '[object Array]' && $toString(value.callee) === '[object Function]'; }; var supportsStandardArguments = (function () { return isStandardArguments(arguments); }()); isStandardArguments.isLegacyArguments = isLegacyArguments; // for tests module.exports = supportsStandardArguments ? isStandardArguments : isLegacyArguments; /***/ }), /***/ 320: /***/ ((module) => { "use strict"; var fnToStr = Function.prototype.toString; var reflectApply = typeof Reflect === 'object' && Reflect !== null && Reflect.apply; var badArrayLike; var isCallableMarker; if (typeof reflectApply === 'function' && typeof Object.defineProperty === 'function') { try { badArrayLike = Object.defineProperty({}, 'length', { get: function () { throw isCallableMarker; } }); isCallableMarker = {}; // eslint-disable-next-line no-throw-literal reflectApply(function () { throw 42; }, null, badArrayLike); } catch (_) { if (_ !== isCallableMarker) { reflectApply = null; } } } else { reflectApply = null; } var constructorRegex = /^\s*class\b/; var isES6ClassFn = function isES6ClassFunction(value) { try { var fnStr = fnToStr.call(value); return constructorRegex.test(fnStr); } catch (e) { return false; // not a function } }; var tryFunctionObject = function tryFunctionToStr(value) { try { if (isES6ClassFn(value)) { return false; } fnToStr.call(value); return true; } catch (e) { return false; } }; var toStr = Object.prototype.toString; var objectClass = '[object Object]'; var fnClass = '[object Function]'; var genClass = '[object GeneratorFunction]'; var ddaClass = '[object HTMLAllCollection]'; // IE 11 var ddaClass2 = '[object HTML document.all class]'; var ddaClass3 = '[object HTMLCollection]'; // IE 9-10 var hasToStringTag = typeof Symbol === 'function' && !!Symbol.toStringTag; // better: use `has-tostringtag` var isIE68 = !(0 in [,]); // eslint-disable-line no-sparse-arrays, comma-spacing var isDDA = function isDocumentDotAll() { return false; }; if (typeof document === 'object') { // Firefox 3 canonicalizes DDA to undefined when it's not accessed directly var all = document.all; if (toStr.call(all) === toStr.call(document.all)) { isDDA = function isDocumentDotAll(value) { /* globals document: false */ // in IE 6-8, typeof document.all is "object" and it's truthy if ((isIE68 || !value) && (typeof value === 'undefined' || typeof value === 'object')) { try { var str = toStr.call(value); return ( str === ddaClass || str === ddaClass2 || str === ddaClass3 // opera 12.16 || str === objectClass // IE 6-8 ) && value('') == null; // eslint-disable-line eqeqeq } catch (e) { /**/ } } return false; }; } } module.exports = reflectApply ? function isCallable(value) { if (isDDA(value)) { return true; } if (!value) { return false; } if (typeof value !== 'function' && typeof value !== 'object') { return false; } try { reflectApply(value, null, badArrayLike); } catch (e) { if (e !== isCallableMarker) { return false; } } return !isES6ClassFn(value) && tryFunctionObject(value); } : function isCallable(value) { if (isDDA(value)) { return true; } if (!value) { return false; } if (typeof value !== 'function' && typeof value !== 'object') { return false; } if (hasToStringTag) { return tryFunctionObject(value); } if (isES6ClassFn(value)) { return false; } var strClass = toStr.call(value); if (strClass !== fnClass && strClass !== genClass && !(/^\[object HTML/).test(strClass)) { return false; } return tryFunctionObject(value); }; /***/ }), /***/ 662: /***/ ((module, __unused_webpack_exports, __webpack_require__) => { "use strict"; var toStr = Object.prototype.toString; var fnToStr = Function.prototype.toString; var isFnRegex = /^\s*(?:function)?\*/; var hasToStringTag = __webpack_require__(410)(); var getProto = Object.getPrototypeOf; var getGeneratorFunc = function () { // eslint-disable-line consistent-return if (!hasToStringTag) { return false; } try { return Function('return function*() {}')(); } catch (e) { } }; var GeneratorFunction; module.exports = function isGeneratorFunction(fn) { if (typeof fn !== 'function') { return false; } if (isFnRegex.test(fnToStr.call(fn))) { return true; } if (!hasToStringTag) { var str = toStr.call(fn); return str === '[object GeneratorFunction]'; } if (!getProto) { return false; } if (typeof GeneratorFunction === 'undefined') { var generatorFunc = getGeneratorFunc(); GeneratorFunction = generatorFunc ? getProto(generatorFunc) : false; } return getProto(fn) === GeneratorFunction; }; /***/ }), /***/ 692: /***/ ((module, __unused_webpack_exports, __webpack_require__) => { "use strict"; var forEach = __webpack_require__(29); var availableTypedArrays = __webpack_require__(83); var callBound = __webpack_require__(924); var $toString = callBound('Object.prototype.toString'); var hasToStringTag = __webpack_require__(410)(); var gOPD = __webpack_require__(296); var g = typeof globalThis === 'undefined' ? __webpack_require__.g : globalThis; var typedArrays = availableTypedArrays(); var $indexOf = callBound('Array.prototype.indexOf', true) || function indexOf(array, value) { for (var i = 0; i < array.length; i += 1) { if (array[i] === value) { return i; } } return -1; }; var $slice = callBound('String.prototype.slice'); var toStrTags = {}; var getPrototypeOf = Object.getPrototypeOf; // require('getprototypeof'); if (hasToStringTag && gOPD && getPrototypeOf) { forEach(typedArrays, function (typedArray) { var arr = new g[typedArray](); if (Symbol.toStringTag in arr) { var proto = getPrototypeOf(arr); var descriptor = gOPD(proto, Symbol.toStringTag); if (!descriptor) { var superProto = getPrototypeOf(proto); descriptor = gOPD(superProto, Symbol.toStringTag); } toStrTags[typedArray] = descriptor.get; } }); } var tryTypedArrays = function tryAllTypedArrays(value) { var anyTrue = false; forEach(toStrTags, function (getter, typedArray) { if (!anyTrue) { try { anyTrue = getter.call(value) === typedArray; } catch (e) { /**/ } } }); return anyTrue; }; module.exports = function isTypedArray(value) { if (!value || typeof value !== 'object') { return false; } if (!hasToStringTag || !(Symbol.toStringTag in value)) { var tag = $slice($toString(value), 8, -1); return $indexOf(typedArrays, tag) > -1; } if (!gOPD) { return false; } return tryTypedArrays(value); }; /***/ }), /***/ 483: /***/ ((module, __unused_webpack_exports, __webpack_require__) => { /*! localForage -- Offline Storage, Improved Version 1.10.0 https://localforage.github.io/localForage (c) 2013-2017 Mozilla, Apache License 2.0 */ (function(f){if(true){module.exports=f()}else { var g; }})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=undefined;if(!u&&a)return require(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw (f.code="MODULE_NOT_FOUND", f)}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=undefined;for(var o=0;o element; its readystatechange event will be fired asynchronously once it is inserted // into the document. Do so, thus queuing up the task. Remember to clean up once it's been called. var scriptEl = global.document.createElement('script'); scriptEl.onreadystatechange = function () { nextTick(); scriptEl.onreadystatechange = null; scriptEl.parentNode.removeChild(scriptEl); scriptEl = null; }; global.document.documentElement.appendChild(scriptEl); }; } else { scheduleDrain = function () { setTimeout(nextTick, 0); }; } } var draining; var queue = []; //named nextTick for less confusing stack traces function nextTick() { draining = true; var i, oldQueue; var len = queue.length; while (len) { oldQueue = queue; queue = []; i = -1; while (++i < len) { oldQueue[i](); } len = queue.length; } draining = false; } module.exports = immediate; function immediate(task) { if (queue.push(task) === 1 && !draining) { scheduleDrain(); } } }).call(this,typeof __webpack_require__.g !== "undefined" ? __webpack_require__.g : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) },{}],2:[function(_dereq_,module,exports){ 'use strict'; var immediate = _dereq_(1); /* istanbul ignore next */ function INTERNAL() {} var handlers = {}; var REJECTED = ['REJECTED']; var FULFILLED = ['FULFILLED']; var PENDING = ['PENDING']; module.exports = Promise; function Promise(resolver) { if (typeof resolver !== 'function') { throw new TypeError('resolver must be a function'); } this.state = PENDING; this.queue = []; this.outcome = void 0; if (resolver !== INTERNAL) { safelyResolveThenable(this, resolver); } } Promise.prototype["catch"] = function (onRejected) { return this.then(null, onRejected); }; Promise.prototype.then = function (onFulfilled, onRejected) { if (typeof onFulfilled !== 'function' && this.state === FULFILLED || typeof onRejected !== 'function' && this.state === REJECTED) { return this; } var promise = new this.constructor(INTERNAL); if (this.state !== PENDING) { var resolver = this.state === FULFILLED ? onFulfilled : onRejected; unwrap(promise, resolver, this.outcome); } else { this.queue.push(new QueueItem(promise, onFulfilled, onRejected)); } return promise; }; function QueueItem(promise, onFulfilled, onRejected) { this.promise = promise; if (typeof onFulfilled === 'function') { this.onFulfilled = onFulfilled; this.callFulfilled = this.otherCallFulfilled; } if (typeof onRejected === 'function') { this.onRejected = onRejected; this.callRejected = this.otherCallRejected; } } QueueItem.prototype.callFulfilled = function (value) { handlers.resolve(this.promise, value); }; QueueItem.prototype.otherCallFulfilled = function (value) { unwrap(this.promise, this.onFulfilled, value); }; QueueItem.prototype.callRejected = function (value) { handlers.reject(this.promise, value); }; QueueItem.prototype.otherCallRejected = function (value) { unwrap(this.promise, this.onRejected, value); }; function unwrap(promise, func, value) { immediate(function () { var returnValue; try { returnValue = func(value); } catch (e) { return handlers.reject(promise, e); } if (returnValue === promise) { handlers.reject(promise, new TypeError('Cannot resolve promise with itself')); } else { handlers.resolve(promise, returnValue); } }); } handlers.resolve = function (self, value) { var result = tryCatch(getThen, value); if (result.status === 'error') { return handlers.reject(self, result.value); } var thenable = result.value; if (thenable) { safelyResolveThenable(self, thenable); } else { self.state = FULFILLED; self.outcome = value; var i = -1; var len = self.queue.length; while (++i < len) { self.queue[i].callFulfilled(value); } } return self; }; handlers.reject = function (self, error) { self.state = REJECTED; self.outcome = error; var i = -1; var len = self.queue.length; while (++i < len) { self.queue[i].callRejected(error); } return self; }; function getThen(obj) { // Make sure we only access the accessor once as required by the spec var then = obj && obj.then; if (obj && (typeof obj === 'object' || typeof obj === 'function') && typeof then === 'function') { return function appyThen() { then.apply(obj, arguments); }; } } function safelyResolveThenable(self, thenable) { // Either fulfill, reject or reject with error var called = false; function onError(value) { if (called) { return; } called = true; handlers.reject(self, value); } function onSuccess(value) { if (called) { return; } called = true; handlers.resolve(self, value); } function tryToUnwrap() { thenable(onSuccess, onError); } var result = tryCatch(tryToUnwrap); if (result.status === 'error') { onError(result.value); } } function tryCatch(func, value) { var out = {}; try { out.value = func(value); out.status = 'success'; } catch (e) { out.status = 'error'; out.value = e; } return out; } Promise.resolve = resolve; function resolve(value) { if (value instanceof this) { return value; } return handlers.resolve(new this(INTERNAL), value); } Promise.reject = reject; function reject(reason) { var promise = new this(INTERNAL); return handlers.reject(promise, reason); } Promise.all = all; function all(iterable) { var self = this; if (Object.prototype.toString.call(iterable) !== '[object Array]') { return this.reject(new TypeError('must be an array')); } var len = iterable.length; var called = false; if (!len) { return this.resolve([]); } var values = new Array(len); var resolved = 0; var i = -1; var promise = new this(INTERNAL); while (++i < len) { allResolver(iterable[i], i); } return promise; function allResolver(value, i) { self.resolve(value).then(resolveFromAll, function (error) { if (!called) { called = true; handlers.reject(promise, error); } }); function resolveFromAll(outValue) { values[i] = outValue; if (++resolved === len && !called) { called = true; handlers.resolve(promise, values); } } } } Promise.race = race; function race(iterable) { var self = this; if (Object.prototype.toString.call(iterable) !== '[object Array]') { return this.reject(new TypeError('must be an array')); } var len = iterable.length; var called = false; if (!len) { return this.resolve([]); } var i = -1; var promise = new this(INTERNAL); while (++i < len) { resolver(iterable[i]); } return promise; function resolver(value) { self.resolve(value).then(function (response) { if (!called) { called = true; handlers.resolve(promise, response); } }, function (error) { if (!called) { called = true; handlers.reject(promise, error); } }); } } },{"1":1}],3:[function(_dereq_,module,exports){ (function (global){ 'use strict'; if (typeof global.Promise !== 'function') { global.Promise = _dereq_(2); } }).call(this,typeof __webpack_require__.g !== "undefined" ? __webpack_require__.g : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) },{"2":2}],4:[function(_dereq_,module,exports){ 'use strict'; var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function getIDB() { /* global indexedDB,webkitIndexedDB,mozIndexedDB,OIndexedDB,msIndexedDB */ try { if (typeof indexedDB !== 'undefined') { return indexedDB; } if (typeof webkitIndexedDB !== 'undefined') { return webkitIndexedDB; } if (typeof mozIndexedDB !== 'undefined') { return mozIndexedDB; } if (typeof OIndexedDB !== 'undefined') { return OIndexedDB; } if (typeof msIndexedDB !== 'undefined') { return msIndexedDB; } } catch (e) { return; } } var idb = getIDB(); function isIndexedDBValid() { try { // Initialize IndexedDB; fall back to vendor-prefixed versions // if needed. if (!idb || !idb.open) { return false; } // We mimic PouchDB here; // // We test for openDatabase because IE Mobile identifies itself // as Safari. Oh the lulz... var isSafari = typeof openDatabase !== 'undefined' && /(Safari|iPhone|iPad|iPod)/.test(navigator.userAgent) && !/Chrome/.test(navigator.userAgent) && !/BlackBerry/.test(navigator.platform); var hasFetch = typeof fetch === 'function' && fetch.toString().indexOf('[native code') !== -1; // Safari <10.1 does not meet our requirements for IDB support // (see: https://github.com/pouchdb/pouchdb/issues/5572). // Safari 10.1 shipped with fetch, we can use that to detect it. // Note: this creates issues with `window.fetch` polyfills and // overrides; see: // https://github.com/localForage/localForage/issues/856 return (!isSafari || hasFetch) && typeof indexedDB !== 'undefined' && // some outdated implementations of IDB that appear on Samsung // and HTC Android devices <4.4 are missing IDBKeyRange // See: https://github.com/mozilla/localForage/issues/128 // See: https://github.com/mozilla/localForage/issues/272 typeof IDBKeyRange !== 'undefined'; } catch (e) { return false; } } // Abstracts constructing a Blob object, so it also works in older // browsers that don't support the native Blob constructor. (i.e. // old QtWebKit versions, at least). // Abstracts constructing a Blob object, so it also works in older // browsers that don't support the native Blob constructor. (i.e. // old QtWebKit versions, at least). function createBlob(parts, properties) { /* global BlobBuilder,MSBlobBuilder,MozBlobBuilder,WebKitBlobBuilder */ parts = parts || []; properties = properties || {}; try { return new Blob(parts, properties); } catch (e) { if (e.name !== 'TypeError') { throw e; } var Builder = typeof BlobBuilder !== 'undefined' ? BlobBuilder : typeof MSBlobBuilder !== 'undefined' ? MSBlobBuilder : typeof MozBlobBuilder !== 'undefined' ? MozBlobBuilder : WebKitBlobBuilder; var builder = new Builder(); for (var i = 0; i < parts.length; i += 1) { builder.append(parts[i]); } return builder.getBlob(properties.type); } } // This is CommonJS because lie is an external dependency, so Rollup // can just ignore it. if (typeof Promise === 'undefined') { // In the "nopromises" build this will just throw if you don't have // a global promise object, but it would throw anyway later. _dereq_(3); } var Promise$1 = Promise; function executeCallback(promise, callback) { if (callback) { promise.then(function (result) { callback(null, result); }, function (error) { callback(error); }); } } function executeTwoCallbacks(promise, callback, errorCallback) { if (typeof callback === 'function') { promise.then(callback); } if (typeof errorCallback === 'function') { promise["catch"](errorCallback); } } function normalizeKey(key) { // Cast the key to a string, as that's all we can set as a key. if (typeof key !== 'string') { console.warn(key + ' used as a key, but it is not a string.'); key = String(key); } return key; } function getCallback() { if (arguments.length && typeof arguments[arguments.length - 1] === 'function') { return arguments[arguments.length - 1]; } } // Some code originally from async_storage.js in // [Gaia](https://github.com/mozilla-b2g/gaia). var DETECT_BLOB_SUPPORT_STORE = 'local-forage-detect-blob-support'; var supportsBlobs = void 0; var dbContexts = {}; var toString = Object.prototype.toString; // Transaction Modes var READ_ONLY = 'readonly'; var READ_WRITE = 'readwrite'; // Transform a binary string to an array buffer, because otherwise // weird stuff happens when you try to work with the binary string directly. // It is known. // From http://stackoverflow.com/questions/14967647/ (continues on next line) // encode-decode-image-with-base64-breaks-image (2013-04-21) function _binStringToArrayBuffer(bin) { var length = bin.length; var buf = new ArrayBuffer(length); var arr = new Uint8Array(buf); for (var i = 0; i < length; i++) { arr[i] = bin.charCodeAt(i); } return buf; } // // Blobs are not supported in all versions of IndexedDB, notably // Chrome <37 and Android <5. In those versions, storing a blob will throw. // // Various other blob bugs exist in Chrome v37-42 (inclusive). // Detecting them is expensive and confusing to users, and Chrome 37-42 // is at very low usage worldwide, so we do a hacky userAgent check instead. // // content-type bug: https://code.google.com/p/chromium/issues/detail?id=408120 // 404 bug: https://code.google.com/p/chromium/issues/detail?id=447916 // FileReader bug: https://code.google.com/p/chromium/issues/detail?id=447836 // // Code borrowed from PouchDB. See: // https://github.com/pouchdb/pouchdb/blob/master/packages/node_modules/pouchdb-adapter-idb/src/blobSupport.js // function _checkBlobSupportWithoutCaching(idb) { return new Promise$1(function (resolve) { var txn = idb.transaction(DETECT_BLOB_SUPPORT_STORE, READ_WRITE); var blob = createBlob(['']); txn.objectStore(DETECT_BLOB_SUPPORT_STORE).put(blob, 'key'); txn.onabort = function (e) { // If the transaction aborts now its due to not being able to // write to the database, likely due to the disk being full e.preventDefault(); e.stopPropagation(); resolve(false); }; txn.oncomplete = function () { var matchedChrome = navigator.userAgent.match(/Chrome\/(\d+)/); var matchedEdge = navigator.userAgent.match(/Edge\//); // MS Edge pretends to be Chrome 42: // https://msdn.microsoft.com/en-us/library/hh869301%28v=vs.85%29.aspx resolve(matchedEdge || !matchedChrome || parseInt(matchedChrome[1], 10) >= 43); }; })["catch"](function () { return false; // error, so assume unsupported }); } function _checkBlobSupport(idb) { if (typeof supportsBlobs === 'boolean') { return Promise$1.resolve(supportsBlobs); } return _checkBlobSupportWithoutCaching(idb).then(function (value) { supportsBlobs = value; return supportsBlobs; }); } function _deferReadiness(dbInfo) { var dbContext = dbContexts[dbInfo.name]; // Create a deferred object representing the current database operation. var deferredOperation = {}; deferredOperation.promise = new Promise$1(function (resolve, reject) { deferredOperation.resolve = resolve; deferredOperation.reject = reject; }); // Enqueue the deferred operation. dbContext.deferredOperations.push(deferredOperation); // Chain its promise to the database readiness. if (!dbContext.dbReady) { dbContext.dbReady = deferredOperation.promise; } else { dbContext.dbReady = dbContext.dbReady.then(function () { return deferredOperation.promise; }); } } function _advanceReadiness(dbInfo) { var dbContext = dbContexts[dbInfo.name]; // Dequeue a deferred operation. var deferredOperation = dbContext.deferredOperations.pop(); // Resolve its promise (which is part of the database readiness // chain of promises). if (deferredOperation) { deferredOperation.resolve(); return deferredOperation.promise; } } function _rejectReadiness(dbInfo, err) { var dbContext = dbContexts[dbInfo.name]; // Dequeue a deferred operation. var deferredOperation = dbContext.deferredOperations.pop(); // Reject its promise (which is part of the database readiness // chain of promises). if (deferredOperation) { deferredOperation.reject(err); return deferredOperation.promise; } } function _getConnection(dbInfo, upgradeNeeded) { return new Promise$1(function (resolve, reject) { dbContexts[dbInfo.name] = dbContexts[dbInfo.name] || createDbContext(); if (dbInfo.db) { if (upgradeNeeded) { _deferReadiness(dbInfo); dbInfo.db.close(); } else { return resolve(dbInfo.db); } } var dbArgs = [dbInfo.name]; if (upgradeNeeded) { dbArgs.push(dbInfo.version); } var openreq = idb.open.apply(idb, dbArgs); if (upgradeNeeded) { openreq.onupgradeneeded = function (e) { var db = openreq.result; try { db.createObjectStore(dbInfo.storeName); if (e.oldVersion <= 1) { // Added when support for blob shims was added db.createObjectStore(DETECT_BLOB_SUPPORT_STORE); } } catch (ex) { if (ex.name === 'ConstraintError') { console.warn('The database "' + dbInfo.name + '"' + ' has been upgraded from version ' + e.oldVersion + ' to version ' + e.newVersion + ', but the storage "' + dbInfo.storeName + '" already exists.'); } else { throw ex; } } }; } openreq.onerror = function (e) { e.preventDefault(); reject(openreq.error); }; openreq.onsuccess = function () { var db = openreq.result; db.onversionchange = function (e) { // Triggered when the database is modified (e.g. adding an objectStore) or // deleted (even when initiated by other sessions in different tabs). // Closing the connection here prevents those operations from being blocked. // If the database is accessed again later by this instance, the connection // will be reopened or the database recreated as needed. e.target.close(); }; resolve(db); _advanceReadiness(dbInfo); }; }); } function _getOriginalConnection(dbInfo) { return _getConnection(dbInfo, false); } function _getUpgradedConnection(dbInfo) { return _getConnection(dbInfo, true); } function _isUpgradeNeeded(dbInfo, defaultVersion) { if (!dbInfo.db) { return true; } var isNewStore = !dbInfo.db.objectStoreNames.contains(dbInfo.storeName); var isDowngrade = dbInfo.version < dbInfo.db.version; var isUpgrade = dbInfo.version > dbInfo.db.version; if (isDowngrade) { // If the version is not the default one // then warn for impossible downgrade. if (dbInfo.version !== defaultVersion) { console.warn('The database "' + dbInfo.name + '"' + " can't be downgraded from version " + dbInfo.db.version + ' to version ' + dbInfo.version + '.'); } // Align the versions to prevent errors. dbInfo.version = dbInfo.db.version; } if (isUpgrade || isNewStore) { // If the store is new then increment the version (if needed). // This will trigger an "upgradeneeded" event which is required // for creating a store. if (isNewStore) { var incVersion = dbInfo.db.version + 1; if (incVersion > dbInfo.version) { dbInfo.version = incVersion; } } return true; } return false; } // encode a blob for indexeddb engines that don't support blobs function _encodeBlob(blob) { return new Promise$1(function (resolve, reject) { var reader = new FileReader(); reader.onerror = reject; reader.onloadend = function (e) { var base64 = btoa(e.target.result || ''); resolve({ __local_forage_encoded_blob: true, data: base64, type: blob.type }); }; reader.readAsBinaryString(blob); }); } // decode an encoded blob function _decodeBlob(encodedBlob) { var arrayBuff = _binStringToArrayBuffer(atob(encodedBlob.data)); return createBlob([arrayBuff], { type: encodedBlob.type }); } // is this one of our fancy encoded blobs? function _isEncodedBlob(value) { return value && value.__local_forage_encoded_blob; } // Specialize the default `ready()` function by making it dependent // on the current database operations. Thus, the driver will be actually // ready when it's been initialized (default) *and* there are no pending // operations on the database (initiated by some other instances). function _fullyReady(callback) { var self = this; var promise = self._initReady().then(function () { var dbContext = dbContexts[self._dbInfo.name]; if (dbContext && dbContext.dbReady) { return dbContext.dbReady; } }); executeTwoCallbacks(promise, callback, callback); return promise; } // Try to establish a new db connection to replace the // current one which is broken (i.e. experiencing // InvalidStateError while creating a transaction). function _tryReconnect(dbInfo) { _deferReadiness(dbInfo); var dbContext = dbContexts[dbInfo.name]; var forages = dbContext.forages; for (var i = 0; i < forages.length; i++) { var forage = forages[i]; if (forage._dbInfo.db) { forage._dbInfo.db.close(); forage._dbInfo.db = null; } } dbInfo.db = null; return _getOriginalConnection(dbInfo).then(function (db) { dbInfo.db = db; if (_isUpgradeNeeded(dbInfo)) { // Reopen the database for upgrading. return _getUpgradedConnection(dbInfo); } return db; }).then(function (db) { // store the latest db reference // in case the db was upgraded dbInfo.db = dbContext.db = db; for (var i = 0; i < forages.length; i++) { forages[i]._dbInfo.db = db; } })["catch"](function (err) { _rejectReadiness(dbInfo, err); throw err; }); } // FF doesn't like Promises (micro-tasks) and IDDB store operations, // so we have to do it with callbacks function createTransaction(dbInfo, mode, callback, retries) { if (retries === undefined) { retries = 1; } try { var tx = dbInfo.db.transaction(dbInfo.storeName, mode); callback(null, tx); } catch (err) { if (retries > 0 && (!dbInfo.db || err.name === 'InvalidStateError' || err.name === 'NotFoundError')) { return Promise$1.resolve().then(function () { if (!dbInfo.db || err.name === 'NotFoundError' && !dbInfo.db.objectStoreNames.contains(dbInfo.storeName) && dbInfo.version <= dbInfo.db.version) { // increase the db version, to create the new ObjectStore if (dbInfo.db) { dbInfo.version = dbInfo.db.version + 1; } // Reopen the database for upgrading. return _getUpgradedConnection(dbInfo); } }).then(function () { return _tryReconnect(dbInfo).then(function () { createTransaction(dbInfo, mode, callback, retries - 1); }); })["catch"](callback); } callback(err); } } function createDbContext() { return { // Running localForages sharing a database. forages: [], // Shared database. db: null, // Database readiness (promise). dbReady: null, // Deferred operations on the database. deferredOperations: [] }; } // Open the IndexedDB database (automatically creates one if one didn't // previously exist), using any options set in the config. function _initStorage(options) { var self = this; var dbInfo = { db: null }; if (options) { for (var i in options) { dbInfo[i] = options[i]; } } // Get the current context of the database; var dbContext = dbContexts[dbInfo.name]; // ...or create a new context. if (!dbContext) { dbContext = createDbContext(); // Register the new context in the global container. dbContexts[dbInfo.name] = dbContext; } // Register itself as a running localForage in the current context. dbContext.forages.push(self); // Replace the default `ready()` function with the specialized one. if (!self._initReady) { self._initReady = self.ready; self.ready = _fullyReady; } // Create an array of initialization states of the related localForages. var initPromises = []; function ignoreErrors() { // Don't handle errors here, // just makes sure related localForages aren't pending. return Promise$1.resolve(); } for (var j = 0; j < dbContext.forages.length; j++) { var forage = dbContext.forages[j]; if (forage !== self) { // Don't wait for itself... initPromises.push(forage._initReady()["catch"](ignoreErrors)); } } // Take a snapshot of the related localForages. var forages = dbContext.forages.slice(0); // Initialize the connection process only when // all the related localForages aren't pending. return Promise$1.all(initPromises).then(function () { dbInfo.db = dbContext.db; // Get the connection or open a new one without upgrade. return _getOriginalConnection(dbInfo); }).then(function (db) { dbInfo.db = db; if (_isUpgradeNeeded(dbInfo, self._defaultConfig.version)) { // Reopen the database for upgrading. return _getUpgradedConnection(dbInfo); } return db; }).then(function (db) { dbInfo.db = dbContext.db = db; self._dbInfo = dbInfo; // Share the final connection amongst related localForages. for (var k = 0; k < forages.length; k++) { var forage = forages[k]; if (forage !== self) { // Self is already up-to-date. forage._dbInfo.db = dbInfo.db; forage._dbInfo.version = dbInfo.version; } } }); } function getItem(key, callback) { var self = this; key = normalizeKey(key); var promise = new Promise$1(function (resolve, reject) { self.ready().then(function () { createTransaction(self._dbInfo, READ_ONLY, function (err, transaction) { if (err) { return reject(err); } try { var store = transaction.objectStore(self._dbInfo.storeName); var req = store.get(key); req.onsuccess = function () { var value = req.result; if (value === undefined) { value = null; } if (_isEncodedBlob(value)) { value = _decodeBlob(value); } resolve(value); }; req.onerror = function () { reject(req.error); }; } catch (e) { reject(e); } }); })["catch"](reject); }); executeCallback(promise, callback); return promise; } // Iterate over all items stored in database. function iterate(iterator, callback) { var self = this; var promise = new Promise$1(function (resolve, reject) { self.ready().then(function () { createTransaction(self._dbInfo, READ_ONLY, function (err, transaction) { if (err) { return reject(err); } try { var store = transaction.objectStore(self._dbInfo.storeName); var req = store.openCursor(); var iterationNumber = 1; req.onsuccess = function () { var cursor = req.result; if (cursor) { var value = cursor.value; if (_isEncodedBlob(value)) { value = _decodeBlob(value); } var result = iterator(value, cursor.key, iterationNumber++); // when the iterator callback returns any // (non-`undefined`) value, then we stop // the iteration immediately if (result !== void 0) { resolve(result); } else { cursor["continue"](); } } else { resolve(); } }; req.onerror = function () { reject(req.error); }; } catch (e) { reject(e); } }); })["catch"](reject); }); executeCallback(promise, callback); return promise; } function setItem(key, value, callback) { var self = this; key = normalizeKey(key); var promise = new Promise$1(function (resolve, reject) { var dbInfo; self.ready().then(function () { dbInfo = self._dbInfo; if (toString.call(value) === '[object Blob]') { return _checkBlobSupport(dbInfo.db).then(function (blobSupport) { if (blobSupport) { return value; } return _encodeBlob(value); }); } return value; }).then(function (value) { createTransaction(self._dbInfo, READ_WRITE, function (err, transaction) { if (err) { return reject(err); } try { var store = transaction.objectStore(self._dbInfo.storeName); // The reason we don't _save_ null is because IE 10 does // not support saving the `null` type in IndexedDB. How // ironic, given the bug below! // See: https://github.com/mozilla/localForage/issues/161 if (value === null) { value = undefined; } var req = store.put(value, key); transaction.oncomplete = function () { // Cast to undefined so the value passed to // callback/promise is the same as what one would get out // of `getItem()` later. This leads to some weirdness // (setItem('foo', undefined) will return `null`), but // it's not my fault localStorage is our baseline and that // it's weird. if (value === undefined) { value = null; } resolve(value); }; transaction.onabort = transaction.onerror = function () { var err = req.error ? req.error : req.transaction.error; reject(err); }; } catch (e) { reject(e); } }); })["catch"](reject); }); executeCallback(promise, callback); return promise; } function removeItem(key, callback) { var self = this; key = normalizeKey(key); var promise = new Promise$1(function (resolve, reject) { self.ready().then(function () { createTransaction(self._dbInfo, READ_WRITE, function (err, transaction) { if (err) { return reject(err); } try { var store = transaction.objectStore(self._dbInfo.storeName); // We use a Grunt task to make this safe for IE and some // versions of Android (including those used by Cordova). // Normally IE won't like `.delete()` and will insist on // using `['delete']()`, but we have a build step that // fixes this for us now. var req = store["delete"](key); transaction.oncomplete = function () { resolve(); }; transaction.onerror = function () { reject(req.error); }; // The request will be also be aborted if we've exceeded our storage // space. transaction.onabort = function () { var err = req.error ? req.error : req.transaction.error; reject(err); }; } catch (e) { reject(e); } }); })["catch"](reject); }); executeCallback(promise, callback); return promise; } function clear(callback) { var self = this; var promise = new Promise$1(function (resolve, reject) { self.ready().then(function () { createTransaction(self._dbInfo, READ_WRITE, function (err, transaction) { if (err) { return reject(err); } try { var store = transaction.objectStore(self._dbInfo.storeName); var req = store.clear(); transaction.oncomplete = function () { resolve(); }; transaction.onabort = transaction.onerror = function () { var err = req.error ? req.error : req.transaction.error; reject(err); }; } catch (e) { reject(e); } }); })["catch"](reject); }); executeCallback(promise, callback); return promise; } function length(callback) { var self = this; var promise = new Promise$1(function (resolve, reject) { self.ready().then(function () { createTransaction(self._dbInfo, READ_ONLY, function (err, transaction) { if (err) { return reject(err); } try { var store = transaction.objectStore(self._dbInfo.storeName); var req = store.count(); req.onsuccess = function () { resolve(req.result); }; req.onerror = function () { reject(req.error); }; } catch (e) { reject(e); } }); })["catch"](reject); }); executeCallback(promise, callback); return promise; } function key(n, callback) { var self = this; var promise = new Promise$1(function (resolve, reject) { if (n < 0) { resolve(null); return; } self.ready().then(function () { createTransaction(self._dbInfo, READ_ONLY, function (err, transaction) { if (err) { return reject(err); } try { var store = transaction.objectStore(self._dbInfo.storeName); var advanced = false; var req = store.openKeyCursor(); req.onsuccess = function () { var cursor = req.result; if (!cursor) { // this means there weren't enough keys resolve(null); return; } if (n === 0) { // We have the first key, return it if that's what they // wanted. resolve(cursor.key); } else { if (!advanced) { // Otherwise, ask the cursor to skip ahead n // records. advanced = true; cursor.advance(n); } else { // When we get here, we've got the nth key. resolve(cursor.key); } } }; req.onerror = function () { reject(req.error); }; } catch (e) { reject(e); } }); })["catch"](reject); }); executeCallback(promise, callback); return promise; } function keys(callback) { var self = this; var promise = new Promise$1(function (resolve, reject) { self.ready().then(function () { createTransaction(self._dbInfo, READ_ONLY, function (err, transaction) { if (err) { return reject(err); } try { var store = transaction.objectStore(self._dbInfo.storeName); var req = store.openKeyCursor(); var keys = []; req.onsuccess = function () { var cursor = req.result; if (!cursor) { resolve(keys); return; } keys.push(cursor.key); cursor["continue"](); }; req.onerror = function () { reject(req.error); }; } catch (e) { reject(e); } }); })["catch"](reject); }); executeCallback(promise, callback); return promise; } function dropInstance(options, callback) { callback = getCallback.apply(this, arguments); var currentConfig = this.config(); options = typeof options !== 'function' && options || {}; if (!options.name) { options.name = options.name || currentConfig.name; options.storeName = options.storeName || currentConfig.storeName; } var self = this; var promise; if (!options.name) { promise = Promise$1.reject('Invalid arguments'); } else { var isCurrentDb = options.name === currentConfig.name && self._dbInfo.db; var dbPromise = isCurrentDb ? Promise$1.resolve(self._dbInfo.db) : _getOriginalConnection(options).then(function (db) { var dbContext = dbContexts[options.name]; var forages = dbContext.forages; dbContext.db = db; for (var i = 0; i < forages.length; i++) { forages[i]._dbInfo.db = db; } return db; }); if (!options.storeName) { promise = dbPromise.then(function (db) { _deferReadiness(options); var dbContext = dbContexts[options.name]; var forages = dbContext.forages; db.close(); for (var i = 0; i < forages.length; i++) { var forage = forages[i]; forage._dbInfo.db = null; } var dropDBPromise = new Promise$1(function (resolve, reject) { var req = idb.deleteDatabase(options.name); req.onerror = function () { var db = req.result; if (db) { db.close(); } reject(req.error); }; req.onblocked = function () { // Closing all open connections in onversionchange handler should prevent this situation, but if // we do get here, it just means the request remains pending - eventually it will succeed or error console.warn('dropInstance blocked for database "' + options.name + '" until all open connections are closed'); }; req.onsuccess = function () { var db = req.result; if (db) { db.close(); } resolve(db); }; }); return dropDBPromise.then(function (db) { dbContext.db = db; for (var i = 0; i < forages.length; i++) { var _forage = forages[i]; _advanceReadiness(_forage._dbInfo); } })["catch"](function (err) { (_rejectReadiness(options, err) || Promise$1.resolve())["catch"](function () {}); throw err; }); }); } else { promise = dbPromise.then(function (db) { if (!db.objectStoreNames.contains(options.storeName)) { return; } var newVersion = db.version + 1; _deferReadiness(options); var dbContext = dbContexts[options.name]; var forages = dbContext.forages; db.close(); for (var i = 0; i < forages.length; i++) { var forage = forages[i]; forage._dbInfo.db = null; forage._dbInfo.version = newVersion; } var dropObjectPromise = new Promise$1(function (resolve, reject) { var req = idb.open(options.name, newVersion); req.onerror = function (err) { var db = req.result; db.close(); reject(err); }; req.onupgradeneeded = function () { var db = req.result; db.deleteObjectStore(options.storeName); }; req.onsuccess = function () { var db = req.result; db.close(); resolve(db); }; }); return dropObjectPromise.then(function (db) { dbContext.db = db; for (var j = 0; j < forages.length; j++) { var _forage2 = forages[j]; _forage2._dbInfo.db = db; _advanceReadiness(_forage2._dbInfo); } })["catch"](function (err) { (_rejectReadiness(options, err) || Promise$1.resolve())["catch"](function () {}); throw err; }); }); } } executeCallback(promise, callback); return promise; } var asyncStorage = { _driver: 'asyncStorage', _initStorage: _initStorage, _support: isIndexedDBValid(), iterate: iterate, getItem: getItem, setItem: setItem, removeItem: removeItem, clear: clear, length: length, key: key, keys: keys, dropInstance: dropInstance }; function isWebSQLValid() { return typeof openDatabase === 'function'; } // Sadly, the best way to save binary data in WebSQL/localStorage is serializing // it to Base64, so this is how we store it to prevent very strange errors with less // verbose ways of binary <-> string data storage. var BASE_CHARS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; var BLOB_TYPE_PREFIX = '~~local_forage_type~'; var BLOB_TYPE_PREFIX_REGEX = /^~~local_forage_type~([^~]+)~/; var SERIALIZED_MARKER = '__lfsc__:'; var SERIALIZED_MARKER_LENGTH = SERIALIZED_MARKER.length; // OMG the serializations! var TYPE_ARRAYBUFFER = 'arbf'; var TYPE_BLOB = 'blob'; var TYPE_INT8ARRAY = 'si08'; var TYPE_UINT8ARRAY = 'ui08'; var TYPE_UINT8CLAMPEDARRAY = 'uic8'; var TYPE_INT16ARRAY = 'si16'; var TYPE_INT32ARRAY = 'si32'; var TYPE_UINT16ARRAY = 'ur16'; var TYPE_UINT32ARRAY = 'ui32'; var TYPE_FLOAT32ARRAY = 'fl32'; var TYPE_FLOAT64ARRAY = 'fl64'; var TYPE_SERIALIZED_MARKER_LENGTH = SERIALIZED_MARKER_LENGTH + TYPE_ARRAYBUFFER.length; var toString$1 = Object.prototype.toString; function stringToBuffer(serializedString) { // Fill the string into a ArrayBuffer. var bufferLength = serializedString.length * 0.75; var len = serializedString.length; var i; var p = 0; var encoded1, encoded2, encoded3, encoded4; if (serializedString[serializedString.length - 1] === '=') { bufferLength--; if (serializedString[serializedString.length - 2] === '=') { bufferLength--; } } var buffer = new ArrayBuffer(bufferLength); var bytes = new Uint8Array(buffer); for (i = 0; i < len; i += 4) { encoded1 = BASE_CHARS.indexOf(serializedString[i]); encoded2 = BASE_CHARS.indexOf(serializedString[i + 1]); encoded3 = BASE_CHARS.indexOf(serializedString[i + 2]); encoded4 = BASE_CHARS.indexOf(serializedString[i + 3]); /*jslint bitwise: true */ bytes[p++] = encoded1 << 2 | encoded2 >> 4; bytes[p++] = (encoded2 & 15) << 4 | encoded3 >> 2; bytes[p++] = (encoded3 & 3) << 6 | encoded4 & 63; } return buffer; } // Converts a buffer to a string to store, serialized, in the backend // storage library. function bufferToString(buffer) { // base64-arraybuffer var bytes = new Uint8Array(buffer); var base64String = ''; var i; for (i = 0; i < bytes.length; i += 3) { /*jslint bitwise: true */ base64String += BASE_CHARS[bytes[i] >> 2]; base64String += BASE_CHARS[(bytes[i] & 3) << 4 | bytes[i + 1] >> 4]; base64String += BASE_CHARS[(bytes[i + 1] & 15) << 2 | bytes[i + 2] >> 6]; base64String += BASE_CHARS[bytes[i + 2] & 63]; } if (bytes.length % 3 === 2) { base64String = base64String.substring(0, base64String.length - 1) + '='; } else if (bytes.length % 3 === 1) { base64String = base64String.substring(0, base64String.length - 2) + '=='; } return base64String; } // Serialize a value, afterwards executing a callback (which usually // instructs the `setItem()` callback/promise to be executed). This is how // we store binary data with localStorage. function serialize(value, callback) { var valueType = ''; if (value) { valueType = toString$1.call(value); } // Cannot use `value instanceof ArrayBuffer` or such here, as these // checks fail when running the tests using casper.js... // // TODO: See why those tests fail and use a better solution. if (value && (valueType === '[object ArrayBuffer]' || value.buffer && toString$1.call(value.buffer) === '[object ArrayBuffer]')) { // Convert binary arrays to a string and prefix the string with // a special marker. var buffer; var marker = SERIALIZED_MARKER; if (value instanceof ArrayBuffer) { buffer = value; marker += TYPE_ARRAYBUFFER; } else { buffer = value.buffer; if (valueType === '[object Int8Array]') { marker += TYPE_INT8ARRAY; } else if (valueType === '[object Uint8Array]') { marker += TYPE_UINT8ARRAY; } else if (valueType === '[object Uint8ClampedArray]') { marker += TYPE_UINT8CLAMPEDARRAY; } else if (valueType === '[object Int16Array]') { marker += TYPE_INT16ARRAY; } else if (valueType === '[object Uint16Array]') { marker += TYPE_UINT16ARRAY; } else if (valueType === '[object Int32Array]') { marker += TYPE_INT32ARRAY; } else if (valueType === '[object Uint32Array]') { marker += TYPE_UINT32ARRAY; } else if (valueType === '[object Float32Array]') { marker += TYPE_FLOAT32ARRAY; } else if (valueType === '[object Float64Array]') { marker += TYPE_FLOAT64ARRAY; } else { callback(new Error('Failed to get type for BinaryArray')); } } callback(marker + bufferToString(buffer)); } else if (valueType === '[object Blob]') { // Conver the blob to a binaryArray and then to a string. var fileReader = new FileReader(); fileReader.onload = function () { // Backwards-compatible prefix for the blob type. var str = BLOB_TYPE_PREFIX + value.type + '~' + bufferToString(this.result); callback(SERIALIZED_MARKER + TYPE_BLOB + str); }; fileReader.readAsArrayBuffer(value); } else { try { callback(JSON.stringify(value)); } catch (e) { console.error("Couldn't convert value into a JSON string: ", value); callback(null, e); } } } // Deserialize data we've inserted into a value column/field. We place // special markers into our strings to mark them as encoded; this isn't // as nice as a meta field, but it's the only sane thing we can do whilst // keeping localStorage support intact. // // Oftentimes this will just deserialize JSON content, but if we have a // special marker (SERIALIZED_MARKER, defined above), we will extract // some kind of arraybuffer/binary data/typed array out of the string. function deserialize(value) { // If we haven't marked this string as being specially serialized (i.e. // something other than serialized JSON), we can just return it and be // done with it. if (value.substring(0, SERIALIZED_MARKER_LENGTH) !== SERIALIZED_MARKER) { return JSON.parse(value); } // The following code deals with deserializing some kind of Blob or // TypedArray. First we separate out the type of data we're dealing // with from the data itself. var serializedString = value.substring(TYPE_SERIALIZED_MARKER_LENGTH); var type = value.substring(SERIALIZED_MARKER_LENGTH, TYPE_SERIALIZED_MARKER_LENGTH); var blobType; // Backwards-compatible blob type serialization strategy. // DBs created with older versions of localForage will simply not have the blob type. if (type === TYPE_BLOB && BLOB_TYPE_PREFIX_REGEX.test(serializedString)) { var matcher = serializedString.match(BLOB_TYPE_PREFIX_REGEX); blobType = matcher[1]; serializedString = serializedString.substring(matcher[0].length); } var buffer = stringToBuffer(serializedString); // Return the right type based on the code/type set during // serialization. switch (type) { case TYPE_ARRAYBUFFER: return buffer; case TYPE_BLOB: return createBlob([buffer], { type: blobType }); case TYPE_INT8ARRAY: return new Int8Array(buffer); case TYPE_UINT8ARRAY: return new Uint8Array(buffer); case TYPE_UINT8CLAMPEDARRAY: return new Uint8ClampedArray(buffer); case TYPE_INT16ARRAY: return new Int16Array(buffer); case TYPE_UINT16ARRAY: return new Uint16Array(buffer); case TYPE_INT32ARRAY: return new Int32Array(buffer); case TYPE_UINT32ARRAY: return new Uint32Array(buffer); case TYPE_FLOAT32ARRAY: return new Float32Array(buffer); case TYPE_FLOAT64ARRAY: return new Float64Array(buffer); default: throw new Error('Unkown type: ' + type); } } var localforageSerializer = { serialize: serialize, deserialize: deserialize, stringToBuffer: stringToBuffer, bufferToString: bufferToString }; /* * Includes code from: * * base64-arraybuffer * https://github.com/niklasvh/base64-arraybuffer * * Copyright (c) 2012 Niklas von Hertzen * Licensed under the MIT license. */ function createDbTable(t, dbInfo, callback, errorCallback) { t.executeSql('CREATE TABLE IF NOT EXISTS ' + dbInfo.storeName + ' ' + '(id INTEGER PRIMARY KEY, key unique, value)', [], callback, errorCallback); } // Open the WebSQL database (automatically creates one if one didn't // previously exist), using any options set in the config. function _initStorage$1(options) { var self = this; var dbInfo = { db: null }; if (options) { for (var i in options) { dbInfo[i] = typeof options[i] !== 'string' ? options[i].toString() : options[i]; } } var dbInfoPromise = new Promise$1(function (resolve, reject) { // Open the database; the openDatabase API will automatically // create it for us if it doesn't exist. try { dbInfo.db = openDatabase(dbInfo.name, String(dbInfo.version), dbInfo.description, dbInfo.size); } catch (e) { return reject(e); } // Create our key/value table if it doesn't exist. dbInfo.db.transaction(function (t) { createDbTable(t, dbInfo, function () { self._dbInfo = dbInfo; resolve(); }, function (t, error) { reject(error); }); }, reject); }); dbInfo.serializer = localforageSerializer; return dbInfoPromise; } function tryExecuteSql(t, dbInfo, sqlStatement, args, callback, errorCallback) { t.executeSql(sqlStatement, args, callback, function (t, error) { if (error.code === error.SYNTAX_ERR) { t.executeSql('SELECT name FROM sqlite_master ' + "WHERE type='table' AND name = ?", [dbInfo.storeName], function (t, results) { if (!results.rows.length) { // if the table is missing (was deleted) // re-create it table and retry createDbTable(t, dbInfo, function () { t.executeSql(sqlStatement, args, callback, errorCallback); }, errorCallback); } else { errorCallback(t, error); } }, errorCallback); } else { errorCallback(t, error); } }, errorCallback); } function getItem$1(key, callback) { var self = this; key = normalizeKey(key); var promise = new Promise$1(function (resolve, reject) { self.ready().then(function () { var dbInfo = self._dbInfo; dbInfo.db.transaction(function (t) { tryExecuteSql(t, dbInfo, 'SELECT * FROM ' + dbInfo.storeName + ' WHERE key = ? LIMIT 1', [key], function (t, results) { var result = results.rows.length ? results.rows.item(0).value : null; // Check to see if this is serialized content we need to // unpack. if (result) { result = dbInfo.serializer.deserialize(result); } resolve(result); }, function (t, error) { reject(error); }); }); })["catch"](reject); }); executeCallback(promise, callback); return promise; } function iterate$1(iterator, callback) { var self = this; var promise = new Promise$1(function (resolve, reject) { self.ready().then(function () { var dbInfo = self._dbInfo; dbInfo.db.transaction(function (t) { tryExecuteSql(t, dbInfo, 'SELECT * FROM ' + dbInfo.storeName, [], function (t, results) { var rows = results.rows; var length = rows.length; for (var i = 0; i < length; i++) { var item = rows.item(i); var result = item.value; // Check to see if this is serialized content // we need to unpack. if (result) { result = dbInfo.serializer.deserialize(result); } result = iterator(result, item.key, i + 1); // void(0) prevents problems with redefinition // of `undefined`. if (result !== void 0) { resolve(result); return; } } resolve(); }, function (t, error) { reject(error); }); }); })["catch"](reject); }); executeCallback(promise, callback); return promise; } function _setItem(key, value, callback, retriesLeft) { var self = this; key = normalizeKey(key); var promise = new Promise$1(function (resolve, reject) { self.ready().then(function () { // The localStorage API doesn't return undefined values in an // "expected" way, so undefined is always cast to null in all // drivers. See: https://github.com/mozilla/localForage/pull/42 if (value === undefined) { value = null; } // Save the original value to pass to the callback. var originalValue = value; var dbInfo = self._dbInfo; dbInfo.serializer.serialize(value, function (value, error) { if (error) { reject(error); } else { dbInfo.db.transaction(function (t) { tryExecuteSql(t, dbInfo, 'INSERT OR REPLACE INTO ' + dbInfo.storeName + ' ' + '(key, value) VALUES (?, ?)', [key, value], function () { resolve(originalValue); }, function (t, error) { reject(error); }); }, function (sqlError) { // The transaction failed; check // to see if it's a quota error. if (sqlError.code === sqlError.QUOTA_ERR) { // We reject the callback outright for now, but // it's worth trying to re-run the transaction. // Even if the user accepts the prompt to use // more storage on Safari, this error will // be called. // // Try to re-run the transaction. if (retriesLeft > 0) { resolve(_setItem.apply(self, [key, originalValue, callback, retriesLeft - 1])); return; } reject(sqlError); } }); } }); })["catch"](reject); }); executeCallback(promise, callback); return promise; } function setItem$1(key, value, callback) { return _setItem.apply(this, [key, value, callback, 1]); } function removeItem$1(key, callback) { var self = this; key = normalizeKey(key); var promise = new Promise$1(function (resolve, reject) { self.ready().then(function () { var dbInfo = self._dbInfo; dbInfo.db.transaction(function (t) { tryExecuteSql(t, dbInfo, 'DELETE FROM ' + dbInfo.storeName + ' WHERE key = ?', [key], function () { resolve(); }, function (t, error) { reject(error); }); }); })["catch"](reject); }); executeCallback(promise, callback); return promise; } // Deletes every item in the table. // TODO: Find out if this resets the AUTO_INCREMENT number. function clear$1(callback) { var self = this; var promise = new Promise$1(function (resolve, reject) { self.ready().then(function () { var dbInfo = self._dbInfo; dbInfo.db.transaction(function (t) { tryExecuteSql(t, dbInfo, 'DELETE FROM ' + dbInfo.storeName, [], function () { resolve(); }, function (t, error) { reject(error); }); }); })["catch"](reject); }); executeCallback(promise, callback); return promise; } // Does a simple `COUNT(key)` to get the number of items stored in // localForage. function length$1(callback) { var self = this; var promise = new Promise$1(function (resolve, reject) { self.ready().then(function () { var dbInfo = self._dbInfo; dbInfo.db.transaction(function (t) { // Ahhh, SQL makes this one soooooo easy. tryExecuteSql(t, dbInfo, 'SELECT COUNT(key) as c FROM ' + dbInfo.storeName, [], function (t, results) { var result = results.rows.item(0).c; resolve(result); }, function (t, error) { reject(error); }); }); })["catch"](reject); }); executeCallback(promise, callback); return promise; } // Return the key located at key index X; essentially gets the key from a // `WHERE id = ?`. This is the most efficient way I can think to implement // this rarely-used (in my experience) part of the API, but it can seem // inconsistent, because we do `INSERT OR REPLACE INTO` on `setItem()`, so // the ID of each key will change every time it's updated. Perhaps a stored // procedure for the `setItem()` SQL would solve this problem? // TODO: Don't change ID on `setItem()`. function key$1(n, callback) { var self = this; var promise = new Promise$1(function (resolve, reject) { self.ready().then(function () { var dbInfo = self._dbInfo; dbInfo.db.transaction(function (t) { tryExecuteSql(t, dbInfo, 'SELECT key FROM ' + dbInfo.storeName + ' WHERE id = ? LIMIT 1', [n + 1], function (t, results) { var result = results.rows.length ? results.rows.item(0).key : null; resolve(result); }, function (t, error) { reject(error); }); }); })["catch"](reject); }); executeCallback(promise, callback); return promise; } function keys$1(callback) { var self = this; var promise = new Promise$1(function (resolve, reject) { self.ready().then(function () { var dbInfo = self._dbInfo; dbInfo.db.transaction(function (t) { tryExecuteSql(t, dbInfo, 'SELECT key FROM ' + dbInfo.storeName, [], function (t, results) { var keys = []; for (var i = 0; i < results.rows.length; i++) { keys.push(results.rows.item(i).key); } resolve(keys); }, function (t, error) { reject(error); }); }); })["catch"](reject); }); executeCallback(promise, callback); return promise; } // https://www.w3.org/TR/webdatabase/#databases // > There is no way to enumerate or delete the databases available for an origin from this API. function getAllStoreNames(db) { return new Promise$1(function (resolve, reject) { db.transaction(function (t) { t.executeSql('SELECT name FROM sqlite_master ' + "WHERE type='table' AND name <> '__WebKitDatabaseInfoTable__'", [], function (t, results) { var storeNames = []; for (var i = 0; i < results.rows.length; i++) { storeNames.push(results.rows.item(i).name); } resolve({ db: db, storeNames: storeNames }); }, function (t, error) { reject(error); }); }, function (sqlError) { reject(sqlError); }); }); } function dropInstance$1(options, callback) { callback = getCallback.apply(this, arguments); var currentConfig = this.config(); options = typeof options !== 'function' && options || {}; if (!options.name) { options.name = options.name || currentConfig.name; options.storeName = options.storeName || currentConfig.storeName; } var self = this; var promise; if (!options.name) { promise = Promise$1.reject('Invalid arguments'); } else { promise = new Promise$1(function (resolve) { var db; if (options.name === currentConfig.name) { // use the db reference of the current instance db = self._dbInfo.db; } else { db = openDatabase(options.name, '', '', 0); } if (!options.storeName) { // drop all database tables resolve(getAllStoreNames(db)); } else { resolve({ db: db, storeNames: [options.storeName] }); } }).then(function (operationInfo) { return new Promise$1(function (resolve, reject) { operationInfo.db.transaction(function (t) { function dropTable(storeName) { return new Promise$1(function (resolve, reject) { t.executeSql('DROP TABLE IF EXISTS ' + storeName, [], function () { resolve(); }, function (t, error) { reject(error); }); }); } var operations = []; for (var i = 0, len = operationInfo.storeNames.length; i < len; i++) { operations.push(dropTable(operationInfo.storeNames[i])); } Promise$1.all(operations).then(function () { resolve(); })["catch"](function (e) { reject(e); }); }, function (sqlError) { reject(sqlError); }); }); }); } executeCallback(promise, callback); return promise; } var webSQLStorage = { _driver: 'webSQLStorage', _initStorage: _initStorage$1, _support: isWebSQLValid(), iterate: iterate$1, getItem: getItem$1, setItem: setItem$1, removeItem: removeItem$1, clear: clear$1, length: length$1, key: key$1, keys: keys$1, dropInstance: dropInstance$1 }; function isLocalStorageValid() { try { return typeof localStorage !== 'undefined' && 'setItem' in localStorage && // in IE8 typeof localStorage.setItem === 'object' !!localStorage.setItem; } catch (e) { return false; } } function _getKeyPrefix(options, defaultConfig) { var keyPrefix = options.name + '/'; if (options.storeName !== defaultConfig.storeName) { keyPrefix += options.storeName + '/'; } return keyPrefix; } // Check if localStorage throws when saving an item function checkIfLocalStorageThrows() { var localStorageTestKey = '_localforage_support_test'; try { localStorage.setItem(localStorageTestKey, true); localStorage.removeItem(localStorageTestKey); return false; } catch (e) { return true; } } // Check if localStorage is usable and allows to save an item // This method checks if localStorage is usable in Safari Private Browsing // mode, or in any other case where the available quota for localStorage // is 0 and there wasn't any saved items yet. function _isLocalStorageUsable() { return !checkIfLocalStorageThrows() || localStorage.length > 0; } // Config the localStorage backend, using options set in the config. function _initStorage$2(options) { var self = this; var dbInfo = {}; if (options) { for (var i in options) { dbInfo[i] = options[i]; } } dbInfo.keyPrefix = _getKeyPrefix(options, self._defaultConfig); if (!_isLocalStorageUsable()) { return Promise$1.reject(); } self._dbInfo = dbInfo; dbInfo.serializer = localforageSerializer; return Promise$1.resolve(); } // Remove all keys from the datastore, effectively destroying all data in // the app's key/value store! function clear$2(callback) { var self = this; var promise = self.ready().then(function () { var keyPrefix = self._dbInfo.keyPrefix; for (var i = localStorage.length - 1; i >= 0; i--) { var key = localStorage.key(i); if (key.indexOf(keyPrefix) === 0) { localStorage.removeItem(key); } } }); executeCallback(promise, callback); return promise; } // Retrieve an item from the store. Unlike the original async_storage // library in Gaia, we don't modify return values at all. If a key's value // is `undefined`, we pass that value to the callback function. function getItem$2(key, callback) { var self = this; key = normalizeKey(key); var promise = self.ready().then(function () { var dbInfo = self._dbInfo; var result = localStorage.getItem(dbInfo.keyPrefix + key); // If a result was found, parse it from the serialized // string into a JS object. If result isn't truthy, the key // is likely undefined and we'll pass it straight to the // callback. if (result) { result = dbInfo.serializer.deserialize(result); } return result; }); executeCallback(promise, callback); return promise; } // Iterate over all items in the store. function iterate$2(iterator, callback) { var self = this; var promise = self.ready().then(function () { var dbInfo = self._dbInfo; var keyPrefix = dbInfo.keyPrefix; var keyPrefixLength = keyPrefix.length; var length = localStorage.length; // We use a dedicated iterator instead of the `i` variable below // so other keys we fetch in localStorage aren't counted in // the `iterationNumber` argument passed to the `iterate()` // callback. // // See: github.com/mozilla/localForage/pull/435#discussion_r38061530 var iterationNumber = 1; for (var i = 0; i < length; i++) { var key = localStorage.key(i); if (key.indexOf(keyPrefix) !== 0) { continue; } var value = localStorage.getItem(key); // If a result was found, parse it from the serialized // string into a JS object. If result isn't truthy, the // key is likely undefined and we'll pass it straight // to the iterator. if (value) { value = dbInfo.serializer.deserialize(value); } value = iterator(value, key.substring(keyPrefixLength), iterationNumber++); if (value !== void 0) { return value; } } }); executeCallback(promise, callback); return promise; } // Same as localStorage's key() method, except takes a callback. function key$2(n, callback) { var self = this; var promise = self.ready().then(function () { var dbInfo = self._dbInfo; var result; try { result = localStorage.key(n); } catch (error) { result = null; } // Remove the prefix from the key, if a key is found. if (result) { result = result.substring(dbInfo.keyPrefix.length); } return result; }); executeCallback(promise, callback); return promise; } function keys$2(callback) { var self = this; var promise = self.ready().then(function () { var dbInfo = self._dbInfo; var length = localStorage.length; var keys = []; for (var i = 0; i < length; i++) { var itemKey = localStorage.key(i); if (itemKey.indexOf(dbInfo.keyPrefix) === 0) { keys.push(itemKey.substring(dbInfo.keyPrefix.length)); } } return keys; }); executeCallback(promise, callback); return promise; } // Supply the number of keys in the datastore to the callback function. function length$2(callback) { var self = this; var promise = self.keys().then(function (keys) { return keys.length; }); executeCallback(promise, callback); return promise; } // Remove an item from the store, nice and simple. function removeItem$2(key, callback) { var self = this; key = normalizeKey(key); var promise = self.ready().then(function () { var dbInfo = self._dbInfo; localStorage.removeItem(dbInfo.keyPrefix + key); }); executeCallback(promise, callback); return promise; } // Set a key's value and run an optional callback once the value is set. // Unlike Gaia's implementation, the callback function is passed the value, // in case you want to operate on that value only after you're sure it // saved, or something like that. function setItem$2(key, value, callback) { var self = this; key = normalizeKey(key); var promise = self.ready().then(function () { // Convert undefined values to null. // https://github.com/mozilla/localForage/pull/42 if (value === undefined) { value = null; } // Save the original value to pass to the callback. var originalValue = value; return new Promise$1(function (resolve, reject) { var dbInfo = self._dbInfo; dbInfo.serializer.serialize(value, function (value, error) { if (error) { reject(error); } else { try { localStorage.setItem(dbInfo.keyPrefix + key, value); resolve(originalValue); } catch (e) { // localStorage capacity exceeded. // TODO: Make this a specific error/event. if (e.name === 'QuotaExceededError' || e.name === 'NS_ERROR_DOM_QUOTA_REACHED') { reject(e); } reject(e); } } }); }); }); executeCallback(promise, callback); return promise; } function dropInstance$2(options, callback) { callback = getCallback.apply(this, arguments); options = typeof options !== 'function' && options || {}; if (!options.name) { var currentConfig = this.config(); options.name = options.name || currentConfig.name; options.storeName = options.storeName || currentConfig.storeName; } var self = this; var promise; if (!options.name) { promise = Promise$1.reject('Invalid arguments'); } else { promise = new Promise$1(function (resolve) { if (!options.storeName) { resolve(options.name + '/'); } else { resolve(_getKeyPrefix(options, self._defaultConfig)); } }).then(function (keyPrefix) { for (var i = localStorage.length - 1; i >= 0; i--) { var key = localStorage.key(i); if (key.indexOf(keyPrefix) === 0) { localStorage.removeItem(key); } } }); } executeCallback(promise, callback); return promise; } var localStorageWrapper = { _driver: 'localStorageWrapper', _initStorage: _initStorage$2, _support: isLocalStorageValid(), iterate: iterate$2, getItem: getItem$2, setItem: setItem$2, removeItem: removeItem$2, clear: clear$2, length: length$2, key: key$2, keys: keys$2, dropInstance: dropInstance$2 }; var sameValue = function sameValue(x, y) { return x === y || typeof x === 'number' && typeof y === 'number' && isNaN(x) && isNaN(y); }; var includes = function includes(array, searchElement) { var len = array.length; var i = 0; while (i < len) { if (sameValue(array[i], searchElement)) { return true; } i++; } return false; }; var isArray = Array.isArray || function (arg) { return Object.prototype.toString.call(arg) === '[object Array]'; }; // Drivers are stored here when `defineDriver()` is called. // They are shared across all instances of localForage. var DefinedDrivers = {}; var DriverSupport = {}; var DefaultDrivers = { INDEXEDDB: asyncStorage, WEBSQL: webSQLStorage, LOCALSTORAGE: localStorageWrapper }; var DefaultDriverOrder = [DefaultDrivers.INDEXEDDB._driver, DefaultDrivers.WEBSQL._driver, DefaultDrivers.LOCALSTORAGE._driver]; var OptionalDriverMethods = ['dropInstance']; var LibraryMethods = ['clear', 'getItem', 'iterate', 'key', 'keys', 'length', 'removeItem', 'setItem'].concat(OptionalDriverMethods); var DefaultConfig = { description: '', driver: DefaultDriverOrder.slice(), name: 'localforage', // Default DB size is _JUST UNDER_ 5MB, as it's the highest size // we can use without a prompt. size: 4980736, storeName: 'keyvaluepairs', version: 1.0 }; function callWhenReady(localForageInstance, libraryMethod) { localForageInstance[libraryMethod] = function () { var _args = arguments; return localForageInstance.ready().then(function () { return localForageInstance[libraryMethod].apply(localForageInstance, _args); }); }; } function extend() { for (var i = 1; i < arguments.length; i++) { var arg = arguments[i]; if (arg) { for (var _key in arg) { if (arg.hasOwnProperty(_key)) { if (isArray(arg[_key])) { arguments[0][_key] = arg[_key].slice(); } else { arguments[0][_key] = arg[_key]; } } } } } return arguments[0]; } var LocalForage = function () { function LocalForage(options) { _classCallCheck(this, LocalForage); for (var driverTypeKey in DefaultDrivers) { if (DefaultDrivers.hasOwnProperty(driverTypeKey)) { var driver = DefaultDrivers[driverTypeKey]; var driverName = driver._driver; this[driverTypeKey] = driverName; if (!DefinedDrivers[driverName]) { // we don't need to wait for the promise, // since the default drivers can be defined // in a blocking manner this.defineDriver(driver); } } } this._defaultConfig = extend({}, DefaultConfig); this._config = extend({}, this._defaultConfig, options); this._driverSet = null; this._initDriver = null; this._ready = false; this._dbInfo = null; this._wrapLibraryMethodsWithReady(); this.setDriver(this._config.driver)["catch"](function () {}); } // Set any config values for localForage; can be called anytime before // the first API call (e.g. `getItem`, `setItem`). // We loop through options so we don't overwrite existing config // values. LocalForage.prototype.config = function config(options) { // If the options argument is an object, we use it to set values. // Otherwise, we return either a specified config value or all // config values. if ((typeof options === 'undefined' ? 'undefined' : _typeof(options)) === 'object') { // If localforage is ready and fully initialized, we can't set // any new configuration values. Instead, we return an error. if (this._ready) { return new Error("Can't call config() after localforage " + 'has been used.'); } for (var i in options) { if (i === 'storeName') { options[i] = options[i].replace(/\W/g, '_'); } if (i === 'version' && typeof options[i] !== 'number') { return new Error('Database version must be a number.'); } this._config[i] = options[i]; } // after all config options are set and // the driver option is used, try setting it if ('driver' in options && options.driver) { return this.setDriver(this._config.driver); } return true; } else if (typeof options === 'string') { return this._config[options]; } else { return this._config; } }; // Used to define a custom driver, shared across all instances of // localForage. LocalForage.prototype.defineDriver = function defineDriver(driverObject, callback, errorCallback) { var promise = new Promise$1(function (resolve, reject) { try { var driverName = driverObject._driver; var complianceError = new Error('Custom driver not compliant; see ' + 'https://mozilla.github.io/localForage/#definedriver'); // A driver name should be defined and not overlap with the // library-defined, default drivers. if (!driverObject._driver) { reject(complianceError); return; } var driverMethods = LibraryMethods.concat('_initStorage'); for (var i = 0, len = driverMethods.length; i < len; i++) { var driverMethodName = driverMethods[i]; // when the property is there, // it should be a method even when optional var isRequired = !includes(OptionalDriverMethods, driverMethodName); if ((isRequired || driverObject[driverMethodName]) && typeof driverObject[driverMethodName] !== 'function') { reject(complianceError); return; } } var configureMissingMethods = function configureMissingMethods() { var methodNotImplementedFactory = function methodNotImplementedFactory(methodName) { return function () { var error = new Error('Method ' + methodName + ' is not implemented by the current driver'); var promise = Promise$1.reject(error); executeCallback(promise, arguments[arguments.length - 1]); return promise; }; }; for (var _i = 0, _len = OptionalDriverMethods.length; _i < _len; _i++) { var optionalDriverMethod = OptionalDriverMethods[_i]; if (!driverObject[optionalDriverMethod]) { driverObject[optionalDriverMethod] = methodNotImplementedFactory(optionalDriverMethod); } } }; configureMissingMethods(); var setDriverSupport = function setDriverSupport(support) { if (DefinedDrivers[driverName]) { console.info('Redefining LocalForage driver: ' + driverName); } DefinedDrivers[driverName] = driverObject; DriverSupport[driverName] = support; // don't use a then, so that we can define // drivers that have simple _support methods // in a blocking manner resolve(); }; if ('_support' in driverObject) { if (driverObject._support && typeof driverObject._support === 'function') { driverObject._support().then(setDriverSupport, reject); } else { setDriverSupport(!!driverObject._support); } } else { setDriverSupport(true); } } catch (e) { reject(e); } }); executeTwoCallbacks(promise, callback, errorCallback); return promise; }; LocalForage.prototype.driver = function driver() { return this._driver || null; }; LocalForage.prototype.getDriver = function getDriver(driverName, callback, errorCallback) { var getDriverPromise = DefinedDrivers[driverName] ? Promise$1.resolve(DefinedDrivers[driverName]) : Promise$1.reject(new Error('Driver not found.')); executeTwoCallbacks(getDriverPromise, callback, errorCallback); return getDriverPromise; }; LocalForage.prototype.getSerializer = function getSerializer(callback) { var serializerPromise = Promise$1.resolve(localforageSerializer); executeTwoCallbacks(serializerPromise, callback); return serializerPromise; }; LocalForage.prototype.ready = function ready(callback) { var self = this; var promise = self._driverSet.then(function () { if (self._ready === null) { self._ready = self._initDriver(); } return self._ready; }); executeTwoCallbacks(promise, callback, callback); return promise; }; LocalForage.prototype.setDriver = function setDriver(drivers, callback, errorCallback) { var self = this; if (!isArray(drivers)) { drivers = [drivers]; } var supportedDrivers = this._getSupportedDrivers(drivers); function setDriverToConfig() { self._config.driver = self.driver(); } function extendSelfWithDriver(driver) { self._extend(driver); setDriverToConfig(); self._ready = self._initStorage(self._config); return self._ready; } function initDriver(supportedDrivers) { return function () { var currentDriverIndex = 0; function driverPromiseLoop() { while (currentDriverIndex < supportedDrivers.length) { var driverName = supportedDrivers[currentDriverIndex]; currentDriverIndex++; self._dbInfo = null; self._ready = null; return self.getDriver(driverName).then(extendSelfWithDriver)["catch"](driverPromiseLoop); } setDriverToConfig(); var error = new Error('No available storage method found.'); self._driverSet = Promise$1.reject(error); return self._driverSet; } return driverPromiseLoop(); }; } // There might be a driver initialization in progress // so wait for it to finish in order to avoid a possible // race condition to set _dbInfo var oldDriverSetDone = this._driverSet !== null ? this._driverSet["catch"](function () { return Promise$1.resolve(); }) : Promise$1.resolve(); this._driverSet = oldDriverSetDone.then(function () { var driverName = supportedDrivers[0]; self._dbInfo = null; self._ready = null; return self.getDriver(driverName).then(function (driver) { self._driver = driver._driver; setDriverToConfig(); self._wrapLibraryMethodsWithReady(); self._initDriver = initDriver(supportedDrivers); }); })["catch"](function () { setDriverToConfig(); var error = new Error('No available storage method found.'); self._driverSet = Promise$1.reject(error); return self._driverSet; }); executeTwoCallbacks(this._driverSet, callback, errorCallback); return this._driverSet; }; LocalForage.prototype.supports = function supports(driverName) { return !!DriverSupport[driverName]; }; LocalForage.prototype._extend = function _extend(libraryMethodsAndProperties) { extend(this, libraryMethodsAndProperties); }; LocalForage.prototype._getSupportedDrivers = function _getSupportedDrivers(drivers) { var supportedDrivers = []; for (var i = 0, len = drivers.length; i < len; i++) { var driverName = drivers[i]; if (this.supports(driverName)) { supportedDrivers.push(driverName); } } return supportedDrivers; }; LocalForage.prototype._wrapLibraryMethodsWithReady = function _wrapLibraryMethodsWithReady() { // Add a stub for each driver API method that delays the call to the // corresponding driver method until localForage is ready. These stubs // will be replaced by the driver methods as soon as the driver is // loaded, so there is no performance impact. for (var i = 0, len = LibraryMethods.length; i < len; i++) { callWhenReady(this, LibraryMethods[i]); } }; LocalForage.prototype.createInstance = function createInstance(options) { return new LocalForage(options); }; return LocalForage; }(); // The actual localForage object that we expose as a module or via a // global. It's extended by pulling in one of our other libraries. var localforage_js = new LocalForage(); module.exports = localforage_js; },{"3":3}]},{},[4])(4) }); /***/ }), /***/ 155: /***/ ((module) => { // shim for using process in browser var process = module.exports = {}; // cached from whatever global is present so that test runners that stub it // don't break things. But we need to wrap it in a try catch in case it is // wrapped in strict mode code which doesn't define any globals. It's inside a // function because try/catches deoptimize in certain engines. var cachedSetTimeout; var cachedClearTimeout; function defaultSetTimout() { throw new Error('setTimeout has not been defined'); } function defaultClearTimeout () { throw new Error('clearTimeout has not been defined'); } (function () { try { if (typeof setTimeout === 'function') { cachedSetTimeout = setTimeout; } else { cachedSetTimeout = defaultSetTimout; } } catch (e) { cachedSetTimeout = defaultSetTimout; } try { if (typeof clearTimeout === 'function') { cachedClearTimeout = clearTimeout; } else { cachedClearTimeout = defaultClearTimeout; } } catch (e) { cachedClearTimeout = defaultClearTimeout; } } ()) function runTimeout(fun) { if (cachedSetTimeout === setTimeout) { //normal enviroments in sane situations return setTimeout(fun, 0); } // if setTimeout wasn't available but was latter defined if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) { cachedSetTimeout = setTimeout; return setTimeout(fun, 0); } try { // when when somebody has screwed with setTimeout but no I.E. maddness return cachedSetTimeout(fun, 0); } catch(e){ try { // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally return cachedSetTimeout.call(null, fun, 0); } catch(e){ // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error return cachedSetTimeout.call(this, fun, 0); } } } function runClearTimeout(marker) { if (cachedClearTimeout === clearTimeout) { //normal enviroments in sane situations return clearTimeout(marker); } // if clearTimeout wasn't available but was latter defined if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) { cachedClearTimeout = clearTimeout; return clearTimeout(marker); } try { // when when somebody has screwed with setTimeout but no I.E. maddness return cachedClearTimeout(marker); } catch (e){ try { // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally return cachedClearTimeout.call(null, marker); } catch (e){ // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error. // Some versions of I.E. have different rules for clearTimeout vs setTimeout return cachedClearTimeout.call(this, marker); } } } var queue = []; var draining = false; var currentQueue; var queueIndex = -1; function cleanUpNextTick() { if (!draining || !currentQueue) { return; } draining = false; if (currentQueue.length) { queue = currentQueue.concat(queue); } else { queueIndex = -1; } if (queue.length) { drainQueue(); } } function drainQueue() { if (draining) { return; } var timeout = runTimeout(cleanUpNextTick); draining = true; var len = queue.length; while(len) { currentQueue = queue; queue = []; while (++queueIndex < len) { if (currentQueue) { currentQueue[queueIndex].run(); } } queueIndex = -1; len = queue.length; } currentQueue = null; draining = false; runClearTimeout(timeout); } process.nextTick = function (fun) { var args = new Array(arguments.length - 1); if (arguments.length > 1) { for (var i = 1; i < arguments.length; i++) { args[i - 1] = arguments[i]; } } queue.push(new Item(fun, args)); if (queue.length === 1 && !draining) { runTimeout(drainQueue); } }; // v8 likes predictible objects function Item(fun, array) { this.fun = fun; this.array = array; } Item.prototype.run = function () { this.fun.apply(null, this.array); }; process.title = 'browser'; process.browser = true; process.env = {}; process.argv = []; process.version = ''; // empty string to avoid regexp issues process.versions = {}; function noop() {} process.on = noop; process.addListener = noop; process.once = noop; process.off = noop; process.removeListener = noop; process.removeAllListeners = noop; process.emit = noop; process.prependListener = noop; process.prependOnceListener = noop; process.listeners = function (name) { return [] } process.binding = function (name) { throw new Error('process.binding is not supported'); }; process.cwd = function () { return '/' }; process.chdir = function (dir) { throw new Error('process.chdir is not supported'); }; process.umask = function() { return 0; }; /***/ }), /***/ 384: /***/ ((module) => { module.exports = function isBuffer(arg) { return arg && typeof arg === 'object' && typeof arg.copy === 'function' && typeof arg.fill === 'function' && typeof arg.readUInt8 === 'function'; } /***/ }), /***/ 955: /***/ ((__unused_webpack_module, exports, __webpack_require__) => { "use strict"; // Currently in sync with Node.js lib/internal/util/types.js // https://github.com/nodejs/node/commit/112cc7c27551254aa2b17098fb774867f05ed0d9 var isArgumentsObject = __webpack_require__(584); var isGeneratorFunction = __webpack_require__(662); var whichTypedArray = __webpack_require__(430); var isTypedArray = __webpack_require__(692); function uncurryThis(f) { return f.call.bind(f); } var BigIntSupported = typeof BigInt !== 'undefined'; var SymbolSupported = typeof Symbol !== 'undefined'; var ObjectToString = uncurryThis(Object.prototype.toString); var numberValue = uncurryThis(Number.prototype.valueOf); var stringValue = uncurryThis(String.prototype.valueOf); var booleanValue = uncurryThis(Boolean.prototype.valueOf); if (BigIntSupported) { var bigIntValue = uncurryThis(BigInt.prototype.valueOf); } if (SymbolSupported) { var symbolValue = uncurryThis(Symbol.prototype.valueOf); } function checkBoxedPrimitive(value, prototypeValueOf) { if (typeof value !== 'object') { return false; } try { prototypeValueOf(value); return true; } catch(e) { return false; } } exports.isArgumentsObject = isArgumentsObject; exports.isGeneratorFunction = isGeneratorFunction; exports.isTypedArray = isTypedArray; // Taken from here and modified for better browser support // https://github.com/sindresorhus/p-is-promise/blob/cda35a513bda03f977ad5cde3a079d237e82d7ef/index.js function isPromise(input) { return ( ( typeof Promise !== 'undefined' && input instanceof Promise ) || ( input !== null && typeof input === 'object' && typeof input.then === 'function' && typeof input.catch === 'function' ) ); } exports.isPromise = isPromise; function isArrayBufferView(value) { if (typeof ArrayBuffer !== 'undefined' && ArrayBuffer.isView) { return ArrayBuffer.isView(value); } return ( isTypedArray(value) || isDataView(value) ); } exports.isArrayBufferView = isArrayBufferView; function isUint8Array(value) { return whichTypedArray(value) === 'Uint8Array'; } exports.isUint8Array = isUint8Array; function isUint8ClampedArray(value) { return whichTypedArray(value) === 'Uint8ClampedArray'; } exports.isUint8ClampedArray = isUint8ClampedArray; function isUint16Array(value) { return whichTypedArray(value) === 'Uint16Array'; } exports.isUint16Array = isUint16Array; function isUint32Array(value) { return whichTypedArray(value) === 'Uint32Array'; } exports.isUint32Array = isUint32Array; function isInt8Array(value) { return whichTypedArray(value) === 'Int8Array'; } exports.isInt8Array = isInt8Array; function isInt16Array(value) { return whichTypedArray(value) === 'Int16Array'; } exports.isInt16Array = isInt16Array; function isInt32Array(value) { return whichTypedArray(value) === 'Int32Array'; } exports.isInt32Array = isInt32Array; function isFloat32Array(value) { return whichTypedArray(value) === 'Float32Array'; } exports.isFloat32Array = isFloat32Array; function isFloat64Array(value) { return whichTypedArray(value) === 'Float64Array'; } exports.isFloat64Array = isFloat64Array; function isBigInt64Array(value) { return whichTypedArray(value) === 'BigInt64Array'; } exports.isBigInt64Array = isBigInt64Array; function isBigUint64Array(value) { return whichTypedArray(value) === 'BigUint64Array'; } exports.isBigUint64Array = isBigUint64Array; function isMapToString(value) { return ObjectToString(value) === '[object Map]'; } isMapToString.working = ( typeof Map !== 'undefined' && isMapToString(new Map()) ); function isMap(value) { if (typeof Map === 'undefined') { return false; } return isMapToString.working ? isMapToString(value) : value instanceof Map; } exports.isMap = isMap; function isSetToString(value) { return ObjectToString(value) === '[object Set]'; } isSetToString.working = ( typeof Set !== 'undefined' && isSetToString(new Set()) ); function isSet(value) { if (typeof Set === 'undefined') { return false; } return isSetToString.working ? isSetToString(value) : value instanceof Set; } exports.isSet = isSet; function isWeakMapToString(value) { return ObjectToString(value) === '[object WeakMap]'; } isWeakMapToString.working = ( typeof WeakMap !== 'undefined' && isWeakMapToString(new WeakMap()) ); function isWeakMap(value) { if (typeof WeakMap === 'undefined') { return false; } return isWeakMapToString.working ? isWeakMapToString(value) : value instanceof WeakMap; } exports.isWeakMap = isWeakMap; function isWeakSetToString(value) { return ObjectToString(value) === '[object WeakSet]'; } isWeakSetToString.working = ( typeof WeakSet !== 'undefined' && isWeakSetToString(new WeakSet()) ); function isWeakSet(value) { return isWeakSetToString(value); } exports.isWeakSet = isWeakSet; function isArrayBufferToString(value) { return ObjectToString(value) === '[object ArrayBuffer]'; } isArrayBufferToString.working = ( typeof ArrayBuffer !== 'undefined' && isArrayBufferToString(new ArrayBuffer()) ); function isArrayBuffer(value) { if (typeof ArrayBuffer === 'undefined') { return false; } return isArrayBufferToString.working ? isArrayBufferToString(value) : value instanceof ArrayBuffer; } exports.isArrayBuffer = isArrayBuffer; function isDataViewToString(value) { return ObjectToString(value) === '[object DataView]'; } isDataViewToString.working = ( typeof ArrayBuffer !== 'undefined' && typeof DataView !== 'undefined' && isDataViewToString(new DataView(new ArrayBuffer(1), 0, 1)) ); function isDataView(value) { if (typeof DataView === 'undefined') { return false; } return isDataViewToString.working ? isDataViewToString(value) : value instanceof DataView; } exports.isDataView = isDataView; // Store a copy of SharedArrayBuffer in case it's deleted elsewhere var SharedArrayBufferCopy = typeof SharedArrayBuffer !== 'undefined' ? SharedArrayBuffer : undefined; function isSharedArrayBufferToString(value) { return ObjectToString(value) === '[object SharedArrayBuffer]'; } function isSharedArrayBuffer(value) { if (typeof SharedArrayBufferCopy === 'undefined') { return false; } if (typeof isSharedArrayBufferToString.working === 'undefined') { isSharedArrayBufferToString.working = isSharedArrayBufferToString(new SharedArrayBufferCopy()); } return isSharedArrayBufferToString.working ? isSharedArrayBufferToString(value) : value instanceof SharedArrayBufferCopy; } exports.isSharedArrayBuffer = isSharedArrayBuffer; function isAsyncFunction(value) { return ObjectToString(value) === '[object AsyncFunction]'; } exports.isAsyncFunction = isAsyncFunction; function isMapIterator(value) { return ObjectToString(value) === '[object Map Iterator]'; } exports.isMapIterator = isMapIterator; function isSetIterator(value) { return ObjectToString(value) === '[object Set Iterator]'; } exports.isSetIterator = isSetIterator; function isGeneratorObject(value) { return ObjectToString(value) === '[object Generator]'; } exports.isGeneratorObject = isGeneratorObject; function isWebAssemblyCompiledModule(value) { return ObjectToString(value) === '[object WebAssembly.Module]'; } exports.isWebAssemblyCompiledModule = isWebAssemblyCompiledModule; function isNumberObject(value) { return checkBoxedPrimitive(value, numberValue); } exports.isNumberObject = isNumberObject; function isStringObject(value) { return checkBoxedPrimitive(value, stringValue); } exports.isStringObject = isStringObject; function isBooleanObject(value) { return checkBoxedPrimitive(value, booleanValue); } exports.isBooleanObject = isBooleanObject; function isBigIntObject(value) { return BigIntSupported && checkBoxedPrimitive(value, bigIntValue); } exports.isBigIntObject = isBigIntObject; function isSymbolObject(value) { return SymbolSupported && checkBoxedPrimitive(value, symbolValue); } exports.isSymbolObject = isSymbolObject; function isBoxedPrimitive(value) { return ( isNumberObject(value) || isStringObject(value) || isBooleanObject(value) || isBigIntObject(value) || isSymbolObject(value) ); } exports.isBoxedPrimitive = isBoxedPrimitive; function isAnyArrayBuffer(value) { return typeof Uint8Array !== 'undefined' && ( isArrayBuffer(value) || isSharedArrayBuffer(value) ); } exports.isAnyArrayBuffer = isAnyArrayBuffer; ['isProxy', 'isExternal', 'isModuleNamespaceObject'].forEach(function(method) { Object.defineProperty(exports, method, { enumerable: false, value: function() { throw new Error(method + ' is not supported in userland'); } }); }); /***/ }), /***/ 539: /***/ ((__unused_webpack_module, exports, __webpack_require__) => { /* provided dependency */ var process = __webpack_require__(155); // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the // "Software"), to deal in the Software without restriction, including // without limitation the rights to use, copy, modify, merge, publish, // distribute, sublicense, and/or sell copies of the Software, and to permit // persons to whom the Software is furnished to do so, subject to the // following conditions: // // The above copyright notice and this permission notice shall be included // in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE // USE OR OTHER DEALINGS IN THE SOFTWARE. var getOwnPropertyDescriptors = Object.getOwnPropertyDescriptors || function getOwnPropertyDescriptors(obj) { var keys = Object.keys(obj); var descriptors = {}; for (var i = 0; i < keys.length; i++) { descriptors[keys[i]] = Object.getOwnPropertyDescriptor(obj, keys[i]); } return descriptors; }; var formatRegExp = /%[sdj%]/g; exports.format = function(f) { if (!isString(f)) { var objects = []; for (var i = 0; i < arguments.length; i++) { objects.push(inspect(arguments[i])); } return objects.join(' '); } var i = 1; var args = arguments; var len = args.length; var str = String(f).replace(formatRegExp, function(x) { if (x === '%%') return '%'; if (i >= len) return x; switch (x) { case '%s': return String(args[i++]); case '%d': return Number(args[i++]); case '%j': try { return JSON.stringify(args[i++]); } catch (_) { return '[Circular]'; } default: return x; } }); for (var x = args[i]; i < len; x = args[++i]) { if (isNull(x) || !isObject(x)) { str += ' ' + x; } else { str += ' ' + inspect(x); } } return str; }; // Mark that a method should not be used. // Returns a modified function which warns once by default. // If --no-deprecation is set, then it is a no-op. exports.deprecate = function(fn, msg) { if (typeof process !== 'undefined' && process.noDeprecation === true) { return fn; } // Allow for deprecating things in the process of starting up. if (typeof process === 'undefined') { return function() { return exports.deprecate(fn, msg).apply(this, arguments); }; } var warned = false; function deprecated() { if (!warned) { if (process.throwDeprecation) { throw new Error(msg); } else if (process.traceDeprecation) { console.trace(msg); } else { console.error(msg); } warned = true; } return fn.apply(this, arguments); } return deprecated; }; var debugs = {}; var debugEnvRegex = /^$/; if (process.env.NODE_DEBUG) { var debugEnv = process.env.NODE_DEBUG; debugEnv = debugEnv.replace(/[|\\{}()[\]^$+?.]/g, '\\$&') .replace(/\*/g, '.*') .replace(/,/g, '$|^') .toUpperCase(); debugEnvRegex = new RegExp('^' + debugEnv + '$', 'i'); } exports.debuglog = function(set) { set = set.toUpperCase(); if (!debugs[set]) { if (debugEnvRegex.test(set)) { var pid = process.pid; debugs[set] = function() { var msg = exports.format.apply(exports, arguments); console.error('%s %d: %s', set, pid, msg); }; } else { debugs[set] = function() {}; } } return debugs[set]; }; /** * Echos the value of a value. Trys to print the value out * in the best way possible given the different types. * * @param {Object} obj The object to print out. * @param {Object} opts Optional options object that alters the output. */ /* legacy: obj, showHidden, depth, colors*/ function inspect(obj, opts) { // default options var ctx = { seen: [], stylize: stylizeNoColor }; // legacy... if (arguments.length >= 3) ctx.depth = arguments[2]; if (arguments.length >= 4) ctx.colors = arguments[3]; if (isBoolean(opts)) { // legacy... ctx.showHidden = opts; } else if (opts) { // got an "options" object exports._extend(ctx, opts); } // set default options if (isUndefined(ctx.showHidden)) ctx.showHidden = false; if (isUndefined(ctx.depth)) ctx.depth = 2; if (isUndefined(ctx.colors)) ctx.colors = false; if (isUndefined(ctx.customInspect)) ctx.customInspect = true; if (ctx.colors) ctx.stylize = stylizeWithColor; return formatValue(ctx, obj, ctx.depth); } exports.inspect = inspect; // http://en.wikipedia.org/wiki/ANSI_escape_code#graphics inspect.colors = { 'bold' : [1, 22], 'italic' : [3, 23], 'underline' : [4, 24], 'inverse' : [7, 27], 'white' : [37, 39], 'grey' : [90, 39], 'black' : [30, 39], 'blue' : [34, 39], 'cyan' : [36, 39], 'green' : [32, 39], 'magenta' : [35, 39], 'red' : [31, 39], 'yellow' : [33, 39] }; // Don't use 'blue' not visible on cmd.exe inspect.styles = { 'special': 'cyan', 'number': 'yellow', 'boolean': 'yellow', 'undefined': 'grey', 'null': 'bold', 'string': 'green', 'date': 'magenta', // "name": intentionally not styling 'regexp': 'red' }; function stylizeWithColor(str, styleType) { var style = inspect.styles[styleType]; if (style) { return '\u001b[' + inspect.colors[style][0] + 'm' + str + '\u001b[' + inspect.colors[style][1] + 'm'; } else { return str; } } function stylizeNoColor(str, styleType) { return str; } function arrayToHash(array) { var hash = {}; array.forEach(function(val, idx) { hash[val] = true; }); return hash; } function formatValue(ctx, value, recurseTimes) { // Provide a hook for user-specified inspect functions. // Check that value is an object with an inspect function on it if (ctx.customInspect && value && isFunction(value.inspect) && // Filter out the util module, it's inspect function is special value.inspect !== exports.inspect && // Also filter out any prototype objects using the circular check. !(value.constructor && value.constructor.prototype === value)) { var ret = value.inspect(recurseTimes, ctx); if (!isString(ret)) { ret = formatValue(ctx, ret, recurseTimes); } return ret; } // Primitive types cannot have properties var primitive = formatPrimitive(ctx, value); if (primitive) { return primitive; } // Look up the keys of the object. var keys = Object.keys(value); var visibleKeys = arrayToHash(keys); if (ctx.showHidden) { keys = Object.getOwnPropertyNames(value); } // IE doesn't make error fields non-enumerable // http://msdn.microsoft.com/en-us/library/ie/dww52sbt(v=vs.94).aspx if (isError(value) && (keys.indexOf('message') >= 0 || keys.indexOf('description') >= 0)) { return formatError(value); } // Some type of object without properties can be shortcutted. if (keys.length === 0) { if (isFunction(value)) { var name = value.name ? ': ' + value.name : ''; return ctx.stylize('[Function' + name + ']', 'special'); } if (isRegExp(value)) { return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); } if (isDate(value)) { return ctx.stylize(Date.prototype.toString.call(value), 'date'); } if (isError(value)) { return formatError(value); } } var base = '', array = false, braces = ['{', '}']; // Make Array say that they are Array if (isArray(value)) { array = true; braces = ['[', ']']; } // Make functions say that they are functions if (isFunction(value)) { var n = value.name ? ': ' + value.name : ''; base = ' [Function' + n + ']'; } // Make RegExps say that they are RegExps if (isRegExp(value)) { base = ' ' + RegExp.prototype.toString.call(value); } // Make dates with properties first say the date if (isDate(value)) { base = ' ' + Date.prototype.toUTCString.call(value); } // Make error with message first say the error if (isError(value)) { base = ' ' + formatError(value); } if (keys.length === 0 && (!array || value.length == 0)) { return braces[0] + base + braces[1]; } if (recurseTimes < 0) { if (isRegExp(value)) { return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); } else { return ctx.stylize('[Object]', 'special'); } } ctx.seen.push(value); var output; if (array) { output = formatArray(ctx, value, recurseTimes, visibleKeys, keys); } else { output = keys.map(function(key) { return formatProperty(ctx, value, recurseTimes, visibleKeys, key, array); }); } ctx.seen.pop(); return reduceToSingleString(output, base, braces); } function formatPrimitive(ctx, value) { if (isUndefined(value)) return ctx.stylize('undefined', 'undefined'); if (isString(value)) { var simple = '\'' + JSON.stringify(value).replace(/^"|"$/g, '') .replace(/'/g, "\\'") .replace(/\\"/g, '"') + '\''; return ctx.stylize(simple, 'string'); } if (isNumber(value)) return ctx.stylize('' + value, 'number'); if (isBoolean(value)) return ctx.stylize('' + value, 'boolean'); // For some reason typeof null is "object", so special case here. if (isNull(value)) return ctx.stylize('null', 'null'); } function formatError(value) { return '[' + Error.prototype.toString.call(value) + ']'; } function formatArray(ctx, value, recurseTimes, visibleKeys, keys) { var output = []; for (var i = 0, l = value.length; i < l; ++i) { if (hasOwnProperty(value, String(i))) { output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, String(i), true)); } else { output.push(''); } } keys.forEach(function(key) { if (!key.match(/^\d+$/)) { output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, key, true)); } }); return output; } function formatProperty(ctx, value, recurseTimes, visibleKeys, key, array) { var name, str, desc; desc = Object.getOwnPropertyDescriptor(value, key) || { value: value[key] }; if (desc.get) { if (desc.set) { str = ctx.stylize('[Getter/Setter]', 'special'); } else { str = ctx.stylize('[Getter]', 'special'); } } else { if (desc.set) { str = ctx.stylize('[Setter]', 'special'); } } if (!hasOwnProperty(visibleKeys, key)) { name = '[' + key + ']'; } if (!str) { if (ctx.seen.indexOf(desc.value) < 0) { if (isNull(recurseTimes)) { str = formatValue(ctx, desc.value, null); } else { str = formatValue(ctx, desc.value, recurseTimes - 1); } if (str.indexOf('\n') > -1) { if (array) { str = str.split('\n').map(function(line) { return ' ' + line; }).join('\n').slice(2); } else { str = '\n' + str.split('\n').map(function(line) { return ' ' + line; }).join('\n'); } } } else { str = ctx.stylize('[Circular]', 'special'); } } if (isUndefined(name)) { if (array && key.match(/^\d+$/)) { return str; } name = JSON.stringify('' + key); if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) { name = name.slice(1, -1); name = ctx.stylize(name, 'name'); } else { name = name.replace(/'/g, "\\'") .replace(/\\"/g, '"') .replace(/(^"|"$)/g, "'"); name = ctx.stylize(name, 'string'); } } return name + ': ' + str; } function reduceToSingleString(output, base, braces) { var numLinesEst = 0; var length = output.reduce(function(prev, cur) { numLinesEst++; if (cur.indexOf('\n') >= 0) numLinesEst++; return prev + cur.replace(/\u001b\[\d\d?m/g, '').length + 1; }, 0); if (length > 60) { return braces[0] + (base === '' ? '' : base + '\n ') + ' ' + output.join(',\n ') + ' ' + braces[1]; } return braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1]; } // NOTE: These type checking functions intentionally don't use `instanceof` // because it is fragile and can be easily faked with `Object.create()`. exports.types = __webpack_require__(955); function isArray(ar) { return Array.isArray(ar); } exports.isArray = isArray; function isBoolean(arg) { return typeof arg === 'boolean'; } exports.isBoolean = isBoolean; function isNull(arg) { return arg === null; } exports.isNull = isNull; function isNullOrUndefined(arg) { return arg == null; } exports.isNullOrUndefined = isNullOrUndefined; function isNumber(arg) { return typeof arg === 'number'; } exports.isNumber = isNumber; function isString(arg) { return typeof arg === 'string'; } exports.isString = isString; function isSymbol(arg) { return typeof arg === 'symbol'; } exports.isSymbol = isSymbol; function isUndefined(arg) { return arg === void 0; } exports.isUndefined = isUndefined; function isRegExp(re) { return isObject(re) && objectToString(re) === '[object RegExp]'; } exports.isRegExp = isRegExp; exports.types.isRegExp = isRegExp; function isObject(arg) { return typeof arg === 'object' && arg !== null; } exports.isObject = isObject; function isDate(d) { return isObject(d) && objectToString(d) === '[object Date]'; } exports.isDate = isDate; exports.types.isDate = isDate; function isError(e) { return isObject(e) && (objectToString(e) === '[object Error]' || e instanceof Error); } exports.isError = isError; exports.types.isNativeError = isError; function isFunction(arg) { return typeof arg === 'function'; } exports.isFunction = isFunction; function isPrimitive(arg) { return arg === null || typeof arg === 'boolean' || typeof arg === 'number' || typeof arg === 'string' || typeof arg === 'symbol' || // ES6 symbol typeof arg === 'undefined'; } exports.isPrimitive = isPrimitive; exports.isBuffer = __webpack_require__(384); function objectToString(o) { return Object.prototype.toString.call(o); } function pad(n) { return n < 10 ? '0' + n.toString(10) : n.toString(10); } var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; // 26 Feb 16:19:34 function timestamp() { var d = new Date(); var time = [pad(d.getHours()), pad(d.getMinutes()), pad(d.getSeconds())].join(':'); return [d.getDate(), months[d.getMonth()], time].join(' '); } // log is just a thin wrapper to console.log that prepends a timestamp exports.log = function() { console.log('%s - %s', timestamp(), exports.format.apply(exports, arguments)); }; /** * Inherit the prototype methods from one constructor into another. * * The Function.prototype.inherits from lang.js rewritten as a standalone * function (not on Function.prototype). NOTE: If this file is to be loaded * during bootstrapping this function needs to be rewritten using some native * functions as prototype setup using normal JavaScript does not work as * expected during bootstrapping (see mirror.js in r114903). * * @param {function} ctor Constructor function which needs to inherit the * prototype. * @param {function} superCtor Constructor function to inherit prototype from. */ exports.inherits = __webpack_require__(717); exports._extend = function(origin, add) { // Don't do anything if add isn't an object if (!add || !isObject(add)) return origin; var keys = Object.keys(add); var i = keys.length; while (i--) { origin[keys[i]] = add[keys[i]]; } return origin; }; function hasOwnProperty(obj, prop) { return Object.prototype.hasOwnProperty.call(obj, prop); } var kCustomPromisifiedSymbol = typeof Symbol !== 'undefined' ? Symbol('util.promisify.custom') : undefined; exports.promisify = function promisify(original) { if (typeof original !== 'function') throw new TypeError('The "original" argument must be of type Function'); if (kCustomPromisifiedSymbol && original[kCustomPromisifiedSymbol]) { var fn = original[kCustomPromisifiedSymbol]; if (typeof fn !== 'function') { throw new TypeError('The "util.promisify.custom" argument must be of type Function'); } Object.defineProperty(fn, kCustomPromisifiedSymbol, { value: fn, enumerable: false, writable: false, configurable: true }); return fn; } function fn() { var promiseResolve, promiseReject; var promise = new Promise(function (resolve, reject) { promiseResolve = resolve; promiseReject = reject; }); var args = []; for (var i = 0; i < arguments.length; i++) { args.push(arguments[i]); } args.push(function (err, value) { if (err) { promiseReject(err); } else { promiseResolve(value); } }); try { original.apply(this, args); } catch (err) { promiseReject(err); } return promise; } Object.setPrototypeOf(fn, Object.getPrototypeOf(original)); if (kCustomPromisifiedSymbol) Object.defineProperty(fn, kCustomPromisifiedSymbol, { value: fn, enumerable: false, writable: false, configurable: true }); return Object.defineProperties( fn, getOwnPropertyDescriptors(original) ); } exports.promisify.custom = kCustomPromisifiedSymbol function callbackifyOnRejected(reason, cb) { // `!reason` guard inspired by bluebird (Ref: https://goo.gl/t5IS6M). // Because `null` is a special error value in callbacks which means "no error // occurred", we error-wrap so the callback consumer can distinguish between // "the promise rejected with null" or "the promise fulfilled with undefined". if (!reason) { var newReason = new Error('Promise was rejected with a falsy value'); newReason.reason = reason; reason = newReason; } return cb(reason); } function callbackify(original) { if (typeof original !== 'function') { throw new TypeError('The "original" argument must be of type Function'); } // We DO NOT return the promise as it gives the user a false sense that // the promise is actually somehow related to the callback's execution // and that the callback throwing will reject the promise. function callbackified() { var args = []; for (var i = 0; i < arguments.length; i++) { args.push(arguments[i]); } var maybeCb = args.pop(); if (typeof maybeCb !== 'function') { throw new TypeError('The last argument must be of type Function'); } var self = this; var cb = function() { return maybeCb.apply(self, arguments); }; // In true node style we process the callback on `nextTick` with all the // implications (stack, `uncaughtException`, `async_hooks`) original.apply(this, args) .then(function(ret) { process.nextTick(cb.bind(null, null, ret)) }, function(rej) { process.nextTick(callbackifyOnRejected.bind(null, rej, cb)) }); } Object.setPrototypeOf(callbackified, Object.getPrototypeOf(original)); Object.defineProperties(callbackified, getOwnPropertyDescriptors(original)); return callbackified; } exports.callbackify = callbackify; /***/ }), /***/ 430: /***/ ((module, __unused_webpack_exports, __webpack_require__) => { "use strict"; var forEach = __webpack_require__(29); var availableTypedArrays = __webpack_require__(83); var callBound = __webpack_require__(924); var gOPD = __webpack_require__(296); var $toString = callBound('Object.prototype.toString'); var hasToStringTag = __webpack_require__(410)(); var g = typeof globalThis === 'undefined' ? __webpack_require__.g : globalThis; var typedArrays = availableTypedArrays(); var $slice = callBound('String.prototype.slice'); var toStrTags = {}; var getPrototypeOf = Object.getPrototypeOf; // require('getprototypeof'); if (hasToStringTag && gOPD && getPrototypeOf) { forEach(typedArrays, function (typedArray) { if (typeof g[typedArray] === 'function') { var arr = new g[typedArray](); if (Symbol.toStringTag in arr) { var proto = getPrototypeOf(arr); var descriptor = gOPD(proto, Symbol.toStringTag); if (!descriptor) { var superProto = getPrototypeOf(proto); descriptor = gOPD(superProto, Symbol.toStringTag); } toStrTags[typedArray] = descriptor.get; } } }); } var tryTypedArrays = function tryAllTypedArrays(value) { var foundName = false; forEach(toStrTags, function (getter, typedArray) { if (!foundName) { try { var name = getter.call(value); if (name === typedArray) { foundName = name; } } catch (e) {} } }); return foundName; }; var isTypedArray = __webpack_require__(692); module.exports = function whichTypedArray(value) { if (!isTypedArray(value)) { return false; } if (!hasToStringTag || !(Symbol.toStringTag in value)) { return $slice($toString(value), 8, -1); } return tryTypedArrays(value); }; /***/ }), /***/ 83: /***/ ((module, __unused_webpack_exports, __webpack_require__) => { "use strict"; var possibleNames = [ 'BigInt64Array', 'BigUint64Array', 'Float32Array', 'Float64Array', 'Int16Array', 'Int32Array', 'Int8Array', 'Uint16Array', 'Uint32Array', 'Uint8Array', 'Uint8ClampedArray' ]; var g = typeof globalThis === 'undefined' ? __webpack_require__.g : globalThis; module.exports = function availableTypedArrays() { var out = []; for (var i = 0; i < possibleNames.length; i++) { if (typeof g[possibleNames[i]] === 'function') { out[out.length] = possibleNames[i]; } } return out; }; /***/ }) /******/ }); /************************************************************************/ /******/ // The module cache /******/ var __webpack_module_cache__ = {}; /******/ /******/ // The require function /******/ function __webpack_require__(moduleId) { /******/ // Check if module is in cache /******/ var cachedModule = __webpack_module_cache__[moduleId]; /******/ if (cachedModule !== undefined) { /******/ return cachedModule.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/global */ /******/ (() => { /******/ __webpack_require__.g = (function() { /******/ if (typeof globalThis === 'object') return globalThis; /******/ try { /******/ return this || new Function('return this')(); /******/ } catch (e) { /******/ if (typeof window === 'object') return window; /******/ } /******/ })(); /******/ })(); /******/ /************************************************************************/ /******/ /******/ // startup /******/ // Load entry module and return exports /******/ // This entry module is referenced by other modules so it can't be inlined /******/ var __webpack_exports__ = __webpack_require__(797); /******/ window.Nedb = __webpack_exports__; /******/ /******/ })() ;