@pol-studios/powersync 1.0.24 → 1.0.30

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 (53) hide show
  1. package/README.md +0 -1
  2. package/dist/attachments/index.d.ts +1 -1
  3. package/dist/{background-sync-ChCXW-EV.d.ts → background-sync-CVR3PkFi.d.ts} +1 -1
  4. package/dist/{chunk-BGBQYQV3.js → chunk-BC2SRII2.js} +180 -299
  5. package/dist/chunk-BC2SRII2.js.map +1 -0
  6. package/dist/{chunk-YSTEESEG.js → chunk-C2ACBYBZ.js} +208 -11
  7. package/dist/chunk-C2ACBYBZ.js.map +1 -0
  8. package/dist/{chunk-24RDMMCL.js → chunk-FNYQFILT.js} +1 -1
  9. package/dist/chunk-FNYQFILT.js.map +1 -0
  10. package/dist/{chunk-YVX3A36I.js → chunk-JCGOZVWL.js} +406 -331
  11. package/dist/chunk-JCGOZVWL.js.map +1 -0
  12. package/dist/{chunk-WGHNIAF7.js → chunk-QREWE3NR.js} +2 -2
  13. package/dist/{chunk-TIFL2KWE.js → chunk-RBPWEOIV.js} +3 -3
  14. package/dist/{chunk-55DKCJV4.js → chunk-RE5HWLCB.js} +124 -13
  15. package/dist/chunk-RE5HWLCB.js.map +1 -0
  16. package/dist/connector/index.d.ts +4 -4
  17. package/dist/connector/index.js +1 -2
  18. package/dist/core/index.d.ts +2 -2
  19. package/dist/generator/cli.js +6 -1
  20. package/dist/generator/index.d.ts +1 -0
  21. package/dist/generator/index.js +9 -1
  22. package/dist/generator/index.js.map +1 -1
  23. package/dist/index.d.ts +7 -7
  24. package/dist/index.js +27 -17
  25. package/dist/index.native.d.ts +5 -5
  26. package/dist/index.native.js +27 -17
  27. package/dist/index.web.d.ts +5 -5
  28. package/dist/index.web.js +27 -17
  29. package/dist/maintenance/index.d.ts +2 -2
  30. package/dist/maintenance/index.js +2 -2
  31. package/dist/platform/index.d.ts +1 -1
  32. package/dist/platform/index.native.d.ts +1 -1
  33. package/dist/platform/index.web.d.ts +1 -1
  34. package/dist/provider/index.d.ts +188 -28
  35. package/dist/provider/index.js +17 -7
  36. package/dist/react/index.d.ts +2 -2
  37. package/dist/react/index.js +3 -3
  38. package/dist/storage/index.d.ts +1 -1
  39. package/dist/storage/index.native.d.ts +1 -1
  40. package/dist/storage/index.web.d.ts +1 -1
  41. package/dist/{supabase-connector-D2oIl2t8.d.ts → supabase-connector-C4YpH_l3.d.ts} +23 -25
  42. package/dist/sync/index.d.ts +42 -5
  43. package/dist/sync/index.js +2 -2
  44. package/dist/{types-DiBvmGEi.d.ts → types-CpM2_LhU.d.ts} +17 -24
  45. package/dist/{types-CDqWh56B.d.ts → types-Dv1uf0LZ.d.ts} +16 -1
  46. package/package.json +2 -2
  47. package/dist/chunk-24RDMMCL.js.map +0 -1
  48. package/dist/chunk-55DKCJV4.js.map +0 -1
  49. package/dist/chunk-BGBQYQV3.js.map +0 -1
  50. package/dist/chunk-YSTEESEG.js.map +0 -1
  51. package/dist/chunk-YVX3A36I.js.map +0 -1
  52. /package/dist/{chunk-WGHNIAF7.js.map → chunk-QREWE3NR.js.map} +0 -0
  53. /package/dist/{chunk-TIFL2KWE.js.map → chunk-RBPWEOIV.js.map} +0 -0
package/README.md CHANGED
@@ -512,7 +512,6 @@ function FailedUploads() {
512
512
  permanentErrorCount,
513
513
  retryFailure,
514
514
  clearFailure,
515
- clearAllFailures,
516
515
  } = useFailedTransactionsContext();
517
516
 
518
517
  if (!hasUploadErrors) return null;
@@ -5,7 +5,7 @@ export { ATTACHMENT_TABLE, AbstractAttachmentQueue, AttachmentState, AttachmentT
5
5
  import { PlatformAdapter, LoggerAdapter } from '../platform/index.js';
6
6
  import { AbstractPowerSyncDatabase } from '@powersync/common';
7
7
  export { AbstractPowerSyncDatabase as PowerSyncDBInterface } from '@powersync/common';
8
- import '../types-CDqWh56B.js';
8
+ import '../types-Dv1uf0LZ.js';
9
9
 
10
10
  /**
11
11
  * POL Storage Adapter
@@ -1,4 +1,4 @@
1
- import { a as SyncStatus, S as SyncMode, e as SyncMetrics, b as ConnectionHealth, f as SyncError } from './types-CDqWh56B.js';
1
+ import { a as SyncStatus, S as SyncMode, e as SyncMetrics, b as ConnectionHealth, f as SyncError } from './types-Dv1uf0LZ.js';
2
2
 
3
3
  /**
4
4
  * Sync Module Types for @pol-studios/powersync
@@ -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
 
@@ -377,8 +362,6 @@ var SupabaseConnector = class _SupabaseConnector {
377
362
  versionColumnPromises = /* @__PURE__ */ new Map();
378
363
  // Flag to track if connector has been destroyed
379
364
  isDestroyed = false;
380
- // Retry configuration
381
- retryConfig;
382
365
  // Track completion failures for circuit breaker logic
383
366
  // Maps transaction fingerprint (hash of entry IDs) to failure tracking info
384
367
  completionFailures = /* @__PURE__ */ new Map();
@@ -386,13 +369,6 @@ var SupabaseConnector = class _SupabaseConnector {
386
369
  static COMPLETION_EXTENDED_TIMEOUT_MS = 6e4;
387
370
  // 60s timeout for retry
388
371
  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
372
  // Upload error middleware chain
397
373
  uploadErrorMiddleware;
398
374
  constructor(options) {
@@ -408,20 +384,6 @@ var SupabaseConnector = class _SupabaseConnector {
408
384
  this.conflictDetection = options.conflictDetection;
409
385
  this.conflictHandler = options.conflictHandler;
410
386
  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
387
  this.uploadErrorMiddleware = options.uploadErrorMiddleware ?? [];
426
388
  if (this.conflictBus) {
427
389
  this.unsubscribeResolution = this.conflictBus.onResolution((table, recordId, resolution) => {
@@ -464,80 +426,46 @@ var SupabaseConnector = class _SupabaseConnector {
464
426
  const sortedIds = entries.map((e) => `${e.table}:${e.id}`).sort();
465
427
  return sortedIds.join("|");
466
428
  }
467
- // ─── Retry Control Methods ─────────────────────────────────────────────────
429
+ // ─── Simplified Entry Processing ───────────────────────────────────────────
430
+ //
431
+ // Architecture:
432
+ // - NO internal retry loops - PowerSync SDK handles all retries naturally
433
+ // - Middleware decides once: success/discard/retry/fail_transaction
434
+ // - 'retry' = transient error, throw to let PowerSync retry on next sync cycle
435
+ // - 'fail_transaction' = permanent error, throw immediately with failure callback
436
+ // - 'discard' = silently skip via DiscardEntryError
437
+ // - 'success' = treat as completed, return normally
438
+ //
439
+ // This keeps error handling simple and lets the user configure middleware
440
+ // to decide what to do with each error type.
468
441
  /**
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
442
+ * Process a single CRUD entry once (no internal retries).
494
443
  *
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.
444
+ * On failure, middleware classifies the error:
445
+ * - 'success': Treat as completed (e.g., idempotent duplicate)
446
+ * - 'discard': Remove from queue silently
447
+ * - 'retry': Throw to let PowerSync retry on next sync cycle
448
+ * - 'fail_transaction': Throw TransactionAbortError immediately
449
+ * - 'continue': Throw original error (PowerSync will retry)
497
450
  *
498
451
  * @param entry - The CRUD entry to process
499
- * @throws Error if all retries exhausted (for critical failures)
452
+ * @throws Error for all errors (PowerSync will retry)
453
+ * @throws TransactionAbortError when middleware returns 'fail_transaction'
454
+ * @throws DiscardEntryError for discarded entries
500
455
  */
501
- async processWithRetry(entry) {
456
+ async processEntryOnce(entry) {
502
457
  if (this.isDestroyed) {
503
458
  throw new Error("Connector destroyed");
504
459
  }
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
460
  try {
529
461
  await this.processCrudEntry(entry);
530
- this.entryCooldowns.delete(entryKey);
531
462
  return;
532
463
  } catch (error) {
533
- lastError = error instanceof Error ? error : new Error(String(error));
534
464
  const classifiedError = classifySupabaseError(error);
535
- classified.isPermanent = classifiedError.isPermanent;
536
- classified.pgCode = classifiedError.pgCode;
537
- classified.userMessage = classifiedError.userMessage;
465
+ const errorObj = error instanceof Error ? error : new Error(String(error));
538
466
  if (isAuthError(error)) {
539
467
  if (__DEV__) {
540
- console.log("[Connector] Auth error detected, refreshing session before retry:", {
468
+ console.log("[Connector] Auth error detected, refreshing session:", {
541
469
  table: entry.table,
542
470
  op: entry.op,
543
471
  id: entry.id
@@ -546,164 +474,99 @@ var SupabaseConnector = class _SupabaseConnector {
546
474
  try {
547
475
  await this.supabase.auth.refreshSession();
548
476
  await this.processCrudEntry(entry);
549
- this.entryCooldowns.delete(entryKey);
550
477
  return;
551
478
  } 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);
479
+ const retryClassified = classifySupabaseError(retryError);
480
+ return this.handleEntryError(entry, retryError instanceof Error ? retryError : new Error(String(retryError)), retryClassified, retryError);
632
481
  }
633
482
  }
483
+ return this.handleEntryError(entry, errorObj, classifiedError, error);
634
484
  }
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:", {
485
+ }
486
+ /**
487
+ * Handle an entry error by running middleware and deciding what to do.
488
+ */
489
+ async handleEntryError(entry, error, classified, originalError) {
490
+ if (__DEV__) {
491
+ console.log("[Connector] Entry failed:", {
639
492
  table: entry.table,
640
493
  op: entry.op,
641
494
  id: entry.id,
642
- maxRetries: selectedConfig.maxRetries,
643
- baseDelayMs: selectedConfig.baseDelayMs,
644
- maxDelayMs: selectedConfig.maxDelayMs
495
+ isPermanent: classified.isPermanent,
496
+ pgCode: classified.pgCode,
497
+ message: error.message
645
498
  });
646
499
  }
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";
500
+ this.logger?.warn("[Connector] Entry failed:", {
501
+ table: entry.table,
502
+ op: entry.op,
503
+ id: entry.id,
504
+ error: error.message,
505
+ isPermanent: classified.isPermanent
506
+ });
507
+ let middlewareResult = "continue";
508
+ if (this.uploadErrorMiddleware.length > 0) {
509
+ const schema = this.schemaRouter(entry.table);
510
+ const middlewareContext = {
511
+ entry,
512
+ error,
513
+ pgCode: classified.pgCode,
514
+ httpStatusCode: extractHttpStatusCode(originalError),
515
+ classified,
516
+ originalError,
517
+ schema,
518
+ supabase: this.supabase
519
+ };
520
+ middlewareResult = await runUploadErrorMiddleware(middlewareContext, this.uploadErrorMiddleware, "continue");
677
521
  if (__DEV__) {
678
- console.log("[Connector] CRUD entry failed after retries, leaving in ps_crud:", {
522
+ console.log("[Connector] Middleware result:", {
679
523
  table: entry.table,
680
- op: entry.op,
681
524
  id: entry.id,
682
- category,
683
- error: finalError.message
525
+ result: middlewareResult
684
526
  });
685
527
  }
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:", {
528
+ }
529
+ switch (middlewareResult) {
530
+ case "success":
531
+ this.logger?.info("[Connector] Entry treated as success by middleware:", {
701
532
  table: entry.table,
702
533
  id: entry.id,
703
- cooldownSec: cooldownMs / 1e3
534
+ pgCode: classified.pgCode
704
535
  });
705
- }
706
- throw finalError;
536
+ return;
537
+ case "discard":
538
+ this.logger?.warn("[Connector] Entry discarded by middleware:", {
539
+ table: entry.table,
540
+ id: entry.id,
541
+ pgCode: classified.pgCode
542
+ });
543
+ throw new DiscardEntryError(`Entry discarded by middleware: ${entry.table}:${entry.id} (${classified.pgCode || "unknown"})`);
544
+ case "fail_transaction":
545
+ this.logger?.error("[Connector] Transaction aborted by middleware:", {
546
+ table: entry.table,
547
+ id: entry.id,
548
+ pgCode: classified.pgCode
549
+ });
550
+ throw new TransactionAbortError(`Transaction aborted by middleware: ${entry.table}:${entry.id}`, error);
551
+ case "retry":
552
+ if (__DEV__) {
553
+ console.log("[Connector] Middleware returned retry - throwing for PowerSync retry:", {
554
+ table: entry.table,
555
+ id: entry.id
556
+ });
557
+ }
558
+ throw error;
559
+ case "continue":
560
+ default:
561
+ if (__DEV__) {
562
+ console.log("[Connector] Error - throwing for PowerSync retry:", {
563
+ table: entry.table,
564
+ id: entry.id,
565
+ isPermanent: classified.isPermanent,
566
+ pgCode: classified.pgCode
567
+ });
568
+ }
569
+ throw error;
707
570
  }
708
571
  }
709
572
  /**
@@ -951,17 +814,23 @@ var SupabaseConnector = class _SupabaseConnector {
951
814
  return;
952
815
  }
953
816
  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
- });
817
+ try {
818
+ for (const entry of entriesToProcess) {
819
+ if (__DEV__) {
820
+ console.log("[Connector] Processing CRUD entry:", {
821
+ table: entry.table,
822
+ op: entry.op,
823
+ id: entry.id,
824
+ opData: entry.opData
825
+ });
826
+ }
827
+ await this.processEntryOnce(entry);
828
+ successfulEntries.push(entry);
962
829
  }
963
- await this.processWithRetry(entry);
964
- successfulEntries.push(entry);
830
+ } catch (error) {
831
+ const classified = classifySupabaseError(error);
832
+ this.onTransactionFailure?.(entriesToProcess, error instanceof Error ? error : new Error(String(error)), classified);
833
+ throw error;
965
834
  }
966
835
  await this.finalizeTransaction({
967
836
  transaction,
@@ -1147,50 +1016,56 @@ var SupabaseConnector = class _SupabaseConnector {
1147
1016
  }]))
1148
1017
  });
1149
1018
  }
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;
1019
+ try {
1020
+ for (const [table, entries] of entriesByTable) {
1021
+ const schema = this.schemaRouter(table);
1022
+ const putEntries = entries.filter((e) => e.op === "PUT" /* PUT */);
1023
+ const patchEntries = entries.filter((e) => e.op === "PATCH" /* PATCH */);
1024
+ const deleteEntries = entries.filter((e) => e.op === "DELETE" /* DELETE */);
1025
+ if (this.crudHandler) {
1026
+ for (const entry of entries) {
1027
+ try {
1028
+ await this.processEntryOnce(entry);
1029
+ successfulEntries.push(entry);
1030
+ } catch (error) {
1031
+ if (error instanceof DiscardEntryError) {
1032
+ discardedEntries.push(entry);
1033
+ continue;
1034
+ }
1035
+ throw error;
1164
1036
  }
1165
- throw error;
1166
1037
  }
1038
+ continue;
1039
+ }
1040
+ if (putEntries.length > 0) {
1041
+ const {
1042
+ successful,
1043
+ discarded
1044
+ } = await this.processBatchedPuts(table, schema, putEntries);
1045
+ successfulEntries.push(...successful);
1046
+ discardedEntries.push(...discarded);
1047
+ }
1048
+ if (deleteEntries.length > 0) {
1049
+ const {
1050
+ successful,
1051
+ discarded
1052
+ } = await this.processBatchedDeletes(table, schema, deleteEntries);
1053
+ successfulEntries.push(...successful);
1054
+ discardedEntries.push(...discarded);
1055
+ }
1056
+ if (patchEntries.length > 0) {
1057
+ const {
1058
+ successful,
1059
+ discarded
1060
+ } = await this.processBatchedPatches(table, schema, patchEntries);
1061
+ successfulEntries.push(...successful);
1062
+ discardedEntries.push(...discarded);
1167
1063
  }
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
1064
  }
1065
+ } catch (error) {
1066
+ const classified = classifySupabaseError(error);
1067
+ this.onTransactionFailure?.(transaction.crud, error instanceof Error ? error : new Error(String(error)), classified);
1068
+ throw error;
1194
1069
  }
1195
1070
  await this.finalizeTransaction({
1196
1071
  transaction,
@@ -1235,7 +1110,7 @@ var SupabaseConnector = class _SupabaseConnector {
1235
1110
  }
1236
1111
  for (const entry of entries) {
1237
1112
  try {
1238
- await this.processWithRetry(entry);
1113
+ await this.processEntryOnce(entry);
1239
1114
  successful.push(entry);
1240
1115
  } catch (e) {
1241
1116
  if (e instanceof DiscardEntryError) {
@@ -1292,7 +1167,7 @@ var SupabaseConnector = class _SupabaseConnector {
1292
1167
  }
1293
1168
  for (const entry of entries) {
1294
1169
  try {
1295
- await this.processWithRetry(entry);
1170
+ await this.processEntryOnce(entry);
1296
1171
  successful.push(entry);
1297
1172
  } catch (e) {
1298
1173
  if (e instanceof DiscardEntryError) {
@@ -1347,7 +1222,7 @@ var SupabaseConnector = class _SupabaseConnector {
1347
1222
  }
1348
1223
  const results = await Promise.all(batch.map(async (entry) => {
1349
1224
  try {
1350
- await this.processWithRetry(entry);
1225
+ await this.processEntryOnce(entry);
1351
1226
  return {
1352
1227
  status: "success",
1353
1228
  entry
@@ -1497,7 +1372,9 @@ var SupabaseConnector = class _SupabaseConnector {
1497
1372
  errorHint: upsertError.hint
1498
1373
  });
1499
1374
  }
1500
- throw new Error(`Upsert failed for ${schema}.${table}: ${upsertError.message}`);
1375
+ const upsertErr = new Error(`Upsert failed for ${schema}.${table}: ${upsertError.message}`);
1376
+ upsertErr.code = upsertError.code;
1377
+ throw upsertErr;
1501
1378
  }
1502
1379
  if (__DEV__) {
1503
1380
  console.log("[Connector] PUT/UPSERT SUCCESS:", {
@@ -1534,7 +1411,9 @@ var SupabaseConnector = class _SupabaseConnector {
1534
1411
  errorHint: updateError.hint
1535
1412
  });
1536
1413
  }
1537
- throw new Error(`Update failed for ${schema}.${table}: ${updateError.message}`);
1414
+ const updateErr = new Error(`Update failed for ${schema}.${table}: ${updateError.message}`);
1415
+ updateErr.code = updateError.code;
1416
+ throw updateErr;
1538
1417
  }
1539
1418
  if (__DEV__) {
1540
1419
  console.log("[Connector] PATCH/UPDATE SUCCESS:", {
@@ -1570,7 +1449,9 @@ var SupabaseConnector = class _SupabaseConnector {
1570
1449
  errorHint: deleteError.hint
1571
1450
  });
1572
1451
  }
1573
- throw new Error(`Delete failed for ${schema}.${table}: ${deleteError.message}`);
1452
+ const deleteErr = new Error(`Delete failed for ${schema}.${table}: ${deleteError.message}`);
1453
+ deleteErr.code = deleteError.code;
1454
+ throw deleteErr;
1574
1455
  }
1575
1456
  if (__DEV__) {
1576
1457
  console.log("[Connector] DELETE SUCCESS:", {
@@ -1607,4 +1488,4 @@ export {
1607
1488
  getLocalVersion,
1608
1489
  SupabaseConnector
1609
1490
  };
1610
- //# sourceMappingURL=chunk-BGBQYQV3.js.map
1491
+ //# sourceMappingURL=chunk-BC2SRII2.js.map