@anfenn/dync 1.0.1 → 1.0.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/README.md +2 -2
- 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 +9 -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/react/index.cjs
CHANGED
|
@@ -175,7 +175,7 @@ var StateManager = class {
|
|
|
175
175
|
}
|
|
176
176
|
addPendingChange(change) {
|
|
177
177
|
const next = clonePersistedState(this.persistedState);
|
|
178
|
-
const queueItem = next.pendingChanges.find((p) => p.localId === change.localId && p.
|
|
178
|
+
const queueItem = next.pendingChanges.find((p) => p.localId === change.localId && p.tableName === change.tableName);
|
|
179
179
|
const omittedChanges = omitFields(change.changes, LOCAL_ONLY_SYNC_FIELDS);
|
|
180
180
|
const omittedBefore = omitFields(change.before, LOCAL_ONLY_SYNC_FIELDS);
|
|
181
181
|
const omittedAfter = omitFields(change.after, LOCAL_ONLY_SYNC_FIELDS);
|
|
@@ -196,7 +196,7 @@ var StateManager = class {
|
|
|
196
196
|
next.pendingChanges = [...next.pendingChanges];
|
|
197
197
|
next.pendingChanges.push({
|
|
198
198
|
action,
|
|
199
|
-
|
|
199
|
+
tableName: change.tableName,
|
|
200
200
|
localId: change.localId,
|
|
201
201
|
id: change.id,
|
|
202
202
|
version: 1,
|
|
@@ -208,18 +208,18 @@ var StateManager = class {
|
|
|
208
208
|
this.persistedState = next;
|
|
209
209
|
return this.persist();
|
|
210
210
|
}
|
|
211
|
-
samePendingVersion(
|
|
212
|
-
return this.persistedState.pendingChanges.find((p) => p.localId === localId && p.
|
|
211
|
+
samePendingVersion(tableName, localId, version) {
|
|
212
|
+
return this.persistedState.pendingChanges.find((p) => p.localId === localId && p.tableName === tableName)?.version === version;
|
|
213
213
|
}
|
|
214
|
-
removePendingChange(localId,
|
|
214
|
+
removePendingChange(localId, tableName) {
|
|
215
215
|
const next = clonePersistedState(this.persistedState);
|
|
216
|
-
next.pendingChanges = next.pendingChanges.filter((p) => !(p.localId === localId && p.
|
|
216
|
+
next.pendingChanges = next.pendingChanges.filter((p) => !(p.localId === localId && p.tableName === tableName));
|
|
217
217
|
this.persistedState = next;
|
|
218
218
|
return this.persist();
|
|
219
219
|
}
|
|
220
|
-
updatePendingChange(
|
|
220
|
+
updatePendingChange(tableName, localId, action, id) {
|
|
221
221
|
const next = clonePersistedState(this.persistedState);
|
|
222
|
-
const changeItem = next.pendingChanges.find((p) => p.
|
|
222
|
+
const changeItem = next.pendingChanges.find((p) => p.tableName === tableName && p.localId === localId);
|
|
223
223
|
if (changeItem) {
|
|
224
224
|
changeItem.action = action;
|
|
225
225
|
if (id) changeItem.id = id;
|
|
@@ -228,9 +228,9 @@ var StateManager = class {
|
|
|
228
228
|
}
|
|
229
229
|
return Promise.resolve();
|
|
230
230
|
}
|
|
231
|
-
setPendingChangeBefore(
|
|
231
|
+
setPendingChangeBefore(tableName, localId, before) {
|
|
232
232
|
const next = clonePersistedState(this.persistedState);
|
|
233
|
-
const changeItem = next.pendingChanges.find((p) => p.
|
|
233
|
+
const changeItem = next.pendingChanges.find((p) => p.tableName === tableName && p.localId === localId);
|
|
234
234
|
if (changeItem) {
|
|
235
235
|
changeItem.before = { ...changeItem.before ?? {}, ...before };
|
|
236
236
|
this.persistedState = next;
|
|
@@ -301,7 +301,7 @@ function cloneConflicts(conflicts) {
|
|
|
301
301
|
const next = {};
|
|
302
302
|
for (const [key, value] of Object.entries(conflicts)) {
|
|
303
303
|
next[key] = {
|
|
304
|
-
|
|
304
|
+
tableName: value.tableName,
|
|
305
305
|
fields: value.fields.map((field) => ({ ...field }))
|
|
306
306
|
};
|
|
307
307
|
}
|
|
@@ -412,7 +412,7 @@ function enhanceSyncTable({ table, tableName, withTransaction, state, enhancedTa
|
|
|
412
412
|
result = await rawAdd(syncedItem);
|
|
413
413
|
await state.addPendingChange({
|
|
414
414
|
action: "create" /* Create */,
|
|
415
|
-
|
|
415
|
+
tableName,
|
|
416
416
|
localId,
|
|
417
417
|
changes: syncedItem,
|
|
418
418
|
before: null,
|
|
@@ -440,7 +440,7 @@ function enhanceSyncTable({ table, tableName, withTransaction, state, enhancedTa
|
|
|
440
440
|
result = await rawPut(syncedItem);
|
|
441
441
|
await state.addPendingChange({
|
|
442
442
|
action: isUpdate ? "update" /* Update */ : "create" /* Create */,
|
|
443
|
-
|
|
443
|
+
tableName,
|
|
444
444
|
localId,
|
|
445
445
|
id: existingRecord?.id,
|
|
446
446
|
changes: syncedItem,
|
|
@@ -467,7 +467,7 @@ function enhanceSyncTable({ table, tableName, withTransaction, state, enhancedTa
|
|
|
467
467
|
if (result > 0) {
|
|
468
468
|
await state.addPendingChange({
|
|
469
469
|
action: "update" /* Update */,
|
|
470
|
-
|
|
470
|
+
tableName,
|
|
471
471
|
localId: key,
|
|
472
472
|
id: record.id,
|
|
473
473
|
changes: updatedChanges,
|
|
@@ -491,7 +491,7 @@ function enhanceSyncTable({ table, tableName, withTransaction, state, enhancedTa
|
|
|
491
491
|
deletedLocalId = record._localId;
|
|
492
492
|
await state.addPendingChange({
|
|
493
493
|
action: "remove" /* Remove */,
|
|
494
|
-
|
|
494
|
+
tableName,
|
|
495
495
|
localId: record._localId,
|
|
496
496
|
id: record.id,
|
|
497
497
|
changes: null,
|
|
@@ -520,7 +520,7 @@ function enhanceSyncTable({ table, tableName, withTransaction, state, enhancedTa
|
|
|
520
520
|
for (const syncedItem of syncedItems) {
|
|
521
521
|
await state.addPendingChange({
|
|
522
522
|
action: "create" /* Create */,
|
|
523
|
-
|
|
523
|
+
tableName,
|
|
524
524
|
localId: syncedItem._localId,
|
|
525
525
|
changes: syncedItem,
|
|
526
526
|
before: null,
|
|
@@ -558,7 +558,7 @@ function enhanceSyncTable({ table, tableName, withTransaction, state, enhancedTa
|
|
|
558
558
|
const existing = existingMap.get(syncedItem._localId);
|
|
559
559
|
await state.addPendingChange({
|
|
560
560
|
action: existing ? "update" /* Update */ : "create" /* Create */,
|
|
561
|
-
|
|
561
|
+
tableName,
|
|
562
562
|
localId: syncedItem._localId,
|
|
563
563
|
id: existing?.id,
|
|
564
564
|
changes: syncedItem,
|
|
@@ -599,7 +599,7 @@ function enhanceSyncTable({ table, tableName, withTransaction, state, enhancedTa
|
|
|
599
599
|
updatedKeys.push(record._localId);
|
|
600
600
|
await state.addPendingChange({
|
|
601
601
|
action: "update" /* Update */,
|
|
602
|
-
|
|
602
|
+
tableName,
|
|
603
603
|
localId: record._localId,
|
|
604
604
|
id: record.id,
|
|
605
605
|
changes,
|
|
@@ -626,7 +626,7 @@ function enhanceSyncTable({ table, tableName, withTransaction, state, enhancedTa
|
|
|
626
626
|
deletedLocalIds.push(record._localId);
|
|
627
627
|
await state.addPendingChange({
|
|
628
628
|
action: "remove" /* Remove */,
|
|
629
|
-
|
|
629
|
+
tableName,
|
|
630
630
|
localId: record._localId,
|
|
631
631
|
id: record.id,
|
|
632
632
|
changes: null,
|
|
@@ -650,7 +650,7 @@ function enhanceSyncTable({ table, tableName, withTransaction, state, enhancedTa
|
|
|
650
650
|
deletedLocalIds.push(record._localId);
|
|
651
651
|
await state.addPendingChange({
|
|
652
652
|
action: "remove" /* Remove */,
|
|
653
|
-
|
|
653
|
+
tableName,
|
|
654
654
|
localId: record._localId,
|
|
655
655
|
id: record.id,
|
|
656
656
|
changes: null,
|
|
@@ -679,33 +679,33 @@ function enhanceSyncTable({ table, tableName, withTransaction, state, enhancedTa
|
|
|
679
679
|
async function pullAll(ctx) {
|
|
680
680
|
let firstSyncError;
|
|
681
681
|
const changedTables = [];
|
|
682
|
-
for (const [
|
|
682
|
+
for (const [tableName, api] of Object.entries(ctx.syncApis)) {
|
|
683
683
|
try {
|
|
684
|
-
const lastPulled = ctx.state.getState().lastPulled[
|
|
684
|
+
const lastPulled = ctx.state.getState().lastPulled[tableName];
|
|
685
685
|
const since = lastPulled ? new Date(lastPulled) : /* @__PURE__ */ new Date(0);
|
|
686
|
-
ctx.logger.debug(`[dync] pull:start
|
|
686
|
+
ctx.logger.debug(`[dync] pull:start tableName=${tableName} since=${since.toISOString()}`);
|
|
687
687
|
const serverData = await api.list(since);
|
|
688
|
-
const changed = await processPullData(
|
|
689
|
-
if (changed) changedTables.push(
|
|
688
|
+
const changed = await processPullData(tableName, serverData, since, ctx);
|
|
689
|
+
if (changed) changedTables.push(tableName);
|
|
690
690
|
} catch (err) {
|
|
691
691
|
firstSyncError = firstSyncError ?? err;
|
|
692
|
-
ctx.logger.error(`[dync] pull:error
|
|
692
|
+
ctx.logger.error(`[dync] pull:error tableName=${tableName}`, err);
|
|
693
693
|
}
|
|
694
694
|
}
|
|
695
695
|
return { error: firstSyncError, changedTables };
|
|
696
696
|
}
|
|
697
|
-
async function handleRemoteItemUpdate(table,
|
|
698
|
-
const pendingChange = ctx.state.getState().pendingChanges.find((p) => p.
|
|
697
|
+
async function handleRemoteItemUpdate(table, tableName, localItem, remote, ctx) {
|
|
698
|
+
const pendingChange = ctx.state.getState().pendingChanges.find((p) => p.tableName === tableName && p.localId === localItem._localId);
|
|
699
699
|
const conflictStrategy = ctx.conflictResolutionStrategy;
|
|
700
700
|
if (pendingChange) {
|
|
701
|
-
ctx.logger.debug(`[dync] pull:conflict-strategy:${conflictStrategy}
|
|
701
|
+
ctx.logger.debug(`[dync] pull:conflict-strategy:${conflictStrategy} tableName=${tableName} id=${remote.id}`);
|
|
702
702
|
switch (conflictStrategy) {
|
|
703
703
|
case "local-wins":
|
|
704
704
|
break;
|
|
705
705
|
case "remote-wins": {
|
|
706
706
|
const merged = { ...remote, _localId: localItem._localId };
|
|
707
707
|
await table.raw.update(localItem._localId, merged);
|
|
708
|
-
await ctx.state.removePendingChange(localItem._localId,
|
|
708
|
+
await ctx.state.removePendingChange(localItem._localId, tableName);
|
|
709
709
|
break;
|
|
710
710
|
}
|
|
711
711
|
case "try-shallow-merge": {
|
|
@@ -718,7 +718,7 @@ async function handleRemoteItemUpdate(table, stateKey, localItem, remote, ctx) {
|
|
|
718
718
|
...syncState,
|
|
719
719
|
conflicts: {
|
|
720
720
|
...syncState.conflicts || {},
|
|
721
|
-
[localItem._localId]: {
|
|
721
|
+
[localItem._localId]: { tableName, fields }
|
|
722
722
|
}
|
|
723
723
|
}));
|
|
724
724
|
} else {
|
|
@@ -741,7 +741,7 @@ async function handleRemoteItemUpdate(table, stateKey, localItem, remote, ctx) {
|
|
|
741
741
|
} else {
|
|
742
742
|
const merged = { ...localItem, ...remote };
|
|
743
743
|
await table.raw.update(localItem._localId, merged);
|
|
744
|
-
ctx.logger.debug(`[dync] pull:merge-remote
|
|
744
|
+
ctx.logger.debug(`[dync] pull:merge-remote tableName=${tableName} id=${remote.id}`);
|
|
745
745
|
}
|
|
746
746
|
}
|
|
747
747
|
async function pullAllBatch(ctx) {
|
|
@@ -755,17 +755,17 @@ async function pullAllBatch(ctx) {
|
|
|
755
755
|
}
|
|
756
756
|
ctx.logger.debug(`[dync] pull:batch:start tables=${[...ctx.batchSync.syncTables].join(",")}`, sinceMap);
|
|
757
757
|
const serverDataByTable = await ctx.batchSync.pull(sinceMap);
|
|
758
|
-
for (const [
|
|
759
|
-
if (!ctx.batchSync.syncTables.includes(
|
|
760
|
-
ctx.logger.warn(`[dync] pull:batch:unknown-table
|
|
758
|
+
for (const [tableName, serverData] of Object.entries(serverDataByTable)) {
|
|
759
|
+
if (!ctx.batchSync.syncTables.includes(tableName)) {
|
|
760
|
+
ctx.logger.warn(`[dync] pull:batch:unknown-table tableName=${tableName}`);
|
|
761
761
|
continue;
|
|
762
762
|
}
|
|
763
763
|
try {
|
|
764
|
-
const changed = await processPullData(
|
|
765
|
-
if (changed) changedTables.push(
|
|
764
|
+
const changed = await processPullData(tableName, serverData, sinceMap[tableName], ctx);
|
|
765
|
+
if (changed) changedTables.push(tableName);
|
|
766
766
|
} catch (err) {
|
|
767
767
|
firstSyncError = firstSyncError ?? err;
|
|
768
|
-
ctx.logger.error(`[dync] pull:batch:error
|
|
768
|
+
ctx.logger.error(`[dync] pull:batch:error tableName=${tableName}`, err);
|
|
769
769
|
}
|
|
770
770
|
}
|
|
771
771
|
} catch (err) {
|
|
@@ -774,40 +774,40 @@ async function pullAllBatch(ctx) {
|
|
|
774
774
|
}
|
|
775
775
|
return { error: firstSyncError, changedTables };
|
|
776
776
|
}
|
|
777
|
-
async function processPullData(
|
|
777
|
+
async function processPullData(tableName, serverData, since, ctx) {
|
|
778
778
|
if (!serverData?.length) return false;
|
|
779
|
-
ctx.logger.debug(`[dync] pull:process
|
|
779
|
+
ctx.logger.debug(`[dync] pull:process tableName=${tableName} count=${serverData.length}`);
|
|
780
780
|
let newest = since;
|
|
781
781
|
let hasChanges = false;
|
|
782
|
-
await ctx.withTransaction("rw", [
|
|
783
|
-
const txTable = tables[
|
|
782
|
+
await ctx.withTransaction("rw", [tableName, DYNC_STATE_TABLE], async (tables) => {
|
|
783
|
+
const txTable = tables[tableName];
|
|
784
784
|
const pendingRemovalById = new Set(
|
|
785
|
-
ctx.state.getState().pendingChanges.filter((p) => p.
|
|
785
|
+
ctx.state.getState().pendingChanges.filter((p) => p.tableName === tableName && p.action === "remove" /* Remove */).map((p) => p.id)
|
|
786
786
|
);
|
|
787
787
|
for (const remote of serverData) {
|
|
788
788
|
const remoteUpdated = new Date(remote.updated_at);
|
|
789
789
|
if (remoteUpdated > newest) newest = remoteUpdated;
|
|
790
790
|
if (pendingRemovalById.has(remote.id)) {
|
|
791
|
-
ctx.logger.debug(`[dync] pull:skip-pending-remove
|
|
791
|
+
ctx.logger.debug(`[dync] pull:skip-pending-remove tableName=${tableName} id=${remote.id}`);
|
|
792
792
|
continue;
|
|
793
793
|
}
|
|
794
794
|
const localItem = await txTable.where("id").equals(remote.id).first();
|
|
795
795
|
if (remote.deleted) {
|
|
796
796
|
if (localItem) {
|
|
797
797
|
await txTable.raw.delete(localItem._localId);
|
|
798
|
-
ctx.logger.debug(`[dync] pull:remove
|
|
798
|
+
ctx.logger.debug(`[dync] pull:remove tableName=${tableName} id=${remote.id}`);
|
|
799
799
|
hasChanges = true;
|
|
800
800
|
}
|
|
801
801
|
continue;
|
|
802
802
|
}
|
|
803
803
|
delete remote.deleted;
|
|
804
804
|
if (localItem) {
|
|
805
|
-
await handleRemoteItemUpdate(txTable,
|
|
805
|
+
await handleRemoteItemUpdate(txTable, tableName, localItem, remote, ctx);
|
|
806
806
|
hasChanges = true;
|
|
807
807
|
} else {
|
|
808
808
|
const newLocalItem = { ...remote, _localId: createLocalId() };
|
|
809
809
|
await txTable.raw.add(newLocalItem);
|
|
810
|
-
ctx.logger.debug(`[dync] pull:add
|
|
810
|
+
ctx.logger.debug(`[dync] pull:add tableName=${tableName} id=${remote.id}`);
|
|
811
811
|
hasChanges = true;
|
|
812
812
|
}
|
|
813
813
|
}
|
|
@@ -815,7 +815,7 @@ async function processPullData(stateKey, serverData, since, ctx) {
|
|
|
815
815
|
...syncState,
|
|
816
816
|
lastPulled: {
|
|
817
817
|
...syncState.lastPulled,
|
|
818
|
-
[
|
|
818
|
+
[tableName]: newest.toISOString()
|
|
819
819
|
}
|
|
820
820
|
}));
|
|
821
821
|
});
|
|
@@ -824,35 +824,35 @@ async function processPullData(stateKey, serverData, since, ctx) {
|
|
|
824
824
|
|
|
825
825
|
// src/core/pushOperations.ts
|
|
826
826
|
async function handleRemoveSuccess(change, ctx) {
|
|
827
|
-
const {
|
|
828
|
-
ctx.logger.debug(`[dync] push:remove:success
|
|
829
|
-
await ctx.state.removePendingChange(localId,
|
|
827
|
+
const { tableName, localId, id } = change;
|
|
828
|
+
ctx.logger.debug(`[dync] push:remove:success tableName=${tableName} localId=${localId} id=${id}`);
|
|
829
|
+
await ctx.state.removePendingChange(localId, tableName);
|
|
830
830
|
}
|
|
831
831
|
async function handleUpdateSuccess(change, ctx) {
|
|
832
|
-
const {
|
|
833
|
-
ctx.logger.debug(`[dync] push:update:success
|
|
834
|
-
if (ctx.state.samePendingVersion(
|
|
835
|
-
await ctx.state.removePendingChange(localId,
|
|
832
|
+
const { tableName, localId, version, changes } = change;
|
|
833
|
+
ctx.logger.debug(`[dync] push:update:success tableName=${tableName} localId=${localId} id=${change.id}`);
|
|
834
|
+
if (ctx.state.samePendingVersion(tableName, localId, version)) {
|
|
835
|
+
await ctx.state.removePendingChange(localId, tableName);
|
|
836
836
|
} else {
|
|
837
|
-
await ctx.state.setPendingChangeBefore(
|
|
837
|
+
await ctx.state.setPendingChangeBefore(tableName, localId, changes);
|
|
838
838
|
}
|
|
839
839
|
}
|
|
840
840
|
async function handleCreateSuccess(change, serverResult, ctx) {
|
|
841
|
-
const {
|
|
842
|
-
ctx.logger.debug(`[dync] push:create:success
|
|
843
|
-
await ctx.withTransaction("rw", [
|
|
844
|
-
const txTable = tables[
|
|
841
|
+
const { tableName, localId, version, changes, id } = change;
|
|
842
|
+
ctx.logger.debug(`[dync] push:create:success tableName=${tableName} localId=${localId} id=${id ?? serverResult.id}`);
|
|
843
|
+
await ctx.withTransaction("rw", [tableName, DYNC_STATE_TABLE], async (tables) => {
|
|
844
|
+
const txTable = tables[tableName];
|
|
845
845
|
const wasChanged = await txTable.raw.update(localId, serverResult) ?? 0;
|
|
846
|
-
if (wasChanged && ctx.state.samePendingVersion(
|
|
847
|
-
await ctx.state.removePendingChange(localId,
|
|
846
|
+
if (wasChanged && ctx.state.samePendingVersion(tableName, localId, version)) {
|
|
847
|
+
await ctx.state.removePendingChange(localId, tableName);
|
|
848
848
|
} else {
|
|
849
849
|
const nextAction = wasChanged ? "update" /* Update */ : "remove" /* Remove */;
|
|
850
|
-
await ctx.state.updatePendingChange(
|
|
850
|
+
await ctx.state.updatePendingChange(tableName, localId, nextAction, serverResult.id);
|
|
851
851
|
if (nextAction === "remove" /* Remove */) return;
|
|
852
852
|
}
|
|
853
853
|
});
|
|
854
854
|
const finalItem = { ...changes, ...serverResult, _localId: localId };
|
|
855
|
-
ctx.syncOptions.onAfterRemoteAdd?.(
|
|
855
|
+
ctx.syncOptions.onAfterRemoteAdd?.(tableName, finalItem);
|
|
856
856
|
}
|
|
857
857
|
async function pushAll(ctx) {
|
|
858
858
|
let firstSyncError;
|
|
@@ -868,15 +868,15 @@ async function pushAll(ctx) {
|
|
|
868
868
|
return firstSyncError;
|
|
869
869
|
}
|
|
870
870
|
async function pushOne(change, ctx) {
|
|
871
|
-
const api = ctx.syncApis[change.
|
|
871
|
+
const api = ctx.syncApis[change.tableName];
|
|
872
872
|
if (!api) return;
|
|
873
|
-
ctx.logger.debug(`[dync] push:attempt action=${change.action}
|
|
874
|
-
const { action,
|
|
873
|
+
ctx.logger.debug(`[dync] push:attempt action=${change.action} tableName=${change.tableName} localId=${change.localId}`);
|
|
874
|
+
const { action, tableName, localId, id, changes, after } = change;
|
|
875
875
|
switch (action) {
|
|
876
876
|
case "remove" /* Remove */:
|
|
877
877
|
if (!id) {
|
|
878
|
-
ctx.logger.warn(`[dync] push:remove:no-id
|
|
879
|
-
await ctx.state.removePendingChange(localId,
|
|
878
|
+
ctx.logger.warn(`[dync] push:remove:no-id tableName=${tableName} localId=${localId}`);
|
|
879
|
+
await ctx.state.removePendingChange(localId, tableName);
|
|
880
880
|
return;
|
|
881
881
|
}
|
|
882
882
|
await api.remove(id);
|
|
@@ -884,7 +884,7 @@ async function pushOne(change, ctx) {
|
|
|
884
884
|
break;
|
|
885
885
|
case "update" /* Update */: {
|
|
886
886
|
if (ctx.state.hasConflicts(localId)) {
|
|
887
|
-
ctx.logger.warn(`[dync] push:update:skipping-with-conflicts
|
|
887
|
+
ctx.logger.warn(`[dync] push:update:skipping-with-conflicts tableName=${tableName} localId=${localId} id=${id}`);
|
|
888
888
|
return;
|
|
889
889
|
}
|
|
890
890
|
const exists = await api.update(id, changes, after);
|
|
@@ -900,9 +900,9 @@ async function pushOne(change, ctx) {
|
|
|
900
900
|
if (result) {
|
|
901
901
|
await handleCreateSuccess(change, result, ctx);
|
|
902
902
|
} else {
|
|
903
|
-
ctx.logger.warn(`[dync] push:create:no-result
|
|
904
|
-
if (ctx.state.samePendingVersion(
|
|
905
|
-
await ctx.state.removePendingChange(localId,
|
|
903
|
+
ctx.logger.warn(`[dync] push:create:no-result tableName=${tableName} localId=${localId} id=${id}`);
|
|
904
|
+
if (ctx.state.samePendingVersion(tableName, localId, change.version)) {
|
|
905
|
+
await ctx.state.removePendingChange(localId, tableName);
|
|
906
906
|
}
|
|
907
907
|
}
|
|
908
908
|
break;
|
|
@@ -910,21 +910,21 @@ async function pushOne(change, ctx) {
|
|
|
910
910
|
}
|
|
911
911
|
}
|
|
912
912
|
async function handleMissingRemoteRecord(change, ctx) {
|
|
913
|
-
const {
|
|
913
|
+
const { tableName, localId } = change;
|
|
914
914
|
const strategy = ctx.syncOptions.missingRemoteRecordDuringUpdateStrategy;
|
|
915
915
|
let localItem;
|
|
916
|
-
await ctx.withTransaction("rw", [
|
|
917
|
-
const txTable = tables[
|
|
916
|
+
await ctx.withTransaction("rw", [tableName, DYNC_STATE_TABLE], async (tables) => {
|
|
917
|
+
const txTable = tables[tableName];
|
|
918
918
|
localItem = await txTable.get(localId);
|
|
919
919
|
if (!localItem) {
|
|
920
|
-
ctx.logger.warn(`[dync] push:missing-remote:no-local-item
|
|
921
|
-
await ctx.state.removePendingChange(localId,
|
|
920
|
+
ctx.logger.warn(`[dync] push:missing-remote:no-local-item tableName=${tableName} localId=${localId}`);
|
|
921
|
+
await ctx.state.removePendingChange(localId, tableName);
|
|
922
922
|
return;
|
|
923
923
|
}
|
|
924
924
|
switch (strategy) {
|
|
925
925
|
case "delete-local-record":
|
|
926
926
|
await txTable.raw.delete(localId);
|
|
927
|
-
ctx.logger.debug(`[dync] push:missing-remote:${strategy}
|
|
927
|
+
ctx.logger.debug(`[dync] push:missing-remote:${strategy} tableName=${tableName} id=${localItem.id}`);
|
|
928
928
|
break;
|
|
929
929
|
case "insert-remote-record": {
|
|
930
930
|
const newItem = {
|
|
@@ -936,36 +936,36 @@ async function handleMissingRemoteRecord(change, ctx) {
|
|
|
936
936
|
await txTable.raw.delete(localId);
|
|
937
937
|
await ctx.state.addPendingChange({
|
|
938
938
|
action: "create" /* Create */,
|
|
939
|
-
|
|
939
|
+
tableName,
|
|
940
940
|
localId: newItem._localId,
|
|
941
941
|
changes: newItem,
|
|
942
942
|
before: null
|
|
943
943
|
});
|
|
944
|
-
ctx.logger.debug(`[dync] push:missing-remote:${strategy}
|
|
944
|
+
ctx.logger.debug(`[dync] push:missing-remote:${strategy} tableName=${tableName} id=${newItem.id}`);
|
|
945
945
|
break;
|
|
946
946
|
}
|
|
947
947
|
case "ignore":
|
|
948
|
-
ctx.logger.debug(`[dync] push:missing-remote:${strategy}
|
|
948
|
+
ctx.logger.debug(`[dync] push:missing-remote:${strategy} tableName=${tableName} id=${localItem.id}`);
|
|
949
949
|
break;
|
|
950
950
|
default:
|
|
951
|
-
ctx.logger.error(`[dync] push:missing-remote:unknown-strategy
|
|
951
|
+
ctx.logger.error(`[dync] push:missing-remote:unknown-strategy tableName=${tableName} id=${localItem.id} strategy=${strategy}`);
|
|
952
952
|
break;
|
|
953
953
|
}
|
|
954
|
-
await ctx.state.removePendingChange(localId,
|
|
954
|
+
await ctx.state.removePendingChange(localId, tableName);
|
|
955
955
|
});
|
|
956
956
|
ctx.syncOptions.onAfterMissingRemoteRecordDuringUpdate?.(strategy, localItem);
|
|
957
957
|
}
|
|
958
958
|
async function pushAllBatch(ctx) {
|
|
959
959
|
let firstSyncError;
|
|
960
960
|
try {
|
|
961
|
-
const changesSnapshot = [...ctx.state.getState().pendingChanges].filter((change) => ctx.batchSync.syncTables.includes(change.
|
|
961
|
+
const changesSnapshot = [...ctx.state.getState().pendingChanges].filter((change) => ctx.batchSync.syncTables.includes(change.tableName)).sort((a, b) => orderFor(a.action) - orderFor(b.action));
|
|
962
962
|
if (changesSnapshot.length === 0) {
|
|
963
963
|
ctx.logger.debug("[dync] push:batch:no-changes");
|
|
964
964
|
return void 0;
|
|
965
965
|
}
|
|
966
966
|
const changesToPush = changesSnapshot.filter((change) => {
|
|
967
967
|
if (change.action === "update" /* Update */ && ctx.state.hasConflicts(change.localId)) {
|
|
968
|
-
ctx.logger.warn(`[dync] push:batch:skipping-with-conflicts
|
|
968
|
+
ctx.logger.warn(`[dync] push:batch:skipping-with-conflicts tableName=${change.tableName} localId=${change.localId}`);
|
|
969
969
|
return false;
|
|
970
970
|
}
|
|
971
971
|
return true;
|
|
@@ -975,7 +975,7 @@ async function pushAllBatch(ctx) {
|
|
|
975
975
|
return void 0;
|
|
976
976
|
}
|
|
977
977
|
const payloads = changesToPush.map((change) => ({
|
|
978
|
-
table: change.
|
|
978
|
+
table: change.tableName,
|
|
979
979
|
action: change.action === "create" /* Create */ ? "add" : change.action === "update" /* Update */ ? "update" : "remove",
|
|
980
980
|
localId: change.localId,
|
|
981
981
|
id: change.id,
|
|
@@ -1007,12 +1007,12 @@ async function pushAllBatch(ctx) {
|
|
|
1007
1007
|
return firstSyncError;
|
|
1008
1008
|
}
|
|
1009
1009
|
async function processBatchPushResult(change, result, ctx) {
|
|
1010
|
-
const { action,
|
|
1010
|
+
const { action, tableName, localId } = change;
|
|
1011
1011
|
if (!result.success) {
|
|
1012
1012
|
if (action === "update" /* Update */) {
|
|
1013
1013
|
await handleMissingRemoteRecord(change, ctx);
|
|
1014
1014
|
} else {
|
|
1015
|
-
ctx.logger.warn(`[dync] push:batch:failed
|
|
1015
|
+
ctx.logger.warn(`[dync] push:batch:failed tableName=${tableName} localId=${localId} error=${result.error}`);
|
|
1016
1016
|
}
|
|
1017
1017
|
return;
|
|
1018
1018
|
}
|
|
@@ -1044,13 +1044,13 @@ async function startFirstLoad(ctx) {
|
|
|
1044
1044
|
return;
|
|
1045
1045
|
}
|
|
1046
1046
|
let error;
|
|
1047
|
-
for (const [
|
|
1047
|
+
for (const [tableName, api] of Object.entries(ctx.syncApis)) {
|
|
1048
1048
|
if (!api.firstLoad) {
|
|
1049
|
-
ctx.logger.error(`[dync] firstLoad:no-api-function
|
|
1049
|
+
ctx.logger.error(`[dync] firstLoad:no-api-function tableName=${tableName}`);
|
|
1050
1050
|
continue;
|
|
1051
1051
|
}
|
|
1052
1052
|
try {
|
|
1053
|
-
ctx.logger.info(`[dync] firstLoad:start
|
|
1053
|
+
ctx.logger.info(`[dync] firstLoad:start tableName=${tableName}`);
|
|
1054
1054
|
let lastId;
|
|
1055
1055
|
let isEmptyTable = true;
|
|
1056
1056
|
let batchCount = 0;
|
|
@@ -1060,19 +1060,19 @@ async function startFirstLoad(ctx) {
|
|
|
1060
1060
|
const batch = await api.firstLoad(lastId);
|
|
1061
1061
|
if (!batch?.length) break;
|
|
1062
1062
|
batchCount++;
|
|
1063
|
-
const { inserted, updated } = await processBatchInChunks(ctx,
|
|
1063
|
+
const { inserted, updated } = await processBatchInChunks(ctx, tableName, batch, isEmptyTable, lastId === void 0);
|
|
1064
1064
|
totalInserted += inserted;
|
|
1065
1065
|
totalUpdated += updated;
|
|
1066
1066
|
if (ctx.onProgress) {
|
|
1067
1067
|
ctx.onProgress({
|
|
1068
|
-
table:
|
|
1068
|
+
table: tableName,
|
|
1069
1069
|
inserted: totalInserted,
|
|
1070
1070
|
updated: totalUpdated,
|
|
1071
1071
|
total: totalInserted + totalUpdated
|
|
1072
1072
|
});
|
|
1073
1073
|
}
|
|
1074
1074
|
if (lastId === void 0) {
|
|
1075
|
-
isEmptyTable = await ctx.table(
|
|
1075
|
+
isEmptyTable = await ctx.table(tableName).count() === batch.length;
|
|
1076
1076
|
}
|
|
1077
1077
|
if (lastId !== void 0 && lastId === batch[batch.length - 1].id) {
|
|
1078
1078
|
throw new Error(`Duplicate records downloaded, stopping to prevent infinite loop`);
|
|
@@ -1082,10 +1082,10 @@ async function startFirstLoad(ctx) {
|
|
|
1082
1082
|
await yieldToEventLoop();
|
|
1083
1083
|
}
|
|
1084
1084
|
}
|
|
1085
|
-
ctx.logger.info(`[dync] firstLoad:done
|
|
1085
|
+
ctx.logger.info(`[dync] firstLoad:done tableName=${tableName} inserted=${totalInserted} updated=${totalUpdated}`);
|
|
1086
1086
|
} catch (err) {
|
|
1087
1087
|
error = error ?? err;
|
|
1088
|
-
ctx.logger.error(`[dync] firstLoad:error
|
|
1088
|
+
ctx.logger.error(`[dync] firstLoad:error tableName=${tableName}`, err);
|
|
1089
1089
|
}
|
|
1090
1090
|
}
|
|
1091
1091
|
await ctx.state.setState((syncState) => ({
|
|
@@ -1095,10 +1095,10 @@ async function startFirstLoad(ctx) {
|
|
|
1095
1095
|
}));
|
|
1096
1096
|
ctx.logger.debug("[dync] First load completed");
|
|
1097
1097
|
}
|
|
1098
|
-
async function processBatchInChunks(ctx,
|
|
1099
|
-
let newest = new Date(ctx.state.getState().lastPulled[
|
|
1100
|
-
return ctx.withTransaction("rw", [
|
|
1101
|
-
const txTable = tables[
|
|
1098
|
+
async function processBatchInChunks(ctx, tableName, batch, isEmptyTable, isFirstBatch) {
|
|
1099
|
+
let newest = new Date(ctx.state.getState().lastPulled[tableName] || 0);
|
|
1100
|
+
return ctx.withTransaction("rw", [tableName, DYNC_STATE_TABLE], async (tables) => {
|
|
1101
|
+
const txTable = tables[tableName];
|
|
1102
1102
|
let tableIsEmpty = isEmptyTable;
|
|
1103
1103
|
if (isFirstBatch) {
|
|
1104
1104
|
const count = await txTable.count();
|
|
@@ -1133,7 +1133,7 @@ async function processBatchInChunks(ctx, stateKey, batch, isEmptyTable, isFirstB
|
|
|
1133
1133
|
...syncState,
|
|
1134
1134
|
lastPulled: {
|
|
1135
1135
|
...syncState.lastPulled,
|
|
1136
|
-
[
|
|
1136
|
+
[tableName]: newest.toISOString()
|
|
1137
1137
|
}
|
|
1138
1138
|
}));
|
|
1139
1139
|
return { inserted, updated };
|
|
@@ -1198,23 +1198,23 @@ async function startFirstLoadBatch(ctx) {
|
|
|
1198
1198
|
break;
|
|
1199
1199
|
}
|
|
1200
1200
|
batchCount++;
|
|
1201
|
-
for (const [
|
|
1202
|
-
if (!ctx.batchSync.syncTables.includes(
|
|
1203
|
-
ctx.logger.warn(`[dync] firstLoad:batch:unknown-table
|
|
1201
|
+
for (const [tableName, batch] of Object.entries(result.data)) {
|
|
1202
|
+
if (!ctx.batchSync.syncTables.includes(tableName)) {
|
|
1203
|
+
ctx.logger.warn(`[dync] firstLoad:batch:unknown-table tableName=${tableName}`);
|
|
1204
1204
|
continue;
|
|
1205
1205
|
}
|
|
1206
1206
|
if (!batch?.length) continue;
|
|
1207
|
-
const isFirstBatch = progress[
|
|
1208
|
-
const isEmptyTable = isFirstBatch && await ctx.table(
|
|
1209
|
-
const { inserted, updated } = await processBatchInChunks(ctx,
|
|
1210
|
-
progress[
|
|
1211
|
-
progress[
|
|
1207
|
+
const isFirstBatch = progress[tableName].inserted === 0 && progress[tableName].updated === 0;
|
|
1208
|
+
const isEmptyTable = isFirstBatch && await ctx.table(tableName).count() === 0;
|
|
1209
|
+
const { inserted, updated } = await processBatchInChunks(ctx, tableName, batch, isEmptyTable, isFirstBatch);
|
|
1210
|
+
progress[tableName].inserted += inserted;
|
|
1211
|
+
progress[tableName].updated += updated;
|
|
1212
1212
|
if (ctx.onProgress) {
|
|
1213
1213
|
ctx.onProgress({
|
|
1214
|
-
table:
|
|
1215
|
-
inserted: progress[
|
|
1216
|
-
updated: progress[
|
|
1217
|
-
total: progress[
|
|
1214
|
+
table: tableName,
|
|
1215
|
+
inserted: progress[tableName].inserted,
|
|
1216
|
+
updated: progress[tableName].updated,
|
|
1217
|
+
total: progress[tableName].inserted + progress[tableName].updated
|
|
1218
1218
|
});
|
|
1219
1219
|
}
|
|
1220
1220
|
}
|
|
@@ -1226,8 +1226,8 @@ async function startFirstLoadBatch(ctx) {
|
|
|
1226
1226
|
break;
|
|
1227
1227
|
}
|
|
1228
1228
|
}
|
|
1229
|
-
for (const [
|
|
1230
|
-
ctx.logger.info(`[dync] firstLoad:batch:done
|
|
1229
|
+
for (const [tableName, p] of Object.entries(progress)) {
|
|
1230
|
+
ctx.logger.info(`[dync] firstLoad:batch:done tableName=${tableName} inserted=${p.inserted} updated=${p.updated}`);
|
|
1231
1231
|
}
|
|
1232
1232
|
} catch (err) {
|
|
1233
1233
|
error = err;
|
|
@@ -1597,8 +1597,8 @@ var DyncBase = class {
|
|
|
1597
1597
|
this.logger.warn(`[dync] No conflict found for localId: ${localId}`);
|
|
1598
1598
|
return;
|
|
1599
1599
|
}
|
|
1600
|
-
await this.withTransaction("rw", [conflict.
|
|
1601
|
-
const txTable = tables[conflict.
|
|
1600
|
+
await this.withTransaction("rw", [conflict.tableName, DYNC_STATE_TABLE], async (tables) => {
|
|
1601
|
+
const txTable = tables[conflict.tableName];
|
|
1602
1602
|
if (!keepLocal) {
|
|
1603
1603
|
const item = await txTable.get(localId);
|
|
1604
1604
|
if (item) {
|
|
@@ -1611,7 +1611,7 @@ var DyncBase = class {
|
|
|
1611
1611
|
}
|
|
1612
1612
|
await this.state.setState((syncState) => ({
|
|
1613
1613
|
...syncState,
|
|
1614
|
-
pendingChanges: syncState.pendingChanges.filter((p) => !(p.localId === localId && p.
|
|
1614
|
+
pendingChanges: syncState.pendingChanges.filter((p) => !(p.localId === localId && p.tableName === conflict.tableName))
|
|
1615
1615
|
}));
|
|
1616
1616
|
}
|
|
1617
1617
|
await this.state.setState((syncState) => {
|