dexie-cloud-addon 4.2.0 → 4.2.2
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/dexie-cloud-import.json +6 -0
- package/dist/modern/dexie-cloud-addon.js +193 -68
- package/dist/modern/dexie-cloud-addon.js.map +1 -1
- package/dist/modern/dexie-cloud-addon.min.js +1 -1
- package/dist/modern/dexie-cloud-addon.min.js.map +1 -1
- package/dist/modern/service-worker.js +193 -68
- package/dist/modern/service-worker.js.map +1 -1
- package/dist/modern/service-worker.min.js +1 -1
- package/dist/modern/service-worker.min.js.map +1 -1
- package/dist/umd/dexie-cloud-addon.js +194 -69
- package/dist/umd/dexie-cloud-addon.js.map +1 -1
- package/dist/umd/dexie-cloud-addon.min.js +1 -1
- package/dist/umd/dexie-cloud-addon.min.js.map +1 -1
- package/dist/umd/service-worker.js +194 -69
- package/dist/umd/service-worker.js.map +1 -1
- package/dist/umd/service-worker.min.js +1 -1
- package/dist/umd/service-worker.min.js.map +1 -1
- package/package.json +4 -4
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
*
|
|
9
9
|
* ==========================================================================
|
|
10
10
|
*
|
|
11
|
-
* Version 4.2.
|
|
11
|
+
* Version 4.2.2, Sat Oct 04 2025
|
|
12
12
|
*
|
|
13
13
|
* https://dexie.org
|
|
14
14
|
*
|
|
@@ -1653,17 +1653,14 @@ function listClientChanges(mutationTables_1, db_1) {
|
|
|
1653
1653
|
: mutationTable;
|
|
1654
1654
|
if (limit < Infinity)
|
|
1655
1655
|
query = query.limit(limit);
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
mut.values = await objTable.bulkGet(mut.keys);
|
|
1661
|
-
}
|
|
1662
|
-
}*/
|
|
1663
|
-
return muts.map((mut) => ({
|
|
1656
|
+
let muts = yield query.toArray();
|
|
1657
|
+
muts = canonicalizeToUpdateOps(muts);
|
|
1658
|
+
muts = removeRedundantUpdateOps(muts);
|
|
1659
|
+
const rv = muts.map((mut) => ({
|
|
1664
1660
|
table: tableName,
|
|
1665
1661
|
mut,
|
|
1666
1662
|
}));
|
|
1663
|
+
return rv;
|
|
1667
1664
|
})));
|
|
1668
1665
|
// Sort by time to get a true order of the operations (between tables)
|
|
1669
1666
|
const sorted = flatten(allMutsOnTables).sort((a, b) => a.mut.txid === b.mut.txid
|
|
@@ -1692,6 +1689,69 @@ function listClientChanges(mutationTables_1, db_1) {
|
|
|
1692
1689
|
return result;
|
|
1693
1690
|
});
|
|
1694
1691
|
}
|
|
1692
|
+
function removeRedundantUpdateOps(muts) {
|
|
1693
|
+
const updateCoverage = new Map();
|
|
1694
|
+
for (const mut of muts) {
|
|
1695
|
+
if (mut.type === 'update') {
|
|
1696
|
+
if (mut.keys.length !== 1 || mut.changeSpecs.length !== 1) {
|
|
1697
|
+
continue; // Don't optimize multi-key updates
|
|
1698
|
+
}
|
|
1699
|
+
const strKey = '' + mut.keys[0];
|
|
1700
|
+
const changeSpecs = mut.changeSpecs[0];
|
|
1701
|
+
if (Object.values(changeSpecs).some(v => typeof v === "object" && v && "@@propmod" in v)) {
|
|
1702
|
+
continue; // Cannot optimize if any PropModification is present
|
|
1703
|
+
}
|
|
1704
|
+
let keyCoverage = updateCoverage.get(strKey);
|
|
1705
|
+
if (keyCoverage) {
|
|
1706
|
+
keyCoverage.push({ txid: mut.txid, updateSpec: changeSpecs });
|
|
1707
|
+
}
|
|
1708
|
+
else {
|
|
1709
|
+
updateCoverage.set(strKey, [{ txid: mut.txid, updateSpec: changeSpecs }]);
|
|
1710
|
+
}
|
|
1711
|
+
}
|
|
1712
|
+
}
|
|
1713
|
+
muts = muts.filter(mut => {
|
|
1714
|
+
// Only apply optimization to update mutations that are single-key
|
|
1715
|
+
if (mut.type !== 'update')
|
|
1716
|
+
return true;
|
|
1717
|
+
if (mut.keys.length !== 1 || mut.changeSpecs.length !== 1)
|
|
1718
|
+
return true;
|
|
1719
|
+
// Keep track of properties that aren't overlapped by later transactions
|
|
1720
|
+
const unoverlappedProps = new Set(Object.keys(mut.changeSpecs[0]));
|
|
1721
|
+
const strKey = '' + mut.keys[0];
|
|
1722
|
+
const keyCoverage = updateCoverage.get(strKey);
|
|
1723
|
+
for (let i = keyCoverage.length - 1; i >= 0; --i) {
|
|
1724
|
+
const { txid, updateSpec } = keyCoverage[i];
|
|
1725
|
+
if (txid === mut.txid)
|
|
1726
|
+
break; // Stop when reaching own txid
|
|
1727
|
+
// If all changes in updateSpec are covered by all props on all mut.changeSpecs then
|
|
1728
|
+
// txid is redundant and can be removed.
|
|
1729
|
+
for (const keyPath of Object.keys(updateSpec)) {
|
|
1730
|
+
unoverlappedProps.delete(keyPath);
|
|
1731
|
+
}
|
|
1732
|
+
}
|
|
1733
|
+
if (unoverlappedProps.size === 0) {
|
|
1734
|
+
// This operation is completely overlapped by later operations. It can be removed.
|
|
1735
|
+
return false;
|
|
1736
|
+
}
|
|
1737
|
+
return true;
|
|
1738
|
+
});
|
|
1739
|
+
return muts;
|
|
1740
|
+
}
|
|
1741
|
+
function canonicalizeToUpdateOps(muts) {
|
|
1742
|
+
muts = muts.map(mut => {
|
|
1743
|
+
if (mut.type === 'modify' && mut.criteria.index === null) {
|
|
1744
|
+
// The criteria is on primary key. Convert to an update operation instead.
|
|
1745
|
+
// It is simpler for the server to handle and also more efficient.
|
|
1746
|
+
const updateMut = Object.assign(Object.assign({}, mut), { criteria: undefined, changeSpec: undefined, type: 'update', keys: mut.keys, changeSpecs: [mut.changeSpec] });
|
|
1747
|
+
delete updateMut.criteria;
|
|
1748
|
+
delete updateMut.changeSpec;
|
|
1749
|
+
return updateMut;
|
|
1750
|
+
}
|
|
1751
|
+
return mut;
|
|
1752
|
+
});
|
|
1753
|
+
return muts;
|
|
1754
|
+
}
|
|
1695
1755
|
|
|
1696
1756
|
function randomString(bytes) {
|
|
1697
1757
|
const buf = new Uint8Array(bytes);
|
|
@@ -4224,6 +4284,7 @@ function createMutationTrackingMiddleware({ currentUserObservable, db, }) {
|
|
|
4224
4284
|
let values = 'values' in req ? req.values : [];
|
|
4225
4285
|
let changeSpec = 'changeSpec' in req ? req.changeSpec : undefined;
|
|
4226
4286
|
let updates = 'updates' in req ? req.updates : undefined;
|
|
4287
|
+
let upsert = updates && 'upsert' in req ? req.upsert : false;
|
|
4227
4288
|
if (hasFailures) {
|
|
4228
4289
|
keys = keys.filter((_, idx) => !failures[idx]);
|
|
4229
4290
|
values = values.filter((_, idx) => !failures[idx]);
|
|
@@ -4255,29 +4316,32 @@ function createMutationTrackingMiddleware({ currentUserObservable, db, }) {
|
|
|
4255
4316
|
};
|
|
4256
4317
|
const validKeys = new RangeSet();
|
|
4257
4318
|
let anyChangeSpecBecameEmpty = false;
|
|
4258
|
-
|
|
4259
|
-
|
|
4260
|
-
|
|
4261
|
-
|
|
4262
|
-
|
|
4263
|
-
|
|
4264
|
-
|
|
4265
|
-
|
|
4319
|
+
if (!upsert) {
|
|
4320
|
+
for (let i = 0, l = strippedChangeSpecs.length; i < l; ++i) {
|
|
4321
|
+
if (Object.keys(strippedChangeSpecs[i]).length > 0) {
|
|
4322
|
+
newUpdates.keys.push(updates.keys[i]);
|
|
4323
|
+
newUpdates.changeSpecs.push(strippedChangeSpecs[i]);
|
|
4324
|
+
validKeys.addKey(updates.keys[i]);
|
|
4325
|
+
}
|
|
4326
|
+
else {
|
|
4327
|
+
anyChangeSpecBecameEmpty = true;
|
|
4328
|
+
}
|
|
4266
4329
|
}
|
|
4267
|
-
|
|
4268
|
-
|
|
4269
|
-
|
|
4270
|
-
|
|
4271
|
-
|
|
4272
|
-
|
|
4273
|
-
|
|
4274
|
-
|
|
4275
|
-
|
|
4276
|
-
|
|
4330
|
+
updates = newUpdates;
|
|
4331
|
+
if (anyChangeSpecBecameEmpty) {
|
|
4332
|
+
// Some keys were stripped. We must also strip them from keys and values
|
|
4333
|
+
// unless this is an upsert operation in which case we want to send them all.
|
|
4334
|
+
let newKeys = [];
|
|
4335
|
+
let newValues = [];
|
|
4336
|
+
for (let i = 0, l = keys.length; i < l; ++i) {
|
|
4337
|
+
if (validKeys.hasKey(keys[i])) {
|
|
4338
|
+
newKeys.push(keys[i]);
|
|
4339
|
+
newValues.push(values[i]);
|
|
4340
|
+
}
|
|
4277
4341
|
}
|
|
4342
|
+
keys = newKeys;
|
|
4343
|
+
values = newValues;
|
|
4278
4344
|
}
|
|
4279
|
-
keys = newKeys;
|
|
4280
|
-
values = newValues;
|
|
4281
4345
|
}
|
|
4282
4346
|
}
|
|
4283
4347
|
}
|
|
@@ -4319,49 +4383,59 @@ function createMutationTrackingMiddleware({ currentUserObservable, db, }) {
|
|
|
4319
4383
|
userId,
|
|
4320
4384
|
values,
|
|
4321
4385
|
}
|
|
4322
|
-
:
|
|
4323
|
-
|
|
4324
|
-
|
|
4325
|
-
|
|
4326
|
-
|
|
4327
|
-
|
|
4328
|
-
|
|
4329
|
-
|
|
4330
|
-
|
|
4331
|
-
|
|
4332
|
-
|
|
4333
|
-
}
|
|
4334
|
-
: changeSpec
|
|
4386
|
+
: upsert ? {
|
|
4387
|
+
type: 'upsert',
|
|
4388
|
+
ts,
|
|
4389
|
+
opNo,
|
|
4390
|
+
keys,
|
|
4391
|
+
values,
|
|
4392
|
+
changeSpecs: updates.changeSpecs.filter((_, idx) => !failures[idx]),
|
|
4393
|
+
txid,
|
|
4394
|
+
userId,
|
|
4395
|
+
}
|
|
4396
|
+
: criteria && changeSpec
|
|
4335
4397
|
? {
|
|
4336
|
-
//
|
|
4337
|
-
type: '
|
|
4398
|
+
// Common changeSpec for all keys
|
|
4399
|
+
type: 'modify',
|
|
4338
4400
|
ts,
|
|
4339
4401
|
opNo,
|
|
4340
4402
|
keys,
|
|
4341
|
-
|
|
4403
|
+
criteria,
|
|
4404
|
+
changeSpec,
|
|
4342
4405
|
txid,
|
|
4343
4406
|
userId,
|
|
4344
4407
|
}
|
|
4345
|
-
:
|
|
4408
|
+
: changeSpec
|
|
4346
4409
|
? {
|
|
4347
|
-
//
|
|
4410
|
+
// In case criteria involved an unsynced property, we go for keys instead.
|
|
4348
4411
|
type: 'update',
|
|
4349
4412
|
ts,
|
|
4350
4413
|
opNo,
|
|
4351
|
-
keys: updates.keys,
|
|
4352
|
-
changeSpecs: updates.changeSpecs,
|
|
4353
|
-
txid,
|
|
4354
|
-
userId,
|
|
4355
|
-
}
|
|
4356
|
-
: {
|
|
4357
|
-
type: 'upsert',
|
|
4358
|
-
ts,
|
|
4359
|
-
opNo,
|
|
4360
4414
|
keys,
|
|
4361
|
-
|
|
4415
|
+
changeSpecs: keys.map(() => changeSpec),
|
|
4362
4416
|
txid,
|
|
4363
4417
|
userId,
|
|
4364
|
-
}
|
|
4418
|
+
}
|
|
4419
|
+
: updates
|
|
4420
|
+
? {
|
|
4421
|
+
// One changeSpec per key
|
|
4422
|
+
type: 'update',
|
|
4423
|
+
ts,
|
|
4424
|
+
opNo,
|
|
4425
|
+
keys: updates.keys,
|
|
4426
|
+
changeSpecs: updates.changeSpecs,
|
|
4427
|
+
txid,
|
|
4428
|
+
userId,
|
|
4429
|
+
}
|
|
4430
|
+
: {
|
|
4431
|
+
type: 'upsert',
|
|
4432
|
+
ts,
|
|
4433
|
+
opNo,
|
|
4434
|
+
keys,
|
|
4435
|
+
values,
|
|
4436
|
+
txid,
|
|
4437
|
+
userId,
|
|
4438
|
+
};
|
|
4365
4439
|
if ('isAdditionalChunk' in req && req.isAdditionalChunk) {
|
|
4366
4440
|
mut.isAdditionalChunk = true;
|
|
4367
4441
|
}
|
|
@@ -5256,34 +5330,85 @@ const Styles = {
|
|
|
5256
5330
|
alignItems: "center",
|
|
5257
5331
|
display: "flex",
|
|
5258
5332
|
justifyContent: "center",
|
|
5333
|
+
padding: "16px",
|
|
5334
|
+
boxSizing: "border-box"
|
|
5259
5335
|
},
|
|
5260
5336
|
DialogInner: {
|
|
5261
5337
|
position: "relative",
|
|
5262
5338
|
color: "#222",
|
|
5263
5339
|
backgroundColor: "#fff",
|
|
5264
|
-
padding: "
|
|
5340
|
+
padding: "24px",
|
|
5265
5341
|
marginBottom: "2em",
|
|
5266
|
-
maxWidth: "
|
|
5342
|
+
maxWidth: "400px",
|
|
5343
|
+
width: "100%",
|
|
5267
5344
|
maxHeight: "90%",
|
|
5268
5345
|
overflowY: "auto",
|
|
5269
5346
|
border: "3px solid #3d3d5d",
|
|
5270
5347
|
borderRadius: "8px",
|
|
5271
5348
|
boxShadow: "0 0 80px 10px #666",
|
|
5272
|
-
width: "auto",
|
|
5273
5349
|
fontFamily: "sans-serif",
|
|
5350
|
+
boxSizing: "border-box"
|
|
5274
5351
|
},
|
|
5275
5352
|
Input: {
|
|
5276
5353
|
height: "35px",
|
|
5277
|
-
width: "
|
|
5354
|
+
width: "100%",
|
|
5355
|
+
maxWidth: "100%",
|
|
5278
5356
|
borderColor: "#ccf4",
|
|
5279
5357
|
outline: "none",
|
|
5280
|
-
fontSize: "
|
|
5281
|
-
padding: "8px"
|
|
5358
|
+
fontSize: "16px",
|
|
5359
|
+
padding: "8px",
|
|
5360
|
+
boxSizing: "border-box"
|
|
5361
|
+
},
|
|
5362
|
+
Button: {
|
|
5363
|
+
padding: "10px 20px",
|
|
5364
|
+
margin: "0 4px",
|
|
5365
|
+
border: "1px solid #d1d5db",
|
|
5366
|
+
borderRadius: "6px",
|
|
5367
|
+
backgroundColor: "#ffffff",
|
|
5368
|
+
cursor: "pointer",
|
|
5369
|
+
fontSize: "14px",
|
|
5370
|
+
fontWeight: "500",
|
|
5371
|
+
color: "#374151",
|
|
5372
|
+
transition: "all 0.2s ease"
|
|
5373
|
+
},
|
|
5374
|
+
PrimaryButton: {
|
|
5375
|
+
padding: "10px 20px",
|
|
5376
|
+
margin: "0 4px",
|
|
5377
|
+
border: "1px solid #3b82f6",
|
|
5378
|
+
borderRadius: "6px",
|
|
5379
|
+
backgroundColor: "#3b82f6",
|
|
5380
|
+
color: "white",
|
|
5381
|
+
cursor: "pointer",
|
|
5382
|
+
fontSize: "14px",
|
|
5383
|
+
fontWeight: "500",
|
|
5384
|
+
transition: "all 0.2s ease"
|
|
5385
|
+
},
|
|
5386
|
+
ButtonsDiv: {
|
|
5387
|
+
display: "flex",
|
|
5388
|
+
justifyContent: "flex-end",
|
|
5389
|
+
gap: "12px",
|
|
5390
|
+
marginTop: "24px",
|
|
5391
|
+
paddingTop: "20px"
|
|
5392
|
+
},
|
|
5393
|
+
Label: {
|
|
5394
|
+
display: "block",
|
|
5395
|
+
marginBottom: "12px",
|
|
5396
|
+
fontSize: "14px",
|
|
5397
|
+
fontWeight: "500",
|
|
5398
|
+
color: "#333"
|
|
5399
|
+
},
|
|
5400
|
+
WindowHeader: {
|
|
5401
|
+
margin: "0 0 20px 0",
|
|
5402
|
+
fontSize: "18px",
|
|
5403
|
+
fontWeight: "600",
|
|
5404
|
+
color: "#333",
|
|
5405
|
+
borderBottom: "1px solid #eee",
|
|
5406
|
+
paddingBottom: "10px"
|
|
5282
5407
|
}
|
|
5283
5408
|
};
|
|
5284
5409
|
|
|
5285
5410
|
function Dialog({ children, className }) {
|
|
5286
|
-
return (h("div", { className: className },
|
|
5411
|
+
return (h("div", { className: `dexie-dialog ${className || ''}` },
|
|
5287
5412
|
h("div", { style: Styles.Darken }),
|
|
5288
5413
|
h("div", { style: Styles.DialogOuter },
|
|
5289
5414
|
h("div", { style: Styles.DialogInner }, children))));
|
|
@@ -5335,7 +5460,7 @@ function LoginDialog({ title, type, alerts, fields, submitLabel, cancelLabel, on
|
|
|
5335
5460
|
} })))))),
|
|
5336
5461
|
h("div", { style: Styles.ButtonsDiv },
|
|
5337
5462
|
h(p$1, null,
|
|
5338
|
-
h("button", { type: "submit", style: Styles.
|
|
5463
|
+
h("button", { type: "submit", style: Styles.PrimaryButton, onClick: () => onSubmit(params) }, submitLabel),
|
|
5339
5464
|
cancelLabel && (h("button", { style: Styles.Button, onClick: onCancel }, cancelLabel))))));
|
|
5340
5465
|
}
|
|
5341
5466
|
function valueTransformer(type, value) {
|
|
@@ -6137,7 +6262,7 @@ function dexieCloud(dexie) {
|
|
|
6137
6262
|
const syncComplete = new Subject();
|
|
6138
6263
|
dexie.cloud = {
|
|
6139
6264
|
// @ts-ignore
|
|
6140
|
-
version: "4.2.
|
|
6265
|
+
version: "4.2.2",
|
|
6141
6266
|
options: Object.assign({}, DEFAULT_OPTIONS),
|
|
6142
6267
|
schema: null,
|
|
6143
6268
|
get currentUserId() {
|
|
@@ -6454,7 +6579,7 @@ function dexieCloud(dexie) {
|
|
|
6454
6579
|
}
|
|
6455
6580
|
}
|
|
6456
6581
|
// @ts-ignore
|
|
6457
|
-
dexieCloud.version = "4.2.
|
|
6582
|
+
dexieCloud.version = "4.2.2";
|
|
6458
6583
|
Dexie.Cloud = dexieCloud;
|
|
6459
6584
|
|
|
6460
6585
|
export { dexieCloud as default, defineYDocTrigger, dexieCloud, getTiedObjectId, getTiedRealmId, resolveText };
|