indexeddbshim 17.3.1 → 17.3.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/IDBCursor.d.ts.map +1 -1
- package/dist/IDBFactory.d.ts.map +1 -1
- package/dist/IDBObjectStore.d.ts +28 -0
- package/dist/IDBObjectStore.d.ts.map +1 -1
- package/dist/IDBTransaction.d.ts.map +1 -1
- package/dist/indexeddbshim-Key.js +1 -1
- package/dist/indexeddbshim-Key.min.js +1 -1
- package/dist/indexeddbshim-UnicodeIdentifiers-node.cjs +507 -150
- package/dist/indexeddbshim-UnicodeIdentifiers-node.cjs.map +1 -1
- package/dist/indexeddbshim-UnicodeIdentifiers.js +334 -89
- package/dist/indexeddbshim-UnicodeIdentifiers.js.map +1 -1
- package/dist/indexeddbshim-UnicodeIdentifiers.min.js +3 -3
- package/dist/indexeddbshim-UnicodeIdentifiers.min.js.map +1 -1
- package/dist/indexeddbshim-node.cjs +507 -150
- package/dist/indexeddbshim-node.cjs.map +1 -1
- package/dist/indexeddbshim-noninvasive.js +334 -89
- package/dist/indexeddbshim-noninvasive.js.map +1 -1
- package/dist/indexeddbshim-noninvasive.min.js +3 -3
- package/dist/indexeddbshim-noninvasive.min.js.map +1 -1
- package/dist/indexeddbshim.js +334 -89
- package/dist/indexeddbshim.js.map +1 -1
- package/dist/indexeddbshim.min.js +3 -3
- package/dist/indexeddbshim.min.js.map +1 -1
- package/dist/nodeSQLiteDatabase.d.ts.map +1 -1
- package/dist/nodeWebSQL.d.ts.map +1 -1
- package/package.json +4 -3
- package/src/IDBCursor.js +34 -4
- package/src/IDBFactory.js +119 -21
- package/src/IDBObjectStore.js +103 -1
- package/src/IDBRecord.js +8 -0
- package/src/IDBTransaction.js +16 -2
- package/src/nodeSQLiteDatabase.js +92 -26
- package/src/nodeWebSQL.js +8 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! indexeddbshim - v17.3.
|
|
1
|
+
/*! indexeddbshim - v17.3.3 - 8/25/2026 */
|
|
2
2
|
|
|
3
3
|
'use strict';
|
|
4
4
|
|
|
@@ -5708,9 +5708,15 @@ IDBTransaction.prototype.__abortTransaction = function (err) {
|
|
|
5708
5708
|
if (err !== null) {
|
|
5709
5709
|
me.__error = err;
|
|
5710
5710
|
}
|
|
5711
|
-
if (me.__requestsFinished) {
|
|
5711
|
+
if (me.__requestsFinished && err !== null) {
|
|
5712
5712
|
// The transaction has already completed, so we can't call "onerror" or "onabort".
|
|
5713
|
-
// So throw the error instead.
|
|
5713
|
+
// So throw the error instead. `err` is only ever `null` here via
|
|
5714
|
+
// `IDBTransaction.prototype.abort`'s own `__abortTransaction(null)`
|
|
5715
|
+
// call, which now checks `__requestsFinished` itself first and
|
|
5716
|
+
// throws `InvalidStateError` synchronously before ever reaching
|
|
5717
|
+
// this point -- so this guard is just defense in depth against
|
|
5718
|
+
// `err` somehow being `null` some other way, not something this
|
|
5719
|
+
// path should see in practice.
|
|
5714
5720
|
setTimeout(() => {
|
|
5715
5721
|
throw err;
|
|
5716
5722
|
}, 0);
|
|
@@ -5828,6 +5834,14 @@ IDBTransaction.prototype.abort = function () {
|
|
|
5828
5834
|
if (me.__committed) {
|
|
5829
5835
|
throw createDOMException('InvalidStateError', 'The transaction has already been committed');
|
|
5830
5836
|
}
|
|
5837
|
+
if (me.__requestsFinished) {
|
|
5838
|
+
// All requests have already finished and the transaction is
|
|
5839
|
+
// auto-committing (the async SQL commit round trip just hasn't
|
|
5840
|
+
// resolved yet) -- too late to abort per spec, even though
|
|
5841
|
+
// `__committed` itself isn't set until that round trip actually
|
|
5842
|
+
// finishes.
|
|
5843
|
+
throw createDOMException('InvalidStateError', 'The transaction is already committing');
|
|
5844
|
+
}
|
|
5831
5845
|
me.__abortTransaction(null);
|
|
5832
5846
|
};
|
|
5833
5847
|
|
|
@@ -6135,8 +6149,8 @@ class Typeson {
|
|
|
6135
6149
|
{
|
|
6136
6150
|
sync: c
|
|
6137
6151
|
} = i,
|
|
6138
|
-
|
|
6139
|
-
|
|
6152
|
+
u = {},
|
|
6153
|
+
y = [],
|
|
6140
6154
|
l = [],
|
|
6141
6155
|
p = [],
|
|
6142
6156
|
f = !("cyclic" in i) || i.cyclic,
|
|
@@ -6145,14 +6159,14 @@ class Typeson {
|
|
|
6145
6159
|
encapsulateError: m
|
|
6146
6160
|
} = i,
|
|
6147
6161
|
finish = e => {
|
|
6148
|
-
const t = Object.values(
|
|
6162
|
+
const t = Object.values(u);
|
|
6149
6163
|
if (i.iterateNone) return t.length ? t[0] : getJSONType(e);
|
|
6150
6164
|
if (t.length) {
|
|
6151
6165
|
if (i.returnTypeNames) return [...new Set(t)];
|
|
6152
|
-
e && isPlainObject(e) && !n(e, "$types") ? e.$types =
|
|
6166
|
+
e && isPlainObject(e) && !n(e, "$types") ? e.$types = u : e = {
|
|
6153
6167
|
$: e,
|
|
6154
6168
|
$types: {
|
|
6155
|
-
$:
|
|
6169
|
+
$: u
|
|
6156
6170
|
}
|
|
6157
6171
|
};
|
|
6158
6172
|
} else isObject(e) && n(e, "$types") && (e = {
|
|
@@ -6166,10 +6180,10 @@ class Typeson {
|
|
|
6166
6180
|
return await Promise.all(r.map(async function (r) {
|
|
6167
6181
|
const n = [],
|
|
6168
6182
|
[a] = t.splice(0, 1),
|
|
6169
|
-
[o,, s, i, c,
|
|
6170
|
-
l = _encapsulate(o, r, s, i, n, true,
|
|
6183
|
+
[o,, s, i, c, u, y] = a,
|
|
6184
|
+
l = _encapsulate(o, r, s, i, n, true, y),
|
|
6171
6185
|
p = hasConstructorOf(l, TypesonPromise);
|
|
6172
|
-
return o && p ? (setOwnEnumerable(c,
|
|
6186
|
+
return o && p ? (setOwnEnumerable(c, u, await l.p), checkPromises(e, n)) : (o ? setOwnEnumerable(c, u, l) : e = p ? l.p : l, checkPromises(e, n));
|
|
6173
6187
|
})), e;
|
|
6174
6188
|
},
|
|
6175
6189
|
_adaptBuiltinStateObjectProperties = (e, t, r) => {
|
|
@@ -6229,11 +6243,11 @@ class Typeson {
|
|
|
6229
6243
|
})) : h = t, b && b(), h;
|
|
6230
6244
|
if (null === t) return b && b(), t;
|
|
6231
6245
|
if (o && t && "object" == typeof t && !s.iterateIn && !s.iterateUnsetNumeric) {
|
|
6232
|
-
const r =
|
|
6233
|
-
if (-1 !== r) return
|
|
6246
|
+
const r = y.indexOf(t);
|
|
6247
|
+
if (-1 !== r) return u[e] = "#", b && b({
|
|
6234
6248
|
cyclicKeypath: l[r]
|
|
6235
6249
|
}), "#" + l[r];
|
|
6236
|
-
true === o && (
|
|
6250
|
+
true === o && (y.push(t), l.push(e));
|
|
6237
6251
|
}
|
|
6238
6252
|
const v = isPlainObject(t),
|
|
6239
6253
|
w = a(t),
|
|
@@ -6297,16 +6311,16 @@ class Typeson {
|
|
|
6297
6311
|
},
|
|
6298
6312
|
replace = (e, t, r, n, a, o, s) => {
|
|
6299
6313
|
const i = a ? this.plainObjectReplacers : this.nonplainObjectReplacers;
|
|
6300
|
-
let
|
|
6301
|
-
for (;
|
|
6302
|
-
const a = i[
|
|
6314
|
+
let y = i.length;
|
|
6315
|
+
for (; y--;) {
|
|
6316
|
+
const a = i[y];
|
|
6303
6317
|
if (a.test(t, r)) {
|
|
6304
6318
|
const {
|
|
6305
6319
|
type: i
|
|
6306
6320
|
} = a;
|
|
6307
6321
|
if (Object.hasOwn(this.revivers, i)) {
|
|
6308
|
-
const t =
|
|
6309
|
-
|
|
6322
|
+
const t = u[e];
|
|
6323
|
+
u[e] = t ? [i].concat(t) : i;
|
|
6310
6324
|
}
|
|
6311
6325
|
if (Object.assign(r, {
|
|
6312
6326
|
type: i,
|
|
@@ -6314,14 +6328,14 @@ class Typeson {
|
|
|
6314
6328
|
}), (c || !a.replaceAsync) && !a.replace) return s && s({
|
|
6315
6329
|
typeDetected: true
|
|
6316
6330
|
}), _encapsulate(e, t, f && "readonly", r, n, o, i);
|
|
6317
|
-
let
|
|
6331
|
+
let y;
|
|
6318
6332
|
if (s && s({
|
|
6319
6333
|
replacing: true
|
|
6320
6334
|
}), c || !a.replaceAsync) {
|
|
6321
6335
|
if (void 0 === a.replace) throw new TypeError("Missing replacer");
|
|
6322
|
-
|
|
6323
|
-
} else
|
|
6324
|
-
return _encapsulate(e,
|
|
6336
|
+
y = a.replace(t, r);
|
|
6337
|
+
} else y = a.replaceAsync(t, r);
|
|
6338
|
+
return _encapsulate(e, y, f && "readonly", r, n, o, i);
|
|
6325
6339
|
}
|
|
6326
6340
|
}
|
|
6327
6341
|
return t;
|
|
@@ -6366,16 +6380,16 @@ class Typeson {
|
|
|
6366
6380
|
if (true === i) return finishRevival(e.$);
|
|
6367
6381
|
if (!i || "object" != typeof i || Array.isArray(i)) return finishRevival(e);
|
|
6368
6382
|
const c = [],
|
|
6369
|
-
|
|
6370
|
-
|
|
6383
|
+
u = Object.create(null),
|
|
6384
|
+
y = {};
|
|
6371
6385
|
let l = true;
|
|
6372
6386
|
i.$ && isPlainObject(i.$) && (e = e.$, i = i.$, l = false);
|
|
6373
6387
|
const executeReviver = (e, t) => {
|
|
6374
6388
|
const [r] = this.revivers[e] ?? [];
|
|
6375
6389
|
if (!r) throw new Error("Unregistered type: " + e);
|
|
6376
6390
|
if (s && !("revive" in r)) return t;
|
|
6377
|
-
if (!s && r.reviveAsync) return r.reviveAsync(t,
|
|
6378
|
-
if (r.revive) return r.revive(t,
|
|
6391
|
+
if (!s && r.reviveAsync) return r.reviveAsync(t, y);
|
|
6392
|
+
if (r.revive) return r.revive(t, y);
|
|
6379
6393
|
throw new Error("Missing reviver");
|
|
6380
6394
|
},
|
|
6381
6395
|
p = [];
|
|
@@ -6413,7 +6427,7 @@ class Typeson {
|
|
|
6413
6427
|
}, void 0);
|
|
6414
6428
|
})();
|
|
6415
6429
|
let d;
|
|
6416
|
-
return hasConstructorOf(f, TypesonPromise) ? d = f.then(() => e) : (d = function _revive(e, t, o,
|
|
6430
|
+
return hasConstructorOf(f, TypesonPromise) ? d = f.then(() => e) : (d = function _revive(e, t, o, y, f) {
|
|
6417
6431
|
if (l && "$types" === e) return;
|
|
6418
6432
|
const d = p.length,
|
|
6419
6433
|
m = n(i, e) ? i[e] : void 0,
|
|
@@ -6426,18 +6440,18 @@ class Typeson {
|
|
|
6426
6440
|
hasConstructorOf(n, TypesonPromise) ? p.push(n.then(e => set(e))) : set(n);
|
|
6427
6441
|
}), t = a; c.length;) {
|
|
6428
6442
|
const [[e, t, r, a]] = c,
|
|
6429
|
-
o = n(
|
|
6430
|
-
s = o ?
|
|
6443
|
+
o = n(u, t),
|
|
6444
|
+
s = o ? u[t] : getByKeyPath(e, t);
|
|
6431
6445
|
if (!o && void 0 === s) break;
|
|
6432
6446
|
setOwnEnumerable(r, a, s), c.shift();
|
|
6433
6447
|
}
|
|
6434
6448
|
}
|
|
6435
|
-
if (!m) return
|
|
6449
|
+
if (!m) return u[e] = t, t;
|
|
6436
6450
|
if ("#" === m) {
|
|
6437
6451
|
const e = t.slice(1),
|
|
6438
|
-
r = n(
|
|
6439
|
-
a = r ?
|
|
6440
|
-
return r || void 0 !== a || c.push([o, e,
|
|
6452
|
+
r = n(u, e),
|
|
6453
|
+
a = r ? u[e] : getByKeyPath(o, e);
|
|
6454
|
+
return r || void 0 !== a || c.push([o, e, y, f]), a;
|
|
6441
6455
|
}
|
|
6442
6456
|
const applyType = t => {
|
|
6443
6457
|
const r = [].concat(m).reduce(function reducer(e, t) {
|
|
@@ -6445,7 +6459,7 @@ class Typeson {
|
|
|
6445
6459
|
if ("string" != typeof t) throw new TypeError("Bad type JSON");
|
|
6446
6460
|
return executeReviver(t, e);
|
|
6447
6461
|
}, t);
|
|
6448
|
-
return hasConstructorOf(r, TypesonPromise) ? r.then(t => (
|
|
6462
|
+
return hasConstructorOf(r, TypesonPromise) ? r.then(t => (u[e] = t, t)) : (u[e] = r, r);
|
|
6449
6463
|
};
|
|
6450
6464
|
return !s && p.length > d ? TypesonPromise.all(p.slice(d)).then(() => applyType(t)) : applyType(t);
|
|
6451
6465
|
}("", e, null), p.length && (d = TypesonPromise.resolve(d).then(e => TypesonPromise.all([e, ...p])).then(([e]) => e))), isThenable(d) ? s && o.throwOnBadSyncType ? (() => {
|
|
@@ -6521,8 +6535,8 @@ class Typeson {
|
|
|
6521
6535
|
class Undefined {}
|
|
6522
6536
|
Undefined.__typeson__type__ = "TypesonUndefined";
|
|
6523
6537
|
const s = ["null", "boolean", "number", "string", "array", "object"];
|
|
6524
|
-
for (var i = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/", c = new Uint8Array(256),
|
|
6525
|
-
var
|
|
6538
|
+
for (var i = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/", c = new Uint8Array(256), u = 0; u < 64; u++) c[i.codePointAt(u)] = u;
|
|
6539
|
+
var y = function encode(e, t, r) {
|
|
6526
6540
|
null == r && (r = e.byteLength);
|
|
6527
6541
|
for (var n = new Uint8Array(e, 0, r), a = n.length, o = "", s = 0; s < a; s += 3) o += i[n[s] >> 2], o += i[(3 & n[s]) << 4 | n[s + 1] >> 4], o += i[(15 & n[s + 1]) << 2 | n[s + 2] >> 6], o += i[63 & n[s + 2]];
|
|
6528
6542
|
return a % 3 == 2 ? o = o.slice(0, -1) + "=" : a % 3 == 1 && (o = o.slice(0, -2) + "=="), o;
|
|
@@ -6535,10 +6549,10 @@ var u = function encode(e, t, r) {
|
|
|
6535
6549
|
o,
|
|
6536
6550
|
s,
|
|
6537
6551
|
i = .75 * e.length,
|
|
6538
|
-
|
|
6552
|
+
u = 0;
|
|
6539
6553
|
"=" === e[e.length - 1] && (i--, "=" === e[e.length - 2] && i--);
|
|
6540
|
-
for (var
|
|
6541
|
-
return
|
|
6554
|
+
for (var y = new ArrayBuffer(i, t), l = new Uint8Array(y), p = 0; p < r; p += 4) n = c[e.codePointAt(p)], a = c[e.codePointAt(p + 1)], o = c[e.codePointAt(p + 2)], s = c[e.codePointAt(p + 3)], l[u++] = n << 2 | a >> 4, l[u++] = (15 & a) << 4 | o >> 2, l[u++] = (3 & o) << 6 | 63 & s;
|
|
6555
|
+
return y;
|
|
6542
6556
|
};
|
|
6543
6557
|
const p = {
|
|
6544
6558
|
arraybuffer: {
|
|
@@ -6549,7 +6563,7 @@ const p = {
|
|
|
6549
6563
|
return -1 !== r ? {
|
|
6550
6564
|
index: r
|
|
6551
6565
|
} : (t.buffers.push(e), {
|
|
6552
|
-
s:
|
|
6566
|
+
s: y(e),
|
|
6553
6567
|
maxByteLength: e.maxByteLength,
|
|
6554
6568
|
resizable: e.resizable
|
|
6555
6569
|
});
|
|
@@ -6583,13 +6597,13 @@ const p = {
|
|
|
6583
6597
|
});
|
|
6584
6598
|
i.push(r), c += r;
|
|
6585
6599
|
}
|
|
6586
|
-
const
|
|
6587
|
-
let
|
|
6600
|
+
const u = new ArrayBuffer(c);
|
|
6601
|
+
let y = 0;
|
|
6588
6602
|
for (let t = 0; t < s; t++) {
|
|
6589
|
-
const r = new Uint8Array(
|
|
6603
|
+
const r = new Uint8Array(u, y, i[t]);
|
|
6590
6604
|
e.copyTo(r, {
|
|
6591
6605
|
planeIndex: t
|
|
6592
|
-
}),
|
|
6606
|
+
}), y += i[t];
|
|
6593
6607
|
}
|
|
6594
6608
|
return {
|
|
6595
6609
|
format: t,
|
|
@@ -6597,7 +6611,7 @@ const p = {
|
|
|
6597
6611
|
numberOfFrames: n,
|
|
6598
6612
|
numberOfChannels: a,
|
|
6599
6613
|
timestamp: o,
|
|
6600
|
-
data:
|
|
6614
|
+
data: u
|
|
6601
6615
|
};
|
|
6602
6616
|
},
|
|
6603
6617
|
revive: ({
|
|
@@ -6713,7 +6727,7 @@ const v = {
|
|
|
6713
6727
|
byteOffset: t,
|
|
6714
6728
|
byteLength: r
|
|
6715
6729
|
} : (n.buffers.push(e), {
|
|
6716
|
-
encoded:
|
|
6730
|
+
encoded: y(e),
|
|
6717
6731
|
maxByteLength: e.maxByteLength,
|
|
6718
6732
|
resizable: e.resizable,
|
|
6719
6733
|
byteOffset: t,
|
|
@@ -7199,7 +7213,7 @@ const X = {};
|
|
|
7199
7213
|
} : (n.buffers.push(e), {
|
|
7200
7214
|
maxByteLength: e.maxByteLength,
|
|
7201
7215
|
resizable: e.resizable,
|
|
7202
|
-
encoded:
|
|
7216
|
+
encoded: y(e),
|
|
7203
7217
|
byteOffset: t,
|
|
7204
7218
|
length: r
|
|
7205
7219
|
});
|
|
@@ -7214,10 +7228,10 @@ const X = {};
|
|
|
7214
7228
|
maxByteLength: i,
|
|
7215
7229
|
resizable: c
|
|
7216
7230
|
} = t;
|
|
7217
|
-
let
|
|
7218
|
-
return "index" in t ?
|
|
7231
|
+
let u;
|
|
7232
|
+
return "index" in t ? u = r.buffers[s] : (u = l(o, c ? {
|
|
7219
7233
|
maxByteLength: i
|
|
7220
|
-
} : void 0), r.buffers.push(
|
|
7234
|
+
} : void 0), r.buffers.push(u)), new e(u, n, a);
|
|
7221
7235
|
}
|
|
7222
7236
|
};
|
|
7223
7237
|
}(e));
|
|
@@ -7250,8 +7264,8 @@ const Y = {
|
|
|
7250
7264
|
duration: s,
|
|
7251
7265
|
visibleRect: i,
|
|
7252
7266
|
displayWidth: c,
|
|
7253
|
-
displayHeight:
|
|
7254
|
-
colorSpace:
|
|
7267
|
+
displayHeight: u,
|
|
7268
|
+
colorSpace: y
|
|
7255
7269
|
} = e,
|
|
7256
7270
|
l = new ArrayBuffer(e.allocationSize());
|
|
7257
7271
|
await e.copyTo(l), t({
|
|
@@ -7267,12 +7281,12 @@ const Y = {
|
|
|
7267
7281
|
height: i.height
|
|
7268
7282
|
},
|
|
7269
7283
|
displayWidth: c,
|
|
7270
|
-
displayHeight:
|
|
7284
|
+
displayHeight: u,
|
|
7271
7285
|
colorSpace: {
|
|
7272
|
-
primaries:
|
|
7273
|
-
transfer:
|
|
7274
|
-
matrix:
|
|
7275
|
-
fullRange:
|
|
7286
|
+
primaries: y.primaries,
|
|
7287
|
+
transfer: y.transfer,
|
|
7288
|
+
matrix: y.matrix,
|
|
7289
|
+
fullRange: y.fullRange
|
|
7276
7290
|
},
|
|
7277
7291
|
data: l
|
|
7278
7292
|
});
|
|
@@ -7290,8 +7304,8 @@ const Y = {
|
|
|
7290
7304
|
displayWidth: s,
|
|
7291
7305
|
displayHeight: i,
|
|
7292
7306
|
colorSpace: c,
|
|
7293
|
-
data:
|
|
7294
|
-
}) => new VideoFrame(new Uint8Array(
|
|
7307
|
+
data: u
|
|
7308
|
+
}) => new VideoFrame(new Uint8Array(u), {
|
|
7295
7309
|
format: e,
|
|
7296
7310
|
codedWidth: t,
|
|
7297
7311
|
codedHeight: r,
|
|
@@ -7345,11 +7359,11 @@ const Y = {
|
|
|
7345
7359
|
}],
|
|
7346
7360
|
ne = [D, M, L, F],
|
|
7347
7361
|
ce = [Z, Y, re, K, ne, O, z, U, _, B, I, h, N, C].concat("function" == typeof Map ? k : [], "function" == typeof Set ? H : [], "function" == typeof ArrayBuffer ? p : [], "function" == typeof Uint8Array ? X : [], "function" == typeof DataView ? w : [], "undefined" != typeof crypto ? v : [], "undefined" != typeof BigInt ? [m, d] : [], "undefined" != typeof DOMException ? A : [], "undefined" != typeof QuotaExceededError ? W : [], "undefined" != typeof WebTransportError ? te : [], "undefined" != typeof DOMRect ? x : [], "undefined" != typeof DOMPoint ? S : [], "undefined" != typeof DOMQuad ? P : [], "undefined" != typeof DOMMatrix ? T : [], "undefined" != typeof AudioData ? f : [], "undefined" != typeof EncodedAudioChunk ? E : [], "undefined" != typeof EncodedVideoChunk ? j : [], "undefined" != typeof VideoFrame ? ee : []);
|
|
7348
|
-
const
|
|
7362
|
+
const ue = ce.concat({
|
|
7349
7363
|
checkDataCloneException: {
|
|
7350
7364
|
test(e) {
|
|
7351
7365
|
const t = {}.toString.call(e).slice(8, -1);
|
|
7352
|
-
if (["symbol", "function"].includes(typeof e) || ["Arguments", "Module", "Promise", "WeakMap", "WeakSet", "Event", "MessageChannel"].includes(t) || ["ArrayBuffer", "DataView", "Int8Array", "Uint8Array", "Uint8ClampedArray", "Int16Array", "Uint16Array", "Int32Array", "Uint32Array", "Float32Array", "Float64Array", "BigInt64Array", "BigUint64Array"].includes(t) && function isBufferDetached(e) {
|
|
7366
|
+
if (["symbol", "function"].includes(typeof e) || ["Arguments", "Module", "Promise", "WeakMap", "WeakSet", "Event", "MessageChannel", "MessagePort"].includes(t) || e && e.constructor && ["MessageChannel", "MessagePort"].includes(e.constructor.name) || ["ArrayBuffer", "DataView", "Int8Array", "Uint8Array", "Uint8ClampedArray", "Int16Array", "Uint16Array", "Int32Array", "Uint32Array", "Float32Array", "Float64Array", "BigInt64Array", "BigUint64Array"].includes(t) && function isBufferDetached(e) {
|
|
7353
7367
|
if ("boolean" == typeof e.detached) return e.detached;
|
|
7354
7368
|
if (0 !== e.byteLength) return false;
|
|
7355
7369
|
try {
|
|
@@ -7365,7 +7379,7 @@ const ye = ce.concat({
|
|
|
7365
7379
|
|
|
7366
7380
|
// See: https://stackoverflow.com/questions/42170826/categories-for-rejection-by-the-structured-cloning-algorithm
|
|
7367
7381
|
|
|
7368
|
-
let typeson = new Typeson().register(
|
|
7382
|
+
let typeson = new Typeson().register(ue);
|
|
7369
7383
|
|
|
7370
7384
|
/**
|
|
7371
7385
|
* @param {(preset: import('typeson-registry').Preset) =>
|
|
@@ -7374,7 +7388,7 @@ let typeson = new Typeson().register(ye);
|
|
|
7374
7388
|
*/
|
|
7375
7389
|
function register(func) {
|
|
7376
7390
|
// eslint-disable-next-line unicorn/no-top-level-assignment-in-function -- Should be one-time cache
|
|
7377
|
-
typeson = new Typeson().register(func(
|
|
7391
|
+
typeson = new Typeson().register(func(ue));
|
|
7378
7392
|
}
|
|
7379
7393
|
|
|
7380
7394
|
/**
|
|
@@ -8424,6 +8438,11 @@ const IDBObjectStoreAlias = IDBObjectStore;
|
|
|
8424
8438
|
* success: (key: import('./Key.js').Key, cn?: Integer) => void,
|
|
8425
8439
|
* failCb: import('./Key.js').SQLFailureCallback
|
|
8426
8440
|
* ) => void,
|
|
8441
|
+
* __checkIndexConstraints: (
|
|
8442
|
+
* tx: WebSQLTransaction,
|
|
8443
|
+
* value: import('./Key.js').Value,
|
|
8444
|
+
* excludeKey: import('./Key.js').Key|Integer|undefined
|
|
8445
|
+
* ) => SyncPromise,
|
|
8427
8446
|
* __insertData: (
|
|
8428
8447
|
* tx: WebSQLTransaction,
|
|
8429
8448
|
* encoded: string,
|
|
@@ -8844,6 +8863,69 @@ IDBObjectStore.prototype.__deriveKey = function (tx, value, key, success, failCb
|
|
|
8844
8863
|
}
|
|
8845
8864
|
};
|
|
8846
8865
|
|
|
8866
|
+
/**
|
|
8867
|
+
* Validates `value`'s unique index entries against the table's *current*
|
|
8868
|
+
* state without mutating anything -- used by `__storingRecordObjectStore`
|
|
8869
|
+
* to check a `put()`'s constraints *before* `__overwrite` deletes the
|
|
8870
|
+
* existing row for that key, so a rejected `put()` can't end up losing
|
|
8871
|
+
* the record it was trying to replace (see
|
|
8872
|
+
* `idbobjectstore-put-unique-index-constraint-is-atomic.any.js`).
|
|
8873
|
+
* `excludeKey`, when given, treats a conflicting record as a non-conflict
|
|
8874
|
+
* if it's the very record being overwritten (its own current entry would
|
|
8875
|
+
* otherwise self-conflict on every no-op `put()` of an unchanged value).
|
|
8876
|
+
* `__insertData` below still runs its own (now redundant, but harmless --
|
|
8877
|
+
* the old row is gone by then) equivalent check as its first step; this
|
|
8878
|
+
* isn't merged into it because `__insertData` also performs the actual
|
|
8879
|
+
* `INSERT`, which cannot safely run before `__overwrite`'s `DELETE` when
|
|
8880
|
+
* overwriting an existing key.
|
|
8881
|
+
* @param {WebSQLTransaction} tx
|
|
8882
|
+
* @param {import('./Key.js').Value} value
|
|
8883
|
+
* @param {import('./Key.js').Key|Integer|undefined} excludeKey
|
|
8884
|
+
* @this {IDBObjectStoreFull}
|
|
8885
|
+
* @returns {SyncPromise}
|
|
8886
|
+
*/
|
|
8887
|
+
IDBObjectStore.prototype.__checkIndexConstraints = function (tx, value, excludeKey) {
|
|
8888
|
+
const me = this;
|
|
8889
|
+
const indexPromises = Object.keys(me.__indexes).map(indexName => {
|
|
8890
|
+
return new SyncPromise((resolve, reject) => {
|
|
8891
|
+
const index = me.__indexes[indexName];
|
|
8892
|
+
if (index.__pendingCreate || index.__deleted || !index.unique) {
|
|
8893
|
+
resolve(undefined);
|
|
8894
|
+
return;
|
|
8895
|
+
}
|
|
8896
|
+
/**
|
|
8897
|
+
* @type {import('./Key.js').KeyValueObject|
|
|
8898
|
+
* import('./Key.js').KeyPathEvaluateValue}
|
|
8899
|
+
*/
|
|
8900
|
+
let indexKey;
|
|
8901
|
+
try {
|
|
8902
|
+
indexKey = extractKeyValueDecodedFromValueUsingKeyPath(value, index.keyPath, index.multiEntry);
|
|
8903
|
+
if ('invalid' in indexKey && indexKey.invalid || 'failure' in indexKey && indexKey.failure) {
|
|
8904
|
+
throw new Error('Go to catch');
|
|
8905
|
+
}
|
|
8906
|
+
} catch (err) {
|
|
8907
|
+
resolve(undefined);
|
|
8908
|
+
return;
|
|
8909
|
+
}
|
|
8910
|
+
indexKey = indexKey.value;
|
|
8911
|
+
if (indexKey === undefined) {
|
|
8912
|
+
resolve(undefined);
|
|
8913
|
+
return;
|
|
8914
|
+
}
|
|
8915
|
+
const multiCheck = index.multiEntry && Array.isArray(indexKey);
|
|
8916
|
+
const fetchArgs = buildFetchIndexDataSQL(true, index, indexKey, 'key', multiCheck);
|
|
8917
|
+
executeFetchIndexData(null, ...fetchArgs, tx, null, function success(key) {
|
|
8918
|
+
if (key === undefined || excludeKey !== undefined && cmp(key, excludeKey) === 0) {
|
|
8919
|
+
resolve(undefined);
|
|
8920
|
+
return;
|
|
8921
|
+
}
|
|
8922
|
+
reject(createDOMException('ConstraintError', 'Index already contains a record equal to ' + (multiCheck ? 'one of the subkeys of' : '') + '`indexKey`'));
|
|
8923
|
+
}, reject);
|
|
8924
|
+
});
|
|
8925
|
+
});
|
|
8926
|
+
return SyncPromise.all(indexPromises);
|
|
8927
|
+
};
|
|
8928
|
+
|
|
8847
8929
|
/**
|
|
8848
8930
|
*
|
|
8849
8931
|
* @param {WebSQLTransaction} tx
|
|
@@ -9096,7 +9178,32 @@ IDBObjectStore.__storingRecordObjectStore = function (request, store, invalidate
|
|
|
9096
9178
|
}, error);
|
|
9097
9179
|
}
|
|
9098
9180
|
if (!noOverwrite) {
|
|
9099
|
-
|
|
9181
|
+
// Validate unique index constraints *before* `__overwrite`
|
|
9182
|
+
// deletes the existing row at this key -- otherwise a
|
|
9183
|
+
// `put()` that ends up rejected still permanently loses
|
|
9184
|
+
// the record it was trying to replace (see
|
|
9185
|
+
// `idbobjectstore-put-unique-index-constraint-is-atomic.any.js`).
|
|
9186
|
+
store.__checkIndexConstraints(tx, value, clonedKeyOrCurrentNumber).then(() => {
|
|
9187
|
+
store.__overwrite(tx, clonedKeyOrCurrentNumber, insert, error);
|
|
9188
|
+
return undefined;
|
|
9189
|
+
/**
|
|
9190
|
+
* @param {Error|DOMException} err
|
|
9191
|
+
* @returns {null}
|
|
9192
|
+
*/
|
|
9193
|
+
}).catch(function (err) {
|
|
9194
|
+
/**
|
|
9195
|
+
* @returns {void}
|
|
9196
|
+
*/
|
|
9197
|
+
function fail() {
|
|
9198
|
+
error(err);
|
|
9199
|
+
}
|
|
9200
|
+
if (typeof oldCn === 'number') {
|
|
9201
|
+
assignCurrentNumber(tx, store, oldCn, fail, fail);
|
|
9202
|
+
return null;
|
|
9203
|
+
}
|
|
9204
|
+
fail();
|
|
9205
|
+
return null;
|
|
9206
|
+
});
|
|
9100
9207
|
return;
|
|
9101
9208
|
}
|
|
9102
9209
|
insert(tx);
|
|
@@ -9970,7 +10077,29 @@ function triggerAnyVersionChangeAndBlockedEvents(openConnections, req, oldVersio
|
|
|
9970
10077
|
return new SyncPromise(function (resolve) {
|
|
9971
10078
|
setTimeout(() => {
|
|
9972
10079
|
entry.dispatchEvent(e); // No need to catch errors
|
|
9973
|
-
|
|
10080
|
+
// Unlike a native `Promise`, `SyncPromise#then` chains
|
|
10081
|
+
// synchronously off `resolve()` (verified directly:
|
|
10082
|
+
// `SyncPromise.resolve().then(cb)` runs `cb` before
|
|
10083
|
+
// even the calling code below it finishes) -- so
|
|
10084
|
+
// resolving immediately here would let the
|
|
10085
|
+
// `connectionsClosed()` check below run before a
|
|
10086
|
+
// same-task-but-microtask-later continuation of a
|
|
10087
|
+
// `versionchange` listener above (e.g. an `await`-
|
|
10088
|
+
// based one that then calls `db.close()`, as in
|
|
10089
|
+
// `transaction-lifetime.any.js`) ever gets a turn,
|
|
10090
|
+
// incorrectly firing `blocked` even though the
|
|
10091
|
+
// connection was about to close in time. Give real
|
|
10092
|
+
// microtask-deferred continuations a small, bounded
|
|
10093
|
+
// number of turns first -- same pattern as
|
|
10094
|
+
// `IDBTransaction.js`'s `checkQueueEntry`.
|
|
10095
|
+
let attemptsLeft = 10;
|
|
10096
|
+
(function wait() {
|
|
10097
|
+
if (attemptsLeft-- <= 0) {
|
|
10098
|
+
resolve(undefined);
|
|
10099
|
+
return;
|
|
10100
|
+
}
|
|
10101
|
+
queueMicrotask(wait);
|
|
10102
|
+
})();
|
|
9974
10103
|
}, 0);
|
|
9975
10104
|
});
|
|
9976
10105
|
});
|
|
@@ -10030,6 +10159,23 @@ function triggerAnyVersionChangeAndBlockedEvents(openConnections, req, oldVersio
|
|
|
10030
10159
|
*/
|
|
10031
10160
|
const websqlDBCache = {};
|
|
10032
10161
|
|
|
10162
|
+
/**
|
|
10163
|
+
* Tracks databases with a creation/upgrade currently in flight but not yet
|
|
10164
|
+
* committed or aborted -- keyed by (unescaped) database name. The
|
|
10165
|
+
* `dbVersions` row in `sysdb` these entries shadow is written *before*
|
|
10166
|
+
* `upgradeneeded` is even dispatched to user code (as the success
|
|
10167
|
+
* callback of that very `INSERT`/`UPDATE`), on the same shared `sysdb`
|
|
10168
|
+
* connection `databases()` itself reads from -- so, absent this, a
|
|
10169
|
+
* `databases()` call made while an upgrade is still pending would see
|
|
10170
|
+
* the new row (or new version) immediately, rather than only once the
|
|
10171
|
+
* corresponding `versionchange` transaction has genuinely committed, as
|
|
10172
|
+
* required by `get-databases.any.js`'s "doesn't pick up changes that
|
|
10173
|
+
* haven't committed" test. `IDBFactory.prototype.databases` filters
|
|
10174
|
+
* its SQL results against this map.
|
|
10175
|
+
* @type {Map<string, {oldVersion: Integer, newVersion: Integer}>}
|
|
10176
|
+
*/
|
|
10177
|
+
const pendingVersionChanges = new Map();
|
|
10178
|
+
|
|
10033
10179
|
/** @type {import('websql-configurable/lib/websql/WebSQLDatabase.js').default} */
|
|
10034
10180
|
let sysdb;
|
|
10035
10181
|
let nameCounter = 0;
|
|
@@ -10332,6 +10478,19 @@ IDBFactory.prototype.open = function (name /* , version */) {
|
|
|
10332
10478
|
if (calledDbCreateError) {
|
|
10333
10479
|
return false;
|
|
10334
10480
|
}
|
|
10481
|
+
// Defensive cleanup: `pendingVersionChanges.set(name, ...)` (see
|
|
10482
|
+
// below) runs *before* the `dbVersions` `INSERT`/`UPDATE` it
|
|
10483
|
+
// guards is even attempted, but only `versionSet`'s own
|
|
10484
|
+
// `on__beforecomplete`/`on__preabort` handlers ever clear it --
|
|
10485
|
+
// and `versionSet` never runs at all if that `INSERT`/`UPDATE`,
|
|
10486
|
+
// or an earlier step in this same `open()` flow, fails first.
|
|
10487
|
+
// Without this, such a failure would leave the entry orphaned
|
|
10488
|
+
// forever, silently corrupting `databases()` for any *other*,
|
|
10489
|
+
// unrelated later `open()` call that happens to reuse the same
|
|
10490
|
+
// database name (common in WPT tests, e.g. generic names like
|
|
10491
|
+
// "DB1"/"TestDatabase" reused across different test files in
|
|
10492
|
+
// the same process). A no-op if no entry was ever set.
|
|
10493
|
+
pendingVersionChanges.delete(name);
|
|
10335
10494
|
const er = err ? webSQLErrback(err) : (/** @type {Error} */tx);
|
|
10336
10495
|
calledDbCreateError = true;
|
|
10337
10496
|
// Re: why bubbling here (and how cancelable is only really relevant for `window.onerror`) see: https://github.com/w3c/IndexedDB/issues/86
|
|
@@ -10443,22 +10602,43 @@ IDBFactory.prototype.open = function (name /* , version */) {
|
|
|
10443
10602
|
// open/close the transaction's active-handler window itself.
|
|
10444
10603
|
req.transaction.__handlerActive = true;
|
|
10445
10604
|
req.dispatchEvent(e);
|
|
10446
|
-
// Give any
|
|
10605
|
+
// Give any microtask-scheduled continuation of the
|
|
10447
10606
|
// `upgradeneeded` handler (e.g. a plain
|
|
10448
|
-
// `Promise.resolve().then(...)
|
|
10449
|
-
//
|
|
10450
|
-
//
|
|
10451
|
-
//
|
|
10452
|
-
//
|
|
10453
|
-
//
|
|
10454
|
-
//
|
|
10455
|
-
//
|
|
10456
|
-
//
|
|
10457
|
-
//
|
|
10458
|
-
//
|
|
10459
|
-
|
|
10460
|
-
|
|
10461
|
-
|
|
10607
|
+
// `Promise.resolve().then(...)`, or an `await`-based
|
|
10608
|
+
// continuation of a promise resolved from within the handler,
|
|
10609
|
+
// such as testharness.js's own `EventWatcher`) a chance to
|
|
10610
|
+
// run -- and still observe the transaction as active -- before
|
|
10611
|
+
// we deactivate it again, per
|
|
10612
|
+
// https://github.com/w3c/IndexedDB/issues/87. A single deferred
|
|
10613
|
+
// tick isn't always enough: an `await`-based continuation can
|
|
10614
|
+
// take more than one microtask turn to resume (e.g.
|
|
10615
|
+
// `transaction-lifetime.any.js`'s `EventWatcher`-based
|
|
10616
|
+
// `await eventWatcher.wait_for('upgradeneeded')`), so retry a
|
|
10617
|
+
// small, bounded number of times first -- same pattern as
|
|
10618
|
+
// `IDBTransaction.js`'s `checkQueueEntry` -- rather than
|
|
10619
|
+
// resetting after only one. Only the flag reset itself is
|
|
10620
|
+
// deferred here -- unlike `IDBTransaction.js`'s
|
|
10621
|
+
// `advanceAfterDispatch`, `finished()` (this transaction's own
|
|
10622
|
+
// queue-advancement/completion signal) still runs
|
|
10623
|
+
// synchronously, at exactly its previous timing: an earlier
|
|
10624
|
+
// attempt at deferring `finished()` too raced against unrelated
|
|
10625
|
+
// test setup that assumed a freshly deleted/created database's
|
|
10626
|
+
// upgrade transaction had already fully completed by the time
|
|
10627
|
+
// this function returns.
|
|
10628
|
+
/**
|
|
10629
|
+
* @param {Integer} attemptsLeft
|
|
10630
|
+
* @returns {void}
|
|
10631
|
+
*/
|
|
10632
|
+
function deferHandlerActiveReset(attemptsLeft) {
|
|
10633
|
+
if (attemptsLeft <= 0) {
|
|
10634
|
+
req.transaction.__handlerActive = false;
|
|
10635
|
+
return;
|
|
10636
|
+
}
|
|
10637
|
+
queueMicrotask(() => {
|
|
10638
|
+
deferHandlerActiveReset(attemptsLeft - 1);
|
|
10639
|
+
});
|
|
10640
|
+
}
|
|
10641
|
+
deferHandlerActiveReset(10);
|
|
10462
10642
|
if (e.__legacyOutputDidListenersThrowError) {
|
|
10463
10643
|
logError('Error', 'An error occurred in an upgradeneeded handler attached to request chain', /** @type {Error} */e.__legacyOutputDidListenersThrowError); // We do nothing else with this error as per spec
|
|
10464
10644
|
req.transaction.__abortTransaction(createDOMException('AbortError', 'A request was aborted.'));
|
|
@@ -10474,6 +10654,7 @@ IDBFactory.prototype.open = function (name /* , version */) {
|
|
|
10474
10654
|
* @returns {void}
|
|
10475
10655
|
*/
|
|
10476
10656
|
function (ev) {
|
|
10657
|
+
pendingVersionChanges.delete(name);
|
|
10477
10658
|
connection.__upgradeTransaction = null;
|
|
10478
10659
|
/** @type {import('./IDBDatabase.js').IDBDatabaseFull} */
|
|
10479
10660
|
req.__result.__versionTransaction = null;
|
|
@@ -10488,6 +10669,7 @@ IDBFactory.prototype.open = function (name /* , version */) {
|
|
|
10488
10669
|
|
|
10489
10670
|
// eslint-disable-next-line camelcase -- Clear API
|
|
10490
10671
|
req.transaction.on__preabort = function () {
|
|
10672
|
+
pendingVersionChanges.delete(name);
|
|
10491
10673
|
connection.__upgradeTransaction = null;
|
|
10492
10674
|
// We ensure any cache is deleted before any request error events fire and try to reopen
|
|
10493
10675
|
if (useDatabaseCache) {
|
|
@@ -10550,6 +10732,10 @@ IDBFactory.prototype.open = function (name /* , version */) {
|
|
|
10550
10732
|
// });
|
|
10551
10733
|
};
|
|
10552
10734
|
}
|
|
10735
|
+
pendingVersionChanges.set(name, {
|
|
10736
|
+
oldVersion,
|
|
10737
|
+
newVersion: version
|
|
10738
|
+
});
|
|
10553
10739
|
if (oldVersion === 0) {
|
|
10554
10740
|
systx.executeSql('INSERT INTO dbVersions VALUES (?,?)', [sqlSafeName, version], versionSet, dbCreateError);
|
|
10555
10741
|
} else {
|
|
@@ -10853,6 +11039,15 @@ IDBFactory.prototype.cmp = function (key1, key2) {
|
|
|
10853
11039
|
IDBFactory.prototype.databases = function () {
|
|
10854
11040
|
const me = this;
|
|
10855
11041
|
let calledDbCreateError = false;
|
|
11042
|
+
// Snapshotted *now*, synchronously, at call time -- not read later
|
|
11043
|
+
// from inside the SQL query's callback below, which runs on a
|
|
11044
|
+
// deferred macrotask (see `nodeSQLiteDatabase.js`'s `exec`) and so
|
|
11045
|
+
// could otherwise race against (and lose to) an in-flight upgrade's
|
|
11046
|
+
// own commit/abort handler clearing its `pendingVersionChanges`
|
|
11047
|
+
// entry in the meantime -- which would make this method incorrectly
|
|
11048
|
+
// reflect a since-committed change that hadn't committed yet when
|
|
11049
|
+
// it was actually called.
|
|
11050
|
+
const pendingVersionChangesSnapshot = new Map(pendingVersionChanges);
|
|
10856
11051
|
return new Promise(function (resolve, reject) {
|
|
10857
11052
|
// eslint-disable-line promise/avoid-new -- Own polyfill
|
|
10858
11053
|
if (!(me instanceof IDBFactory)) {
|
|
@@ -10882,11 +11077,30 @@ IDBFactory.prototype.databases = function () {
|
|
|
10882
11077
|
const dbNames = [];
|
|
10883
11078
|
for (let i = 0; i < data.rows.length; i++) {
|
|
10884
11079
|
const {
|
|
10885
|
-
name,
|
|
11080
|
+
name: encodedName,
|
|
10886
11081
|
version
|
|
10887
11082
|
} = /** @type {{name: string, version: Integer}} */data.rows.item(i);
|
|
11083
|
+
const name = unescapeSQLiteResponse(encodedName);
|
|
11084
|
+
// A row for a database whose creation/upgrade hasn't
|
|
11085
|
+
// committed yet (see `pendingVersionChanges`) must
|
|
11086
|
+
// not reflect that in-flight change: a brand new
|
|
11087
|
+
// database (`oldVersion === 0`) isn't reported at
|
|
11088
|
+
// all until its creation commits, and an existing
|
|
11089
|
+
// database being upgraded is still reported, but
|
|
11090
|
+
// with its pre-upgrade version.
|
|
11091
|
+
const pending = pendingVersionChangesSnapshot.get(name);
|
|
11092
|
+
if (pending) {
|
|
11093
|
+
if (pending.oldVersion === 0) {
|
|
11094
|
+
continue;
|
|
11095
|
+
}
|
|
11096
|
+
dbNames.push({
|
|
11097
|
+
name,
|
|
11098
|
+
version: pending.oldVersion
|
|
11099
|
+
});
|
|
11100
|
+
continue;
|
|
11101
|
+
}
|
|
10888
11102
|
dbNames.push({
|
|
10889
|
-
name
|
|
11103
|
+
name,
|
|
10890
11104
|
version
|
|
10891
11105
|
});
|
|
10892
11106
|
}
|
|
@@ -11034,6 +11248,14 @@ readonlyProperties.forEach(prop => {
|
|
|
11034
11248
|
* @returns {import('./Key.js').Key|import('./Key.js').Value}
|
|
11035
11249
|
*/
|
|
11036
11250
|
get [prop]() {
|
|
11251
|
+
// This is defined on the *shared* prototype (see above), so,
|
|
11252
|
+
// unlike a per-instance getter, it's reachable by calling it
|
|
11253
|
+
// directly on `IDBRecord.prototype` itself (not a real
|
|
11254
|
+
// instance) -- WebIDL requires that to throw.
|
|
11255
|
+
if (!(this instanceof IDBRecordAlias)) {
|
|
11256
|
+
throw new TypeError('Illegal invocation');
|
|
11257
|
+
}
|
|
11258
|
+
// @ts-ignore `this` is a real instance past the check above (not an issue in TS7)
|
|
11037
11259
|
return this['__' + prop];
|
|
11038
11260
|
}
|
|
11039
11261
|
};
|
|
@@ -11291,9 +11513,26 @@ IDBCursor.prototype.__findBasic = function (key, primaryKey, tx, success, error,
|
|
|
11291
11513
|
// Key.convertValueToKey(key); // Already checked by `continue` or `continuePrimaryKey`
|
|
11292
11514
|
sqlValues.push(/** @type {string} */encode$1(key));
|
|
11293
11515
|
} else if (continueCall && me.__key !== undefined) {
|
|
11294
|
-
sql.push('AND', quotedKeyColumnName, op + ' ?');
|
|
11295
11516
|
// Key.convertValueToKey(me.__key); // Already checked when stored
|
|
11296
|
-
|
|
11517
|
+
if (!me.__unique && me.__keyColumnName !== 'key' && me.__primaryKey !== undefined) {
|
|
11518
|
+
// A plain `continue()` on a non-unique index cursor must find
|
|
11519
|
+
// the next record strictly after the (key, primaryKey) pair
|
|
11520
|
+
// this cursor last returned -- a scalar `key > lastKey` alone
|
|
11521
|
+
// would wrongly exclude a *different*, not-yet-visited record
|
|
11522
|
+
// that's still tied on key with the last one (e.g. another
|
|
11523
|
+
// record that always had that same indexed value), and would
|
|
11524
|
+
// also wrongly re-admit the *same* record forever if a
|
|
11525
|
+
// same-transaction `update()` bumped its own key back above
|
|
11526
|
+
// the threshold, since a scalar comparison can't distinguish
|
|
11527
|
+
// "some other record newly tied" from "this record moved
|
|
11528
|
+
// past its own last position." Comparing the full tuple (via
|
|
11529
|
+
// this OR) against both key and primary key resolves both.
|
|
11530
|
+
sql.push('AND (', quotedKeyColumnName, op, '?', 'OR (', quotedKeyColumnName, '= ?', 'AND', quotedKey, op, '?))');
|
|
11531
|
+
sqlValues.push(/** @type {string} */encode$1(me.__key), /** @type {string} */encode$1(me.__key), /** @type {string} */encode$1(me.__primaryKey));
|
|
11532
|
+
} else {
|
|
11533
|
+
sql.push('AND', quotedKeyColumnName, op + ' ?');
|
|
11534
|
+
sqlValues.push(/** @type {string} */encode$1(me.__key));
|
|
11535
|
+
}
|
|
11297
11536
|
}
|
|
11298
11537
|
if (!me.__count) {
|
|
11299
11538
|
// 1. Sort by key
|
|
@@ -11907,9 +12146,15 @@ IDBCursor.prototype.update = function (valueToUpdate) {
|
|
|
11907
12146
|
* @returns {void}
|
|
11908
12147
|
*/
|
|
11909
12148
|
function addToQueue(clonedValue) {
|
|
11910
|
-
//
|
|
12149
|
+
// `invalidateCache: true` so any cursor on this store (including
|
|
12150
|
+
// this one) drops its prefetched row batch, forcing its next
|
|
12151
|
+
// `continue()` to re-query live rather than serve rows snapshotted
|
|
12152
|
+
// before this update -- needed for the compound-tuple
|
|
12153
|
+
// continuation logic in `__findBasic` to see this update's
|
|
12154
|
+
// effect on ordering (see "Modify records during cursor
|
|
12155
|
+
// iteration" in idbcursor_update_index.any.js).
|
|
11911
12156
|
// @ts-ignore -- API (not erring in TS 6)
|
|
11912
|
-
IDBObjectStore.__storingRecordObjectStore(request, me.__store,
|
|
12157
|
+
IDBObjectStore.__storingRecordObjectStore(request, me.__store, true, clonedValue, false, key);
|
|
11913
12158
|
}
|
|
11914
12159
|
if (me.__store.keyPath !== null) {
|
|
11915
12160
|
const [evaluatedKey, clonedValue] = me.__store.__validateKeyAndValueAndCloneValue(valueToUpdate, undefined, true);
|
|
@@ -13031,11 +13276,9 @@ function runBatch(self, batch) {
|
|
|
13031
13276
|
self._running = false;
|
|
13032
13277
|
runAllSql(self);
|
|
13033
13278
|
}
|
|
13034
|
-
const currentTask = /** @type {import('./WebSQLDatabase.js').TransactionTask} */
|
|
13035
|
-
self._websqlDatabase._currentTask;
|
|
13036
13279
|
const {
|
|
13037
13280
|
readOnly
|
|
13038
|
-
} =
|
|
13281
|
+
} = self._task;
|
|
13039
13282
|
self._websqlDatabase._db.exec(batch, readOnly, function (err, results) {
|
|
13040
13283
|
/* c8 ignore next */
|
|
13041
13284
|
if (err || !results) {
|
|
@@ -13123,10 +13366,12 @@ function executeSql(self, sql, args, sqlCallback, sqlErrorCallback, executeDelay
|
|
|
13123
13366
|
class WebSQLTransaction {
|
|
13124
13367
|
/**
|
|
13125
13368
|
* @param {import('./WebSQLDatabase.js').default} websqlDatabase
|
|
13369
|
+
* @param {import('./WebSQLDatabase.js').TransactionTask} task
|
|
13126
13370
|
* @param {import('../types.js').Delay} [executeDelay]
|
|
13127
13371
|
*/
|
|
13128
|
-
constructor(websqlDatabase, executeDelay) {
|
|
13372
|
+
constructor(websqlDatabase, task, executeDelay) {
|
|
13129
13373
|
this._websqlDatabase = websqlDatabase;
|
|
13374
|
+
this._task = task;
|
|
13130
13375
|
/** @type {Error | null} */
|
|
13131
13376
|
this._error = null;
|
|
13132
13377
|
this._complete = false;
|
|
@@ -13135,11 +13380,14 @@ class WebSQLTransaction {
|
|
|
13135
13380
|
this._executeDelay = executeDelay || immediate;
|
|
13136
13381
|
/** @type {import('tiny-queue').default<SQLTask>} */
|
|
13137
13382
|
this._sqlQueue = new Queue();
|
|
13138
|
-
|
|
13139
|
-
|
|
13140
|
-
|
|
13141
|
-
//
|
|
13142
|
-
//
|
|
13383
|
+
if (!task.readOnly) {
|
|
13384
|
+
// A read-only task never needs a transaction wrapper for its own
|
|
13385
|
+
// sake (reads don't need atomicity against each other) -- true
|
|
13386
|
+
// whether or not `concurrentReaders` (see `WebSQLDatabase`) lets
|
|
13387
|
+
// multiple read-only tasks actually run at once. This is a perf
|
|
13388
|
+
// boost either way. A non-read-only task always still gets one, and
|
|
13389
|
+
// always still runs with full exclusivity (see
|
|
13390
|
+
// `WebSQLDatabase#runNextTransaction`).
|
|
13143
13391
|
this._sqlQueue.push(new SQLTask('BEGIN;', [], noop, noop));
|
|
13144
13392
|
}
|
|
13145
13393
|
}
|
|
@@ -13220,39 +13468,68 @@ class WebSQLDatabase {
|
|
|
13220
13468
|
this._db = db;
|
|
13221
13469
|
/** @type {import('tiny-queue').default<TransactionTask>} */
|
|
13222
13470
|
this._txnQueue = new Queue();
|
|
13223
|
-
|
|
13471
|
+
// Off by default: queued transactions -- read or write alike -- run
|
|
13472
|
+
// strictly one at a time, in the order requested, per the WebSQL spec
|
|
13473
|
+
// (see `#runNextTransaction`). When true, any number of read-only
|
|
13474
|
+
// tasks may instead run concurrently; a non-read-only task still
|
|
13475
|
+
// always runs with full exclusivity either way.
|
|
13476
|
+
this._concurrentReaders = Boolean(webSQLOverrides.concurrentReaders);
|
|
13477
|
+
/** @type {Set<TransactionTask>} */
|
|
13478
|
+
this._activeReaders = new Set();
|
|
13224
13479
|
/** @type {TransactionTask | null} */
|
|
13225
|
-
this.
|
|
13480
|
+
this._activeWriter = null;
|
|
13226
13481
|
this._transactionDelay = webSQLOverrides.transactionDelay || immediate;
|
|
13227
13482
|
this._executeDelay = webSQLOverrides.executeDelay || immediate;
|
|
13228
13483
|
}
|
|
13229
13484
|
|
|
13230
13485
|
/**
|
|
13231
|
-
*
|
|
13486
|
+
* @param {TransactionTask} task
|
|
13232
13487
|
*/
|
|
13233
|
-
#runTransaction() {
|
|
13234
|
-
const txn = new WebSQLTransaction(this, this._executeDelay);
|
|
13488
|
+
#runTransaction(task) {
|
|
13489
|
+
const txn = new WebSQLTransaction(this, task, this._executeDelay);
|
|
13235
13490
|
this._transactionDelay(() => {
|
|
13236
|
-
|
|
13237
|
-
currentTask.txnCallback(txn);
|
|
13491
|
+
task.txnCallback(txn);
|
|
13238
13492
|
txn._checkDone();
|
|
13239
13493
|
});
|
|
13240
13494
|
}
|
|
13241
13495
|
|
|
13242
13496
|
/**
|
|
13243
|
-
*
|
|
13497
|
+
* Starts as many queued tasks as the current lock state allows. With
|
|
13498
|
+
* `concurrentReaders` off (the default), a task only starts once
|
|
13499
|
+
* nothing else is active at all -- full mutual exclusion, matching the
|
|
13500
|
+
* WebSQL spec's strict one-at-a-time, in-request-order guarantee (see
|
|
13501
|
+
* this file's own test suite, "callback order 2"). With it on, any
|
|
13502
|
+
* leading run of read-only tasks can all start together instead
|
|
13503
|
+
* (concurrent reads are always fine); a non-read-only task still needs
|
|
13504
|
+
* exclusivity regardless, so nothing past it may start until it
|
|
13505
|
+
* finishes. Not starvation-proof in the `concurrentReaders` case -- a
|
|
13506
|
+
* steady stream of arriving readers could in principle keep a waiting
|
|
13507
|
+
* writer waiting indefinitely -- but that's an acceptable tradeoff over
|
|
13508
|
+
* the added complexity of tracking arrival order across reader/writer
|
|
13509
|
+
* kinds.
|
|
13244
13510
|
*/
|
|
13245
13511
|
#runNextTransaction() {
|
|
13246
|
-
|
|
13247
|
-
|
|
13248
|
-
|
|
13249
|
-
|
|
13250
|
-
|
|
13251
|
-
|
|
13512
|
+
for (;;) {
|
|
13513
|
+
const [nextTask] = this._txnQueue.slice(0, 1);
|
|
13514
|
+
if (!nextTask) {
|
|
13515
|
+
return;
|
|
13516
|
+
}
|
|
13517
|
+
const readerMayShare = this._concurrentReaders && nextTask.readOnly;
|
|
13518
|
+
if (readerMayShare) {
|
|
13519
|
+
if (this._activeWriter) {
|
|
13520
|
+
return;
|
|
13521
|
+
}
|
|
13522
|
+
} else if (this._activeWriter || this._activeReaders.size) {
|
|
13523
|
+
return;
|
|
13524
|
+
}
|
|
13525
|
+
this._txnQueue.shift();
|
|
13526
|
+
if (nextTask.readOnly) {
|
|
13527
|
+
this._activeReaders.add(nextTask);
|
|
13528
|
+
} else {
|
|
13529
|
+
this._activeWriter = nextTask;
|
|
13530
|
+
}
|
|
13531
|
+
this.#runTransaction(nextTask);
|
|
13252
13532
|
}
|
|
13253
|
-
this._currentTask = task;
|
|
13254
|
-
this._running = true;
|
|
13255
|
-
this.#runTransaction();
|
|
13256
13533
|
}
|
|
13257
13534
|
|
|
13258
13535
|
/**
|
|
@@ -13280,6 +13557,7 @@ class WebSQLDatabase {
|
|
|
13280
13557
|
*/
|
|
13281
13558
|
// eslint-disable-next-line unicorn/prefer-private-class-fields -- see above
|
|
13282
13559
|
_onTransactionComplete(err, transaction) {
|
|
13560
|
+
const task = transaction._task;
|
|
13283
13561
|
/**
|
|
13284
13562
|
* @param {Error | boolean | null} [er]
|
|
13285
13563
|
*/
|
|
@@ -13294,14 +13572,15 @@ class WebSQLDatabase {
|
|
|
13294
13572
|
transaction._complete = true;
|
|
13295
13573
|
}
|
|
13296
13574
|
if (er) {
|
|
13297
|
-
|
|
13298
|
-
|
|
13299
|
-
|
|
13300
|
-
}
|
|
13301
|
-
|
|
13575
|
+
task.errorCallback(/** @type {Error} */er);
|
|
13576
|
+
} else {
|
|
13577
|
+
task.successCallback();
|
|
13578
|
+
}
|
|
13579
|
+
if (task.readOnly) {
|
|
13580
|
+
this._activeReaders.delete(task);
|
|
13581
|
+
} else if (this._activeWriter === task) {
|
|
13582
|
+
this._activeWriter = null;
|
|
13302
13583
|
}
|
|
13303
|
-
this._running = false;
|
|
13304
|
-
this._currentTask = null;
|
|
13305
13584
|
this.#runNextTransaction();
|
|
13306
13585
|
};
|
|
13307
13586
|
/**
|
|
@@ -13327,13 +13606,13 @@ class WebSQLDatabase {
|
|
|
13327
13606
|
}
|
|
13328
13607
|
});
|
|
13329
13608
|
};
|
|
13330
|
-
if (
|
|
13331
|
-
const cont =
|
|
13609
|
+
if (task.nonstandardTransCb) {
|
|
13610
|
+
const cont = task.nonstandardTransCb.call(this, task, err, done, rollback, commit);
|
|
13332
13611
|
if (!cont) {
|
|
13333
13612
|
return;
|
|
13334
13613
|
}
|
|
13335
13614
|
}
|
|
13336
|
-
if (
|
|
13615
|
+
if (task.readOnly) {
|
|
13337
13616
|
done(err); // read-only doesn't require a transaction
|
|
13338
13617
|
} else if (err) {
|
|
13339
13618
|
rollback(err);
|
|
@@ -14291,16 +14570,28 @@ const READ_ONLY_ERROR = new Error('could not prepare statement (23 not authorize
|
|
|
14291
14570
|
// connection and a newly-opened one during an upgrade. `PRAGMA
|
|
14292
14571
|
// busy_timeout` can't safely arbitrate between them here: it blocks the
|
|
14293
14572
|
// single JS thread synchronously while it retries, but the lock holder's
|
|
14294
|
-
// own release is itself scheduled via `
|
|
14295
|
-
// fire while that retry loop is blocking the same thread -- so
|
|
14296
|
-
// waiting,
|
|
14297
|
-
// locked".
|
|
14298
|
-
//
|
|
14299
|
-
//
|
|
14573
|
+
// own release is itself scheduled via `setImmediate` below, which can
|
|
14574
|
+
// never fire while that retry loop is blocking the same thread -- so
|
|
14575
|
+
// instead of waiting, a second connection's write just fails with
|
|
14576
|
+
// "database is locked".
|
|
14577
|
+
//
|
|
14578
|
+
// `fileReaders`/`fileWriter` implement a simple (not starvation-proof --
|
|
14579
|
+
// see the release loop below) reader/writer lock per file path instead:
|
|
14580
|
+
// any number of `readonly` transactions may hold the file concurrently,
|
|
14581
|
+
// matching what SQLite itself already natively supports (multiple
|
|
14582
|
+
// readers never need to exclude each other, only a writer needs
|
|
14583
|
+
// exclusivity), while a non-`readonly` transaction still waits for
|
|
14584
|
+
// exclusive access -- no concurrent readers, no concurrent writer. A
|
|
14585
|
+
// simple single-owner mutex (this file's prior implementation) would
|
|
14586
|
+
// otherwise serialize even purely-concurrent-reader scenarios that
|
|
14587
|
+
// never touch a writer at all, for no reason `better-sqlite3`/SQLite
|
|
14588
|
+
// itself requires.
|
|
14589
|
+
/** @type {Map<string, Set<{_db: any, _qFilePath: string}>>} */
|
|
14590
|
+
const fileReaders = new Map();
|
|
14300
14591
|
/** @type {Map<string, {_db: any, _qFilePath: string}>} */
|
|
14301
|
-
const
|
|
14302
|
-
/** @type {Map<string, (
|
|
14303
|
-
const
|
|
14592
|
+
const fileWriter = new Map();
|
|
14593
|
+
/** @type {Map<string, {isReader: boolean, resume: () => void}[]>} */
|
|
14594
|
+
const fileWaiters = new Map();
|
|
14304
14595
|
const beginRe = /^\s*BEGIN\b/iu;
|
|
14305
14596
|
const endRe = /^\s*(END|COMMIT|ROLLBACK)\b/iu;
|
|
14306
14597
|
|
|
@@ -14412,14 +14703,29 @@ SQLiteDatabase.prototype.exec = function exec(queries, readOnly, callback) {
|
|
|
14412
14703
|
// already fully independent -- so there is nothing to serialize.
|
|
14413
14704
|
const filePath = this._qFilePath === ':memory:' ? null : this._qFilePath;
|
|
14414
14705
|
if (filePath && queries[0] && beginRe.test(queries[0].sql)) {
|
|
14415
|
-
const
|
|
14416
|
-
|
|
14417
|
-
|
|
14418
|
-
|
|
14419
|
-
|
|
14706
|
+
const activeReaders = fileReaders.get(filePath);
|
|
14707
|
+
const hasActiveReaders = Boolean(activeReaders && activeReaders.size);
|
|
14708
|
+
const activeWriter = fileWriter.get(filePath);
|
|
14709
|
+
const blockedByWriter = Boolean(activeWriter && activeWriter !== this);
|
|
14710
|
+
const blocked = blockedByWriter || !readOnly && hasActiveReaders;
|
|
14711
|
+
if (blocked) {
|
|
14712
|
+
const waiters = fileWaiters.get(filePath) || [];
|
|
14713
|
+
waiters.push({
|
|
14714
|
+
isReader: readOnly,
|
|
14715
|
+
resume: () => this.exec(queries, readOnly, callback)
|
|
14716
|
+
});
|
|
14717
|
+
fileWaiters.set(filePath, waiters);
|
|
14420
14718
|
return;
|
|
14421
14719
|
}
|
|
14422
|
-
|
|
14720
|
+
if (readOnly) {
|
|
14721
|
+
if (activeReaders) {
|
|
14722
|
+
activeReaders.add(this);
|
|
14723
|
+
} else {
|
|
14724
|
+
fileReaders.set(filePath, new Set([this]));
|
|
14725
|
+
}
|
|
14726
|
+
} else {
|
|
14727
|
+
fileWriter.set(filePath, this);
|
|
14728
|
+
}
|
|
14423
14729
|
}
|
|
14424
14730
|
const db = this._db._db;
|
|
14425
14731
|
const len = queries.length;
|
|
@@ -14461,13 +14767,15 @@ SQLiteDatabase.prototype.exec = function exec(queries, readOnly, callback) {
|
|
|
14461
14767
|
}
|
|
14462
14768
|
}
|
|
14463
14769
|
}
|
|
14464
|
-
// A real
|
|
14465
|
-
//
|
|
14466
|
-
//
|
|
14770
|
+
// A real macrotask (not `queueMicrotask`) so this yields properly:
|
|
14771
|
+
// code that synchronously issues a new request from within each
|
|
14772
|
+
// request's callback (e.g. to keep a transaction alive) would
|
|
14467
14773
|
// otherwise chain microtask to microtask forever, starving out any
|
|
14468
14774
|
// `setTimeout`-based code (including IndexedDB's own internal request
|
|
14469
|
-
// scheduling) that never gets a turn to run.
|
|
14470
|
-
setTimeout(
|
|
14775
|
+
// scheduling) that never gets a turn to run. `setImmediate` (Node's
|
|
14776
|
+
// "check" phase) still yields the same way `setTimeout(..., 0)` did,
|
|
14777
|
+
// but runs sooner in Node's event loop.
|
|
14778
|
+
setImmediate(() => {
|
|
14471
14779
|
// Release the file lock (if held) and hand it to the next waiting
|
|
14472
14780
|
// connection, if any, only once this transaction has genuinely
|
|
14473
14781
|
// finished -- and only here, on its own turn, so a resumed
|
|
@@ -14482,15 +14790,52 @@ SQLiteDatabase.prototype.exec = function exec(queries, readOnly, callback) {
|
|
|
14482
14790
|
// and never see the matching release, deadlocking every later
|
|
14483
14791
|
// connection to the same file.
|
|
14484
14792
|
if (filePath && queries.some(q => endRe.test(q.sql))) {
|
|
14485
|
-
|
|
14486
|
-
|
|
14487
|
-
|
|
14488
|
-
|
|
14489
|
-
|
|
14793
|
+
const activeReaders = fileReaders.get(filePath);
|
|
14794
|
+
if (activeReaders) {
|
|
14795
|
+
activeReaders.delete(this);
|
|
14796
|
+
if (!activeReaders.size) {
|
|
14797
|
+
fileReaders.delete(filePath);
|
|
14798
|
+
}
|
|
14799
|
+
}
|
|
14800
|
+
if (fileWriter.get(filePath) === this) {
|
|
14801
|
+
fileWriter.delete(filePath);
|
|
14802
|
+
}
|
|
14803
|
+
// Resume as many waiters as the lock now genuinely allows:
|
|
14804
|
+
// any leading run of readers (concurrent reads are always
|
|
14805
|
+
// fine), then at most one writer, since a writer needs
|
|
14806
|
+
// exclusivity -- stop there rather than looking past it.
|
|
14807
|
+
// Not starvation-proof: a steady stream of arriving readers
|
|
14808
|
+
// could in principle keep a waiting writer waiting
|
|
14809
|
+
// indefinitely, but that's an acceptable tradeoff here over
|
|
14810
|
+
// the added complexity of tracking arrival order across
|
|
14811
|
+
// reader/writer kinds.
|
|
14812
|
+
const waiters = fileWaiters.get(filePath);
|
|
14813
|
+
if (waiters) {
|
|
14814
|
+
while (waiters.length) {
|
|
14815
|
+
if (fileWriter.has(filePath)) {
|
|
14816
|
+
break;
|
|
14817
|
+
}
|
|
14818
|
+
const next = waiters[0];
|
|
14819
|
+
const stillHasReaders = fileReaders.get(filePath);
|
|
14820
|
+
if (!next.isReader && stillHasReaders && stillHasReaders.size) {
|
|
14821
|
+
break;
|
|
14822
|
+
}
|
|
14823
|
+
waiters.shift();
|
|
14824
|
+
next.resume();
|
|
14825
|
+
if (!next.isReader) {
|
|
14826
|
+
// A writer just took exclusive ownership (inside
|
|
14827
|
+
// `resume()`, synchronously, via the acquire
|
|
14828
|
+
// logic above) -- nothing else may proceed now.
|
|
14829
|
+
break;
|
|
14830
|
+
}
|
|
14831
|
+
}
|
|
14832
|
+
if (!waiters.length) {
|
|
14833
|
+
fileWaiters.delete(filePath);
|
|
14834
|
+
}
|
|
14490
14835
|
}
|
|
14491
14836
|
}
|
|
14492
14837
|
callback(null, results);
|
|
14493
|
-
}
|
|
14838
|
+
});
|
|
14494
14839
|
};
|
|
14495
14840
|
|
|
14496
14841
|
/**
|
|
@@ -14530,7 +14875,19 @@ function wrappedSQLiteDatabase(name) {
|
|
|
14530
14875
|
}
|
|
14531
14876
|
return db;
|
|
14532
14877
|
}
|
|
14533
|
-
|
|
14878
|
+
|
|
14879
|
+
// `concurrentReaders` is off by default in `websql-configurable` itself (to
|
|
14880
|
+
// preserve the WebSQL spec's strict, one-at-a-time transaction ordering
|
|
14881
|
+
// that library's own test suite depends on), but IndexedDBShim only ever
|
|
14882
|
+
// uses it as an internal SQL execution engine -- it doesn't need or expose
|
|
14883
|
+
// that ordering guarantee itself -- so it's safe, and needed, to opt in
|
|
14884
|
+
// here: without it, two same-scope `readonly` IDBTransactions can deadlock
|
|
14885
|
+
// waiting on each other (see `transaction-scheduling-within-database.any.js`).
|
|
14886
|
+
const nodeWebSQL = customOpenDatabase(/** @type {SQLiteDatabaseConstructor} */ /** @type {unknown} */wrappedSQLiteDatabase, {
|
|
14887
|
+
websql: {
|
|
14888
|
+
concurrentReaders: true
|
|
14889
|
+
}
|
|
14890
|
+
});
|
|
14534
14891
|
|
|
14535
14892
|
// ID_Start (includes Other_ID_Start)
|
|
14536
14893
|
const UnicodeIDStart = String.raw`(?:[$A-Z_a-z\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u052F\u0531-\u0556\u0559\u0561-\u0587\u05D0-\u05EA\u05F0-\u05F2\u0620-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u08A0-\u08B4\u08B6-\u08BD\u0904-\u0939\u093D\u0950\u0958-\u0961\u0971-\u0980\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09F0\u09F1\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0AF9\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D\u0C58-\u0C5A\u0C60\u0C61\u0C80\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0CF1\u0CF2\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D\u0D4E\u0D54-\u0D56\u0D5F-\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6\u0EDC-\u0EDF\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081\u108E\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F5\u13F8-\u13FD\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F8\u1700-\u170C\u170E-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7\u17DC\u1820-\u1877\u1880-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191E\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u1A00-\u1A16\u1A20-\u1A54\u1AA7\u1B05-\u1B33\u1B45-\u1B4B\u1B83-\u1BA0\u1BAE\u1BAF\u1BBA-\u1BE5\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C7D\u1C80-\u1C88\u1CE9-\u1CEC\u1CEE-\u1CF1\u1CF5\u1CF6\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2071\u207F\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2118-\u211D\u2124\u2126\u2128\u212A-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2160-\u2188\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303C\u3041-\u3096\u309B-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FD5\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B\uA640-\uA66E\uA67F-\uA69D\uA6A0-\uA6EF\uA717-\uA71F\uA722-\uA788\uA78B-\uA7AE\uA7B0-\uA7B7\uA7F7-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB\uA8FD\uA90A-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF\uA9E0-\uA9E4\uA9E6-\uA9EF\uA9FA-\uA9FE\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA76\uAA7A\uAA7E-\uAAAF\uAAB1\uAAB5\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB65\uAB70-\uABE2\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]|\uD800[\uDC00-\uDC0B\uDC0D-\uDC26\uDC28-\uDC3A\uDC3C\uDC3D\uDC3F-\uDC4D\uDC50-\uDC5D\uDC80-\uDCFA\uDD40-\uDD74\uDE80-\uDE9C\uDEA0-\uDED0\uDF00-\uDF1F\uDF30-\uDF4A\uDF50-\uDF75\uDF80-\uDF9D\uDFA0-\uDFC3\uDFC8-\uDFCF\uDFD1-\uDFD5]|\uD801[\uDC00-\uDC9D\uDCB0-\uDCD3\uDCD8-\uDCFB\uDD00-\uDD27\uDD30-\uDD63\uDE00-\uDF36\uDF40-\uDF55\uDF60-\uDF67]|\uD802[\uDC00-\uDC05\uDC08\uDC0A-\uDC35\uDC37\uDC38\uDC3C\uDC3F-\uDC55\uDC60-\uDC76\uDC80-\uDC9E\uDCE0-\uDCF2\uDCF4\uDCF5\uDD00-\uDD15\uDD20-\uDD39\uDD80-\uDDB7\uDDBE\uDDBF\uDE00\uDE10-\uDE13\uDE15-\uDE17\uDE19-\uDE33\uDE60-\uDE7C\uDE80-\uDE9C\uDEC0-\uDEC7\uDEC9-\uDEE4\uDF00-\uDF35\uDF40-\uDF55\uDF60-\uDF72\uDF80-\uDF91]|\uD803[\uDC00-\uDC48\uDC80-\uDCB2\uDCC0-\uDCF2]|\uD804[\uDC03-\uDC37\uDC83-\uDCAF\uDCD0-\uDCE8\uDD03-\uDD26\uDD50-\uDD72\uDD76\uDD83-\uDDB2\uDDC1-\uDDC4\uDDDA\uDDDC\uDE00-\uDE11\uDE13-\uDE2B\uDE80-\uDE86\uDE88\uDE8A-\uDE8D\uDE8F-\uDE9D\uDE9F-\uDEA8\uDEB0-\uDEDE\uDF05-\uDF0C\uDF0F\uDF10\uDF13-\uDF28\uDF2A-\uDF30\uDF32\uDF33\uDF35-\uDF39\uDF3D\uDF50\uDF5D-\uDF61]|\uD805[\uDC00-\uDC34\uDC47-\uDC4A\uDC80-\uDCAF\uDCC4\uDCC5\uDCC7\uDD80-\uDDAE\uDDD8-\uDDDB\uDE00-\uDE2F\uDE44\uDE80-\uDEAA\uDF00-\uDF19]|\uD806[\uDCA0-\uDCDF\uDCFF\uDEC0-\uDEF8]|\uD807[\uDC00-\uDC08\uDC0A-\uDC2E\uDC40\uDC72-\uDC8F]|\uD808[\uDC00-\uDF99]|\uD809[\uDC00-\uDC6E\uDC80-\uDD43]|[\uD80C\uD81C-\uD820\uD840-\uD868\uD86A-\uD86C\uD86F-\uD872][\uDC00-\uDFFF]|\uD80D[\uDC00-\uDC2E]|\uD811[\uDC00-\uDE46]|\uD81A[\uDC00-\uDE38\uDE40-\uDE5E\uDED0-\uDEED\uDF00-\uDF2F\uDF40-\uDF43\uDF63-\uDF77\uDF7D-\uDF8F]|\uD81B[\uDF00-\uDF44\uDF50\uDF93-\uDF9F\uDFE0]|\uD821[\uDC00-\uDFEC]|\uD822[\uDC00-\uDEF2]|\uD82C[\uDC00\uDC01]|\uD82F[\uDC00-\uDC6A\uDC70-\uDC7C\uDC80-\uDC88\uDC90-\uDC99]|\uD835[\uDC00-\uDC54\uDC56-\uDC9C\uDC9E\uDC9F\uDCA2\uDCA5\uDCA6\uDCA9-\uDCAC\uDCAE-\uDCB9\uDCBB\uDCBD-\uDCC3\uDCC5-\uDD05\uDD07-\uDD0A\uDD0D-\uDD14\uDD16-\uDD1C\uDD1E-\uDD39\uDD3B-\uDD3E\uDD40-\uDD44\uDD46\uDD4A-\uDD50\uDD52-\uDEA5\uDEA8-\uDEC0\uDEC2-\uDEDA\uDEDC-\uDEFA\uDEFC-\uDF14\uDF16-\uDF34\uDF36-\uDF4E\uDF50-\uDF6E\uDF70-\uDF88\uDF8A-\uDFA8\uDFAA-\uDFC2\uDFC4-\uDFCB]|\uD83A[\uDC00-\uDCC4\uDD00-\uDD43]|\uD83B[\uDE00-\uDE03\uDE05-\uDE1F\uDE21\uDE22\uDE24\uDE27\uDE29-\uDE32\uDE34-\uDE37\uDE39\uDE3B\uDE42\uDE47\uDE49\uDE4B\uDE4D-\uDE4F\uDE51\uDE52\uDE54\uDE57\uDE59\uDE5B\uDE5D\uDE5F\uDE61\uDE62\uDE64\uDE67-\uDE6A\uDE6C-\uDE72\uDE74-\uDE77\uDE79-\uDE7C\uDE7E\uDE80-\uDE89\uDE8B-\uDE9B\uDEA1-\uDEA3\uDEA5-\uDEA9\uDEAB-\uDEBB]|\uD869[\uDC00-\uDED6\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D\uDC20-\uDFFF]|\uD873[\uDC00-\uDEA1]|\uD87E[\uDC00-\uDE1D])`;
|