@pol-studios/db 1.0.57 → 1.0.59
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/DataLayerContext-V5FotiSk.d.ts +563 -0
- package/dist/auth/context.js +2 -2
- package/dist/auth/hooks.js +3 -3
- package/dist/auth/index.js +3 -3
- package/dist/{chunk-YRIPM2AN.js → chunk-4PZ744G2.js} +207 -6
- package/dist/chunk-4PZ744G2.js.map +1 -0
- package/dist/{chunk-6SDH7M7J.js → chunk-ARALLEDJ.js} +2 -2
- package/dist/{chunk-Z456IHCB.js → chunk-F4HW4NT5.js} +1 -1
- package/dist/chunk-F4HW4NT5.js.map +1 -0
- package/dist/{chunk-VSJKGPRI.js → chunk-K46TGKB2.js} +323 -379
- package/dist/chunk-K46TGKB2.js.map +1 -0
- package/dist/{chunk-GWYTROSD.js → chunk-L4DFVMTS.js} +335 -4
- package/dist/chunk-L4DFVMTS.js.map +1 -0
- package/dist/{chunk-MEBT5YHA.js → chunk-SNPZMRBC.js} +2 -2
- package/dist/{chunk-DDL63KLQ.js → chunk-VADZSRHY.js} +16 -337
- package/dist/chunk-VADZSRHY.js.map +1 -0
- package/dist/{chunk-4EO55YV2.js → chunk-VSY6766U.js} +4 -4
- package/dist/{chunk-VYFAMTHI.js → chunk-WY6MNB6K.js} +2 -2
- package/dist/core/index.d.ts +1 -1
- package/dist/{executor-D15yjeMo.d.ts → executor-Bu1OlqCl.d.ts} +43 -3
- package/dist/hooks/index.d.ts +3 -3
- package/dist/hooks/index.js +2 -2
- package/dist/{index-CFUuTzXO.d.ts → index-vwVJ0BWj.d.ts} +1 -9
- package/dist/index.d.ts +5 -5
- package/dist/index.js +20 -12
- package/dist/index.native.d.ts +77 -76
- package/dist/index.native.js +20 -12
- package/dist/index.web.d.ts +21 -44
- package/dist/index.web.js +215 -149
- package/dist/index.web.js.map +1 -1
- package/dist/powersync-bridge/index.d.ts +1 -1
- package/dist/query/index.d.ts +1 -1
- package/dist/query/index.js +1 -1
- package/dist/types/index.d.ts +3 -3
- package/dist/types/index.js +1 -1
- package/dist/{useDbCount-Ckb-FhZk.d.ts → useDbCount-dCkdaBpP.d.ts} +41 -83
- package/dist/{useResolveFeedback-CuUkdHoR.d.ts → useResolveFeedback-thFi-4h8.d.ts} +429 -5
- package/dist/with-auth/index.js +5 -5
- package/package.json +1 -1
- package/dist/DataLayerContext-BYZtDD0g.d.ts +0 -946
- package/dist/chunk-DDL63KLQ.js.map +0 -1
- package/dist/chunk-GWYTROSD.js.map +0 -1
- package/dist/chunk-VSJKGPRI.js.map +0 -1
- package/dist/chunk-YRIPM2AN.js.map +0 -1
- package/dist/chunk-Z456IHCB.js.map +0 -1
- /package/dist/{chunk-6SDH7M7J.js.map → chunk-ARALLEDJ.js.map} +0 -0
- /package/dist/{chunk-MEBT5YHA.js.map → chunk-SNPZMRBC.js.map} +0 -0
- /package/dist/{chunk-4EO55YV2.js.map → chunk-VSY6766U.js.map} +0 -0
- /package/dist/{chunk-VYFAMTHI.js.map → chunk-WY6MNB6K.js.map} +0 -0
|
@@ -7,14 +7,342 @@ import {
|
|
|
7
7
|
mergeRelatedUpdate
|
|
8
8
|
} from "./chunk-QYAFI34Q.js";
|
|
9
9
|
|
|
10
|
+
// src/adapters/auto-detector.ts
|
|
11
|
+
var BackendStatus = /* @__PURE__ */ ((BackendStatus2) => {
|
|
12
|
+
BackendStatus2["AVAILABLE"] = "available";
|
|
13
|
+
BackendStatus2["INITIALIZING"] = "initializing";
|
|
14
|
+
BackendStatus2["UNAVAILABLE"] = "unavailable";
|
|
15
|
+
return BackendStatus2;
|
|
16
|
+
})(BackendStatus || {});
|
|
17
|
+
var AdapterAutoDetector = class {
|
|
18
|
+
constructor(powerSyncDb, supabase, options = {}) {
|
|
19
|
+
this.powerSyncDb = powerSyncDb;
|
|
20
|
+
this.supabase = supabase;
|
|
21
|
+
this.options = {
|
|
22
|
+
preferPowerSync: options.preferPowerSync ?? true,
|
|
23
|
+
statusCheckTimeout: options.statusCheckTimeout ?? 1e3,
|
|
24
|
+
useOnlineUntilSynced: options.useOnlineUntilSynced ?? true
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
options;
|
|
28
|
+
listeners = /* @__PURE__ */ new Set();
|
|
29
|
+
lastResult = null;
|
|
30
|
+
syncStatus = null;
|
|
31
|
+
/**
|
|
32
|
+
* Update the PowerSync database reference.
|
|
33
|
+
* Called when PowerSync becomes available after initial construction.
|
|
34
|
+
*
|
|
35
|
+
* @param db - PowerSync database instance or null
|
|
36
|
+
*/
|
|
37
|
+
setPowerSyncDb(db) {
|
|
38
|
+
this.powerSyncDb = db;
|
|
39
|
+
if (db) {
|
|
40
|
+
this.detectSilent();
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Update the sync status from PowerSync.
|
|
45
|
+
* Called when sync status changes to re-evaluate backend recommendation.
|
|
46
|
+
*
|
|
47
|
+
* @param status - Current sync status or null if not available
|
|
48
|
+
*/
|
|
49
|
+
updateSyncStatus(status) {
|
|
50
|
+
const hadSynced = this.syncStatus?.hasSynced;
|
|
51
|
+
const hasSyncedNow = status?.hasSynced;
|
|
52
|
+
const changed = hadSynced !== hasSyncedNow;
|
|
53
|
+
this.syncStatus = status;
|
|
54
|
+
if (changed) {
|
|
55
|
+
this.detect();
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Get current sync status.
|
|
60
|
+
* @returns Current sync status or null
|
|
61
|
+
*/
|
|
62
|
+
getSyncStatus() {
|
|
63
|
+
return this.syncStatus;
|
|
64
|
+
}
|
|
65
|
+
// ===========================================================================
|
|
66
|
+
// Main Detection Methods
|
|
67
|
+
// ===========================================================================
|
|
68
|
+
/**
|
|
69
|
+
* Detect backend availability and recommend best option.
|
|
70
|
+
*
|
|
71
|
+
* The detection logic follows this priority:
|
|
72
|
+
* 1. If preferPowerSync is true and PowerSync is available, use PowerSync
|
|
73
|
+
* 2. If PowerSync is initializing and online with Supabase available, use Supabase temporarily
|
|
74
|
+
* 3. If online with Supabase available, use Supabase
|
|
75
|
+
* 4. If offline but PowerSync available, use PowerSync (offline mode)
|
|
76
|
+
* 5. If offline and PowerSync exists (even if initializing), use PowerSync local data
|
|
77
|
+
* 6. Default to Supabase as fallback
|
|
78
|
+
*
|
|
79
|
+
* @returns Detection result with recommendation and reasoning
|
|
80
|
+
*/
|
|
81
|
+
detect() {
|
|
82
|
+
const result = this.performDetection();
|
|
83
|
+
if (this.hasResultChanged(result)) {
|
|
84
|
+
this.lastResult = result;
|
|
85
|
+
this.notifyListeners(result);
|
|
86
|
+
}
|
|
87
|
+
return result;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Detect backend availability WITHOUT notifying listeners.
|
|
91
|
+
*
|
|
92
|
+
* This method is safe to call during React's render phase because it does not
|
|
93
|
+
* trigger state updates in other components. Use this method when you need to
|
|
94
|
+
* check backend status synchronously during render (e.g., in getAdapter()).
|
|
95
|
+
*
|
|
96
|
+
* The regular detect() method with listener notifications should only be called
|
|
97
|
+
* from useEffect or event handlers to avoid the React warning:
|
|
98
|
+
* "Cannot update a component while rendering a different component"
|
|
99
|
+
*
|
|
100
|
+
* @returns Detection result with recommendation and reasoning
|
|
101
|
+
*/
|
|
102
|
+
detectSilent() {
|
|
103
|
+
const result = this.performDetection();
|
|
104
|
+
this.lastResult = result;
|
|
105
|
+
return result;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Internal detection logic shared by detect() and detectSilent().
|
|
109
|
+
* @private
|
|
110
|
+
*/
|
|
111
|
+
performDetection() {
|
|
112
|
+
const powerSyncStatus = this.detectPowerSyncStatus();
|
|
113
|
+
const supabaseStatus = this.detectSupabaseStatus();
|
|
114
|
+
const isOnline = this.checkOnlineStatus();
|
|
115
|
+
let recommendedBackend;
|
|
116
|
+
let reason;
|
|
117
|
+
if (this.options.preferPowerSync && powerSyncStatus === "available" /* AVAILABLE */) {
|
|
118
|
+
recommendedBackend = "powersync";
|
|
119
|
+
reason = "PowerSync is available and preferred for offline-first experience";
|
|
120
|
+
} else if (powerSyncStatus === "initializing" /* INITIALIZING */ && isOnline && supabaseStatus === "available" /* AVAILABLE */) {
|
|
121
|
+
recommendedBackend = "supabase";
|
|
122
|
+
reason = "PowerSync initial sync in progress; using Supabase for fresh data";
|
|
123
|
+
} else if (supabaseStatus === "available" /* AVAILABLE */ && isOnline) {
|
|
124
|
+
recommendedBackend = "supabase";
|
|
125
|
+
reason = "Using Supabase direct connection";
|
|
126
|
+
} else if (powerSyncStatus === "available" /* AVAILABLE */) {
|
|
127
|
+
recommendedBackend = "powersync";
|
|
128
|
+
reason = "Offline mode using PowerSync local data";
|
|
129
|
+
} else if (!isOnline && this.powerSyncDb) {
|
|
130
|
+
recommendedBackend = "powersync";
|
|
131
|
+
reason = "Offline mode - using PowerSync local data (initial sync may be incomplete)";
|
|
132
|
+
} else {
|
|
133
|
+
recommendedBackend = "supabase";
|
|
134
|
+
reason = "No confirmed available backend; defaulting to Supabase";
|
|
135
|
+
}
|
|
136
|
+
return {
|
|
137
|
+
powerSyncStatus,
|
|
138
|
+
supabaseStatus,
|
|
139
|
+
recommendedBackend,
|
|
140
|
+
isOnline,
|
|
141
|
+
reason
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Check if PowerSync is available.
|
|
146
|
+
*
|
|
147
|
+
* PowerSync status depends on:
|
|
148
|
+
* 1. Database instance exists
|
|
149
|
+
* 2. If useOnlineUntilSynced is true, also checks if initial sync completed
|
|
150
|
+
*
|
|
151
|
+
* @returns PowerSync backend status
|
|
152
|
+
*/
|
|
153
|
+
detectPowerSyncStatus() {
|
|
154
|
+
if (!this.powerSyncDb) {
|
|
155
|
+
return "unavailable" /* UNAVAILABLE */;
|
|
156
|
+
}
|
|
157
|
+
try {
|
|
158
|
+
if (typeof this.powerSyncDb.getAll !== "function") {
|
|
159
|
+
return "initializing" /* INITIALIZING */;
|
|
160
|
+
}
|
|
161
|
+
if (this.options.useOnlineUntilSynced) {
|
|
162
|
+
if (!this.syncStatus || !this.syncStatus.hasSynced) {
|
|
163
|
+
return "initializing" /* INITIALIZING */;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
return "available" /* AVAILABLE */;
|
|
167
|
+
} catch {
|
|
168
|
+
return "initializing" /* INITIALIZING */;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Check if Supabase is available.
|
|
173
|
+
*
|
|
174
|
+
* Supabase is considered available if we have a client instance.
|
|
175
|
+
* The actual network connectivity is checked separately via checkOnlineStatus().
|
|
176
|
+
*
|
|
177
|
+
* @returns Supabase backend status
|
|
178
|
+
*/
|
|
179
|
+
detectSupabaseStatus() {
|
|
180
|
+
if (!this.supabase) {
|
|
181
|
+
return "unavailable" /* UNAVAILABLE */;
|
|
182
|
+
}
|
|
183
|
+
try {
|
|
184
|
+
if (typeof this.supabase.from === "function") {
|
|
185
|
+
return "available" /* AVAILABLE */;
|
|
186
|
+
}
|
|
187
|
+
return "unavailable" /* UNAVAILABLE */;
|
|
188
|
+
} catch {
|
|
189
|
+
return "unavailable" /* UNAVAILABLE */;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Check if device is online.
|
|
194
|
+
*
|
|
195
|
+
* Prefers the sync status's isOnline property if available (from React Native NetInfo).
|
|
196
|
+
* Falls back to navigator.onLine in browser environments.
|
|
197
|
+
* Returns false by default for non-browser environments (React Native, Node.js, etc.)
|
|
198
|
+
* to ensure offline-first behavior works correctly.
|
|
199
|
+
*
|
|
200
|
+
* @returns Whether the device has network connectivity
|
|
201
|
+
*/
|
|
202
|
+
checkOnlineStatus() {
|
|
203
|
+
if (this.syncStatus?.isOnline !== void 0) {
|
|
204
|
+
return this.syncStatus.isOnline;
|
|
205
|
+
}
|
|
206
|
+
if (typeof window !== "undefined" && typeof navigator !== "undefined") {
|
|
207
|
+
return navigator.onLine;
|
|
208
|
+
}
|
|
209
|
+
return false;
|
|
210
|
+
}
|
|
211
|
+
// ===========================================================================
|
|
212
|
+
// Instance Management Methods
|
|
213
|
+
// ===========================================================================
|
|
214
|
+
/**
|
|
215
|
+
* Update PowerSync instance (e.g., when it becomes available).
|
|
216
|
+
*
|
|
217
|
+
* @param db - New PowerSync database instance or null
|
|
218
|
+
*/
|
|
219
|
+
setPowerSync(db) {
|
|
220
|
+
this.powerSyncDb = db;
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Update Supabase instance.
|
|
224
|
+
*
|
|
225
|
+
* @param supabase - New Supabase client instance or null
|
|
226
|
+
*/
|
|
227
|
+
setSupabase(supabase) {
|
|
228
|
+
this.supabase = supabase;
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* Get current PowerSync instance.
|
|
232
|
+
*
|
|
233
|
+
* @returns Current PowerSync database instance or null
|
|
234
|
+
*/
|
|
235
|
+
getPowerSync() {
|
|
236
|
+
return this.powerSyncDb;
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* Get current Supabase instance.
|
|
240
|
+
*
|
|
241
|
+
* @returns Current Supabase client instance or null
|
|
242
|
+
*/
|
|
243
|
+
getSupabase() {
|
|
244
|
+
return this.supabase;
|
|
245
|
+
}
|
|
246
|
+
// ===========================================================================
|
|
247
|
+
// Options Management
|
|
248
|
+
// ===========================================================================
|
|
249
|
+
/**
|
|
250
|
+
* Update detector options.
|
|
251
|
+
*
|
|
252
|
+
* @param options - New options to merge with existing
|
|
253
|
+
*/
|
|
254
|
+
setOptions(options) {
|
|
255
|
+
this.options = {
|
|
256
|
+
...this.options,
|
|
257
|
+
...options
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* Get current detector options.
|
|
262
|
+
*
|
|
263
|
+
* @returns Current detector options
|
|
264
|
+
*/
|
|
265
|
+
getOptions() {
|
|
266
|
+
return {
|
|
267
|
+
...this.options
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
// ===========================================================================
|
|
271
|
+
// Listener Management
|
|
272
|
+
// ===========================================================================
|
|
273
|
+
/**
|
|
274
|
+
* Add a listener for backend change events.
|
|
275
|
+
*
|
|
276
|
+
* @param listener - Callback to invoke when detection result changes
|
|
277
|
+
* @returns Function to remove the listener
|
|
278
|
+
*/
|
|
279
|
+
addListener(listener) {
|
|
280
|
+
this.listeners.add(listener);
|
|
281
|
+
return () => this.listeners.delete(listener);
|
|
282
|
+
}
|
|
283
|
+
/**
|
|
284
|
+
* Remove a listener for backend change events.
|
|
285
|
+
*
|
|
286
|
+
* @param listener - Listener to remove
|
|
287
|
+
*/
|
|
288
|
+
removeListener(listener) {
|
|
289
|
+
this.listeners.delete(listener);
|
|
290
|
+
}
|
|
291
|
+
/**
|
|
292
|
+
* Get the last detection result.
|
|
293
|
+
*
|
|
294
|
+
* @returns Last detection result or null if never detected
|
|
295
|
+
*/
|
|
296
|
+
getLastResult() {
|
|
297
|
+
return this.lastResult;
|
|
298
|
+
}
|
|
299
|
+
// ===========================================================================
|
|
300
|
+
// Private Helper Methods
|
|
301
|
+
// ===========================================================================
|
|
302
|
+
/**
|
|
303
|
+
* Check if the detection result has changed from the last result.
|
|
304
|
+
*/
|
|
305
|
+
hasResultChanged(result) {
|
|
306
|
+
if (!this.lastResult) {
|
|
307
|
+
return true;
|
|
308
|
+
}
|
|
309
|
+
return this.lastResult.powerSyncStatus !== result.powerSyncStatus || this.lastResult.supabaseStatus !== result.supabaseStatus || this.lastResult.recommendedBackend !== result.recommendedBackend || this.lastResult.isOnline !== result.isOnline;
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* Notify all listeners of a detection result change.
|
|
313
|
+
*/
|
|
314
|
+
notifyListeners(result) {
|
|
315
|
+
const isDev = typeof __DEV__ !== "undefined" ? __DEV__ : process.env.NODE_ENV !== "production";
|
|
316
|
+
if (isDev) {
|
|
317
|
+
const prevBackend = this.lastResult?.recommendedBackend;
|
|
318
|
+
if (prevBackend && prevBackend !== result.recommendedBackend) {
|
|
319
|
+
console.log(`[DataLayer] Backend switched: ${prevBackend} \u2192 ${result.recommendedBackend}`, `| Reason: ${result.reason}`);
|
|
320
|
+
}
|
|
321
|
+
if (result.recommendedBackend === "supabase" && this.options.preferPowerSync) {
|
|
322
|
+
console.log(`[DataLayer] Using online fallback (Supabase)`, `| PowerSync: ${result.powerSyncStatus}`, `| Online: ${result.isOnline}`, `| Reason: ${result.reason}`);
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
Array.from(this.listeners).forEach((listener) => {
|
|
326
|
+
try {
|
|
327
|
+
listener(result);
|
|
328
|
+
} catch (error) {
|
|
329
|
+
console.error("Error in backend change listener:", error);
|
|
330
|
+
}
|
|
331
|
+
});
|
|
332
|
+
}
|
|
333
|
+
};
|
|
334
|
+
function createAdapterAutoDetector(powerSyncDb, supabase, options) {
|
|
335
|
+
return new AdapterAutoDetector(powerSyncDb, supabase, options);
|
|
336
|
+
}
|
|
337
|
+
|
|
10
338
|
// src/providers/DataLayerContext.ts
|
|
11
339
|
import { createContext } from "react";
|
|
340
|
+
var DataLayerContext = createContext(null);
|
|
341
|
+
DataLayerContext.displayName = "DataLayerContext";
|
|
12
342
|
var DataLayerCoreContext = createContext(null);
|
|
13
343
|
DataLayerCoreContext.displayName = "DataLayerCoreContext";
|
|
14
344
|
var DataLayerStatusContext = createContext(null);
|
|
15
345
|
DataLayerStatusContext.displayName = "DataLayerStatusContext";
|
|
16
|
-
var DataLayerContext = createContext(null);
|
|
17
|
-
DataLayerContext.displayName = "DataLayerContext";
|
|
18
346
|
var DataLayerNestingContext = createContext(false);
|
|
19
347
|
DataLayerNestingContext.displayName = "DataLayerNestingContext";
|
|
20
348
|
|
|
@@ -371,9 +699,12 @@ function useDbQueryById(table, id, options = {}) {
|
|
|
371
699
|
}
|
|
372
700
|
|
|
373
701
|
export {
|
|
702
|
+
BackendStatus,
|
|
703
|
+
AdapterAutoDetector,
|
|
704
|
+
createAdapterAutoDetector,
|
|
705
|
+
DataLayerContext,
|
|
374
706
|
DataLayerCoreContext,
|
|
375
707
|
DataLayerStatusContext,
|
|
376
|
-
DataLayerContext,
|
|
377
708
|
DataLayerNestingContext,
|
|
378
709
|
useDataLayerCore,
|
|
379
710
|
useDataLayerCoreOptional,
|
|
@@ -385,4 +716,4 @@ export {
|
|
|
385
716
|
useDbQuery,
|
|
386
717
|
useDbQueryById
|
|
387
718
|
};
|
|
388
|
-
//# sourceMappingURL=chunk-
|
|
719
|
+
//# sourceMappingURL=chunk-L4DFVMTS.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/adapters/auto-detector.ts","../src/providers/DataLayerContext.ts","../src/hooks/useDataLayer.ts","../src/hooks/useDbQuery.ts","../src/utils/dev-log.ts","../src/hooks/useDbQueryById.ts"],"sourcesContent":["/**\n * Adapter Auto-Detector\n *\n * Detects available backends (PowerSync, Supabase) at runtime and recommends\n * the best one to use based on availability and configuration preferences.\n *\n * This enables the V3 data layer to automatically select the optimal backend\n * for offline-first or online-first experiences.\n */\n\nimport type { SupabaseClient } from \"@supabase/supabase-js\";\nimport type { PowerSyncDatabase } from \"../query/executor\";\n\n// React Native global for dev mode detection\ndeclare const __DEV__: boolean | undefined;\n\n// =============================================================================\n// Enums\n// =============================================================================\n\n/**\n * Status of a backend adapter\n */\nexport enum BackendStatus {\n /** Backend is available and ready to use */\n AVAILABLE = \"available\",\n /** Backend is initializing (e.g., PowerSync syncing) */\n INITIALIZING = \"initializing\",\n /** Backend is not available */\n UNAVAILABLE = \"unavailable\",\n}\n\n// =============================================================================\n// Types\n// =============================================================================\n\n/**\n * Result of auto-detection\n */\nexport interface AutoDetectionResult {\n /** PowerSync availability status */\n powerSyncStatus: BackendStatus;\n /** Supabase availability status */\n supabaseStatus: BackendStatus;\n /** Recommended backend to use */\n recommendedBackend: \"powersync\" | \"supabase\";\n /** Whether device is online */\n isOnline: boolean;\n /** Reason for recommendation */\n reason: string;\n}\n\n/**\n * Sync status information from PowerSync\n */\nexport interface SyncStatusInfo {\n /** Whether PowerSync has completed at least one full sync */\n hasSynced: boolean;\n /** Whether connected to PowerSync service */\n connected: boolean;\n /** Whether currently connecting */\n connecting: boolean;\n /** Network connectivity status from platform adapter (NetInfo on React Native) */\n isOnline?: boolean;\n}\n\n/**\n * Options for auto-detection\n */\nexport interface AutoDetectorOptions {\n /** Prefer PowerSync when available (default: true) */\n preferPowerSync?: boolean;\n /** Timeout for status checks in ms (default: 1000) */\n statusCheckTimeout?: number;\n /**\n * Use Supabase for queries until PowerSync completes initial sync.\n * When true, queries return online data while syncing.\n * @default true\n */\n useOnlineUntilSynced?: boolean;\n}\n\n/**\n * Listener for backend change events\n */\nexport type BackendChangeListener = (result: AutoDetectionResult) => void;\n\n// =============================================================================\n// AdapterAutoDetector Class\n// =============================================================================\n\n/**\n * Detects available backends and recommends the best one to use.\n *\n * The auto-detector checks for PowerSync and Supabase availability and\n * makes intelligent recommendations based on:\n * - Backend availability\n * - Network connectivity\n * - User preferences (preferPowerSync option)\n *\n * @example\n * ```typescript\n * const detector = new AdapterAutoDetector(powerSyncDb, supabaseClient, {\n * preferPowerSync: true,\n * });\n *\n * const result = detector.detect();\n * console.log(`Using ${result.recommendedBackend}: ${result.reason}`);\n * ```\n */\nexport class AdapterAutoDetector {\n private options: Required<AutoDetectorOptions>;\n private listeners: Set<BackendChangeListener> = new Set();\n private lastResult: AutoDetectionResult | null = null;\n private syncStatus: SyncStatusInfo | null = null;\n constructor(private powerSyncDb: PowerSyncDatabase | null, private supabase: SupabaseClient | null, options: AutoDetectorOptions = {}) {\n this.options = {\n preferPowerSync: options.preferPowerSync ?? true,\n statusCheckTimeout: options.statusCheckTimeout ?? 1000,\n useOnlineUntilSynced: options.useOnlineUntilSynced ?? true\n };\n }\n\n /**\n * Update the PowerSync database reference.\n * Called when PowerSync becomes available after initial construction.\n *\n * @param db - PowerSync database instance or null\n */\n setPowerSyncDb(db: PowerSyncDatabase | null): void {\n this.powerSyncDb = db;\n // Re-detect to update backend recommendation silently to avoid\n // \"Cannot update while rendering\" React errors when called from\n // ensurePowerSyncAdapter() during another component's render phase.\n // The full detect() with listener notifications will be called from\n // useEffect in DataLayerProvider when appropriate.\n if (db) {\n this.detectSilent();\n }\n }\n\n /**\n * Update the sync status from PowerSync.\n * Called when sync status changes to re-evaluate backend recommendation.\n *\n * @param status - Current sync status or null if not available\n */\n updateSyncStatus(status: SyncStatusInfo | null): void {\n const hadSynced = this.syncStatus?.hasSynced;\n const hasSyncedNow = status?.hasSynced;\n const changed = hadSynced !== hasSyncedNow;\n this.syncStatus = status;\n if (changed) {\n // Re-detect to potentially switch backends\n this.detect();\n }\n }\n\n /**\n * Get current sync status.\n * @returns Current sync status or null\n */\n getSyncStatus(): SyncStatusInfo | null {\n return this.syncStatus;\n }\n\n // ===========================================================================\n // Main Detection Methods\n // ===========================================================================\n\n /**\n * Detect backend availability and recommend best option.\n *\n * The detection logic follows this priority:\n * 1. If preferPowerSync is true and PowerSync is available, use PowerSync\n * 2. If PowerSync is initializing and online with Supabase available, use Supabase temporarily\n * 3. If online with Supabase available, use Supabase\n * 4. If offline but PowerSync available, use PowerSync (offline mode)\n * 5. If offline and PowerSync exists (even if initializing), use PowerSync local data\n * 6. Default to Supabase as fallback\n *\n * @returns Detection result with recommendation and reasoning\n */\n detect(): AutoDetectionResult {\n const result = this.performDetection();\n\n // Store last result and notify listeners if changed\n if (this.hasResultChanged(result)) {\n this.lastResult = result;\n this.notifyListeners(result);\n }\n return result;\n }\n\n /**\n * Detect backend availability WITHOUT notifying listeners.\n *\n * This method is safe to call during React's render phase because it does not\n * trigger state updates in other components. Use this method when you need to\n * check backend status synchronously during render (e.g., in getAdapter()).\n *\n * The regular detect() method with listener notifications should only be called\n * from useEffect or event handlers to avoid the React warning:\n * \"Cannot update a component while rendering a different component\"\n *\n * @returns Detection result with recommendation and reasoning\n */\n detectSilent(): AutoDetectionResult {\n const result = this.performDetection();\n // Update lastResult to keep hasResultChanged() accurate, but do NOT notify listeners\n this.lastResult = result;\n return result;\n }\n\n /**\n * Internal detection logic shared by detect() and detectSilent().\n * @private\n */\n private performDetection(): AutoDetectionResult {\n const powerSyncStatus = this.detectPowerSyncStatus();\n const supabaseStatus = this.detectSupabaseStatus();\n const isOnline = this.checkOnlineStatus();\n let recommendedBackend: \"powersync\" | \"supabase\";\n let reason: string;\n\n // Decision logic\n if (this.options.preferPowerSync && powerSyncStatus === BackendStatus.AVAILABLE) {\n recommendedBackend = \"powersync\";\n reason = \"PowerSync is available and preferred for offline-first experience\";\n } else if (powerSyncStatus === BackendStatus.INITIALIZING && isOnline && supabaseStatus === BackendStatus.AVAILABLE) {\n recommendedBackend = \"supabase\";\n reason = \"PowerSync initial sync in progress; using Supabase for fresh data\";\n } else if (supabaseStatus === BackendStatus.AVAILABLE && isOnline) {\n recommendedBackend = \"supabase\";\n reason = \"Using Supabase direct connection\";\n } else if (powerSyncStatus === BackendStatus.AVAILABLE) {\n // Offline but PowerSync available\n recommendedBackend = \"powersync\";\n reason = \"Offline mode using PowerSync local data\";\n } else if (!isOnline && this.powerSyncDb) {\n // Offline with PowerSync database available (even if initial sync incomplete)\n // Use local data - some data is better than no data\n recommendedBackend = \"powersync\";\n reason = \"Offline mode - using PowerSync local data (initial sync may be incomplete)\";\n } else {\n // Fallback - try Supabase even if not confirmed available\n recommendedBackend = \"supabase\";\n reason = \"No confirmed available backend; defaulting to Supabase\";\n }\n return {\n powerSyncStatus,\n supabaseStatus,\n recommendedBackend,\n isOnline,\n reason\n };\n }\n\n /**\n * Check if PowerSync is available.\n *\n * PowerSync status depends on:\n * 1. Database instance exists\n * 2. If useOnlineUntilSynced is true, also checks if initial sync completed\n *\n * @returns PowerSync backend status\n */\n detectPowerSyncStatus(): BackendStatus {\n if (!this.powerSyncDb) {\n return BackendStatus.UNAVAILABLE;\n }\n try {\n // Check if db instance has required methods\n if (typeof this.powerSyncDb.getAll !== \"function\") {\n return BackendStatus.INITIALIZING;\n }\n\n // If useOnlineUntilSynced is enabled, treat as INITIALIZING until\n // we have sync status AND hasSynced is true.\n // IMPORTANT: If syncStatus is null, we haven't received status yet,\n // so assume NOT synced (INITIALIZING) to trigger Supabase fallback.\n if (this.options.useOnlineUntilSynced) {\n if (!this.syncStatus || !this.syncStatus.hasSynced) {\n return BackendStatus.INITIALIZING;\n }\n }\n return BackendStatus.AVAILABLE;\n } catch {\n return BackendStatus.INITIALIZING;\n }\n }\n\n /**\n * Check if Supabase is available.\n *\n * Supabase is considered available if we have a client instance.\n * The actual network connectivity is checked separately via checkOnlineStatus().\n *\n * @returns Supabase backend status\n */\n detectSupabaseStatus(): BackendStatus {\n if (!this.supabase) {\n return BackendStatus.UNAVAILABLE;\n }\n\n // Supabase client exists, assume available (actual network check is async)\n // The from() method is a good indicator that the client is properly initialized\n try {\n if (typeof this.supabase.from === \"function\") {\n return BackendStatus.AVAILABLE;\n }\n return BackendStatus.UNAVAILABLE;\n } catch {\n return BackendStatus.UNAVAILABLE;\n }\n }\n\n /**\n * Check if device is online.\n *\n * Prefers the sync status's isOnline property if available (from React Native NetInfo).\n * Falls back to navigator.onLine in browser environments.\n * Returns false by default for non-browser environments (React Native, Node.js, etc.)\n * to ensure offline-first behavior works correctly.\n *\n * @returns Whether the device has network connectivity\n */\n checkOnlineStatus(): boolean {\n // Use sync status isOnline if available (from React Native NetInfo via platform adapter)\n if (this.syncStatus?.isOnline !== undefined) {\n return this.syncStatus.isOnline;\n }\n\n // Browser environment fallback\n if (typeof window !== \"undefined\" && typeof navigator !== \"undefined\") {\n return navigator.onLine;\n }\n\n // For React Native and other non-browser environments, default to offline-safe behavior.\n // This ensures mutations route to PowerSync local storage instead of hanging on Supabase.\n return false;\n }\n\n // ===========================================================================\n // Instance Management Methods\n // ===========================================================================\n\n /**\n * Update PowerSync instance (e.g., when it becomes available).\n *\n * @param db - New PowerSync database instance or null\n */\n setPowerSync(db: PowerSyncDatabase | null): void {\n this.powerSyncDb = db;\n }\n\n /**\n * Update Supabase instance.\n *\n * @param supabase - New Supabase client instance or null\n */\n setSupabase(supabase: SupabaseClient | null): void {\n this.supabase = supabase;\n }\n\n /**\n * Get current PowerSync instance.\n *\n * @returns Current PowerSync database instance or null\n */\n getPowerSync(): PowerSyncDatabase | null {\n return this.powerSyncDb;\n }\n\n /**\n * Get current Supabase instance.\n *\n * @returns Current Supabase client instance or null\n */\n getSupabase(): SupabaseClient | null {\n return this.supabase;\n }\n\n // ===========================================================================\n // Options Management\n // ===========================================================================\n\n /**\n * Update detector options.\n *\n * @param options - New options to merge with existing\n */\n setOptions(options: Partial<AutoDetectorOptions>): void {\n this.options = {\n ...this.options,\n ...options\n };\n }\n\n /**\n * Get current detector options.\n *\n * @returns Current detector options\n */\n getOptions(): Required<AutoDetectorOptions> {\n return {\n ...this.options\n };\n }\n\n // ===========================================================================\n // Listener Management\n // ===========================================================================\n\n /**\n * Add a listener for backend change events.\n *\n * @param listener - Callback to invoke when detection result changes\n * @returns Function to remove the listener\n */\n addListener(listener: BackendChangeListener): () => void {\n this.listeners.add(listener);\n return () => this.listeners.delete(listener);\n }\n\n /**\n * Remove a listener for backend change events.\n *\n * @param listener - Listener to remove\n */\n removeListener(listener: BackendChangeListener): void {\n this.listeners.delete(listener);\n }\n\n /**\n * Get the last detection result.\n *\n * @returns Last detection result or null if never detected\n */\n getLastResult(): AutoDetectionResult | null {\n return this.lastResult;\n }\n\n // ===========================================================================\n // Private Helper Methods\n // ===========================================================================\n\n /**\n * Check if the detection result has changed from the last result.\n */\n private hasResultChanged(result: AutoDetectionResult): boolean {\n if (!this.lastResult) {\n return true;\n }\n return this.lastResult.powerSyncStatus !== result.powerSyncStatus || this.lastResult.supabaseStatus !== result.supabaseStatus || this.lastResult.recommendedBackend !== result.recommendedBackend || this.lastResult.isOnline !== result.isOnline;\n }\n\n /**\n * Notify all listeners of a detection result change.\n */\n private notifyListeners(result: AutoDetectionResult): void {\n // Log backend switches in dev mode (React Native __DEV__ or NODE_ENV)\n const isDev = typeof __DEV__ !== \"undefined\" ? __DEV__ : process.env.NODE_ENV !== \"production\";\n if (isDev) {\n const prevBackend = this.lastResult?.recommendedBackend;\n if (prevBackend && prevBackend !== result.recommendedBackend) {\n console.log(`[DataLayer] Backend switched: ${prevBackend} → ${result.recommendedBackend}`, `| Reason: ${result.reason}`);\n }\n // Log when using Supabase fallback (not PowerSync)\n if (result.recommendedBackend === \"supabase\" && this.options.preferPowerSync) {\n console.log(`[DataLayer] Using online fallback (Supabase)`, `| PowerSync: ${result.powerSyncStatus}`, `| Online: ${result.isOnline}`, `| Reason: ${result.reason}`);\n }\n }\n\n // Convert to array to avoid Set iteration issues with older targets\n Array.from(this.listeners).forEach(listener => {\n try {\n listener(result);\n } catch (error) {\n console.error(\"Error in backend change listener:\", error);\n }\n });\n }\n}\n\n// =============================================================================\n// Factory Function\n// =============================================================================\n\n/**\n * Create an AdapterAutoDetector instance.\n *\n * @param powerSyncDb - PowerSync database instance or null\n * @param supabase - Supabase client instance or null\n * @param options - Detection options\n * @returns New AdapterAutoDetector instance\n *\n * @example\n * ```typescript\n * const detector = createAdapterAutoDetector(powerSyncDb, supabaseClient, {\n * preferPowerSync: true,\n * statusCheckTimeout: 2000,\n * });\n *\n * const { recommendedBackend, reason } = detector.detect();\n * ```\n */\nexport function createAdapterAutoDetector(powerSyncDb: PowerSyncDatabase | null, supabase: SupabaseClient | null, options?: AutoDetectorOptions): AdapterAutoDetector {\n return new AdapterAutoDetector(powerSyncDb, supabase, options);\n}","/**\n * V3 Data Layer Context - SIMPLIFIED\n *\n * Single context with stable values and lazy PowerSync initialization.\n *\n * SIMPLIFIED ARCHITECTURE:\n * - Supports lazy init: start with Supabase, switch to PowerSync when available\n * - Simple adapter selection: if (powerSync && table is offline) use PowerSync, else Supabase\n * - No complex AutoDetector class - just useMemo with prop dependencies\n * - No render-during-render bugs - all state derived from props\n */\n\nimport { createContext } from \"react\";\nimport type { SupabaseClient } from \"@supabase/supabase-js\";\nimport type { QueryClient } from \"@tanstack/react-query\";\nimport type { PowerSyncDatabase } from \"../query/executor\";\nimport type { DatabaseSchema, SyncStatus, SyncControl, DataLayerConfig, TableStrategy } from \"../core/types\";\nimport type { TableDataAdapter } from \"../adapters/types\";\n\n// Import from auto-detector for backward compatibility (avoids duplicate exports)\nimport { BackendStatus, type AutoDetectionResult } from \"../adapters/auto-detector\";\n\n// Re-export for backward compatibility (consumers importing from providers)\nexport { BackendStatus };\nexport type { AutoDetectionResult };\n\n// =============================================================================\n// Status Types\n// =============================================================================\n\n/**\n * Status type for the data layer\n */\nexport interface DataLayerStatus {\n isInitialized: boolean;\n currentBackend: \"powersync\" | \"supabase\" | null;\n powerSyncStatus: BackendStatus;\n isOnline: boolean;\n lastDetection: AutoDetectionResult | null;\n error: Error | null;\n hasSynced: boolean;\n}\n\n// =============================================================================\n// Simplified Registry Interface\n// =============================================================================\n\n/**\n * Simplified adapter registry interface.\n *\n * This provides the same interface as the old AdapterRegistry class\n * but is implemented inline in the provider.\n */\nexport interface SimpleAdapterRegistry {\n /** Get adapter for a specific table */\n getAdapter: (table: string, operation?: 'read' | 'write') => TableDataAdapter;\n /** Get strategy for a table */\n getTableStrategy: (table: string) => TableStrategy | undefined;\n /** Check if table uses PowerSync */\n usesPowerSync: (table: string) => boolean;\n /** Get all PowerSync table names */\n getPowerSyncTables: () => string[];\n /** Get PowerSync alias for a table */\n getTableAlias: (table: string) => string;\n /** Get debug info */\n getDebugInfo: () => {\n isInitialized: boolean;\n hasPowerSync: boolean;\n hasSupabase: boolean;\n configuredTableCount: number;\n powerSyncTables: string[];\n };\n /** Config reference */\n config: DataLayerConfig;\n /** Whether registry is initialized */\n isInitialized: boolean;\n}\n\n// =============================================================================\n// Context Value Types\n// =============================================================================\n\n/**\n * Core context value - stable values that don't change after initialization.\n *\n * Supports lazy init: start with Supabase, automatically switch to PowerSync when available.\n */\nexport interface DataLayerCoreContextValue {\n /** Simplified registry for adapter access */\n registry: SimpleAdapterRegistry;\n\n /** Get adapter for a table - simple: PowerSync if offline table, else Supabase */\n getAdapter: (table: string, operation?: 'read' | 'write') => TableDataAdapter;\n\n /** PowerSync database instance (null if not using offline-first) */\n powerSync: PowerSyncDatabase | null;\n\n /** Supabase client (always available) */\n supabase: SupabaseClient;\n\n /** React Query client */\n queryClient: QueryClient;\n\n /** Database schema */\n schema: DatabaseSchema;\n\n /** Sync controls (no-op functions when PowerSync not available) */\n syncControl: SyncControl;\n}\n\n/**\n * Status context value - dynamic values that change during runtime.\n */\nexport interface DataLayerStatusContextValue {\n /** Current status */\n status: DataLayerStatus;\n /** Sync status (for PowerSync, default values for Supabase-only) */\n syncStatus: SyncStatus;\n}\n\n/**\n * Combined context value for backward compatibility.\n * Combines core and status values.\n *\n * @deprecated Prefer using useDataLayerCore() for queries/mutations\n * and useDataLayerStatus() for status display components.\n */\nexport interface DataLayerContextValue extends DataLayerCoreContextValue, DataLayerStatusContextValue {}\n\n// =============================================================================\n// Context Creation\n// =============================================================================\n\n/**\n * Main data layer context (combined).\n * For backward compatibility - use DataLayerCoreContext for better performance.\n */\nexport const DataLayerContext = createContext<DataLayerContextValue | null>(null);\nDataLayerContext.displayName = \"DataLayerContext\";\n\n/**\n * Core context - stable values that don't change after initialization.\n * Components using useDataLayerCore() will NOT re-render on status changes.\n */\nexport const DataLayerCoreContext = createContext<DataLayerCoreContextValue | null>(null);\nDataLayerCoreContext.displayName = \"DataLayerCoreContext\";\n\n/**\n * Status context - dynamic values that change during runtime.\n * Components using useDataLayerStatus() WILL re-render on status changes.\n */\nexport const DataLayerStatusContext = createContext<DataLayerStatusContextValue | null>(null);\nDataLayerStatusContext.displayName = \"DataLayerStatusContext\";\n\n/**\n * Nesting detection context.\n * Warns if DataLayerProvider is accidentally nested.\n */\nexport const DataLayerNestingContext = createContext<boolean>(false);\nDataLayerNestingContext.displayName = \"DataLayerNestingContext\";","/**\n * V3 Data Layer Hooks - SIMPLIFIED\n *\n * Three hooks for different use cases:\n * - useDataLayerCore(): Stable values only (best for queries/mutations)\n * - useDataLayerStatus(): Dynamic values (best for status UI)\n * - useDataLayer(): Combined (backward compatible)\n */\n\nimport { useContext } from \"react\";\nimport { DataLayerContext, DataLayerCoreContext, DataLayerStatusContext, type DataLayerContextValue, type DataLayerCoreContextValue, type DataLayerStatusContextValue } from \"../providers/DataLayerContext\";\n\n// =============================================================================\n// Performance-Optimized Hooks\n// =============================================================================\n\n/**\n * Access ONLY stable core values (registry, adapters, clients).\n *\n * PERFORMANCE: Components using this hook will NOT re-render when\n * network status or sync status changes. Use this in query/mutation hooks.\n *\n * Provides:\n * - registry: Simplified adapter registry\n * - getAdapter(table): Get adapter for a table\n * - powerSync: PowerSync database (null if not using offline)\n * - supabase: Supabase client\n * - queryClient: React Query client\n * - schema: Database schema\n * - syncControl: Sync controls\n *\n * @throws Error if used outside DataLayerProvider\n *\n * @example\n * ```tsx\n * const { getAdapter, powerSync } = useDataLayerCore();\n * const adapter = getAdapter(\"Task\");\n * ```\n */\nexport function useDataLayerCore() {\n const context = useContext(DataLayerCoreContext);\n if (!context) {\n throw new Error(\"useDataLayerCore must be used within a DataLayerProvider. Make sure you have wrapped your app with <DataLayerProvider>.\");\n }\n return context;\n}\n\n/**\n * Optional version that returns null instead of throwing.\n * Use for graceful fallback behavior.\n */\nexport function useDataLayerCoreOptional() {\n return useContext(DataLayerCoreContext);\n}\n\n/**\n * Access ONLY dynamic status values.\n *\n * PERFORMANCE: Only components that need status info will re-render\n * when status changes. Use for sync status, online indicator, etc.\n *\n * Provides:\n * - status: Initialization and connection status\n * - syncStatus: PowerSync sync status\n *\n * @throws Error if used outside DataLayerProvider\n *\n * @example\n * ```tsx\n * const { status, syncStatus } = useDataLayerStatus();\n * return <StatusBar isOnline={status.isOnline} />;\n * ```\n */\nexport function useDataLayerStatus() {\n const context = useContext(DataLayerStatusContext);\n if (!context) {\n throw new Error(\"useDataLayerStatus must be used within a DataLayerProvider. Make sure you have wrapped your app with <DataLayerProvider>.\");\n }\n return context;\n}\n\n// =============================================================================\n// Backward Compatible Hook\n// =============================================================================\n\n/**\n * Access the combined data layer context (core + status).\n *\n * NOTE: For better performance, prefer using:\n * - useDataLayerCore() for queries/mutations\n * - useDataLayerStatus() for status UI\n *\n * This hook re-renders on ALL status changes.\n *\n * @throws Error if used outside DataLayerProvider\n *\n * @example\n * ```tsx\n * const { getAdapter, status } = useDataLayer();\n * const adapter = getAdapter(\"Task\");\n * ```\n */\nexport function useDataLayer() {\n const context = useContext(DataLayerContext);\n if (!context) {\n throw new Error(\"useDataLayer must be used within a DataLayerProvider. Make sure you have wrapped your app with <DataLayerProvider>.\");\n }\n return context;\n}\n\n/**\n * Optional version that returns null instead of throwing.\n * Use for components that may render outside the provider.\n */\nexport function useDataLayerOptional() {\n return useContext(DataLayerContext);\n}\nexport default useDataLayer;","/**\n * V3 useDbQuery Hook\n *\n * React hook for querying multiple records from a table.\n * Works identically whether PowerSync or Supabase is the backend.\n * Uses React Query for state management and caching.\n *\n * Types are automatically inferred from table names when you augment\n * the DatabaseTypes interface with your app's Database type.\n *\n * @example\n * // In your app's types/db.d.ts:\n * declare module \"@pol-studios/db\" {\n * interface DatabaseTypes {\n * database: import(\"@/database.types\").Database;\n * }\n * }\n *\n * // Then usage auto-infers types:\n * const { data } = useDbQuery(\"EquipmentFixtureUnit\", { ... });\n * // data is typed as Tables<\"EquipmentFixtureUnit\">[]\n */\n\nimport { useMemo, useEffect, useCallback, useRef } from \"react\";\nimport { useQuery } from \"@tanstack/react-query\";\nimport { useDataLayerCore } from \"./useDataLayer\";\nimport type { QueryOptions } from \"../core/types\";\nimport { devLog, devWarn } from \"../utils/dev-log\";\nimport { parseSelect, extractExplicitFkRelations, selectHasExplicitFkSyntax } from \"../query/select-parser\";\nimport type { ExtractedExplicitFk } from \"../query/select-parser\";\nimport { mergeRelatedUpdate } from \"../realtime/explicit-fk-merge\";\n\n// =============================================================================\n// Module Augmentation Interface\n// =============================================================================\n\n/**\n * Augment this interface in your app to enable automatic type inference.\n *\n * @example\n * // In types/db.d.ts\n * declare module \"@pol-studios/db\" {\n * interface DatabaseTypes {\n * database: import(\"@/database.types\").Database;\n * }\n * }\n */\n// eslint-disable-next-line @typescript-eslint/no-empty-interface\nexport interface DatabaseTypes {}\n\n// =============================================================================\n// Database Type Helpers\n// =============================================================================\n\n/**\n * The configured Database type, or a generic fallback\n */\ntype ConfiguredDatabase = DatabaseTypes extends {\n database: infer DB;\n} ? DB : GenericSchema;\n\n/**\n * Generic schema structure for fallback\n */\ntype GenericSchema = {\n public: {\n Tables: Record<string, {\n Row: Record<string, unknown>;\n }>;\n Views: Record<string, {\n Row: Record<string, unknown>;\n }>;\n };\n [schema: string]: {\n Tables: Record<string, {\n Row: Record<string, unknown>;\n }>;\n Views?: Record<string, {\n Row: Record<string, unknown>;\n }>;\n };\n};\n\n/**\n * Default schema from Database (usually \"public\")\n */\ntype DefaultSchema = ConfiguredDatabase extends {\n public: infer S;\n} ? S : never;\n\n/**\n * Extract all valid table names from the default schema\n */\nexport type PublicTableNames = DefaultSchema extends {\n Tables: infer T;\n} ? keyof T & string : string;\n\n/**\n * Extract all valid schema names\n */\nexport type SchemaNames = keyof ConfiguredDatabase & string;\n\n/**\n * Extract table names for a specific schema\n */\nexport type SchemaTableNames<S extends string> = ConfiguredDatabase extends { [K in S]: {\n Tables: infer T;\n} } ? keyof T & string : string;\n\n/**\n * Build dot notation strings for all schema.table combinations\n */\ntype SchemaDotTable = { [S in SchemaNames]: S extends \"public\" ? never // Skip public schema for dot notation\n: `${S}.${SchemaTableNames<S>}` }[SchemaNames];\n\n/**\n * Table identifier - provides autocomplete for valid table names\n *\n * Supports:\n * - \"TableName\" - public schema tables\n * - \"schema.TableName\" - dot notation for other schemas\n * - { schema, table } - object format for other schemas\n */\nexport type TableIdentifier = PublicTableNames | SchemaDotTable | { [S in Exclude<SchemaNames, \"public\">]: {\n schema: S;\n table: SchemaTableNames<S>;\n} }[Exclude<SchemaNames, \"public\">];\n\n/**\n * Resolve row type from a table identifier\n *\n * Supports:\n * - \"TableName\" → public schema\n * - \"schema.TableName\" → specified schema (dot notation)\n * - { schema: \"schema\", table: \"TableName\" } → specified schema (object)\n */\nexport type ResolveRowType<T extends TableIdentifier> = T extends string ?\n// Check for dot notation first (e.g., \"core.Profile\")\nT extends `${infer Schema}.${infer Table}` ? ConfiguredDatabase extends { [K in Schema]: {\n Tables: { [K2 in Table]: {\n Row: infer R;\n } };\n} } ? R : Record<string, unknown> :\n// Plain string - look in public schema\nDefaultSchema extends {\n Tables: { [K in T]: {\n Row: infer R;\n } };\n} ? R : DefaultSchema extends {\n Views: { [K in T]: {\n Row: infer R;\n } };\n} ? R : Record<string, unknown> : T extends {\n schema: infer S;\n table: infer TN;\n} ?\n// Object with schema - look in specified schema\nS extends string ? TN extends string ? ConfiguredDatabase extends { [K in S]: {\n Tables: { [K2 in TN]: {\n Row: infer R;\n } };\n} } ? R : Record<string, unknown> : Record<string, unknown> : Record<string, unknown> : Record<string, unknown>;\n\n// =============================================================================\n// Types\n// =============================================================================\n\n/**\n * Options for useDbQuery hook\n */\nexport interface UseDbQueryOptions extends Omit<QueryOptions, \"enabled\"> {\n /** Whether the query is enabled (default: true) */\n enabled?: boolean;\n /**\n * React Query stale time in ms\n * Default depends on backend:\n * - PowerSync (offline): 0 - always refetch from SQLite (disk is fast)\n * - Supabase (online): 30000 - use normal caching\n */\n staleTime?: number;\n /** React Query gcTime (cache time) in ms (default: 300000 - 5 minutes) */\n gcTime?: number;\n /** Whether to refetch on window focus (default: true) */\n refetchOnWindowFocus?: boolean;\n /**\n * Whether to refetch on mount\n * Default depends on backend:\n * - PowerSync (offline): \"always\" - always query SQLite\n * - Supabase (online): true - refetch if stale\n */\n refetchOnMount?: boolean | \"always\";\n /** Whether to enable real-time subscriptions (if adapter supports) */\n realtime?: boolean;\n /** If true, returns single item instead of array (for compatibility with V2) */\n single?: boolean;\n}\n\n/**\n * Result from useDbQuery hook\n */\nexport interface UseDbQueryResult<T> {\n /** Query data */\n data: T[] | undefined;\n /** Whether query is loading (initial load) */\n isLoading: boolean;\n /** Whether query is in pending state */\n isPending: boolean;\n /** Whether query is currently fetching (including refetch) */\n isFetching: boolean;\n /** Whether query is currently refetching (alias for isFetching for V2 compatibility) */\n isRefetching: boolean;\n /** Whether query completed successfully */\n isSuccess: boolean;\n /** Whether query errored */\n isError: boolean;\n /** Query error if any */\n error: Error | null;\n /** Refetch the query */\n refetch: () => Promise<void>;\n /** Total count (if pagination is used) */\n count?: number;\n /** Whether data is stale */\n isStale: boolean;\n /** Timestamp of last data update */\n dataUpdatedAt: number | null;\n}\n\n// =============================================================================\n// Helper Functions\n// =============================================================================\n\n/**\n * Build a query key for React Query\n *\n * Creates a stable, unique key for caching based on table and query options.\n * Keys are namespaced with \"v3\" to avoid collisions with V2 queries.\n *\n * NOTE: Backend is intentionally NOT included in the key. The data is the same\n * regardless of whether it comes from Supabase or PowerSync - switching backends\n * should NOT invalidate the cache. This is critical for offline-first UX.\n */\nfunction buildQueryKey(table: string, options: UseDbQueryOptions): unknown[] {\n return [\"v3\", \"query\", table, options.select ?? \"*\", JSON.stringify(options.where ?? {}), JSON.stringify(options.orderBy ?? []), options.limit, options.offset];\n}\n\n/**\n * Serialize query options for dependency tracking\n */\nfunction serializeQueryOptions(options: UseDbQueryOptions): string {\n return JSON.stringify({\n select: options.select,\n where: options.where,\n orderBy: options.orderBy,\n limit: options.limit,\n offset: options.offset\n });\n}\n\n// =============================================================================\n// Hook Implementation\n// =============================================================================\n\n/**\n * Helper to resolve table name from TableIdentifier\n */\nfunction resolveTableName(table: TableIdentifier): string {\n if (typeof table === \"string\") {\n return table;\n }\n return `${table.schema}.${table.table}`;\n}\n\n/**\n * Hook for querying multiple records from a table\n *\n * This hook provides a unified interface for querying data that works\n * identically whether the backend is PowerSync (offline-first) or\n * Supabase (online-only). It uses React Query for caching and state management.\n *\n * Features:\n * - Automatic type inference from table names (when DatabaseTypes is augmented)\n * - Automatic backend selection based on DataLayerProvider configuration\n * - React Query integration for caching, deduplication, and background updates\n * - Optional real-time subscriptions (when adapter supports it)\n * - Pagination support with count\n *\n * @param table - Table name (string) or { schema, table } object\n * @param options - Query options (select, where, orderBy, limit, offset, etc.)\n * @returns Query result with data, loading states, error, and refetch function\n *\n * @example\n * // Basic query - types auto-inferred from table name\n * const { data } = useDbQuery(\"EquipmentFixtureUnit\");\n * // data is typed as Tables<\"EquipmentFixtureUnit\">[]\n *\n * @example\n * // Query from non-public schema\n * const { data } = useDbQuery({ schema: \"core\", table: \"Profile\" });\n * // data is typed as Tables<{ schema: \"core\" }, \"Profile\">[]\n *\n * @example\n * // Query with filters and sorting\n * const { data } = useDbQuery(\"Task\", {\n * select: \"*, Project(*)\",\n * where: { status: \"active\" },\n * orderBy: [{ field: \"createdAt\", direction: \"desc\" }],\n * limit: 10,\n * });\n */\n/**\n * Main hook signature with auto-inferred types from table identifiers\n */\nexport function useDbQuery<T extends TableIdentifier>(table: T, options?: UseDbQueryOptions): UseDbQueryResult<ResolveRowType<T>>;\n\n/**\n * Overload for explicit type parameter when table name is a string literal\n */\nexport function useDbQuery<T>(table: string, options?: UseDbQueryOptions): UseDbQueryResult<T>;\n\n// Implementation signature - uses any to satisfy both overloads\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport function useDbQuery<T = any>(table: TableIdentifier | string, options: UseDbQueryOptions = {}): UseDbQueryResult<T> {\n const tableName = typeof table === \"string\" ? table : resolveTableName(table as TableIdentifier);\n const {\n registry,\n queryClient,\n powerSync\n } = useDataLayerCore();\n\n // Determine if using PowerSync (offline/SQLite) or Supabase (online)\n const isPowerSync = powerSync !== null;\n\n // Backend-aware defaults:\n // - PowerSync: staleTime=0, refetchOnMount=\"always\" (SQLite is fast, always query disk)\n // - Supabase: staleTime=30000, refetchOnMount=true (use normal React Query caching)\n // - realtime: PowerSync=true (use watch() for live updates), Supabase=false (no streaming)\n const {\n enabled = true,\n staleTime = isPowerSync ? 0 : 30000,\n gcTime = 300000,\n // 5 minutes - keep in memory for instant display while refetching\n refetchOnWindowFocus = true,\n refetchOnMount = isPowerSync ? \"always\" : true,\n realtime = isPowerSync,\n // Enable real-time subscriptions by default for PowerSync\n ...queryOptions\n } = options;\n\n // Get adapter for this table\n // No isInitialized check needed - if we get here, core context exists = initialized\n const adapter = useMemo(() => {\n try {\n return registry.getAdapter(tableName);\n } catch {\n return null;\n }\n }, [registry, tableName]);\n\n // Serialize options into a stable memoized value BEFORE using in other dependencies\n const serializedOptions = useMemo(() => serializeQueryOptions(options), [options.select, options.where, options.orderBy, options.limit, options.offset]);\n\n // Build query key - memoized to prevent unnecessary re-renders\n // Backend is NOT included - cache persists across backend switches for offline-first UX\n const queryKey = useMemo(() => buildQueryKey(tableName, options), [tableName, serializedOptions]);\n\n // Memoize query options to prevent re-creating on every render\n const memoizedQueryOptions = useMemo(() => ({\n select: queryOptions.select,\n where: queryOptions.where,\n orderBy: queryOptions.orderBy,\n limit: queryOptions.limit,\n offset: queryOptions.offset\n }), [serializedOptions]);\n\n // Track the adapter name that was actually used for the most recent query\n // This is used for accurate logging since the memoized adapter may be stale\n const lastUsedAdapterNameRef = useRef<string>(\"unknown\");\n\n // Query function - resolve adapter lazily at query time to ensure we always\n // have the latest adapter instance (the memoized adapter may be stale)\n const queryFn = useCallback(async () => {\n // Use currentAdapter directly - registry.getAdapter() throws if unavailable\n const currentAdapter = registry.getAdapter(tableName);\n\n // Track which adapter was actually used for accurate logging\n lastUsedAdapterNameRef.current = currentAdapter.name;\n const result = await currentAdapter.query(tableName, memoizedQueryOptions);\n return result;\n }, [registry, tableName, memoizedQueryOptions]);\n\n // Execute query with React Query\n // Backend-aware caching strategy:\n // - PowerSync: SQLite is source of truth, always refetch from disk (it's fast)\n // - Supabase: Use normal React Query caching to avoid unnecessary network requests\n const query = useQuery({\n queryKey,\n queryFn,\n enabled: enabled && adapter !== null,\n staleTime,\n gcTime,\n refetchOnWindowFocus,\n refetchOnMount\n });\n\n // Create debounced invalidation function for subscriptions\n const invalidateTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const debouncedInvalidate = useCallback(() => {\n if (invalidateTimeoutRef.current) {\n clearTimeout(invalidateTimeoutRef.current);\n }\n invalidateTimeoutRef.current = setTimeout(() => {\n queryClient.invalidateQueries({\n queryKey\n });\n }, 100);\n }, [queryClient, queryKey]);\n\n // Clean up timeout on unmount\n useEffect(() => {\n return () => {\n if (invalidateTimeoutRef.current) {\n clearTimeout(invalidateTimeoutRef.current);\n }\n };\n }, []);\n\n // Set up real-time subscription if enabled\n useEffect(() => {\n // Resolve adapter lazily to get current backend\n let currentAdapter_0;\n try {\n currentAdapter_0 = registry.getAdapter(tableName);\n } catch {\n return; // Adapter not available yet\n }\n if (!realtime || !currentAdapter_0?.subscribe) {\n return;\n }\n\n // Only skip first callback for PowerSync adapter (which fires immediately with current data)\n // SupabaseAdapter's subscribe only fires on actual database changes\n // Use currentAdapter.name for the isFirstCallback check (survives minification)\n const isPowerSyncAdapter = currentAdapter_0.name === \"powersync\";\n let isFirstCallback = isPowerSyncAdapter;\n const unsubscribe = currentAdapter_0.subscribe(tableName, memoizedQueryOptions, data => {\n // Skip the first callback since initial query handles it\n if (isFirstCallback) {\n isFirstCallback = false;\n return;\n }\n\n // Check if query has relations (contains parentheses like \"Table(*)\")\n const hasRelations = memoizedQueryOptions.select?.includes(\"(\");\n if (hasRelations) {\n // Has relations - use debounced invalidation to prevent rapid successive invalidations\n debouncedInvalidate();\n } else {\n // No relations - safe to directly update cache with flat data\n queryClient.setQueryData(queryKey, {\n data,\n count: data.length\n });\n }\n });\n return () => {\n unsubscribe?.();\n };\n }, [realtime, registry, tableName, memoizedQueryOptions, queryClient, queryKey, debouncedInvalidate]);\n\n // Extract explicit FK relations for optimistic merge subscriptions\n const explicitFkRelations = useMemo<ExtractedExplicitFk[]>(() => {\n const select = memoizedQueryOptions.select;\n if (!select || !selectHasExplicitFkSyntax(select)) {\n return [];\n }\n const parsed = parseSelect(select);\n return extractExplicitFkRelations(parsed);\n }, [memoizedQueryOptions.select]);\n\n // Set up realtime subscriptions for explicit FK target tables\n // This enables optimistic merge when related records change\n useEffect(() => {\n // Skip if no explicit FK relations or realtime not enabled\n if (!realtime || explicitFkRelations.length === 0) {\n return;\n }\n\n // Resolve adapter lazily to get current backend\n let currentAdapter_1;\n try {\n currentAdapter_1 = registry.getAdapter(tableName);\n } catch {\n return; // Adapter not available yet\n }\n if (!currentAdapter_1?.subscribe) {\n return;\n }\n const isPowerSyncAdapter_0 = currentAdapter_1.name === \"powersync\";\n\n // Track unsubscribe functions for all related table watchers\n const unsubscribes: (() => void)[] = [];\n\n // Group relations by target table to avoid duplicate subscriptions\n const relationsByTable = new Map<string, ExtractedExplicitFk[]>();\n for (const relation of explicitFkRelations) {\n const existing = relationsByTable.get(relation.targetTable) ?? [];\n existing.push(relation);\n relationsByTable.set(relation.targetTable, existing);\n }\n\n // Set up a watcher for each unique target table\n for (const [targetTable, relations] of relationsByTable) {\n // Track if first callback (PowerSync fires immediately with current data)\n let isFirstCallback_0 = isPowerSyncAdapter_0;\n\n // Debounce timer for this table's updates\n let mergeTimeoutId: ReturnType<typeof setTimeout> | null = null;\n const unsubscribe_0 = currentAdapter_1.subscribe(targetTable, {\n select: \"*\"\n },\n // Watch all columns on the related table\n (changedRecords: Record<string, unknown>[]) => {\n // Skip the first callback since initial query handles it\n if (isFirstCallback_0) {\n isFirstCallback_0 = false;\n return;\n }\n\n // Debounce rapid updates during sync\n if (mergeTimeoutId) {\n clearTimeout(mergeTimeoutId);\n }\n mergeTimeoutId = setTimeout(() => {\n mergeTimeoutId = null;\n\n // Get current cached data\n const cachedResult = queryClient.getQueryData(queryKey) as {\n data?: Record<string, unknown>[];\n count?: number;\n } | undefined;\n if (!cachedResult?.data || cachedResult.data.length === 0) {\n // No cached data to merge into - trigger refetch instead\n debouncedInvalidate();\n return;\n }\n\n // Apply optimistic merge for each relation that uses this table\n let updatedData = cachedResult.data;\n let hasChanges = false;\n for (const relation_0 of relations) {\n const merged = mergeRelatedUpdate(updatedData, relation_0, changedRecords as {\n id: string;\n [key: string]: unknown;\n }[]);\n if (merged !== updatedData) {\n updatedData = merged;\n hasChanges = true;\n }\n }\n if (hasChanges) {\n // Update cache with merged data\n queryClient.setQueryData(queryKey, {\n data: updatedData,\n count: cachedResult.count\n });\n devLog(\"useDbQuery\", `${tableName}: Optimistic merge from ${targetTable} change`);\n }\n }, 50); // Small debounce to batch rapid changes\n });\n unsubscribes.push(() => {\n if (mergeTimeoutId) {\n clearTimeout(mergeTimeoutId);\n }\n unsubscribe_0?.();\n });\n }\n return () => {\n for (const unsubscribe_1 of unsubscribes) {\n unsubscribe_1();\n }\n };\n }, [realtime, registry, tableName, explicitFkRelations, queryClient, queryKey, debouncedInvalidate]);\n\n // Dev logging for debugging\n // Uses lastUsedAdapterNameRef to log the adapter that was ACTUALLY used for the query,\n // not the memoized adapter from render time (which may be stale due to auto-detection)\n useEffect(() => {\n const adapterName = lastUsedAdapterNameRef.current;\n\n // Log errors\n if (query.isError && query.error) {\n devWarn(\"useDbQuery\", `${tableName} via ${adapterName}: Error - ${query.error.message}`);\n }\n\n // Log empty results (only after successful fetch, not during loading)\n if (query.isSuccess && query.data?.data?.length === 0) {\n devLog(\"useDbQuery\", `${tableName} via ${adapterName}: 0 results`);\n }\n }, [query.isError, query.error, query.isSuccess, query.data, tableName]);\n\n // Build refetch function\n const refetch = useCallback(async () => {\n await query.refetch();\n }, [query]);\n return {\n data: query.data?.data as T[] | undefined,\n isLoading: query.isLoading,\n isPending: query.isPending,\n isFetching: query.isFetching,\n isRefetching: query.isFetching,\n // Alias for V2 compatibility\n isSuccess: query.isSuccess,\n isError: query.isError,\n error: query.error as Error | null,\n refetch,\n count: query.data?.count,\n isStale: query.isStale,\n dataUpdatedAt: query.dataUpdatedAt ?? null\n };\n}\nexport default useDbQuery;","/**\n * Development-only logging utility for V3 hooks\n *\n * Logs are only output when __DEV__ is true (development builds).\n * In production builds, these calls are no-ops.\n */\n\ndeclare const __DEV__: boolean;\n\n/**\n * Log a message with a prefix, only in development\n *\n * @param prefix - Hook or component name (e.g., \"useDbQuery\")\n * @param message - Message to log\n *\n * @example\n * devLog(\"useDbQuery\", \"EquipmentUnit via PowerSync: 0 results\");\n * // Output: [useDbQuery] EquipmentUnit via PowerSync: 0 results\n */\nexport function devLog(prefix: string, message: string): void {\n if (typeof __DEV__ !== \"undefined\" && __DEV__) {\n console.log(`[${prefix}] ${message}`);\n }\n}\n\n/**\n * Log a warning with a prefix, only in development\n */\nexport function devWarn(prefix: string, message: string): void {\n if (typeof __DEV__ !== \"undefined\" && __DEV__) {\n console.warn(`[${prefix}] ${message}`);\n }\n}\n\n/**\n * Log an error with a prefix, only in development\n */\nexport function devError(prefix: string, message: string, error?: unknown): void {\n if (typeof __DEV__ !== \"undefined\" && __DEV__) {\n if (error) {\n console.error(`[${prefix}] ${message}`, error);\n } else {\n console.error(`[${prefix}] ${message}`);\n }\n }\n}","/**\n * V3 useDbQueryById Hook\n *\n * React hook for querying a single record by ID from a table.\n * Works identically whether PowerSync or Supabase is the backend.\n * Uses React Query for state management and caching.\n */\n\nimport { useCallback, useEffect, useMemo, useRef } from \"react\";\nimport { useQuery } from \"@tanstack/react-query\";\nimport { useDataLayerCore } from \"./useDataLayer\";\nimport type { WhereClause } from \"../core/types\";\nimport { devLog, devWarn } from \"../utils/dev-log\";\n\n// =============================================================================\n// Types\n// =============================================================================\n\n/**\n * Options for useDbQueryById hook\n */\nexport interface UseDbQueryByIdOptions {\n /** Columns to select (Supabase-style select string) */\n select?: string;\n /** Whether the query is enabled (default: true if id is provided) */\n enabled?: boolean;\n /** React Query stale time in ms (default: 30000) */\n staleTime?: number;\n}\n\n/**\n * Result from useDbQueryById hook\n */\nexport interface UseDbQueryByIdResult<T> {\n /** Query data (undefined while loading, null if not found) */\n data: T | null | undefined;\n /** Whether query is loading (initial load) */\n isLoading: boolean;\n /** Whether query is in pending state */\n isPending: boolean;\n /** Whether query is currently fetching (including refetch) */\n isFetching: boolean;\n /** Query error if any */\n error: Error | null;\n /** Refetch the query */\n refetch: () => Promise<void>;\n}\n\n// =============================================================================\n// Helper Functions\n// =============================================================================\n\n/**\n * Build a query key for React Query\n *\n * Creates a stable, unique key for caching based on table, ID, and select.\n * Keys are namespaced with \"v3\" to avoid collisions with V2 queries.\n */\nfunction buildQueryKey(table: string, id: string | number | null | undefined, select?: string): unknown[] {\n return [\"v3\", \"queryById\", table, id, select ?? \"*\"];\n}\n\n// =============================================================================\n// Hook Implementation\n// =============================================================================\n\n/**\n * Hook for querying a single record by ID\n *\n * This hook provides a unified interface for fetching a single record that works\n * identically whether the backend is PowerSync (offline-first) or\n * Supabase (online-only). It uses React Query for caching and state management.\n *\n * Features:\n * - Automatic backend selection based on DataLayerProvider configuration\n * - React Query integration for caching, deduplication, and background updates\n * - Automatic disabling when ID is null/undefined\n * - Fallback to query with where clause if adapter doesn't support queryById\n * - Type-safe with generic type parameter\n *\n * @param table - The table name to query\n * @param id - The record ID (query is disabled if null/undefined)\n * @param options - Query options (select, enabled, staleTime)\n * @returns Query result with data, loading states, error, and refetch function\n *\n * @example\n * // Basic query by ID\n * const { data, isLoading, error } = useDbQueryById<Task>(\"Task\", taskId);\n *\n * @example\n * // Query with relations\n * const { data, isLoading, error } = useDbQueryById<Task>(\"Task\", taskId, {\n * select: \"*, Project(*), AssignedUser:User(*)\",\n * });\n *\n * @example\n * // Conditional query based on other state\n * const { data } = useDbQueryById<Project>(\"Project\", selectedProjectId, {\n * enabled: hasPermission && !!selectedProjectId,\n * });\n *\n * @example\n * // With custom stale time\n * const { data } = useDbQueryById<User>(\"User\", userId, {\n * staleTime: 60000, // 1 minute\n * });\n */\nexport function useDbQueryById<T = Record<string, unknown>>(table: string, id: string | number | null | undefined, options: UseDbQueryByIdOptions = {}): UseDbQueryByIdResult<T> {\n const {\n registry\n } = useDataLayerCore();\n const {\n select,\n enabled = id != null,\n staleTime = 30000\n } = options;\n\n // Get adapter for this table\n // No isInitialized check needed - if we get here, core context exists = initialized\n const adapter = useMemo(() => {\n try {\n return registry.getAdapter(table);\n } catch (error) {\n devWarn(\"useDbQueryById\", `Failed to get adapter for ${table}: ${(error as Error).message}`);\n return null;\n }\n }, [registry, table]);\n\n // Build query key - memoized to prevent unnecessary re-renders\n const queryKey = useMemo(() => buildQueryKey(table, id, select), [table, id, select]);\n\n // Track the adapter name that was actually used for the most recent query\n // This is used for accurate logging since the memoized adapter may be stale\n const lastUsedAdapterNameRef = useRef<string>(\"unknown\");\n\n // Query function - resolve adapter lazily at query time to ensure we always\n // have the latest adapter instance (the memoized adapter may be stale)\n const queryFn = useCallback(async (): Promise<T | null> => {\n if (id == null) {\n return null;\n }\n\n // Use currentAdapter directly - registry.getAdapter() throws if unavailable\n const currentAdapter = registry.getAdapter(table);\n\n // Track which adapter was actually used for accurate logging\n lastUsedAdapterNameRef.current = currentAdapter.name;\n\n // Use queryById if available, otherwise fall back to query with where\n if (currentAdapter.queryById) {\n return currentAdapter.queryById<T>(table, String(id), {\n select\n });\n }\n\n // Fallback: use query with where clause\n const result = await currentAdapter.query<T>(table, {\n select,\n where: {\n id\n } as WhereClause,\n limit: 1\n });\n return result.data[0] ?? null;\n }, [registry, table, id, select]);\n\n // Execute query with React Query\n const query = useQuery({\n queryKey,\n queryFn,\n enabled: enabled && adapter !== null && id != null,\n staleTime\n });\n\n // Dev logging for debugging\n // Uses lastUsedAdapterNameRef to log the adapter that was ACTUALLY used for the query,\n // not the memoized adapter from render time (which may be stale due to auto-detection)\n useEffect(() => {\n const adapterName = lastUsedAdapterNameRef.current;\n\n // Log errors\n if (query.isError && query.error) {\n devWarn(\"useDbQueryById\", `${table}(${id}) via ${adapterName}: Error - ${query.error.message}`);\n }\n\n // Log not found (only after successful fetch, not during loading)\n if (query.isSuccess && query.data === null) {\n devLog(\"useDbQueryById\", `${table}(${id}) via ${adapterName}: not found`);\n }\n }, [query.isError, query.error, query.isSuccess, query.data, table, id]);\n\n // Build refetch function\n const refetch = useCallback(async () => {\n await query.refetch();\n }, [query]);\n return {\n data: query.data,\n isLoading: query.isLoading,\n isPending: query.isPending,\n isFetching: query.isFetching,\n error: query.error as Error | null,\n refetch\n };\n}\nexport default useDbQueryById;"],"mappings":"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","names":["BackendStatus","useCallback","useEffect","useMemo","useRef","useQuery","buildQueryKey","useMemo","useRef","useCallback","useQuery","useEffect"]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
permissionContext,
|
|
3
3
|
setupAuthContext
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-ARALLEDJ.js";
|
|
5
5
|
|
|
6
6
|
// src/auth/hooks/useAuth.ts
|
|
7
7
|
import { isUsable } from "@pol-studios/utils";
|
|
@@ -205,4 +205,4 @@ export {
|
|
|
205
205
|
useInvalidatePermission,
|
|
206
206
|
usePermissionLoading
|
|
207
207
|
};
|
|
208
|
-
//# sourceMappingURL=chunk-
|
|
208
|
+
//# sourceMappingURL=chunk-SNPZMRBC.js.map
|