@anfenn/dync 1.0.32 → 1.1.0
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 +1 -1
- package/dist/index.cjs +45 -14
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +45 -14
- package/dist/index.js.map +1 -1
- package/dist/react/index.d.cts +1 -1
- package/dist/react/index.d.ts +1 -1
- package/dist/{types-Dhx9MuUp.d.ts → types-BIJhsSOf.d.ts} +7 -5
- package/dist/{types-BszcepJK.d.cts → types-DhCTdAep.d.cts} +7 -5
- package/package.json +2 -2
- package/src/core/StateManager.ts +3 -2
- package/src/core/firstLoad.ts +5 -5
- package/src/core/pullOperations.ts +46 -8
- package/src/core/pushOperations.ts +2 -2
- package/src/index.native.ts +1 -1
- package/src/index.shared.ts +6 -5
- package/src/index.ts +1 -1
- package/src/types.ts +7 -4
package/dist/react/index.d.cts
CHANGED
package/dist/react/index.d.ts
CHANGED
|
@@ -19,11 +19,12 @@ interface SyncedRecord {
|
|
|
19
19
|
updated_at: string;
|
|
20
20
|
[k: string]: any;
|
|
21
21
|
}
|
|
22
|
-
interface
|
|
22
|
+
interface CrudSyncApi {
|
|
23
23
|
add: (item: any) => Promise<any | undefined>;
|
|
24
24
|
update: (id: any, changes: any, item: any) => Promise<boolean>;
|
|
25
25
|
remove: (id: any) => Promise<void>;
|
|
26
26
|
list: (lastUpdatedAt: Date) => Promise<any[]>;
|
|
27
|
+
listExtraIntervalMs?: number;
|
|
27
28
|
firstLoad?: (lastId: any) => Promise<any[]>;
|
|
28
29
|
}
|
|
29
30
|
/**
|
|
@@ -86,7 +87,7 @@ type ConflictResolutionStrategy = 'local-wins' | 'remote-wins' | 'try-shallow-me
|
|
|
86
87
|
type AfterRemoteAddCallback = (tableName: string, item: SyncedRecord) => void;
|
|
87
88
|
type MissingRemoteRecordDuringUpdateCallback = (strategy: MissingRemoteRecordStrategy, item: SyncedRecord) => void;
|
|
88
89
|
interface SyncOptions {
|
|
89
|
-
|
|
90
|
+
syncIntervalMs?: number;
|
|
90
91
|
logger?: Logger;
|
|
91
92
|
minLogLevel?: LogLevel;
|
|
92
93
|
onAfterRemoteAdd?: AfterRemoteAddCallback;
|
|
@@ -97,7 +98,7 @@ interface SyncOptions {
|
|
|
97
98
|
interface DyncOptions<TStoreMap extends Record<string, any> = Record<string, any>> {
|
|
98
99
|
databaseName: string;
|
|
99
100
|
storageAdapter: StorageAdapter;
|
|
100
|
-
sync?: Partial<Record<keyof TStoreMap,
|
|
101
|
+
sync?: Partial<Record<keyof TStoreMap, CrudSyncApi>> | BatchSync;
|
|
101
102
|
options?: SyncOptions;
|
|
102
103
|
}
|
|
103
104
|
interface FirstLoadProgress {
|
|
@@ -123,7 +124,8 @@ interface MutationEvent {
|
|
|
123
124
|
interface PersistedSyncState {
|
|
124
125
|
firstLoadDone: boolean;
|
|
125
126
|
pendingChanges: PendingChange[];
|
|
126
|
-
|
|
127
|
+
newestServerUpdatedAt: Record<string, string>;
|
|
128
|
+
lastPulledAt?: Record<string, number>;
|
|
127
129
|
conflicts?: Record<string, Conflict>;
|
|
128
130
|
}
|
|
129
131
|
type SyncStatus = 'disabled' | 'disabling' | 'idle' | 'syncing' | 'error';
|
|
@@ -160,4 +162,4 @@ type TableMap<TStoreMap extends Record<string, any>> = {
|
|
|
160
162
|
[K in keyof TStoreMap]: StorageTable<TStoreMap[K]>;
|
|
161
163
|
};
|
|
162
164
|
|
|
163
|
-
export { type AfterRemoteAddCallback as A, type BatchSync as B, type
|
|
165
|
+
export { type AfterRemoteAddCallback as A, type BatchSync as B, type CrudSyncApi as C, type DyncOptions as D, type FirstLoadProgress as F, type MissingRemoteRecordStrategy as M, type SyncStatus as S, type TableMap as T, type SyncApi as a, SyncAction as b, type BatchPushPayload as c, type BatchPushResult as d, type BatchFirstLoadResult as e, type ConflictResolutionStrategy as f, type FirstLoadProgressCallback as g, type MissingRemoteRecordDuringUpdateCallback as h, type MutationEvent as i, type SyncOptions as j, type SyncState as k, type SyncedRecord as l };
|
|
@@ -19,11 +19,12 @@ interface SyncedRecord {
|
|
|
19
19
|
updated_at: string;
|
|
20
20
|
[k: string]: any;
|
|
21
21
|
}
|
|
22
|
-
interface
|
|
22
|
+
interface CrudSyncApi {
|
|
23
23
|
add: (item: any) => Promise<any | undefined>;
|
|
24
24
|
update: (id: any, changes: any, item: any) => Promise<boolean>;
|
|
25
25
|
remove: (id: any) => Promise<void>;
|
|
26
26
|
list: (lastUpdatedAt: Date) => Promise<any[]>;
|
|
27
|
+
listExtraIntervalMs?: number;
|
|
27
28
|
firstLoad?: (lastId: any) => Promise<any[]>;
|
|
28
29
|
}
|
|
29
30
|
/**
|
|
@@ -86,7 +87,7 @@ type ConflictResolutionStrategy = 'local-wins' | 'remote-wins' | 'try-shallow-me
|
|
|
86
87
|
type AfterRemoteAddCallback = (tableName: string, item: SyncedRecord) => void;
|
|
87
88
|
type MissingRemoteRecordDuringUpdateCallback = (strategy: MissingRemoteRecordStrategy, item: SyncedRecord) => void;
|
|
88
89
|
interface SyncOptions {
|
|
89
|
-
|
|
90
|
+
syncIntervalMs?: number;
|
|
90
91
|
logger?: Logger;
|
|
91
92
|
minLogLevel?: LogLevel;
|
|
92
93
|
onAfterRemoteAdd?: AfterRemoteAddCallback;
|
|
@@ -97,7 +98,7 @@ interface SyncOptions {
|
|
|
97
98
|
interface DyncOptions<TStoreMap extends Record<string, any> = Record<string, any>> {
|
|
98
99
|
databaseName: string;
|
|
99
100
|
storageAdapter: StorageAdapter;
|
|
100
|
-
sync?: Partial<Record<keyof TStoreMap,
|
|
101
|
+
sync?: Partial<Record<keyof TStoreMap, CrudSyncApi>> | BatchSync;
|
|
101
102
|
options?: SyncOptions;
|
|
102
103
|
}
|
|
103
104
|
interface FirstLoadProgress {
|
|
@@ -123,7 +124,8 @@ interface MutationEvent {
|
|
|
123
124
|
interface PersistedSyncState {
|
|
124
125
|
firstLoadDone: boolean;
|
|
125
126
|
pendingChanges: PendingChange[];
|
|
126
|
-
|
|
127
|
+
newestServerUpdatedAt: Record<string, string>;
|
|
128
|
+
lastPulledAt?: Record<string, number>;
|
|
127
129
|
conflicts?: Record<string, Conflict>;
|
|
128
130
|
}
|
|
129
131
|
type SyncStatus = 'disabled' | 'disabling' | 'idle' | 'syncing' | 'error';
|
|
@@ -160,4 +162,4 @@ type TableMap<TStoreMap extends Record<string, any>> = {
|
|
|
160
162
|
[K in keyof TStoreMap]: StorageTable<TStoreMap[K]>;
|
|
161
163
|
};
|
|
162
164
|
|
|
163
|
-
export { type AfterRemoteAddCallback as A, type BatchSync as B, type
|
|
165
|
+
export { type AfterRemoteAddCallback as A, type BatchSync as B, type CrudSyncApi as C, type DyncOptions as D, type FirstLoadProgress as F, type MissingRemoteRecordStrategy as M, type SyncStatus as S, type TableMap as T, type SyncApi as a, SyncAction as b, type BatchPushPayload as c, type BatchPushResult as d, type BatchFirstLoadResult as e, type ConflictResolutionStrategy as f, type FirstLoadProgressCallback as g, type MissingRemoteRecordDuringUpdateCallback as h, type MutationEvent as i, type SyncOptions as j, type SyncState as k, type SyncedRecord as l };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@anfenn/dync",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Write once, run IndexedDB & SQLite with sync anywhere - React, React Native, Expo, Capacitor, Electron & Node.js",
|
|
6
6
|
"keywords": [
|
|
@@ -144,7 +144,7 @@
|
|
|
144
144
|
"test:browser:full": "pnpm --filter tests test:browser:full",
|
|
145
145
|
"reinstall": "find . -name node_modules -type d -prune -exec rm -rf {} + && pnpm install",
|
|
146
146
|
"push": "bash -c '[ -n \"$1\" ] && git add . && git commit -m \"$1\" && git push' --",
|
|
147
|
-
"release": "bash -c '[ -n \"$1\" ] || { echo \"Usage: pnpm release <commit-message
|
|
147
|
+
"release": "bash -c '[ -n \"$1\" ] || { echo \"Usage: pnpm release <commit-message> [--no-patch]\"; exit 1; } && pnpm build:all && pnpm test:all && pnpm test:browser:full && git add . && git commit -m \"$1\" && { [ \"$2\" = \"--no-patch\" ] || npm version patch; } && git push && npm login && npm publish' --"
|
|
148
148
|
},
|
|
149
149
|
"devDependencies": {
|
|
150
150
|
"@capacitor-community/sqlite": "7.0.2",
|
package/src/core/StateManager.ts
CHANGED
|
@@ -16,7 +16,7 @@ interface StateRow {
|
|
|
16
16
|
const DEFAULT_STATE: PersistedSyncState = {
|
|
17
17
|
firstLoadDone: false,
|
|
18
18
|
pendingChanges: [],
|
|
19
|
-
|
|
19
|
+
newestServerUpdatedAt: {},
|
|
20
20
|
};
|
|
21
21
|
|
|
22
22
|
interface StateContext {
|
|
@@ -247,7 +247,8 @@ function clonePersistedState(state: PersistedSyncState): PersistedSyncState {
|
|
|
247
247
|
before: cloneRecord(change.before),
|
|
248
248
|
after: cloneRecord(change.after),
|
|
249
249
|
})),
|
|
250
|
-
|
|
250
|
+
newestServerUpdatedAt: { ...state.newestServerUpdatedAt },
|
|
251
|
+
lastPulledAt: state.lastPulledAt ? { ...state.lastPulledAt } : undefined,
|
|
251
252
|
conflicts: cloneConflicts(state.conflicts),
|
|
252
253
|
};
|
|
253
254
|
}
|
package/src/core/firstLoad.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createLocalId, sleep } from '../helpers';
|
|
2
2
|
import type { Logger } from '../logger';
|
|
3
|
-
import type {
|
|
3
|
+
import type { CrudSyncApi, BatchFirstLoadResult, BatchSync, FirstLoadProgressCallback } from '../types';
|
|
4
4
|
import type { StorageTable } from '../storage/types';
|
|
5
5
|
import { DYNC_STATE_TABLE, type StateHelpers } from './StateManager';
|
|
6
6
|
import type { WithTransaction } from './types';
|
|
@@ -14,7 +14,7 @@ export interface FirstLoadBaseContext {
|
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
export interface FirstLoadContext extends FirstLoadBaseContext {
|
|
17
|
-
syncApis: Record<string,
|
|
17
|
+
syncApis: Record<string, CrudSyncApi>;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
export interface FirstLoadBatchContext extends FirstLoadBaseContext {
|
|
@@ -125,7 +125,7 @@ async function processBatchInChunks(
|
|
|
125
125
|
isEmptyTable: boolean,
|
|
126
126
|
isFirstBatch: boolean,
|
|
127
127
|
): Promise<BatchResult> {
|
|
128
|
-
let newest = new Date(ctx.state.getState().
|
|
128
|
+
let newest = new Date(ctx.state.getState().newestServerUpdatedAt[tableName] || 0);
|
|
129
129
|
|
|
130
130
|
return ctx.withTransaction('rw', [tableName, DYNC_STATE_TABLE], async (tables) => {
|
|
131
131
|
const txTable = tables[tableName]!;
|
|
@@ -174,8 +174,8 @@ async function processBatchInChunks(
|
|
|
174
174
|
|
|
175
175
|
await ctx.state.setState((syncState) => ({
|
|
176
176
|
...syncState,
|
|
177
|
-
|
|
178
|
-
...syncState.
|
|
177
|
+
newestServerUpdatedAt: {
|
|
178
|
+
...syncState.newestServerUpdatedAt,
|
|
179
179
|
[tableName]: newest.toISOString(),
|
|
180
180
|
},
|
|
181
181
|
}));
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createLocalId } from '../helpers';
|
|
2
2
|
import type { Logger } from '../logger';
|
|
3
|
-
import type {
|
|
3
|
+
import type { CrudSyncApi, BatchSync, ConflictResolutionStrategy, FieldConflict, SyncedRecord } from '../types';
|
|
4
4
|
import { SyncAction } from '../types';
|
|
5
5
|
import type { StorageTable } from '../storage/types';
|
|
6
6
|
import { DYNC_STATE_TABLE, type StateHelpers } from './StateManager';
|
|
@@ -15,7 +15,8 @@ export interface PullContext {
|
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
export interface PullAllContext extends PullContext {
|
|
18
|
-
syncApis: Record<string,
|
|
18
|
+
syncApis: Record<string, CrudSyncApi>;
|
|
19
|
+
syncIntervalMs: number;
|
|
19
20
|
}
|
|
20
21
|
|
|
21
22
|
export interface PullAllBatchContext extends PullContext {
|
|
@@ -27,14 +28,33 @@ export async function pullAll(ctx: PullAllContext): Promise<{ error?: Error; cha
|
|
|
27
28
|
const changedTables: string[] = [];
|
|
28
29
|
for (const [tableName, api] of Object.entries(ctx.syncApis)) {
|
|
29
30
|
try {
|
|
30
|
-
const
|
|
31
|
-
|
|
31
|
+
const now = Date.now();
|
|
32
|
+
|
|
33
|
+
// Skip pull if within listExtraIntervalMs
|
|
34
|
+
if (beforeListExtraInterval(api, tableName, ctx, now)) {
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const newestServerUpdatedAt = ctx.state.getState().newestServerUpdatedAt[tableName];
|
|
39
|
+
const since = newestServerUpdatedAt ? new Date(newestServerUpdatedAt) : new Date(0);
|
|
32
40
|
|
|
33
41
|
ctx.logger.debug(`[dync] pull:start tableName=${tableName} since=${since.toISOString()}`);
|
|
34
42
|
|
|
35
43
|
const serverData = (await api.list(since)) as SyncedRecord[];
|
|
36
44
|
const changed = await processPullData(tableName, serverData, since, ctx);
|
|
37
45
|
if (changed) changedTables.push(tableName);
|
|
46
|
+
|
|
47
|
+
// Track when api.list() was called for this table (for listExtraIntervalMs feature)
|
|
48
|
+
// but only if listExtraIntervalMs is set, to reduce storage calls
|
|
49
|
+
if (hasListExtraInterval(api)) {
|
|
50
|
+
await ctx.state.setState((syncState) => ({
|
|
51
|
+
...syncState,
|
|
52
|
+
lastPulledAt: {
|
|
53
|
+
...syncState.lastPulledAt,
|
|
54
|
+
[tableName]: now,
|
|
55
|
+
},
|
|
56
|
+
}));
|
|
57
|
+
}
|
|
38
58
|
} catch (err) {
|
|
39
59
|
firstSyncError = firstSyncError ?? (err as Error);
|
|
40
60
|
ctx.logger.error(`[dync] pull:error tableName=${tableName}`, err);
|
|
@@ -43,6 +63,24 @@ export async function pullAll(ctx: PullAllContext): Promise<{ error?: Error; cha
|
|
|
43
63
|
return { error: firstSyncError, changedTables };
|
|
44
64
|
}
|
|
45
65
|
|
|
66
|
+
function hasListExtraInterval(api: CrudSyncApi): boolean {
|
|
67
|
+
return Number.isFinite(api.listExtraIntervalMs) && api.listExtraIntervalMs! > 0;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function beforeListExtraInterval(api: CrudSyncApi, tableName: string, ctx: PullAllContext, now: number): boolean {
|
|
71
|
+
if (!hasListExtraInterval(api)) {
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
const lastPulledAt = ctx.state.getState().lastPulledAt?.[tableName] ?? 0;
|
|
75
|
+
if (now - lastPulledAt < api.listExtraIntervalMs!) {
|
|
76
|
+
ctx.logger.debug(
|
|
77
|
+
`[dync] pull:skip-interval tableName=${tableName} lastPulledAt=${new Date(lastPulledAt).toISOString()} nextAllowed=${new Date(lastPulledAt + api.listExtraIntervalMs!).toISOString()}`,
|
|
78
|
+
);
|
|
79
|
+
return true;
|
|
80
|
+
}
|
|
81
|
+
return false;
|
|
82
|
+
}
|
|
83
|
+
|
|
46
84
|
async function handleRemoteItemUpdate(table: StorageTable<any>, tableName: string, localItem: any, remote: any, ctx: PullContext): Promise<void> {
|
|
47
85
|
const pendingChange = ctx.state.getState().pendingChanges.find((p) => p.tableName === tableName && p.localId === localItem._localId);
|
|
48
86
|
const conflictStrategy = ctx.conflictResolutionStrategy;
|
|
@@ -117,8 +155,8 @@ export async function pullAllBatch(ctx: PullAllBatchContext): Promise<{ error?:
|
|
|
117
155
|
// Build since map for all synced tables
|
|
118
156
|
const sinceMap: Record<string, Date> = {};
|
|
119
157
|
for (const tableName of ctx.batchSync.syncTables) {
|
|
120
|
-
const
|
|
121
|
-
sinceMap[tableName] =
|
|
158
|
+
const newestServerUpdatedAt = ctx.state.getState().newestServerUpdatedAt[tableName];
|
|
159
|
+
sinceMap[tableName] = newestServerUpdatedAt ? new Date(newestServerUpdatedAt) : new Date(0);
|
|
122
160
|
}
|
|
123
161
|
|
|
124
162
|
ctx.logger.debug(`[dync] pull:batch:start tables=${[...ctx.batchSync.syncTables].join(',')}`, sinceMap);
|
|
@@ -201,8 +239,8 @@ async function processPullData(tableName: string, serverData: SyncedRecord[], si
|
|
|
201
239
|
|
|
202
240
|
await ctx.state.setState((syncState) => ({
|
|
203
241
|
...syncState,
|
|
204
|
-
|
|
205
|
-
...syncState.
|
|
242
|
+
newestServerUpdatedAt: {
|
|
243
|
+
...syncState.newestServerUpdatedAt,
|
|
206
244
|
[tableName]: newest.toISOString(),
|
|
207
245
|
},
|
|
208
246
|
}));
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createLocalId, orderFor } from '../helpers';
|
|
2
2
|
import type { Logger } from '../logger';
|
|
3
|
-
import type {
|
|
3
|
+
import type { CrudSyncApi, BatchPushPayload, BatchPushResult, BatchSync, PendingChange, SyncOptions } from '../types';
|
|
4
4
|
import { SyncAction } from '../types';
|
|
5
5
|
import type { StorageTable } from '../storage/types';
|
|
6
6
|
import { DYNC_STATE_TABLE, type StateHelpers } from './StateManager';
|
|
@@ -15,7 +15,7 @@ export interface PushContext {
|
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
export interface PushAllContext extends PushContext {
|
|
18
|
-
syncApis: Record<string,
|
|
18
|
+
syncApis: Record<string, CrudSyncApi>;
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
export interface PushAllBatchContext extends PushContext {
|
package/src/index.native.ts
CHANGED
package/src/index.shared.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { newLogger, type Logger, type LogLevel } from './logger';
|
|
2
2
|
import { sleep } from './helpers';
|
|
3
3
|
import {
|
|
4
|
-
type
|
|
4
|
+
type CrudSyncApi,
|
|
5
5
|
type BatchSync,
|
|
6
6
|
type DyncOptions,
|
|
7
7
|
type SyncOptions,
|
|
@@ -50,7 +50,7 @@ class DyncBase<_TStoreMap extends Record<string, any> = Record<string, any>> {
|
|
|
50
50
|
private sleepAbortController?: AbortController;
|
|
51
51
|
private closing = false;
|
|
52
52
|
// Per-table sync mode
|
|
53
|
-
private syncApis: Record<string,
|
|
53
|
+
private syncApis: Record<string, CrudSyncApi> = {};
|
|
54
54
|
// Batch sync mode
|
|
55
55
|
private batchSync?: BatchSync;
|
|
56
56
|
private syncedTables: Set<string> = new Set();
|
|
@@ -93,7 +93,7 @@ class DyncBase<_TStoreMap extends Record<string, any> = Record<string, any>> {
|
|
|
93
93
|
this.batchSync = syncConfig as BatchSync;
|
|
94
94
|
this.syncedTables = new Set(this.batchSync.syncTables);
|
|
95
95
|
} else {
|
|
96
|
-
this.syncApis = syncConfig as Record<string,
|
|
96
|
+
this.syncApis = syncConfig as Record<string, CrudSyncApi>;
|
|
97
97
|
this.syncedTables = new Set(Object.keys(this.syncApis));
|
|
98
98
|
}
|
|
99
99
|
}
|
|
@@ -101,7 +101,7 @@ class DyncBase<_TStoreMap extends Record<string, any> = Record<string, any>> {
|
|
|
101
101
|
this.adapter = storageAdapter;
|
|
102
102
|
this.name = databaseName;
|
|
103
103
|
this.syncOptions = {
|
|
104
|
-
|
|
104
|
+
syncIntervalMs: DEFAULT_SYNC_INTERVAL_MILLIS,
|
|
105
105
|
logger: DEFAULT_LOGGER,
|
|
106
106
|
minLogLevel: DEFAULT_MIN_LOG_LEVEL,
|
|
107
107
|
missingRemoteRecordDuringUpdateStrategy: DEFAULT_MISSING_REMOTE_RECORD_STRATEGY,
|
|
@@ -430,6 +430,7 @@ class DyncBase<_TStoreMap extends Record<string, any> = Record<string, any>> {
|
|
|
430
430
|
return runPullAll({
|
|
431
431
|
...baseContext,
|
|
432
432
|
syncApis: this.syncApis,
|
|
433
|
+
syncIntervalMs: this.syncOptions.syncIntervalMs!,
|
|
433
434
|
});
|
|
434
435
|
}
|
|
435
436
|
|
|
@@ -470,7 +471,7 @@ class DyncBase<_TStoreMap extends Record<string, any> = Record<string, any>> {
|
|
|
470
471
|
while (this.syncTimerStarted) {
|
|
471
472
|
this.sleepAbortController = new AbortController();
|
|
472
473
|
await this.syncOnce();
|
|
473
|
-
await sleep(this.syncOptions.
|
|
474
|
+
await sleep(this.syncOptions.syncIntervalMs!, this.sleepAbortController.signal);
|
|
474
475
|
}
|
|
475
476
|
|
|
476
477
|
this.syncStatus = 'disabled';
|
package/src/index.ts
CHANGED
package/src/types.ts
CHANGED
|
@@ -24,11 +24,13 @@ export interface SyncedRecord {
|
|
|
24
24
|
[k: string]: any;
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
export interface
|
|
27
|
+
export interface CrudSyncApi {
|
|
28
28
|
add: (item: any) => Promise<any | undefined>;
|
|
29
29
|
update: (id: any, changes: any, item: any) => Promise<boolean>;
|
|
30
30
|
remove: (id: any) => Promise<void>;
|
|
31
31
|
list: (lastUpdatedAt: Date) => Promise<any[]>;
|
|
32
|
+
// Optional: Extend `SyncOptions.syncIntervalMs` for this table's pull sync
|
|
33
|
+
listExtraIntervalMs?: number;
|
|
32
34
|
firstLoad?: (lastId: any) => Promise<any[]>;
|
|
33
35
|
}
|
|
34
36
|
|
|
@@ -113,7 +115,7 @@ export type AfterRemoteAddCallback = (tableName: string, item: SyncedRecord) =>
|
|
|
113
115
|
export type MissingRemoteRecordDuringUpdateCallback = (strategy: MissingRemoteRecordStrategy, item: SyncedRecord) => void;
|
|
114
116
|
|
|
115
117
|
export interface SyncOptions {
|
|
116
|
-
|
|
118
|
+
syncIntervalMs?: number;
|
|
117
119
|
logger?: Logger;
|
|
118
120
|
minLogLevel?: LogLevel;
|
|
119
121
|
onAfterRemoteAdd?: AfterRemoteAddCallback;
|
|
@@ -125,7 +127,7 @@ export interface SyncOptions {
|
|
|
125
127
|
export interface DyncOptions<TStoreMap extends Record<string, any> = Record<string, any>> {
|
|
126
128
|
databaseName: string;
|
|
127
129
|
storageAdapter: StorageAdapter;
|
|
128
|
-
sync?: Partial<Record<keyof TStoreMap,
|
|
130
|
+
sync?: Partial<Record<keyof TStoreMap, CrudSyncApi>> | BatchSync;
|
|
129
131
|
options?: SyncOptions;
|
|
130
132
|
}
|
|
131
133
|
|
|
@@ -157,7 +159,8 @@ export interface MutationEvent {
|
|
|
157
159
|
export interface PersistedSyncState {
|
|
158
160
|
firstLoadDone: boolean;
|
|
159
161
|
pendingChanges: PendingChange[];
|
|
160
|
-
|
|
162
|
+
newestServerUpdatedAt: Record<string, string>;
|
|
163
|
+
lastPulledAt?: Record<string, number>;
|
|
161
164
|
conflicts?: Record<string, Conflict>;
|
|
162
165
|
}
|
|
163
166
|
|