@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.
@@ -1,4 +1,4 @@
1
- import { a as SyncApi, k as SyncState } from '../types-BszcepJK.cjs';
1
+ import { a as SyncApi, k as SyncState } from '../types-DhCTdAep.cjs';
2
2
  import '../dexie-3VOQSn1s.cjs';
3
3
  import 'dexie';
4
4
  import '../types-6-NyRQ0D.cjs';
@@ -1,4 +1,4 @@
1
- import { a as SyncApi, k as SyncState } from '../types-Dhx9MuUp.js';
1
+ import { a as SyncApi, k as SyncState } from '../types-BIJhsSOf.js';
2
2
  import '../dexie-D85rTx4g.js';
3
3
  import 'dexie';
4
4
  import '../types-6-NyRQ0D.js';
@@ -19,11 +19,12 @@ interface SyncedRecord {
19
19
  updated_at: string;
20
20
  [k: string]: any;
21
21
  }
22
- interface ApiFunctions {
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
- syncInterval?: number;
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, ApiFunctions>> | BatchSync;
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
- lastPulled: Record<string, string>;
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 ConflictResolutionStrategy 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 ApiFunctions as c, type BatchPushPayload as d, type BatchPushResult as e, type BatchFirstLoadResult 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 };
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 ApiFunctions {
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
- syncInterval?: number;
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, ApiFunctions>> | BatchSync;
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
- lastPulled: Record<string, string>;
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 ConflictResolutionStrategy 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 ApiFunctions as c, type BatchPushPayload as d, type BatchPushResult as e, type BatchFirstLoadResult 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 };
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.32",
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>\"; exit 1; } && pnpm build:all && pnpm test:all && pnpm test:browser:full && git add . && git commit -m \"$1\" && npm version patch && git push && npm login && npm publish' --"
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",
@@ -16,7 +16,7 @@ interface StateRow {
16
16
  const DEFAULT_STATE: PersistedSyncState = {
17
17
  firstLoadDone: false,
18
18
  pendingChanges: [],
19
- lastPulled: {},
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
- lastPulled: { ...state.lastPulled },
250
+ newestServerUpdatedAt: { ...state.newestServerUpdatedAt },
251
+ lastPulledAt: state.lastPulledAt ? { ...state.lastPulledAt } : undefined,
251
252
  conflicts: cloneConflicts(state.conflicts),
252
253
  };
253
254
  }
@@ -1,6 +1,6 @@
1
1
  import { createLocalId, sleep } from '../helpers';
2
2
  import type { Logger } from '../logger';
3
- import type { ApiFunctions, BatchFirstLoadResult, BatchSync, FirstLoadProgressCallback } from '../types';
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, ApiFunctions>;
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().lastPulled[tableName] || 0);
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
- lastPulled: {
178
- ...syncState.lastPulled,
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 { ApiFunctions, BatchSync, ConflictResolutionStrategy, FieldConflict, SyncedRecord } from '../types';
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, ApiFunctions>;
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 lastPulled = ctx.state.getState().lastPulled[tableName];
31
- const since = lastPulled ? new Date(lastPulled) : new Date(0);
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 lastPulled = ctx.state.getState().lastPulled[tableName];
121
- sinceMap[tableName] = lastPulled ? new Date(lastPulled) : new Date(0);
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
- lastPulled: {
205
- ...syncState.lastPulled,
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 { ApiFunctions, BatchPushPayload, BatchPushResult, BatchSync, PendingChange, SyncOptions } from '../types';
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, ApiFunctions>;
18
+ syncApis: Record<string, CrudSyncApi>;
19
19
  }
20
20
 
21
21
  export interface PushAllBatchContext extends PushContext {
@@ -10,7 +10,7 @@ export { createLocalId } from './helpers';
10
10
 
11
11
  export type {
12
12
  AfterRemoteAddCallback,
13
- ApiFunctions,
13
+ CrudSyncApi,
14
14
  BatchSync,
15
15
  BatchPushPayload,
16
16
  BatchPushResult,
@@ -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 ApiFunctions,
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, ApiFunctions> = {};
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, ApiFunctions>;
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
- syncInterval: DEFAULT_SYNC_INTERVAL_MILLIS,
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.syncInterval!, this.sleepAbortController.signal);
474
+ await sleep(this.syncOptions.syncIntervalMs!, this.sleepAbortController.signal);
474
475
  }
475
476
 
476
477
  this.syncStatus = 'disabled';
package/src/index.ts CHANGED
@@ -10,7 +10,7 @@ export { createLocalId } from './helpers';
10
10
 
11
11
  export type {
12
12
  AfterRemoteAddCallback,
13
- ApiFunctions,
13
+ CrudSyncApi,
14
14
  BatchSync,
15
15
  BatchPushPayload,
16
16
  BatchPushResult,
package/src/types.ts CHANGED
@@ -24,11 +24,13 @@ export interface SyncedRecord {
24
24
  [k: string]: any;
25
25
  }
26
26
 
27
- export interface ApiFunctions {
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
- syncInterval?: number;
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, ApiFunctions>> | BatchSync;
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
- lastPulled: Record<string, string>;
162
+ newestServerUpdatedAt: Record<string, string>;
163
+ lastPulledAt?: Record<string, number>;
161
164
  conflicts?: Record<string, Conflict>;
162
165
  }
163
166