@pol-studios/db 1.0.50 → 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/auth/context.js +2 -2
- package/dist/auth/hooks.js +3 -3
- package/dist/auth/index.js +3 -3
- package/dist/{chunk-RJIVXO4U.js → chunk-3Q74DK5K.js} +44 -48
- package/dist/chunk-3Q74DK5K.js.map +1 -0
- package/dist/{chunk-DKUF2FKB.js → chunk-DP3YEVSX.js} +2 -2
- package/dist/{chunk-7CLN4ORU.js → chunk-EOJGUOJR.js} +681 -693
- package/dist/chunk-EOJGUOJR.js.map +1 -0
- package/dist/{chunk-GY7HDOBA.js → chunk-FIAXWEBK.js} +4 -4
- package/dist/{chunk-FLGHJCW3.js → chunk-FMYXG4VN.js} +2 -2
- package/dist/{chunk-WBMZDH2U.js → chunk-GSORUAS7.js} +19 -6
- package/dist/chunk-GSORUAS7.js.map +1 -0
- package/dist/{chunk-AIYPSXIO.js → chunk-WQLIGVQR.js} +15 -13
- package/dist/{chunk-AIYPSXIO.js.map → chunk-WQLIGVQR.js.map} +1 -1
- package/dist/hooks/index.d.ts +2 -2
- package/dist/hooks/index.js +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 +7 -7
- package/dist/index.native.d.ts +5 -5
- package/dist/index.native.js +7 -7
- package/dist/index.web.d.ts +6 -6
- package/dist/index.web.js +6 -6
- 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/dist/with-auth/index.js +5 -5
- package/package.json +1 -1
- package/dist/chunk-7CLN4ORU.js.map +0 -1
- package/dist/chunk-RJIVXO4U.js.map +0 -1
- package/dist/chunk-WBMZDH2U.js.map +0 -1
- /package/dist/{chunk-DKUF2FKB.js.map → chunk-DP3YEVSX.js.map} +0 -0
- /package/dist/{chunk-GY7HDOBA.js.map → chunk-FIAXWEBK.js.map} +0 -0
- /package/dist/{chunk-FLGHJCW3.js.map → chunk-FMYXG4VN.js.map} +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
useDbUpsert
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-3Q74DK5K.js";
|
|
4
4
|
import {
|
|
5
5
|
normalizeFilter
|
|
6
6
|
} from "./chunk-Z3EJX3VG.js";
|
|
@@ -9,10 +9,10 @@ import {
|
|
|
9
9
|
} from "./chunk-7SCJNYTE.js";
|
|
10
10
|
import {
|
|
11
11
|
useDbQuery
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-DP3YEVSX.js";
|
|
13
13
|
import {
|
|
14
14
|
useDataLayerCoreOptional
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-WQLIGVQR.js";
|
|
16
16
|
import {
|
|
17
17
|
getSupabaseUrl
|
|
18
18
|
} from "./chunk-GC3TBUWE.js";
|
|
@@ -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) {
|
|
@@ -4613,497 +4285,813 @@ var AdapterRegistry = class {
|
|
|
4613
4285
|
/**
|
|
4614
4286
|
* Create a new adapter registry
|
|
4615
4287
|
*
|
|
4616
|
-
* @param config - Data layer configuration with table strategies
|
|
4288
|
+
* @param config - Data layer configuration with table strategies
|
|
4289
|
+
*/
|
|
4290
|
+
constructor(config) {
|
|
4291
|
+
this.config = config;
|
|
4292
|
+
}
|
|
4293
|
+
/**
|
|
4294
|
+
* Cache of created adapters by table name
|
|
4295
|
+
*/
|
|
4296
|
+
adapters = /* @__PURE__ */ new Map();
|
|
4297
|
+
/**
|
|
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
|
|
4617
4530
|
*/
|
|
4618
|
-
|
|
4619
|
-
this.
|
|
4531
|
+
getPowerSyncAdapter() {
|
|
4532
|
+
return this.powerSyncAdapter;
|
|
4620
4533
|
}
|
|
4621
4534
|
/**
|
|
4622
|
-
*
|
|
4535
|
+
* Get the Supabase adapter directly
|
|
4536
|
+
*
|
|
4537
|
+
* @returns Supabase adapter or null if not initialized
|
|
4623
4538
|
*/
|
|
4624
|
-
|
|
4539
|
+
getSupabaseAdapter() {
|
|
4540
|
+
return this.supabaseAdapter;
|
|
4541
|
+
}
|
|
4625
4542
|
/**
|
|
4626
|
-
*
|
|
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
|
-
*
|
|
4680
|
-
*/
|
|
4681
|
-
get isInitialized() {
|
|
4682
|
-
return this._isInitialized;
|
|
4683
|
-
}
|
|
4684
|
-
/**
|
|
4685
|
-
* Initialize the registry with dependencies.
|
|
4686
|
-
* Called by DataLayerProvider when PowerSync and Supabase are ready.
|
|
4671
|
+
* Create an adapter based on the strategy type
|
|
4687
4672
|
*
|
|
4688
|
-
* @param
|
|
4673
|
+
* @param strategy - The table strategy configuration
|
|
4674
|
+
* @returns The created adapter
|
|
4675
|
+
* @throws Error if the required base adapter is not initialized
|
|
4689
4676
|
*/
|
|
4690
|
-
|
|
4691
|
-
|
|
4692
|
-
|
|
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
|
+
}
|
|
4693
4711
|
}
|
|
4712
|
+
// ===========================================================================
|
|
4713
|
+
// Utility Methods
|
|
4714
|
+
// ===========================================================================
|
|
4694
4715
|
/**
|
|
4695
|
-
*
|
|
4696
|
-
*
|
|
4697
|
-
* @param adapter - PowerSync adapter implementation
|
|
4716
|
+
* Clear all cached adapters.
|
|
4717
|
+
* Useful when configuration changes and adapters need to be recreated.
|
|
4698
4718
|
*/
|
|
4699
|
-
|
|
4700
|
-
this.
|
|
4701
|
-
if (this.syncTracker) {
|
|
4702
|
-
this.syncTrackingAdapter = new SyncTrackingAdapter(adapter, this.syncTracker);
|
|
4703
|
-
} else {
|
|
4704
|
-
this.syncTrackingAdapter = null;
|
|
4705
|
-
}
|
|
4719
|
+
clearCache() {
|
|
4720
|
+
this.adapters.clear();
|
|
4706
4721
|
}
|
|
4707
4722
|
/**
|
|
4708
|
-
*
|
|
4709
|
-
*
|
|
4710
|
-
* This allows the registry to lazily create the PowerSync adapter when
|
|
4711
|
-
* PowerSync becomes available, rather than requiring it at initialization time.
|
|
4712
|
-
* Solves race conditions where queries/mutations run before PowerSync is ready.
|
|
4713
|
-
*
|
|
4714
|
-
* @param getter - Function that returns the PowerSync database instance (or null if not ready)
|
|
4715
|
-
* @param factory - Function that creates a TableDataAdapter from the database instance
|
|
4723
|
+
* Reset the registry to uninitialized state.
|
|
4724
|
+
* Used during cleanup or testing.
|
|
4716
4725
|
*/
|
|
4717
|
-
|
|
4718
|
-
this.
|
|
4719
|
-
this.
|
|
4726
|
+
reset() {
|
|
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;
|
|
4720
4740
|
}
|
|
4721
4741
|
/**
|
|
4722
|
-
*
|
|
4723
|
-
*
|
|
4724
|
-
* Checks the getter (if set) and lazily creates the adapter if PowerSync
|
|
4725
|
-
* is now available. Also updates the auto-detector with the new reference.
|
|
4726
|
-
*
|
|
4727
|
-
* @returns true if PowerSync adapter is available, false otherwise
|
|
4742
|
+
* Dispose all adapters and clean up resources.
|
|
4743
|
+
* Called when the DataLayerProvider unmounts.
|
|
4728
4744
|
*/
|
|
4729
|
-
|
|
4730
|
-
|
|
4731
|
-
return true;
|
|
4732
|
-
}
|
|
4733
|
-
if (!this.powerSyncGetter || !this.powerSyncAdapterFactory) {
|
|
4734
|
-
return false;
|
|
4735
|
-
}
|
|
4736
|
-
const db = this.powerSyncGetter();
|
|
4737
|
-
if (!db) {
|
|
4738
|
-
return false;
|
|
4739
|
-
}
|
|
4740
|
-
const adapter = this.powerSyncAdapterFactory(db);
|
|
4741
|
-
this.setPowerSyncAdapter(adapter);
|
|
4742
|
-
if (this.autoDetector) {
|
|
4743
|
-
this.autoDetector.setPowerSyncDb(db);
|
|
4744
|
-
}
|
|
4745
|
-
return true;
|
|
4745
|
+
dispose() {
|
|
4746
|
+
this.reset();
|
|
4746
4747
|
}
|
|
4747
4748
|
/**
|
|
4748
|
-
*
|
|
4749
|
-
* When set, write operations on PowerSync tables will
|
|
4750
|
-
* automatically track pending mutations.
|
|
4751
|
-
*
|
|
4752
|
-
* NOTE: This also clears the adapter cache to ensure any
|
|
4753
|
-
* previously cached adapters (which may have been created
|
|
4754
|
-
* before the sync tracker was available) are recreated
|
|
4755
|
-
* with the new sync tracker on next access.
|
|
4749
|
+
* Get debug information about the registry state
|
|
4756
4750
|
*/
|
|
4757
|
-
|
|
4758
|
-
|
|
4759
|
-
|
|
4760
|
-
this.
|
|
4761
|
-
|
|
4762
|
-
|
|
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
|
+
};
|
|
4763
4785
|
}
|
|
4786
|
+
options;
|
|
4787
|
+
listeners = /* @__PURE__ */ new Set();
|
|
4788
|
+
lastResult = null;
|
|
4789
|
+
syncStatus = null;
|
|
4764
4790
|
/**
|
|
4765
|
-
*
|
|
4791
|
+
* Update the PowerSync database reference.
|
|
4792
|
+
* Called when PowerSync becomes available after initial construction.
|
|
4766
4793
|
*
|
|
4767
|
-
* @param
|
|
4794
|
+
* @param db - PowerSync database instance or null
|
|
4768
4795
|
*/
|
|
4769
|
-
|
|
4770
|
-
this.
|
|
4796
|
+
setPowerSyncDb(db) {
|
|
4797
|
+
this.powerSyncDb = db;
|
|
4798
|
+
if (db) {
|
|
4799
|
+
this.detect();
|
|
4800
|
+
}
|
|
4771
4801
|
}
|
|
4772
4802
|
/**
|
|
4773
|
-
*
|
|
4803
|
+
* Update the sync status from PowerSync.
|
|
4804
|
+
* Called when sync status changes to re-evaluate backend recommendation.
|
|
4774
4805
|
*
|
|
4775
|
-
* @param
|
|
4806
|
+
* @param status - Current sync status or null if not available
|
|
4776
4807
|
*/
|
|
4777
|
-
|
|
4778
|
-
|
|
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();
|
|
4815
|
+
}
|
|
4779
4816
|
}
|
|
4780
4817
|
/**
|
|
4781
|
-
*
|
|
4782
|
-
*
|
|
4783
|
-
* @param detector - The auto-detector to use
|
|
4818
|
+
* Get current sync status.
|
|
4819
|
+
* @returns Current sync status or null
|
|
4784
4820
|
*/
|
|
4785
|
-
|
|
4786
|
-
this.
|
|
4787
|
-
detector.addListener((result) => {
|
|
4788
|
-
this.lastDetectionResult = result;
|
|
4789
|
-
this.notifyBackendChange(result.recommendedBackend);
|
|
4790
|
-
});
|
|
4821
|
+
getSyncStatus() {
|
|
4822
|
+
return this.syncStatus;
|
|
4791
4823
|
}
|
|
4792
4824
|
// ===========================================================================
|
|
4793
|
-
//
|
|
4825
|
+
// Main Detection Methods
|
|
4794
4826
|
// ===========================================================================
|
|
4795
4827
|
/**
|
|
4796
|
-
*
|
|
4797
|
-
*
|
|
4798
|
-
* The adapter is selected based on the table's strategy in config.tables:
|
|
4799
|
-
* - "powersync": Returns PowerSyncAdapter
|
|
4800
|
-
* - "supabase": Returns SupabaseAdapter
|
|
4801
|
-
* - "cached": Returns CachedAdapter (wrapping Supabase)
|
|
4802
|
-
* - "hybrid": Returns HybridAdapter (combining PowerSync + Cached)
|
|
4803
|
-
* - "auto": Uses auto-detection to select the best backend
|
|
4804
|
-
*
|
|
4805
|
-
* For tables not in config, defaults to auto-detection if available,
|
|
4806
|
-
* otherwise falls back to SupabaseAdapter.
|
|
4828
|
+
* Detect backend availability and recommend best option.
|
|
4807
4829
|
*
|
|
4808
|
-
*
|
|
4809
|
-
*
|
|
4810
|
-
*
|
|
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
|
|
4811
4837
|
*
|
|
4812
|
-
* @
|
|
4813
|
-
* @param operation - The operation type: 'read' uses fallback logic during init, 'write' always uses PowerSync for powersync tables
|
|
4814
|
-
* @returns The appropriate adapter for the table
|
|
4815
|
-
* @throws Error if adapters are not initialized
|
|
4838
|
+
* @returns Detection result with recommendation and reasoning
|
|
4816
4839
|
*/
|
|
4817
|
-
|
|
4818
|
-
this.
|
|
4819
|
-
|
|
4820
|
-
|
|
4821
|
-
|
|
4822
|
-
if (this.powerSyncAdapter) {
|
|
4823
|
-
const powerSyncTableKeys = this.getPowerSyncTableKeys();
|
|
4824
|
-
const isConfigured = powerSyncTableKeys.some((key) => key === table || key === tableWithoutSchema || key.includes(".") && key.split(".")[1] === tableWithoutSchema);
|
|
4825
|
-
if (!isConfigured) {
|
|
4826
|
-
if (this.supabaseAdapter) {
|
|
4827
|
-
return this.supabaseAdapter;
|
|
4828
|
-
}
|
|
4829
|
-
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.`);
|
|
4830
|
-
}
|
|
4831
|
-
}
|
|
4832
|
-
return this.getAutoAdapter(strategy, table);
|
|
4833
|
-
}
|
|
4834
|
-
if (strategy.strategy === "powersync" && this.autoDetector && this.supabaseAdapter) {
|
|
4835
|
-
const detection = this.autoDetector.detectSilent();
|
|
4836
|
-
if (detection.powerSyncStatus === "initializing" /* INITIALIZING */ && detection.isOnline) {
|
|
4837
|
-
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
4838
|
-
console.warn(`[AdapterRegistry] Table "${table}" configured for PowerSync but using Supabase. PowerSync status: ${detection.powerSyncStatus}, Online: ${detection.isOnline}`);
|
|
4839
|
-
}
|
|
4840
|
-
return this.supabaseAdapter;
|
|
4841
|
-
}
|
|
4842
|
-
}
|
|
4843
|
-
const existing = this.adapters.get(table);
|
|
4844
|
-
if (existing) {
|
|
4845
|
-
return existing;
|
|
4840
|
+
detect() {
|
|
4841
|
+
const result = this.performDetection();
|
|
4842
|
+
if (this.hasResultChanged(result)) {
|
|
4843
|
+
this.lastResult = result;
|
|
4844
|
+
this.notifyListeners(result);
|
|
4846
4845
|
}
|
|
4847
|
-
|
|
4848
|
-
this.adapters.set(table, adapter);
|
|
4849
|
-
return adapter;
|
|
4846
|
+
return result;
|
|
4850
4847
|
}
|
|
4851
4848
|
/**
|
|
4852
|
-
*
|
|
4849
|
+
* Detect backend availability WITHOUT notifying listeners.
|
|
4853
4850
|
*
|
|
4854
|
-
*
|
|
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
|
|
4855
4860
|
*/
|
|
4856
|
-
|
|
4857
|
-
|
|
4861
|
+
detectSilent() {
|
|
4862
|
+
const result = this.performDetection();
|
|
4863
|
+
this.lastResult = result;
|
|
4864
|
+
return result;
|
|
4858
4865
|
}
|
|
4859
4866
|
/**
|
|
4860
|
-
*
|
|
4861
|
-
*
|
|
4862
|
-
* @returns Supabase adapter or null if not initialized
|
|
4867
|
+
* Internal detection logic shared by detect() and detectSilent().
|
|
4868
|
+
* @private
|
|
4863
4869
|
*/
|
|
4864
|
-
|
|
4865
|
-
|
|
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
|
+
};
|
|
4866
4902
|
}
|
|
4867
4903
|
/**
|
|
4868
|
-
*
|
|
4904
|
+
* Check if PowerSync is available.
|
|
4869
4905
|
*
|
|
4870
|
-
*
|
|
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
|
|
4871
4911
|
*/
|
|
4872
|
-
|
|
4873
|
-
|
|
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
|
+
}
|
|
4874
4929
|
}
|
|
4875
4930
|
/**
|
|
4876
|
-
*
|
|
4931
|
+
* Check if Supabase is available.
|
|
4877
4932
|
*
|
|
4878
|
-
*
|
|
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
|
|
4879
4937
|
*/
|
|
4880
|
-
|
|
4881
|
-
|
|
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
|
+
}
|
|
4882
4950
|
}
|
|
4883
4951
|
/**
|
|
4884
|
-
*
|
|
4952
|
+
* Check if device is online.
|
|
4885
4953
|
*
|
|
4886
|
-
*
|
|
4887
|
-
*
|
|
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
|
|
4888
4960
|
*/
|
|
4889
|
-
|
|
4890
|
-
|
|
4891
|
-
|
|
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;
|
|
4892
4969
|
}
|
|
4970
|
+
// ===========================================================================
|
|
4971
|
+
// Instance Management Methods
|
|
4972
|
+
// ===========================================================================
|
|
4893
4973
|
/**
|
|
4894
|
-
*
|
|
4974
|
+
* Update PowerSync instance (e.g., when it becomes available).
|
|
4895
4975
|
*
|
|
4896
|
-
* @param
|
|
4897
|
-
* @returns True if table uses PowerSync, Hybrid, or Auto strategy
|
|
4976
|
+
* @param db - New PowerSync database instance or null
|
|
4898
4977
|
*/
|
|
4899
|
-
|
|
4900
|
-
|
|
4901
|
-
return strategy?.strategy === "powersync" || strategy?.strategy === "hybrid" || strategy?.strategy === "auto";
|
|
4978
|
+
setPowerSync(db) {
|
|
4979
|
+
this.powerSyncDb = db;
|
|
4902
4980
|
}
|
|
4903
4981
|
/**
|
|
4904
|
-
*
|
|
4982
|
+
* Update Supabase instance.
|
|
4905
4983
|
*
|
|
4906
|
-
* @
|
|
4984
|
+
* @param supabase - New Supabase client instance or null
|
|
4907
4985
|
*/
|
|
4908
|
-
|
|
4909
|
-
|
|
4986
|
+
setSupabase(supabase) {
|
|
4987
|
+
this.supabase = supabase;
|
|
4910
4988
|
}
|
|
4911
4989
|
/**
|
|
4912
|
-
* Get
|
|
4990
|
+
* Get current PowerSync instance.
|
|
4913
4991
|
*
|
|
4914
|
-
* @returns
|
|
4992
|
+
* @returns Current PowerSync database instance or null
|
|
4915
4993
|
*/
|
|
4916
|
-
|
|
4917
|
-
return
|
|
4994
|
+
getPowerSync() {
|
|
4995
|
+
return this.powerSyncDb;
|
|
4918
4996
|
}
|
|
4919
4997
|
/**
|
|
4920
|
-
* Get
|
|
4921
|
-
* Uses explicit alias from config if set, otherwise auto-generates.
|
|
4998
|
+
* Get current Supabase instance.
|
|
4922
4999
|
*
|
|
4923
|
-
* @
|
|
4924
|
-
* @returns The alias to use in PowerSync schema
|
|
5000
|
+
* @returns Current Supabase client instance or null
|
|
4925
5001
|
*/
|
|
4926
|
-
|
|
4927
|
-
|
|
4928
|
-
const tableWithoutSchema = table.includes(".") ? table.split(".")[1] : table;
|
|
4929
|
-
const configKey = this.config.tables[table] ? table : tableWithoutSchema;
|
|
4930
|
-
return getPowerSyncAlias(configKey, strategy);
|
|
5002
|
+
getSupabase() {
|
|
5003
|
+
return this.supabase;
|
|
4931
5004
|
}
|
|
4932
5005
|
// ===========================================================================
|
|
4933
|
-
//
|
|
5006
|
+
// Options Management
|
|
4934
5007
|
// ===========================================================================
|
|
4935
5008
|
/**
|
|
4936
|
-
*
|
|
5009
|
+
* Update detector options.
|
|
4937
5010
|
*
|
|
4938
|
-
* @param
|
|
4939
|
-
* @returns The automatically selected adapter
|
|
5011
|
+
* @param options - New options to merge with existing
|
|
4940
5012
|
*/
|
|
4941
|
-
|
|
4942
|
-
|
|
4943
|
-
|
|
4944
|
-
|
|
4945
|
-
|
|
4946
|
-
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
4947
|
-
console.warn(`[AdapterRegistry] No auto-detector configured${table ? ` for table "${table}"` : ""}. Using Supabase fallback.`);
|
|
4948
|
-
}
|
|
4949
|
-
return this.supabaseAdapter;
|
|
4950
|
-
}
|
|
4951
|
-
const detection = this.autoDetector.detectSilent();
|
|
4952
|
-
this.lastDetectionResult = detection;
|
|
4953
|
-
if (detection.recommendedBackend === "powersync") {
|
|
4954
|
-
if (!this.powerSyncAdapter) {
|
|
4955
|
-
if (!this.supabaseAdapter) {
|
|
4956
|
-
throw new Error("Neither PowerSync nor Supabase adapters are available.");
|
|
4957
|
-
}
|
|
4958
|
-
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
4959
|
-
console.warn(`[AdapterRegistry] PowerSync recommended${table ? ` for table "${table}"` : ""} but adapter not available. Falling back to Supabase. Reason: ${detection.reason}`);
|
|
4960
|
-
}
|
|
4961
|
-
return this.supabaseAdapter;
|
|
4962
|
-
}
|
|
4963
|
-
return this.powerSyncAdapter;
|
|
4964
|
-
}
|
|
4965
|
-
if (!this.supabaseAdapter) {
|
|
4966
|
-
throw new Error("Supabase adapter not available and PowerSync not recommended.");
|
|
4967
|
-
}
|
|
4968
|
-
return this.supabaseAdapter;
|
|
5013
|
+
setOptions(options) {
|
|
5014
|
+
this.options = {
|
|
5015
|
+
...this.options,
|
|
5016
|
+
...options
|
|
5017
|
+
};
|
|
4969
5018
|
}
|
|
4970
5019
|
/**
|
|
4971
|
-
*
|
|
5020
|
+
* Get current detector options.
|
|
4972
5021
|
*
|
|
4973
|
-
* @
|
|
4974
|
-
* @returns Unsubscribe function
|
|
5022
|
+
* @returns Current detector options
|
|
4975
5023
|
*/
|
|
4976
|
-
|
|
4977
|
-
|
|
4978
|
-
|
|
4979
|
-
this.backendChangeListeners.delete(callback);
|
|
5024
|
+
getOptions() {
|
|
5025
|
+
return {
|
|
5026
|
+
...this.options
|
|
4980
5027
|
};
|
|
4981
5028
|
}
|
|
5029
|
+
// ===========================================================================
|
|
5030
|
+
// Listener Management
|
|
5031
|
+
// ===========================================================================
|
|
4982
5032
|
/**
|
|
4983
|
-
*
|
|
5033
|
+
* Add a listener for backend change events.
|
|
4984
5034
|
*
|
|
4985
|
-
* @param
|
|
5035
|
+
* @param listener - Callback to invoke when detection result changes
|
|
5036
|
+
* @returns Function to remove the listener
|
|
4986
5037
|
*/
|
|
4987
|
-
|
|
4988
|
-
this.
|
|
4989
|
-
|
|
4990
|
-
callback(backend);
|
|
4991
|
-
} catch (error) {
|
|
4992
|
-
console.error("Error in backend change listener:", error);
|
|
4993
|
-
}
|
|
4994
|
-
});
|
|
5038
|
+
addListener(listener) {
|
|
5039
|
+
this.listeners.add(listener);
|
|
5040
|
+
return () => this.listeners.delete(listener);
|
|
4995
5041
|
}
|
|
4996
5042
|
/**
|
|
4997
|
-
*
|
|
5043
|
+
* Remove a listener for backend change events.
|
|
4998
5044
|
*
|
|
4999
|
-
* @
|
|
5045
|
+
* @param listener - Listener to remove
|
|
5000
5046
|
*/
|
|
5001
|
-
|
|
5002
|
-
|
|
5047
|
+
removeListener(listener) {
|
|
5048
|
+
this.listeners.delete(listener);
|
|
5003
5049
|
}
|
|
5004
5050
|
/**
|
|
5005
|
-
* Get the
|
|
5051
|
+
* Get the last detection result.
|
|
5006
5052
|
*
|
|
5007
|
-
* @returns
|
|
5053
|
+
* @returns Last detection result or null if never detected
|
|
5008
5054
|
*/
|
|
5009
|
-
|
|
5010
|
-
return this.
|
|
5055
|
+
getLastResult() {
|
|
5056
|
+
return this.lastResult;
|
|
5011
5057
|
}
|
|
5012
5058
|
// ===========================================================================
|
|
5013
|
-
// Private Methods
|
|
5059
|
+
// Private Helper Methods
|
|
5014
5060
|
// ===========================================================================
|
|
5015
5061
|
/**
|
|
5016
|
-
*
|
|
5017
|
-
*
|
|
5018
|
-
* @param strategy - The table strategy configuration
|
|
5019
|
-
* @returns The created adapter
|
|
5020
|
-
* @throws Error if the required base adapter is not initialized
|
|
5062
|
+
* Check if the detection result has changed from the last result.
|
|
5021
5063
|
*/
|
|
5022
|
-
|
|
5023
|
-
|
|
5024
|
-
|
|
5025
|
-
if (!this.powerSyncAdapter) {
|
|
5026
|
-
if (this.supabaseAdapter) {
|
|
5027
|
-
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
5028
|
-
console.warn(`[AdapterRegistry] PowerSync not ready, falling back to Supabase`);
|
|
5029
|
-
}
|
|
5030
|
-
return this.supabaseAdapter;
|
|
5031
|
-
}
|
|
5032
|
-
throw new Error("PowerSync adapter not initialized and Supabase not available. Ensure PowerSyncAdapter is set before accessing PowerSync tables.");
|
|
5033
|
-
}
|
|
5034
|
-
return this.syncTrackingAdapter ?? this.powerSyncAdapter;
|
|
5035
|
-
case "supabase":
|
|
5036
|
-
if (!this.supabaseAdapter) {
|
|
5037
|
-
throw new Error("Supabase adapter not initialized. Ensure SupabaseAdapter is set before accessing Supabase tables.");
|
|
5038
|
-
}
|
|
5039
|
-
return this.supabaseAdapter;
|
|
5040
|
-
case "cached":
|
|
5041
|
-
if (this.cachedAdapter) {
|
|
5042
|
-
return this.cachedAdapter;
|
|
5043
|
-
}
|
|
5044
|
-
throw new Error("CachedAdapter not yet implemented. This feature will be available in Wave 2. For now, use 'supabase' strategy as a fallback.");
|
|
5045
|
-
case "hybrid":
|
|
5046
|
-
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.");
|
|
5047
|
-
default:
|
|
5048
|
-
if (!this.supabaseAdapter) {
|
|
5049
|
-
throw new Error("Supabase adapter not initialized. Ensure SupabaseAdapter is set before accessing tables.");
|
|
5050
|
-
}
|
|
5051
|
-
return this.supabaseAdapter;
|
|
5064
|
+
hasResultChanged(result) {
|
|
5065
|
+
if (!this.lastResult) {
|
|
5066
|
+
return true;
|
|
5052
5067
|
}
|
|
5053
|
-
|
|
5054
|
-
// ===========================================================================
|
|
5055
|
-
// Utility Methods
|
|
5056
|
-
// ===========================================================================
|
|
5057
|
-
/**
|
|
5058
|
-
* Clear all cached adapters.
|
|
5059
|
-
* Useful when configuration changes and adapters need to be recreated.
|
|
5060
|
-
*/
|
|
5061
|
-
clearCache() {
|
|
5062
|
-
this.adapters.clear();
|
|
5063
|
-
}
|
|
5064
|
-
/**
|
|
5065
|
-
* Reset the registry to uninitialized state.
|
|
5066
|
-
* Used during cleanup or testing.
|
|
5067
|
-
*/
|
|
5068
|
-
reset() {
|
|
5069
|
-
this.adapters.clear();
|
|
5070
|
-
this.powerSyncAdapter = null;
|
|
5071
|
-
this.supabaseAdapter = null;
|
|
5072
|
-
this.cachedAdapter = null;
|
|
5073
|
-
this.deps = null;
|
|
5074
|
-
this._isInitialized = false;
|
|
5075
|
-
this.autoDetector = null;
|
|
5076
|
-
this.backendChangeListeners.clear();
|
|
5077
|
-
this.lastDetectionResult = null;
|
|
5078
|
-
this.syncTracker = null;
|
|
5079
|
-
this.syncTrackingAdapter = null;
|
|
5080
|
-
}
|
|
5081
|
-
/**
|
|
5082
|
-
* Dispose all adapters and clean up resources.
|
|
5083
|
-
* Called when the DataLayerProvider unmounts.
|
|
5084
|
-
*/
|
|
5085
|
-
dispose() {
|
|
5086
|
-
this.reset();
|
|
5068
|
+
return this.lastResult.powerSyncStatus !== result.powerSyncStatus || this.lastResult.supabaseStatus !== result.supabaseStatus || this.lastResult.recommendedBackend !== result.recommendedBackend || this.lastResult.isOnline !== result.isOnline;
|
|
5087
5069
|
}
|
|
5088
5070
|
/**
|
|
5089
|
-
*
|
|
5071
|
+
* Notify all listeners of a detection result change.
|
|
5090
5072
|
*/
|
|
5091
|
-
|
|
5092
|
-
|
|
5093
|
-
|
|
5094
|
-
|
|
5095
|
-
|
|
5096
|
-
|
|
5097
|
-
|
|
5098
|
-
|
|
5099
|
-
|
|
5100
|
-
|
|
5101
|
-
|
|
5102
|
-
|
|
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
|
+
});
|
|
5103
5091
|
}
|
|
5104
5092
|
};
|
|
5105
|
-
function
|
|
5106
|
-
return new
|
|
5093
|
+
function createAdapterAutoDetector(powerSyncDb, supabase, options) {
|
|
5094
|
+
return new AdapterAutoDetector(powerSyncDb, supabase, options);
|
|
5107
5095
|
}
|
|
5108
5096
|
|
|
5109
5097
|
// src/adapters/supabase-adapter.ts
|
|
@@ -7933,13 +7921,13 @@ export {
|
|
|
7933
7921
|
useMutationSuccess,
|
|
7934
7922
|
useMutationSuccessRN,
|
|
7935
7923
|
ADAPTER_STRATEGIES,
|
|
7936
|
-
BackendStatus,
|
|
7937
|
-
AdapterAutoDetector,
|
|
7938
|
-
createAdapterAutoDetector,
|
|
7939
7924
|
SyncTrackingAdapter,
|
|
7940
7925
|
stripSchemaPrefix,
|
|
7941
7926
|
AdapterRegistry,
|
|
7942
7927
|
createAdapterRegistry,
|
|
7928
|
+
BackendStatus,
|
|
7929
|
+
AdapterAutoDetector,
|
|
7930
|
+
createAdapterAutoDetector,
|
|
7943
7931
|
SupabaseAdapter,
|
|
7944
7932
|
createSupabaseAdapter,
|
|
7945
7933
|
getErrorBody,
|
|
@@ -7996,4 +7984,4 @@ moment/moment.js:
|
|
|
7996
7984
|
(*! license : MIT *)
|
|
7997
7985
|
(*! momentjs.com *)
|
|
7998
7986
|
*/
|
|
7999
|
-
//# sourceMappingURL=chunk-
|
|
7987
|
+
//# sourceMappingURL=chunk-EOJGUOJR.js.map
|