@pol-studios/db 1.0.51 → 1.0.52
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--jqUiEMX.d.ts → DataLayerContext-C7cJtiO8.d.ts} +3 -3
- package/dist/{chunk-PGTRDT5K.js → chunk-EOJGUOJR.js} +674 -695
- package/dist/chunk-EOJGUOJR.js.map +1 -0
- package/dist/{chunk-G6E25CWV.js → chunk-GSORUAS7.js} +2 -2
- package/dist/hooks/index.d.ts +2 -2
- package/dist/{index-CJ8GAb_-.d.ts → index-jVYdTeWx.d.ts} +1 -1
- package/dist/index.d.ts +4 -4
- package/dist/index.js +2 -2
- package/dist/index.native.d.ts +5 -5
- package/dist/index.native.js +2 -2
- package/dist/index.web.d.ts +6 -6
- package/dist/index.web.js +1 -1
- package/dist/types/index.d.ts +2 -2
- package/dist/{useDbCount-DeXtNH0E.d.ts → useDbCount-DHLJzmkO.d.ts} +1 -1
- package/dist/{useResolveFeedback-HTdDM4AQ.d.ts → useResolveFeedback-B0UcYWVI.d.ts} +3 -3
- package/package.json +1 -1
- package/dist/chunk-PGTRDT5K.js.map +0 -1
- /package/dist/{chunk-G6E25CWV.js.map → chunk-GSORUAS7.js.map} +0 -0
|
@@ -4143,334 +4143,6 @@ var ADAPTER_STRATEGIES = {
|
|
|
4143
4143
|
AUTO: "auto"
|
|
4144
4144
|
};
|
|
4145
4145
|
|
|
4146
|
-
// src/adapters/auto-detector.ts
|
|
4147
|
-
var BackendStatus = /* @__PURE__ */ ((BackendStatus2) => {
|
|
4148
|
-
BackendStatus2["AVAILABLE"] = "available";
|
|
4149
|
-
BackendStatus2["INITIALIZING"] = "initializing";
|
|
4150
|
-
BackendStatus2["UNAVAILABLE"] = "unavailable";
|
|
4151
|
-
return BackendStatus2;
|
|
4152
|
-
})(BackendStatus || {});
|
|
4153
|
-
var AdapterAutoDetector = class {
|
|
4154
|
-
constructor(powerSyncDb, supabase, options = {}) {
|
|
4155
|
-
this.powerSyncDb = powerSyncDb;
|
|
4156
|
-
this.supabase = supabase;
|
|
4157
|
-
this.options = {
|
|
4158
|
-
preferPowerSync: options.preferPowerSync ?? true,
|
|
4159
|
-
statusCheckTimeout: options.statusCheckTimeout ?? 1e3,
|
|
4160
|
-
useOnlineUntilSynced: options.useOnlineUntilSynced ?? true
|
|
4161
|
-
};
|
|
4162
|
-
}
|
|
4163
|
-
options;
|
|
4164
|
-
listeners = /* @__PURE__ */ new Set();
|
|
4165
|
-
lastResult = null;
|
|
4166
|
-
syncStatus = null;
|
|
4167
|
-
/**
|
|
4168
|
-
* Update the PowerSync database reference.
|
|
4169
|
-
* Called when PowerSync becomes available after initial construction.
|
|
4170
|
-
*
|
|
4171
|
-
* @param db - PowerSync database instance or null
|
|
4172
|
-
*/
|
|
4173
|
-
setPowerSyncDb(db) {
|
|
4174
|
-
this.powerSyncDb = db;
|
|
4175
|
-
if (db) {
|
|
4176
|
-
this.detect();
|
|
4177
|
-
}
|
|
4178
|
-
}
|
|
4179
|
-
/**
|
|
4180
|
-
* Update the sync status from PowerSync.
|
|
4181
|
-
* Called when sync status changes to re-evaluate backend recommendation.
|
|
4182
|
-
*
|
|
4183
|
-
* @param status - Current sync status or null if not available
|
|
4184
|
-
*/
|
|
4185
|
-
updateSyncStatus(status) {
|
|
4186
|
-
const hadSynced = this.syncStatus?.hasSynced;
|
|
4187
|
-
const hasSyncedNow = status?.hasSynced;
|
|
4188
|
-
const changed = hadSynced !== hasSyncedNow;
|
|
4189
|
-
this.syncStatus = status;
|
|
4190
|
-
if (changed) {
|
|
4191
|
-
this.detect();
|
|
4192
|
-
}
|
|
4193
|
-
}
|
|
4194
|
-
/**
|
|
4195
|
-
* Get current sync status.
|
|
4196
|
-
* @returns Current sync status or null
|
|
4197
|
-
*/
|
|
4198
|
-
getSyncStatus() {
|
|
4199
|
-
return this.syncStatus;
|
|
4200
|
-
}
|
|
4201
|
-
// ===========================================================================
|
|
4202
|
-
// Main Detection Methods
|
|
4203
|
-
// ===========================================================================
|
|
4204
|
-
/**
|
|
4205
|
-
* Detect backend availability and recommend best option.
|
|
4206
|
-
*
|
|
4207
|
-
* The detection logic follows this priority:
|
|
4208
|
-
* 1. If preferPowerSync is true and PowerSync is available, use PowerSync
|
|
4209
|
-
* 2. If PowerSync is initializing and online with Supabase available, use Supabase temporarily
|
|
4210
|
-
* 3. If online with Supabase available, use Supabase
|
|
4211
|
-
* 4. If offline but PowerSync available, use PowerSync (offline mode)
|
|
4212
|
-
* 5. If offline and PowerSync exists (even if initializing), use PowerSync local data
|
|
4213
|
-
* 6. Default to Supabase as fallback
|
|
4214
|
-
*
|
|
4215
|
-
* @returns Detection result with recommendation and reasoning
|
|
4216
|
-
*/
|
|
4217
|
-
detect() {
|
|
4218
|
-
const result = this.performDetection();
|
|
4219
|
-
if (this.hasResultChanged(result)) {
|
|
4220
|
-
this.lastResult = result;
|
|
4221
|
-
this.notifyListeners(result);
|
|
4222
|
-
}
|
|
4223
|
-
return result;
|
|
4224
|
-
}
|
|
4225
|
-
/**
|
|
4226
|
-
* Detect backend availability WITHOUT notifying listeners.
|
|
4227
|
-
*
|
|
4228
|
-
* This method is safe to call during React's render phase because it does not
|
|
4229
|
-
* trigger state updates in other components. Use this method when you need to
|
|
4230
|
-
* check backend status synchronously during render (e.g., in getAdapter()).
|
|
4231
|
-
*
|
|
4232
|
-
* The regular detect() method with listener notifications should only be called
|
|
4233
|
-
* from useEffect or event handlers to avoid the React warning:
|
|
4234
|
-
* "Cannot update a component while rendering a different component"
|
|
4235
|
-
*
|
|
4236
|
-
* @returns Detection result with recommendation and reasoning
|
|
4237
|
-
*/
|
|
4238
|
-
detectSilent() {
|
|
4239
|
-
const result = this.performDetection();
|
|
4240
|
-
this.lastResult = result;
|
|
4241
|
-
return result;
|
|
4242
|
-
}
|
|
4243
|
-
/**
|
|
4244
|
-
* Internal detection logic shared by detect() and detectSilent().
|
|
4245
|
-
* @private
|
|
4246
|
-
*/
|
|
4247
|
-
performDetection() {
|
|
4248
|
-
const powerSyncStatus = this.detectPowerSyncStatus();
|
|
4249
|
-
const supabaseStatus = this.detectSupabaseStatus();
|
|
4250
|
-
const isOnline = this.checkOnlineStatus();
|
|
4251
|
-
let recommendedBackend;
|
|
4252
|
-
let reason;
|
|
4253
|
-
if (this.options.preferPowerSync && powerSyncStatus === "available" /* AVAILABLE */) {
|
|
4254
|
-
recommendedBackend = "powersync";
|
|
4255
|
-
reason = "PowerSync is available and preferred for offline-first experience";
|
|
4256
|
-
} else if (powerSyncStatus === "initializing" /* INITIALIZING */ && isOnline && supabaseStatus === "available" /* AVAILABLE */) {
|
|
4257
|
-
recommendedBackend = "supabase";
|
|
4258
|
-
reason = "PowerSync initial sync in progress; using Supabase for fresh data";
|
|
4259
|
-
} else if (supabaseStatus === "available" /* AVAILABLE */ && isOnline) {
|
|
4260
|
-
recommendedBackend = "supabase";
|
|
4261
|
-
reason = "Using Supabase direct connection";
|
|
4262
|
-
} else if (powerSyncStatus === "available" /* AVAILABLE */) {
|
|
4263
|
-
recommendedBackend = "powersync";
|
|
4264
|
-
reason = "Offline mode using PowerSync local data";
|
|
4265
|
-
} else if (!isOnline && this.powerSyncDb) {
|
|
4266
|
-
recommendedBackend = "powersync";
|
|
4267
|
-
reason = "Offline mode - using PowerSync local data (initial sync may be incomplete)";
|
|
4268
|
-
} else {
|
|
4269
|
-
recommendedBackend = "supabase";
|
|
4270
|
-
reason = "No confirmed available backend; defaulting to Supabase";
|
|
4271
|
-
}
|
|
4272
|
-
return {
|
|
4273
|
-
powerSyncStatus,
|
|
4274
|
-
supabaseStatus,
|
|
4275
|
-
recommendedBackend,
|
|
4276
|
-
isOnline,
|
|
4277
|
-
reason
|
|
4278
|
-
};
|
|
4279
|
-
}
|
|
4280
|
-
/**
|
|
4281
|
-
* Check if PowerSync is available.
|
|
4282
|
-
*
|
|
4283
|
-
* PowerSync status depends on:
|
|
4284
|
-
* 1. Database instance exists
|
|
4285
|
-
* 2. If useOnlineUntilSynced is true, also checks if initial sync completed
|
|
4286
|
-
*
|
|
4287
|
-
* @returns PowerSync backend status
|
|
4288
|
-
*/
|
|
4289
|
-
detectPowerSyncStatus() {
|
|
4290
|
-
if (!this.powerSyncDb) {
|
|
4291
|
-
return "unavailable" /* UNAVAILABLE */;
|
|
4292
|
-
}
|
|
4293
|
-
try {
|
|
4294
|
-
if (typeof this.powerSyncDb.getAll !== "function") {
|
|
4295
|
-
return "initializing" /* INITIALIZING */;
|
|
4296
|
-
}
|
|
4297
|
-
if (this.options.useOnlineUntilSynced) {
|
|
4298
|
-
if (!this.syncStatus || !this.syncStatus.hasSynced) {
|
|
4299
|
-
return "initializing" /* INITIALIZING */;
|
|
4300
|
-
}
|
|
4301
|
-
}
|
|
4302
|
-
return "available" /* AVAILABLE */;
|
|
4303
|
-
} catch {
|
|
4304
|
-
return "initializing" /* INITIALIZING */;
|
|
4305
|
-
}
|
|
4306
|
-
}
|
|
4307
|
-
/**
|
|
4308
|
-
* Check if Supabase is available.
|
|
4309
|
-
*
|
|
4310
|
-
* Supabase is considered available if we have a client instance.
|
|
4311
|
-
* The actual network connectivity is checked separately via checkOnlineStatus().
|
|
4312
|
-
*
|
|
4313
|
-
* @returns Supabase backend status
|
|
4314
|
-
*/
|
|
4315
|
-
detectSupabaseStatus() {
|
|
4316
|
-
if (!this.supabase) {
|
|
4317
|
-
return "unavailable" /* UNAVAILABLE */;
|
|
4318
|
-
}
|
|
4319
|
-
try {
|
|
4320
|
-
if (typeof this.supabase.from === "function") {
|
|
4321
|
-
return "available" /* AVAILABLE */;
|
|
4322
|
-
}
|
|
4323
|
-
return "unavailable" /* UNAVAILABLE */;
|
|
4324
|
-
} catch {
|
|
4325
|
-
return "unavailable" /* UNAVAILABLE */;
|
|
4326
|
-
}
|
|
4327
|
-
}
|
|
4328
|
-
/**
|
|
4329
|
-
* Check if device is online.
|
|
4330
|
-
*
|
|
4331
|
-
* Prefers the sync status's isOnline property if available (from React Native NetInfo).
|
|
4332
|
-
* Falls back to navigator.onLine in browser environments.
|
|
4333
|
-
* Returns false by default for non-browser environments (React Native, Node.js, etc.)
|
|
4334
|
-
* to ensure offline-first behavior works correctly.
|
|
4335
|
-
*
|
|
4336
|
-
* @returns Whether the device has network connectivity
|
|
4337
|
-
*/
|
|
4338
|
-
checkOnlineStatus() {
|
|
4339
|
-
if (this.syncStatus?.isOnline !== void 0) {
|
|
4340
|
-
return this.syncStatus.isOnline;
|
|
4341
|
-
}
|
|
4342
|
-
if (typeof window !== "undefined" && typeof navigator !== "undefined") {
|
|
4343
|
-
return navigator.onLine;
|
|
4344
|
-
}
|
|
4345
|
-
return false;
|
|
4346
|
-
}
|
|
4347
|
-
// ===========================================================================
|
|
4348
|
-
// Instance Management Methods
|
|
4349
|
-
// ===========================================================================
|
|
4350
|
-
/**
|
|
4351
|
-
* Update PowerSync instance (e.g., when it becomes available).
|
|
4352
|
-
*
|
|
4353
|
-
* @param db - New PowerSync database instance or null
|
|
4354
|
-
*/
|
|
4355
|
-
setPowerSync(db) {
|
|
4356
|
-
this.powerSyncDb = db;
|
|
4357
|
-
}
|
|
4358
|
-
/**
|
|
4359
|
-
* Update Supabase instance.
|
|
4360
|
-
*
|
|
4361
|
-
* @param supabase - New Supabase client instance or null
|
|
4362
|
-
*/
|
|
4363
|
-
setSupabase(supabase) {
|
|
4364
|
-
this.supabase = supabase;
|
|
4365
|
-
}
|
|
4366
|
-
/**
|
|
4367
|
-
* Get current PowerSync instance.
|
|
4368
|
-
*
|
|
4369
|
-
* @returns Current PowerSync database instance or null
|
|
4370
|
-
*/
|
|
4371
|
-
getPowerSync() {
|
|
4372
|
-
return this.powerSyncDb;
|
|
4373
|
-
}
|
|
4374
|
-
/**
|
|
4375
|
-
* Get current Supabase instance.
|
|
4376
|
-
*
|
|
4377
|
-
* @returns Current Supabase client instance or null
|
|
4378
|
-
*/
|
|
4379
|
-
getSupabase() {
|
|
4380
|
-
return this.supabase;
|
|
4381
|
-
}
|
|
4382
|
-
// ===========================================================================
|
|
4383
|
-
// Options Management
|
|
4384
|
-
// ===========================================================================
|
|
4385
|
-
/**
|
|
4386
|
-
* Update detector options.
|
|
4387
|
-
*
|
|
4388
|
-
* @param options - New options to merge with existing
|
|
4389
|
-
*/
|
|
4390
|
-
setOptions(options) {
|
|
4391
|
-
this.options = {
|
|
4392
|
-
...this.options,
|
|
4393
|
-
...options
|
|
4394
|
-
};
|
|
4395
|
-
}
|
|
4396
|
-
/**
|
|
4397
|
-
* Get current detector options.
|
|
4398
|
-
*
|
|
4399
|
-
* @returns Current detector options
|
|
4400
|
-
*/
|
|
4401
|
-
getOptions() {
|
|
4402
|
-
return {
|
|
4403
|
-
...this.options
|
|
4404
|
-
};
|
|
4405
|
-
}
|
|
4406
|
-
// ===========================================================================
|
|
4407
|
-
// Listener Management
|
|
4408
|
-
// ===========================================================================
|
|
4409
|
-
/**
|
|
4410
|
-
* Add a listener for backend change events.
|
|
4411
|
-
*
|
|
4412
|
-
* @param listener - Callback to invoke when detection result changes
|
|
4413
|
-
* @returns Function to remove the listener
|
|
4414
|
-
*/
|
|
4415
|
-
addListener(listener) {
|
|
4416
|
-
this.listeners.add(listener);
|
|
4417
|
-
return () => this.listeners.delete(listener);
|
|
4418
|
-
}
|
|
4419
|
-
/**
|
|
4420
|
-
* Remove a listener for backend change events.
|
|
4421
|
-
*
|
|
4422
|
-
* @param listener - Listener to remove
|
|
4423
|
-
*/
|
|
4424
|
-
removeListener(listener) {
|
|
4425
|
-
this.listeners.delete(listener);
|
|
4426
|
-
}
|
|
4427
|
-
/**
|
|
4428
|
-
* Get the last detection result.
|
|
4429
|
-
*
|
|
4430
|
-
* @returns Last detection result or null if never detected
|
|
4431
|
-
*/
|
|
4432
|
-
getLastResult() {
|
|
4433
|
-
return this.lastResult;
|
|
4434
|
-
}
|
|
4435
|
-
// ===========================================================================
|
|
4436
|
-
// Private Helper Methods
|
|
4437
|
-
// ===========================================================================
|
|
4438
|
-
/**
|
|
4439
|
-
* Check if the detection result has changed from the last result.
|
|
4440
|
-
*/
|
|
4441
|
-
hasResultChanged(result) {
|
|
4442
|
-
if (!this.lastResult) {
|
|
4443
|
-
return true;
|
|
4444
|
-
}
|
|
4445
|
-
return this.lastResult.powerSyncStatus !== result.powerSyncStatus || this.lastResult.supabaseStatus !== result.supabaseStatus || this.lastResult.recommendedBackend !== result.recommendedBackend || this.lastResult.isOnline !== result.isOnline;
|
|
4446
|
-
}
|
|
4447
|
-
/**
|
|
4448
|
-
* Notify all listeners of a detection result change.
|
|
4449
|
-
*/
|
|
4450
|
-
notifyListeners(result) {
|
|
4451
|
-
const isDev = typeof __DEV__ !== "undefined" ? __DEV__ : process.env.NODE_ENV !== "production";
|
|
4452
|
-
if (isDev) {
|
|
4453
|
-
const prevBackend = this.lastResult?.recommendedBackend;
|
|
4454
|
-
if (prevBackend && prevBackend !== result.recommendedBackend) {
|
|
4455
|
-
console.log(`[DataLayer] Backend switched: ${prevBackend} \u2192 ${result.recommendedBackend}`, `| Reason: ${result.reason}`);
|
|
4456
|
-
}
|
|
4457
|
-
if (result.recommendedBackend === "supabase" && this.options.preferPowerSync) {
|
|
4458
|
-
console.log(`[DataLayer] Using online fallback (Supabase)`, `| PowerSync: ${result.powerSyncStatus}`, `| Online: ${result.isOnline}`, `| Reason: ${result.reason}`);
|
|
4459
|
-
}
|
|
4460
|
-
}
|
|
4461
|
-
Array.from(this.listeners).forEach((listener) => {
|
|
4462
|
-
try {
|
|
4463
|
-
listener(result);
|
|
4464
|
-
} catch (error) {
|
|
4465
|
-
console.error("Error in backend change listener:", error);
|
|
4466
|
-
}
|
|
4467
|
-
});
|
|
4468
|
-
}
|
|
4469
|
-
};
|
|
4470
|
-
function createAdapterAutoDetector(powerSyncDb, supabase, options) {
|
|
4471
|
-
return new AdapterAutoDetector(powerSyncDb, supabase, options);
|
|
4472
|
-
}
|
|
4473
|
-
|
|
4474
4146
|
// src/adapters/sync-tracking-adapter.ts
|
|
4475
4147
|
var DEBUG_SYNC_TRACKING_VERBOSE = false;
|
|
4476
4148
|
function debugLog(message, ...args) {
|
|
@@ -4623,496 +4295,803 @@ var AdapterRegistry = class {
|
|
|
4623
4295
|
*/
|
|
4624
4296
|
adapters = /* @__PURE__ */ new Map();
|
|
4625
4297
|
/**
|
|
4626
|
-
* PowerSync adapter instance (set during initialization or lazily via getter)
|
|
4298
|
+
* PowerSync adapter instance (set during initialization or lazily via getter)
|
|
4299
|
+
*/
|
|
4300
|
+
powerSyncAdapter = null;
|
|
4301
|
+
/**
|
|
4302
|
+
* Getter function to retrieve PowerSync database instance.
|
|
4303
|
+
* Used for lazy initialization when PowerSync becomes available after registry creation.
|
|
4304
|
+
*/
|
|
4305
|
+
powerSyncGetter = null;
|
|
4306
|
+
/**
|
|
4307
|
+
* Factory function to create PowerSync adapter from database instance.
|
|
4308
|
+
* Set via setPowerSyncGetter along with the getter.
|
|
4309
|
+
*/
|
|
4310
|
+
powerSyncAdapterFactory = null;
|
|
4311
|
+
/**
|
|
4312
|
+
* Supabase adapter instance (set during initialization)
|
|
4313
|
+
*/
|
|
4314
|
+
supabaseAdapter = null;
|
|
4315
|
+
/**
|
|
4316
|
+
* Cached adapter instance (wraps Supabase with TanStack Query)
|
|
4317
|
+
*/
|
|
4318
|
+
cachedAdapter = null;
|
|
4319
|
+
/**
|
|
4320
|
+
* Dependencies for creating adapters
|
|
4321
|
+
*/
|
|
4322
|
+
deps = null;
|
|
4323
|
+
/**
|
|
4324
|
+
* Whether the registry has been initialized with adapters
|
|
4325
|
+
*/
|
|
4326
|
+
_isInitialized = false;
|
|
4327
|
+
/**
|
|
4328
|
+
* Auto-detector instance for automatic backend selection
|
|
4329
|
+
*/
|
|
4330
|
+
autoDetector = null;
|
|
4331
|
+
/**
|
|
4332
|
+
* Sync tracker for mutation tracking
|
|
4333
|
+
*/
|
|
4334
|
+
syncTracker = null;
|
|
4335
|
+
/**
|
|
4336
|
+
* Sync tracking adapter that wraps PowerSync adapter
|
|
4337
|
+
*/
|
|
4338
|
+
syncTrackingAdapter = null;
|
|
4339
|
+
/**
|
|
4340
|
+
* Listeners for backend change events
|
|
4341
|
+
*/
|
|
4342
|
+
backendChangeListeners = /* @__PURE__ */ new Set();
|
|
4343
|
+
/**
|
|
4344
|
+
* Last auto-detection result for debugging and status
|
|
4345
|
+
*/
|
|
4346
|
+
lastDetectionResult = null;
|
|
4347
|
+
// ===========================================================================
|
|
4348
|
+
// Initialization
|
|
4349
|
+
// ===========================================================================
|
|
4350
|
+
/**
|
|
4351
|
+
* Check if the registry has been initialized
|
|
4352
|
+
*/
|
|
4353
|
+
get isInitialized() {
|
|
4354
|
+
return this._isInitialized;
|
|
4355
|
+
}
|
|
4356
|
+
/**
|
|
4357
|
+
* Initialize the registry with dependencies.
|
|
4358
|
+
* Called by DataLayerProvider when PowerSync and Supabase are ready.
|
|
4359
|
+
*
|
|
4360
|
+
* @param deps - Dependencies needed to create adapters
|
|
4361
|
+
*/
|
|
4362
|
+
initialize(deps) {
|
|
4363
|
+
this.deps = deps;
|
|
4364
|
+
this._isInitialized = true;
|
|
4365
|
+
}
|
|
4366
|
+
/**
|
|
4367
|
+
* Set the PowerSync adapter instance
|
|
4368
|
+
*
|
|
4369
|
+
* @param adapter - PowerSync adapter implementation
|
|
4370
|
+
*/
|
|
4371
|
+
setPowerSyncAdapter(adapter) {
|
|
4372
|
+
this.powerSyncAdapter = adapter;
|
|
4373
|
+
if (this.syncTracker) {
|
|
4374
|
+
this.syncTrackingAdapter = new SyncTrackingAdapter(adapter, this.syncTracker);
|
|
4375
|
+
} else {
|
|
4376
|
+
this.syncTrackingAdapter = null;
|
|
4377
|
+
}
|
|
4378
|
+
this.adapters.clear();
|
|
4379
|
+
}
|
|
4380
|
+
/**
|
|
4381
|
+
* Set a getter function for lazy PowerSync adapter initialization.
|
|
4382
|
+
*
|
|
4383
|
+
* This allows the registry to lazily create the PowerSync adapter when
|
|
4384
|
+
* PowerSync becomes available, rather than requiring it at initialization time.
|
|
4385
|
+
* Solves race conditions where queries/mutations run before PowerSync is ready.
|
|
4386
|
+
*
|
|
4387
|
+
* @param getter - Function that returns the PowerSync database instance (or null if not ready)
|
|
4388
|
+
* @param factory - Function that creates a TableDataAdapter from the database instance
|
|
4389
|
+
*/
|
|
4390
|
+
setPowerSyncGetter(getter, factory) {
|
|
4391
|
+
this.powerSyncGetter = getter;
|
|
4392
|
+
this.powerSyncAdapterFactory = factory;
|
|
4393
|
+
}
|
|
4394
|
+
/**
|
|
4395
|
+
* Ensure PowerSync adapter is initialized if available.
|
|
4396
|
+
*
|
|
4397
|
+
* Checks the getter (if set) and lazily creates the adapter if PowerSync
|
|
4398
|
+
* is now available. Also updates the auto-detector with the new reference.
|
|
4399
|
+
*
|
|
4400
|
+
* @returns true if PowerSync adapter is available, false otherwise
|
|
4401
|
+
*/
|
|
4402
|
+
ensurePowerSyncAdapter() {
|
|
4403
|
+
if (this.powerSyncAdapter) {
|
|
4404
|
+
return true;
|
|
4405
|
+
}
|
|
4406
|
+
if (!this.powerSyncGetter || !this.powerSyncAdapterFactory) {
|
|
4407
|
+
return false;
|
|
4408
|
+
}
|
|
4409
|
+
const db = this.powerSyncGetter();
|
|
4410
|
+
if (!db) {
|
|
4411
|
+
return false;
|
|
4412
|
+
}
|
|
4413
|
+
const adapter = this.powerSyncAdapterFactory(db);
|
|
4414
|
+
this.setPowerSyncAdapter(adapter);
|
|
4415
|
+
if (this.autoDetector) {
|
|
4416
|
+
this.autoDetector.setPowerSyncDb(db);
|
|
4417
|
+
}
|
|
4418
|
+
return true;
|
|
4419
|
+
}
|
|
4420
|
+
/**
|
|
4421
|
+
* Set the sync tracker for mutation tracking.
|
|
4422
|
+
* When set, write operations on PowerSync tables will
|
|
4423
|
+
* automatically track pending mutations.
|
|
4424
|
+
*
|
|
4425
|
+
* NOTE: This also clears the adapter cache to ensure any
|
|
4426
|
+
* previously cached adapters (which may have been created
|
|
4427
|
+
* before the sync tracker was available) are recreated
|
|
4428
|
+
* with the new sync tracker on next access.
|
|
4429
|
+
*/
|
|
4430
|
+
setSyncTracker(tracker) {
|
|
4431
|
+
this.syncTracker = tracker;
|
|
4432
|
+
if (this.powerSyncAdapter) {
|
|
4433
|
+
this.syncTrackingAdapter = new SyncTrackingAdapter(this.powerSyncAdapter, tracker);
|
|
4434
|
+
}
|
|
4435
|
+
this.adapters.clear();
|
|
4436
|
+
}
|
|
4437
|
+
/**
|
|
4438
|
+
* Set the Supabase adapter instance
|
|
4439
|
+
*
|
|
4440
|
+
* @param adapter - Supabase adapter implementation
|
|
4441
|
+
*/
|
|
4442
|
+
setSupabaseAdapter(adapter) {
|
|
4443
|
+
this.supabaseAdapter = adapter;
|
|
4444
|
+
}
|
|
4445
|
+
/**
|
|
4446
|
+
* Set the Cached adapter instance
|
|
4447
|
+
*
|
|
4448
|
+
* @param adapter - Cached adapter implementation
|
|
4449
|
+
*/
|
|
4450
|
+
setCachedAdapter(adapter) {
|
|
4451
|
+
this.cachedAdapter = adapter;
|
|
4452
|
+
}
|
|
4453
|
+
/**
|
|
4454
|
+
* Initialize auto-detection with a detector instance
|
|
4455
|
+
*
|
|
4456
|
+
* @param detector - The auto-detector to use
|
|
4457
|
+
*/
|
|
4458
|
+
initializeAutoDetection(detector) {
|
|
4459
|
+
this.autoDetector = detector;
|
|
4460
|
+
detector.addListener((result) => {
|
|
4461
|
+
this.lastDetectionResult = result;
|
|
4462
|
+
this.notifyBackendChange(result.recommendedBackend);
|
|
4463
|
+
});
|
|
4464
|
+
}
|
|
4465
|
+
// ===========================================================================
|
|
4466
|
+
// Adapter Access
|
|
4467
|
+
// ===========================================================================
|
|
4468
|
+
/**
|
|
4469
|
+
* Get the appropriate adapter for a table based on configuration.
|
|
4470
|
+
*
|
|
4471
|
+
* The adapter is selected based on the table's strategy in config.tables:
|
|
4472
|
+
* - "powersync": Returns PowerSyncAdapter
|
|
4473
|
+
* - "supabase": Returns SupabaseAdapter
|
|
4474
|
+
* - "cached": Returns CachedAdapter (wrapping Supabase)
|
|
4475
|
+
* - "hybrid": Returns HybridAdapter (combining PowerSync + Cached)
|
|
4476
|
+
* - "auto": Uses auto-detection to select the best backend
|
|
4477
|
+
*
|
|
4478
|
+
* For tables not in config, defaults to auto-detection if available,
|
|
4479
|
+
* otherwise falls back to SupabaseAdapter.
|
|
4480
|
+
*
|
|
4481
|
+
* Supports schema-qualified table names:
|
|
4482
|
+
* - "core.Profile" looks up config["core.Profile"] first, then config["Profile"]
|
|
4483
|
+
* - Auto-generates PowerSync alias as "CoreProfile" if not explicitly set
|
|
4484
|
+
*
|
|
4485
|
+
* @param table - The table name (may be schema-qualified like "core.Profile")
|
|
4486
|
+
* @param operation - The operation type: 'read' uses fallback logic during init, 'write' always uses PowerSync for powersync tables
|
|
4487
|
+
* @returns The appropriate adapter for the table
|
|
4488
|
+
* @throws Error if adapters are not initialized
|
|
4489
|
+
*/
|
|
4490
|
+
getAdapter(table, _operation = "read") {
|
|
4491
|
+
this.ensurePowerSyncAdapter();
|
|
4492
|
+
const tableWithoutSchema = table.includes(".") ? table.split(".")[1] : table;
|
|
4493
|
+
const strategy = this.config.tables[table] ?? this.config.tables[tableWithoutSchema];
|
|
4494
|
+
if (!strategy || strategy.strategy === "auto") {
|
|
4495
|
+
if (this.powerSyncAdapter) {
|
|
4496
|
+
const powerSyncTableKeys = this.getPowerSyncTableKeys();
|
|
4497
|
+
const isConfigured = powerSyncTableKeys.some((key) => key === table || key === tableWithoutSchema || key.includes(".") && key.split(".")[1] === tableWithoutSchema);
|
|
4498
|
+
if (!isConfigured) {
|
|
4499
|
+
if (this.supabaseAdapter) {
|
|
4500
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
4501
|
+
console.warn(`[AdapterRegistry] Table "${table}" is not configured for PowerSync sync. Using Supabase fallback.`);
|
|
4502
|
+
}
|
|
4503
|
+
return this.supabaseAdapter;
|
|
4504
|
+
}
|
|
4505
|
+
throw new Error(`Table "${table}" is not configured for PowerSync sync and Supabase adapter is not available. Either add this table to the PowerSync schema or initialize the Supabase adapter.`);
|
|
4506
|
+
}
|
|
4507
|
+
}
|
|
4508
|
+
return this.getAutoAdapter(strategy, table);
|
|
4509
|
+
}
|
|
4510
|
+
if (strategy.strategy === "powersync") {
|
|
4511
|
+
if (this.powerSyncAdapter) {
|
|
4512
|
+
return this.syncTrackingAdapter ?? this.powerSyncAdapter;
|
|
4513
|
+
}
|
|
4514
|
+
if (this.supabaseAdapter) {
|
|
4515
|
+
return this.supabaseAdapter;
|
|
4516
|
+
}
|
|
4517
|
+
}
|
|
4518
|
+
const existing = this.adapters.get(table);
|
|
4519
|
+
if (existing) {
|
|
4520
|
+
return existing;
|
|
4521
|
+
}
|
|
4522
|
+
const adapter = this.createAdapter(strategy);
|
|
4523
|
+
this.adapters.set(table, adapter);
|
|
4524
|
+
return adapter;
|
|
4525
|
+
}
|
|
4526
|
+
/**
|
|
4527
|
+
* Get the PowerSync adapter directly
|
|
4528
|
+
*
|
|
4529
|
+
* @returns PowerSync adapter or null if not initialized
|
|
4530
|
+
*/
|
|
4531
|
+
getPowerSyncAdapter() {
|
|
4532
|
+
return this.powerSyncAdapter;
|
|
4533
|
+
}
|
|
4534
|
+
/**
|
|
4535
|
+
* Get the Supabase adapter directly
|
|
4536
|
+
*
|
|
4537
|
+
* @returns Supabase adapter or null if not initialized
|
|
4538
|
+
*/
|
|
4539
|
+
getSupabaseAdapter() {
|
|
4540
|
+
return this.supabaseAdapter;
|
|
4541
|
+
}
|
|
4542
|
+
/**
|
|
4543
|
+
* Get the Cached adapter directly
|
|
4544
|
+
*
|
|
4545
|
+
* @returns Cached adapter or null if not initialized
|
|
4627
4546
|
*/
|
|
4628
|
-
|
|
4547
|
+
getCachedAdapter() {
|
|
4548
|
+
return this.cachedAdapter;
|
|
4549
|
+
}
|
|
4629
4550
|
/**
|
|
4630
|
-
*
|
|
4631
|
-
*
|
|
4551
|
+
* Get all configured table names
|
|
4552
|
+
*
|
|
4553
|
+
* @returns Array of table names with explicit strategy configuration
|
|
4632
4554
|
*/
|
|
4633
|
-
|
|
4555
|
+
getConfiguredTables() {
|
|
4556
|
+
return Object.keys(this.config.tables);
|
|
4557
|
+
}
|
|
4634
4558
|
/**
|
|
4635
|
-
*
|
|
4636
|
-
*
|
|
4559
|
+
* Get the strategy for a specific table
|
|
4560
|
+
*
|
|
4561
|
+
* @param table - The table name (may include schema prefix like "core.Profile")
|
|
4562
|
+
* @returns The table strategy or undefined if not configured
|
|
4637
4563
|
*/
|
|
4638
|
-
|
|
4564
|
+
getTableStrategy(table) {
|
|
4565
|
+
const tableWithoutSchema = table.includes(".") ? table.split(".")[1] : table;
|
|
4566
|
+
return this.config.tables[table] ?? this.config.tables[tableWithoutSchema];
|
|
4567
|
+
}
|
|
4639
4568
|
/**
|
|
4640
|
-
*
|
|
4569
|
+
* Check if a table uses PowerSync strategy
|
|
4570
|
+
*
|
|
4571
|
+
* @param table - The table name (may include schema prefix like "core.Profile")
|
|
4572
|
+
* @returns True if table uses PowerSync, Hybrid, or Auto strategy
|
|
4641
4573
|
*/
|
|
4642
|
-
|
|
4574
|
+
usesPowerSync(table) {
|
|
4575
|
+
const strategy = this.getTableStrategy(table);
|
|
4576
|
+
return strategy?.strategy === "powersync" || strategy?.strategy === "hybrid" || strategy?.strategy === "auto";
|
|
4577
|
+
}
|
|
4643
4578
|
/**
|
|
4644
|
-
*
|
|
4579
|
+
* Get all table config keys that use PowerSync (may be schema-qualified)
|
|
4580
|
+
*
|
|
4581
|
+
* @returns Array of config keys using PowerSync, Hybrid, or Auto strategy
|
|
4645
4582
|
*/
|
|
4646
|
-
|
|
4583
|
+
getPowerSyncTableKeys() {
|
|
4584
|
+
return Object.entries(this.config.tables).filter(([_, strategy]) => strategy.strategy === "powersync" || strategy.strategy === "hybrid" || strategy.strategy === "auto").map(([key]) => key);
|
|
4585
|
+
}
|
|
4647
4586
|
/**
|
|
4648
|
-
*
|
|
4587
|
+
* Get all tables that use PowerSync (returns aliases for PowerSync schema)
|
|
4588
|
+
*
|
|
4589
|
+
* @returns Array of PowerSync table aliases
|
|
4649
4590
|
*/
|
|
4650
|
-
|
|
4591
|
+
getPowerSyncTables() {
|
|
4592
|
+
return Object.entries(this.config.tables).filter(([_, strategy]) => strategy.strategy === "powersync" || strategy.strategy === "hybrid" || strategy.strategy === "auto").map(([key, strategy]) => getPowerSyncAlias(key, strategy));
|
|
4593
|
+
}
|
|
4651
4594
|
/**
|
|
4652
|
-
*
|
|
4595
|
+
* Get the PowerSync alias for a table.
|
|
4596
|
+
* Uses explicit alias from config if set, otherwise auto-generates.
|
|
4597
|
+
*
|
|
4598
|
+
* @param table - Table name (may be schema-qualified)
|
|
4599
|
+
* @returns The alias to use in PowerSync schema
|
|
4653
4600
|
*/
|
|
4654
|
-
|
|
4601
|
+
getTableAlias(table) {
|
|
4602
|
+
const strategy = this.getTableStrategy(table);
|
|
4603
|
+
const tableWithoutSchema = table.includes(".") ? table.split(".")[1] : table;
|
|
4604
|
+
const configKey = this.config.tables[table] ? table : tableWithoutSchema;
|
|
4605
|
+
return getPowerSyncAlias(configKey, strategy);
|
|
4606
|
+
}
|
|
4607
|
+
// ===========================================================================
|
|
4608
|
+
// Auto-Detection Methods
|
|
4609
|
+
// ===========================================================================
|
|
4655
4610
|
/**
|
|
4656
|
-
*
|
|
4611
|
+
* Get adapter using auto-detection.
|
|
4612
|
+
*
|
|
4613
|
+
* Simple logic: PowerSync first, Supabase fallback.
|
|
4614
|
+
* Once PowerSync is initialized, always use it for offline-first behavior.
|
|
4657
4615
|
*/
|
|
4658
|
-
|
|
4616
|
+
getAutoAdapter(_strategy, _table) {
|
|
4617
|
+
if (this.powerSyncAdapter) {
|
|
4618
|
+
return this.powerSyncAdapter;
|
|
4619
|
+
}
|
|
4620
|
+
if (this.supabaseAdapter) {
|
|
4621
|
+
return this.supabaseAdapter;
|
|
4622
|
+
}
|
|
4623
|
+
throw new Error("No adapters available. Initialize PowerSync or Supabase.");
|
|
4624
|
+
}
|
|
4659
4625
|
/**
|
|
4660
|
-
*
|
|
4626
|
+
* Subscribe to backend changes
|
|
4627
|
+
*
|
|
4628
|
+
* @param callback - Function called when recommended backend changes
|
|
4629
|
+
* @returns Unsubscribe function
|
|
4661
4630
|
*/
|
|
4662
|
-
|
|
4631
|
+
onBackendChange(callback) {
|
|
4632
|
+
this.backendChangeListeners.add(callback);
|
|
4633
|
+
return () => {
|
|
4634
|
+
this.backendChangeListeners.delete(callback);
|
|
4635
|
+
};
|
|
4636
|
+
}
|
|
4663
4637
|
/**
|
|
4664
|
-
*
|
|
4638
|
+
* Notify listeners of backend change
|
|
4639
|
+
*
|
|
4640
|
+
* @param backend - The new recommended backend
|
|
4665
4641
|
*/
|
|
4666
|
-
|
|
4642
|
+
notifyBackendChange(backend) {
|
|
4643
|
+
this.backendChangeListeners.forEach((callback) => {
|
|
4644
|
+
try {
|
|
4645
|
+
callback(backend);
|
|
4646
|
+
} catch (error) {
|
|
4647
|
+
console.error("Error in backend change listener:", error);
|
|
4648
|
+
}
|
|
4649
|
+
});
|
|
4650
|
+
}
|
|
4667
4651
|
/**
|
|
4668
|
-
*
|
|
4652
|
+
* Get the last auto-detection result
|
|
4653
|
+
*
|
|
4654
|
+
* @returns Last detection result or null if never detected
|
|
4669
4655
|
*/
|
|
4670
|
-
|
|
4656
|
+
getLastDetectionResult() {
|
|
4657
|
+
return this.lastDetectionResult;
|
|
4658
|
+
}
|
|
4671
4659
|
/**
|
|
4672
|
-
*
|
|
4660
|
+
* Get the auto-detector instance
|
|
4661
|
+
*
|
|
4662
|
+
* @returns Auto-detector instance or null if not initialized
|
|
4673
4663
|
*/
|
|
4674
|
-
|
|
4664
|
+
getAutoDetector() {
|
|
4665
|
+
return this.autoDetector;
|
|
4666
|
+
}
|
|
4675
4667
|
// ===========================================================================
|
|
4676
|
-
//
|
|
4668
|
+
// Private Methods
|
|
4677
4669
|
// ===========================================================================
|
|
4678
4670
|
/**
|
|
4679
|
-
*
|
|
4671
|
+
* Create an adapter based on the strategy type
|
|
4672
|
+
*
|
|
4673
|
+
* @param strategy - The table strategy configuration
|
|
4674
|
+
* @returns The created adapter
|
|
4675
|
+
* @throws Error if the required base adapter is not initialized
|
|
4680
4676
|
*/
|
|
4681
|
-
|
|
4682
|
-
|
|
4677
|
+
createAdapter(strategy) {
|
|
4678
|
+
switch (strategy.strategy) {
|
|
4679
|
+
case "powersync":
|
|
4680
|
+
if (!this.powerSyncAdapter) {
|
|
4681
|
+
if (this.supabaseAdapter) {
|
|
4682
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
4683
|
+
console.warn(`[AdapterRegistry] PowerSync not ready, falling back to Supabase`);
|
|
4684
|
+
}
|
|
4685
|
+
return this.supabaseAdapter;
|
|
4686
|
+
}
|
|
4687
|
+
throw new Error("PowerSync adapter not initialized and Supabase not available. Ensure PowerSyncAdapter is set before accessing PowerSync tables.");
|
|
4688
|
+
}
|
|
4689
|
+
return this.syncTrackingAdapter ?? this.powerSyncAdapter;
|
|
4690
|
+
case "supabase":
|
|
4691
|
+
if (!this.supabaseAdapter) {
|
|
4692
|
+
throw new Error("Supabase adapter not initialized. Ensure SupabaseAdapter is set before accessing Supabase tables.");
|
|
4693
|
+
}
|
|
4694
|
+
return this.supabaseAdapter;
|
|
4695
|
+
case "cached":
|
|
4696
|
+
if (this.cachedAdapter) {
|
|
4697
|
+
return this.cachedAdapter;
|
|
4698
|
+
}
|
|
4699
|
+
throw new Error("CachedAdapter not yet implemented. This feature will be available in Wave 2. For now, use 'supabase' strategy as a fallback.");
|
|
4700
|
+
case "hybrid":
|
|
4701
|
+
throw new Error("HybridAdapter not yet implemented. This feature will be available in Wave 2. For now, use 'powersync' or 'supabase' strategy as a fallback.");
|
|
4702
|
+
default:
|
|
4703
|
+
if (!this.supabaseAdapter) {
|
|
4704
|
+
throw new Error("Supabase adapter not initialized. Ensure SupabaseAdapter is set before accessing tables.");
|
|
4705
|
+
}
|
|
4706
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
4707
|
+
console.warn(`[AdapterRegistry] Unknown strategy "${strategy.strategy}". Using Supabase fallback.`);
|
|
4708
|
+
}
|
|
4709
|
+
return this.supabaseAdapter;
|
|
4710
|
+
}
|
|
4683
4711
|
}
|
|
4712
|
+
// ===========================================================================
|
|
4713
|
+
// Utility Methods
|
|
4714
|
+
// ===========================================================================
|
|
4684
4715
|
/**
|
|
4685
|
-
*
|
|
4686
|
-
*
|
|
4687
|
-
*
|
|
4688
|
-
* @param deps - Dependencies needed to create adapters
|
|
4716
|
+
* Clear all cached adapters.
|
|
4717
|
+
* Useful when configuration changes and adapters need to be recreated.
|
|
4689
4718
|
*/
|
|
4690
|
-
|
|
4691
|
-
this.
|
|
4692
|
-
this._isInitialized = true;
|
|
4719
|
+
clearCache() {
|
|
4720
|
+
this.adapters.clear();
|
|
4693
4721
|
}
|
|
4694
4722
|
/**
|
|
4695
|
-
*
|
|
4696
|
-
*
|
|
4697
|
-
* @param adapter - PowerSync adapter implementation
|
|
4723
|
+
* Reset the registry to uninitialized state.
|
|
4724
|
+
* Used during cleanup or testing.
|
|
4698
4725
|
*/
|
|
4699
|
-
|
|
4700
|
-
this.powerSyncAdapter = adapter;
|
|
4701
|
-
if (this.syncTracker) {
|
|
4702
|
-
this.syncTrackingAdapter = new SyncTrackingAdapter(adapter, this.syncTracker);
|
|
4703
|
-
} else {
|
|
4704
|
-
this.syncTrackingAdapter = null;
|
|
4705
|
-
}
|
|
4726
|
+
reset() {
|
|
4706
4727
|
this.adapters.clear();
|
|
4728
|
+
this.powerSyncAdapter = null;
|
|
4729
|
+
this.powerSyncGetter = null;
|
|
4730
|
+
this.powerSyncAdapterFactory = null;
|
|
4731
|
+
this.supabaseAdapter = null;
|
|
4732
|
+
this.cachedAdapter = null;
|
|
4733
|
+
this.deps = null;
|
|
4734
|
+
this._isInitialized = false;
|
|
4735
|
+
this.autoDetector = null;
|
|
4736
|
+
this.backendChangeListeners.clear();
|
|
4737
|
+
this.lastDetectionResult = null;
|
|
4738
|
+
this.syncTracker = null;
|
|
4739
|
+
this.syncTrackingAdapter = null;
|
|
4707
4740
|
}
|
|
4708
4741
|
/**
|
|
4709
|
-
*
|
|
4710
|
-
*
|
|
4711
|
-
* This allows the registry to lazily create the PowerSync adapter when
|
|
4712
|
-
* PowerSync becomes available, rather than requiring it at initialization time.
|
|
4713
|
-
* Solves race conditions where queries/mutations run before PowerSync is ready.
|
|
4714
|
-
*
|
|
4715
|
-
* @param getter - Function that returns the PowerSync database instance (or null if not ready)
|
|
4716
|
-
* @param factory - Function that creates a TableDataAdapter from the database instance
|
|
4742
|
+
* Dispose all adapters and clean up resources.
|
|
4743
|
+
* Called when the DataLayerProvider unmounts.
|
|
4717
4744
|
*/
|
|
4718
|
-
|
|
4719
|
-
this.
|
|
4720
|
-
|
|
4745
|
+
dispose() {
|
|
4746
|
+
this.reset();
|
|
4747
|
+
}
|
|
4748
|
+
/**
|
|
4749
|
+
* Get debug information about the registry state
|
|
4750
|
+
*/
|
|
4751
|
+
getDebugInfo() {
|
|
4752
|
+
return {
|
|
4753
|
+
isInitialized: this._isInitialized,
|
|
4754
|
+
hasPowerSync: this.powerSyncAdapter !== null,
|
|
4755
|
+
hasSupabase: this.supabaseAdapter !== null,
|
|
4756
|
+
hasCached: this.cachedAdapter !== null,
|
|
4757
|
+
cachedAdapterCount: this.adapters.size,
|
|
4758
|
+
configuredTableCount: Object.keys(this.config.tables).length,
|
|
4759
|
+
powerSyncTables: this.getPowerSyncTables(),
|
|
4760
|
+
hasAutoDetector: this.autoDetector !== null,
|
|
4761
|
+
lastDetectionResult: this.lastDetectionResult
|
|
4762
|
+
};
|
|
4763
|
+
}
|
|
4764
|
+
};
|
|
4765
|
+
function createAdapterRegistry(config) {
|
|
4766
|
+
return new AdapterRegistry(config);
|
|
4767
|
+
}
|
|
4768
|
+
|
|
4769
|
+
// src/adapters/auto-detector.ts
|
|
4770
|
+
var BackendStatus = /* @__PURE__ */ ((BackendStatus2) => {
|
|
4771
|
+
BackendStatus2["AVAILABLE"] = "available";
|
|
4772
|
+
BackendStatus2["INITIALIZING"] = "initializing";
|
|
4773
|
+
BackendStatus2["UNAVAILABLE"] = "unavailable";
|
|
4774
|
+
return BackendStatus2;
|
|
4775
|
+
})(BackendStatus || {});
|
|
4776
|
+
var AdapterAutoDetector = class {
|
|
4777
|
+
constructor(powerSyncDb, supabase, options = {}) {
|
|
4778
|
+
this.powerSyncDb = powerSyncDb;
|
|
4779
|
+
this.supabase = supabase;
|
|
4780
|
+
this.options = {
|
|
4781
|
+
preferPowerSync: options.preferPowerSync ?? true,
|
|
4782
|
+
statusCheckTimeout: options.statusCheckTimeout ?? 1e3,
|
|
4783
|
+
useOnlineUntilSynced: options.useOnlineUntilSynced ?? true
|
|
4784
|
+
};
|
|
4721
4785
|
}
|
|
4786
|
+
options;
|
|
4787
|
+
listeners = /* @__PURE__ */ new Set();
|
|
4788
|
+
lastResult = null;
|
|
4789
|
+
syncStatus = null;
|
|
4722
4790
|
/**
|
|
4723
|
-
*
|
|
4724
|
-
*
|
|
4725
|
-
* Checks the getter (if set) and lazily creates the adapter if PowerSync
|
|
4726
|
-
* is now available. Also updates the auto-detector with the new reference.
|
|
4791
|
+
* Update the PowerSync database reference.
|
|
4792
|
+
* Called when PowerSync becomes available after initial construction.
|
|
4727
4793
|
*
|
|
4728
|
-
* @
|
|
4794
|
+
* @param db - PowerSync database instance or null
|
|
4729
4795
|
*/
|
|
4730
|
-
|
|
4731
|
-
|
|
4732
|
-
|
|
4733
|
-
|
|
4734
|
-
if (!this.powerSyncGetter || !this.powerSyncAdapterFactory) {
|
|
4735
|
-
return false;
|
|
4736
|
-
}
|
|
4737
|
-
const db = this.powerSyncGetter();
|
|
4738
|
-
if (!db) {
|
|
4739
|
-
return false;
|
|
4740
|
-
}
|
|
4741
|
-
const adapter = this.powerSyncAdapterFactory(db);
|
|
4742
|
-
this.setPowerSyncAdapter(adapter);
|
|
4743
|
-
if (this.autoDetector) {
|
|
4744
|
-
this.autoDetector.setPowerSyncDb(db);
|
|
4796
|
+
setPowerSyncDb(db) {
|
|
4797
|
+
this.powerSyncDb = db;
|
|
4798
|
+
if (db) {
|
|
4799
|
+
this.detect();
|
|
4745
4800
|
}
|
|
4746
|
-
return true;
|
|
4747
4801
|
}
|
|
4748
4802
|
/**
|
|
4749
|
-
*
|
|
4750
|
-
*
|
|
4751
|
-
* automatically track pending mutations.
|
|
4803
|
+
* Update the sync status from PowerSync.
|
|
4804
|
+
* Called when sync status changes to re-evaluate backend recommendation.
|
|
4752
4805
|
*
|
|
4753
|
-
*
|
|
4754
|
-
* previously cached adapters (which may have been created
|
|
4755
|
-
* before the sync tracker was available) are recreated
|
|
4756
|
-
* with the new sync tracker on next access.
|
|
4806
|
+
* @param status - Current sync status or null if not available
|
|
4757
4807
|
*/
|
|
4758
|
-
|
|
4759
|
-
|
|
4760
|
-
|
|
4761
|
-
|
|
4808
|
+
updateSyncStatus(status) {
|
|
4809
|
+
const hadSynced = this.syncStatus?.hasSynced;
|
|
4810
|
+
const hasSyncedNow = status?.hasSynced;
|
|
4811
|
+
const changed = hadSynced !== hasSyncedNow;
|
|
4812
|
+
this.syncStatus = status;
|
|
4813
|
+
if (changed) {
|
|
4814
|
+
this.detect();
|
|
4762
4815
|
}
|
|
4763
|
-
this.adapters.clear();
|
|
4764
|
-
}
|
|
4765
|
-
/**
|
|
4766
|
-
* Set the Supabase adapter instance
|
|
4767
|
-
*
|
|
4768
|
-
* @param adapter - Supabase adapter implementation
|
|
4769
|
-
*/
|
|
4770
|
-
setSupabaseAdapter(adapter) {
|
|
4771
|
-
this.supabaseAdapter = adapter;
|
|
4772
4816
|
}
|
|
4773
4817
|
/**
|
|
4774
|
-
*
|
|
4775
|
-
*
|
|
4776
|
-
* @param adapter - Cached adapter implementation
|
|
4777
|
-
*/
|
|
4778
|
-
setCachedAdapter(adapter) {
|
|
4779
|
-
this.cachedAdapter = adapter;
|
|
4780
|
-
}
|
|
4781
|
-
/**
|
|
4782
|
-
* Initialize auto-detection with a detector instance
|
|
4783
|
-
*
|
|
4784
|
-
* @param detector - The auto-detector to use
|
|
4818
|
+
* Get current sync status.
|
|
4819
|
+
* @returns Current sync status or null
|
|
4785
4820
|
*/
|
|
4786
|
-
|
|
4787
|
-
this.
|
|
4788
|
-
detector.addListener((result) => {
|
|
4789
|
-
this.lastDetectionResult = result;
|
|
4790
|
-
this.notifyBackendChange(result.recommendedBackend);
|
|
4791
|
-
});
|
|
4821
|
+
getSyncStatus() {
|
|
4822
|
+
return this.syncStatus;
|
|
4792
4823
|
}
|
|
4793
4824
|
// ===========================================================================
|
|
4794
|
-
//
|
|
4825
|
+
// Main Detection Methods
|
|
4795
4826
|
// ===========================================================================
|
|
4796
4827
|
/**
|
|
4797
|
-
*
|
|
4798
|
-
*
|
|
4799
|
-
* The adapter is selected based on the table's strategy in config.tables:
|
|
4800
|
-
* - "powersync": Returns PowerSyncAdapter
|
|
4801
|
-
* - "supabase": Returns SupabaseAdapter
|
|
4802
|
-
* - "cached": Returns CachedAdapter (wrapping Supabase)
|
|
4803
|
-
* - "hybrid": Returns HybridAdapter (combining PowerSync + Cached)
|
|
4804
|
-
* - "auto": Uses auto-detection to select the best backend
|
|
4805
|
-
*
|
|
4806
|
-
* For tables not in config, defaults to auto-detection if available,
|
|
4807
|
-
* otherwise falls back to SupabaseAdapter.
|
|
4828
|
+
* Detect backend availability and recommend best option.
|
|
4808
4829
|
*
|
|
4809
|
-
*
|
|
4810
|
-
*
|
|
4811
|
-
*
|
|
4830
|
+
* The detection logic follows this priority:
|
|
4831
|
+
* 1. If preferPowerSync is true and PowerSync is available, use PowerSync
|
|
4832
|
+
* 2. If PowerSync is initializing and online with Supabase available, use Supabase temporarily
|
|
4833
|
+
* 3. If online with Supabase available, use Supabase
|
|
4834
|
+
* 4. If offline but PowerSync available, use PowerSync (offline mode)
|
|
4835
|
+
* 5. If offline and PowerSync exists (even if initializing), use PowerSync local data
|
|
4836
|
+
* 6. Default to Supabase as fallback
|
|
4812
4837
|
*
|
|
4813
|
-
* @
|
|
4814
|
-
* @param operation - The operation type: 'read' uses fallback logic during init, 'write' always uses PowerSync for powersync tables
|
|
4815
|
-
* @returns The appropriate adapter for the table
|
|
4816
|
-
* @throws Error if adapters are not initialized
|
|
4838
|
+
* @returns Detection result with recommendation and reasoning
|
|
4817
4839
|
*/
|
|
4818
|
-
|
|
4819
|
-
this.
|
|
4820
|
-
|
|
4821
|
-
|
|
4822
|
-
|
|
4823
|
-
if (this.powerSyncAdapter) {
|
|
4824
|
-
const powerSyncTableKeys = this.getPowerSyncTableKeys();
|
|
4825
|
-
const isConfigured = powerSyncTableKeys.some((key) => key === table || key === tableWithoutSchema || key.includes(".") && key.split(".")[1] === tableWithoutSchema);
|
|
4826
|
-
if (!isConfigured) {
|
|
4827
|
-
if (this.supabaseAdapter) {
|
|
4828
|
-
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
4829
|
-
console.warn(`[AdapterRegistry] Table "${table}" is not configured for PowerSync sync. Using Supabase fallback.`);
|
|
4830
|
-
}
|
|
4831
|
-
return this.supabaseAdapter;
|
|
4832
|
-
}
|
|
4833
|
-
throw new Error(`Table "${table}" is not configured for PowerSync sync and Supabase adapter is not available. Either add this table to the PowerSync schema or initialize the Supabase adapter.`);
|
|
4834
|
-
}
|
|
4835
|
-
}
|
|
4836
|
-
return this.getAutoAdapter(strategy, table);
|
|
4837
|
-
}
|
|
4838
|
-
if (strategy.strategy === "powersync" && this.autoDetector && this.supabaseAdapter) {
|
|
4839
|
-
const detection = this.autoDetector.detectSilent();
|
|
4840
|
-
if (detection.powerSyncStatus === "initializing" /* INITIALIZING */ && detection.isOnline) {
|
|
4841
|
-
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
4842
|
-
console.warn(`[AdapterRegistry] Table "${table}" configured for PowerSync but using Supabase. PowerSync status: ${detection.powerSyncStatus}, Online: ${detection.isOnline}`);
|
|
4843
|
-
}
|
|
4844
|
-
return this.supabaseAdapter;
|
|
4845
|
-
}
|
|
4846
|
-
}
|
|
4847
|
-
const existing = this.adapters.get(table);
|
|
4848
|
-
if (existing) {
|
|
4849
|
-
return existing;
|
|
4840
|
+
detect() {
|
|
4841
|
+
const result = this.performDetection();
|
|
4842
|
+
if (this.hasResultChanged(result)) {
|
|
4843
|
+
this.lastResult = result;
|
|
4844
|
+
this.notifyListeners(result);
|
|
4850
4845
|
}
|
|
4851
|
-
|
|
4852
|
-
this.adapters.set(table, adapter);
|
|
4853
|
-
return adapter;
|
|
4846
|
+
return result;
|
|
4854
4847
|
}
|
|
4855
4848
|
/**
|
|
4856
|
-
*
|
|
4849
|
+
* Detect backend availability WITHOUT notifying listeners.
|
|
4857
4850
|
*
|
|
4858
|
-
*
|
|
4851
|
+
* This method is safe to call during React's render phase because it does not
|
|
4852
|
+
* trigger state updates in other components. Use this method when you need to
|
|
4853
|
+
* check backend status synchronously during render (e.g., in getAdapter()).
|
|
4854
|
+
*
|
|
4855
|
+
* The regular detect() method with listener notifications should only be called
|
|
4856
|
+
* from useEffect or event handlers to avoid the React warning:
|
|
4857
|
+
* "Cannot update a component while rendering a different component"
|
|
4858
|
+
*
|
|
4859
|
+
* @returns Detection result with recommendation and reasoning
|
|
4859
4860
|
*/
|
|
4860
|
-
|
|
4861
|
-
|
|
4861
|
+
detectSilent() {
|
|
4862
|
+
const result = this.performDetection();
|
|
4863
|
+
this.lastResult = result;
|
|
4864
|
+
return result;
|
|
4862
4865
|
}
|
|
4863
4866
|
/**
|
|
4864
|
-
*
|
|
4865
|
-
*
|
|
4866
|
-
* @returns Supabase adapter or null if not initialized
|
|
4867
|
+
* Internal detection logic shared by detect() and detectSilent().
|
|
4868
|
+
* @private
|
|
4867
4869
|
*/
|
|
4868
|
-
|
|
4869
|
-
|
|
4870
|
+
performDetection() {
|
|
4871
|
+
const powerSyncStatus = this.detectPowerSyncStatus();
|
|
4872
|
+
const supabaseStatus = this.detectSupabaseStatus();
|
|
4873
|
+
const isOnline = this.checkOnlineStatus();
|
|
4874
|
+
let recommendedBackend;
|
|
4875
|
+
let reason;
|
|
4876
|
+
if (this.options.preferPowerSync && powerSyncStatus === "available" /* AVAILABLE */) {
|
|
4877
|
+
recommendedBackend = "powersync";
|
|
4878
|
+
reason = "PowerSync is available and preferred for offline-first experience";
|
|
4879
|
+
} else if (powerSyncStatus === "initializing" /* INITIALIZING */ && isOnline && supabaseStatus === "available" /* AVAILABLE */) {
|
|
4880
|
+
recommendedBackend = "supabase";
|
|
4881
|
+
reason = "PowerSync initial sync in progress; using Supabase for fresh data";
|
|
4882
|
+
} else if (supabaseStatus === "available" /* AVAILABLE */ && isOnline) {
|
|
4883
|
+
recommendedBackend = "supabase";
|
|
4884
|
+
reason = "Using Supabase direct connection";
|
|
4885
|
+
} else if (powerSyncStatus === "available" /* AVAILABLE */) {
|
|
4886
|
+
recommendedBackend = "powersync";
|
|
4887
|
+
reason = "Offline mode using PowerSync local data";
|
|
4888
|
+
} else if (!isOnline && this.powerSyncDb) {
|
|
4889
|
+
recommendedBackend = "powersync";
|
|
4890
|
+
reason = "Offline mode - using PowerSync local data (initial sync may be incomplete)";
|
|
4891
|
+
} else {
|
|
4892
|
+
recommendedBackend = "supabase";
|
|
4893
|
+
reason = "No confirmed available backend; defaulting to Supabase";
|
|
4894
|
+
}
|
|
4895
|
+
return {
|
|
4896
|
+
powerSyncStatus,
|
|
4897
|
+
supabaseStatus,
|
|
4898
|
+
recommendedBackend,
|
|
4899
|
+
isOnline,
|
|
4900
|
+
reason
|
|
4901
|
+
};
|
|
4870
4902
|
}
|
|
4871
4903
|
/**
|
|
4872
|
-
*
|
|
4904
|
+
* Check if PowerSync is available.
|
|
4873
4905
|
*
|
|
4874
|
-
*
|
|
4906
|
+
* PowerSync status depends on:
|
|
4907
|
+
* 1. Database instance exists
|
|
4908
|
+
* 2. If useOnlineUntilSynced is true, also checks if initial sync completed
|
|
4909
|
+
*
|
|
4910
|
+
* @returns PowerSync backend status
|
|
4875
4911
|
*/
|
|
4876
|
-
|
|
4877
|
-
|
|
4912
|
+
detectPowerSyncStatus() {
|
|
4913
|
+
if (!this.powerSyncDb) {
|
|
4914
|
+
return "unavailable" /* UNAVAILABLE */;
|
|
4915
|
+
}
|
|
4916
|
+
try {
|
|
4917
|
+
if (typeof this.powerSyncDb.getAll !== "function") {
|
|
4918
|
+
return "initializing" /* INITIALIZING */;
|
|
4919
|
+
}
|
|
4920
|
+
if (this.options.useOnlineUntilSynced) {
|
|
4921
|
+
if (!this.syncStatus || !this.syncStatus.hasSynced) {
|
|
4922
|
+
return "initializing" /* INITIALIZING */;
|
|
4923
|
+
}
|
|
4924
|
+
}
|
|
4925
|
+
return "available" /* AVAILABLE */;
|
|
4926
|
+
} catch {
|
|
4927
|
+
return "initializing" /* INITIALIZING */;
|
|
4928
|
+
}
|
|
4878
4929
|
}
|
|
4879
4930
|
/**
|
|
4880
|
-
*
|
|
4931
|
+
* Check if Supabase is available.
|
|
4881
4932
|
*
|
|
4882
|
-
*
|
|
4933
|
+
* Supabase is considered available if we have a client instance.
|
|
4934
|
+
* The actual network connectivity is checked separately via checkOnlineStatus().
|
|
4935
|
+
*
|
|
4936
|
+
* @returns Supabase backend status
|
|
4883
4937
|
*/
|
|
4884
|
-
|
|
4885
|
-
|
|
4938
|
+
detectSupabaseStatus() {
|
|
4939
|
+
if (!this.supabase) {
|
|
4940
|
+
return "unavailable" /* UNAVAILABLE */;
|
|
4941
|
+
}
|
|
4942
|
+
try {
|
|
4943
|
+
if (typeof this.supabase.from === "function") {
|
|
4944
|
+
return "available" /* AVAILABLE */;
|
|
4945
|
+
}
|
|
4946
|
+
return "unavailable" /* UNAVAILABLE */;
|
|
4947
|
+
} catch {
|
|
4948
|
+
return "unavailable" /* UNAVAILABLE */;
|
|
4949
|
+
}
|
|
4886
4950
|
}
|
|
4887
4951
|
/**
|
|
4888
|
-
*
|
|
4952
|
+
* Check if device is online.
|
|
4889
4953
|
*
|
|
4890
|
-
*
|
|
4891
|
-
*
|
|
4954
|
+
* Prefers the sync status's isOnline property if available (from React Native NetInfo).
|
|
4955
|
+
* Falls back to navigator.onLine in browser environments.
|
|
4956
|
+
* Returns false by default for non-browser environments (React Native, Node.js, etc.)
|
|
4957
|
+
* to ensure offline-first behavior works correctly.
|
|
4958
|
+
*
|
|
4959
|
+
* @returns Whether the device has network connectivity
|
|
4892
4960
|
*/
|
|
4893
|
-
|
|
4894
|
-
|
|
4895
|
-
|
|
4961
|
+
checkOnlineStatus() {
|
|
4962
|
+
if (this.syncStatus?.isOnline !== void 0) {
|
|
4963
|
+
return this.syncStatus.isOnline;
|
|
4964
|
+
}
|
|
4965
|
+
if (typeof window !== "undefined" && typeof navigator !== "undefined") {
|
|
4966
|
+
return navigator.onLine;
|
|
4967
|
+
}
|
|
4968
|
+
return false;
|
|
4896
4969
|
}
|
|
4970
|
+
// ===========================================================================
|
|
4971
|
+
// Instance Management Methods
|
|
4972
|
+
// ===========================================================================
|
|
4897
4973
|
/**
|
|
4898
|
-
*
|
|
4974
|
+
* Update PowerSync instance (e.g., when it becomes available).
|
|
4899
4975
|
*
|
|
4900
|
-
* @param
|
|
4901
|
-
* @returns True if table uses PowerSync, Hybrid, or Auto strategy
|
|
4976
|
+
* @param db - New PowerSync database instance or null
|
|
4902
4977
|
*/
|
|
4903
|
-
|
|
4904
|
-
|
|
4905
|
-
return strategy?.strategy === "powersync" || strategy?.strategy === "hybrid" || strategy?.strategy === "auto";
|
|
4978
|
+
setPowerSync(db) {
|
|
4979
|
+
this.powerSyncDb = db;
|
|
4906
4980
|
}
|
|
4907
4981
|
/**
|
|
4908
|
-
*
|
|
4982
|
+
* Update Supabase instance.
|
|
4909
4983
|
*
|
|
4910
|
-
* @
|
|
4984
|
+
* @param supabase - New Supabase client instance or null
|
|
4911
4985
|
*/
|
|
4912
|
-
|
|
4913
|
-
|
|
4986
|
+
setSupabase(supabase) {
|
|
4987
|
+
this.supabase = supabase;
|
|
4914
4988
|
}
|
|
4915
4989
|
/**
|
|
4916
|
-
* Get
|
|
4990
|
+
* Get current PowerSync instance.
|
|
4917
4991
|
*
|
|
4918
|
-
* @returns
|
|
4992
|
+
* @returns Current PowerSync database instance or null
|
|
4919
4993
|
*/
|
|
4920
|
-
|
|
4921
|
-
return
|
|
4994
|
+
getPowerSync() {
|
|
4995
|
+
return this.powerSyncDb;
|
|
4922
4996
|
}
|
|
4923
4997
|
/**
|
|
4924
|
-
* Get
|
|
4925
|
-
* Uses explicit alias from config if set, otherwise auto-generates.
|
|
4998
|
+
* Get current Supabase instance.
|
|
4926
4999
|
*
|
|
4927
|
-
* @
|
|
4928
|
-
* @returns The alias to use in PowerSync schema
|
|
5000
|
+
* @returns Current Supabase client instance or null
|
|
4929
5001
|
*/
|
|
4930
|
-
|
|
4931
|
-
|
|
4932
|
-
const tableWithoutSchema = table.includes(".") ? table.split(".")[1] : table;
|
|
4933
|
-
const configKey = this.config.tables[table] ? table : tableWithoutSchema;
|
|
4934
|
-
return getPowerSyncAlias(configKey, strategy);
|
|
5002
|
+
getSupabase() {
|
|
5003
|
+
return this.supabase;
|
|
4935
5004
|
}
|
|
4936
5005
|
// ===========================================================================
|
|
4937
|
-
//
|
|
5006
|
+
// Options Management
|
|
4938
5007
|
// ===========================================================================
|
|
4939
5008
|
/**
|
|
4940
|
-
*
|
|
5009
|
+
* Update detector options.
|
|
4941
5010
|
*
|
|
4942
|
-
* @param
|
|
4943
|
-
* @returns The automatically selected adapter
|
|
5011
|
+
* @param options - New options to merge with existing
|
|
4944
5012
|
*/
|
|
4945
|
-
|
|
4946
|
-
|
|
4947
|
-
|
|
4948
|
-
|
|
4949
|
-
|
|
4950
|
-
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
4951
|
-
console.warn(`[AdapterRegistry] No auto-detector configured${table ? ` for table "${table}"` : ""}. Using Supabase fallback.`);
|
|
4952
|
-
}
|
|
4953
|
-
return this.supabaseAdapter;
|
|
4954
|
-
}
|
|
4955
|
-
const detection = this.autoDetector.detectSilent();
|
|
4956
|
-
this.lastDetectionResult = detection;
|
|
4957
|
-
if (detection.recommendedBackend === "powersync") {
|
|
4958
|
-
if (!this.powerSyncAdapter) {
|
|
4959
|
-
if (!this.supabaseAdapter) {
|
|
4960
|
-
throw new Error("Neither PowerSync nor Supabase adapters are available.");
|
|
4961
|
-
}
|
|
4962
|
-
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
4963
|
-
console.warn(`[AdapterRegistry] PowerSync recommended${table ? ` for table "${table}"` : ""} but adapter not available. Falling back to Supabase. Reason: ${detection.reason}`);
|
|
4964
|
-
}
|
|
4965
|
-
return this.supabaseAdapter;
|
|
4966
|
-
}
|
|
4967
|
-
return this.powerSyncAdapter;
|
|
4968
|
-
}
|
|
4969
|
-
if (!this.supabaseAdapter) {
|
|
4970
|
-
throw new Error("Supabase adapter not available and PowerSync not recommended.");
|
|
4971
|
-
}
|
|
4972
|
-
return this.supabaseAdapter;
|
|
5013
|
+
setOptions(options) {
|
|
5014
|
+
this.options = {
|
|
5015
|
+
...this.options,
|
|
5016
|
+
...options
|
|
5017
|
+
};
|
|
4973
5018
|
}
|
|
4974
5019
|
/**
|
|
4975
|
-
*
|
|
5020
|
+
* Get current detector options.
|
|
4976
5021
|
*
|
|
4977
|
-
* @
|
|
4978
|
-
* @returns Unsubscribe function
|
|
5022
|
+
* @returns Current detector options
|
|
4979
5023
|
*/
|
|
4980
|
-
|
|
4981
|
-
|
|
4982
|
-
|
|
4983
|
-
this.backendChangeListeners.delete(callback);
|
|
5024
|
+
getOptions() {
|
|
5025
|
+
return {
|
|
5026
|
+
...this.options
|
|
4984
5027
|
};
|
|
4985
5028
|
}
|
|
5029
|
+
// ===========================================================================
|
|
5030
|
+
// Listener Management
|
|
5031
|
+
// ===========================================================================
|
|
4986
5032
|
/**
|
|
4987
|
-
*
|
|
5033
|
+
* Add a listener for backend change events.
|
|
4988
5034
|
*
|
|
4989
|
-
* @param
|
|
5035
|
+
* @param listener - Callback to invoke when detection result changes
|
|
5036
|
+
* @returns Function to remove the listener
|
|
4990
5037
|
*/
|
|
4991
|
-
|
|
4992
|
-
this.
|
|
4993
|
-
|
|
4994
|
-
callback(backend);
|
|
4995
|
-
} catch (error) {
|
|
4996
|
-
console.error("Error in backend change listener:", error);
|
|
4997
|
-
}
|
|
4998
|
-
});
|
|
5038
|
+
addListener(listener) {
|
|
5039
|
+
this.listeners.add(listener);
|
|
5040
|
+
return () => this.listeners.delete(listener);
|
|
4999
5041
|
}
|
|
5000
5042
|
/**
|
|
5001
|
-
*
|
|
5043
|
+
* Remove a listener for backend change events.
|
|
5002
5044
|
*
|
|
5003
|
-
* @
|
|
5045
|
+
* @param listener - Listener to remove
|
|
5004
5046
|
*/
|
|
5005
|
-
|
|
5006
|
-
|
|
5047
|
+
removeListener(listener) {
|
|
5048
|
+
this.listeners.delete(listener);
|
|
5007
5049
|
}
|
|
5008
5050
|
/**
|
|
5009
|
-
* Get the
|
|
5051
|
+
* Get the last detection result.
|
|
5010
5052
|
*
|
|
5011
|
-
* @returns
|
|
5053
|
+
* @returns Last detection result or null if never detected
|
|
5012
5054
|
*/
|
|
5013
|
-
|
|
5014
|
-
return this.
|
|
5055
|
+
getLastResult() {
|
|
5056
|
+
return this.lastResult;
|
|
5015
5057
|
}
|
|
5016
5058
|
// ===========================================================================
|
|
5017
|
-
// Private Methods
|
|
5059
|
+
// Private Helper Methods
|
|
5018
5060
|
// ===========================================================================
|
|
5019
5061
|
/**
|
|
5020
|
-
*
|
|
5021
|
-
*
|
|
5022
|
-
* @param strategy - The table strategy configuration
|
|
5023
|
-
* @returns The created adapter
|
|
5024
|
-
* @throws Error if the required base adapter is not initialized
|
|
5062
|
+
* Check if the detection result has changed from the last result.
|
|
5025
5063
|
*/
|
|
5026
|
-
|
|
5027
|
-
|
|
5028
|
-
|
|
5029
|
-
if (!this.powerSyncAdapter) {
|
|
5030
|
-
if (this.supabaseAdapter) {
|
|
5031
|
-
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
5032
|
-
console.warn(`[AdapterRegistry] PowerSync not ready, falling back to Supabase`);
|
|
5033
|
-
}
|
|
5034
|
-
return this.supabaseAdapter;
|
|
5035
|
-
}
|
|
5036
|
-
throw new Error("PowerSync adapter not initialized and Supabase not available. Ensure PowerSyncAdapter is set before accessing PowerSync tables.");
|
|
5037
|
-
}
|
|
5038
|
-
return this.syncTrackingAdapter ?? this.powerSyncAdapter;
|
|
5039
|
-
case "supabase":
|
|
5040
|
-
if (!this.supabaseAdapter) {
|
|
5041
|
-
throw new Error("Supabase adapter not initialized. Ensure SupabaseAdapter is set before accessing Supabase tables.");
|
|
5042
|
-
}
|
|
5043
|
-
return this.supabaseAdapter;
|
|
5044
|
-
case "cached":
|
|
5045
|
-
if (this.cachedAdapter) {
|
|
5046
|
-
return this.cachedAdapter;
|
|
5047
|
-
}
|
|
5048
|
-
throw new Error("CachedAdapter not yet implemented. This feature will be available in Wave 2. For now, use 'supabase' strategy as a fallback.");
|
|
5049
|
-
case "hybrid":
|
|
5050
|
-
throw new Error("HybridAdapter not yet implemented. This feature will be available in Wave 2. For now, use 'powersync' or 'supabase' strategy as a fallback.");
|
|
5051
|
-
default:
|
|
5052
|
-
if (!this.supabaseAdapter) {
|
|
5053
|
-
throw new Error("Supabase adapter not initialized. Ensure SupabaseAdapter is set before accessing tables.");
|
|
5054
|
-
}
|
|
5055
|
-
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
5056
|
-
console.warn(`[AdapterRegistry] Unknown strategy "${strategy.strategy}". Using Supabase fallback.`);
|
|
5057
|
-
}
|
|
5058
|
-
return this.supabaseAdapter;
|
|
5064
|
+
hasResultChanged(result) {
|
|
5065
|
+
if (!this.lastResult) {
|
|
5066
|
+
return true;
|
|
5059
5067
|
}
|
|
5060
|
-
|
|
5061
|
-
// ===========================================================================
|
|
5062
|
-
// Utility Methods
|
|
5063
|
-
// ===========================================================================
|
|
5064
|
-
/**
|
|
5065
|
-
* Clear all cached adapters.
|
|
5066
|
-
* Useful when configuration changes and adapters need to be recreated.
|
|
5067
|
-
*/
|
|
5068
|
-
clearCache() {
|
|
5069
|
-
this.adapters.clear();
|
|
5070
|
-
}
|
|
5071
|
-
/**
|
|
5072
|
-
* Reset the registry to uninitialized state.
|
|
5073
|
-
* Used during cleanup or testing.
|
|
5074
|
-
*/
|
|
5075
|
-
reset() {
|
|
5076
|
-
this.adapters.clear();
|
|
5077
|
-
this.powerSyncAdapter = null;
|
|
5078
|
-
this.powerSyncGetter = null;
|
|
5079
|
-
this.powerSyncAdapterFactory = null;
|
|
5080
|
-
this.supabaseAdapter = null;
|
|
5081
|
-
this.cachedAdapter = null;
|
|
5082
|
-
this.deps = null;
|
|
5083
|
-
this._isInitialized = false;
|
|
5084
|
-
this.autoDetector = null;
|
|
5085
|
-
this.backendChangeListeners.clear();
|
|
5086
|
-
this.lastDetectionResult = null;
|
|
5087
|
-
this.syncTracker = null;
|
|
5088
|
-
this.syncTrackingAdapter = null;
|
|
5089
|
-
}
|
|
5090
|
-
/**
|
|
5091
|
-
* Dispose all adapters and clean up resources.
|
|
5092
|
-
* Called when the DataLayerProvider unmounts.
|
|
5093
|
-
*/
|
|
5094
|
-
dispose() {
|
|
5095
|
-
this.reset();
|
|
5068
|
+
return this.lastResult.powerSyncStatus !== result.powerSyncStatus || this.lastResult.supabaseStatus !== result.supabaseStatus || this.lastResult.recommendedBackend !== result.recommendedBackend || this.lastResult.isOnline !== result.isOnline;
|
|
5096
5069
|
}
|
|
5097
5070
|
/**
|
|
5098
|
-
*
|
|
5071
|
+
* Notify all listeners of a detection result change.
|
|
5099
5072
|
*/
|
|
5100
|
-
|
|
5101
|
-
|
|
5102
|
-
|
|
5103
|
-
|
|
5104
|
-
|
|
5105
|
-
|
|
5106
|
-
|
|
5107
|
-
|
|
5108
|
-
|
|
5109
|
-
|
|
5110
|
-
|
|
5111
|
-
|
|
5073
|
+
notifyListeners(result) {
|
|
5074
|
+
const isDev = typeof __DEV__ !== "undefined" ? __DEV__ : process.env.NODE_ENV !== "production";
|
|
5075
|
+
if (isDev) {
|
|
5076
|
+
const prevBackend = this.lastResult?.recommendedBackend;
|
|
5077
|
+
if (prevBackend && prevBackend !== result.recommendedBackend) {
|
|
5078
|
+
console.log(`[DataLayer] Backend switched: ${prevBackend} \u2192 ${result.recommendedBackend}`, `| Reason: ${result.reason}`);
|
|
5079
|
+
}
|
|
5080
|
+
if (result.recommendedBackend === "supabase" && this.options.preferPowerSync) {
|
|
5081
|
+
console.log(`[DataLayer] Using online fallback (Supabase)`, `| PowerSync: ${result.powerSyncStatus}`, `| Online: ${result.isOnline}`, `| Reason: ${result.reason}`);
|
|
5082
|
+
}
|
|
5083
|
+
}
|
|
5084
|
+
Array.from(this.listeners).forEach((listener) => {
|
|
5085
|
+
try {
|
|
5086
|
+
listener(result);
|
|
5087
|
+
} catch (error) {
|
|
5088
|
+
console.error("Error in backend change listener:", error);
|
|
5089
|
+
}
|
|
5090
|
+
});
|
|
5112
5091
|
}
|
|
5113
5092
|
};
|
|
5114
|
-
function
|
|
5115
|
-
return new
|
|
5093
|
+
function createAdapterAutoDetector(powerSyncDb, supabase, options) {
|
|
5094
|
+
return new AdapterAutoDetector(powerSyncDb, supabase, options);
|
|
5116
5095
|
}
|
|
5117
5096
|
|
|
5118
5097
|
// src/adapters/supabase-adapter.ts
|
|
@@ -7942,13 +7921,13 @@ export {
|
|
|
7942
7921
|
useMutationSuccess,
|
|
7943
7922
|
useMutationSuccessRN,
|
|
7944
7923
|
ADAPTER_STRATEGIES,
|
|
7945
|
-
BackendStatus,
|
|
7946
|
-
AdapterAutoDetector,
|
|
7947
|
-
createAdapterAutoDetector,
|
|
7948
7924
|
SyncTrackingAdapter,
|
|
7949
7925
|
stripSchemaPrefix,
|
|
7950
7926
|
AdapterRegistry,
|
|
7951
7927
|
createAdapterRegistry,
|
|
7928
|
+
BackendStatus,
|
|
7929
|
+
AdapterAutoDetector,
|
|
7930
|
+
createAdapterAutoDetector,
|
|
7952
7931
|
SupabaseAdapter,
|
|
7953
7932
|
createSupabaseAdapter,
|
|
7954
7933
|
getErrorBody,
|
|
@@ -8005,4 +7984,4 @@ moment/moment.js:
|
|
|
8005
7984
|
(*! license : MIT *)
|
|
8006
7985
|
(*! momentjs.com *)
|
|
8007
7986
|
*/
|
|
8008
|
-
//# sourceMappingURL=chunk-
|
|
7987
|
+
//# sourceMappingURL=chunk-EOJGUOJR.js.map
|