@pol-studios/powersync 1.0.6 → 1.0.10

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 (128) hide show
  1. package/README.md +933 -0
  2. package/dist/CacheSettingsManager-uz-kbnRH.d.ts +461 -0
  3. package/dist/attachments/index.d.ts +745 -332
  4. package/dist/attachments/index.js +152 -6
  5. package/dist/{types-Cd7RhNqf.d.ts → background-sync-ChCXW-EV.d.ts} +53 -2
  6. package/dist/chunk-24RDMMCL.js +44 -0
  7. package/dist/chunk-24RDMMCL.js.map +1 -0
  8. package/dist/chunk-4TXTAEF2.js +2060 -0
  9. package/dist/chunk-4TXTAEF2.js.map +1 -0
  10. package/dist/chunk-63PXSPIN.js +358 -0
  11. package/dist/chunk-63PXSPIN.js.map +1 -0
  12. package/dist/chunk-654ERHA7.js +1 -0
  13. package/dist/chunk-A4IBBWGO.js +377 -0
  14. package/dist/chunk-A4IBBWGO.js.map +1 -0
  15. package/dist/chunk-BRXQNASY.js +1720 -0
  16. package/dist/chunk-BRXQNASY.js.map +1 -0
  17. package/dist/chunk-CAB26E6F.js +142 -0
  18. package/dist/chunk-CAB26E6F.js.map +1 -0
  19. package/dist/{chunk-EJ23MXPQ.js → chunk-CGL33PL4.js} +3 -1
  20. package/dist/chunk-CGL33PL4.js.map +1 -0
  21. package/dist/{chunk-R4YFWQ3Q.js → chunk-CUCAYK7Z.js} +309 -92
  22. package/dist/chunk-CUCAYK7Z.js.map +1 -0
  23. package/dist/chunk-FV2HXEIY.js +124 -0
  24. package/dist/chunk-FV2HXEIY.js.map +1 -0
  25. package/dist/chunk-HWSNV45P.js +279 -0
  26. package/dist/chunk-HWSNV45P.js.map +1 -0
  27. package/dist/{chunk-62J2DPKX.js → chunk-KN2IZERF.js} +530 -413
  28. package/dist/chunk-KN2IZERF.js.map +1 -0
  29. package/dist/{chunk-7EMDVIZX.js → chunk-N75DEF5J.js} +19 -1
  30. package/dist/chunk-N75DEF5J.js.map +1 -0
  31. package/dist/chunk-P4HZA6ZT.js +83 -0
  32. package/dist/chunk-P4HZA6ZT.js.map +1 -0
  33. package/dist/chunk-P6WOZO7H.js +49 -0
  34. package/dist/chunk-P6WOZO7H.js.map +1 -0
  35. package/dist/chunk-T4AO7JIG.js +1 -0
  36. package/dist/chunk-TGBT5XBE.js +1 -0
  37. package/dist/{chunk-FPTDATY5.js → chunk-VACPAAQZ.js} +54 -12
  38. package/dist/chunk-VACPAAQZ.js.map +1 -0
  39. package/dist/chunk-WGHNIAF7.js +329 -0
  40. package/dist/chunk-WGHNIAF7.js.map +1 -0
  41. package/dist/{chunk-3AYXHQ4W.js → chunk-WN5ZJ3E2.js} +108 -47
  42. package/dist/chunk-WN5ZJ3E2.js.map +1 -0
  43. package/dist/chunk-XAEII4ZX.js +456 -0
  44. package/dist/chunk-XAEII4ZX.js.map +1 -0
  45. package/dist/chunk-XOY2CJ67.js +289 -0
  46. package/dist/chunk-XOY2CJ67.js.map +1 -0
  47. package/dist/chunk-YHTZ7VMV.js +1 -0
  48. package/dist/chunk-YSTEESEG.js +676 -0
  49. package/dist/chunk-YSTEESEG.js.map +1 -0
  50. package/dist/chunk-Z6VOBGTU.js +32 -0
  51. package/dist/chunk-Z6VOBGTU.js.map +1 -0
  52. package/dist/chunk-ZM4ENYMF.js +230 -0
  53. package/dist/chunk-ZM4ENYMF.js.map +1 -0
  54. package/dist/connector/index.d.ts +236 -4
  55. package/dist/connector/index.js +15 -4
  56. package/dist/core/index.d.ts +16 -3
  57. package/dist/core/index.js +6 -2
  58. package/dist/error/index.d.ts +54 -0
  59. package/dist/error/index.js +7 -0
  60. package/dist/error/index.js.map +1 -0
  61. package/dist/index.d.ts +102 -12
  62. package/dist/index.js +309 -37
  63. package/dist/index.native.d.ts +22 -10
  64. package/dist/index.native.js +309 -38
  65. package/dist/index.web.d.ts +22 -10
  66. package/dist/index.web.js +310 -38
  67. package/dist/maintenance/index.d.ts +118 -0
  68. package/dist/maintenance/index.js +16 -0
  69. package/dist/maintenance/index.js.map +1 -0
  70. package/dist/platform/index.d.ts +16 -1
  71. package/dist/platform/index.js.map +1 -1
  72. package/dist/platform/index.native.d.ts +2 -2
  73. package/dist/platform/index.native.js +1 -1
  74. package/dist/platform/index.web.d.ts +1 -1
  75. package/dist/platform/index.web.js +1 -1
  76. package/dist/pol-attachment-queue-BVAIueoP.d.ts +817 -0
  77. package/dist/provider/index.d.ts +451 -21
  78. package/dist/provider/index.js +32 -13
  79. package/dist/react/index.d.ts +372 -0
  80. package/dist/react/index.js +25 -0
  81. package/dist/react/index.js.map +1 -0
  82. package/dist/storage/index.d.ts +6 -0
  83. package/dist/storage/index.js +42 -0
  84. package/dist/storage/index.js.map +1 -0
  85. package/dist/storage/index.native.d.ts +6 -0
  86. package/dist/storage/index.native.js +40 -0
  87. package/dist/storage/index.native.js.map +1 -0
  88. package/dist/storage/index.web.d.ts +6 -0
  89. package/dist/storage/index.web.js +40 -0
  90. package/dist/storage/index.web.js.map +1 -0
  91. package/dist/storage/upload/index.d.ts +54 -0
  92. package/dist/storage/upload/index.js +15 -0
  93. package/dist/storage/upload/index.js.map +1 -0
  94. package/dist/storage/upload/index.native.d.ts +56 -0
  95. package/dist/storage/upload/index.native.js +15 -0
  96. package/dist/storage/upload/index.native.js.map +1 -0
  97. package/dist/storage/upload/index.web.d.ts +2 -0
  98. package/dist/storage/upload/index.web.js +14 -0
  99. package/dist/storage/upload/index.web.js.map +1 -0
  100. package/dist/supabase-connector-T9vHq_3i.d.ts +202 -0
  101. package/dist/sync/index.d.ts +288 -23
  102. package/dist/sync/index.js +22 -10
  103. package/dist/{index-l3iL9Jte.d.ts → types-B212hgfA.d.ts} +101 -158
  104. package/dist/{types-afHtE1U_.d.ts → types-CDqWh56B.d.ts} +2 -0
  105. package/dist/types-CyvBaAl8.d.ts +60 -0
  106. package/dist/types-D0WcHrq6.d.ts +234 -0
  107. package/package.json +89 -5
  108. package/dist/chunk-32OLICZO.js +0 -1
  109. package/dist/chunk-3AYXHQ4W.js.map +0 -1
  110. package/dist/chunk-5FIMA26D.js +0 -1
  111. package/dist/chunk-62J2DPKX.js.map +0 -1
  112. package/dist/chunk-7EMDVIZX.js.map +0 -1
  113. package/dist/chunk-EJ23MXPQ.js.map +0 -1
  114. package/dist/chunk-FPTDATY5.js.map +0 -1
  115. package/dist/chunk-KCDG2MNP.js +0 -1431
  116. package/dist/chunk-KCDG2MNP.js.map +0 -1
  117. package/dist/chunk-OLHGI472.js +0 -1
  118. package/dist/chunk-PAFBKNL3.js +0 -99
  119. package/dist/chunk-PAFBKNL3.js.map +0 -1
  120. package/dist/chunk-R4YFWQ3Q.js.map +0 -1
  121. package/dist/chunk-V6LJ6MR2.js +0 -740
  122. package/dist/chunk-V6LJ6MR2.js.map +0 -1
  123. package/dist/chunk-VJCL2SWD.js +0 -1
  124. package/dist/failed-upload-store-C0cLxxPz.d.ts +0 -33
  125. /package/dist/{chunk-32OLICZO.js.map → chunk-654ERHA7.js.map} +0 -0
  126. /package/dist/{chunk-5FIMA26D.js.map → chunk-T4AO7JIG.js.map} +0 -0
  127. /package/dist/{chunk-OLHGI472.js.map → chunk-TGBT5XBE.js.map} +0 -0
  128. /package/dist/{chunk-VJCL2SWD.js.map → chunk-YHTZ7VMV.js.map} +0 -0
@@ -0,0 +1,1720 @@
1
+ import {
2
+ PowerSyncErrorBoundary
3
+ } from "./chunk-P6WOZO7H.js";
4
+ import {
5
+ createPolAttachmentQueue
6
+ } from "./chunk-4TXTAEF2.js";
7
+ import {
8
+ HealthMonitor,
9
+ MetricsCollector,
10
+ SyncStatusTracker
11
+ } from "./chunk-CUCAYK7Z.js";
12
+ import {
13
+ DEFAULT_CONNECTION_HEALTH,
14
+ DEFAULT_SYNC_METRICS,
15
+ DEFAULT_SYNC_STATUS
16
+ } from "./chunk-24RDMMCL.js";
17
+ import {
18
+ AttachmentQueueContext,
19
+ CompletedTransactionsContext,
20
+ ConnectionHealthContext,
21
+ ConnectionStatusContext,
22
+ FailedTransactionsContext,
23
+ PendingMutationsContext,
24
+ PowerSyncContext,
25
+ SyncActivityContext,
26
+ SyncMetricsContext,
27
+ SyncModeContext,
28
+ SyncStatusContext,
29
+ useOnlineStatus,
30
+ usePendingMutationsContext,
31
+ usePowerSync,
32
+ useSyncStatus
33
+ } from "./chunk-YSTEESEG.js";
34
+ import {
35
+ createSupabaseUploadHandler
36
+ } from "./chunk-CAB26E6F.js";
37
+ import {
38
+ SupabaseStorageAdapter
39
+ } from "./chunk-XAEII4ZX.js";
40
+ import {
41
+ createNativePlatformAdapter
42
+ } from "./chunk-WN5ZJ3E2.js";
43
+ import {
44
+ SupabaseConnector
45
+ } from "./chunk-KN2IZERF.js";
46
+ import {
47
+ createSyncError,
48
+ extractEntityIds,
49
+ extractTableNames
50
+ } from "./chunk-VACPAAQZ.js";
51
+
52
+ // src/provider/PowerSyncProvider.tsx
53
+ import { useEffect, useState, useRef, useMemo, useCallback } from "react";
54
+
55
+ // src/conflicts/conflict-bus.ts
56
+ var ConflictBus = class _ConflictBus {
57
+ static MAX_PENDING = 100;
58
+ conflictListeners = /* @__PURE__ */ new Set();
59
+ resolutionListeners = /* @__PURE__ */ new Set();
60
+ pendingConflicts = [];
61
+ /**
62
+ * Subscribe to conflict detection events.
63
+ * Flushes any pending conflicts to ALL listeners (including the new one).
64
+ * @returns Unsubscribe function
65
+ */
66
+ onConflict(listener) {
67
+ this.conflictListeners.add(listener);
68
+ if (this.pendingConflicts.length > 0) {
69
+ const pending = [...this.pendingConflicts];
70
+ this.pendingConflicts = [];
71
+ for (const conflict of pending) {
72
+ this.conflictListeners.forEach((l) => l(conflict));
73
+ }
74
+ }
75
+ return () => this.conflictListeners.delete(listener);
76
+ }
77
+ /**
78
+ * Subscribe to resolution events.
79
+ * @returns Unsubscribe function
80
+ */
81
+ onResolution(listener) {
82
+ this.resolutionListeners.add(listener);
83
+ return () => this.resolutionListeners.delete(listener);
84
+ }
85
+ /**
86
+ * Emit a conflict detection event (called by connector).
87
+ * If no listeners are subscribed, queues the conflict for later delivery.
88
+ */
89
+ emitConflict(conflict) {
90
+ if (this.conflictListeners.size === 0) {
91
+ console.warn("[ConflictBus] No listeners - queueing conflict");
92
+ if (this.pendingConflicts.length >= _ConflictBus.MAX_PENDING) {
93
+ console.warn("[ConflictBus] Pending queue full, dropping oldest conflict");
94
+ this.pendingConflicts.shift();
95
+ }
96
+ this.pendingConflicts.push(conflict);
97
+ return;
98
+ }
99
+ this.conflictListeners.forEach((listener) => listener(conflict));
100
+ }
101
+ /**
102
+ * Emit a resolution event (called by UI/ConflictContext).
103
+ */
104
+ emitResolution(table, recordId, resolution) {
105
+ this.resolutionListeners.forEach((listener) => listener(table, recordId, resolution));
106
+ }
107
+ /**
108
+ * Clear all listeners and pending conflicts (for cleanup).
109
+ */
110
+ destroy() {
111
+ this.conflictListeners.clear();
112
+ this.resolutionListeners.clear();
113
+ this.pendingConflicts = [];
114
+ }
115
+ /**
116
+ * Get the number of pending conflicts (useful for debugging/testing).
117
+ */
118
+ get pendingCount() {
119
+ return this.pendingConflicts.length;
120
+ }
121
+ };
122
+
123
+ // src/provider/PowerSyncProvider.tsx
124
+ import { jsx } from "react/jsx-runtime";
125
+ function PowerSyncProvider({
126
+ config,
127
+ children,
128
+ onReady,
129
+ onError,
130
+ onSyncStatusChange
131
+ }) {
132
+ const {
133
+ platform,
134
+ schema,
135
+ powerSyncUrl,
136
+ supabaseClient,
137
+ dbFilename = "powersync.db",
138
+ connector: connectorConfig,
139
+ attachments: attachmentConfig,
140
+ sync: syncConfig
141
+ } = config;
142
+ const logger = platform.logger;
143
+ const mergedSyncConfig = {
144
+ autoConnect: syncConfig?.autoConnect ?? true,
145
+ syncInterval: syncConfig?.syncInterval ?? 0,
146
+ enableHealthMonitoring: syncConfig?.enableHealthMonitoring ?? true,
147
+ enableMetrics: syncConfig?.enableMetrics ?? true
148
+ };
149
+ const [db, setDb] = useState(null);
150
+ const [connector, setConnector] = useState(null);
151
+ const [attachmentQueue, setAttachmentQueue] = useState(null);
152
+ const [isReady, setIsReady] = useState(false);
153
+ const [isInitializing, setIsInitializing] = useState(true);
154
+ const [attachmentQueueReady, setAttachmentQueueReady] = useState(!attachmentConfig);
155
+ const [error, setError] = useState(null);
156
+ const [session, setSession] = useState(null);
157
+ const conflictBusRef = useRef(null);
158
+ if (!conflictBusRef.current) {
159
+ conflictBusRef.current = new ConflictBus();
160
+ }
161
+ const conflictBus = conflictBusRef.current;
162
+ const [syncStatus, setSyncStatus] = useState(DEFAULT_SYNC_STATUS);
163
+ const [pendingMutations, setPendingMutations] = useState([]);
164
+ const [syncModeState, setSyncModeState] = useState({
165
+ loaded: false,
166
+ mode: "push-pull"
167
+ });
168
+ const [lastSyncedAt, setLastSyncedAt] = useState(null);
169
+ const [connectionError, setConnectionError] = useState(null);
170
+ const [failedTransactions, setFailedTransactions] = useState([]);
171
+ const [completedTransactions, setCompletedTransactions] = useState([]);
172
+ const [newCompletedTransactions, setNewCompletedTransactions] = useState([]);
173
+ const [connectionHealth, setConnectionHealth] = useState(DEFAULT_CONNECTION_HEALTH);
174
+ const [syncMetrics, setSyncMetrics] = useState(DEFAULT_SYNC_METRICS);
175
+ const [isAutoOffline, setIsAutoOffline] = useState(false);
176
+ const [networkReachable, setNetworkReachable] = useState(true);
177
+ const statusTrackerRef = useRef(null);
178
+ const metricsCollectorRef = useRef(null);
179
+ const healthMonitorRef = useRef(null);
180
+ const attachmentQueueRef = useRef(null);
181
+ const listenerUnsubscribeRef = useRef(null);
182
+ const wasSyncingRef = useRef(false);
183
+ const wasUploadingRef = useRef(false);
184
+ const initializingRef = useRef(false);
185
+ const dbClosedRef = useRef(false);
186
+ const connectorRef = useRef(null);
187
+ const cleanupPromiseRef = useRef(null);
188
+ const isCleaningUpRef = useRef(false);
189
+ const prevNetworkConnectedRef = useRef(null);
190
+ const autoOfflineInitializedRef = useRef(false);
191
+ const isAutoOfflineRef = useRef(false);
192
+ const syncModeRef = useRef("push-pull");
193
+ const removePendingMutationRef = useRef(() => {
194
+ });
195
+ const onSyncStatusChangeRef = useRef(onSyncStatusChange);
196
+ const onReadyRef = useRef(onReady);
197
+ const onErrorRef = useRef(onError);
198
+ useEffect(() => {
199
+ onSyncStatusChangeRef.current = onSyncStatusChange;
200
+ }, [onSyncStatusChange]);
201
+ useEffect(() => {
202
+ onReadyRef.current = onReady;
203
+ }, [onReady]);
204
+ useEffect(() => {
205
+ onErrorRef.current = onError;
206
+ }, [onError]);
207
+ useEffect(() => {
208
+ isAutoOfflineRef.current = isAutoOffline;
209
+ syncModeRef.current = syncModeState.mode;
210
+ }, [isAutoOffline, syncModeState.mode]);
211
+ useEffect(() => {
212
+ const statusTracker = new SyncStatusTracker(platform.storage, logger, {
213
+ onStatusChange: (status) => {
214
+ setSyncStatus(status);
215
+ setLastSyncedAt(status.lastSyncedAt);
216
+ onSyncStatusChangeRef.current?.(status);
217
+ }
218
+ });
219
+ statusTrackerRef.current = statusTracker;
220
+ const metricsCollector = new MetricsCollector(platform.storage, logger, {
221
+ onMetricsChange: setSyncMetrics
222
+ });
223
+ metricsCollectorRef.current = metricsCollector;
224
+ const healthMonitor = new HealthMonitor(logger, {
225
+ onHealthChange: setConnectionHealth
226
+ });
227
+ healthMonitorRef.current = healthMonitor;
228
+ const initPromise = Promise.all([statusTracker.init(), metricsCollector.init()]);
229
+ const timeoutPromise = new Promise((resolve) => {
230
+ setTimeout(() => {
231
+ logger.warn("[PowerSyncProvider] Sync mode state load timed out, using default (push-pull)");
232
+ resolve([void 0, void 0]);
233
+ }, 5e3);
234
+ });
235
+ Promise.race([initPromise, timeoutPromise]).then(() => {
236
+ const loadedMode = statusTracker.getSyncMode();
237
+ const loadedIsAutoOffline = statusTracker.getIsAutoOffline();
238
+ logger.info("[PowerSyncProvider] Sync mode state loaded:", {
239
+ mode: loadedMode,
240
+ isAutoOffline: loadedIsAutoOffline
241
+ });
242
+ setSyncModeState({
243
+ loaded: true,
244
+ mode: loadedMode
245
+ });
246
+ setIsAutoOffline(loadedIsAutoOffline);
247
+ setCompletedTransactions(statusTracker.getCompletedTransactions());
248
+ setNewCompletedTransactions(statusTracker.getNewCompletedTransactions());
249
+ setFailedTransactions(statusTracker.getFailedTransactions());
250
+ });
251
+ return () => {
252
+ statusTracker.dispose();
253
+ metricsCollector.dispose();
254
+ healthMonitor.dispose();
255
+ };
256
+ }, [platform, logger]);
257
+ useEffect(() => {
258
+ logger.debug("[PowerSyncProvider] Setting up auth listener");
259
+ supabaseClient.auth.getSession().then(({
260
+ data: {
261
+ session: initialSession
262
+ }
263
+ }) => {
264
+ logger.debug("[PowerSyncProvider] Initial session:", !!initialSession);
265
+ setSession(initialSession);
266
+ });
267
+ const {
268
+ data: {
269
+ subscription
270
+ }
271
+ } = supabaseClient.auth.onAuthStateChange((_event, newSession) => {
272
+ logger.debug("[PowerSyncProvider] Auth state changed, hasSession:", !!newSession);
273
+ setSession(newSession);
274
+ });
275
+ return () => {
276
+ subscription.unsubscribe();
277
+ };
278
+ }, [supabaseClient, logger]);
279
+ useEffect(() => {
280
+ if (initializingRef.current) {
281
+ logger.debug("[PowerSyncProvider] Already initializing, skipping...");
282
+ return;
283
+ }
284
+ initializingRef.current = true;
285
+ const controller = {
286
+ cancelled: false
287
+ };
288
+ const initDatabase = async () => {
289
+ try {
290
+ if (cleanupPromiseRef.current) {
291
+ logger.debug("[PowerSyncProvider] Waiting for cleanup to complete...");
292
+ await cleanupPromiseRef.current;
293
+ if (controller.cancelled) {
294
+ initializingRef.current = false;
295
+ return;
296
+ }
297
+ logger.debug("[PowerSyncProvider] Cleanup complete, proceeding with init");
298
+ }
299
+ dbClosedRef.current = false;
300
+ logger.info("[PowerSyncProvider] Initializing database...");
301
+ const database = await platform.createDatabase({
302
+ dbFilename,
303
+ schema
304
+ });
305
+ if (controller.cancelled) {
306
+ logger.debug("[PowerSyncProvider] Init cancelled, closing database...");
307
+ await database.close();
308
+ initializingRef.current = false;
309
+ return;
310
+ }
311
+ logger.info("[PowerSyncProvider] Database initialized");
312
+ setDb(database);
313
+ setIsReady(true);
314
+ setIsInitializing(false);
315
+ healthMonitorRef.current?.setDatabase(database);
316
+ if (mergedSyncConfig.enableHealthMonitoring) {
317
+ healthMonitorRef.current?.start();
318
+ }
319
+ onReadyRef.current?.();
320
+ } catch (err) {
321
+ const initError = err instanceof Error ? err : new Error(String(err));
322
+ logger.error("[PowerSyncProvider] Initialization failed:", initError);
323
+ if (!controller.cancelled) {
324
+ setError(initError);
325
+ setIsInitializing(false);
326
+ onErrorRef.current?.(initError);
327
+ }
328
+ initializingRef.current = false;
329
+ }
330
+ };
331
+ initDatabase();
332
+ return () => {
333
+ controller.cancelled = true;
334
+ initializingRef.current = false;
335
+ };
336
+ }, [platform, dbFilename, schema, logger, mergedSyncConfig.enableHealthMonitoring]);
337
+ useEffect(() => {
338
+ if (__DEV__) {
339
+ console.log("[PowerSyncProvider] Connect effect triggered:", {
340
+ hasDb: !!db,
341
+ hasSession: !!session,
342
+ autoConnect: mergedSyncConfig.autoConnect,
343
+ syncModeState
344
+ });
345
+ }
346
+ logger.info("[PowerSyncProvider] Connect effect - db:", !!db, "session:", !!session, "autoConnect:", mergedSyncConfig.autoConnect, "syncModeLoaded:", syncModeState.loaded, "syncMode:", syncModeState.mode);
347
+ if (!db) {
348
+ logger.debug("[PowerSyncProvider] Connect effect - waiting for db");
349
+ return;
350
+ }
351
+ if (!session) {
352
+ logger.debug("[PowerSyncProvider] Connect effect - no session");
353
+ return;
354
+ }
355
+ if (!mergedSyncConfig.autoConnect) {
356
+ logger.debug("[PowerSyncProvider] Connect effect - autoConnect disabled");
357
+ return;
358
+ }
359
+ if (!syncModeState.loaded) {
360
+ logger.info("[PowerSyncProvider] Waiting for sync mode state to load...");
361
+ return;
362
+ }
363
+ if (syncModeState.mode === "offline") {
364
+ logger.debug("[PowerSyncProvider] Skipping connect - offline mode");
365
+ return;
366
+ }
367
+ const abortController = new AbortController();
368
+ const connectPowerSync = async () => {
369
+ try {
370
+ if (abortController.signal.aborted) {
371
+ logger.debug("[PowerSyncProvider] Connect aborted before start");
372
+ return;
373
+ }
374
+ setConnectionError(null);
375
+ if (connectorRef.current) {
376
+ connectorRef.current.destroy();
377
+ connectorRef.current = null;
378
+ }
379
+ if (abortController.signal.aborted) {
380
+ logger.debug("[PowerSyncProvider] Connect aborted after connector cleanup");
381
+ return;
382
+ }
383
+ const statusTracker_0 = statusTrackerRef.current;
384
+ const newConnector = new SupabaseConnector({
385
+ supabaseClient,
386
+ powerSyncUrl,
387
+ schemaRouter: connectorConfig?.schemaRouter,
388
+ crudHandler: connectorConfig?.crudHandler,
389
+ retryConfig: connectorConfig?.retryConfig,
390
+ logger,
391
+ // Conflict detection - enabled by default
392
+ conflictDetection: {
393
+ enabled: true
394
+ },
395
+ conflictBus,
396
+ // Check if uploads should be performed based on sync mode
397
+ shouldUpload: () => statusTrackerRef.current?.shouldUpload() ?? true,
398
+ // Clear failures when transaction succeeds
399
+ onTransactionSuccess: (entries) => {
400
+ if (!statusTracker_0) return;
401
+ const entityIds = extractEntityIds(entries);
402
+ entityIds.forEach((id) => {
403
+ const failures = statusTracker_0.getFailuresForEntity(id);
404
+ failures.forEach((f) => statusTracker_0.clearFailure(f.id));
405
+ });
406
+ setFailedTransactions(statusTracker_0.getFailedTransactions());
407
+ },
408
+ // Record failures when transaction fails
409
+ onTransactionFailure: (entries_0, error_0, classified) => {
410
+ if (!statusTracker_0) return;
411
+ statusTracker_0.recordTransactionFailure(entries_0, createSyncError(classified, error_0.message), classified.isPermanent, extractEntityIds(entries_0), extractTableNames(entries_0));
412
+ setFailedTransactions(statusTracker_0.getFailedTransactions());
413
+ },
414
+ // Record completed transactions
415
+ onTransactionComplete: (entries_1) => {
416
+ if (!statusTracker_0) return;
417
+ statusTracker_0.recordTransactionComplete(entries_1);
418
+ setCompletedTransactions(statusTracker_0.getCompletedTransactions());
419
+ setNewCompletedTransactions(statusTracker_0.getNewCompletedTransactions());
420
+ }
421
+ });
422
+ if (abortController.signal.aborted) {
423
+ logger.debug("[PowerSyncProvider] Connect aborted after connector creation, destroying new connector");
424
+ newConnector.destroy();
425
+ return;
426
+ }
427
+ setConnector(newConnector);
428
+ connectorRef.current = newConnector;
429
+ if (db.connected) {
430
+ logger.debug("[PowerSyncProvider] Already connected, reconnecting...");
431
+ await db.disconnect();
432
+ }
433
+ if (abortController.signal.aborted) {
434
+ logger.debug("[PowerSyncProvider] Connect aborted after disconnect");
435
+ return;
436
+ }
437
+ logger.info("[PowerSyncProvider] Connecting to PowerSync...");
438
+ await db.connect(newConnector);
439
+ if (abortController.signal.aborted) {
440
+ logger.debug("[PowerSyncProvider] Connect aborted after connection established");
441
+ return;
442
+ }
443
+ if (db.connected) {
444
+ logger.info("[PowerSyncProvider] Connected successfully");
445
+ healthMonitorRef.current?.resetReconnectAttempts();
446
+ } else {
447
+ logger.warn("[PowerSyncProvider] Connection initiated but streaming not established - check PowerSync URL");
448
+ }
449
+ } catch (err_0) {
450
+ if (abortController.signal.aborted) {
451
+ logger.debug("[PowerSyncProvider] Connect error ignored due to abort");
452
+ return;
453
+ }
454
+ const connectError = err_0 instanceof Error ? err_0 : new Error(String(err_0));
455
+ logger.error("[PowerSyncProvider] Connection failed:", connectError);
456
+ setConnectionError(connectError);
457
+ healthMonitorRef.current?.recordReconnectAttempt();
458
+ }
459
+ };
460
+ connectPowerSync();
461
+ return () => {
462
+ abortController.abort();
463
+ };
464
+ }, [db, session, powerSyncUrl, supabaseClient, connectorConfig, conflictBus, mergedSyncConfig.autoConnect, syncModeState, logger]);
465
+ useEffect(() => {
466
+ if (!db) return;
467
+ const initialStatus = db.currentStatus;
468
+ if (initialStatus) {
469
+ statusTrackerRef.current?.handleStatusChange(initialStatus);
470
+ }
471
+ const unsubscribe = db.registerListener({
472
+ statusChanged: (status_0) => {
473
+ statusTrackerRef.current?.handleStatusChange(status_0);
474
+ const dataFlow = status_0.dataFlowStatus;
475
+ const isDownloading = dataFlow?.downloading ?? false;
476
+ const isUploading = dataFlow?.uploading ?? false;
477
+ const progress = status_0.downloadProgress;
478
+ if (isDownloading && !wasSyncingRef.current) {
479
+ logger.info("[PowerSyncProvider] Downloading from server...");
480
+ metricsCollectorRef.current?.markSyncStart();
481
+ }
482
+ if (!isDownloading && wasSyncingRef.current) {
483
+ const duration = metricsCollectorRef.current?.markSyncEnd();
484
+ logger.info("[PowerSyncProvider] Download complete", duration ? `(${duration}ms)` : "");
485
+ if (duration !== null && duration !== void 0) {
486
+ metricsCollectorRef.current?.recordSync({
487
+ durationMs: duration,
488
+ success: true,
489
+ operationsDownloaded: progress?.totalOperations ?? 0
490
+ });
491
+ }
492
+ }
493
+ if (isUploading && !wasUploadingRef.current) {
494
+ logger.info("[PowerSyncProvider] Uploading local changes...");
495
+ }
496
+ if (!isUploading && wasUploadingRef.current) {
497
+ logger.info("[PowerSyncProvider] Upload complete");
498
+ }
499
+ wasSyncingRef.current = isDownloading;
500
+ wasUploadingRef.current = isUploading;
501
+ }
502
+ });
503
+ listenerUnsubscribeRef.current = unsubscribe;
504
+ return () => {
505
+ unsubscribe();
506
+ listenerUnsubscribeRef.current = null;
507
+ };
508
+ }, [db]);
509
+ const hydratePendingMutations = useCallback(async () => {
510
+ if (!db || dbClosedRef.current) {
511
+ return;
512
+ }
513
+ try {
514
+ const rows = await db.getAll("SELECT id, tx_id, data FROM ps_crud ORDER BY id ASC");
515
+ const mutations = rows.map((row) => {
516
+ try {
517
+ const parsed = JSON.parse(row.data);
518
+ let createdAt = /* @__PURE__ */ new Date();
519
+ if (parsed.data?._metadata) {
520
+ try {
521
+ const metadata = typeof parsed.data._metadata === "string" ? JSON.parse(parsed.data._metadata) : parsed.data._metadata;
522
+ if (metadata?.createdAt) {
523
+ createdAt = new Date(metadata.createdAt);
524
+ }
525
+ } catch {
526
+ }
527
+ }
528
+ return {
529
+ id: parsed.data?.id ?? parsed.id ?? row.id,
530
+ clientId: parseInt(row.id, 10) || 0,
531
+ op: parsed.op ?? "PUT",
532
+ table: parsed.type ?? "unknown",
533
+ opData: parsed.data,
534
+ transactionId: row.tx_id ?? void 0,
535
+ createdAt
536
+ };
537
+ } catch {
538
+ return null;
539
+ }
540
+ }).filter((e) => e !== null);
541
+ if (!dbClosedRef.current) {
542
+ statusTrackerRef.current?.updatePendingMutations(mutations);
543
+ setPendingMutations(mutations);
544
+ }
545
+ } catch {
546
+ }
547
+ }, [db]);
548
+ const addPendingMutation = useCallback((entry) => {
549
+ const entryWithTimestamp = {
550
+ ...entry,
551
+ createdAt: entry.createdAt ?? /* @__PURE__ */ new Date()
552
+ };
553
+ setPendingMutations((prev) => {
554
+ const newMutations = [...prev, entryWithTimestamp];
555
+ statusTrackerRef.current?.updatePendingMutations(newMutations);
556
+ return newMutations;
557
+ });
558
+ }, []);
559
+ const removePendingMutation = useCallback((id_0) => {
560
+ setPendingMutations((prev_0) => {
561
+ const newMutations_0 = prev_0.filter((m) => m.id !== id_0);
562
+ statusTrackerRef.current?.updatePendingMutations(newMutations_0);
563
+ return newMutations_0;
564
+ });
565
+ }, []);
566
+ useEffect(() => {
567
+ removePendingMutationRef.current = removePendingMutation;
568
+ }, [removePendingMutation]);
569
+ useEffect(() => {
570
+ if (!db) return;
571
+ dbClosedRef.current = false;
572
+ hydratePendingMutations();
573
+ }, [db, hydratePendingMutations]);
574
+ useEffect(() => {
575
+ if (!db || !attachmentConfig || attachmentQueueRef.current) {
576
+ return;
577
+ }
578
+ const controller_0 = {
579
+ cancelled: false
580
+ };
581
+ const initAttachmentQueue = async () => {
582
+ try {
583
+ logger.info("[PowerSyncProvider] Initializing attachment queue...");
584
+ const remoteStorage = new SupabaseStorageAdapter({
585
+ client: supabaseClient,
586
+ defaultBucket: attachmentConfig.bucket,
587
+ logger,
588
+ imageTransform: attachmentConfig.compression ? {
589
+ enabled: attachmentConfig.compression.enabled ?? true,
590
+ width: attachmentConfig.compression.maxWidth,
591
+ quality: attachmentConfig.compression.quality ? Math.round(attachmentConfig.compression.quality * 100) : void 0
592
+ } : void 0
593
+ }, platform.fileSystem);
594
+ const queueOptions = {
595
+ ...attachmentConfig,
596
+ remoteStorage
597
+ };
598
+ const queue = createPolAttachmentQueue(db, platform, queueOptions);
599
+ await queue.init();
600
+ if (controller_0.cancelled) {
601
+ queue.dispose();
602
+ return;
603
+ }
604
+ attachmentQueueRef.current = queue;
605
+ setAttachmentQueue(queue);
606
+ setAttachmentQueueReady(true);
607
+ logger.info("[PowerSyncProvider] Attachment queue initialized successfully");
608
+ } catch (err_1) {
609
+ if (!controller_0.cancelled) {
610
+ logger.error("[PowerSyncProvider] Attachment queue initialization failed:", err_1);
611
+ setAttachmentQueueReady(true);
612
+ }
613
+ }
614
+ };
615
+ initAttachmentQueue();
616
+ return () => {
617
+ controller_0.cancelled = true;
618
+ attachmentQueueRef.current?.dispose();
619
+ attachmentQueueRef.current = null;
620
+ setAttachmentQueueReady(false);
621
+ };
622
+ }, [db, attachmentConfig, platform, logger, supabaseClient]);
623
+ useEffect(() => {
624
+ return () => {
625
+ if (isCleaningUpRef.current) {
626
+ logger.debug("[PowerSyncProvider] Cleanup already in progress, skipping...");
627
+ return;
628
+ }
629
+ logger.info("[PowerSyncProvider] Cleaning up...");
630
+ isCleaningUpRef.current = true;
631
+ dbClosedRef.current = true;
632
+ connectorRef.current?.destroy();
633
+ connectorRef.current = null;
634
+ listenerUnsubscribeRef.current?.();
635
+ attachmentQueueRef.current?.dispose();
636
+ healthMonitorRef.current?.stop();
637
+ conflictBusRef.current?.destroy();
638
+ if (db) {
639
+ cleanupPromiseRef.current = (async () => {
640
+ try {
641
+ await db.disconnect();
642
+ await db.close();
643
+ logger.debug("[PowerSyncProvider] Database cleanup completed");
644
+ } catch (err_2) {
645
+ const errorMessage = err_2 instanceof Error ? err_2.message : String(err_2);
646
+ if (!errorMessage.includes("not open") && !errorMessage.includes("closed")) {
647
+ logger.warn("[PowerSyncProvider] Error during cleanup:", err_2);
648
+ }
649
+ } finally {
650
+ isCleaningUpRef.current = false;
651
+ cleanupPromiseRef.current = null;
652
+ }
653
+ })();
654
+ } else {
655
+ isCleaningUpRef.current = false;
656
+ }
657
+ };
658
+ }, [db, logger]);
659
+ useEffect(() => {
660
+ if (!isReady || !syncModeState.loaded) return;
661
+ const handleNetworkChange = async (isConnected) => {
662
+ const wasConnected = prevNetworkConnectedRef.current;
663
+ prevNetworkConnectedRef.current = isConnected;
664
+ const tracker = statusTrackerRef.current;
665
+ if (tracker) {
666
+ tracker.setNetworkReachable(isConnected);
667
+ }
668
+ setNetworkReachable(isConnected);
669
+ if (!autoOfflineInitializedRef.current) {
670
+ autoOfflineInitializedRef.current = true;
671
+ logger.debug("[PowerSyncProvider] Auto-offline initialized, network:", isConnected);
672
+ return;
673
+ }
674
+ if (wasConnected === true && !isConnected) {
675
+ logger.info("[PowerSyncProvider] Network lost - auto-entering offline mode");
676
+ const tracker_0 = statusTrackerRef.current;
677
+ if (tracker_0) {
678
+ await tracker_0.setIsAutoOffline(true);
679
+ setIsAutoOffline(true);
680
+ await tracker_0.setSyncMode("offline");
681
+ setSyncModeState({
682
+ loaded: true,
683
+ mode: "offline"
684
+ });
685
+ }
686
+ return;
687
+ }
688
+ if (wasConnected === false && isConnected) {
689
+ if (isAutoOfflineRef.current && syncModeRef.current === "offline") {
690
+ logger.info("[PowerSyncProvider] Network restored - auto-resuming sync");
691
+ const tracker_1 = statusTrackerRef.current;
692
+ if (tracker_1) {
693
+ await tracker_1.setIsAutoOffline(false);
694
+ setIsAutoOffline(false);
695
+ await tracker_1.setSyncMode("push-pull");
696
+ setSyncModeState({
697
+ loaded: true,
698
+ mode: "push-pull"
699
+ });
700
+ if (db && connector && !db.connected) {
701
+ try {
702
+ await db.connect(connector);
703
+ logger.info("[PowerSyncProvider] Reconnected after network restore");
704
+ } catch (err_3) {
705
+ logger.warn("[PowerSyncProvider] Failed to reconnect after network restore:", err_3);
706
+ }
707
+ }
708
+ }
709
+ } else {
710
+ logger.debug("[PowerSyncProvider] Network restored but not auto-resuming (manual offline or different mode)");
711
+ }
712
+ }
713
+ };
714
+ const unsubscribe_0 = platform.network.addConnectionListener(handleNetworkChange);
715
+ platform.network.isConnected().then((connected) => {
716
+ prevNetworkConnectedRef.current = connected;
717
+ autoOfflineInitializedRef.current = true;
718
+ const tracker_2 = statusTrackerRef.current;
719
+ if (tracker_2) {
720
+ tracker_2.setNetworkReachable(connected);
721
+ }
722
+ setNetworkReachable(connected);
723
+ if (connected && isAutoOfflineRef.current && syncModeRef.current === "offline") {
724
+ logger.info("[PowerSyncProvider] Network available on startup with auto-offline active, auto-resuming from offline");
725
+ if (tracker_2) {
726
+ tracker_2.setIsAutoOffline(false);
727
+ setIsAutoOffline(false);
728
+ tracker_2.setSyncMode("push-pull");
729
+ setSyncModeState({
730
+ loaded: true,
731
+ mode: "push-pull"
732
+ });
733
+ if (db && connector && !db.connected) {
734
+ db.connect(connector).then(() => {
735
+ logger.info("[PowerSyncProvider] Reconnected after auto-resume on startup");
736
+ }).catch((err_4) => {
737
+ logger.warn("[PowerSyncProvider] Failed to reconnect after auto-resume on startup:", err_4);
738
+ });
739
+ }
740
+ }
741
+ }
742
+ logger.debug("[PowerSyncProvider] Auto-offline ready, initial network:", connected);
743
+ });
744
+ return () => {
745
+ unsubscribe_0();
746
+ };
747
+ }, [isReady, syncModeState.loaded, syncModeState.mode, isAutoOffline, db, connector, platform, logger]);
748
+ const clearFailure = useCallback((failureId) => {
749
+ const tracker_3 = statusTrackerRef.current;
750
+ if (!tracker_3) {
751
+ logger.warn("[PowerSyncProvider] Cannot clear failure - tracker not initialized");
752
+ return;
753
+ }
754
+ tracker_3.clearFailure(failureId);
755
+ setFailedTransactions(tracker_3.getFailedTransactions());
756
+ }, [logger]);
757
+ const clearAllFailures = useCallback(() => {
758
+ const tracker_4 = statusTrackerRef.current;
759
+ if (!tracker_4) {
760
+ logger.warn("[PowerSyncProvider] Cannot clear failures - tracker not initialized");
761
+ return;
762
+ }
763
+ tracker_4.clearAllFailures();
764
+ setFailedTransactions(tracker_4.getFailedTransactions());
765
+ }, [logger]);
766
+ const clearCompletedHistory = useCallback(() => {
767
+ const tracker_5 = statusTrackerRef.current;
768
+ if (!tracker_5) {
769
+ logger.warn("[PowerSyncProvider] Cannot clear completed history - tracker not initialized");
770
+ return;
771
+ }
772
+ tracker_5.clearCompletedHistory();
773
+ setCompletedTransactions(tracker_5.getCompletedTransactions());
774
+ setNewCompletedTransactions(tracker_5.getNewCompletedTransactions());
775
+ }, [logger]);
776
+ const clearCompletedItem = useCallback((completedId) => {
777
+ const tracker_6 = statusTrackerRef.current;
778
+ if (!tracker_6) {
779
+ logger.warn("[PowerSyncProvider] Cannot clear completed item - tracker not initialized");
780
+ return;
781
+ }
782
+ tracker_6.clearCompletedItem(completedId);
783
+ setCompletedTransactions(tracker_6.getCompletedTransactions());
784
+ setNewCompletedTransactions(tracker_6.getNewCompletedTransactions());
785
+ }, [logger]);
786
+ const markNotificationsAsSeen = useCallback(() => {
787
+ const tracker_7 = statusTrackerRef.current;
788
+ if (!tracker_7) {
789
+ logger.warn("[PowerSyncProvider] Cannot mark notifications as seen - tracker not initialized");
790
+ return;
791
+ }
792
+ tracker_7.markNotificationsAsSeen();
793
+ setNewCompletedTransactions(tracker_7.getNewCompletedTransactions());
794
+ }, [logger]);
795
+ const setSyncMode = useCallback(async (mode) => {
796
+ const tracker_8 = statusTrackerRef.current;
797
+ if (!tracker_8) {
798
+ logger.warn("[PowerSyncProvider] Cannot set sync mode - tracker not initialized");
799
+ return;
800
+ }
801
+ await tracker_8.setIsAutoOffline(false);
802
+ setIsAutoOffline(false);
803
+ await tracker_8.setSyncMode(mode);
804
+ setSyncModeState({
805
+ loaded: true,
806
+ mode
807
+ });
808
+ }, [logger]);
809
+ const setForceNextUpload = useCallback((force) => {
810
+ const tracker_9 = statusTrackerRef.current;
811
+ if (!tracker_9) {
812
+ logger.warn("[PowerSyncProvider] Cannot set force upload - tracker not initialized");
813
+ return;
814
+ }
815
+ tracker_9.setForceNextUpload(force);
816
+ }, [logger]);
817
+ const setAutoOfflineMode = useCallback(async (mode_0, isAuto) => {
818
+ const tracker_10 = statusTrackerRef.current;
819
+ if (!tracker_10) {
820
+ logger.warn("[PowerSyncProvider] Cannot set sync mode - tracker not initialized");
821
+ return;
822
+ }
823
+ await tracker_10.setIsAutoOffline(isAuto);
824
+ setIsAutoOffline(isAuto);
825
+ await tracker_10.setSyncMode(mode_0);
826
+ setSyncModeState({
827
+ loaded: true,
828
+ mode: mode_0
829
+ });
830
+ }, [logger]);
831
+ const discardPendingMutation = useCallback(async (clientId) => {
832
+ if (!db || !connector) {
833
+ logger.warn("[PowerSync] Cannot discard - not initialized");
834
+ return;
835
+ }
836
+ if (syncStatus.uploading) {
837
+ throw new Error("Cannot discard while upload is in progress");
838
+ }
839
+ logger.info("[PowerSync] Discarding pending mutation:", clientId);
840
+ await db.disconnect();
841
+ try {
842
+ await db.execute("DELETE FROM ps_crud WHERE id = ?", [clientId]);
843
+ logger.info("[PowerSync] Mutation discarded successfully");
844
+ } finally {
845
+ const currentConnector = connectorRef.current;
846
+ if (currentConnector && db) {
847
+ try {
848
+ await db.connect(currentConnector);
849
+ } catch (reconnectError) {
850
+ logger.error("[PowerSync] Failed to reconnect after discard:", reconnectError);
851
+ throw reconnectError;
852
+ }
853
+ }
854
+ }
855
+ }, [db, connector, syncStatus.uploading, logger]);
856
+ const discardAllPendingMutations = useCallback(async () => {
857
+ if (!db || !connector) {
858
+ logger.warn("[PowerSync] Cannot discard all - not initialized");
859
+ return;
860
+ }
861
+ if (syncStatus.uploading) {
862
+ throw new Error("Cannot discard while upload is in progress");
863
+ }
864
+ logger.info("[PowerSync] Discarding all pending mutations");
865
+ await db.disconnect();
866
+ try {
867
+ await db.execute("DELETE FROM ps_crud");
868
+ logger.info("[PowerSync] All mutations discarded successfully");
869
+ } finally {
870
+ const currentConnector = connectorRef.current;
871
+ if (currentConnector && db) {
872
+ try {
873
+ await db.connect(currentConnector);
874
+ } catch (reconnectError) {
875
+ logger.error("[PowerSync] Failed to reconnect after discard:", reconnectError);
876
+ throw reconnectError;
877
+ }
878
+ }
879
+ }
880
+ }, [db, connector, syncStatus.uploading, logger]);
881
+ const pauseAutoRetry = useCallback(() => {
882
+ if (!connector) {
883
+ logger.warn("[PowerSyncProvider] Cannot pause auto-retry - connector not initialized");
884
+ return;
885
+ }
886
+ connector.pauseAutoRetry();
887
+ }, [connector, logger]);
888
+ const resumeAutoRetry = useCallback(() => {
889
+ if (!connector) {
890
+ logger.warn("[PowerSyncProvider] Cannot resume auto-retry - connector not initialized");
891
+ return;
892
+ }
893
+ connector.resumeAutoRetry();
894
+ }, [connector, logger]);
895
+ const retryFailure = useCallback(async (failureId_0) => {
896
+ const tracker_11 = statusTrackerRef.current;
897
+ if (!tracker_11) return;
898
+ const failures_0 = tracker_11.getFailedTransactions();
899
+ const failure = failures_0.find((f_0) => f_0.id === failureId_0);
900
+ if (!failure) {
901
+ logger.warn("[PowerSyncProvider] Failure not found:", failureId_0);
902
+ return;
903
+ }
904
+ const entries_2 = tracker_11.takeFailureForRetry(failureId_0);
905
+ if (!entries_2 || entries_2.length === 0) return;
906
+ setFailedTransactions(tracker_11.getFailedTransactions());
907
+ if (!db || !connector) {
908
+ logger.warn("[PowerSyncProvider] Cannot retry - not initialized");
909
+ tracker_11.recordTransactionFailure(failure.entries, failure.error, failure.isPermanent, failure.affectedEntityIds, failure.affectedTables, {
910
+ retryCount: failure.retryCount,
911
+ firstFailedAt: failure.firstFailedAt
912
+ });
913
+ setFailedTransactions(tracker_11.getFailedTransactions());
914
+ return;
915
+ }
916
+ try {
917
+ if (db.connected) {
918
+ await db.disconnect();
919
+ }
920
+ await db.connect(connector);
921
+ logger.info("[PowerSyncProvider] Retry triggered for failure:", failureId_0);
922
+ } catch (err_5) {
923
+ logger.error("[PowerSyncProvider] Retry failed, re-recording failure:", err_5);
924
+ tracker_11.recordTransactionFailure(failure.entries, failure.error, failure.isPermanent, failure.affectedEntityIds, failure.affectedTables, {
925
+ retryCount: failure.retryCount,
926
+ firstFailedAt: failure.firstFailedAt
927
+ });
928
+ setFailedTransactions(tracker_11.getFailedTransactions());
929
+ }
930
+ }, [db, connector, logger]);
931
+ const powerSyncContextValue = useMemo(() => ({
932
+ db,
933
+ connector,
934
+ attachmentQueue,
935
+ isReady,
936
+ isInitializing,
937
+ attachmentQueueReady,
938
+ error,
939
+ schema,
940
+ platform,
941
+ conflictBus
942
+ }), [db, connector, attachmentQueue, isReady, isInitializing, attachmentQueueReady, error, schema, platform, conflictBus]);
943
+ const syncStatusContextValue = useMemo(() => ({
944
+ status: syncStatus,
945
+ pendingMutations,
946
+ pendingCount: pendingMutations.length,
947
+ // Expose uploading/downloading directly from syncStatus for reliable activity detection
948
+ isUploading: syncStatus.uploading,
949
+ isDownloading: syncStatus.downloading,
950
+ isPaused: syncModeState.mode === "offline",
951
+ syncMode: syncModeState.mode,
952
+ lastSyncedAt,
953
+ // Connection error for consumers to display
954
+ connectionError,
955
+ // Failed transaction fields
956
+ failedTransactions,
957
+ hasUploadErrors: failedTransactions.length > 0,
958
+ permanentErrorCount: failedTransactions.filter((f_1) => f_1.isPermanent).length,
959
+ // Clear failure functions
960
+ clearFailure,
961
+ clearAllFailures,
962
+ // Completed transaction fields
963
+ completedTransactions,
964
+ clearCompletedHistory,
965
+ // Sync mode control functions
966
+ setSyncMode,
967
+ setForceNextUpload,
968
+ // Discard mutation functions
969
+ discardPendingMutation,
970
+ discardAllPendingMutations,
971
+ // Retry control functions
972
+ pauseAutoRetry,
973
+ resumeAutoRetry
974
+ }), [syncStatus, pendingMutations, syncModeState.mode, lastSyncedAt, connectionError, failedTransactions, clearFailure, clearAllFailures, completedTransactions, clearCompletedHistory, setSyncMode, setForceNextUpload, discardPendingMutation, discardAllPendingMutations, pauseAutoRetry, resumeAutoRetry]);
975
+ const connectionHealthContextValue = useMemo(() => ({
976
+ health: connectionHealth
977
+ }), [connectionHealth]);
978
+ const syncMetricsContextValue = useMemo(() => ({
979
+ metrics: syncMetrics
980
+ }), [syncMetrics]);
981
+ const connectionStatusValue = useMemo(() => ({
982
+ connected: syncStatus.connected,
983
+ connecting: syncStatus.connecting,
984
+ hasSynced: syncStatus.hasSynced,
985
+ lastSyncedAt,
986
+ connectionError
987
+ }), [syncStatus.connected, syncStatus.connecting, syncStatus.hasSynced, lastSyncedAt, connectionError]);
988
+ const syncActivityValue = useMemo(() => ({
989
+ uploading: syncStatus.uploading,
990
+ downloading: syncStatus.downloading,
991
+ downloadProgress: syncStatus.downloadProgress
992
+ }), [syncStatus.uploading, syncStatus.downloading, syncStatus.downloadProgress]);
993
+ const pendingMutationsValue = useMemo(() => ({
994
+ pendingMutations,
995
+ pendingCount: pendingMutations.length,
996
+ discardPendingMutation,
997
+ discardAllPendingMutations,
998
+ addPendingMutation,
999
+ removePendingMutation
1000
+ }), [pendingMutations, discardPendingMutation, discardAllPendingMutations, addPendingMutation, removePendingMutation]);
1001
+ const failedTransactionsValue = useMemo(() => ({
1002
+ failedTransactions,
1003
+ hasUploadErrors: failedTransactions.length > 0,
1004
+ permanentErrorCount: failedTransactions.filter((f_2) => f_2.isPermanent).length,
1005
+ clearFailure,
1006
+ clearAllFailures,
1007
+ pauseAutoRetry,
1008
+ resumeAutoRetry,
1009
+ retryFailure
1010
+ }), [failedTransactions, clearFailure, clearAllFailures, pauseAutoRetry, resumeAutoRetry, retryFailure]);
1011
+ const completedTransactionsValue = useMemo(() => ({
1012
+ completedTransactions,
1013
+ clearCompletedHistory,
1014
+ clearCompletedItem,
1015
+ newCompletedTransactions,
1016
+ markNotificationsAsSeen
1017
+ }), [completedTransactions, clearCompletedHistory, clearCompletedItem, newCompletedTransactions, markNotificationsAsSeen]);
1018
+ const syncModeValue = useMemo(() => ({
1019
+ syncMode: syncModeState.mode,
1020
+ isPaused: syncModeState.mode === "offline",
1021
+ isAutoOffline,
1022
+ networkReachable,
1023
+ setSyncMode,
1024
+ setForceNextUpload
1025
+ }), [syncModeState.mode, isAutoOffline, networkReachable, setSyncMode, setForceNextUpload]);
1026
+ return /* @__PURE__ */ jsx(PowerSyncContext.Provider, { value: powerSyncContextValue, children: /* @__PURE__ */ jsx(ConnectionStatusContext.Provider, { value: connectionStatusValue, children: /* @__PURE__ */ jsx(SyncActivityContext.Provider, { value: syncActivityValue, children: /* @__PURE__ */ jsx(PendingMutationsContext.Provider, { value: pendingMutationsValue, children: /* @__PURE__ */ jsx(FailedTransactionsContext.Provider, { value: failedTransactionsValue, children: /* @__PURE__ */ jsx(CompletedTransactionsContext.Provider, { value: completedTransactionsValue, children: /* @__PURE__ */ jsx(SyncModeContext.Provider, { value: syncModeValue, children: /* @__PURE__ */ jsx(SyncStatusContext.Provider, { value: syncStatusContextValue, children: /* @__PURE__ */ jsx(ConnectionHealthContext.Provider, { value: connectionHealthContextValue, children: /* @__PURE__ */ jsx(SyncMetricsContext.Provider, { value: syncMetricsContextValue, children: /* @__PURE__ */ jsx(AttachmentQueueContext.Provider, { value: attachmentQueue, children }) }) }) }) }) }) }) }) }) }) });
1027
+ }
1028
+
1029
+ // src/provider/OfflineDataProvider.tsx
1030
+ import { c as _c } from "react/compiler-runtime";
1031
+ import { useEffect as useEffect3, useRef as useRef3, useState as useState2 } from "react";
1032
+ import { View, Text, StyleSheet, Pressable } from "react-native";
1033
+ import { DataLayerProvider } from "@pol-studios/db";
1034
+
1035
+ // src/provider/ProviderBridge.tsx
1036
+ import { useEffect as useEffect2, useRef as useRef2 } from "react";
1037
+ import { PowerSyncContext as PowerSyncContext2 } from "@powersync/react-native";
1038
+ import { StorageQueueProvider, ConflictProvider } from "@pol-studios/db";
1039
+ import { Fragment, jsx as jsx2 } from "react/jsx-runtime";
1040
+ function ProviderBridge({
1041
+ children,
1042
+ skipConflictProvider = false,
1043
+ skipStorageQueueProvider = false,
1044
+ backgroundSync,
1045
+ onBackgroundSyncSystemReady,
1046
+ onDbReady,
1047
+ onSyncStatusChange,
1048
+ onAddPendingMutationReady,
1049
+ onRemovePendingMutationReady
1050
+ }) {
1051
+ const {
1052
+ db,
1053
+ attachmentQueue,
1054
+ isReady,
1055
+ attachmentQueueReady,
1056
+ conflictBus,
1057
+ platform
1058
+ } = usePowerSync();
1059
+ const {
1060
+ status: syncStatus
1061
+ } = useSyncStatus();
1062
+ const {
1063
+ addPendingMutation,
1064
+ removePendingMutation
1065
+ } = usePendingMutationsContext();
1066
+ const isOnline = useOnlineStatus();
1067
+ const onDbReadyRef = useRef2(onDbReady);
1068
+ const onSyncStatusChangeRef = useRef2(onSyncStatusChange);
1069
+ useEffect2(() => {
1070
+ onDbReadyRef.current = onDbReady;
1071
+ }, [onDbReady]);
1072
+ useEffect2(() => {
1073
+ onSyncStatusChangeRef.current = onSyncStatusChange;
1074
+ }, [onSyncStatusChange]);
1075
+ const hasSignalledReady = useRef2(false);
1076
+ useEffect2(() => {
1077
+ if (!isReady) return;
1078
+ platform.logger.debug("[ProviderBridge] Passing pending mutation functions to parent");
1079
+ onAddPendingMutationReady(addPendingMutation);
1080
+ onRemovePendingMutationReady(removePendingMutation);
1081
+ }, [isReady, addPendingMutation, removePendingMutation, onAddPendingMutationReady, onRemovePendingMutationReady, platform]);
1082
+ useEffect2(() => {
1083
+ if (!isReady || !db) return;
1084
+ const snapshot = {
1085
+ hasSynced: syncStatus.hasSynced,
1086
+ connected: syncStatus.connected,
1087
+ connecting: syncStatus.connecting,
1088
+ isOnline
1089
+ };
1090
+ if (!hasSignalledReady.current) {
1091
+ hasSignalledReady.current = true;
1092
+ onDbReadyRef.current(db, snapshot);
1093
+ } else {
1094
+ onSyncStatusChangeRef.current(snapshot);
1095
+ }
1096
+ }, [isReady, db, syncStatus.hasSynced, syncStatus.connected, syncStatus.connecting, isOnline]);
1097
+ useEffect2(() => {
1098
+ if (!isReady || !db || !backgroundSync?.enabled) return;
1099
+ const backgroundSystem = {
1100
+ init: async () => {
1101
+ if (!db.connected) {
1102
+ platform.logger.info("[Background Sync] DB not connected, waiting for connection...");
1103
+ }
1104
+ },
1105
+ disconnect: async () => {
1106
+ await db.disconnect();
1107
+ },
1108
+ isConnected: () => db.connected,
1109
+ getDatabase: () => db,
1110
+ onStatusChange: (callback) => {
1111
+ return db.registerListener({
1112
+ statusChanged: (status) => {
1113
+ callback({
1114
+ lastSyncedAt: status.lastSyncedAt ?? null,
1115
+ downloading: status.dataFlowStatus?.downloading ?? false,
1116
+ uploading: status.dataFlowStatus?.uploading ?? false
1117
+ });
1118
+ }
1119
+ });
1120
+ }
1121
+ };
1122
+ onBackgroundSyncSystemReady?.(backgroundSystem);
1123
+ return () => {
1124
+ onBackgroundSyncSystemReady?.(null);
1125
+ };
1126
+ }, [isReady, db, backgroundSync?.enabled, onBackgroundSyncSystemReady, platform]);
1127
+ if (!isReady) {
1128
+ return null;
1129
+ }
1130
+ let content = children;
1131
+ if (!skipStorageQueueProvider) {
1132
+ content = /* @__PURE__ */ jsx2(StorageQueueProvider, { attachmentQueue, isReady: attachmentQueueReady, children: content });
1133
+ }
1134
+ if (!skipConflictProvider) {
1135
+ content = /* @__PURE__ */ jsx2(ConflictProvider, { conflictBus, children: content });
1136
+ }
1137
+ if (db) {
1138
+ return (
1139
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1140
+ /* @__PURE__ */ jsx2(PowerSyncContext2.Provider, { value: db, children: content })
1141
+ );
1142
+ }
1143
+ return /* @__PURE__ */ jsx2(Fragment, { children: content });
1144
+ }
1145
+
1146
+ // src/provider/OfflineDataProvider.tsx
1147
+ import { Fragment as Fragment2, jsx as jsx3, jsxs } from "react/jsx-runtime";
1148
+ var defaultLogger = {
1149
+ debug: (...args) => console.debug("[OfflineData]", ...args),
1150
+ info: (...args) => console.info("[OfflineData]", ...args),
1151
+ warn: (...args) => console.warn("[OfflineData]", ...args),
1152
+ error: (...args) => console.error("[OfflineData]", ...args)
1153
+ };
1154
+ var errorStyles = StyleSheet.create({
1155
+ container: {
1156
+ flex: 1,
1157
+ justifyContent: "center",
1158
+ alignItems: "center",
1159
+ backgroundColor: "#f5f5f5",
1160
+ padding: 20
1161
+ },
1162
+ content: {
1163
+ backgroundColor: "white",
1164
+ borderRadius: 12,
1165
+ padding: 24,
1166
+ maxWidth: 400,
1167
+ width: "100%",
1168
+ shadowColor: "#000",
1169
+ shadowOffset: {
1170
+ width: 0,
1171
+ height: 2
1172
+ },
1173
+ shadowOpacity: 0.1,
1174
+ shadowRadius: 8,
1175
+ elevation: 4
1176
+ },
1177
+ title: {
1178
+ fontSize: 20,
1179
+ fontWeight: "600",
1180
+ color: "#1a1a1a",
1181
+ marginBottom: 12,
1182
+ textAlign: "center"
1183
+ },
1184
+ message: {
1185
+ fontSize: 14,
1186
+ color: "#666",
1187
+ marginBottom: 16,
1188
+ textAlign: "center",
1189
+ lineHeight: 20
1190
+ },
1191
+ errorDetail: {
1192
+ fontSize: 12,
1193
+ color: "#999",
1194
+ marginBottom: 20,
1195
+ textAlign: "center",
1196
+ fontFamily: "monospace"
1197
+ },
1198
+ retryButton: {
1199
+ backgroundColor: "#007AFF",
1200
+ borderRadius: 8,
1201
+ paddingVertical: 12,
1202
+ paddingHorizontal: 24,
1203
+ alignItems: "center"
1204
+ },
1205
+ retryButtonText: {
1206
+ color: "white",
1207
+ fontSize: 16,
1208
+ fontWeight: "600"
1209
+ }
1210
+ });
1211
+ function DefaultErrorRecoveryUI(t0) {
1212
+ const $ = _c(10);
1213
+ const {
1214
+ error,
1215
+ onRetry
1216
+ } = t0;
1217
+ let t1;
1218
+ let t2;
1219
+ if ($[0] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
1220
+ t1 = /* @__PURE__ */ jsx3(Text, { style: errorStyles.title, children: "Database Error" });
1221
+ t2 = /* @__PURE__ */ jsx3(Text, { style: errorStyles.message, children: "The local database encountered an error. This can happen if the app was interrupted during startup." });
1222
+ $[0] = t1;
1223
+ $[1] = t2;
1224
+ } else {
1225
+ t1 = $[0];
1226
+ t2 = $[1];
1227
+ }
1228
+ let t3;
1229
+ if ($[2] !== error.message) {
1230
+ t3 = /* @__PURE__ */ jsx3(Text, { style: errorStyles.errorDetail, children: error.message });
1231
+ $[2] = error.message;
1232
+ $[3] = t3;
1233
+ } else {
1234
+ t3 = $[3];
1235
+ }
1236
+ let t4;
1237
+ if ($[4] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
1238
+ t4 = /* @__PURE__ */ jsx3(Text, { style: errorStyles.retryButtonText, children: "Retry" });
1239
+ $[4] = t4;
1240
+ } else {
1241
+ t4 = $[4];
1242
+ }
1243
+ let t5;
1244
+ if ($[5] !== onRetry) {
1245
+ t5 = /* @__PURE__ */ jsx3(Pressable, { style: errorStyles.retryButton, onPress: onRetry, children: t4 });
1246
+ $[5] = onRetry;
1247
+ $[6] = t5;
1248
+ } else {
1249
+ t5 = $[6];
1250
+ }
1251
+ let t6;
1252
+ if ($[7] !== t3 || $[8] !== t5) {
1253
+ t6 = /* @__PURE__ */ jsx3(View, { style: errorStyles.container, children: /* @__PURE__ */ jsxs(View, { style: errorStyles.content, children: [
1254
+ t1,
1255
+ t2,
1256
+ t3,
1257
+ t5
1258
+ ] }) });
1259
+ $[7] = t3;
1260
+ $[8] = t5;
1261
+ $[9] = t6;
1262
+ } else {
1263
+ t6 = $[9];
1264
+ }
1265
+ return t6;
1266
+ }
1267
+ function OfflineDataProvider(t0) {
1268
+ const $ = _c(106);
1269
+ const {
1270
+ config,
1271
+ children,
1272
+ dataLayer,
1273
+ backgroundSync,
1274
+ skipConflictProvider: t1,
1275
+ skipStorageQueueProvider: t2,
1276
+ storageBackend,
1277
+ renderInitError,
1278
+ renderError,
1279
+ onReady,
1280
+ onError,
1281
+ onSyncStatusChange,
1282
+ onBackgroundSyncSystemReady: onBackgroundSyncSystemReadyProp
1283
+ } = t0;
1284
+ const skipConflictProvider = t1 === void 0 ? false : t1;
1285
+ const skipStorageQueueProvider = t2 === void 0 ? false : t2;
1286
+ const {
1287
+ schema,
1288
+ supabaseClient,
1289
+ queryClient,
1290
+ powerSyncUrl,
1291
+ dbFilename: t3,
1292
+ attachments,
1293
+ platform: customPlatform,
1294
+ connector: connectorConfig,
1295
+ sync: syncConfig
1296
+ } = config;
1297
+ const dbFilename = t3 === void 0 ? "powersync.db" : t3;
1298
+ const [initError, setInitError] = useState2(null);
1299
+ const [retryKey, setRetryKey] = useState2(0);
1300
+ const [powerSyncInstance, setPowerSyncInstance] = useState2(null);
1301
+ const [powerSyncSyncStatus, setPowerSyncSyncStatus] = useState2(void 0);
1302
+ const addPendingMutationRef = useRef3(null);
1303
+ const removePendingMutationRef = useRef3(null);
1304
+ const backgroundSyncSystemRef = useRef3(null);
1305
+ let t4;
1306
+ if ($[0] !== customPlatform) {
1307
+ t4 = customPlatform ?? createNativePlatformAdapter(defaultLogger);
1308
+ $[0] = customPlatform;
1309
+ $[1] = t4;
1310
+ } else {
1311
+ t4 = $[1];
1312
+ }
1313
+ const platform = t4;
1314
+ let t10;
1315
+ let t5;
1316
+ let t6;
1317
+ let t7;
1318
+ let t8;
1319
+ let t9;
1320
+ if ($[2] !== platform.logger) {
1321
+ t5 = async () => {
1322
+ platform.logger.warn("Sync not available: Use useSyncControl from PowerSync context");
1323
+ };
1324
+ t6 = async () => {
1325
+ platform.logger.warn("Live sync not available: Use useSyncControl from PowerSync context");
1326
+ };
1327
+ t7 = () => {
1328
+ platform.logger.warn("Live sync not available: Use useSyncControl from PowerSync context");
1329
+ };
1330
+ t8 = async () => {
1331
+ platform.logger.warn("Scope control not available: Use useSyncControl from PowerSync context");
1332
+ };
1333
+ t9 = async () => {
1334
+ platform.logger.warn("Retry not available: Use useSyncControl from PowerSync context");
1335
+ };
1336
+ t10 = () => {
1337
+ platform.logger.warn("Clear failed uploads not available: Use useSyncControl from PowerSync context");
1338
+ };
1339
+ $[2] = platform.logger;
1340
+ $[3] = t10;
1341
+ $[4] = t5;
1342
+ $[5] = t6;
1343
+ $[6] = t7;
1344
+ $[7] = t8;
1345
+ $[8] = t9;
1346
+ } else {
1347
+ t10 = $[3];
1348
+ t5 = $[4];
1349
+ t6 = $[5];
1350
+ t7 = $[6];
1351
+ t8 = $[7];
1352
+ t9 = $[8];
1353
+ }
1354
+ let t11;
1355
+ if ($[9] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
1356
+ t11 = [];
1357
+ $[9] = t11;
1358
+ } else {
1359
+ t11 = $[9];
1360
+ }
1361
+ let t12;
1362
+ let t13;
1363
+ if ($[10] !== platform.logger) {
1364
+ t12 = () => {
1365
+ platform.logger.warn("Pause auto-retry not available: Use useSyncControl from PowerSync context");
1366
+ };
1367
+ t13 = () => {
1368
+ platform.logger.warn("Resume auto-retry not available: Use useSyncControl from PowerSync context");
1369
+ };
1370
+ $[10] = platform.logger;
1371
+ $[11] = t12;
1372
+ $[12] = t13;
1373
+ } else {
1374
+ t12 = $[11];
1375
+ t13 = $[12];
1376
+ }
1377
+ let t14;
1378
+ let t15;
1379
+ if ($[13] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
1380
+ t14 = (entry) => {
1381
+ if (addPendingMutationRef.current) {
1382
+ addPendingMutationRef.current(entry);
1383
+ }
1384
+ };
1385
+ t15 = (id) => {
1386
+ if (removePendingMutationRef.current) {
1387
+ removePendingMutationRef.current(id);
1388
+ }
1389
+ };
1390
+ $[13] = t14;
1391
+ $[14] = t15;
1392
+ } else {
1393
+ t14 = $[13];
1394
+ t15 = $[14];
1395
+ }
1396
+ let t16;
1397
+ if ($[15] !== t10 || $[16] !== t12 || $[17] !== t13 || $[18] !== t5 || $[19] !== t6 || $[20] !== t7 || $[21] !== t8 || $[22] !== t9) {
1398
+ t16 = {
1399
+ triggerSync: t5,
1400
+ startLiveSync: t6,
1401
+ stopLiveSync: t7,
1402
+ setScope: t8,
1403
+ retryFailedUploads: t9,
1404
+ clearFailedUploads: t10,
1405
+ failedUploads: t11,
1406
+ pauseAutoRetry: t12,
1407
+ resumeAutoRetry: t13,
1408
+ isAutoRetryPaused: false,
1409
+ addPendingMutation: t14,
1410
+ removePendingMutation: t15
1411
+ };
1412
+ $[15] = t10;
1413
+ $[16] = t12;
1414
+ $[17] = t13;
1415
+ $[18] = t5;
1416
+ $[19] = t6;
1417
+ $[20] = t7;
1418
+ $[21] = t8;
1419
+ $[22] = t9;
1420
+ $[23] = t16;
1421
+ } else {
1422
+ t16 = $[23];
1423
+ }
1424
+ const syncControl = t16;
1425
+ let t17;
1426
+ bb0: {
1427
+ if (!attachments) {
1428
+ t17 = void 0;
1429
+ break bb0;
1430
+ }
1431
+ let t182;
1432
+ if ($[24] !== attachments.bucket || $[25] !== storageBackend || $[26] !== supabaseClient) {
1433
+ t182 = supabaseClient ? createSupabaseUploadHandler(supabaseClient, {
1434
+ defaultBucket: attachments.bucket,
1435
+ resolver: storageBackend?.resolveBucket?.bind(storageBackend)
1436
+ }) : void 0;
1437
+ $[24] = attachments.bucket;
1438
+ $[25] = storageBackend;
1439
+ $[26] = supabaseClient;
1440
+ $[27] = t182;
1441
+ } else {
1442
+ t182 = $[27];
1443
+ }
1444
+ const nativeUploadHandler = t182;
1445
+ const t192 = storageBackend;
1446
+ let t202;
1447
+ if ($[28] !== attachments.bucket || $[29] !== attachments.compression || $[30] !== attachments.download || $[31] !== attachments.maxCacheBytes || $[32] !== attachments.onUploadComplete || $[33] !== attachments.onUploadFailed || $[34] !== attachments.skipDownload || $[35] !== attachments.watchIds || $[36] !== nativeUploadHandler || $[37] !== t192) {
1448
+ t202 = {
1449
+ bucket: attachments.bucket,
1450
+ watchIds: attachments.watchIds,
1451
+ skipDownload: attachments.skipDownload,
1452
+ onUploadComplete: attachments.onUploadComplete,
1453
+ onUploadFailed: attachments.onUploadFailed,
1454
+ maxCacheBytes: attachments.maxCacheBytes,
1455
+ compression: attachments.compression,
1456
+ download: attachments.download,
1457
+ remoteStorage: t192,
1458
+ uploadHandler: nativeUploadHandler
1459
+ };
1460
+ $[28] = attachments.bucket;
1461
+ $[29] = attachments.compression;
1462
+ $[30] = attachments.download;
1463
+ $[31] = attachments.maxCacheBytes;
1464
+ $[32] = attachments.onUploadComplete;
1465
+ $[33] = attachments.onUploadFailed;
1466
+ $[34] = attachments.skipDownload;
1467
+ $[35] = attachments.watchIds;
1468
+ $[36] = nativeUploadHandler;
1469
+ $[37] = t192;
1470
+ $[38] = t202;
1471
+ } else {
1472
+ t202 = $[38];
1473
+ }
1474
+ t17 = t202;
1475
+ }
1476
+ const attachmentConfig = t17;
1477
+ const t18 = powerSyncUrl ?? "";
1478
+ const t19 = syncConfig?.autoConnect ?? true;
1479
+ const t20 = syncConfig?.enableHealthMonitoring ?? true;
1480
+ const t21 = syncConfig?.enableMetrics ?? true;
1481
+ let t22;
1482
+ if ($[39] !== t19 || $[40] !== t20 || $[41] !== t21) {
1483
+ t22 = {
1484
+ autoConnect: t19,
1485
+ enableHealthMonitoring: t20,
1486
+ enableMetrics: t21
1487
+ };
1488
+ $[39] = t19;
1489
+ $[40] = t20;
1490
+ $[41] = t21;
1491
+ $[42] = t22;
1492
+ } else {
1493
+ t22 = $[42];
1494
+ }
1495
+ let t23;
1496
+ if ($[43] !== attachmentConfig || $[44] !== connectorConfig || $[45] !== dbFilename || $[46] !== platform || $[47] !== queryClient || $[48] !== schema || $[49] !== supabaseClient || $[50] !== t18 || $[51] !== t22) {
1497
+ t23 = {
1498
+ platform,
1499
+ schema,
1500
+ powerSyncUrl: t18,
1501
+ supabaseClient,
1502
+ queryClient,
1503
+ dbFilename,
1504
+ connector: connectorConfig,
1505
+ attachments: attachmentConfig,
1506
+ sync: t22
1507
+ };
1508
+ $[43] = attachmentConfig;
1509
+ $[44] = connectorConfig;
1510
+ $[45] = dbFilename;
1511
+ $[46] = platform;
1512
+ $[47] = queryClient;
1513
+ $[48] = schema;
1514
+ $[49] = supabaseClient;
1515
+ $[50] = t18;
1516
+ $[51] = t22;
1517
+ $[52] = t23;
1518
+ } else {
1519
+ t23 = $[52];
1520
+ }
1521
+ const powerSyncConfig = t23;
1522
+ let t24;
1523
+ if ($[53] !== onError || $[54] !== platform.logger) {
1524
+ t24 = (err) => {
1525
+ platform.logger.error("PowerSync error:", err);
1526
+ const errorMessage = err.message ?? "";
1527
+ if (errorMessage.includes("not open") || errorMessage.includes("closed") || errorMessage.includes("failed to open") || errorMessage.includes("initialization failed")) {
1528
+ setInitError(err);
1529
+ }
1530
+ onError?.(err);
1531
+ };
1532
+ $[53] = onError;
1533
+ $[54] = platform.logger;
1534
+ $[55] = t24;
1535
+ } else {
1536
+ t24 = $[55];
1537
+ }
1538
+ const handlePowerSyncError = t24;
1539
+ let t25;
1540
+ if ($[56] !== platform.logger) {
1541
+ t25 = () => {
1542
+ platform.logger.info("Retrying PowerSync initialization...");
1543
+ setInitError(null);
1544
+ setRetryKey(_temp);
1545
+ };
1546
+ $[56] = platform.logger;
1547
+ $[57] = t25;
1548
+ } else {
1549
+ t25 = $[57];
1550
+ }
1551
+ const handleRetry = t25;
1552
+ let t26;
1553
+ if ($[58] !== backgroundSync?.callbacks || $[59] !== onBackgroundSyncSystemReadyProp || $[60] !== platform.logger) {
1554
+ t26 = (system) => {
1555
+ backgroundSyncSystemRef.current = system;
1556
+ backgroundSync?.callbacks?.onSyncStart?.();
1557
+ onBackgroundSyncSystemReadyProp?.(system);
1558
+ platform.logger.info("[Background Sync] System ready");
1559
+ };
1560
+ $[58] = backgroundSync?.callbacks;
1561
+ $[59] = onBackgroundSyncSystemReadyProp;
1562
+ $[60] = platform.logger;
1563
+ $[61] = t26;
1564
+ } else {
1565
+ t26 = $[61];
1566
+ }
1567
+ backgroundSync?.callbacks;
1568
+ const handleBackgroundSyncSystemReady = t26;
1569
+ let t27;
1570
+ if ($[62] !== renderError || $[63] !== renderInitError) {
1571
+ t27 = (error, retry) => {
1572
+ const customRenderer = renderInitError ?? renderError;
1573
+ if (customRenderer) {
1574
+ return customRenderer(error, retry);
1575
+ }
1576
+ return /* @__PURE__ */ jsx3(DefaultErrorRecoveryUI, { error, onRetry: retry });
1577
+ };
1578
+ $[62] = renderError;
1579
+ $[63] = renderInitError;
1580
+ $[64] = t27;
1581
+ } else {
1582
+ t27 = $[64];
1583
+ }
1584
+ const errorFallback = t27;
1585
+ let t28;
1586
+ if ($[65] !== powerSyncSyncStatus || $[66] !== powerSyncUrl) {
1587
+ t28 = !powerSyncUrl ? {
1588
+ hasSynced: true,
1589
+ connected: true,
1590
+ connecting: false,
1591
+ isOnline: true
1592
+ } : powerSyncSyncStatus;
1593
+ $[65] = powerSyncSyncStatus;
1594
+ $[66] = powerSyncUrl;
1595
+ $[67] = t28;
1596
+ } else {
1597
+ t28 = $[67];
1598
+ }
1599
+ const effectiveSyncStatus = t28;
1600
+ let t29;
1601
+ let t30;
1602
+ if ($[68] !== effectiveSyncStatus || $[69] !== onSyncStatusChange) {
1603
+ t29 = () => {
1604
+ if (effectiveSyncStatus) {
1605
+ onSyncStatusChange?.(effectiveSyncStatus);
1606
+ }
1607
+ };
1608
+ t30 = [effectiveSyncStatus, onSyncStatusChange];
1609
+ $[68] = effectiveSyncStatus;
1610
+ $[69] = onSyncStatusChange;
1611
+ $[70] = t29;
1612
+ $[71] = t30;
1613
+ } else {
1614
+ t29 = $[70];
1615
+ t30 = $[71];
1616
+ }
1617
+ useEffect3(t29, t30);
1618
+ let t31;
1619
+ let t32;
1620
+ if ($[72] !== backgroundSync || $[73] !== children || $[74] !== dataLayer || $[75] !== effectiveSyncStatus || $[76] !== errorFallback || $[77] !== handleBackgroundSyncSystemReady || $[78] !== handlePowerSyncError || $[79] !== handleRetry || $[80] !== initError || $[81] !== onError || $[82] !== onReady || $[83] !== platform.logger || $[84] !== powerSyncConfig || $[85] !== powerSyncInstance || $[86] !== powerSyncUrl || $[87] !== queryClient || $[88] !== renderError || $[89] !== renderInitError || $[90] !== retryKey || $[91] !== skipConflictProvider || $[92] !== skipStorageQueueProvider || $[93] !== supabaseClient || $[94] !== syncControl) {
1621
+ t32 = /* @__PURE__ */ Symbol.for("react.early_return_sentinel");
1622
+ bb1: {
1623
+ const renderContent = () => {
1624
+ if (!powerSyncUrl) {
1625
+ return /* @__PURE__ */ jsx3(Fragment2, { children });
1626
+ }
1627
+ if (initError) {
1628
+ const customRenderer_0 = renderInitError ?? renderError;
1629
+ if (customRenderer_0) {
1630
+ return /* @__PURE__ */ jsx3(Fragment2, { children: customRenderer_0(initError, handleRetry) });
1631
+ }
1632
+ return /* @__PURE__ */ jsx3(DefaultErrorRecoveryUI, { error: initError, onRetry: handleRetry });
1633
+ }
1634
+ return /* @__PURE__ */ jsx3(PowerSyncErrorBoundary, { fallback: errorFallback, onError: handlePowerSyncError, children: /* @__PURE__ */ jsx3(PowerSyncProvider, { config: powerSyncConfig, onReady: () => {
1635
+ platform.logger.info("PowerSync initialized and ready");
1636
+ setInitError(null);
1637
+ onReady?.();
1638
+ }, onError: handlePowerSyncError, children: /* @__PURE__ */ jsx3(ProviderBridge, { skipConflictProvider, skipStorageQueueProvider, backgroundSync, onBackgroundSyncSystemReady: handleBackgroundSyncSystemReady, onDbReady: (db, syncStatus) => {
1639
+ setPowerSyncInstance(db);
1640
+ setPowerSyncSyncStatus(syncStatus);
1641
+ }, onSyncStatusChange: (syncStatus_0) => {
1642
+ setPowerSyncSyncStatus(syncStatus_0);
1643
+ }, onAddPendingMutationReady: (add) => {
1644
+ addPendingMutationRef.current = add;
1645
+ }, onRemovePendingMutationReady: (remove) => {
1646
+ removePendingMutationRef.current = remove;
1647
+ }, children }) }, retryKey) });
1648
+ };
1649
+ let t33;
1650
+ if ($[97] !== dataLayer.config || $[98] !== effectiveSyncStatus || $[99] !== onError || $[100] !== platform.logger || $[101] !== powerSyncInstance || $[102] !== queryClient || $[103] !== supabaseClient || $[104] !== syncControl) {
1651
+ t33 = (content) => /* @__PURE__ */ jsx3(DataLayerProvider, { config: dataLayer.config, powerSyncInstance, supabaseClient, queryClient, powerSyncSyncStatus: effectiveSyncStatus, syncControl, onInitialized: () => {
1652
+ platform.logger.info("Data layer initialized");
1653
+ }, onError: (err_0) => {
1654
+ platform.logger.error("Data layer error:", err_0);
1655
+ onError?.(err_0);
1656
+ }, children: content });
1657
+ $[97] = dataLayer.config;
1658
+ $[98] = effectiveSyncStatus;
1659
+ $[99] = onError;
1660
+ $[100] = platform.logger;
1661
+ $[101] = powerSyncInstance;
1662
+ $[102] = queryClient;
1663
+ $[103] = supabaseClient;
1664
+ $[104] = syncControl;
1665
+ $[105] = t33;
1666
+ } else {
1667
+ t33 = $[105];
1668
+ }
1669
+ const renderWithDataLayer = t33;
1670
+ if (dataLayer && !dataLayer.skip) {
1671
+ t32 = renderWithDataLayer(renderContent());
1672
+ break bb1;
1673
+ }
1674
+ t31 = renderContent();
1675
+ }
1676
+ $[72] = backgroundSync;
1677
+ $[73] = children;
1678
+ $[74] = dataLayer;
1679
+ $[75] = effectiveSyncStatus;
1680
+ $[76] = errorFallback;
1681
+ $[77] = handleBackgroundSyncSystemReady;
1682
+ $[78] = handlePowerSyncError;
1683
+ $[79] = handleRetry;
1684
+ $[80] = initError;
1685
+ $[81] = onError;
1686
+ $[82] = onReady;
1687
+ $[83] = platform.logger;
1688
+ $[84] = powerSyncConfig;
1689
+ $[85] = powerSyncInstance;
1690
+ $[86] = powerSyncUrl;
1691
+ $[87] = queryClient;
1692
+ $[88] = renderError;
1693
+ $[89] = renderInitError;
1694
+ $[90] = retryKey;
1695
+ $[91] = skipConflictProvider;
1696
+ $[92] = skipStorageQueueProvider;
1697
+ $[93] = supabaseClient;
1698
+ $[94] = syncControl;
1699
+ $[95] = t31;
1700
+ $[96] = t32;
1701
+ } else {
1702
+ t31 = $[95];
1703
+ t32 = $[96];
1704
+ }
1705
+ if (t32 !== /* @__PURE__ */ Symbol.for("react.early_return_sentinel")) {
1706
+ return t32;
1707
+ }
1708
+ return t31;
1709
+ }
1710
+ function _temp(prev) {
1711
+ return prev + 1;
1712
+ }
1713
+
1714
+ export {
1715
+ ConflictBus,
1716
+ PowerSyncProvider,
1717
+ ProviderBridge,
1718
+ OfflineDataProvider
1719
+ };
1720
+ //# sourceMappingURL=chunk-BRXQNASY.js.map