@pol-studios/powersync 1.0.25 → 1.0.32
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/README.md +0 -1
- package/dist/{CacheSettingsManager-uz-kbnRH.d.ts → CacheSettingsManager-0H_7thHW.d.ts} +21 -3
- package/dist/attachments/index.d.ts +30 -30
- package/dist/attachments/index.js +13 -4
- package/dist/{background-sync-ChCXW-EV.d.ts → background-sync-BujnI3IR.d.ts} +1 -1
- package/dist/{chunk-55DKCJV4.js → chunk-2RDWLXJW.js} +408 -78
- package/dist/chunk-2RDWLXJW.js.map +1 -0
- package/dist/{chunk-P4HZA6ZT.js → chunk-4665ZSE5.js} +2 -2
- package/dist/chunk-4665ZSE5.js.map +1 -0
- package/dist/{chunk-XOY2CJ67.js → chunk-4F5B5CZ7.js} +3 -3
- package/dist/chunk-5WRI5ZAA.js +31 -0
- package/dist/{chunk-BGBQYQV3.js → chunk-65A3SYJZ.js} +193 -299
- package/dist/chunk-65A3SYJZ.js.map +1 -0
- package/dist/chunk-6SZ64KCZ.js +755 -0
- package/dist/chunk-6SZ64KCZ.js.map +1 -0
- package/dist/{chunk-YSTEESEG.js → chunk-74TBHWJ4.js} +122 -11
- package/dist/chunk-74TBHWJ4.js.map +1 -0
- package/dist/chunk-ANXWYQEJ.js +1 -0
- package/dist/chunk-ANXWYQEJ.js.map +1 -0
- package/dist/{chunk-CAB26E6F.js → chunk-C4J4MLER.js} +29 -24
- package/dist/chunk-C4J4MLER.js.map +1 -0
- package/dist/{chunk-C5ODS3XH.js → chunk-EOW7JK7Q.js} +9 -16
- package/dist/chunk-EOW7JK7Q.js.map +1 -0
- package/dist/chunk-HRAVPIAZ.js +220 -0
- package/dist/chunk-HRAVPIAZ.js.map +1 -0
- package/dist/{chunk-XAEII4ZX.js → chunk-NUGQOTEM.js} +32 -4
- package/dist/chunk-NUGQOTEM.js.map +1 -0
- package/dist/chunk-OGUFUZSY.js +5415 -0
- package/dist/chunk-OGUFUZSY.js.map +1 -0
- package/dist/{chunk-VB737IVN.js → chunk-P4D6BQ4X.js} +328 -706
- package/dist/chunk-P4D6BQ4X.js.map +1 -0
- package/dist/{chunk-CACKC6XG.js → chunk-PGEDE6IM.js} +136 -89
- package/dist/chunk-PGEDE6IM.js.map +1 -0
- package/dist/{chunk-A4IBBWGO.js → chunk-RALHHPTU.js} +1 -1
- package/dist/chunk-RIDSPLE5.js +42 -0
- package/dist/chunk-RIDSPLE5.js.map +1 -0
- package/dist/{chunk-Z6VOBGTU.js → chunk-UOMHWUHV.js} +2 -12
- package/dist/chunk-UOMHWUHV.js.map +1 -0
- package/dist/{chunk-WGHNIAF7.js → chunk-YONQYTVH.js} +2 -2
- package/dist/chunk-ZAN22NGL.js +13 -0
- package/dist/chunk-ZAN22NGL.js.map +1 -0
- package/dist/config/index.d.ts +200 -0
- package/dist/config/index.js +23 -0
- package/dist/config/index.js.map +1 -0
- package/dist/connector/index.d.ts +23 -5
- package/dist/connector/index.js +4 -2
- package/dist/core/index.d.ts +2 -2
- package/dist/core/index.js +1 -0
- package/dist/error/index.js +1 -0
- package/dist/generator/index.js +2 -0
- package/dist/generator/index.js.map +1 -1
- package/dist/index.d.ts +19 -16
- package/dist/index.js +88 -46
- package/dist/index.native.d.ts +18 -14
- package/dist/index.native.js +93 -44
- package/dist/index.web.d.ts +17 -14
- package/dist/index.web.js +88 -46
- package/dist/maintenance/index.d.ts +2 -2
- package/dist/maintenance/index.js +3 -2
- package/dist/platform/index.d.ts +1 -1
- package/dist/platform/index.js +2 -0
- package/dist/platform/index.js.map +1 -1
- package/dist/platform/index.native.d.ts +1 -1
- package/dist/platform/index.native.js +1 -0
- package/dist/platform/index.web.d.ts +1 -1
- package/dist/platform/index.web.js +1 -0
- package/dist/pol-attachment-queue-DqBvLAEY.d.ts +255 -0
- package/dist/provider/index.d.ts +319 -124
- package/dist/provider/index.js +21 -16
- package/dist/provider/index.native.d.ts +108 -0
- package/dist/provider/index.native.js +121 -0
- package/dist/provider/index.native.js.map +1 -0
- package/dist/provider/index.web.d.ts +16 -0
- package/dist/provider/index.web.js +112 -0
- package/dist/provider/index.web.js.map +1 -0
- package/dist/react/index.d.ts +16 -65
- package/dist/react/index.js +2 -9
- package/dist/storage/index.d.ts +5 -4
- package/dist/storage/index.js +12 -9
- package/dist/storage/index.native.d.ts +5 -4
- package/dist/storage/index.native.js +8 -5
- package/dist/storage/index.web.d.ts +5 -4
- package/dist/storage/index.web.js +11 -8
- package/dist/storage/upload/index.d.ts +4 -3
- package/dist/storage/upload/index.js +4 -2
- package/dist/storage/upload/index.native.d.ts +4 -3
- package/dist/storage/upload/index.native.js +4 -2
- package/dist/storage/upload/index.web.d.ts +2 -1
- package/dist/storage/upload/index.web.js +4 -2
- package/dist/{supabase-connector-D2oIl2t8.d.ts → supabase-connector-HMxBA9Kg.d.ts} +23 -25
- package/dist/sync/index.d.ts +183 -11
- package/dist/sync/index.js +13 -3
- package/dist/{types-CyvBaAl8.d.ts → types-6QHGELuY.d.ts} +4 -1
- package/dist/{types-CDqWh56B.d.ts → types-B9MptP7E.d.ts} +13 -1
- package/dist/types-BhAEsJj-.d.ts +330 -0
- package/dist/{types-D0WcHrq6.d.ts → types-CGMibJKD.d.ts} +8 -0
- package/dist/{types-DiBvmGEi.d.ts → types-DqJnP50o.d.ts} +22 -24
- package/dist/{pol-attachment-queue-BE2HU3Us.d.ts → types-JCEhw2Lf.d.ts} +139 -346
- package/package.json +18 -4
- package/dist/chunk-24RDMMCL.js +0 -44
- package/dist/chunk-24RDMMCL.js.map +0 -1
- package/dist/chunk-55DKCJV4.js.map +0 -1
- package/dist/chunk-654ERHA7.js +0 -1
- package/dist/chunk-BGBQYQV3.js.map +0 -1
- package/dist/chunk-C5ODS3XH.js.map +0 -1
- package/dist/chunk-CAB26E6F.js.map +0 -1
- package/dist/chunk-CACKC6XG.js.map +0 -1
- package/dist/chunk-P4HZA6ZT.js.map +0 -1
- package/dist/chunk-TIFL2KWE.js +0 -358
- package/dist/chunk-TIFL2KWE.js.map +0 -1
- package/dist/chunk-VB737IVN.js.map +0 -1
- package/dist/chunk-XAEII4ZX.js.map +0 -1
- package/dist/chunk-YSTEESEG.js.map +0 -1
- package/dist/chunk-Z6VOBGTU.js.map +0 -1
- /package/dist/{chunk-XOY2CJ67.js.map → chunk-4F5B5CZ7.js.map} +0 -0
- /package/dist/{chunk-654ERHA7.js.map → chunk-5WRI5ZAA.js.map} +0 -0
- /package/dist/{chunk-A4IBBWGO.js.map → chunk-RALHHPTU.js.map} +0 -0
- /package/dist/{chunk-WGHNIAF7.js.map → chunk-YONQYTVH.js.map} +0 -0
|
@@ -1,10 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
withExponentialBackoff
|
|
3
|
-
} from "./chunk-FV2HXEIY.js";
|
|
4
1
|
import {
|
|
5
2
|
classifySupabaseError,
|
|
6
|
-
extractHttpStatusCode
|
|
7
|
-
isRlsError
|
|
3
|
+
extractHttpStatusCode
|
|
8
4
|
} from "./chunk-I2AYMY5O.js";
|
|
9
5
|
|
|
10
6
|
// src/connector/types.ts
|
|
@@ -13,31 +9,20 @@ var DEFAULT_RETRY_CONFIG = {
|
|
|
13
9
|
transient: {
|
|
14
10
|
maxRetries: 3,
|
|
15
11
|
baseDelayMs: 1e3,
|
|
16
|
-
// 1 second initial delay
|
|
17
12
|
maxDelayMs: 4e3,
|
|
18
|
-
// 4 second cap
|
|
19
13
|
backoffMultiplier: 2
|
|
20
|
-
// 1s → 2s → 4s
|
|
21
14
|
},
|
|
22
15
|
permanent: {
|
|
23
16
|
maxRetries: 0,
|
|
24
|
-
// No retries - permanent errors won't succeed
|
|
25
17
|
baseDelayMs: 1e3,
|
|
26
|
-
// Irrelevant with 0 retries, but needed for type
|
|
27
18
|
maxDelayMs: 1e3,
|
|
28
|
-
// Irrelevant with 0 retries
|
|
29
19
|
backoffMultiplier: 1
|
|
30
|
-
// Irrelevant with 0 retries
|
|
31
20
|
},
|
|
32
21
|
rls: {
|
|
33
|
-
maxRetries:
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
maxDelayMs: 12e4,
|
|
38
|
-
// 2 minutes max delay
|
|
39
|
-
backoffMultiplier: 2
|
|
40
|
-
// 30s → 60s → 120s → 120s → 120s
|
|
22
|
+
maxRetries: 0,
|
|
23
|
+
baseDelayMs: 1e3,
|
|
24
|
+
maxDelayMs: 1e3,
|
|
25
|
+
backoffMultiplier: 1
|
|
41
26
|
}
|
|
42
27
|
};
|
|
43
28
|
|
|
@@ -64,6 +49,18 @@ function discardOrphaned() {
|
|
|
64
49
|
return "continue";
|
|
65
50
|
};
|
|
66
51
|
}
|
|
52
|
+
function discardOnRlsDenied() {
|
|
53
|
+
return ({
|
|
54
|
+
entry,
|
|
55
|
+
pgCode
|
|
56
|
+
}) => {
|
|
57
|
+
if (pgCode === "42501") {
|
|
58
|
+
console.warn(`[PowerSync] Discarding entry for table "${entry.table}" (id: ${entry.id}): RLS policy denied the operation (PostgreSQL error 42501). This entry will not be retried.`);
|
|
59
|
+
return "discard";
|
|
60
|
+
}
|
|
61
|
+
return "continue";
|
|
62
|
+
};
|
|
63
|
+
}
|
|
67
64
|
function discardOnPgCodes(codes) {
|
|
68
65
|
const codeSet = new Set(codes);
|
|
69
66
|
return ({
|
|
@@ -377,8 +374,6 @@ var SupabaseConnector = class _SupabaseConnector {
|
|
|
377
374
|
versionColumnPromises = /* @__PURE__ */ new Map();
|
|
378
375
|
// Flag to track if connector has been destroyed
|
|
379
376
|
isDestroyed = false;
|
|
380
|
-
// Retry configuration
|
|
381
|
-
retryConfig;
|
|
382
377
|
// Track completion failures for circuit breaker logic
|
|
383
378
|
// Maps transaction fingerprint (hash of entry IDs) to failure tracking info
|
|
384
379
|
completionFailures = /* @__PURE__ */ new Map();
|
|
@@ -386,13 +381,6 @@ var SupabaseConnector = class _SupabaseConnector {
|
|
|
386
381
|
static COMPLETION_EXTENDED_TIMEOUT_MS = 6e4;
|
|
387
382
|
// 60s timeout for retry
|
|
388
383
|
static MAX_STORED_RESOLUTIONS = 100;
|
|
389
|
-
autoRetryPaused = false;
|
|
390
|
-
// Per-entry cooldown tracking for failed operations
|
|
391
|
-
// Maps entry key (table:id) to the timestamp when it can be retried
|
|
392
|
-
entryCooldowns = /* @__PURE__ */ new Map();
|
|
393
|
-
static COOLDOWN_DURATION_MS = 6e4;
|
|
394
|
-
// 1 minute cooldown after exhausting retries
|
|
395
|
-
static MAX_ENTRY_COOLDOWNS = 200;
|
|
396
384
|
// Upload error middleware chain
|
|
397
385
|
uploadErrorMiddleware;
|
|
398
386
|
constructor(options) {
|
|
@@ -408,20 +396,6 @@ var SupabaseConnector = class _SupabaseConnector {
|
|
|
408
396
|
this.conflictDetection = options.conflictDetection;
|
|
409
397
|
this.conflictHandler = options.conflictHandler;
|
|
410
398
|
this.conflictBus = options.conflictBus;
|
|
411
|
-
this.retryConfig = {
|
|
412
|
-
transient: {
|
|
413
|
-
...DEFAULT_RETRY_CONFIG.transient,
|
|
414
|
-
...options.retryConfig?.transient
|
|
415
|
-
},
|
|
416
|
-
permanent: {
|
|
417
|
-
...DEFAULT_RETRY_CONFIG.permanent,
|
|
418
|
-
...options.retryConfig?.permanent
|
|
419
|
-
},
|
|
420
|
-
rls: {
|
|
421
|
-
...DEFAULT_RETRY_CONFIG.rls,
|
|
422
|
-
...options.retryConfig?.rls
|
|
423
|
-
}
|
|
424
|
-
};
|
|
425
399
|
this.uploadErrorMiddleware = options.uploadErrorMiddleware ?? [];
|
|
426
400
|
if (this.conflictBus) {
|
|
427
401
|
this.unsubscribeResolution = this.conflictBus.onResolution((table, recordId, resolution) => {
|
|
@@ -464,80 +438,46 @@ var SupabaseConnector = class _SupabaseConnector {
|
|
|
464
438
|
const sortedIds = entries.map((e) => `${e.table}:${e.id}`).sort();
|
|
465
439
|
return sortedIds.join("|");
|
|
466
440
|
}
|
|
467
|
-
// ───
|
|
441
|
+
// ─── Simplified Entry Processing ───────────────────────────────────────────
|
|
442
|
+
//
|
|
443
|
+
// Architecture:
|
|
444
|
+
// - NO internal retry loops - PowerSync SDK handles all retries naturally
|
|
445
|
+
// - Middleware decides once: success/discard/retry/fail_transaction
|
|
446
|
+
// - 'retry' = transient error, throw to let PowerSync retry on next sync cycle
|
|
447
|
+
// - 'fail_transaction' = permanent error, throw immediately with failure callback
|
|
448
|
+
// - 'discard' = silently skip via DiscardEntryError
|
|
449
|
+
// - 'success' = treat as completed, return normally
|
|
450
|
+
//
|
|
451
|
+
// This keeps error handling simple and lets the user configure middleware
|
|
452
|
+
// to decide what to do with each error type.
|
|
468
453
|
/**
|
|
469
|
-
*
|
|
470
|
-
* Use this when the user goes offline intentionally or wants manual control.
|
|
471
|
-
*/
|
|
472
|
-
pauseAutoRetry() {
|
|
473
|
-
this.autoRetryPaused = true;
|
|
474
|
-
if (__DEV__) {
|
|
475
|
-
console.log("[Connector] Auto-retry paused");
|
|
476
|
-
}
|
|
477
|
-
}
|
|
478
|
-
/**
|
|
479
|
-
* Resume automatic retry of failed uploads.
|
|
480
|
-
*/
|
|
481
|
-
resumeAutoRetry() {
|
|
482
|
-
this.autoRetryPaused = false;
|
|
483
|
-
if (__DEV__) {
|
|
484
|
-
console.log("[Connector] Auto-retry resumed");
|
|
485
|
-
}
|
|
486
|
-
}
|
|
487
|
-
// ─── Private Retry Logic ───────────────────────────────────────────────────
|
|
488
|
-
/**
|
|
489
|
-
* Process a single CRUD entry with exponential backoff retry.
|
|
490
|
-
*
|
|
491
|
-
* This method uses a two-phase approach:
|
|
492
|
-
* 1. First attempt - try the operation to classify the error type
|
|
493
|
-
* 2. Retry phase - use the appropriate config (transient vs permanent) based on classification
|
|
454
|
+
* Process a single CRUD entry once (no internal retries).
|
|
494
455
|
*
|
|
495
|
-
*
|
|
496
|
-
*
|
|
456
|
+
* On failure, middleware classifies the error:
|
|
457
|
+
* - 'success': Treat as completed (e.g., idempotent duplicate)
|
|
458
|
+
* - 'discard': Remove from queue silently
|
|
459
|
+
* - 'retry': Throw to let PowerSync retry on next sync cycle
|
|
460
|
+
* - 'fail_transaction': Throw TransactionAbortError immediately
|
|
461
|
+
* - 'continue': Throw original error (PowerSync will retry)
|
|
497
462
|
*
|
|
498
463
|
* @param entry - The CRUD entry to process
|
|
499
|
-
* @throws Error
|
|
464
|
+
* @throws Error for all errors (PowerSync will retry)
|
|
465
|
+
* @throws TransactionAbortError when middleware returns 'fail_transaction'
|
|
466
|
+
* @throws DiscardEntryError for discarded entries
|
|
500
467
|
*/
|
|
501
|
-
async
|
|
468
|
+
async processEntryOnce(entry) {
|
|
502
469
|
if (this.isDestroyed) {
|
|
503
470
|
throw new Error("Connector destroyed");
|
|
504
471
|
}
|
|
505
|
-
const entryKey = `${entry.table}:${entry.id}`;
|
|
506
|
-
const cooldownUntil = this.entryCooldowns.get(entryKey);
|
|
507
|
-
if (cooldownUntil) {
|
|
508
|
-
if (Date.now() >= cooldownUntil) {
|
|
509
|
-
this.entryCooldowns.delete(entryKey);
|
|
510
|
-
} else {
|
|
511
|
-
const remainingMs = cooldownUntil - Date.now();
|
|
512
|
-
if (__DEV__) {
|
|
513
|
-
console.log("[Connector] Entry in cooldown, skipping:", {
|
|
514
|
-
table: entry.table,
|
|
515
|
-
id: entry.id,
|
|
516
|
-
remainingSec: Math.round(remainingMs / 1e3)
|
|
517
|
-
});
|
|
518
|
-
}
|
|
519
|
-
throw new Error(`Entry in cooldown for ${Math.round(remainingMs / 1e3)}s`);
|
|
520
|
-
}
|
|
521
|
-
}
|
|
522
|
-
const classified = {
|
|
523
|
-
isPermanent: false,
|
|
524
|
-
pgCode: void 0,
|
|
525
|
-
userMessage: ""
|
|
526
|
-
};
|
|
527
|
-
let lastError;
|
|
528
472
|
try {
|
|
529
473
|
await this.processCrudEntry(entry);
|
|
530
|
-
this.entryCooldowns.delete(entryKey);
|
|
531
474
|
return;
|
|
532
475
|
} catch (error) {
|
|
533
|
-
lastError = error instanceof Error ? error : new Error(String(error));
|
|
534
476
|
const classifiedError = classifySupabaseError(error);
|
|
535
|
-
|
|
536
|
-
classified.pgCode = classifiedError.pgCode;
|
|
537
|
-
classified.userMessage = classifiedError.userMessage;
|
|
477
|
+
const errorObj = error instanceof Error ? error : new Error(String(error));
|
|
538
478
|
if (isAuthError(error)) {
|
|
539
479
|
if (__DEV__) {
|
|
540
|
-
console.log("[Connector] Auth error detected, refreshing session
|
|
480
|
+
console.log("[Connector] Auth error detected, refreshing session:", {
|
|
541
481
|
table: entry.table,
|
|
542
482
|
op: entry.op,
|
|
543
483
|
id: entry.id
|
|
@@ -546,164 +486,99 @@ var SupabaseConnector = class _SupabaseConnector {
|
|
|
546
486
|
try {
|
|
547
487
|
await this.supabase.auth.refreshSession();
|
|
548
488
|
await this.processCrudEntry(entry);
|
|
549
|
-
this.entryCooldowns.delete(entryKey);
|
|
550
489
|
return;
|
|
551
490
|
} catch (retryError) {
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
classified.isPermanent = retriedClassification.isPermanent;
|
|
555
|
-
classified.pgCode = retriedClassification.pgCode;
|
|
556
|
-
classified.userMessage = retriedClassification.userMessage;
|
|
557
|
-
}
|
|
558
|
-
}
|
|
559
|
-
if (__DEV__) {
|
|
560
|
-
console.log("[Connector] Initial attempt failed, will retry with appropriate config:", {
|
|
561
|
-
table: entry.table,
|
|
562
|
-
op: entry.op,
|
|
563
|
-
id: entry.id,
|
|
564
|
-
isPermanent: classified.isPermanent,
|
|
565
|
-
pgCode: classified.pgCode,
|
|
566
|
-
userMessage: classified.userMessage
|
|
567
|
-
});
|
|
568
|
-
}
|
|
569
|
-
this.logger?.warn("[Connector] Initial attempt failed:", {
|
|
570
|
-
table: entry.table,
|
|
571
|
-
op: entry.op,
|
|
572
|
-
id: entry.id,
|
|
573
|
-
error: lastError.message,
|
|
574
|
-
isPermanent: classified.isPermanent
|
|
575
|
-
});
|
|
576
|
-
if (this.uploadErrorMiddleware.length > 0) {
|
|
577
|
-
const classifiedError2 = classifySupabaseError(error);
|
|
578
|
-
const schema = this.schemaRouter(entry.table);
|
|
579
|
-
const middlewareContext = {
|
|
580
|
-
entry,
|
|
581
|
-
error: lastError,
|
|
582
|
-
pgCode: classified.pgCode,
|
|
583
|
-
httpStatusCode: extractHttpStatusCode(error),
|
|
584
|
-
classified: classifiedError2,
|
|
585
|
-
originalError: error,
|
|
586
|
-
schema,
|
|
587
|
-
supabase: this.supabase
|
|
588
|
-
};
|
|
589
|
-
const middlewareResult = await runUploadErrorMiddleware(
|
|
590
|
-
middlewareContext,
|
|
591
|
-
this.uploadErrorMiddleware,
|
|
592
|
-
"continue"
|
|
593
|
-
// Default to continue if no middleware matches
|
|
594
|
-
);
|
|
595
|
-
if (__DEV__) {
|
|
596
|
-
console.log("[Connector] Upload error middleware result:", {
|
|
597
|
-
table: entry.table,
|
|
598
|
-
id: entry.id,
|
|
599
|
-
result: middlewareResult
|
|
600
|
-
});
|
|
601
|
-
}
|
|
602
|
-
switch (middlewareResult) {
|
|
603
|
-
case "success":
|
|
604
|
-
this.entryCooldowns.delete(entryKey);
|
|
605
|
-
this.logger?.info("[Connector] Entry treated as success by middleware:", {
|
|
606
|
-
table: entry.table,
|
|
607
|
-
id: entry.id,
|
|
608
|
-
pgCode: classified.pgCode
|
|
609
|
-
});
|
|
610
|
-
return;
|
|
611
|
-
case "discard":
|
|
612
|
-
this.entryCooldowns.delete(entryKey);
|
|
613
|
-
this.logger?.warn("[Connector] Entry discarded by middleware:", {
|
|
614
|
-
table: entry.table,
|
|
615
|
-
id: entry.id,
|
|
616
|
-
pgCode: classified.pgCode,
|
|
617
|
-
error: lastError.message
|
|
618
|
-
});
|
|
619
|
-
throw new DiscardEntryError(`Entry discarded by middleware: ${entry.table}:${entry.id} (${classified.pgCode || "unknown"})`);
|
|
620
|
-
case "retry":
|
|
621
|
-
break;
|
|
622
|
-
case "continue":
|
|
623
|
-
break;
|
|
624
|
-
case "fail_transaction":
|
|
625
|
-
this.logger?.error("[Connector] Transaction aborted by middleware:", {
|
|
626
|
-
table: entry.table,
|
|
627
|
-
id: entry.id,
|
|
628
|
-
pgCode: classified.pgCode,
|
|
629
|
-
error: lastError.message
|
|
630
|
-
});
|
|
631
|
-
throw new TransactionAbortError(`Transaction aborted by middleware: ${entry.table}:${entry.id}`, lastError);
|
|
491
|
+
const retryClassified = classifySupabaseError(retryError);
|
|
492
|
+
return this.handleEntryError(entry, retryError instanceof Error ? retryError : new Error(String(retryError)), retryClassified, retryError);
|
|
632
493
|
}
|
|
633
494
|
}
|
|
495
|
+
return this.handleEntryError(entry, errorObj, classifiedError, error);
|
|
634
496
|
}
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
497
|
+
}
|
|
498
|
+
/**
|
|
499
|
+
* Handle an entry error by running middleware and deciding what to do.
|
|
500
|
+
*/
|
|
501
|
+
async handleEntryError(entry, error, classified, originalError) {
|
|
502
|
+
if (__DEV__) {
|
|
503
|
+
console.log("[Connector] Entry failed:", {
|
|
639
504
|
table: entry.table,
|
|
640
505
|
op: entry.op,
|
|
641
506
|
id: entry.id,
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
507
|
+
isPermanent: classified.isPermanent,
|
|
508
|
+
pgCode: classified.pgCode,
|
|
509
|
+
message: error.message
|
|
645
510
|
});
|
|
646
511
|
}
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
errorMessage: error.message
|
|
669
|
-
});
|
|
670
|
-
}
|
|
671
|
-
}
|
|
672
|
-
});
|
|
673
|
-
this.entryCooldowns.delete(entryKey);
|
|
674
|
-
} catch (error) {
|
|
675
|
-
const finalError = error instanceof Error ? error : new Error(String(error));
|
|
676
|
-
const category = classified.isPermanent ? "permanent" : classified.pgCode ? "transient" : "unknown";
|
|
512
|
+
this.logger?.warn("[Connector] Entry failed:", {
|
|
513
|
+
table: entry.table,
|
|
514
|
+
op: entry.op,
|
|
515
|
+
id: entry.id,
|
|
516
|
+
error: error.message,
|
|
517
|
+
isPermanent: classified.isPermanent
|
|
518
|
+
});
|
|
519
|
+
let middlewareResult = "continue";
|
|
520
|
+
if (this.uploadErrorMiddleware.length > 0) {
|
|
521
|
+
const schema = this.schemaRouter(entry.table);
|
|
522
|
+
const middlewareContext = {
|
|
523
|
+
entry,
|
|
524
|
+
error,
|
|
525
|
+
pgCode: classified.pgCode,
|
|
526
|
+
httpStatusCode: extractHttpStatusCode(originalError),
|
|
527
|
+
classified,
|
|
528
|
+
originalError,
|
|
529
|
+
schema,
|
|
530
|
+
supabase: this.supabase
|
|
531
|
+
};
|
|
532
|
+
middlewareResult = await runUploadErrorMiddleware(middlewareContext, this.uploadErrorMiddleware, "continue");
|
|
677
533
|
if (__DEV__) {
|
|
678
|
-
console.log("[Connector]
|
|
534
|
+
console.log("[Connector] Middleware result:", {
|
|
679
535
|
table: entry.table,
|
|
680
|
-
op: entry.op,
|
|
681
536
|
id: entry.id,
|
|
682
|
-
|
|
683
|
-
error: finalError.message
|
|
537
|
+
result: middlewareResult
|
|
684
538
|
});
|
|
685
539
|
}
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
error: finalError.message,
|
|
691
|
-
category
|
|
692
|
-
});
|
|
693
|
-
const cooldownMs = _SupabaseConnector.COOLDOWN_DURATION_MS;
|
|
694
|
-
if (this.entryCooldowns.size >= _SupabaseConnector.MAX_ENTRY_COOLDOWNS) {
|
|
695
|
-
const firstKey = this.entryCooldowns.keys().next().value;
|
|
696
|
-
if (firstKey) this.entryCooldowns.delete(firstKey);
|
|
697
|
-
}
|
|
698
|
-
this.entryCooldowns.set(entryKey, Date.now() + cooldownMs);
|
|
699
|
-
if (__DEV__) {
|
|
700
|
-
console.log("[Connector] Entry placed in cooldown:", {
|
|
540
|
+
}
|
|
541
|
+
switch (middlewareResult) {
|
|
542
|
+
case "success":
|
|
543
|
+
this.logger?.info("[Connector] Entry treated as success by middleware:", {
|
|
701
544
|
table: entry.table,
|
|
702
545
|
id: entry.id,
|
|
703
|
-
|
|
546
|
+
pgCode: classified.pgCode
|
|
704
547
|
});
|
|
705
|
-
|
|
706
|
-
|
|
548
|
+
return;
|
|
549
|
+
case "discard":
|
|
550
|
+
this.logger?.warn("[Connector] Entry discarded by middleware:", {
|
|
551
|
+
table: entry.table,
|
|
552
|
+
id: entry.id,
|
|
553
|
+
pgCode: classified.pgCode
|
|
554
|
+
});
|
|
555
|
+
throw new DiscardEntryError(`Entry discarded by middleware: ${entry.table}:${entry.id} (${classified.pgCode || "unknown"})`);
|
|
556
|
+
case "fail_transaction":
|
|
557
|
+
this.logger?.error("[Connector] Transaction aborted by middleware:", {
|
|
558
|
+
table: entry.table,
|
|
559
|
+
id: entry.id,
|
|
560
|
+
pgCode: classified.pgCode
|
|
561
|
+
});
|
|
562
|
+
throw new TransactionAbortError(`Transaction aborted by middleware: ${entry.table}:${entry.id}`, error);
|
|
563
|
+
case "retry":
|
|
564
|
+
if (__DEV__) {
|
|
565
|
+
console.log("[Connector] Middleware returned retry - throwing for PowerSync retry:", {
|
|
566
|
+
table: entry.table,
|
|
567
|
+
id: entry.id
|
|
568
|
+
});
|
|
569
|
+
}
|
|
570
|
+
throw error;
|
|
571
|
+
case "continue":
|
|
572
|
+
default:
|
|
573
|
+
if (__DEV__) {
|
|
574
|
+
console.log("[Connector] Error - throwing for PowerSync retry:", {
|
|
575
|
+
table: entry.table,
|
|
576
|
+
id: entry.id,
|
|
577
|
+
isPermanent: classified.isPermanent,
|
|
578
|
+
pgCode: classified.pgCode
|
|
579
|
+
});
|
|
580
|
+
}
|
|
581
|
+
throw error;
|
|
707
582
|
}
|
|
708
583
|
}
|
|
709
584
|
/**
|
|
@@ -951,17 +826,23 @@ var SupabaseConnector = class _SupabaseConnector {
|
|
|
951
826
|
return;
|
|
952
827
|
}
|
|
953
828
|
const successfulEntries = [];
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
829
|
+
try {
|
|
830
|
+
for (const entry of entriesToProcess) {
|
|
831
|
+
if (__DEV__) {
|
|
832
|
+
console.log("[Connector] Processing CRUD entry:", {
|
|
833
|
+
table: entry.table,
|
|
834
|
+
op: entry.op,
|
|
835
|
+
id: entry.id,
|
|
836
|
+
opData: entry.opData
|
|
837
|
+
});
|
|
838
|
+
}
|
|
839
|
+
await this.processEntryOnce(entry);
|
|
840
|
+
successfulEntries.push(entry);
|
|
962
841
|
}
|
|
963
|
-
|
|
964
|
-
|
|
842
|
+
} catch (error) {
|
|
843
|
+
const classified = classifySupabaseError(error);
|
|
844
|
+
this.onTransactionFailure?.(entriesToProcess, error instanceof Error ? error : new Error(String(error)), classified);
|
|
845
|
+
throw error;
|
|
965
846
|
}
|
|
966
847
|
await this.finalizeTransaction({
|
|
967
848
|
transaction,
|
|
@@ -1147,50 +1028,56 @@ var SupabaseConnector = class _SupabaseConnector {
|
|
|
1147
1028
|
}]))
|
|
1148
1029
|
});
|
|
1149
1030
|
}
|
|
1150
|
-
|
|
1151
|
-
const
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1031
|
+
try {
|
|
1032
|
+
for (const [table, entries] of entriesByTable) {
|
|
1033
|
+
const schema = this.schemaRouter(table);
|
|
1034
|
+
const putEntries = entries.filter((e) => e.op === "PUT" /* PUT */);
|
|
1035
|
+
const patchEntries = entries.filter((e) => e.op === "PATCH" /* PATCH */);
|
|
1036
|
+
const deleteEntries = entries.filter((e) => e.op === "DELETE" /* DELETE */);
|
|
1037
|
+
if (this.crudHandler) {
|
|
1038
|
+
for (const entry of entries) {
|
|
1039
|
+
try {
|
|
1040
|
+
await this.processEntryOnce(entry);
|
|
1041
|
+
successfulEntries.push(entry);
|
|
1042
|
+
} catch (error) {
|
|
1043
|
+
if (error instanceof DiscardEntryError) {
|
|
1044
|
+
discardedEntries.push(entry);
|
|
1045
|
+
continue;
|
|
1046
|
+
}
|
|
1047
|
+
throw error;
|
|
1164
1048
|
}
|
|
1165
|
-
throw error;
|
|
1166
1049
|
}
|
|
1050
|
+
continue;
|
|
1051
|
+
}
|
|
1052
|
+
if (putEntries.length > 0) {
|
|
1053
|
+
const {
|
|
1054
|
+
successful,
|
|
1055
|
+
discarded
|
|
1056
|
+
} = await this.processBatchedPuts(table, schema, putEntries);
|
|
1057
|
+
successfulEntries.push(...successful);
|
|
1058
|
+
discardedEntries.push(...discarded);
|
|
1059
|
+
}
|
|
1060
|
+
if (deleteEntries.length > 0) {
|
|
1061
|
+
const {
|
|
1062
|
+
successful,
|
|
1063
|
+
discarded
|
|
1064
|
+
} = await this.processBatchedDeletes(table, schema, deleteEntries);
|
|
1065
|
+
successfulEntries.push(...successful);
|
|
1066
|
+
discardedEntries.push(...discarded);
|
|
1067
|
+
}
|
|
1068
|
+
if (patchEntries.length > 0) {
|
|
1069
|
+
const {
|
|
1070
|
+
successful,
|
|
1071
|
+
discarded
|
|
1072
|
+
} = await this.processBatchedPatches(table, schema, patchEntries);
|
|
1073
|
+
successfulEntries.push(...successful);
|
|
1074
|
+
discardedEntries.push(...discarded);
|
|
1167
1075
|
}
|
|
1168
|
-
continue;
|
|
1169
|
-
}
|
|
1170
|
-
if (putEntries.length > 0) {
|
|
1171
|
-
const {
|
|
1172
|
-
successful,
|
|
1173
|
-
discarded
|
|
1174
|
-
} = await this.processBatchedPuts(table, schema, putEntries);
|
|
1175
|
-
successfulEntries.push(...successful);
|
|
1176
|
-
discardedEntries.push(...discarded);
|
|
1177
|
-
}
|
|
1178
|
-
if (deleteEntries.length > 0) {
|
|
1179
|
-
const {
|
|
1180
|
-
successful,
|
|
1181
|
-
discarded
|
|
1182
|
-
} = await this.processBatchedDeletes(table, schema, deleteEntries);
|
|
1183
|
-
successfulEntries.push(...successful);
|
|
1184
|
-
discardedEntries.push(...discarded);
|
|
1185
|
-
}
|
|
1186
|
-
if (patchEntries.length > 0) {
|
|
1187
|
-
const {
|
|
1188
|
-
successful,
|
|
1189
|
-
discarded
|
|
1190
|
-
} = await this.processBatchedPatches(table, schema, patchEntries);
|
|
1191
|
-
successfulEntries.push(...successful);
|
|
1192
|
-
discardedEntries.push(...discarded);
|
|
1193
1076
|
}
|
|
1077
|
+
} catch (error) {
|
|
1078
|
+
const classified = classifySupabaseError(error);
|
|
1079
|
+
this.onTransactionFailure?.(transaction.crud, error instanceof Error ? error : new Error(String(error)), classified);
|
|
1080
|
+
throw error;
|
|
1194
1081
|
}
|
|
1195
1082
|
await this.finalizeTransaction({
|
|
1196
1083
|
transaction,
|
|
@@ -1235,7 +1122,7 @@ var SupabaseConnector = class _SupabaseConnector {
|
|
|
1235
1122
|
}
|
|
1236
1123
|
for (const entry of entries) {
|
|
1237
1124
|
try {
|
|
1238
|
-
await this.
|
|
1125
|
+
await this.processEntryOnce(entry);
|
|
1239
1126
|
successful.push(entry);
|
|
1240
1127
|
} catch (e) {
|
|
1241
1128
|
if (e instanceof DiscardEntryError) {
|
|
@@ -1292,7 +1179,7 @@ var SupabaseConnector = class _SupabaseConnector {
|
|
|
1292
1179
|
}
|
|
1293
1180
|
for (const entry of entries) {
|
|
1294
1181
|
try {
|
|
1295
|
-
await this.
|
|
1182
|
+
await this.processEntryOnce(entry);
|
|
1296
1183
|
successful.push(entry);
|
|
1297
1184
|
} catch (e) {
|
|
1298
1185
|
if (e instanceof DiscardEntryError) {
|
|
@@ -1347,7 +1234,7 @@ var SupabaseConnector = class _SupabaseConnector {
|
|
|
1347
1234
|
}
|
|
1348
1235
|
const results = await Promise.all(batch.map(async (entry) => {
|
|
1349
1236
|
try {
|
|
1350
|
-
await this.
|
|
1237
|
+
await this.processEntryOnce(entry);
|
|
1351
1238
|
return {
|
|
1352
1239
|
status: "success",
|
|
1353
1240
|
entry
|
|
@@ -1497,7 +1384,9 @@ var SupabaseConnector = class _SupabaseConnector {
|
|
|
1497
1384
|
errorHint: upsertError.hint
|
|
1498
1385
|
});
|
|
1499
1386
|
}
|
|
1500
|
-
|
|
1387
|
+
const upsertErr = new Error(`Upsert failed for ${schema}.${table}: ${upsertError.message}`);
|
|
1388
|
+
upsertErr.code = upsertError.code;
|
|
1389
|
+
throw upsertErr;
|
|
1501
1390
|
}
|
|
1502
1391
|
if (__DEV__) {
|
|
1503
1392
|
console.log("[Connector] PUT/UPSERT SUCCESS:", {
|
|
@@ -1534,7 +1423,9 @@ var SupabaseConnector = class _SupabaseConnector {
|
|
|
1534
1423
|
errorHint: updateError.hint
|
|
1535
1424
|
});
|
|
1536
1425
|
}
|
|
1537
|
-
|
|
1426
|
+
const updateErr = new Error(`Update failed for ${schema}.${table}: ${updateError.message}`);
|
|
1427
|
+
updateErr.code = updateError.code;
|
|
1428
|
+
throw updateErr;
|
|
1538
1429
|
}
|
|
1539
1430
|
if (__DEV__) {
|
|
1540
1431
|
console.log("[Connector] PATCH/UPDATE SUCCESS:", {
|
|
@@ -1570,7 +1461,9 @@ var SupabaseConnector = class _SupabaseConnector {
|
|
|
1570
1461
|
errorHint: deleteError.hint
|
|
1571
1462
|
});
|
|
1572
1463
|
}
|
|
1573
|
-
|
|
1464
|
+
const deleteErr = new Error(`Delete failed for ${schema}.${table}: ${deleteError.message}`);
|
|
1465
|
+
deleteErr.code = deleteError.code;
|
|
1466
|
+
throw deleteErr;
|
|
1574
1467
|
}
|
|
1575
1468
|
if (__DEV__) {
|
|
1576
1469
|
console.log("[Connector] DELETE SUCCESS:", {
|
|
@@ -1591,6 +1484,7 @@ export {
|
|
|
1591
1484
|
DEFAULT_RETRY_CONFIG,
|
|
1592
1485
|
idempotentTables,
|
|
1593
1486
|
discardOrphaned,
|
|
1487
|
+
discardOnRlsDenied,
|
|
1594
1488
|
discardOnPgCodes,
|
|
1595
1489
|
successOnPgCodes,
|
|
1596
1490
|
retryOnHttpStatus,
|
|
@@ -1607,4 +1501,4 @@ export {
|
|
|
1607
1501
|
getLocalVersion,
|
|
1608
1502
|
SupabaseConnector
|
|
1609
1503
|
};
|
|
1610
|
-
//# sourceMappingURL=chunk-
|
|
1504
|
+
//# sourceMappingURL=chunk-65A3SYJZ.js.map
|