@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.
Files changed (118) hide show
  1. package/README.md +0 -1
  2. package/dist/{CacheSettingsManager-uz-kbnRH.d.ts → CacheSettingsManager-0H_7thHW.d.ts} +21 -3
  3. package/dist/attachments/index.d.ts +30 -30
  4. package/dist/attachments/index.js +13 -4
  5. package/dist/{background-sync-ChCXW-EV.d.ts → background-sync-BujnI3IR.d.ts} +1 -1
  6. package/dist/{chunk-55DKCJV4.js → chunk-2RDWLXJW.js} +408 -78
  7. package/dist/chunk-2RDWLXJW.js.map +1 -0
  8. package/dist/{chunk-P4HZA6ZT.js → chunk-4665ZSE5.js} +2 -2
  9. package/dist/chunk-4665ZSE5.js.map +1 -0
  10. package/dist/{chunk-XOY2CJ67.js → chunk-4F5B5CZ7.js} +3 -3
  11. package/dist/chunk-5WRI5ZAA.js +31 -0
  12. package/dist/{chunk-BGBQYQV3.js → chunk-65A3SYJZ.js} +193 -299
  13. package/dist/chunk-65A3SYJZ.js.map +1 -0
  14. package/dist/chunk-6SZ64KCZ.js +755 -0
  15. package/dist/chunk-6SZ64KCZ.js.map +1 -0
  16. package/dist/{chunk-YSTEESEG.js → chunk-74TBHWJ4.js} +122 -11
  17. package/dist/chunk-74TBHWJ4.js.map +1 -0
  18. package/dist/chunk-ANXWYQEJ.js +1 -0
  19. package/dist/chunk-ANXWYQEJ.js.map +1 -0
  20. package/dist/{chunk-CAB26E6F.js → chunk-C4J4MLER.js} +29 -24
  21. package/dist/chunk-C4J4MLER.js.map +1 -0
  22. package/dist/{chunk-C5ODS3XH.js → chunk-EOW7JK7Q.js} +9 -16
  23. package/dist/chunk-EOW7JK7Q.js.map +1 -0
  24. package/dist/chunk-HRAVPIAZ.js +220 -0
  25. package/dist/chunk-HRAVPIAZ.js.map +1 -0
  26. package/dist/{chunk-XAEII4ZX.js → chunk-NUGQOTEM.js} +32 -4
  27. package/dist/chunk-NUGQOTEM.js.map +1 -0
  28. package/dist/chunk-OGUFUZSY.js +5415 -0
  29. package/dist/chunk-OGUFUZSY.js.map +1 -0
  30. package/dist/{chunk-VB737IVN.js → chunk-P4D6BQ4X.js} +328 -706
  31. package/dist/chunk-P4D6BQ4X.js.map +1 -0
  32. package/dist/{chunk-CACKC6XG.js → chunk-PGEDE6IM.js} +136 -89
  33. package/dist/chunk-PGEDE6IM.js.map +1 -0
  34. package/dist/{chunk-A4IBBWGO.js → chunk-RALHHPTU.js} +1 -1
  35. package/dist/chunk-RIDSPLE5.js +42 -0
  36. package/dist/chunk-RIDSPLE5.js.map +1 -0
  37. package/dist/{chunk-Z6VOBGTU.js → chunk-UOMHWUHV.js} +2 -12
  38. package/dist/chunk-UOMHWUHV.js.map +1 -0
  39. package/dist/{chunk-WGHNIAF7.js → chunk-YONQYTVH.js} +2 -2
  40. package/dist/chunk-ZAN22NGL.js +13 -0
  41. package/dist/chunk-ZAN22NGL.js.map +1 -0
  42. package/dist/config/index.d.ts +200 -0
  43. package/dist/config/index.js +23 -0
  44. package/dist/config/index.js.map +1 -0
  45. package/dist/connector/index.d.ts +23 -5
  46. package/dist/connector/index.js +4 -2
  47. package/dist/core/index.d.ts +2 -2
  48. package/dist/core/index.js +1 -0
  49. package/dist/error/index.js +1 -0
  50. package/dist/generator/index.js +2 -0
  51. package/dist/generator/index.js.map +1 -1
  52. package/dist/index.d.ts +19 -16
  53. package/dist/index.js +88 -46
  54. package/dist/index.native.d.ts +18 -14
  55. package/dist/index.native.js +93 -44
  56. package/dist/index.web.d.ts +17 -14
  57. package/dist/index.web.js +88 -46
  58. package/dist/maintenance/index.d.ts +2 -2
  59. package/dist/maintenance/index.js +3 -2
  60. package/dist/platform/index.d.ts +1 -1
  61. package/dist/platform/index.js +2 -0
  62. package/dist/platform/index.js.map +1 -1
  63. package/dist/platform/index.native.d.ts +1 -1
  64. package/dist/platform/index.native.js +1 -0
  65. package/dist/platform/index.web.d.ts +1 -1
  66. package/dist/platform/index.web.js +1 -0
  67. package/dist/pol-attachment-queue-DqBvLAEY.d.ts +255 -0
  68. package/dist/provider/index.d.ts +319 -124
  69. package/dist/provider/index.js +21 -16
  70. package/dist/provider/index.native.d.ts +108 -0
  71. package/dist/provider/index.native.js +121 -0
  72. package/dist/provider/index.native.js.map +1 -0
  73. package/dist/provider/index.web.d.ts +16 -0
  74. package/dist/provider/index.web.js +112 -0
  75. package/dist/provider/index.web.js.map +1 -0
  76. package/dist/react/index.d.ts +16 -65
  77. package/dist/react/index.js +2 -9
  78. package/dist/storage/index.d.ts +5 -4
  79. package/dist/storage/index.js +12 -9
  80. package/dist/storage/index.native.d.ts +5 -4
  81. package/dist/storage/index.native.js +8 -5
  82. package/dist/storage/index.web.d.ts +5 -4
  83. package/dist/storage/index.web.js +11 -8
  84. package/dist/storage/upload/index.d.ts +4 -3
  85. package/dist/storage/upload/index.js +4 -2
  86. package/dist/storage/upload/index.native.d.ts +4 -3
  87. package/dist/storage/upload/index.native.js +4 -2
  88. package/dist/storage/upload/index.web.d.ts +2 -1
  89. package/dist/storage/upload/index.web.js +4 -2
  90. package/dist/{supabase-connector-D2oIl2t8.d.ts → supabase-connector-HMxBA9Kg.d.ts} +23 -25
  91. package/dist/sync/index.d.ts +183 -11
  92. package/dist/sync/index.js +13 -3
  93. package/dist/{types-CyvBaAl8.d.ts → types-6QHGELuY.d.ts} +4 -1
  94. package/dist/{types-CDqWh56B.d.ts → types-B9MptP7E.d.ts} +13 -1
  95. package/dist/types-BhAEsJj-.d.ts +330 -0
  96. package/dist/{types-D0WcHrq6.d.ts → types-CGMibJKD.d.ts} +8 -0
  97. package/dist/{types-DiBvmGEi.d.ts → types-DqJnP50o.d.ts} +22 -24
  98. package/dist/{pol-attachment-queue-BE2HU3Us.d.ts → types-JCEhw2Lf.d.ts} +139 -346
  99. package/package.json +18 -4
  100. package/dist/chunk-24RDMMCL.js +0 -44
  101. package/dist/chunk-24RDMMCL.js.map +0 -1
  102. package/dist/chunk-55DKCJV4.js.map +0 -1
  103. package/dist/chunk-654ERHA7.js +0 -1
  104. package/dist/chunk-BGBQYQV3.js.map +0 -1
  105. package/dist/chunk-C5ODS3XH.js.map +0 -1
  106. package/dist/chunk-CAB26E6F.js.map +0 -1
  107. package/dist/chunk-CACKC6XG.js.map +0 -1
  108. package/dist/chunk-P4HZA6ZT.js.map +0 -1
  109. package/dist/chunk-TIFL2KWE.js +0 -358
  110. package/dist/chunk-TIFL2KWE.js.map +0 -1
  111. package/dist/chunk-VB737IVN.js.map +0 -1
  112. package/dist/chunk-XAEII4ZX.js.map +0 -1
  113. package/dist/chunk-YSTEESEG.js.map +0 -1
  114. package/dist/chunk-Z6VOBGTU.js.map +0 -1
  115. /package/dist/{chunk-XOY2CJ67.js.map → chunk-4F5B5CZ7.js.map} +0 -0
  116. /package/dist/{chunk-654ERHA7.js.map → chunk-5WRI5ZAA.js.map} +0 -0
  117. /package/dist/{chunk-A4IBBWGO.js.map → chunk-RALHHPTU.js.map} +0 -0
  118. /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: 5,
34
- // Extended retries for RLS errors
35
- baseDelayMs: 3e4,
36
- // 30 seconds initial delay
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
- // ─── Retry Control Methods ─────────────────────────────────────────────────
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
- * Pause automatic retry of failed uploads.
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
- * This fixes the issue where reassigning selectedConfig inside withExponentialBackoff's
496
- * callback had no effect because the config was already destructured at call time.
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 if all retries exhausted (for critical failures)
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 processWithRetry(entry) {
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
- classified.isPermanent = classifiedError.isPermanent;
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 before retry:", {
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
- lastError = retryError instanceof Error ? retryError : new Error(String(retryError));
553
- const retriedClassification = classifySupabaseError(retryError);
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
- const isRlsPermissionError = lastError && isRlsError(lastError);
636
- const selectedConfig = isRlsPermissionError ? this.retryConfig.rls : classified.isPermanent ? this.retryConfig.permanent : this.retryConfig.transient;
637
- if (__DEV__ && isRlsPermissionError) {
638
- console.log("[Connector] RLS/permission error detected, using extended retry config:", {
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
- maxRetries: selectedConfig.maxRetries,
643
- baseDelayMs: selectedConfig.baseDelayMs,
644
- maxDelayMs: selectedConfig.maxDelayMs
507
+ isPermanent: classified.isPermanent,
508
+ pgCode: classified.pgCode,
509
+ message: error.message
645
510
  });
646
511
  }
647
- try {
648
- await withExponentialBackoff(async () => {
649
- await this.processCrudEntry(entry);
650
- }, selectedConfig, {
651
- onRetry: (attempt, delay, error) => {
652
- this.logger?.debug("[Connector] Retry attempt:", {
653
- table: entry.table,
654
- op: entry.op,
655
- id: entry.id,
656
- attempt,
657
- delay,
658
- error: error.message
659
- });
660
- if (__DEV__) {
661
- console.log("[Connector] Retry attempt:", {
662
- table: entry.table,
663
- op: entry.op,
664
- id: entry.id,
665
- attempt,
666
- maxRetries: selectedConfig.maxRetries,
667
- delayMs: delay,
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] CRUD entry failed after retries, leaving in ps_crud:", {
534
+ console.log("[Connector] Middleware result:", {
679
535
  table: entry.table,
680
- op: entry.op,
681
536
  id: entry.id,
682
- category,
683
- error: finalError.message
537
+ result: middlewareResult
684
538
  });
685
539
  }
686
- this.logger?.error("[Connector] CRUD entry failed after retries:", {
687
- table: entry.table,
688
- op: entry.op,
689
- id: entry.id,
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
- cooldownSec: cooldownMs / 1e3
546
+ pgCode: classified.pgCode
704
547
  });
705
- }
706
- throw finalError;
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
- for (const entry of entriesToProcess) {
955
- if (__DEV__) {
956
- console.log("[Connector] Processing CRUD entry with retry:", {
957
- table: entry.table,
958
- op: entry.op,
959
- id: entry.id,
960
- opData: entry.opData
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
- await this.processWithRetry(entry);
964
- successfulEntries.push(entry);
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
- for (const [table, entries] of entriesByTable) {
1151
- const schema = this.schemaRouter(table);
1152
- const putEntries = entries.filter((e) => e.op === "PUT" /* PUT */);
1153
- const patchEntries = entries.filter((e) => e.op === "PATCH" /* PATCH */);
1154
- const deleteEntries = entries.filter((e) => e.op === "DELETE" /* DELETE */);
1155
- if (this.crudHandler) {
1156
- for (const entry of entries) {
1157
- try {
1158
- await this.processWithRetry(entry);
1159
- successfulEntries.push(entry);
1160
- } catch (error) {
1161
- if (error instanceof DiscardEntryError) {
1162
- discardedEntries.push(entry);
1163
- continue;
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.processWithRetry(entry);
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.processWithRetry(entry);
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.processWithRetry(entry);
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
- throw new Error(`Upsert failed for ${schema}.${table}: ${upsertError.message}`);
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
- throw new Error(`Update failed for ${schema}.${table}: ${updateError.message}`);
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
- throw new Error(`Delete failed for ${schema}.${table}: ${deleteError.message}`);
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-BGBQYQV3.js.map
1504
+ //# sourceMappingURL=chunk-65A3SYJZ.js.map