supastash 0.1.52 → 0.1.54

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/core/config/index.ts"],"names":[],"mappings":"AACA,OAAO,EACL,eAAe,EACf,0BAA0B,EAC3B,MAAM,mCAAmC,CAAC;AA4B3C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+CG;AAEH,wBAAgB,kBAAkB,CAAC,CAAC,SAAS,0BAA0B,EACrE,MAAM,EAAE,eAAe,CAAC,CAAC,CAAC,GAAG;IAAE,gBAAgB,EAAE,CAAC,CAAA;CAAE,QAuCrD;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,kBAAkB,CAChC,CAAC,SAAS,0BAA0B,KACjC,eAAe,CAAC,CAAC,CAAC,CAEtB;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,qBAAqB,CACnC,CAAC,SAAS,0BAA0B,EACpC,MAAM,EAAE;IACR,SAAS,EAAE,eAAe,CAAC,CAAC,CAAC,GAAG;QAC9B,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;KAC3B,CAAC;CACH,QAEA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/core/config/index.ts"],"names":[],"mappings":"AACA,OAAO,EACL,eAAe,EACf,0BAA0B,EAC3B,MAAM,mCAAmC,CAAC;AA6B3C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+CG;AAEH,wBAAgB,kBAAkB,CAAC,CAAC,SAAS,0BAA0B,EACrE,MAAM,EAAE,eAAe,CAAC,CAAC,CAAC,GAAG;IAAE,gBAAgB,EAAE,CAAC,CAAA;CAAE,QAuCrD;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,kBAAkB,CAChC,CAAC,SAAS,0BAA0B,KACjC,eAAe,CAAC,CAAC,CAAC,CAEtB;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,qBAAqB,CACnC,CAAC,SAAS,0BAA0B,EACpC,MAAM,EAAE;IACR,SAAS,EAAE,eAAe,CAAC,CAAC,CAAC,GAAG;QAC9B,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;KAC3B,CAAC;CACH,QAEA"}
@@ -15,6 +15,7 @@ let _config = {
15
15
  useFiltersFromStore: true,
16
16
  },
17
17
  listeners: 250,
18
+ supabaseBatchSize: 100,
18
19
  debugMode: true,
19
20
  syncPolicy: DEFAULT_POLICY,
20
21
  fieldEnforcement: DEFAULT_FIELDS,
@@ -13,8 +13,23 @@ export type SupastashSQLiteClientTypes =
13
13
  export type SupastashMode = "live" | "ghost";
14
14
 
15
15
  export type SupastashConfig<T extends SupastashSQLiteClientTypes> = {
16
+ // --------------------------------------------------
17
+ // Core Database & Client Configuration
18
+ // --------------------------------------------------
19
+
20
+ /**
21
+ * Name of the local SQLite database.
22
+ */
16
23
  dbName: string;
24
+
25
+ /**
26
+ * Supabase client instance.
27
+ */
17
28
  supabaseClient: SupabaseClient<any, "public", any> | null;
29
+
30
+ /**
31
+ * SQLite client adapter.
32
+ */
18
33
  sqliteClient: T extends "expo"
19
34
  ? ExpoSQLiteClient
20
35
  : T extends "rn-storage"
@@ -22,23 +37,111 @@ export type SupastashConfig<T extends SupastashSQLiteClientTypes> = {
22
37
  : T extends "rn-nitro"
23
38
  ? RNSqliteNitroClient
24
39
  : null;
40
+
41
+ /**
42
+ * Type of SQLite client.
43
+ */
25
44
  sqliteClientType: T;
26
- excludeTables?: { pull?: string[]; push?: string[] };
45
+
46
+ // --------------------------------------------------
47
+ // Supabase Write Batching
48
+ // --------------------------------------------------
49
+
50
+ /**
51
+ * Maximum number of rows sent per Supabase write request.
52
+ * Large payloads are automatically split into sequential batches.
53
+ * Default: 100.
54
+ */
55
+ supabaseBatchSize?: number;
56
+
57
+ // --------------------------------------------------
58
+ // Table Inclusion / Exclusion Rules
59
+ // --------------------------------------------------
60
+
61
+ /**
62
+ * Control which tables are included in pull and push sync operations.
63
+ */
64
+ excludeTables?: {
65
+ pull?: string[];
66
+ push?: string[];
67
+ };
68
+
69
+ // --------------------------------------------------
70
+ // Sync Polling Intervals
71
+ // --------------------------------------------------
72
+
73
+ /**
74
+ * Background sync polling intervals (in milliseconds).
75
+ */
27
76
  pollingInterval?: {
28
77
  pull?: number;
29
78
  push?: number;
30
79
  };
80
+
81
+ // --------------------------------------------------
82
+ // Sync Engine Toggles & Behavior
83
+ // --------------------------------------------------
84
+
85
+ /**
86
+ * High-level switches controlling sync behavior.
87
+ */
31
88
  syncEngine?: {
32
89
  push?: boolean;
33
90
  pull?: boolean;
34
91
  useFiltersFromStore?: boolean;
35
92
  };
93
+
94
+ // --------------------------------------------------
95
+ // Supabase Realtime Configuration
96
+ // --------------------------------------------------
97
+
98
+ /**
99
+ * Maximum number of active event listeners.
100
+ */
36
101
  listeners?: number;
102
+
103
+ // --------------------------------------------------
104
+ // Schema Initialization Hook
105
+ // --------------------------------------------------
106
+
107
+ /**
108
+ * Called once after local database initialization.
109
+ * Intended for defineLocalSchema calls.
110
+ */
37
111
  onSchemaInit?: () => Promise<void>;
112
+
113
+ // --------------------------------------------------
114
+ // Debugging & Diagnostics
115
+ // --------------------------------------------------
116
+
117
+ /**
118
+ * Enables verbose logging for sync and database operations.
119
+ */
38
120
  debugMode?: boolean;
39
121
 
122
+ // --------------------------------------------------
123
+ // Conflict Resolution & Retry Policy
124
+ // --------------------------------------------------
125
+
126
+ /**
127
+ * Defines how Supastash classifies and handles sync conflicts.
128
+ */
40
129
  syncPolicy?: SupastashSyncPolicy;
130
+
131
+ // --------------------------------------------------
132
+ // Field Validation & Auto-Fill Enforcement
133
+ // --------------------------------------------------
134
+
41
135
  fieldEnforcement?: FieldEnforcement;
136
+
137
+ // --------------------------------------------------
138
+ // Conflict Cleanup Behavior
139
+ // --------------------------------------------------
140
+
141
+ /**
142
+ * When true, local rows involved in non-retryable conflicts
143
+ * will be deleted instead of retained.
144
+ */
42
145
  deleteConflictedRows?: boolean;
43
146
  /**
44
147
  * The path to the RPC function to use for upserts.
@@ -1 +1 @@
1
- {"version":3,"file":"queueRemote.d.ts","sourceRoot":"","sources":["../../../../src/utils/query/helpers/queueRemote.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,WAAW,EACX,cAAc,EACf,MAAM,4BAA4B,CAAC;AA0CpC,wBAAgB,eAAe,CAAC,CAAC,SAAS,WAAW,EAAE,CAAC,SAAS,OAAO,EAAE,CAAC,EACzE,KAAK,EAAE,cAAc,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,GAC7B,OAAO,CAAC,OAAO,CAAC,CAYlB"}
1
+ {"version":3,"file":"queueRemote.d.ts","sourceRoot":"","sources":["../../../../src/utils/query/helpers/queueRemote.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,WAAW,EACX,cAAc,EACf,MAAM,4BAA4B,CAAC;AA0CpC,wBAAgB,eAAe,CAAC,CAAC,SAAS,WAAW,EAAE,CAAC,SAAS,OAAO,EAAE,CAAC,EACzE,KAAK,EAAE,cAAc,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,GAC7B,OAAO,CAAC,OAAO,CAAC,CAYlB"}
@@ -1,3 +1,4 @@
1
+ import { getSupastashConfig } from "../../../core/config";
1
2
  import { isOnline } from "../../../utils/connection";
2
3
  import { log, logWarn } from "../../../utils/logs";
3
4
  import { getQueryStatusFromDb } from "../../../utils/sync/queryStatus";
@@ -44,6 +45,25 @@ function scheduleBatch() {
44
45
  batchTimer = null;
45
46
  }, BATCH_DELAY);
46
47
  }
48
+ async function executeSupabaseCall(state) {
49
+ const config = getSupastashConfig();
50
+ const payload = state.payload;
51
+ if (!Array.isArray(payload)) {
52
+ return querySupabase(state, true);
53
+ }
54
+ const batchSize = config.supabaseBatchSize ?? 100;
55
+ for (let i = 0; i < payload.length; i += batchSize) {
56
+ const chunk = payload.slice(i, i + batchSize);
57
+ const result = await querySupabase({
58
+ ...state,
59
+ payload: chunk,
60
+ }, true);
61
+ if (result.error) {
62
+ return result;
63
+ }
64
+ }
65
+ return { error: null };
66
+ }
47
67
  async function processBatch() {
48
68
  if (isProcessing || batchQueue.length === 0)
49
69
  return;
@@ -76,7 +96,7 @@ async function processBatch() {
76
96
  continue;
77
97
  }
78
98
  calledOfflineRetries.delete(opKey);
79
- const { error } = await querySupabase({ ...state }, true);
99
+ const { error } = await executeSupabaseCall(state);
80
100
  if (!error) {
81
101
  successfulCalls.add(opKey);
82
102
  retryCount.delete(opKey);
@@ -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,kBAiDA;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":"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"}
@@ -28,10 +28,15 @@ export async function pageThrough(base) {
28
28
  let q = supabase
29
29
  .from(table)
30
30
  .select(select)
31
- .gte(base.tsCol, cursorTs)
32
31
  .order(base.tsCol, { ascending: true })
33
32
  .order("id", { ascending: true })
34
33
  .limit(PAGE_SIZE);
34
+ if (cursorId) {
35
+ q = q.or(`${base.tsCol}.gt.${cursorTs},and(${base.tsCol}.eq.${cursorTs},id.gt.${cursorId})`);
36
+ }
37
+ else {
38
+ q = q.gte(base.tsCol, cursorTs);
39
+ }
35
40
  if (!base.includeDeleted)
36
41
  q = q.is("deleted_at", null);
37
42
  if (filters) {
@@ -42,12 +47,7 @@ export async function pageThrough(base) {
42
47
  throw error;
43
48
  if (!data || data.length === 0)
44
49
  break;
45
- const page = results.length === 0
46
- ? data.filter((r) => !(r[base.tsCol] === cursorTs &&
47
- typeof r.id === "string" &&
48
- r.id === cursorId))
49
- : data;
50
- results.push(...page);
50
+ results.push(...data);
51
51
  if (data.length < PAGE_SIZE)
52
52
  break;
53
53
  const last = data[data.length - 1];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "supastash",
3
- "version": "0.1.52",
3
+ "version": "0.1.54",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "type": "module",