supastash 0.1.54 → 0.1.55

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 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/hooks/syncEngine/index.ts"],"names":[],"mappings":"AA4BA;;;;;GAKG;AACH,wBAAsB,OAAO,CAAC,KAAK,GAAE,OAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAmCnE;AAuDD;;;;;GAKG;AACH,wBAAgB,aAAa;;;EA8D5B;AAMD;;;;GAIG;AACH,wBAAsB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAgC5D;AAED;;GAEG;AACH,wBAAsB,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC,CAEnD"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/hooks/syncEngine/index.ts"],"names":[],"mappings":"AA6BA;;;;;GAKG;AACH,wBAAsB,OAAO,CAAC,KAAK,GAAE,OAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAqCnE;AAuDD;;;;;GAKG;AACH,wBAAgB,aAAa;;;EA8D5B;AAMD;;;;GAIG;AACH,wBAAsB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAgC5D;AAED;;GAEG;AACH,wBAAsB,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC,CAEnD"}
@@ -2,6 +2,7 @@ import { useEffect, useRef } from "react";
2
2
  import { AppState } from "react-native";
3
3
  import { getSupastashConfig } from "../../core/config";
4
4
  import { syncCalls } from "../../store/syncCalls";
5
+ import { isSyncGateClosed } from "../../store/syncStatus";
5
6
  import { tableFilters } from "../../store/tableFilters";
6
7
  import { isOnline } from "../../utils/connection";
7
8
  import log from "../../utils/logs";
@@ -28,6 +29,9 @@ const MIN_FOREGROUND_GAP = 5000; // ms
28
29
  * - "force" ignores pull cadence timing.
29
30
  */
30
31
  export async function syncAll(force = false) {
32
+ const isGateClosed = isSyncGateClosed();
33
+ if (isGateClosed)
34
+ return;
31
35
  if (isSyncing)
32
36
  return;
33
37
  if (!(await isOnline()))
package/dist/index.d.ts CHANGED
@@ -6,6 +6,7 @@ export { useSupastashFilters } from "./hooks/supastashFilters";
6
6
  export { useSupastash } from "./hooks/supastashLogic";
7
7
  export { syncAllTables, syncTable } from "./hooks/syncEngine";
8
8
  export { useSupastashSyncStatus } from "./hooks/syncStatus";
9
+ export { closeSyncGate, isSyncGateClosed, openSyncGate, } from "./store/syncStatus";
9
10
  export { supastashEventBus } from "./utils/events/eventBus";
10
11
  export { supastash } from "./utils/query/builder";
11
12
  export { refreshScreen } from "./utils/refreshScreenCalls";
@@ -13,7 +14,7 @@ export { dropAllTables, dropTable, wipeAllTables, wipeOldDataForAllTables, wipeO
13
14
  export { getSupastashRuntimeMode, reinitializeSupastash, } from "./utils/supastashMode";
14
15
  export { getAllTables } from "./utils/sync/getAllTables";
15
16
  export { updateFilters } from "./utils/sync/pullFromRemote/updateFilter";
16
- export { upsertData } from "./utils/sync/pullFromRemote/updateLocalDb";
17
+ export { updateLocalDb, upsertData, } from "./utils/sync/pullFromRemote/updateLocalDb";
17
18
  export { refreshAllTables, refreshTable, refreshTableWithPayload, } from "./utils/sync/refreshTables";
18
19
  export { clearSyncCalls, getAllSyncTables, getSyncCall, registerSyncCall, unregisterSyncCall, } from "./utils/sync/registration/syncCalls";
19
20
  export { clearAllLocalDeleteLog, clearAllLocalSyncLog, clearLocalDeleteLog, clearLocalSyncLog, clearSyncLog, getLocalDeleteLog, getSyncLog, resetSyncLog, setLocalDeleteLog, setLocalSyncLog, setSyncLog, } from "./utils/sync/status/syncStatus";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AACvE,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAEzD,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AACtD,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC9D,OAAO,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;AAC5D,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAC3D,OAAO,EACL,aAAa,EACb,SAAS,EACT,aAAa,EACb,uBAAuB,EACvB,oBAAoB,EACpB,SAAS,GACV,MAAM,2BAA2B,CAAC;AACnC,OAAO,EACL,uBAAuB,EACvB,qBAAqB,GACtB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AACzD,OAAO,EAAE,aAAa,EAAE,MAAM,0CAA0C,CAAC;AACzE,OAAO,EAAE,UAAU,EAAE,MAAM,2CAA2C,CAAC;AACvE,OAAO,EACL,gBAAgB,EAChB,YAAY,EACZ,uBAAuB,GACxB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EACL,cAAc,EACd,gBAAgB,EAChB,WAAW,EACX,gBAAgB,EAChB,kBAAkB,GACnB,MAAM,qCAAqC,CAAC;AAC7C,OAAO,EACL,sBAAsB,EACtB,oBAAoB,EACpB,mBAAmB,EACnB,iBAAiB,EACjB,YAAY,EACZ,iBAAiB,EACjB,UAAU,EACV,YAAY,EACZ,iBAAiB,EACjB,eAAe,EACf,UAAU,GACX,MAAM,gCAAgC,CAAC;AAExC,YAAY,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AACvD,YAAY,EACV,eAAe,EACf,mBAAmB,EACnB,eAAe,GAChB,MAAM,4BAA4B,CAAC;AACpC,YAAY,EACV,eAAe,EACf,mBAAmB,EACnB,0BAA0B,EAC1B,uBAAuB,GACxB,MAAM,+BAA+B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AACvE,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAEzD,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AACtD,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC9D,OAAO,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;AAC5D,OAAO,EACL,aAAa,EACb,gBAAgB,EAChB,YAAY,GACb,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAC3D,OAAO,EACL,aAAa,EACb,SAAS,EACT,aAAa,EACb,uBAAuB,EACvB,oBAAoB,EACpB,SAAS,GACV,MAAM,2BAA2B,CAAC;AACnC,OAAO,EACL,uBAAuB,EACvB,qBAAqB,GACtB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AACzD,OAAO,EAAE,aAAa,EAAE,MAAM,0CAA0C,CAAC;AACzE,OAAO,EACL,aAAa,EACb,UAAU,GACX,MAAM,2CAA2C,CAAC;AACnD,OAAO,EACL,gBAAgB,EAChB,YAAY,EACZ,uBAAuB,GACxB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EACL,cAAc,EACd,gBAAgB,EAChB,WAAW,EACX,gBAAgB,EAChB,kBAAkB,GACnB,MAAM,qCAAqC,CAAC;AAC7C,OAAO,EACL,sBAAsB,EACtB,oBAAoB,EACpB,mBAAmB,EACnB,iBAAiB,EACjB,YAAY,EACZ,iBAAiB,EACjB,UAAU,EACV,YAAY,EACZ,iBAAiB,EACjB,eAAe,EACf,UAAU,GACX,MAAM,gCAAgC,CAAC;AAExC,YAAY,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AACvD,YAAY,EACV,eAAe,EACf,mBAAmB,EACnB,eAAe,GAChB,MAAM,4BAA4B,CAAC;AACpC,YAAY,EACV,eAAe,EACf,mBAAmB,EACnB,0BAA0B,EAC1B,uBAAuB,GACxB,MAAM,+BAA+B,CAAC"}
package/dist/index.js CHANGED
@@ -7,6 +7,7 @@ export { useSupastashFilters } from "./hooks/supastashFilters";
7
7
  export { useSupastash } from "./hooks/supastashLogic";
8
8
  export { syncAllTables, syncTable } from "./hooks/syncEngine";
9
9
  export { useSupastashSyncStatus } from "./hooks/syncStatus";
10
+ export { closeSyncGate, isSyncGateClosed, openSyncGate, } from "./store/syncStatus";
10
11
  export { supastashEventBus } from "./utils/events/eventBus";
11
12
  export { supastash } from "./utils/query/builder";
12
13
  export { refreshScreen } from "./utils/refreshScreenCalls";
@@ -14,7 +15,7 @@ export { dropAllTables, dropTable, wipeAllTables, wipeOldDataForAllTables, wipeO
14
15
  export { getSupastashRuntimeMode, reinitializeSupastash, } from "./utils/supastashMode";
15
16
  export { getAllTables } from "./utils/sync/getAllTables";
16
17
  export { updateFilters } from "./utils/sync/pullFromRemote/updateFilter";
17
- export { upsertData } from "./utils/sync/pullFromRemote/updateLocalDb";
18
+ export { updateLocalDb, upsertData, } from "./utils/sync/pullFromRemote/updateLocalDb";
18
19
  export { refreshAllTables, refreshTable, refreshTableWithPayload, } from "./utils/sync/refreshTables";
19
20
  export { clearSyncCalls, getAllSyncTables, getSyncCall, registerSyncCall, unregisterSyncCall, } from "./utils/sync/registration/syncCalls";
20
21
  export { clearAllLocalDeleteLog, clearAllLocalSyncLog, clearLocalDeleteLog, clearLocalSyncLog, clearSyncLog, getLocalDeleteLog, getSyncLog, resetSyncLog, setLocalDeleteLog, setLocalSyncLog, setSyncLog, } from "./utils/sync/status/syncStatus";
@@ -1,4 +1,4 @@
1
- import { SyncInfo, SyncLogEntry } from "../types/syncEngine.types";
1
+ import { ReceivedDataCompleted, ReceivedDataCompletedMap, SyncInfo, SyncLogEntry } from "../types/syncEngine.types";
2
2
  /**
3
3
  * A map tracking sync status for each row in each table.
4
4
  *
@@ -24,4 +24,21 @@ import { SyncInfo, SyncLogEntry } from "../types/syncEngine.types";
24
24
  export declare const syncStatusMap: Map<string, Map<string, "error" | "pending" | "success">>;
25
25
  export declare const syncInfo: SyncInfo;
26
26
  export declare const DEFAULT_SYNC_LOG_ENTRY: SyncLogEntry;
27
+ export declare const RECEIVED_DATA_THRESHOLD = 1000;
28
+ export declare const RECEIVED_DATA_COMPLETED_MAP: ReceivedDataCompletedMap;
29
+ export declare const DEFAULT_RECEIVED_DATA_COMPLETED: ReceivedDataCompleted;
30
+ /**
31
+ * Closes the global sync gate.
32
+ * Prevents all sync operations from running.
33
+ */
34
+ export declare function closeSyncGate(): void;
35
+ /**
36
+ * Opens the global sync gate.
37
+ * Allows sync operations to run.
38
+ */
39
+ export declare function openSyncGate(): void;
40
+ /**
41
+ * Returns whether the global sync gate is currently closed.
42
+ */
43
+ export declare function isSyncGateClosed(): boolean;
27
44
  //# sourceMappingURL=syncStatus.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"syncStatus.d.ts","sourceRoot":"","sources":["../../src/store/syncStatus.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAEnE;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,eAAO,MAAM,aAAa,2DAGvB,CAAC;AAEJ,eAAO,MAAM,QAAQ,EAAE,QAyBtB,CAAC;AAEF,eAAO,MAAM,sBAAsB,EAAE,YAapC,CAAC"}
1
+ {"version":3,"file":"syncStatus.d.ts","sourceRoot":"","sources":["../../src/store/syncStatus.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,qBAAqB,EACrB,wBAAwB,EACxB,QAAQ,EACR,YAAY,EACb,MAAM,2BAA2B,CAAC;AAEnC;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,eAAO,MAAM,aAAa,2DAGvB,CAAC;AAEJ,eAAO,MAAM,QAAQ,EAAE,QAyBtB,CAAC;AAEF,eAAO,MAAM,sBAAsB,EAAE,YAapC,CAAC;AAEF,eAAO,MAAM,uBAAuB,OAAO,CAAC;AAC5C,eAAO,MAAM,2BAA2B,EAAE,wBAA6B,CAAC;AACxE,eAAO,MAAM,+BAA+B,EAAE,qBAI7C,CAAC;AASF;;;GAGG;AACH,wBAAgB,aAAa,IAAI,IAAI,CAEpC;AAED;;;GAGG;AACH,wBAAgB,YAAY,IAAI,IAAI,CAEnC;AAED;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,OAAO,CAE1C"}
@@ -61,3 +61,36 @@ export const DEFAULT_SYNC_LOG_ENTRY = {
61
61
  startTime: 0,
62
62
  endTime: 0,
63
63
  };
64
+ export const RECEIVED_DATA_THRESHOLD = 1000;
65
+ export const RECEIVED_DATA_COMPLETED_MAP = {};
66
+ export const DEFAULT_RECEIVED_DATA_COMPLETED = {
67
+ completed: false,
68
+ lastTimestamp: "",
69
+ lastId: "",
70
+ };
71
+ /**
72
+ * Global Sync Gate
73
+ * ----------------
74
+ * Acts as a hard stop for all sync operations across the app.
75
+ */
76
+ let syncGateClosed = false;
77
+ /**
78
+ * Closes the global sync gate.
79
+ * Prevents all sync operations from running.
80
+ */
81
+ export function closeSyncGate() {
82
+ syncGateClosed = true;
83
+ }
84
+ /**
85
+ * Opens the global sync gate.
86
+ * Allows sync operations to run.
87
+ */
88
+ export function openSyncGate() {
89
+ syncGateClosed = false;
90
+ }
91
+ /**
92
+ * Returns whether the global sync gate is currently closed.
93
+ */
94
+ export function isSyncGateClosed() {
95
+ return syncGateClosed;
96
+ }
@@ -1,5 +1,6 @@
1
1
  import { PayloadData } from "../../../types/query.types";
2
2
  import { RealtimeFilter } from "../../../types/realtimeData.types";
3
+ import { ReceivedDataCompleted } from "../../../types/syncEngine.types";
3
4
  export declare function pageThrough(base: {
4
5
  tsCol: "created_at" | "updated_at" | "deleted_at";
5
6
  since: string;
@@ -7,7 +8,18 @@ export declare function pageThrough(base: {
7
8
  select?: string;
8
9
  filters?: RealtimeFilter[];
9
10
  includeDeleted?: boolean;
11
+ batchId: string;
10
12
  }): Promise<any[]>;
11
13
  export declare function getMaxDate(rows: PayloadData[], col: "created_at" | "updated_at" | "deleted_at"): string | null;
12
14
  export declare function logNoUpdates(table: string): void;
15
+ export declare function getReceivedDataCompleted({ batchId, col, }: {
16
+ batchId: string;
17
+ col: "created_at" | "updated_at" | "deleted_at";
18
+ }): ReceivedDataCompleted;
19
+ export declare function setReceivedDataCompleted({ batchId, col, completed, }: {
20
+ batchId: string;
21
+ col: "created_at" | "updated_at" | "deleted_at";
22
+ completed: ReceivedDataCompleted;
23
+ }): void;
24
+ export declare function deleteReceivedDataCompleted(batchId: string): void;
13
25
  //# sourceMappingURL=helpers.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../../../src/utils/sync/pullFromRemote/helpers.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AACzD,OAAO,EAAE,cAAc,EAAE,MAAM,mCAAmC,CAAC;AAqBnE,wBAAsB,WAAW,CAAC,IAAI,EAAE;IACtC,KAAK,EAAE,YAAY,GAAG,YAAY,GAAG,YAAY,CAAC;IAClD,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,cAAc,EAAE,CAAC;IAC3B,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B,kBA2CA;AAED,wBAAgB,UAAU,CACxB,IAAI,EAAE,WAAW,EAAE,EACnB,GAAG,EAAE,YAAY,GAAG,YAAY,GAAG,YAAY,GAC9C,MAAM,GAAG,IAAI,CAUf;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,QAczC"}
1
+ {"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../../../src/utils/sync/pullFromRemote/helpers.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AACzD,OAAO,EAAE,cAAc,EAAE,MAAM,mCAAmC,CAAC;AACnE,OAAO,EAAE,qBAAqB,EAAE,MAAM,iCAAiC,CAAC;AAsBxE,wBAAsB,WAAW,CAAC,IAAI,EAAE;IACtC,KAAK,EAAE,YAAY,GAAG,YAAY,GAAG,YAAY,CAAC;IAClD,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,cAAc,EAAE,CAAC;IAC3B,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,OAAO,EAAE,MAAM,CAAC;CACjB,kBA4EA;AAED,wBAAgB,UAAU,CACxB,IAAI,EAAE,WAAW,EAAE,EACnB,GAAG,EAAE,YAAY,GAAG,YAAY,GAAG,YAAY,GAC9C,MAAM,GAAG,IAAI,CAUf;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,QAczC;AAED,wBAAgB,wBAAwB,CAAC,EACvC,OAAO,EACP,GAAG,GACJ,EAAE;IACD,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,YAAY,GAAG,YAAY,GAAG,YAAY,CAAC;CACjD,GAAG,qBAAqB,CAMxB;AAED,wBAAgB,wBAAwB,CAAC,EACvC,OAAO,EACP,GAAG,EACH,SAAS,GACV,EAAE;IACD,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,YAAY,GAAG,YAAY,GAAG,YAAY,CAAC;IAChD,SAAS,EAAE,qBAAqB,CAAC;CAClC,QAKA;AAED,wBAAgB,2BAA2B,CAAC,OAAO,EAAE,MAAM,QAE1D"}
@@ -1,9 +1,11 @@
1
1
  import { getSupastashConfig } from "../../../core/config";
2
+ import { RECEIVED_DATA_COMPLETED_MAP, RECEIVED_DATA_THRESHOLD, } from "../../../store/syncStatus";
2
3
  import log from "../../logs";
3
4
  import { supabaseClientErr } from "../../supabaseClientErr";
4
5
  import isValidFilter from "./validateFilters";
5
6
  const RANDOM_OLD_DATE = "2000-01-01T00:00:00Z";
6
- const PAGE_SIZE = 1000;
7
+ const PAGE_SIZE = RECEIVED_DATA_THRESHOLD;
8
+ const MAX_PAGE_SIZE = 2000;
7
9
  const timesPulled = new Map();
8
10
  const lastPulled = new Map();
9
11
  const DEFAULT_MAX_PULL_ATTEMPTS = 150;
@@ -21,8 +23,15 @@ export async function pageThrough(base) {
21
23
  if (!supabase)
22
24
  throw new Error(`No supabase client found: ${supabaseClientErr}`);
23
25
  const results = [];
24
- let cursorTs = base.since || RANDOM_OLD_DATE;
25
- let cursorId = "";
26
+ const lastWork = getReceivedDataCompleted({
27
+ batchId: base.batchId,
28
+ col: base.tsCol,
29
+ });
30
+ if (lastWork.completed)
31
+ return results;
32
+ let cursorTs = lastWork.lastTimestamp || base.since || RANDOM_OLD_DATE;
33
+ let cursorId = lastWork.lastId || "";
34
+ let lastDataSize = 0;
26
35
  const { table, filters = [], select = "*" } = base;
27
36
  while (true) {
28
37
  let q = supabase
@@ -48,11 +57,35 @@ export async function pageThrough(base) {
48
57
  if (!data || data.length === 0)
49
58
  break;
50
59
  results.push(...data);
51
- if (data.length < PAGE_SIZE)
60
+ if (data.length < PAGE_SIZE) {
61
+ setReceivedDataCompleted({
62
+ batchId: base.batchId,
63
+ col: base.tsCol,
64
+ completed: {
65
+ completed: true,
66
+ lastTimestamp: cursorTs,
67
+ lastId: cursorId,
68
+ },
69
+ });
52
70
  break;
71
+ }
53
72
  const last = data[data.length - 1];
54
73
  cursorTs = last[base.tsCol];
55
74
  cursorId = last.id;
75
+ lastDataSize += data.length;
76
+ setReceivedDataCompleted({
77
+ batchId: base.batchId,
78
+ col: base.tsCol,
79
+ completed: {
80
+ completed: false,
81
+ lastTimestamp: cursorTs,
82
+ lastId: cursorId,
83
+ },
84
+ });
85
+ if (lastDataSize >= MAX_PAGE_SIZE) {
86
+ break;
87
+ }
88
+ await new Promise((res) => setTimeout(res, 0));
56
89
  }
57
90
  return results;
58
91
  }
@@ -80,3 +113,19 @@ export function logNoUpdates(table) {
80
113
  timesPulled.set(table, 0);
81
114
  }
82
115
  }
116
+ export function getReceivedDataCompleted({ batchId, col, }) {
117
+ if (!batchId || !RECEIVED_DATA_COMPLETED_MAP[batchId]) {
118
+ throw new Error(`Batch ${batchId} not found`);
119
+ }
120
+ const completed = RECEIVED_DATA_COMPLETED_MAP[batchId][col] ?? false;
121
+ return completed;
122
+ }
123
+ export function setReceivedDataCompleted({ batchId, col, completed, }) {
124
+ if (!batchId || !RECEIVED_DATA_COMPLETED_MAP[batchId]) {
125
+ throw new Error(`Batch ${batchId} not found`);
126
+ }
127
+ RECEIVED_DATA_COMPLETED_MAP[batchId][col] = completed;
128
+ }
129
+ export function deleteReceivedDataCompleted(batchId) {
130
+ delete RECEIVED_DATA_COMPLETED_MAP[batchId];
131
+ }
@@ -5,7 +5,11 @@ import { RealtimeFilter } from "../../../types/realtimeData.types";
5
5
  * @param table - The table to pull data from
6
6
  * @returns The data from the table
7
7
  */
8
- export declare function pullData(table: string, filters?: RealtimeFilter[]): Promise<{
8
+ export declare function pullData({ table, filters, batchId, }: {
9
+ table: string;
10
+ filters?: RealtimeFilter[];
11
+ batchId: string;
12
+ }): Promise<{
9
13
  data: PayloadData[];
10
14
  deletedIds: string[];
11
15
  timestamps: {
@@ -1 +1 @@
1
- {"version":3,"file":"pullData.d.ts","sourceRoot":"","sources":["../../../../src/utils/sync/pullFromRemote/pullData.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AACzD,OAAO,EAAE,cAAc,EAAE,MAAM,mCAAmC,CAAC;AAQnE;;;;GAIG;AACH,wBAAsB,QAAQ,CAC5B,KAAK,EAAE,MAAM,EACb,OAAO,CAAC,EAAE,cAAc,EAAE,GACzB,OAAO,CAAC;IACT,IAAI,EAAE,WAAW,EAAE,CAAC;IACpB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,UAAU,EAAE;QACV,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;QAC1B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;QAC1B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;KAC3B,CAAC;CACH,GAAG,IAAI,CAAC,CAuER"}
1
+ {"version":3,"file":"pullData.d.ts","sourceRoot":"","sources":["../../../../src/utils/sync/pullFromRemote/pullData.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AACzD,OAAO,EAAE,cAAc,EAAE,MAAM,mCAAmC,CAAC;AAQnE;;;;GAIG;AACH,wBAAsB,QAAQ,CAAC,EAC7B,KAAK,EACL,OAAO,EACP,OAAO,GACR,EAAE;IACD,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,cAAc,EAAE,CAAC;IAC3B,OAAO,EAAE,MAAM,CAAC;CACjB,GAAG,OAAO,CAAC;IACV,IAAI,EAAE,WAAW,EAAE,CAAC;IACpB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,UAAU,EAAE;QACV,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;QAC1B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;QAC1B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;KAC3B,CAAC;CACH,GAAG,IAAI,CAAC,CA8ER"}
@@ -11,7 +11,7 @@ import { getMaxDate, logNoUpdates, pageThrough } from "./helpers";
11
11
  * @param table - The table to pull data from
12
12
  * @returns The data from the table
13
13
  */
14
- export async function pullData(table, filters) {
14
+ export async function pullData({ table, filters, batchId, }) {
15
15
  const supabase = getSupastashConfig().supabaseClient;
16
16
  if (!supabase)
17
17
  throw new Error(`No supabase client found: ${supabaseClientErr}`);
@@ -35,8 +35,15 @@ export async function pullData(table, filters) {
35
35
  since: last_created_at,
36
36
  table,
37
37
  filters,
38
+ batchId,
39
+ }),
40
+ pageThrough({
41
+ tsCol: "updated_at",
42
+ since: last_synced_at,
43
+ table,
44
+ filters,
45
+ batchId,
38
46
  }),
39
- pageThrough({ tsCol: "updated_at", since: last_synced_at, table, filters }),
40
47
  pageThrough({
41
48
  tsCol: "deleted_at",
42
49
  since: last_deleted_at,
@@ -44,6 +51,7 @@ export async function pullData(table, filters) {
44
51
  select: "id, deleted_at",
45
52
  table,
46
53
  filters,
54
+ batchId,
47
55
  }),
48
56
  ]);
49
57
  const merged = {};
@@ -1 +1 @@
1
- {"version":3,"file":"updateLocalDb.d.ts","sourceRoot":"","sources":["../../../../src/utils/sync/pullFromRemote/updateLocalDb.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,cAAc,EAAE,MAAM,mCAAmC,CAAC;AAgBnE;;;GAGG;AACH,wBAAsB,aAAa,CACjC,KAAK,EAAE,MAAM,EACb,OAAO,CAAC,EAAE,cAAc,EAAE,EAC1B,aAAa,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,KAAK,OAAO,CAAC,IAAI,CAAC,iBAqGhD;AAID;;;;;GAKG;AACH,wBAAsB,UAAU,CAC9B,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,GAAG,EACX,SAAS,CAAC,EAAE,OAAO,iBAsEpB"}
1
+ {"version":3,"file":"updateLocalDb.d.ts","sourceRoot":"","sources":["../../../../src/utils/sync/pullFromRemote/updateLocalDb.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,cAAc,EAAE,MAAM,mCAAmC,CAAC;AAkBnE;;;GAGG;AACH,wBAAsB,aAAa,CACjC,KAAK,EAAE,MAAM,EACb,OAAO,CAAC,EAAE,cAAc,EAAE,EAC1B,aAAa,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,KAAK,OAAO,CAAC,IAAI,CAAC,iBAuHhD;AAID;;;;;GAKG;AACH,wBAAsB,UAAU,CAC9B,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,GAAG,EACX,SAAS,CAAC,EAAE,OAAO,iBAsEpB"}
@@ -1,12 +1,15 @@
1
1
  import { getSupastashConfig } from "../../../core/config";
2
2
  import { getSupastashDb } from "../../../db/dbInitializer";
3
+ import { DEFAULT_RECEIVED_DATA_COMPLETED, RECEIVED_DATA_COMPLETED_MAP, } from "../../../store/syncStatus";
3
4
  import { isOnline } from "../../connection";
5
+ import { generateUUIDv4 } from "../../genUUID";
4
6
  import { getTableSchema } from "../../getTableSchema";
5
7
  import log, { logError, logWarn } from "../../logs";
6
8
  import { refreshScreen } from "../../refreshScreenCalls";
7
9
  import { SyncInfoUpdater } from "../queryStatus";
8
10
  import { setSupastashSyncStatus } from "../status/services";
9
11
  import { updateLocalSyncedAt } from "../status/syncUpdate";
12
+ import { deleteReceivedDataCompleted } from "./helpers";
10
13
  import { pullData } from "./pullData";
11
14
  import { stringifyValue } from "./stringifyFields";
12
15
  let isInSync = new Map();
@@ -20,84 +23,100 @@ const DELETE_CHUNK = 999;
20
23
  export async function updateLocalDb(table, filters, onReceiveData) {
21
24
  if (isInSync.get(table))
22
25
  return;
23
- isInSync.set(table, true);
24
26
  const cfg = getSupastashConfig();
25
27
  if (cfg.supastashMode === "ghost")
26
28
  return;
29
+ if (!(await isOnline()))
30
+ return;
31
+ isInSync.set(table, true);
32
+ const batchId = generateUUIDv4();
27
33
  try {
28
- if (!(await isOnline()))
29
- return;
30
34
  const db = await getSupastashDb();
31
- const dataResult = await pullData(table, filters);
32
- const data = dataResult?.data;
33
- const timestamps = dataResult?.timestamps;
34
- const deletedIds = dataResult?.deletedIds;
35
- const deletedIdSet = new Set(deletedIds ?? []);
36
- SyncInfoUpdater.setUnsyncedDataCount({
37
- amount: data?.length ?? 0,
38
- type: "pull",
39
- table,
40
- });
41
- SyncInfoUpdater.setUnsyncedDeletedCount({
42
- amount: deletedIds?.length ?? 0,
43
- type: "pull",
44
- table,
45
- });
46
- const refreshNeeded = !!data?.length || !!deletedIds?.length;
47
- // Delete records that are no longer in the remote data
48
- if (deletedIds && deletedIds.length > 0) {
49
- const ids = deletedIds;
50
- for (let i = 0; i < ids.length; i += DELETE_CHUNK) {
51
- const slice = ids.slice(i, i + DELETE_CHUNK);
52
- const placeholders = slice.map(() => "?").join(", ");
53
- await db.runAsync(`DELETE FROM ${table} WHERE id IN (${placeholders})`, slice);
54
- }
55
- }
56
- // Get the local stamp of the records
57
- let localStamp = new Map();
58
- if (data?.length) {
59
- const ids = data.map((r) => r.id).filter(Boolean);
60
- for (let i = 0; i < ids.length; i += DELETE_CHUNK) {
61
- const slice = ids.slice(i, i + DELETE_CHUNK);
62
- const placeholders = slice.map(() => "?").join(", ");
63
- const rows = await db.getAllAsync(`SELECT id, updated_at FROM ${table} WHERE id IN (${placeholders})`, slice);
64
- for (const row of rows ?? []) {
65
- localStamp.set(row.id, row.updated_at ?? null);
35
+ // Initialize the batch completed map
36
+ RECEIVED_DATA_COMPLETED_MAP[batchId] = {
37
+ created_at: DEFAULT_RECEIVED_DATA_COMPLETED,
38
+ updated_at: DEFAULT_RECEIVED_DATA_COMPLETED,
39
+ deleted_at: DEFAULT_RECEIVED_DATA_COMPLETED,
40
+ };
41
+ let refreshNeeded = false;
42
+ while (true) {
43
+ const dataResult = await pullData({ table, filters, batchId });
44
+ if (!dataResult)
45
+ break;
46
+ const data = dataResult?.data;
47
+ const timestamps = dataResult.timestamps;
48
+ const deletedIds = dataResult.deletedIds;
49
+ const deletedIdSet = new Set(deletedIds ?? []);
50
+ SyncInfoUpdater.setUnsyncedDataCount({
51
+ amount: data?.length ?? 0,
52
+ type: "pull",
53
+ table,
54
+ });
55
+ SyncInfoUpdater.setUnsyncedDeletedCount({
56
+ amount: deletedIds?.length ?? 0,
57
+ type: "pull",
58
+ table,
59
+ });
60
+ refreshNeeded = !!data?.length || !!deletedIds?.length;
61
+ // Delete records that are no longer in the remote data
62
+ if (deletedIds && deletedIds.length > 0) {
63
+ const ids = deletedIds;
64
+ for (let i = 0; i < ids.length; i += DELETE_CHUNK) {
65
+ const slice = ids.slice(i, i + DELETE_CHUNK);
66
+ const placeholders = slice.map(() => "?").join(", ");
67
+ await db.runAsync(`DELETE FROM ${table} WHERE id IN (${placeholders})`, slice);
66
68
  }
67
69
  }
68
- }
69
- // Update local database with remote changes
70
- if (data?.length) {
71
- for (let i = 0; i < data.length; i++) {
72
- const record = data[i];
73
- if (!record?.id)
74
- continue;
75
- if (deletedIdSet.has(record.id))
76
- continue;
77
- const localUpdated = localStamp.get(record.id) ?? DEFAULT_DATE;
78
- const remoteUpdated = record.updated_at ?? DEFAULT_DATE;
79
- if (new Date(localUpdated) >= new Date(remoteUpdated)) {
80
- // local is newer or same — skip
81
- continue;
82
- }
83
- if (onReceiveData) {
84
- await onReceiveData(record);
70
+ // Get the local stamp of the records
71
+ let localStamp = new Map();
72
+ if (data?.length) {
73
+ const ids = data.map((r) => r.id).filter(Boolean);
74
+ for (let i = 0; i < ids.length; i += DELETE_CHUNK) {
75
+ const slice = ids.slice(i, i + DELETE_CHUNK);
76
+ const placeholders = slice.map(() => "?").join(", ");
77
+ const rows = await db.getAllAsync(`SELECT id, updated_at FROM ${table} WHERE id IN (${placeholders})`, slice);
78
+ for (const row of rows ?? []) {
79
+ localStamp.set(row.id, row.updated_at ?? null);
80
+ }
85
81
  }
86
- else {
87
- await upsertData(table, record, localStamp.has(record.id));
88
- }
89
- if ((i + 1) % BATCH_SIZE === 0) {
90
- await new Promise((res) => setTimeout(res, 0));
82
+ }
83
+ // Update local database with remote changes
84
+ if (data?.length) {
85
+ for (let i = 0; i < data.length; i++) {
86
+ const record = data[i];
87
+ if (!record?.id)
88
+ continue;
89
+ if (deletedIdSet.has(record.id))
90
+ continue;
91
+ const localUpdated = localStamp.get(record.id) ?? DEFAULT_DATE;
92
+ const remoteUpdated = record.updated_at ?? DEFAULT_DATE;
93
+ if (new Date(localUpdated) >= new Date(remoteUpdated)) {
94
+ // local is newer or same — skip
95
+ continue;
96
+ }
97
+ if (onReceiveData) {
98
+ await onReceiveData(record);
99
+ }
100
+ else {
101
+ await upsertData(table, record, localStamp.has(record.id));
102
+ }
103
+ if ((i + 1) % BATCH_SIZE === 0) {
104
+ await new Promise((res) => setTimeout(res, 0));
105
+ }
91
106
  }
92
107
  }
93
- }
94
- if (timestamps) {
95
- await setSupastashSyncStatus(table, filters, {
96
- lastCreatedAt: timestamps.createdMax,
97
- lastSyncedAt: timestamps.updatedMax,
98
- lastDeletedAt: timestamps.deletedMax,
99
- filterNamespace: "global",
100
- });
108
+ if (timestamps) {
109
+ await setSupastashSyncStatus(table, filters, {
110
+ lastCreatedAt: timestamps.createdMax,
111
+ lastSyncedAt: timestamps.updatedMax,
112
+ lastDeletedAt: timestamps.deletedMax,
113
+ filterNamespace: "global",
114
+ });
115
+ }
116
+ const completedSet = RECEIVED_DATA_COMPLETED_MAP[batchId];
117
+ if (Object.values(completedSet ?? {}).every(Boolean)) {
118
+ break;
119
+ }
101
120
  }
102
121
  if (refreshNeeded)
103
122
  refreshScreen(table);
@@ -108,6 +127,7 @@ export async function updateLocalDb(table, filters, onReceiveData) {
108
127
  }
109
128
  finally {
110
129
  isInSync.delete(table);
130
+ deleteReceivedDataCompleted(batchId);
111
131
  }
112
132
  }
113
133
  const warned = new Map();
@@ -1 +1 @@
1
- {"version":3,"file":"validateFilters.d.ts","sourceRoot":"","sources":["../../../../src/utils/sync/pullFromRemote/validateFilters.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,mCAAmC,CAAC;AAcnE,iBAAS,aAAa,CAAC,CAAC,GAAG,GAAG,EAAE,OAAO,EAAE,cAAc,CAAC,CAAC,CAAC,EAAE,GAAG,OAAO,CAyDrE;AAED,eAAe,aAAa,CAAC;AAM7B,wBAAgB,cAAc,CAAC,CAAC,GAAG,GAAG,EACpC,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,cAAc,CAAC,CAAC,CAAC,EAAE,QAkD7B"}
1
+ {"version":3,"file":"validateFilters.d.ts","sourceRoot":"","sources":["../../../../src/utils/sync/pullFromRemote/validateFilters.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,mCAAmC,CAAC;AAcnE,iBAAS,aAAa,CAAC,CAAC,GAAG,GAAG,EAAE,OAAO,EAAE,cAAc,CAAC,CAAC,CAAC,EAAE,GAAG,OAAO,CA+DrE;AAED,eAAe,aAAa,CAAC;AAM7B,wBAAgB,cAAc,CAAC,CAAC,GAAG,GAAG,EACpC,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,cAAc,CAAC,CAAC,CAAC,EAAE,QAkD7B"}
@@ -24,6 +24,11 @@ function isValidFilter(filters) {
24
24
  }
25
25
  switch (operator) {
26
26
  case "is":
27
+ if (typeof value === "boolean") {
28
+ // normalize
29
+ filter.value = value ? "true" : "false";
30
+ break;
31
+ }
27
32
  if (!(value === null ||
28
33
  value === "null" ||
29
34
  value === "true" ||
@@ -13,13 +13,13 @@ let isInSync = new Map();
13
13
  export async function pushLocalDataToRemote(table, onPushToRemote, noSync) {
14
14
  if (isInSync.get(table))
15
15
  return;
16
- isInSync.set(table, true);
17
16
  const cfg = getSupastashConfig();
18
17
  if (cfg.supastashMode === "ghost")
19
18
  return false;
19
+ if (!(await isOnline()))
20
+ return false;
21
+ isInSync.set(table, true);
20
22
  try {
21
- if (!(await isOnline()))
22
- return false;
23
23
  const data = await getAllUnsyncedData(table);
24
24
  const deletedData = await getAllDeletedData(table);
25
25
  SyncInfoUpdater.setUnsyncedDataCount({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "supastash",
3
- "version": "0.1.54",
3
+ "version": "0.1.55",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "type": "module",