supastash 0.2.17 → 0.2.18

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/desktop/utils/sync/pushLocal/index.ts"],"names":[],"mappings":"AAaA;;GAEG;AACH,wBAAsB,aAAa,kBAiGlC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/desktop/utils/sync/pushLocal/index.ts"],"names":[],"mappings":"AAaA;;GAEG;AACH,wBAAsB,aAAa,kBAwGlC"}
@@ -21,7 +21,14 @@ export async function pushLocalData() {
21
21
  return;
22
22
  }
23
23
  const excludeTables = getSupastashConfig()?.excludeTables?.push || [];
24
- const tablesToPush = tables.filter((table) => !excludeTables?.includes(table));
24
+ const pushOrder = getSupastashConfig()?.syncSortOrder?.push || [];
25
+ const filtered = tables.filter((table) => !excludeTables?.includes(table));
26
+ const tablesToPush = pushOrder.length > 0
27
+ ? [
28
+ ...pushOrder.filter((t) => filtered.includes(t)),
29
+ ...filtered.filter((t) => !pushOrder.includes(t)),
30
+ ]
31
+ : filtered;
25
32
  numberOfTables = tablesToPush.length;
26
33
  SyncInfoUpdater.setInProgress({
27
34
  action: "start",
@@ -75,7 +82,7 @@ export async function pushLocalData() {
75
82
  tablePushLock.set(table, false);
76
83
  }
77
84
  });
78
- await runLimitedConcurrency(jobs, 3);
85
+ await runLimitedConcurrency(jobs, pushOrder.length > 0 ? 1 : 3);
79
86
  const hadAnyWork = results.some((r) => r.hadWork);
80
87
  if (!hadAnyWork) {
81
88
  emptyPassCount += 1;
@@ -1 +1 @@
1
- {"version":3,"file":"uploadHelpers.d.ts","sourceRoot":"","sources":["../../../../../src/desktop/utils/sync/pushLocal/uploadHelpers.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,eAAe,EAAE,MAAM,gDAAgD,CAAC;AACjF,OAAO,EAAE,OAAO,EAAE,MAAM,2CAA2C,CAAC;AAOpE,wBAAgB,eAAe,CAC7B,GAAG,EAAE,eAAe,CAAC,GAAG,CAAC,EACzB,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,wFAYvB;AAED,iBAAe,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,QAAQ,EAAE,GAAG,gBAEvE;AAED,iBAAe,YAAY,CACzB,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,OAAO,EACZ,QAAQ,EAAE,GAAG,EACb,SAAS,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,gBAwBjC;AAED,iBAAe,OAAO,CAAC,QAAQ,EAAE,MAAM,iBAOtC;AAmBD,iBAAe,SAAS,CAAC,EACvB,KAAK,EACL,IAAI,EACJ,QAAQ,GACT,EAAE;IACD,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,OAAO,EAAE,CAAC;IAChB,QAAQ,EAAE,GAAG,CAAC;CACf;;;;;;;GA+CA;AAED,iBAAe,eAAe,CAAC,EAC7B,KAAK,EACL,GAAG,EACH,QAAQ,EACR,SAAS,GACV,EAAE;IACD,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,OAAO,CAAC;IACb,QAAQ,EAAE,GAAG,CAAC;IACd,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACjC;;;;;;GAaA;AAMD,iBAAe,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,iBAIrD;AAWD,iBAAS,qBAAqB,CAC5B,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,OAAO,EAAE,EAChB,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,aAiCjC;AAMD,iBAAe,gBAAgB,CAC7B,GAAG,EAAE,eAAe,CAAC,GAAG,CAAC,EACzB,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,OAAO,EACZ,GAAG,EAAE,GAAG,EACR,QAAQ,EAAE,GAAG,GACZ,OAAO,CAAC,MAAM,GAAG,MAAM,GAAG,UAAU,CAAC,CA4DvC;AAgBD,OAAO,EACL,OAAO,EACP,WAAW,EACX,qBAAqB,EACrB,gBAAgB,EAChB,UAAU,EACV,SAAS,EACT,eAAe,EACf,YAAY,GACb,CAAC;AAEF;;;GAGG;AACH,wBAAsB,kBAAkB,CACtC,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,GAAG,iBAkBd;AASD,wBAAsB,uBAAuB,CAC3C,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,MAAM,EAAE,EACb,QAAQ,EAAE,GAAG,gCAcd"}
1
+ {"version":3,"file":"uploadHelpers.d.ts","sourceRoot":"","sources":["../../../../../src/desktop/utils/sync/pushLocal/uploadHelpers.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,eAAe,EAAE,MAAM,gDAAgD,CAAC;AACjF,OAAO,EAAE,OAAO,EAAE,MAAM,2CAA2C,CAAC;AAOpE,wBAAgB,eAAe,CAC7B,GAAG,EAAE,eAAe,CAAC,GAAG,CAAC,EACzB,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,wFAYvB;AAED,iBAAe,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,QAAQ,EAAE,GAAG,gBAEvE;AAED,iBAAe,YAAY,CACzB,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,OAAO,EACZ,QAAQ,EAAE,GAAG,EACb,SAAS,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,gBAwBjC;AAED,iBAAe,OAAO,CAAC,QAAQ,EAAE,MAAM,iBAOtC;AAmBD,iBAAe,SAAS,CAAC,EACvB,KAAK,EACL,IAAI,EACJ,QAAQ,GACT,EAAE;IACD,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,OAAO,EAAE,CAAC;IAChB,QAAQ,EAAE,GAAG,CAAC;CACf;;;;;;;GA+CA;AAED,iBAAe,eAAe,CAAC,EAC7B,KAAK,EACL,GAAG,EACH,QAAQ,EACR,SAAS,GACV,EAAE;IACD,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,OAAO,CAAC;IACb,QAAQ,EAAE,GAAG,CAAC;IACd,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACjC;;;;;;GAaA;AAMD,iBAAe,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,iBAIrD;AAWD,iBAAS,qBAAqB,CAC5B,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,OAAO,EAAE,EAChB,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,aAiCjC;AAMD,iBAAe,gBAAgB,CAC7B,GAAG,EAAE,eAAe,CAAC,GAAG,CAAC,EACzB,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,OAAO,EACZ,GAAG,EAAE,GAAG,EACR,QAAQ,EAAE,GAAG,GACZ,OAAO,CAAC,MAAM,GAAG,MAAM,GAAG,UAAU,CAAC,CAqFvC;AAyBD,OAAO,EACL,OAAO,EACP,WAAW,EACX,qBAAqB,EACrB,gBAAgB,EAChB,UAAU,EACV,SAAS,EACT,eAAe,EACf,YAAY,GACb,CAAC;AAEF;;;GAGG;AACH,wBAAsB,kBAAkB,CACtC,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,GAAG,iBAkBd;AASD,wBAAsB,uBAAuB,CAC3C,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,MAAM,EAAE,EACb,QAAQ,EAAE,GAAG,gCAcd"}
@@ -182,6 +182,11 @@ async function handleRowFailure(cfg, table, row, err, supabase) {
182
182
  const klass = classifyFailure(cfg, code);
183
183
  if (klass === "NON_RETRYABLE") {
184
184
  const action = cfg.syncPolicy?.onNonRetryable ?? "accept-server";
185
+ if (!await hasValidSession(supabase)) {
186
+ logWarn(`Row ${row.id} on ${table} hit NON_RETRYABLE but no active session — skipping delete, will retry`, JSON.stringify(err));
187
+ setQueryStatus(row.id, table, "error");
188
+ return "KEEP";
189
+ }
185
190
  if (action === "delete-local" || cfg.deleteConflictedRows) {
186
191
  logWarn(`Row ${row.id} on ${table} hit NON_RETRYABLE conflict → deleting local`, JSON.stringify(err));
187
192
  await deleteLocalRow(table, row.id, supabase);
@@ -195,6 +200,11 @@ async function handleRowFailure(cfg, table, row, err, supabase) {
195
200
  }
196
201
  }
197
202
  if (klass === "UNIQUE_VIOLATION") {
203
+ if (!await hasValidSession(supabase)) {
204
+ logWarn(`Row ${row.id} on ${table} hit UNIQUE_VIOLATION but no active session — skipping delete, will retry`, JSON.stringify(err));
205
+ setQueryStatus(row.id, table, "error");
206
+ return "KEEP";
207
+ }
198
208
  logWarn(`[Supastash] Row ${row.id} on ${table} violated a unique constraint (23505) → deleting local copy`, JSON.stringify(err));
199
209
  await deleteLocalRow(table, row.id, supabase);
200
210
  cfg.syncPolicy?.onRowDroppedLocal?.(table, row.id);
@@ -209,6 +219,11 @@ async function handleRowFailure(cfg, table, row, err, supabase) {
209
219
  if (klass === "HTTP" || klass === "RETRYABLE" || klass === "UNKNOWN") {
210
220
  log(`Row ${row.id} on ${table} transient/HTTP error → scheduling retry`, JSON.stringify(err));
211
221
  if (klass === "HTTP") {
222
+ if (!await hasValidSession(supabase)) {
223
+ logWarn(`Row ${row.id} on ${table} hit HTTP conflict but no active session — skipping replace, will retry`, JSON.stringify(err));
224
+ setQueryStatus(row.id, table, "error");
225
+ return "KEEP";
226
+ }
212
227
  await deleteLocalRow(table, row.id, supabase);
213
228
  return "REPLACED";
214
229
  }
@@ -224,6 +239,15 @@ function quoteIdent(name) {
224
239
  }
225
240
  return `"${name.replace(/"/g, '""')}"`;
226
241
  }
242
+ async function hasValidSession(supabase) {
243
+ try {
244
+ const { data } = await supabase.auth.getSession();
245
+ return !!data?.session;
246
+ }
247
+ catch {
248
+ return false;
249
+ }
250
+ }
227
251
  async function deleteLocalRow(table, id, supabase) {
228
252
  await rewindAndDropLocal(table, id, supabase);
229
253
  setQueryStatus(id, table, "success");
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/native/utils/sync/pushLocal/index.ts"],"names":[],"mappings":"AAaA;;GAEG;AACH,wBAAsB,aAAa,kBAiGlC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/native/utils/sync/pushLocal/index.ts"],"names":[],"mappings":"AAaA;;GAEG;AACH,wBAAsB,aAAa,kBAwGlC"}
@@ -21,7 +21,14 @@ export async function pushLocalData() {
21
21
  return;
22
22
  }
23
23
  const excludeTables = getSupastashConfig()?.excludeTables?.push || [];
24
- const tablesToPush = tables.filter((table) => !excludeTables?.includes(table));
24
+ const pushOrder = getSupastashConfig()?.syncSortOrder?.push || [];
25
+ const filtered = tables.filter((table) => !excludeTables?.includes(table));
26
+ const tablesToPush = pushOrder.length > 0
27
+ ? [
28
+ ...pushOrder.filter((t) => filtered.includes(t)),
29
+ ...filtered.filter((t) => !pushOrder.includes(t)),
30
+ ]
31
+ : filtered;
25
32
  numberOfTables = tablesToPush.length;
26
33
  SyncInfoUpdater.setInProgress({
27
34
  action: "start",
@@ -75,7 +82,7 @@ export async function pushLocalData() {
75
82
  tablePushLock.set(table, false);
76
83
  }
77
84
  });
78
- await runLimitedConcurrency(jobs, 3);
85
+ await runLimitedConcurrency(jobs, pushOrder.length > 0 ? 1 : 3);
79
86
  const hadAnyWork = results.some((r) => r.hadWork);
80
87
  if (!hadAnyWork) {
81
88
  emptyPassCount += 1;
@@ -1 +1 @@
1
- {"version":3,"file":"uploadHelpers.d.ts","sourceRoot":"","sources":["../../../../../src/native/utils/sync/pushLocal/uploadHelpers.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,eAAe,EAAE,MAAM,gDAAgD,CAAC;AACjF,OAAO,EAAE,OAAO,EAAE,MAAM,2CAA2C,CAAC;AAOpE,wBAAgB,eAAe,CAC7B,GAAG,EAAE,eAAe,CAAC,GAAG,CAAC,EACzB,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,wFAYvB;AAED,iBAAe,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,QAAQ,EAAE,GAAG,gBAEvE;AAED,iBAAe,YAAY,CACzB,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,OAAO,EACZ,QAAQ,EAAE,GAAG,EACb,SAAS,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,gBAwBjC;AAED,iBAAe,OAAO,CAAC,QAAQ,EAAE,MAAM,iBAOtC;AAmBD,iBAAe,SAAS,CAAC,EACvB,KAAK,EACL,IAAI,EACJ,QAAQ,GACT,EAAE;IACD,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,OAAO,EAAE,CAAC;IAChB,QAAQ,EAAE,GAAG,CAAC;CACf;;;;;;;GA+CA;AAED,iBAAe,eAAe,CAAC,EAC7B,KAAK,EACL,GAAG,EACH,QAAQ,EACR,SAAS,GACV,EAAE;IACD,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,OAAO,CAAC;IACb,QAAQ,EAAE,GAAG,CAAC;IACd,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACjC;;;;;;GAaA;AAMD,iBAAe,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,iBAIrD;AAWD,iBAAS,qBAAqB,CAC5B,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,OAAO,EAAE,EAChB,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,aAiCjC;AAMD,iBAAe,gBAAgB,CAC7B,GAAG,EAAE,eAAe,CAAC,GAAG,CAAC,EACzB,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,OAAO,EACZ,GAAG,EAAE,GAAG,EACR,QAAQ,EAAE,GAAG,GACZ,OAAO,CAAC,MAAM,GAAG,MAAM,GAAG,UAAU,CAAC,CA4DvC;AAgBD,OAAO,EACL,OAAO,EACP,WAAW,EACX,qBAAqB,EACrB,gBAAgB,EAChB,UAAU,EACV,SAAS,EACT,eAAe,EACf,YAAY,GACb,CAAC;AAEF;;;GAGG;AACH,wBAAsB,kBAAkB,CACtC,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,GAAG,iBAkBd;AASD,wBAAsB,uBAAuB,CAC3C,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,MAAM,EAAE,EACb,QAAQ,EAAE,GAAG,gCAcd"}
1
+ {"version":3,"file":"uploadHelpers.d.ts","sourceRoot":"","sources":["../../../../../src/native/utils/sync/pushLocal/uploadHelpers.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,eAAe,EAAE,MAAM,gDAAgD,CAAC;AACjF,OAAO,EAAE,OAAO,EAAE,MAAM,2CAA2C,CAAC;AAOpE,wBAAgB,eAAe,CAC7B,GAAG,EAAE,eAAe,CAAC,GAAG,CAAC,EACzB,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,wFAYvB;AAED,iBAAe,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,QAAQ,EAAE,GAAG,gBAEvE;AAED,iBAAe,YAAY,CACzB,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,OAAO,EACZ,QAAQ,EAAE,GAAG,EACb,SAAS,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,gBAwBjC;AAED,iBAAe,OAAO,CAAC,QAAQ,EAAE,MAAM,iBAOtC;AAmBD,iBAAe,SAAS,CAAC,EACvB,KAAK,EACL,IAAI,EACJ,QAAQ,GACT,EAAE;IACD,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,OAAO,EAAE,CAAC;IAChB,QAAQ,EAAE,GAAG,CAAC;CACf;;;;;;;GA+CA;AAED,iBAAe,eAAe,CAAC,EAC7B,KAAK,EACL,GAAG,EACH,QAAQ,EACR,SAAS,GACV,EAAE;IACD,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,OAAO,CAAC;IACb,QAAQ,EAAE,GAAG,CAAC;IACd,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACjC;;;;;;GAaA;AAMD,iBAAe,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,iBAIrD;AAWD,iBAAS,qBAAqB,CAC5B,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,OAAO,EAAE,EAChB,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,aAiCjC;AAMD,iBAAe,gBAAgB,CAC7B,GAAG,EAAE,eAAe,CAAC,GAAG,CAAC,EACzB,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,OAAO,EACZ,GAAG,EAAE,GAAG,EACR,QAAQ,EAAE,GAAG,GACZ,OAAO,CAAC,MAAM,GAAG,MAAM,GAAG,UAAU,CAAC,CAqFvC;AAyBD,OAAO,EACL,OAAO,EACP,WAAW,EACX,qBAAqB,EACrB,gBAAgB,EAChB,UAAU,EACV,SAAS,EACT,eAAe,EACf,YAAY,GACb,CAAC;AAEF;;;GAGG;AACH,wBAAsB,kBAAkB,CACtC,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,GAAG,iBAkBd;AASD,wBAAsB,uBAAuB,CAC3C,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,MAAM,EAAE,EACb,QAAQ,EAAE,GAAG,gCAcd"}
@@ -182,6 +182,11 @@ async function handleRowFailure(cfg, table, row, err, supabase) {
182
182
  const klass = classifyFailure(cfg, code);
183
183
  if (klass === "NON_RETRYABLE") {
184
184
  const action = cfg.syncPolicy?.onNonRetryable ?? "accept-server";
185
+ if (!await hasValidSession(supabase)) {
186
+ logWarn(`Row ${row.id} on ${table} hit NON_RETRYABLE but no active session — skipping delete, will retry`, JSON.stringify(err));
187
+ setQueryStatus(row.id, table, "error");
188
+ return "KEEP";
189
+ }
185
190
  if (action === "delete-local" || cfg.deleteConflictedRows) {
186
191
  logWarn(`Row ${row.id} on ${table} hit NON_RETRYABLE conflict → deleting local`, JSON.stringify(err));
187
192
  await deleteLocalRow(table, row.id, supabase);
@@ -195,6 +200,11 @@ async function handleRowFailure(cfg, table, row, err, supabase) {
195
200
  }
196
201
  }
197
202
  if (klass === "UNIQUE_VIOLATION") {
203
+ if (!await hasValidSession(supabase)) {
204
+ logWarn(`Row ${row.id} on ${table} hit UNIQUE_VIOLATION but no active session — skipping delete, will retry`, JSON.stringify(err));
205
+ setQueryStatus(row.id, table, "error");
206
+ return "KEEP";
207
+ }
198
208
  logWarn(`[Supastash] Row ${row.id} on ${table} violated a unique constraint (23505) → deleting local copy`, JSON.stringify(err));
199
209
  await deleteLocalRow(table, row.id, supabase);
200
210
  cfg.syncPolicy?.onRowDroppedLocal?.(table, row.id);
@@ -209,6 +219,11 @@ async function handleRowFailure(cfg, table, row, err, supabase) {
209
219
  if (klass === "HTTP" || klass === "RETRYABLE" || klass === "UNKNOWN") {
210
220
  log(`Row ${row.id} on ${table} transient/HTTP error → scheduling retry`, JSON.stringify(err));
211
221
  if (klass === "HTTP") {
222
+ if (!await hasValidSession(supabase)) {
223
+ logWarn(`Row ${row.id} on ${table} hit HTTP conflict but no active session — skipping replace, will retry`, JSON.stringify(err));
224
+ setQueryStatus(row.id, table, "error");
225
+ return "KEEP";
226
+ }
212
227
  await deleteLocalRow(table, row.id, supabase);
213
228
  return "REPLACED";
214
229
  }
@@ -224,6 +239,15 @@ function quoteIdent(name) {
224
239
  }
225
240
  return `"${name.replace(/"/g, '""')}"`;
226
241
  }
242
+ async function hasValidSession(supabase) {
243
+ try {
244
+ const { data } = await supabase.auth.getSession();
245
+ return !!data?.session;
246
+ }
247
+ catch {
248
+ return false;
249
+ }
250
+ }
227
251
  async function deleteLocalRow(table, id, supabase) {
228
252
  await rewindAndDropLocal(table, id, supabase);
229
253
  setQueryStatus(id, table, "success");
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/shared/core/config/index.ts"],"names":[],"mappings":"AACA,OAAO,EACL,eAAe,EACf,0BAA0B,EAC3B,MAAM,mCAAmC,CAAC;AAyC3C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiDG;AAEH,wBAAgB,kBAAkB,CAAC,CAAC,SAAS,0BAA0B,EACrE,MAAM,EAAE,eAAe,CAAC,CAAC,CAAC,GAAG;IAAE,gBAAgB,EAAE,CAAC,CAAA;CAAE,QA4CrD;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/shared/core/config/index.ts"],"names":[],"mappings":"AACA,OAAO,EACL,eAAe,EACf,0BAA0B,EAC3B,MAAM,mCAAmC,CAAC;AA4C3C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiDG;AAEH,wBAAgB,kBAAkB,CAAC,CAAC,SAAS,0BAA0B,EACrE,MAAM,EAAE,eAAe,CAAC,CAAC,CAAC,GAAG;IAAE,gBAAgB,EAAE,CAAC,CAAA;CAAE,QA+CrD;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"}
@@ -34,6 +34,9 @@ let _config = {
34
34
  push: {},
35
35
  pull: {},
36
36
  },
37
+ syncSortOrder: {
38
+ push: [],
39
+ },
37
40
  };
38
41
  let _configured = false;
39
42
  /**
@@ -122,6 +125,9 @@ export function configureSupastash(config) {
122
125
  push: config.ignoredColumns?.push ?? _config.ignoredColumns?.push ?? {},
123
126
  pull: config.ignoredColumns?.pull ?? _config.ignoredColumns?.pull ?? {},
124
127
  },
128
+ syncSortOrder: {
129
+ push: config.syncSortOrder?.push ?? _config.syncSortOrder?.push ?? [],
130
+ },
125
131
  };
126
132
  _configured = true;
127
133
  }
@@ -143,6 +143,24 @@ export type SupastashConfig<T extends SupastashSQLiteClientTypes> = {
143
143
  push?: string[];
144
144
  };
145
145
 
146
+ /**
147
+ * Defines the push order for tables before syncing to Supabase.
148
+ *
149
+ * Tables listed here are pushed **first**, in the order provided.
150
+ * This is useful for respecting foreign key constraints — list parent
151
+ * tables before their dependent children to reduce FK violation errors.
152
+ *
153
+ * Tables not listed are pushed after the ordered ones, in their default order.
154
+ *
155
+ * @example
156
+ * syncSortOrder: {
157
+ * push: ["users", "shops", "orders", "order_items"],
158
+ * }
159
+ */
160
+ syncSortOrder?: {
161
+ push?: string[];
162
+ };
163
+
146
164
  /**
147
165
  * Per-table column blocklists for upsert operations.
148
166
  *
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "supastash",
3
- "version": "0.2.17",
3
+ "version": "0.2.18",
4
4
  "main": "./dist/index.js",
5
5
  "types": "./dist/index.d.ts",
6
6
  "type": "module",