@anfenn/dync 1.0.0 → 1.0.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/dist/{chunk-LGHOZECP.js → chunk-66PSQW4D.js} +120 -120
- package/dist/chunk-66PSQW4D.js.map +1 -0
- package/dist/index.cjs +119 -119
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/{index.shared-YSn6c01d.d.cts → index.shared-BGwvMH8f.d.cts} +3 -3
- package/dist/{index.shared-CPIge2ZM.d.ts → index.shared-CkYsQYyn.d.ts} +3 -3
- package/dist/react/index.cjs +119 -119
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.d.cts +1 -1
- package/dist/react/index.d.ts +1 -1
- package/dist/react/index.js +1 -1
- package/package.json +6 -4
- package/src/core/StateManager.ts +15 -15
- package/src/core/firstLoad.ts +27 -27
- package/src/core/pullOperations.ts +28 -28
- package/src/core/pushOperations.ts +41 -41
- package/src/core/tableEnhancers.ts +9 -9
- package/src/index.shared.ts +3 -3
- package/src/types.ts +3 -3
- package/dist/chunk-LGHOZECP.js.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -184,7 +184,7 @@ var StateManager = class {
|
|
|
184
184
|
}
|
|
185
185
|
addPendingChange(change) {
|
|
186
186
|
const next = clonePersistedState(this.persistedState);
|
|
187
|
-
const queueItem = next.pendingChanges.find((p) => p.localId === change.localId && p.
|
|
187
|
+
const queueItem = next.pendingChanges.find((p) => p.localId === change.localId && p.tableName === change.tableName);
|
|
188
188
|
const omittedChanges = omitFields(change.changes, LOCAL_ONLY_SYNC_FIELDS);
|
|
189
189
|
const omittedBefore = omitFields(change.before, LOCAL_ONLY_SYNC_FIELDS);
|
|
190
190
|
const omittedAfter = omitFields(change.after, LOCAL_ONLY_SYNC_FIELDS);
|
|
@@ -205,7 +205,7 @@ var StateManager = class {
|
|
|
205
205
|
next.pendingChanges = [...next.pendingChanges];
|
|
206
206
|
next.pendingChanges.push({
|
|
207
207
|
action,
|
|
208
|
-
|
|
208
|
+
tableName: change.tableName,
|
|
209
209
|
localId: change.localId,
|
|
210
210
|
id: change.id,
|
|
211
211
|
version: 1,
|
|
@@ -217,18 +217,18 @@ var StateManager = class {
|
|
|
217
217
|
this.persistedState = next;
|
|
218
218
|
return this.persist();
|
|
219
219
|
}
|
|
220
|
-
samePendingVersion(
|
|
221
|
-
return this.persistedState.pendingChanges.find((p) => p.localId === localId && p.
|
|
220
|
+
samePendingVersion(tableName, localId, version) {
|
|
221
|
+
return this.persistedState.pendingChanges.find((p) => p.localId === localId && p.tableName === tableName)?.version === version;
|
|
222
222
|
}
|
|
223
|
-
removePendingChange(localId,
|
|
223
|
+
removePendingChange(localId, tableName) {
|
|
224
224
|
const next = clonePersistedState(this.persistedState);
|
|
225
|
-
next.pendingChanges = next.pendingChanges.filter((p) => !(p.localId === localId && p.
|
|
225
|
+
next.pendingChanges = next.pendingChanges.filter((p) => !(p.localId === localId && p.tableName === tableName));
|
|
226
226
|
this.persistedState = next;
|
|
227
227
|
return this.persist();
|
|
228
228
|
}
|
|
229
|
-
updatePendingChange(
|
|
229
|
+
updatePendingChange(tableName, localId, action, id) {
|
|
230
230
|
const next = clonePersistedState(this.persistedState);
|
|
231
|
-
const changeItem = next.pendingChanges.find((p) => p.
|
|
231
|
+
const changeItem = next.pendingChanges.find((p) => p.tableName === tableName && p.localId === localId);
|
|
232
232
|
if (changeItem) {
|
|
233
233
|
changeItem.action = action;
|
|
234
234
|
if (id) changeItem.id = id;
|
|
@@ -237,9 +237,9 @@ var StateManager = class {
|
|
|
237
237
|
}
|
|
238
238
|
return Promise.resolve();
|
|
239
239
|
}
|
|
240
|
-
setPendingChangeBefore(
|
|
240
|
+
setPendingChangeBefore(tableName, localId, before) {
|
|
241
241
|
const next = clonePersistedState(this.persistedState);
|
|
242
|
-
const changeItem = next.pendingChanges.find((p) => p.
|
|
242
|
+
const changeItem = next.pendingChanges.find((p) => p.tableName === tableName && p.localId === localId);
|
|
243
243
|
if (changeItem) {
|
|
244
244
|
changeItem.before = { ...changeItem.before ?? {}, ...before };
|
|
245
245
|
this.persistedState = next;
|
|
@@ -310,7 +310,7 @@ function cloneConflicts(conflicts) {
|
|
|
310
310
|
const next = {};
|
|
311
311
|
for (const [key, value] of Object.entries(conflicts)) {
|
|
312
312
|
next[key] = {
|
|
313
|
-
|
|
313
|
+
tableName: value.tableName,
|
|
314
314
|
fields: value.fields.map((field) => ({ ...field }))
|
|
315
315
|
};
|
|
316
316
|
}
|
|
@@ -421,7 +421,7 @@ function enhanceSyncTable({ table, tableName, withTransaction, state, enhancedTa
|
|
|
421
421
|
result = await rawAdd(syncedItem);
|
|
422
422
|
await state.addPendingChange({
|
|
423
423
|
action: "create" /* Create */,
|
|
424
|
-
|
|
424
|
+
tableName,
|
|
425
425
|
localId,
|
|
426
426
|
changes: syncedItem,
|
|
427
427
|
before: null,
|
|
@@ -449,7 +449,7 @@ function enhanceSyncTable({ table, tableName, withTransaction, state, enhancedTa
|
|
|
449
449
|
result = await rawPut(syncedItem);
|
|
450
450
|
await state.addPendingChange({
|
|
451
451
|
action: isUpdate ? "update" /* Update */ : "create" /* Create */,
|
|
452
|
-
|
|
452
|
+
tableName,
|
|
453
453
|
localId,
|
|
454
454
|
id: existingRecord?.id,
|
|
455
455
|
changes: syncedItem,
|
|
@@ -476,7 +476,7 @@ function enhanceSyncTable({ table, tableName, withTransaction, state, enhancedTa
|
|
|
476
476
|
if (result > 0) {
|
|
477
477
|
await state.addPendingChange({
|
|
478
478
|
action: "update" /* Update */,
|
|
479
|
-
|
|
479
|
+
tableName,
|
|
480
480
|
localId: key,
|
|
481
481
|
id: record.id,
|
|
482
482
|
changes: updatedChanges,
|
|
@@ -500,7 +500,7 @@ function enhanceSyncTable({ table, tableName, withTransaction, state, enhancedTa
|
|
|
500
500
|
deletedLocalId = record._localId;
|
|
501
501
|
await state.addPendingChange({
|
|
502
502
|
action: "remove" /* Remove */,
|
|
503
|
-
|
|
503
|
+
tableName,
|
|
504
504
|
localId: record._localId,
|
|
505
505
|
id: record.id,
|
|
506
506
|
changes: null,
|
|
@@ -529,7 +529,7 @@ function enhanceSyncTable({ table, tableName, withTransaction, state, enhancedTa
|
|
|
529
529
|
for (const syncedItem of syncedItems) {
|
|
530
530
|
await state.addPendingChange({
|
|
531
531
|
action: "create" /* Create */,
|
|
532
|
-
|
|
532
|
+
tableName,
|
|
533
533
|
localId: syncedItem._localId,
|
|
534
534
|
changes: syncedItem,
|
|
535
535
|
before: null,
|
|
@@ -567,7 +567,7 @@ function enhanceSyncTable({ table, tableName, withTransaction, state, enhancedTa
|
|
|
567
567
|
const existing = existingMap.get(syncedItem._localId);
|
|
568
568
|
await state.addPendingChange({
|
|
569
569
|
action: existing ? "update" /* Update */ : "create" /* Create */,
|
|
570
|
-
|
|
570
|
+
tableName,
|
|
571
571
|
localId: syncedItem._localId,
|
|
572
572
|
id: existing?.id,
|
|
573
573
|
changes: syncedItem,
|
|
@@ -608,7 +608,7 @@ function enhanceSyncTable({ table, tableName, withTransaction, state, enhancedTa
|
|
|
608
608
|
updatedKeys.push(record._localId);
|
|
609
609
|
await state.addPendingChange({
|
|
610
610
|
action: "update" /* Update */,
|
|
611
|
-
|
|
611
|
+
tableName,
|
|
612
612
|
localId: record._localId,
|
|
613
613
|
id: record.id,
|
|
614
614
|
changes,
|
|
@@ -635,7 +635,7 @@ function enhanceSyncTable({ table, tableName, withTransaction, state, enhancedTa
|
|
|
635
635
|
deletedLocalIds.push(record._localId);
|
|
636
636
|
await state.addPendingChange({
|
|
637
637
|
action: "remove" /* Remove */,
|
|
638
|
-
|
|
638
|
+
tableName,
|
|
639
639
|
localId: record._localId,
|
|
640
640
|
id: record.id,
|
|
641
641
|
changes: null,
|
|
@@ -659,7 +659,7 @@ function enhanceSyncTable({ table, tableName, withTransaction, state, enhancedTa
|
|
|
659
659
|
deletedLocalIds.push(record._localId);
|
|
660
660
|
await state.addPendingChange({
|
|
661
661
|
action: "remove" /* Remove */,
|
|
662
|
-
|
|
662
|
+
tableName,
|
|
663
663
|
localId: record._localId,
|
|
664
664
|
id: record.id,
|
|
665
665
|
changes: null,
|
|
@@ -688,33 +688,33 @@ function enhanceSyncTable({ table, tableName, withTransaction, state, enhancedTa
|
|
|
688
688
|
async function pullAll(ctx) {
|
|
689
689
|
let firstSyncError;
|
|
690
690
|
const changedTables = [];
|
|
691
|
-
for (const [
|
|
691
|
+
for (const [tableName, api] of Object.entries(ctx.syncApis)) {
|
|
692
692
|
try {
|
|
693
|
-
const lastPulled = ctx.state.getState().lastPulled[
|
|
693
|
+
const lastPulled = ctx.state.getState().lastPulled[tableName];
|
|
694
694
|
const since = lastPulled ? new Date(lastPulled) : /* @__PURE__ */ new Date(0);
|
|
695
|
-
ctx.logger.debug(`[dync] pull:start
|
|
695
|
+
ctx.logger.debug(`[dync] pull:start tableName=${tableName} since=${since.toISOString()}`);
|
|
696
696
|
const serverData = await api.list(since);
|
|
697
|
-
const changed = await processPullData(
|
|
698
|
-
if (changed) changedTables.push(
|
|
697
|
+
const changed = await processPullData(tableName, serverData, since, ctx);
|
|
698
|
+
if (changed) changedTables.push(tableName);
|
|
699
699
|
} catch (err) {
|
|
700
700
|
firstSyncError = firstSyncError ?? err;
|
|
701
|
-
ctx.logger.error(`[dync] pull:error
|
|
701
|
+
ctx.logger.error(`[dync] pull:error tableName=${tableName}`, err);
|
|
702
702
|
}
|
|
703
703
|
}
|
|
704
704
|
return { error: firstSyncError, changedTables };
|
|
705
705
|
}
|
|
706
|
-
async function handleRemoteItemUpdate(table,
|
|
707
|
-
const pendingChange = ctx.state.getState().pendingChanges.find((p) => p.
|
|
706
|
+
async function handleRemoteItemUpdate(table, tableName, localItem, remote, ctx) {
|
|
707
|
+
const pendingChange = ctx.state.getState().pendingChanges.find((p) => p.tableName === tableName && p.localId === localItem._localId);
|
|
708
708
|
const conflictStrategy = ctx.conflictResolutionStrategy;
|
|
709
709
|
if (pendingChange) {
|
|
710
|
-
ctx.logger.debug(`[dync] pull:conflict-strategy:${conflictStrategy}
|
|
710
|
+
ctx.logger.debug(`[dync] pull:conflict-strategy:${conflictStrategy} tableName=${tableName} id=${remote.id}`);
|
|
711
711
|
switch (conflictStrategy) {
|
|
712
712
|
case "local-wins":
|
|
713
713
|
break;
|
|
714
714
|
case "remote-wins": {
|
|
715
715
|
const merged = { ...remote, _localId: localItem._localId };
|
|
716
716
|
await table.raw.update(localItem._localId, merged);
|
|
717
|
-
await ctx.state.removePendingChange(localItem._localId,
|
|
717
|
+
await ctx.state.removePendingChange(localItem._localId, tableName);
|
|
718
718
|
break;
|
|
719
719
|
}
|
|
720
720
|
case "try-shallow-merge": {
|
|
@@ -727,7 +727,7 @@ async function handleRemoteItemUpdate(table, stateKey, localItem, remote, ctx) {
|
|
|
727
727
|
...syncState,
|
|
728
728
|
conflicts: {
|
|
729
729
|
...syncState.conflicts || {},
|
|
730
|
-
[localItem._localId]: {
|
|
730
|
+
[localItem._localId]: { tableName, fields }
|
|
731
731
|
}
|
|
732
732
|
}));
|
|
733
733
|
} else {
|
|
@@ -750,7 +750,7 @@ async function handleRemoteItemUpdate(table, stateKey, localItem, remote, ctx) {
|
|
|
750
750
|
} else {
|
|
751
751
|
const merged = { ...localItem, ...remote };
|
|
752
752
|
await table.raw.update(localItem._localId, merged);
|
|
753
|
-
ctx.logger.debug(`[dync] pull:merge-remote
|
|
753
|
+
ctx.logger.debug(`[dync] pull:merge-remote tableName=${tableName} id=${remote.id}`);
|
|
754
754
|
}
|
|
755
755
|
}
|
|
756
756
|
async function pullAllBatch(ctx) {
|
|
@@ -764,17 +764,17 @@ async function pullAllBatch(ctx) {
|
|
|
764
764
|
}
|
|
765
765
|
ctx.logger.debug(`[dync] pull:batch:start tables=${[...ctx.batchSync.syncTables].join(",")}`, sinceMap);
|
|
766
766
|
const serverDataByTable = await ctx.batchSync.pull(sinceMap);
|
|
767
|
-
for (const [
|
|
768
|
-
if (!ctx.batchSync.syncTables.includes(
|
|
769
|
-
ctx.logger.warn(`[dync] pull:batch:unknown-table
|
|
767
|
+
for (const [tableName, serverData] of Object.entries(serverDataByTable)) {
|
|
768
|
+
if (!ctx.batchSync.syncTables.includes(tableName)) {
|
|
769
|
+
ctx.logger.warn(`[dync] pull:batch:unknown-table tableName=${tableName}`);
|
|
770
770
|
continue;
|
|
771
771
|
}
|
|
772
772
|
try {
|
|
773
|
-
const changed = await processPullData(
|
|
774
|
-
if (changed) changedTables.push(
|
|
773
|
+
const changed = await processPullData(tableName, serverData, sinceMap[tableName], ctx);
|
|
774
|
+
if (changed) changedTables.push(tableName);
|
|
775
775
|
} catch (err) {
|
|
776
776
|
firstSyncError = firstSyncError ?? err;
|
|
777
|
-
ctx.logger.error(`[dync] pull:batch:error
|
|
777
|
+
ctx.logger.error(`[dync] pull:batch:error tableName=${tableName}`, err);
|
|
778
778
|
}
|
|
779
779
|
}
|
|
780
780
|
} catch (err) {
|
|
@@ -783,40 +783,40 @@ async function pullAllBatch(ctx) {
|
|
|
783
783
|
}
|
|
784
784
|
return { error: firstSyncError, changedTables };
|
|
785
785
|
}
|
|
786
|
-
async function processPullData(
|
|
786
|
+
async function processPullData(tableName, serverData, since, ctx) {
|
|
787
787
|
if (!serverData?.length) return false;
|
|
788
|
-
ctx.logger.debug(`[dync] pull:process
|
|
788
|
+
ctx.logger.debug(`[dync] pull:process tableName=${tableName} count=${serverData.length}`);
|
|
789
789
|
let newest = since;
|
|
790
790
|
let hasChanges = false;
|
|
791
|
-
await ctx.withTransaction("rw", [
|
|
792
|
-
const txTable = tables[
|
|
791
|
+
await ctx.withTransaction("rw", [tableName, DYNC_STATE_TABLE], async (tables) => {
|
|
792
|
+
const txTable = tables[tableName];
|
|
793
793
|
const pendingRemovalById = new Set(
|
|
794
|
-
ctx.state.getState().pendingChanges.filter((p) => p.
|
|
794
|
+
ctx.state.getState().pendingChanges.filter((p) => p.tableName === tableName && p.action === "remove" /* Remove */).map((p) => p.id)
|
|
795
795
|
);
|
|
796
796
|
for (const remote of serverData) {
|
|
797
797
|
const remoteUpdated = new Date(remote.updated_at);
|
|
798
798
|
if (remoteUpdated > newest) newest = remoteUpdated;
|
|
799
799
|
if (pendingRemovalById.has(remote.id)) {
|
|
800
|
-
ctx.logger.debug(`[dync] pull:skip-pending-remove
|
|
800
|
+
ctx.logger.debug(`[dync] pull:skip-pending-remove tableName=${tableName} id=${remote.id}`);
|
|
801
801
|
continue;
|
|
802
802
|
}
|
|
803
803
|
const localItem = await txTable.where("id").equals(remote.id).first();
|
|
804
804
|
if (remote.deleted) {
|
|
805
805
|
if (localItem) {
|
|
806
806
|
await txTable.raw.delete(localItem._localId);
|
|
807
|
-
ctx.logger.debug(`[dync] pull:remove
|
|
807
|
+
ctx.logger.debug(`[dync] pull:remove tableName=${tableName} id=${remote.id}`);
|
|
808
808
|
hasChanges = true;
|
|
809
809
|
}
|
|
810
810
|
continue;
|
|
811
811
|
}
|
|
812
812
|
delete remote.deleted;
|
|
813
813
|
if (localItem) {
|
|
814
|
-
await handleRemoteItemUpdate(txTable,
|
|
814
|
+
await handleRemoteItemUpdate(txTable, tableName, localItem, remote, ctx);
|
|
815
815
|
hasChanges = true;
|
|
816
816
|
} else {
|
|
817
817
|
const newLocalItem = { ...remote, _localId: createLocalId() };
|
|
818
818
|
await txTable.raw.add(newLocalItem);
|
|
819
|
-
ctx.logger.debug(`[dync] pull:add
|
|
819
|
+
ctx.logger.debug(`[dync] pull:add tableName=${tableName} id=${remote.id}`);
|
|
820
820
|
hasChanges = true;
|
|
821
821
|
}
|
|
822
822
|
}
|
|
@@ -824,7 +824,7 @@ async function processPullData(stateKey, serverData, since, ctx) {
|
|
|
824
824
|
...syncState,
|
|
825
825
|
lastPulled: {
|
|
826
826
|
...syncState.lastPulled,
|
|
827
|
-
[
|
|
827
|
+
[tableName]: newest.toISOString()
|
|
828
828
|
}
|
|
829
829
|
}));
|
|
830
830
|
});
|
|
@@ -833,35 +833,35 @@ async function processPullData(stateKey, serverData, since, ctx) {
|
|
|
833
833
|
|
|
834
834
|
// src/core/pushOperations.ts
|
|
835
835
|
async function handleRemoveSuccess(change, ctx) {
|
|
836
|
-
const {
|
|
837
|
-
ctx.logger.debug(`[dync] push:remove:success
|
|
838
|
-
await ctx.state.removePendingChange(localId,
|
|
836
|
+
const { tableName, localId, id } = change;
|
|
837
|
+
ctx.logger.debug(`[dync] push:remove:success tableName=${tableName} localId=${localId} id=${id}`);
|
|
838
|
+
await ctx.state.removePendingChange(localId, tableName);
|
|
839
839
|
}
|
|
840
840
|
async function handleUpdateSuccess(change, ctx) {
|
|
841
|
-
const {
|
|
842
|
-
ctx.logger.debug(`[dync] push:update:success
|
|
843
|
-
if (ctx.state.samePendingVersion(
|
|
844
|
-
await ctx.state.removePendingChange(localId,
|
|
841
|
+
const { tableName, localId, version, changes } = change;
|
|
842
|
+
ctx.logger.debug(`[dync] push:update:success tableName=${tableName} localId=${localId} id=${change.id}`);
|
|
843
|
+
if (ctx.state.samePendingVersion(tableName, localId, version)) {
|
|
844
|
+
await ctx.state.removePendingChange(localId, tableName);
|
|
845
845
|
} else {
|
|
846
|
-
await ctx.state.setPendingChangeBefore(
|
|
846
|
+
await ctx.state.setPendingChangeBefore(tableName, localId, changes);
|
|
847
847
|
}
|
|
848
848
|
}
|
|
849
849
|
async function handleCreateSuccess(change, serverResult, ctx) {
|
|
850
|
-
const {
|
|
851
|
-
ctx.logger.debug(`[dync] push:create:success
|
|
852
|
-
await ctx.withTransaction("rw", [
|
|
853
|
-
const txTable = tables[
|
|
850
|
+
const { tableName, localId, version, changes, id } = change;
|
|
851
|
+
ctx.logger.debug(`[dync] push:create:success tableName=${tableName} localId=${localId} id=${id ?? serverResult.id}`);
|
|
852
|
+
await ctx.withTransaction("rw", [tableName, DYNC_STATE_TABLE], async (tables) => {
|
|
853
|
+
const txTable = tables[tableName];
|
|
854
854
|
const wasChanged = await txTable.raw.update(localId, serverResult) ?? 0;
|
|
855
|
-
if (wasChanged && ctx.state.samePendingVersion(
|
|
856
|
-
await ctx.state.removePendingChange(localId,
|
|
855
|
+
if (wasChanged && ctx.state.samePendingVersion(tableName, localId, version)) {
|
|
856
|
+
await ctx.state.removePendingChange(localId, tableName);
|
|
857
857
|
} else {
|
|
858
858
|
const nextAction = wasChanged ? "update" /* Update */ : "remove" /* Remove */;
|
|
859
|
-
await ctx.state.updatePendingChange(
|
|
859
|
+
await ctx.state.updatePendingChange(tableName, localId, nextAction, serverResult.id);
|
|
860
860
|
if (nextAction === "remove" /* Remove */) return;
|
|
861
861
|
}
|
|
862
862
|
});
|
|
863
863
|
const finalItem = { ...changes, ...serverResult, _localId: localId };
|
|
864
|
-
ctx.syncOptions.onAfterRemoteAdd?.(
|
|
864
|
+
ctx.syncOptions.onAfterRemoteAdd?.(tableName, finalItem);
|
|
865
865
|
}
|
|
866
866
|
async function pushAll(ctx) {
|
|
867
867
|
let firstSyncError;
|
|
@@ -877,15 +877,15 @@ async function pushAll(ctx) {
|
|
|
877
877
|
return firstSyncError;
|
|
878
878
|
}
|
|
879
879
|
async function pushOne(change, ctx) {
|
|
880
|
-
const api = ctx.syncApis[change.
|
|
880
|
+
const api = ctx.syncApis[change.tableName];
|
|
881
881
|
if (!api) return;
|
|
882
|
-
ctx.logger.debug(`[dync] push:attempt action=${change.action}
|
|
883
|
-
const { action,
|
|
882
|
+
ctx.logger.debug(`[dync] push:attempt action=${change.action} tableName=${change.tableName} localId=${change.localId}`);
|
|
883
|
+
const { action, tableName, localId, id, changes, after } = change;
|
|
884
884
|
switch (action) {
|
|
885
885
|
case "remove" /* Remove */:
|
|
886
886
|
if (!id) {
|
|
887
|
-
ctx.logger.warn(`[dync] push:remove:no-id
|
|
888
|
-
await ctx.state.removePendingChange(localId,
|
|
887
|
+
ctx.logger.warn(`[dync] push:remove:no-id tableName=${tableName} localId=${localId}`);
|
|
888
|
+
await ctx.state.removePendingChange(localId, tableName);
|
|
889
889
|
return;
|
|
890
890
|
}
|
|
891
891
|
await api.remove(id);
|
|
@@ -893,7 +893,7 @@ async function pushOne(change, ctx) {
|
|
|
893
893
|
break;
|
|
894
894
|
case "update" /* Update */: {
|
|
895
895
|
if (ctx.state.hasConflicts(localId)) {
|
|
896
|
-
ctx.logger.warn(`[dync] push:update:skipping-with-conflicts
|
|
896
|
+
ctx.logger.warn(`[dync] push:update:skipping-with-conflicts tableName=${tableName} localId=${localId} id=${id}`);
|
|
897
897
|
return;
|
|
898
898
|
}
|
|
899
899
|
const exists = await api.update(id, changes, after);
|
|
@@ -909,9 +909,9 @@ async function pushOne(change, ctx) {
|
|
|
909
909
|
if (result) {
|
|
910
910
|
await handleCreateSuccess(change, result, ctx);
|
|
911
911
|
} else {
|
|
912
|
-
ctx.logger.warn(`[dync] push:create:no-result
|
|
913
|
-
if (ctx.state.samePendingVersion(
|
|
914
|
-
await ctx.state.removePendingChange(localId,
|
|
912
|
+
ctx.logger.warn(`[dync] push:create:no-result tableName=${tableName} localId=${localId} id=${id}`);
|
|
913
|
+
if (ctx.state.samePendingVersion(tableName, localId, change.version)) {
|
|
914
|
+
await ctx.state.removePendingChange(localId, tableName);
|
|
915
915
|
}
|
|
916
916
|
}
|
|
917
917
|
break;
|
|
@@ -919,21 +919,21 @@ async function pushOne(change, ctx) {
|
|
|
919
919
|
}
|
|
920
920
|
}
|
|
921
921
|
async function handleMissingRemoteRecord(change, ctx) {
|
|
922
|
-
const {
|
|
922
|
+
const { tableName, localId } = change;
|
|
923
923
|
const strategy = ctx.syncOptions.missingRemoteRecordDuringUpdateStrategy;
|
|
924
924
|
let localItem;
|
|
925
|
-
await ctx.withTransaction("rw", [
|
|
926
|
-
const txTable = tables[
|
|
925
|
+
await ctx.withTransaction("rw", [tableName, DYNC_STATE_TABLE], async (tables) => {
|
|
926
|
+
const txTable = tables[tableName];
|
|
927
927
|
localItem = await txTable.get(localId);
|
|
928
928
|
if (!localItem) {
|
|
929
|
-
ctx.logger.warn(`[dync] push:missing-remote:no-local-item
|
|
930
|
-
await ctx.state.removePendingChange(localId,
|
|
929
|
+
ctx.logger.warn(`[dync] push:missing-remote:no-local-item tableName=${tableName} localId=${localId}`);
|
|
930
|
+
await ctx.state.removePendingChange(localId, tableName);
|
|
931
931
|
return;
|
|
932
932
|
}
|
|
933
933
|
switch (strategy) {
|
|
934
934
|
case "delete-local-record":
|
|
935
935
|
await txTable.raw.delete(localId);
|
|
936
|
-
ctx.logger.debug(`[dync] push:missing-remote:${strategy}
|
|
936
|
+
ctx.logger.debug(`[dync] push:missing-remote:${strategy} tableName=${tableName} id=${localItem.id}`);
|
|
937
937
|
break;
|
|
938
938
|
case "insert-remote-record": {
|
|
939
939
|
const newItem = {
|
|
@@ -945,36 +945,36 @@ async function handleMissingRemoteRecord(change, ctx) {
|
|
|
945
945
|
await txTable.raw.delete(localId);
|
|
946
946
|
await ctx.state.addPendingChange({
|
|
947
947
|
action: "create" /* Create */,
|
|
948
|
-
|
|
948
|
+
tableName,
|
|
949
949
|
localId: newItem._localId,
|
|
950
950
|
changes: newItem,
|
|
951
951
|
before: null
|
|
952
952
|
});
|
|
953
|
-
ctx.logger.debug(`[dync] push:missing-remote:${strategy}
|
|
953
|
+
ctx.logger.debug(`[dync] push:missing-remote:${strategy} tableName=${tableName} id=${newItem.id}`);
|
|
954
954
|
break;
|
|
955
955
|
}
|
|
956
956
|
case "ignore":
|
|
957
|
-
ctx.logger.debug(`[dync] push:missing-remote:${strategy}
|
|
957
|
+
ctx.logger.debug(`[dync] push:missing-remote:${strategy} tableName=${tableName} id=${localItem.id}`);
|
|
958
958
|
break;
|
|
959
959
|
default:
|
|
960
|
-
ctx.logger.error(`[dync] push:missing-remote:unknown-strategy
|
|
960
|
+
ctx.logger.error(`[dync] push:missing-remote:unknown-strategy tableName=${tableName} id=${localItem.id} strategy=${strategy}`);
|
|
961
961
|
break;
|
|
962
962
|
}
|
|
963
|
-
await ctx.state.removePendingChange(localId,
|
|
963
|
+
await ctx.state.removePendingChange(localId, tableName);
|
|
964
964
|
});
|
|
965
965
|
ctx.syncOptions.onAfterMissingRemoteRecordDuringUpdate?.(strategy, localItem);
|
|
966
966
|
}
|
|
967
967
|
async function pushAllBatch(ctx) {
|
|
968
968
|
let firstSyncError;
|
|
969
969
|
try {
|
|
970
|
-
const changesSnapshot = [...ctx.state.getState().pendingChanges].filter((change) => ctx.batchSync.syncTables.includes(change.
|
|
970
|
+
const changesSnapshot = [...ctx.state.getState().pendingChanges].filter((change) => ctx.batchSync.syncTables.includes(change.tableName)).sort((a, b) => orderFor(a.action) - orderFor(b.action));
|
|
971
971
|
if (changesSnapshot.length === 0) {
|
|
972
972
|
ctx.logger.debug("[dync] push:batch:no-changes");
|
|
973
973
|
return void 0;
|
|
974
974
|
}
|
|
975
975
|
const changesToPush = changesSnapshot.filter((change) => {
|
|
976
976
|
if (change.action === "update" /* Update */ && ctx.state.hasConflicts(change.localId)) {
|
|
977
|
-
ctx.logger.warn(`[dync] push:batch:skipping-with-conflicts
|
|
977
|
+
ctx.logger.warn(`[dync] push:batch:skipping-with-conflicts tableName=${change.tableName} localId=${change.localId}`);
|
|
978
978
|
return false;
|
|
979
979
|
}
|
|
980
980
|
return true;
|
|
@@ -984,7 +984,7 @@ async function pushAllBatch(ctx) {
|
|
|
984
984
|
return void 0;
|
|
985
985
|
}
|
|
986
986
|
const payloads = changesToPush.map((change) => ({
|
|
987
|
-
table: change.
|
|
987
|
+
table: change.tableName,
|
|
988
988
|
action: change.action === "create" /* Create */ ? "add" : change.action === "update" /* Update */ ? "update" : "remove",
|
|
989
989
|
localId: change.localId,
|
|
990
990
|
id: change.id,
|
|
@@ -1016,12 +1016,12 @@ async function pushAllBatch(ctx) {
|
|
|
1016
1016
|
return firstSyncError;
|
|
1017
1017
|
}
|
|
1018
1018
|
async function processBatchPushResult(change, result, ctx) {
|
|
1019
|
-
const { action,
|
|
1019
|
+
const { action, tableName, localId } = change;
|
|
1020
1020
|
if (!result.success) {
|
|
1021
1021
|
if (action === "update" /* Update */) {
|
|
1022
1022
|
await handleMissingRemoteRecord(change, ctx);
|
|
1023
1023
|
} else {
|
|
1024
|
-
ctx.logger.warn(`[dync] push:batch:failed
|
|
1024
|
+
ctx.logger.warn(`[dync] push:batch:failed tableName=${tableName} localId=${localId} error=${result.error}`);
|
|
1025
1025
|
}
|
|
1026
1026
|
return;
|
|
1027
1027
|
}
|
|
@@ -1053,13 +1053,13 @@ async function startFirstLoad(ctx) {
|
|
|
1053
1053
|
return;
|
|
1054
1054
|
}
|
|
1055
1055
|
let error;
|
|
1056
|
-
for (const [
|
|
1056
|
+
for (const [tableName, api] of Object.entries(ctx.syncApis)) {
|
|
1057
1057
|
if (!api.firstLoad) {
|
|
1058
|
-
ctx.logger.error(`[dync] firstLoad:no-api-function
|
|
1058
|
+
ctx.logger.error(`[dync] firstLoad:no-api-function tableName=${tableName}`);
|
|
1059
1059
|
continue;
|
|
1060
1060
|
}
|
|
1061
1061
|
try {
|
|
1062
|
-
ctx.logger.info(`[dync] firstLoad:start
|
|
1062
|
+
ctx.logger.info(`[dync] firstLoad:start tableName=${tableName}`);
|
|
1063
1063
|
let lastId;
|
|
1064
1064
|
let isEmptyTable = true;
|
|
1065
1065
|
let batchCount = 0;
|
|
@@ -1069,19 +1069,19 @@ async function startFirstLoad(ctx) {
|
|
|
1069
1069
|
const batch = await api.firstLoad(lastId);
|
|
1070
1070
|
if (!batch?.length) break;
|
|
1071
1071
|
batchCount++;
|
|
1072
|
-
const { inserted, updated } = await processBatchInChunks(ctx,
|
|
1072
|
+
const { inserted, updated } = await processBatchInChunks(ctx, tableName, batch, isEmptyTable, lastId === void 0);
|
|
1073
1073
|
totalInserted += inserted;
|
|
1074
1074
|
totalUpdated += updated;
|
|
1075
1075
|
if (ctx.onProgress) {
|
|
1076
1076
|
ctx.onProgress({
|
|
1077
|
-
table:
|
|
1077
|
+
table: tableName,
|
|
1078
1078
|
inserted: totalInserted,
|
|
1079
1079
|
updated: totalUpdated,
|
|
1080
1080
|
total: totalInserted + totalUpdated
|
|
1081
1081
|
});
|
|
1082
1082
|
}
|
|
1083
1083
|
if (lastId === void 0) {
|
|
1084
|
-
isEmptyTable = await ctx.table(
|
|
1084
|
+
isEmptyTable = await ctx.table(tableName).count() === batch.length;
|
|
1085
1085
|
}
|
|
1086
1086
|
if (lastId !== void 0 && lastId === batch[batch.length - 1].id) {
|
|
1087
1087
|
throw new Error(`Duplicate records downloaded, stopping to prevent infinite loop`);
|
|
@@ -1091,10 +1091,10 @@ async function startFirstLoad(ctx) {
|
|
|
1091
1091
|
await yieldToEventLoop();
|
|
1092
1092
|
}
|
|
1093
1093
|
}
|
|
1094
|
-
ctx.logger.info(`[dync] firstLoad:done
|
|
1094
|
+
ctx.logger.info(`[dync] firstLoad:done tableName=${tableName} inserted=${totalInserted} updated=${totalUpdated}`);
|
|
1095
1095
|
} catch (err) {
|
|
1096
1096
|
error = error ?? err;
|
|
1097
|
-
ctx.logger.error(`[dync] firstLoad:error
|
|
1097
|
+
ctx.logger.error(`[dync] firstLoad:error tableName=${tableName}`, err);
|
|
1098
1098
|
}
|
|
1099
1099
|
}
|
|
1100
1100
|
await ctx.state.setState((syncState) => ({
|
|
@@ -1104,10 +1104,10 @@ async function startFirstLoad(ctx) {
|
|
|
1104
1104
|
}));
|
|
1105
1105
|
ctx.logger.debug("[dync] First load completed");
|
|
1106
1106
|
}
|
|
1107
|
-
async function processBatchInChunks(ctx,
|
|
1108
|
-
let newest = new Date(ctx.state.getState().lastPulled[
|
|
1109
|
-
return ctx.withTransaction("rw", [
|
|
1110
|
-
const txTable = tables[
|
|
1107
|
+
async function processBatchInChunks(ctx, tableName, batch, isEmptyTable, isFirstBatch) {
|
|
1108
|
+
let newest = new Date(ctx.state.getState().lastPulled[tableName] || 0);
|
|
1109
|
+
return ctx.withTransaction("rw", [tableName, DYNC_STATE_TABLE], async (tables) => {
|
|
1110
|
+
const txTable = tables[tableName];
|
|
1111
1111
|
let tableIsEmpty = isEmptyTable;
|
|
1112
1112
|
if (isFirstBatch) {
|
|
1113
1113
|
const count = await txTable.count();
|
|
@@ -1142,7 +1142,7 @@ async function processBatchInChunks(ctx, stateKey, batch, isEmptyTable, isFirstB
|
|
|
1142
1142
|
...syncState,
|
|
1143
1143
|
lastPulled: {
|
|
1144
1144
|
...syncState.lastPulled,
|
|
1145
|
-
[
|
|
1145
|
+
[tableName]: newest.toISOString()
|
|
1146
1146
|
}
|
|
1147
1147
|
}));
|
|
1148
1148
|
return { inserted, updated };
|
|
@@ -1207,23 +1207,23 @@ async function startFirstLoadBatch(ctx) {
|
|
|
1207
1207
|
break;
|
|
1208
1208
|
}
|
|
1209
1209
|
batchCount++;
|
|
1210
|
-
for (const [
|
|
1211
|
-
if (!ctx.batchSync.syncTables.includes(
|
|
1212
|
-
ctx.logger.warn(`[dync] firstLoad:batch:unknown-table
|
|
1210
|
+
for (const [tableName, batch] of Object.entries(result.data)) {
|
|
1211
|
+
if (!ctx.batchSync.syncTables.includes(tableName)) {
|
|
1212
|
+
ctx.logger.warn(`[dync] firstLoad:batch:unknown-table tableName=${tableName}`);
|
|
1213
1213
|
continue;
|
|
1214
1214
|
}
|
|
1215
1215
|
if (!batch?.length) continue;
|
|
1216
|
-
const isFirstBatch = progress[
|
|
1217
|
-
const isEmptyTable = isFirstBatch && await ctx.table(
|
|
1218
|
-
const { inserted, updated } = await processBatchInChunks(ctx,
|
|
1219
|
-
progress[
|
|
1220
|
-
progress[
|
|
1216
|
+
const isFirstBatch = progress[tableName].inserted === 0 && progress[tableName].updated === 0;
|
|
1217
|
+
const isEmptyTable = isFirstBatch && await ctx.table(tableName).count() === 0;
|
|
1218
|
+
const { inserted, updated } = await processBatchInChunks(ctx, tableName, batch, isEmptyTable, isFirstBatch);
|
|
1219
|
+
progress[tableName].inserted += inserted;
|
|
1220
|
+
progress[tableName].updated += updated;
|
|
1221
1221
|
if (ctx.onProgress) {
|
|
1222
1222
|
ctx.onProgress({
|
|
1223
|
-
table:
|
|
1224
|
-
inserted: progress[
|
|
1225
|
-
updated: progress[
|
|
1226
|
-
total: progress[
|
|
1223
|
+
table: tableName,
|
|
1224
|
+
inserted: progress[tableName].inserted,
|
|
1225
|
+
updated: progress[tableName].updated,
|
|
1226
|
+
total: progress[tableName].inserted + progress[tableName].updated
|
|
1227
1227
|
});
|
|
1228
1228
|
}
|
|
1229
1229
|
}
|
|
@@ -1235,8 +1235,8 @@ async function startFirstLoadBatch(ctx) {
|
|
|
1235
1235
|
break;
|
|
1236
1236
|
}
|
|
1237
1237
|
}
|
|
1238
|
-
for (const [
|
|
1239
|
-
ctx.logger.info(`[dync] firstLoad:batch:done
|
|
1238
|
+
for (const [tableName, p] of Object.entries(progress)) {
|
|
1239
|
+
ctx.logger.info(`[dync] firstLoad:batch:done tableName=${tableName} inserted=${p.inserted} updated=${p.updated}`);
|
|
1240
1240
|
}
|
|
1241
1241
|
} catch (err) {
|
|
1242
1242
|
error = err;
|
|
@@ -1606,8 +1606,8 @@ var DyncBase = class {
|
|
|
1606
1606
|
this.logger.warn(`[dync] No conflict found for localId: ${localId}`);
|
|
1607
1607
|
return;
|
|
1608
1608
|
}
|
|
1609
|
-
await this.withTransaction("rw", [conflict.
|
|
1610
|
-
const txTable = tables[conflict.
|
|
1609
|
+
await this.withTransaction("rw", [conflict.tableName, DYNC_STATE_TABLE], async (tables) => {
|
|
1610
|
+
const txTable = tables[conflict.tableName];
|
|
1611
1611
|
if (!keepLocal) {
|
|
1612
1612
|
const item = await txTable.get(localId);
|
|
1613
1613
|
if (item) {
|
|
@@ -1620,7 +1620,7 @@ var DyncBase = class {
|
|
|
1620
1620
|
}
|
|
1621
1621
|
await this.state.setState((syncState) => ({
|
|
1622
1622
|
...syncState,
|
|
1623
|
-
pendingChanges: syncState.pendingChanges.filter((p) => !(p.localId === localId && p.
|
|
1623
|
+
pendingChanges: syncState.pendingChanges.filter((p) => !(p.localId === localId && p.tableName === conflict.tableName))
|
|
1624
1624
|
}));
|
|
1625
1625
|
}
|
|
1626
1626
|
await this.state.setState((syncState) => {
|