@pol-studios/powersync 1.0.6 → 1.0.7

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