dexie
Version:
A Minimalistic Wrapper for IndexedDB
1,544 lines (1,527 loc) • 240 kB
JavaScript
/*
* Dexie.js - a minimalistic wrapper for IndexedDB
* ===============================================
*
* By David Fahlander, david.fahlander@gmail.com
*
* Version 4.4.3, Wed May 27 2026
*
* https://dexie.org
*
* Apache License Version 2.0, January 2004, http://www.apache.org/licenses/
*/
const _global = typeof globalThis !== 'undefined'
? globalThis
: typeof self !== 'undefined'
? self
: typeof window !== 'undefined'
? window
: global;
const keys = Object.keys;
const isArray = Array.isArray;
if (typeof Promise !== 'undefined' && !_global.Promise) {
_global.Promise = Promise;
}
function extend(obj, extension) {
if (typeof extension !== 'object')
return obj;
keys(extension).forEach(function (key) {
obj[key] = extension[key];
});
return obj;
}
const getProto = Object.getPrototypeOf;
const _hasOwn = {}.hasOwnProperty;
function hasOwn(obj, prop) {
return _hasOwn.call(obj, prop);
}
function props(proto, extension) {
if (typeof extension === 'function')
extension = extension(getProto(proto));
(typeof Reflect === 'undefined' ? keys : Reflect.ownKeys)(extension).forEach((key) => {
setProp(proto, key, extension[key]);
});
}
const defineProperty = Object.defineProperty;
function setProp(obj, prop, functionOrGetSet, options) {
defineProperty(obj, prop, extend(functionOrGetSet &&
hasOwn(functionOrGetSet, 'get') &&
typeof functionOrGetSet.get === 'function'
? {
get: functionOrGetSet.get,
set: functionOrGetSet.set,
configurable: true,
}
: { value: functionOrGetSet, configurable: true, writable: true }, options));
}
function derive(Child) {
return {
from: function (Parent) {
Child.prototype = Object.create(Parent.prototype);
setProp(Child.prototype, 'constructor', Child);
return {
extend: props.bind(null, Child.prototype),
};
},
};
}
const getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;
function getPropertyDescriptor(obj, prop) {
const pd = getOwnPropertyDescriptor(obj, prop);
let proto;
return pd || ((proto = getProto(obj)) && getPropertyDescriptor(proto, prop));
}
const _slice = [].slice;
function slice(args, start, end) {
return _slice.call(args, start, end);
}
function override(origFunc, overridedFactory) {
return overridedFactory(origFunc);
}
function assert(b) {
if (!b)
throw new Error('Assertion Failed');
}
function asap$1(fn) {
if (_global.setImmediate)
setImmediate(fn);
else
setTimeout(fn, 0);
}
function arrayToObject(array, extractor) {
return array.reduce((result, item, i) => {
var nameAndValue = extractor(item, i);
if (nameAndValue)
result[nameAndValue[0]] = nameAndValue[1];
return result;
}, {});
}
function getByKeyPath(obj, keyPath) {
if (typeof keyPath === 'string' && hasOwn(obj, keyPath))
return obj[keyPath];
if (!keyPath)
return obj;
if (typeof keyPath !== 'string') {
var rv = [];
for (var i = 0, l = keyPath.length; i < l; ++i) {
var val = getByKeyPath(obj, keyPath[i]);
rv.push(val);
}
return rv;
}
var period = keyPath.indexOf('.');
if (period !== -1) {
var innerObj = obj[keyPath.substr(0, period)];
return innerObj == null
? undefined
: getByKeyPath(innerObj, keyPath.substr(period + 1));
}
return undefined;
}
function setByKeyPath(obj, keyPath, value) {
if (!obj || keyPath === undefined)
return;
if ('isFrozen' in Object && Object.isFrozen(obj))
return;
if (typeof keyPath !== 'string' && 'length' in keyPath) {
assert(typeof value !== 'string' && 'length' in value);
for (var i = 0, l = keyPath.length; i < l; ++i) {
setByKeyPath(obj, keyPath[i], value[i]);
}
}
else {
var period = keyPath.indexOf('.');
if (period !== -1) {
var currentKeyPath = keyPath.substr(0, period);
var remainingKeyPath = keyPath.substr(period + 1);
if (remainingKeyPath === '')
if (value === undefined) {
if (isArray(obj) && !isNaN(parseInt(currentKeyPath)))
obj.splice(currentKeyPath, 1);
else
delete obj[currentKeyPath];
}
else
obj[currentKeyPath] = value;
else {
var innerObj = obj[currentKeyPath];
if (!innerObj || !hasOwn(obj, currentKeyPath)) {
if (value === undefined)
return;
innerObj = obj[currentKeyPath] = {};
}
setByKeyPath(innerObj, remainingKeyPath, value);
}
}
else {
if (value === undefined) {
if (isArray(obj) && !isNaN(parseInt(keyPath)))
obj.splice(keyPath, 1);
else
delete obj[keyPath];
}
else
obj[keyPath] = value;
}
}
}
function delByKeyPath(obj, keyPath) {
if (typeof keyPath === 'string')
setByKeyPath(obj, keyPath, undefined);
else if ('length' in keyPath)
[].map.call(keyPath, function (kp) {
setByKeyPath(obj, kp, undefined);
});
}
function shallowClone(obj) {
var rv = {};
for (var m in obj) {
if (hasOwn(obj, m))
rv[m] = obj[m];
}
return rv;
}
const concat = [].concat;
function flatten(a) {
return concat.apply([], a);
}
const intrinsicTypeNames = 'BigUint64Array,BigInt64Array,Array,Boolean,String,Date,RegExp,Blob,File,FileList,FileSystemFileHandle,FileSystemDirectoryHandle,ArrayBuffer,DataView,Uint8ClampedArray,ImageBitmap,ImageData,Map,Set,CryptoKey'
.split(',')
.concat(flatten([8, 16, 32, 64].map((num) => ['Int', 'Uint', 'Float'].map((t) => t + num + 'Array'))))
.filter((t) => _global[t]);
const intrinsicTypes = new Set(intrinsicTypeNames.map((t) => _global[t]));
function cloneSimpleObjectTree(o) {
const rv = {};
for (const k in o)
if (hasOwn(o, k)) {
const v = o[k];
rv[k] =
!v || typeof v !== 'object' || intrinsicTypes.has(v.constructor)
? v
: cloneSimpleObjectTree(v);
}
return rv;
}
let circularRefs = null;
function deepClone(any) {
circularRefs = new WeakMap();
const rv = innerDeepClone(any);
circularRefs = null;
return rv;
}
function innerDeepClone(x) {
if (!x || typeof x !== 'object')
return x;
let rv = circularRefs.get(x);
if (rv)
return rv;
if (isArray(x)) {
rv = [];
circularRefs.set(x, rv);
for (var i = 0, l = x.length; i < l; ++i) {
rv.push(innerDeepClone(x[i]));
}
}
else if (intrinsicTypes.has(x.constructor)) {
rv = x;
}
else {
const proto = getProto(x);
rv = proto === Object.prototype ? {} : Object.create(proto);
circularRefs.set(x, rv);
for (var prop in x) {
if (hasOwn(x, prop)) {
rv[prop] = innerDeepClone(x[prop]);
}
}
}
return rv;
}
const { toString } = {};
function toStringTag(o) {
return toString.call(o).slice(8, -1);
}
const iteratorSymbol = typeof Symbol !== 'undefined' ? Symbol.iterator : '@@iterator';
const getIteratorOf = typeof iteratorSymbol === 'symbol'
? function (x) {
var i;
return x != null && (i = x[iteratorSymbol]) && i.apply(x);
}
: function () {
return null;
};
function delArrayItem(a, x) {
const i = a.indexOf(x);
if (i >= 0)
a.splice(i, 1);
return i >= 0;
}
const NO_CHAR_ARRAY = {};
function getArrayOf(arrayLike) {
var i, a, x, it;
if (arguments.length === 1) {
if (isArray(arrayLike))
return arrayLike.slice();
if (this === NO_CHAR_ARRAY && typeof arrayLike === 'string')
return [arrayLike];
if ((it = getIteratorOf(arrayLike))) {
a = [];
while (((x = it.next()), !x.done))
a.push(x.value);
return a;
}
if (arrayLike == null)
return [arrayLike];
i = arrayLike.length;
if (typeof i === 'number') {
a = new Array(i);
while (i--)
a[i] = arrayLike[i];
return a;
}
return [arrayLike];
}
i = arguments.length;
a = new Array(i);
while (i--)
a[i] = arguments[i];
return a;
}
const isAsyncFunction = typeof Symbol !== 'undefined'
? (fn) => fn[Symbol.toStringTag] === 'AsyncFunction'
: () => false;
var dexieErrorNames = [
'Modify',
'Bulk',
'OpenFailed',
'VersionChange',
'Schema',
'Upgrade',
'InvalidTable',
'MissingAPI',
'NoSuchDatabase',
'InvalidArgument',
'SubTransaction',
'Unsupported',
'Internal',
'DatabaseClosed',
'PrematureCommit',
'ForeignAwait',
];
var idbDomErrorNames = [
'Unknown',
'Constraint',
'Data',
'TransactionInactive',
'ReadOnly',
'Version',
'NotFound',
'InvalidState',
'InvalidAccess',
'Abort',
'Timeout',
'QuotaExceeded',
'Syntax',
'DataClone',
];
var errorList = dexieErrorNames.concat(idbDomErrorNames);
var defaultTexts = {
VersionChanged: 'Database version changed by other database connection',
DatabaseClosed: 'Database has been closed',
Abort: 'Transaction aborted',
TransactionInactive: 'Transaction has already completed or failed',
MissingAPI: 'IndexedDB API missing. Please visit https://tinyurl.com/y2uuvskb',
};
function DexieError(name, msg) {
this.name = name;
this.message = msg;
}
derive(DexieError)
.from(Error)
.extend({
toString: function () {
return this.name + ': ' + this.message;
},
});
function getMultiErrorMessage(msg, failures) {
return (msg +
'. Errors: ' +
Object.keys(failures)
.map((key) => failures[key].toString())
.filter((v, i, s) => s.indexOf(v) === i)
.join('\n'));
}
function ModifyError(msg, failures, successCount, failedKeys) {
this.failures = failures;
this.failedKeys = failedKeys;
this.successCount = successCount;
this.message = getMultiErrorMessage(msg, failures);
}
derive(ModifyError).from(DexieError);
function BulkError(msg, failures) {
this.name = 'BulkError';
this.failures = Object.keys(failures).map((pos) => failures[pos]);
this.failuresByPos = failures;
this.message = getMultiErrorMessage(msg, this.failures);
}
derive(BulkError).from(DexieError);
var errnames = errorList.reduce((obj, name) => ((obj[name] = name + 'Error'), obj), {});
const BaseException = DexieError;
var exceptions = errorList.reduce((obj, name) => {
var fullName = name + 'Error';
function DexieError(msgOrInner, inner) {
this.name = fullName;
if (!msgOrInner) {
this.message = defaultTexts[name] || fullName;
this.inner = null;
}
else if (typeof msgOrInner === 'string') {
this.message = `${msgOrInner}${!inner ? '' : '\n ' + inner}`;
this.inner = inner || null;
}
else if (typeof msgOrInner === 'object') {
this.message = `${msgOrInner.name} ${msgOrInner.message}`;
this.inner = msgOrInner;
}
}
derive(DexieError).from(BaseException);
obj[name] = DexieError;
return obj;
}, {});
exceptions.Syntax = SyntaxError;
exceptions.Type = TypeError;
exceptions.Range = RangeError;
var exceptionMap = idbDomErrorNames.reduce((obj, name) => {
obj[name + 'Error'] = exceptions[name];
return obj;
}, {});
function mapError(domError, message) {
if (!domError ||
domError instanceof DexieError ||
domError instanceof TypeError ||
domError instanceof SyntaxError ||
!domError.name ||
!exceptionMap[domError.name])
return domError;
var rv = new exceptionMap[domError.name](message || domError.message, domError);
if ('stack' in domError) {
setProp(rv, 'stack', {
get: function () {
return this.inner.stack;
},
});
}
return rv;
}
var fullNameExceptions = errorList.reduce((obj, name) => {
if (['Syntax', 'Type', 'Range'].indexOf(name) === -1)
obj[name + 'Error'] = exceptions[name];
return obj;
}, {});
fullNameExceptions.ModifyError = ModifyError;
fullNameExceptions.DexieError = DexieError;
fullNameExceptions.BulkError = BulkError;
function nop() { }
function mirror(val) {
return val;
}
function pureFunctionChain(f1, f2) {
if (f1 == null || f1 === mirror)
return f2;
return function (val) {
return f2(f1(val));
};
}
function callBoth(on1, on2) {
return function () {
on1.apply(this, arguments);
on2.apply(this, arguments);
};
}
function hookCreatingChain(f1, f2) {
if (f1 === nop)
return f2;
return function () {
var res = f1.apply(this, arguments);
if (res !== undefined)
arguments[0] = res;
var onsuccess = this.onsuccess,
onerror = this.onerror;
this.onsuccess = null;
this.onerror = null;
var res2 = f2.apply(this, arguments);
if (onsuccess)
this.onsuccess = this.onsuccess
? callBoth(onsuccess, this.onsuccess)
: onsuccess;
if (onerror)
this.onerror = this.onerror ? callBoth(onerror, this.onerror) : onerror;
return res2 !== undefined ? res2 : res;
};
}
function hookDeletingChain(f1, f2) {
if (f1 === nop)
return f2;
return function () {
f1.apply(this, arguments);
var onsuccess = this.onsuccess,
onerror = this.onerror;
this.onsuccess = this.onerror = null;
f2.apply(this, arguments);
if (onsuccess)
this.onsuccess = this.onsuccess
? callBoth(onsuccess, this.onsuccess)
: onsuccess;
if (onerror)
this.onerror = this.onerror ? callBoth(onerror, this.onerror) : onerror;
};
}
function hookUpdatingChain(f1, f2) {
if (f1 === nop)
return f2;
return function (modifications) {
var res = f1.apply(this, arguments);
extend(modifications, res);
var onsuccess = this.onsuccess,
onerror = this.onerror;
this.onsuccess = null;
this.onerror = null;
var res2 = f2.apply(this, arguments);
if (onsuccess)
this.onsuccess = this.onsuccess
? callBoth(onsuccess, this.onsuccess)
: onsuccess;
if (onerror)
this.onerror = this.onerror ? callBoth(onerror, this.onerror) : onerror;
return res === undefined
? res2 === undefined
? undefined
: res2
: extend(res, res2);
};
}
function reverseStoppableEventChain(f1, f2) {
if (f1 === nop)
return f2;
return function () {
if (f2.apply(this, arguments) === false)
return false;
return f1.apply(this, arguments);
};
}
function promisableChain(f1, f2) {
if (f1 === nop)
return f2;
return function () {
var res = f1.apply(this, arguments);
if (res && typeof res.then === 'function') {
var thiz = this, i = arguments.length, args = new Array(i);
while (i--)
args[i] = arguments[i];
return res.then(function () {
return f2.apply(thiz, args);
});
}
return f2.apply(this, arguments);
};
}
var debug = typeof location !== 'undefined' &&
/^(http|https):\/\/(localhost|127\.0\.0\.1)/.test(location.href);
function setDebug(value, filter) {
debug = value;
}
var INTERNAL = {};
const ZONE_ECHO_LIMIT = 100, [resolvedNativePromise, nativePromiseProto, resolvedGlobalPromise] = typeof Promise === 'undefined'
? []
: (() => {
let globalP = Promise.resolve();
if (typeof crypto === 'undefined' || !crypto.subtle)
return [globalP, getProto(globalP), globalP];
const nativeP = crypto.subtle.digest('SHA-512', new Uint8Array([0]));
return [nativeP, getProto(nativeP), globalP];
})(), nativePromiseThen = nativePromiseProto && nativePromiseProto.then;
const NativePromise = resolvedNativePromise && resolvedNativePromise.constructor;
const patchGlobalPromise = !!resolvedGlobalPromise;
function schedulePhysicalTick() {
queueMicrotask(physicalTick);
}
var asap = function (callback, args) {
microtickQueue.push([callback, args]);
if (needsNewPhysicalTick) {
schedulePhysicalTick();
needsNewPhysicalTick = false;
}
};
var isOutsideMicroTick = true,
needsNewPhysicalTick = true,
unhandledErrors = [],
rejectingErrors = [],
rejectionMapper = mirror;
var globalPSD = {
id: 'global',
global: true,
ref: 0,
unhandleds: [],
onunhandled: nop,
pgp: false,
env: {},
finalize: nop,
};
var PSD = globalPSD;
var microtickQueue = [];
var numScheduledCalls = 0;
var tickFinalizers = [];
function DexiePromise(fn) {
if (typeof this !== 'object')
throw new TypeError('Promises must be constructed via new');
this._listeners = [];
this._lib = false;
var psd = (this._PSD = PSD);
if (typeof fn !== 'function') {
if (fn !== INTERNAL)
throw new TypeError('Not a function');
this._state = arguments[1];
this._value = arguments[2];
if (this._state === false)
handleRejection(this, this._value);
return;
}
this._state = null;
this._value = null;
++psd.ref;
executePromiseTask(this, fn);
}
const thenProp = {
get: function () {
var psd = PSD, microTaskId = totalEchoes;
function then(onFulfilled, onRejected) {
var possibleAwait = !psd.global && (psd !== PSD || microTaskId !== totalEchoes);
const cleanup = possibleAwait && !decrementExpectedAwaits();
var rv = new DexiePromise((resolve, reject) => {
propagateToListener(this, new Listener(nativeAwaitCompatibleWrap(onFulfilled, psd, possibleAwait, cleanup), nativeAwaitCompatibleWrap(onRejected, psd, possibleAwait, cleanup), resolve, reject, psd));
});
if (this._consoleTask)
rv._consoleTask = this._consoleTask;
return rv;
}
then.prototype = INTERNAL;
return then;
},
set: function (value) {
setProp(this, 'then', value && value.prototype === INTERNAL
? thenProp
: {
get: function () {
return value;
},
set: thenProp.set,
});
},
};
props(DexiePromise.prototype, {
then: thenProp,
_then: function (onFulfilled, onRejected) {
propagateToListener(this, new Listener(null, null, onFulfilled, onRejected, PSD));
},
catch: function (onRejected) {
if (arguments.length === 1)
return this.then(null, onRejected);
var type = arguments[0], handler = arguments[1];
return typeof type === 'function'
? this.then(null, (err) =>
err instanceof type ? handler(err) : PromiseReject(err))
: this.then(null, (err) =>
err && err.name === type ? handler(err) : PromiseReject(err));
},
finally: function (onFinally) {
return this.then((value) => {
return DexiePromise.resolve(onFinally()).then(() => value);
}, (err) => {
return DexiePromise.resolve(onFinally()).then(() => PromiseReject(err));
});
},
timeout: function (ms, msg) {
return ms < Infinity
? new DexiePromise((resolve, reject) => {
var handle = setTimeout(() => reject(new exceptions.Timeout(msg)), ms);
this.then(resolve, reject).finally(clearTimeout.bind(null, handle));
})
: this;
},
});
if (typeof Symbol !== 'undefined' && Symbol.toStringTag)
setProp(DexiePromise.prototype, Symbol.toStringTag, 'Dexie.Promise');
globalPSD.env = snapShot();
function Listener(onFulfilled, onRejected, resolve, reject, zone) {
this.onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : null;
this.onRejected = typeof onRejected === 'function' ? onRejected : null;
this.resolve = resolve;
this.reject = reject;
this.psd = zone;
}
props(DexiePromise, {
all: function () {
var values = getArrayOf
.apply(null, arguments)
.map(onPossibleParallellAsync);
return new DexiePromise(function (resolve, reject) {
if (values.length === 0)
resolve([]);
var remaining = values.length;
values.forEach((a, i) => DexiePromise.resolve(a).then((x) => {
values[i] = x;
if (!--remaining)
resolve(values);
}, reject));
});
},
resolve: (value) => {
if (value instanceof DexiePromise)
return value;
if (value && typeof value.then === 'function')
return new DexiePromise((resolve, reject) => {
value.then(resolve, reject);
});
var rv = new DexiePromise(INTERNAL, true, value);
return rv;
},
reject: PromiseReject,
race: function () {
var values = getArrayOf
.apply(null, arguments)
.map(onPossibleParallellAsync);
return new DexiePromise((resolve, reject) => {
values.map((value) => DexiePromise.resolve(value).then(resolve, reject));
});
},
PSD: {
get: () => PSD,
set: (value) => (PSD = value),
},
totalEchoes: { get: () => totalEchoes },
newPSD: newScope,
usePSD: usePSD,
scheduler: {
get: () => asap,
set: (value) => {
asap = value;
},
},
rejectionMapper: {
get: () => rejectionMapper,
set: (value) => {
rejectionMapper = value;
},
},
follow: (fn, zoneProps) => {
return new DexiePromise((resolve, reject) => {
return newScope((resolve, reject) => {
var psd = PSD;
psd.unhandleds = [];
psd.onunhandled = reject;
psd.finalize = callBoth(function () {
run_at_end_of_this_or_next_physical_tick(() => {
this.unhandleds.length === 0
? resolve()
: reject(this.unhandleds[0]);
});
}, psd.finalize);
fn();
}, zoneProps, resolve, reject);
});
},
});
if (NativePromise) {
if (NativePromise.allSettled)
setProp(DexiePromise, 'allSettled', function () {
const possiblePromises = getArrayOf
.apply(null, arguments)
.map(onPossibleParallellAsync);
return new DexiePromise((resolve) => {
if (possiblePromises.length === 0)
resolve([]);
let remaining = possiblePromises.length;
const results = new Array(remaining);
possiblePromises.forEach((p, i) => DexiePromise.resolve(p)
.then((value) => (results[i] = { status: 'fulfilled', value }), (reason) => (results[i] = { status: 'rejected', reason }))
.then(() => --remaining || resolve(results)));
});
});
if (NativePromise.any && typeof AggregateError !== 'undefined')
setProp(DexiePromise, 'any', function () {
const possiblePromises = getArrayOf
.apply(null, arguments)
.map(onPossibleParallellAsync);
return new DexiePromise((resolve, reject) => {
if (possiblePromises.length === 0)
reject(new AggregateError([]));
let remaining = possiblePromises.length;
const failures = new Array(remaining);
possiblePromises.forEach((p, i) => DexiePromise.resolve(p).then((value) => resolve(value), (failure) => {
failures[i] = failure;
if (!--remaining)
reject(new AggregateError(failures));
}));
});
});
if (NativePromise.withResolvers)
DexiePromise.withResolvers = NativePromise.withResolvers;
}
function executePromiseTask(promise, fn) {
try {
fn((value) => {
if (promise._state !== null)
return;
if (value === promise)
throw new TypeError('A promise cannot be resolved with itself.');
var shouldExecuteTick = promise._lib && beginMicroTickScope();
if (value && typeof value.then === 'function') {
executePromiseTask(promise, (resolve, reject) => {
value instanceof DexiePromise
? value._then(resolve, reject)
: value.then(resolve, reject);
});
}
else {
promise._state = true;
promise._value = value;
propagateAllListeners(promise);
}
if (shouldExecuteTick)
endMicroTickScope();
}, handleRejection.bind(null, promise));
}
catch (ex) {
handleRejection(promise, ex);
}
}
function handleRejection(promise, reason) {
rejectingErrors.push(reason);
if (promise._state !== null)
return;
var shouldExecuteTick = promise._lib && beginMicroTickScope();
reason = rejectionMapper(reason);
promise._state = false;
promise._value = reason;
addPossiblyUnhandledError(promise);
propagateAllListeners(promise);
if (shouldExecuteTick)
endMicroTickScope();
}
function propagateAllListeners(promise) {
var listeners = promise._listeners;
promise._listeners = [];
for (var i = 0, len = listeners.length; i < len; ++i) {
propagateToListener(promise, listeners[i]);
}
var psd = promise._PSD;
--psd.ref || psd.finalize();
if (numScheduledCalls === 0) {
++numScheduledCalls;
asap(() => {
if (--numScheduledCalls === 0)
finalizePhysicalTick();
}, []);
}
}
function propagateToListener(promise, listener) {
if (promise._state === null) {
promise._listeners.push(listener);
return;
}
var cb = promise._state ? listener.onFulfilled : listener.onRejected;
if (cb === null) {
return (promise._state ? listener.resolve : listener.reject)(promise._value);
}
++listener.psd.ref;
++numScheduledCalls;
asap(callListener, [cb, promise, listener]);
}
function callListener(cb, promise, listener) {
try {
var ret, value = promise._value;
if (!promise._state && rejectingErrors.length)
rejectingErrors = [];
ret =
debug && promise._consoleTask
? promise._consoleTask.run(() => cb(value))
: cb(value);
if (!promise._state && rejectingErrors.indexOf(value) === -1) {
markErrorAsHandled(promise);
}
listener.resolve(ret);
}
catch (e) {
listener.reject(e);
}
finally {
if (--numScheduledCalls === 0)
finalizePhysicalTick();
--listener.psd.ref || listener.psd.finalize();
}
}
function physicalTick() {
usePSD(globalPSD, () => {
beginMicroTickScope() && endMicroTickScope();
});
}
function beginMicroTickScope() {
var wasRootExec = isOutsideMicroTick;
isOutsideMicroTick = false;
needsNewPhysicalTick = false;
return wasRootExec;
}
function endMicroTickScope() {
var callbacks, i, l;
do {
while (microtickQueue.length > 0) {
callbacks = microtickQueue;
microtickQueue = [];
l = callbacks.length;
for (i = 0; i < l; ++i) {
var item = callbacks[i];
item[0].apply(null, item[1]);
}
}
} while (microtickQueue.length > 0);
isOutsideMicroTick = true;
needsNewPhysicalTick = true;
}
function finalizePhysicalTick() {
var unhandledErrs = unhandledErrors;
unhandledErrors = [];
unhandledErrs.forEach((p) => {
p._PSD.onunhandled.call(null, p._value, p);
});
var finalizers = tickFinalizers.slice(0);
var i = finalizers.length;
while (i)
finalizers[--i]();
}
function run_at_end_of_this_or_next_physical_tick(fn) {
function finalizer() {
fn();
tickFinalizers.splice(tickFinalizers.indexOf(finalizer), 1);
}
tickFinalizers.push(finalizer);
++numScheduledCalls;
asap(() => {
if (--numScheduledCalls === 0)
finalizePhysicalTick();
}, []);
}
function addPossiblyUnhandledError(promise) {
if (!unhandledErrors.some((p) => p._value === promise._value))
unhandledErrors.push(promise);
}
function markErrorAsHandled(promise) {
var i = unhandledErrors.length;
while (i)
if (unhandledErrors[--i]._value === promise._value) {
unhandledErrors.splice(i, 1);
return;
}
}
function PromiseReject(reason) {
return new DexiePromise(INTERNAL, false, reason);
}
function wrap(fn, errorCatcher) {
var psd = PSD;
return function () {
var wasRootExec = beginMicroTickScope(), outerScope = PSD;
try {
switchToZone(psd, true);
return fn.apply(this, arguments);
}
catch (e) {
errorCatcher && errorCatcher(e);
}
finally {
switchToZone(outerScope, false);
if (wasRootExec)
endMicroTickScope();
}
};
}
const task = { awaits: 0, echoes: 0, id: 0 };
var taskCounter = 0;
var zoneStack = [];
var zoneEchoes = 0;
var totalEchoes = 0;
var zone_id_counter = 0;
function newScope(fn, props, a1, a2) {
var parent = PSD, psd = Object.create(parent);
psd.parent = parent;
psd.ref = 0;
psd.global = false;
psd.id = ++zone_id_counter;
globalPSD.env;
psd.env = patchGlobalPromise
? {
Promise: DexiePromise,
PromiseProp: {
value: DexiePromise,
configurable: true,
writable: true,
},
all: DexiePromise.all,
race: DexiePromise.race,
allSettled: DexiePromise.allSettled,
any: DexiePromise.any,
resolve: DexiePromise.resolve,
reject: DexiePromise.reject,
}
: {};
if (props)
extend(psd, props);
++parent.ref;
psd.finalize = function () {
--this.parent.ref || this.parent.finalize();
};
var rv = usePSD(psd, fn, a1, a2);
if (psd.ref === 0)
psd.finalize();
return rv;
}
function incrementExpectedAwaits() {
if (!task.id)
task.id = ++taskCounter;
++task.awaits;
task.echoes += ZONE_ECHO_LIMIT;
return task.id;
}
function decrementExpectedAwaits() {
if (!task.awaits)
return false;
if (--task.awaits === 0)
task.id = 0;
task.echoes = task.awaits * ZONE_ECHO_LIMIT;
return true;
}
if (('' + nativePromiseThen).indexOf('[native code]') === -1) {
incrementExpectedAwaits = decrementExpectedAwaits = nop;
}
function onPossibleParallellAsync(possiblePromise) {
if (task.echoes &&
possiblePromise &&
possiblePromise.constructor === NativePromise) {
incrementExpectedAwaits();
return possiblePromise.then((x) => {
decrementExpectedAwaits();
return x;
}, (e) => {
decrementExpectedAwaits();
return rejection(e);
});
}
return possiblePromise;
}
function zoneEnterEcho(targetZone) {
++totalEchoes;
if (!task.echoes || --task.echoes === 0) {
task.echoes = task.awaits = task.id = 0;
}
zoneStack.push(PSD);
switchToZone(targetZone, true);
}
function zoneLeaveEcho() {
var zone = zoneStack[zoneStack.length - 1];
zoneStack.pop();
switchToZone(zone, false);
}
function switchToZone(targetZone, bEnteringZone) {
var currentZone = PSD;
if (bEnteringZone
? task.echoes && (!zoneEchoes++ || targetZone !== PSD)
: zoneEchoes && (!--zoneEchoes || targetZone !== PSD)) {
queueMicrotask(bEnteringZone ? zoneEnterEcho.bind(null, targetZone) : zoneLeaveEcho);
}
if (targetZone === PSD)
return;
PSD = targetZone;
if (currentZone === globalPSD)
globalPSD.env = snapShot();
if (patchGlobalPromise) {
var GlobalPromise = globalPSD.env.Promise;
var targetEnv = targetZone.env;
if (currentZone.global || targetZone.global) {
Object.defineProperty(_global, 'Promise', targetEnv.PromiseProp);
GlobalPromise.all = targetEnv.all;
GlobalPromise.race = targetEnv.race;
GlobalPromise.resolve = targetEnv.resolve;
GlobalPromise.reject = targetEnv.reject;
if (targetEnv.allSettled)
GlobalPromise.allSettled = targetEnv.allSettled;
if (targetEnv.any)
GlobalPromise.any = targetEnv.any;
}
}
}
function snapShot() {
var GlobalPromise = _global.Promise;
return patchGlobalPromise
? {
Promise: GlobalPromise,
PromiseProp: Object.getOwnPropertyDescriptor(_global, 'Promise'),
all: GlobalPromise.all,
race: GlobalPromise.race,
allSettled: GlobalPromise.allSettled,
any: GlobalPromise.any,
resolve: GlobalPromise.resolve,
reject: GlobalPromise.reject,
}
: {};
}
function usePSD(psd, fn, a1, a2, a3) {
var outerScope = PSD;
try {
switchToZone(psd, true);
return fn(a1, a2, a3);
}
finally {
switchToZone(outerScope, false);
}
}
function nativeAwaitCompatibleWrap(fn, zone, possibleAwait, cleanup) {
return typeof fn !== 'function'
? fn
: function () {
var outerZone = PSD;
if (possibleAwait)
incrementExpectedAwaits();
switchToZone(zone, true);
try {
return fn.apply(this, arguments);
}
finally {
switchToZone(outerZone, false);
if (cleanup)
queueMicrotask(decrementExpectedAwaits);
}
};
}
function execInGlobalContext(cb) {
if (Promise === NativePromise && task.echoes === 0) {
if (zoneEchoes === 0) {
cb();
}
else {
enqueueNativeMicroTask(cb);
}
}
else {
setTimeout(cb, 0);
}
}
var rejection = DexiePromise.reject;
function tempTransaction(db, mode, storeNames, fn) {
if (!db.idbdb || (!db._state.openComplete && !PSD.letThrough && !db._vip)) {
if (db._state.openComplete) {
return rejection(new exceptions.DatabaseClosed(db._state.dbOpenError));
}
if (!db._state.isBeingOpened) {
if (!db._state.autoOpen)
return rejection(new exceptions.DatabaseClosed());
db.open().catch(nop);
}
return db._state.dbReadyPromise.then(() => tempTransaction(db, mode, storeNames, fn));
}
else {
var trans = db._createTransaction(mode, storeNames, db._dbSchema);
try {
trans.create();
db._state.PR1398_maxLoop = 3;
}
catch (ex) {
if (ex.name === errnames.InvalidState &&
db.isOpen() &&
--db._state.PR1398_maxLoop > 0) {
console.warn('Dexie: Need to reopen db');
db.close({ disableAutoOpen: false });
return db.open().then(() => tempTransaction(db, mode, storeNames, fn));
}
return rejection(ex);
}
return trans
._promise(mode, (resolve, reject) => {
return newScope(() => {
PSD.trans = trans;
return fn(resolve, reject, trans);
});
})
.then((result) => {
if (mode === 'readwrite')
try {
trans.idbtrans.commit();
}
catch { }
return mode === 'readonly'
? result
: trans._completion.then(() => result);
});
}
}
const DEXIE_VERSION = '4.4.3';
const maxString = String.fromCharCode(65535);
const minKey = -Infinity;
const INVALID_KEY_ARGUMENT = 'Invalid key provided. Keys must be of type string, number, Date or Array<string | number | Date>.';
const STRING_EXPECTED = 'String expected.';
const DEFAULT_MAX_CONNECTIONS = 1000;
const DBNAMES_DB = '__dbnames';
const READONLY = 'readonly';
const READWRITE = 'readwrite';
function combine(filter1, filter2) {
return filter1
? filter2
? function () {
return (filter1.apply(this, arguments) && filter2.apply(this, arguments));
}
: filter1
: filter2;
}
const AnyRange = {
type: 3 ,
lower: -Infinity,
lowerOpen: false,
upper: [[]],
upperOpen: false,
};
function workaroundForUndefinedPrimKey(keyPath) {
return typeof keyPath === 'string' && !/\./.test(keyPath)
? (obj) => {
if (obj[keyPath] === undefined && keyPath in obj) {
obj = deepClone(obj);
delete obj[keyPath];
}
return obj;
}
: (obj) => obj;
}
function Entity() {
throw exceptions.Type(`Entity instances must never be new:ed. Instances are generated by the framework bypassing the constructor.`);
}
function cmp(a, b) {
try {
const ta = type(a);
const tb = type(b);
if (ta !== tb) {
if (ta === 'Array')
return 1;
if (tb === 'Array')
return -1;
if (ta === 'binary')
return 1;
if (tb === 'binary')
return -1;
if (ta === 'string')
return 1;
if (tb === 'string')
return -1;
if (ta === 'Date')
return 1;
if (tb !== 'Date')
return NaN;
return -1;
}
switch (ta) {
case 'number':
case 'Date':
case 'string':
return a > b ? 1 : a < b ? -1 : 0;
case 'binary': {
return compareUint8Arrays(getUint8Array(a), getUint8Array(b));
}
case 'Array':
return compareArrays(a, b);
}
}
catch { }
return NaN;
}
function compareArrays(a, b) {
const al = a.length;
const bl = b.length;
const l = al < bl ? al : bl;
for (let i = 0; i < l; ++i) {
const res = cmp(a[i], b[i]);
if (res !== 0)
return res;
}
return al === bl ? 0 : al < bl ? -1 : 1;
}
function compareUint8Arrays(a, b) {
const al = a.length;
const bl = b.length;
const l = al < bl ? al : bl;
for (let i = 0; i < l; ++i) {
if (a[i] !== b[i])
return a[i] < b[i] ? -1 : 1;
}
return al === bl ? 0 : al < bl ? -1 : 1;
}
function type(x) {
const t = typeof x;
if (t !== 'object')
return t;
if (ArrayBuffer.isView(x))
return 'binary';
const tsTag = toStringTag(x);
return tsTag === 'ArrayBuffer' ? 'binary' : tsTag;
}
function getUint8Array(a) {
if (a instanceof Uint8Array)
return a;
if (ArrayBuffer.isView(a))
return new Uint8Array(a.buffer, a.byteOffset, a.byteLength);
return new Uint8Array(a);
}
function builtInDeletionTrigger(table, keys, res) {
const { yProps } = table.schema;
if (!yProps)
return res;
if (keys && res.numFailures > 0)
keys = keys.filter((_, i) => !res.failures[i]);
return Promise.all(yProps.map(({ updatesTable }) => keys
? table.db.table(updatesTable).where('k').anyOf(keys).delete()
: table.db.table(updatesTable).clear())).then(() => res);
}
class PropModification {
execute(value) {
const spec = this['@@propmod'];
if (spec.add !== undefined) {
const term = spec.add;
if (isArray(term)) {
return [...(isArray(value) ? value : []), ...term].sort();
}
if (typeof term === 'number')
return (Number(value) || 0) + term;
if (typeof term === 'bigint') {
try {
return BigInt(value) + term;
}
catch {
return BigInt(0) + term;
}
}
throw new TypeError(`Invalid term ${term}`);
}
if (spec.remove !== undefined) {
const subtrahend = spec.remove;
if (isArray(subtrahend)) {
return isArray(value)
? value.filter((item) => !subtrahend.includes(item)).sort()
: [];
}
if (typeof subtrahend === 'number')
return Number(value) - subtrahend;
if (typeof subtrahend === 'bigint') {
try {
return BigInt(value) - subtrahend;
}
catch {
return BigInt(0) - subtrahend;
}
}
throw new TypeError(`Invalid subtrahend ${subtrahend}`);
}
const prefixToReplace = spec.replacePrefix?.[0];
if (prefixToReplace &&
typeof value === 'string' &&
value.startsWith(prefixToReplace)) {
return spec.replacePrefix[1] + value.substring(prefixToReplace.length);
}
return value;
}
constructor(spec) {
this['@@propmod'] = spec;
}
}
function applyUpdateSpec(obj, changes) {
const keyPaths = keys(changes);
const numKeys = keyPaths.length;
let anythingModified = false;
for (let i = 0; i < numKeys; ++i) {
const keyPath = keyPaths[i];
const value = changes[keyPath];
const origValue = getByKeyPath(obj, keyPath);
if (value instanceof PropModification) {
setByKeyPath(obj, keyPath, value.execute(origValue));
anythingModified = true;
}
else if (origValue !== value) {
setByKeyPath(obj, keyPath, value);
anythingModified = true;
}
}
return anythingModified;
}
class Table {
_trans(mode, fn, writeLocked) {
const trans = this._tx || PSD.trans;
const tableName = this.name;
const task = debug &&
typeof console !== 'undefined' &&
console.createTask &&
console.createTask(`Dexie: ${mode === 'readonly' ? 'read' : 'write'} ${this.name}`);
function checkTableInTransaction(resolve, reject, trans) {
if (!trans.schema[tableName])
throw new exceptions.NotFound('Table ' + tableName + ' not part of transaction');
return fn(trans.idbtrans, trans);
}
const wasRootExec = beginMicroTickScope();
try {
let p = trans && trans.db._novip === this.db._novip
? trans === PSD.trans
? trans._promise(mode, checkTableInTransaction, writeLocked)
: newScope(() => trans._promise(mode, checkTableInTransaction, writeLocked), { trans: trans, transless: PSD.transless || PSD })
: tempTransaction(this.db, mode, [this.name], checkTableInTransaction);
if (task) {
p._consoleTask = task;
p = p.catch((err) => {
console.trace(err);
return rejection(err);
});
}
return p;
}
finally {
if (wasRootExec)
endMicroTickScope();
}
}
get(keyOrCrit, cb) {
if (keyOrCrit && keyOrCrit.constructor === Object)
return this.where(keyOrCrit).first(cb);
if (keyOrCrit == null)
return rejection(new exceptions.Type(`Invalid argument to Table.get()`));
return this._trans('readonly', (trans) => {
return this.core
.get({ trans, key: keyOrCrit })
.then((res) => this.hook.reading.fire(res));
}).then(cb);
}
where(indexOrCrit) {
if (typeof indexOrCrit === 'string')
return new this.db.WhereClause(this, indexOrCrit);
if (isArray(indexOrCrit))
return new this.db.WhereClause(this, `[${indexOrCrit.join('+')}]`);
const keyPaths = keys(indexOrCrit);
if (keyPaths.length === 1)
return this.where(keyPaths[0]).equals(indexOrCrit[keyPaths[0]]);
const compoundIndex = this.schema.indexes
.concat(this.schema.primKey)
.filter((ix) => {
if (ix.compound &&
keyPaths.every((keyPath) => ix.keyPath.indexOf(keyPath) >= 0)) {
for (let i = 0; i < keyPaths.length; ++i) {
if (keyPaths.indexOf(ix.keyPath[i]) === -1)
return false;
}
return true;
}
return false;
})
.sort((a, b) => a.keyPath.length - b.keyPath.length)[0];
if (compoundIndex && this.db._maxKey !== maxString) {
const keyPathsInValidOrder = compoundIndex.keyPath.slice(0, keyPaths.length);
return this.where(keyPathsInValidOrder).equals(keyPathsInValidOrder.map((kp) => indexOrCrit[kp]));
}
if (!compoundIndex && debug)
console.warn(`The query ${JSON.stringify(indexOrCrit)} on ${this.name} would benefit from a ` +
`compound index [${keyPaths.join('+')}]`);
const { idxByName } = this.schema;
function equals(a, b) {
return cmp(a, b) === 0;
}
const [idx, filterFunction] = keyPaths.reduce(([prevIndex, prevFilterFn], keyPath) => {
const index = idxByName[keyPath];
const value = indexOrCrit[keyPath];
return [
prevIndex || index,
prevIndex || !index
? combine(prevFilterFn, index && index.multi
? (x) => {
const prop = getByKeyPath(x, keyPath);
return (isArray(prop) &&
prop.some((item) => equals(value, item)));
}
: (x) => equals(value, getByKeyPath(x, keyPath)))
: prevFilterFn,
];
}, [null, null]);
return idx
? this.where(idx.name)
.equals(indexOrCrit[idx.keyPath])
.filter(filterFunction)
: compoundIndex
? this.filter(filterFunction)
: this.where(keyPaths).equals('');
}
filter(filterFunction) {
return this.toCollection().and(filterFunction);
}
count(thenShortcut) {
return this.toCollection().count(thenShortcut);
}
offset(offset) {
return this.toCollection().offset(offset);
}
limit(numRows) {
return this.toCollection().limit(numRows);
}
each(callback) {
return this.toCollection().each(callback);
}
toArray(thenShortcut) {
return this.toCollection().toArray(thenShortcut);
}
toCollection() {
return new this.db.Collection(new this.db.WhereClause(this));
}
orderBy(index) {
return new this.db.Collection(new this.db.WhereClause(this, isArray(index) ? `[${index.join('+')}]` : index));
}
reverse() {
return this.toCollection().reverse();
}
mapToClass(constructor) {
const { db, name: tableName } = this;
this.schema.mappedClass = constructor;
if (constructor.prototype instanceof Entity) {
constructor = class extends constructor {
get db() {
return db;
}
table() {
return tableName;
}
};
}
const inheritedProps = new Set();
for (let proto = constructor.prototype; proto; proto = getProto(proto)) {
Object.getOwnPropertyNames(proto).forEach((propName) => inheritedProps.add(propName));
}
const readHook = (obj) => {
if (!obj)
return obj;
const res = Object.create(constructor.prototype);
for (let m in obj)
if (!inheritedProps.has(m))
try {
res[m] = obj[m];
}
catch (_) { }
return res;
};
if (this.schema.readHook) {
this.hook.reading.unsubscribe(this.schema.readHook);
}
this.schema.readHook = readHook;
this.hook('reading', readHook);
return constructor;
}
defineClass() {
function Class(content) {
extend(this, content);
}
return thi