supastash 0.2.16 → 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.
- package/dist/desktop/utils/sync/pushLocal/index.d.ts.map +1 -1
- package/dist/desktop/utils/sync/pushLocal/index.js +9 -2
- package/dist/desktop/utils/sync/pushLocal/uploadHelpers.d.ts.map +1 -1
- package/dist/desktop/utils/sync/pushLocal/uploadHelpers.js +24 -0
- package/dist/native/utils/sync/pushLocal/index.d.ts.map +1 -1
- package/dist/native/utils/sync/pushLocal/index.js +9 -2
- package/dist/native/utils/sync/pushLocal/uploadHelpers.d.ts.map +1 -1
- package/dist/native/utils/sync/pushLocal/uploadHelpers.js +24 -0
- package/dist/shared/core/config/index.d.ts.map +1 -1
- package/dist/shared/core/config/index.js +6 -0
- package/dist/shared/types/supastashConfig.types.d.ts +18 -0
- package/package.json +1 -1
|
@@ -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,
|
|
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
|
|
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,
|
|
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,
|
|
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
|
|
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,
|
|
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;
|
|
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
|
*
|