@pol-studios/db 1.0.54 → 1.0.55

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/dist/auth/context.js +4 -4
  2. package/dist/auth/hooks.js +5 -5
  3. package/dist/auth/index.js +5 -5
  4. package/dist/{chunk-FIAXWEBK.js → chunk-7YGDT46S.js} +4 -4
  5. package/dist/{chunk-BZSAPFFB.js → chunk-AA3VUWTP.js} +112 -16
  6. package/dist/chunk-AA3VUWTP.js.map +1 -0
  7. package/dist/{chunk-3Q74DK5K.js → chunk-AKCNWHXV.js} +2 -2
  8. package/dist/{chunk-UJWETW36.js → chunk-AKIRHA4Q.js} +527 -418
  9. package/dist/chunk-AKIRHA4Q.js.map +1 -0
  10. package/dist/{chunk-FMYXG4VN.js → chunk-BRFFTGVJ.js} +2 -2
  11. package/dist/{chunk-YA6MUTA7.js → chunk-FI6JAD5G.js} +3 -3
  12. package/dist/chunk-JOULSXOI.js +415 -0
  13. package/dist/chunk-JOULSXOI.js.map +1 -0
  14. package/dist/{chunk-OKYHI6JG.js → chunk-LF3V3ERS.js} +3 -3
  15. package/dist/{chunk-2XS2PM62.js → chunk-OC6S4XFL.js} +7 -7
  16. package/dist/{chunk-DP3YEVSX.js → chunk-WILXD5X3.js} +3 -3
  17. package/dist/{chunk-ZGQ7Q4ZU.js → chunk-WM25QE7E.js} +2 -2
  18. package/dist/{chunk-WQLIGVQR.js → chunk-WSKBZIEI.js} +4 -1
  19. package/dist/chunk-WSKBZIEI.js.map +1 -0
  20. package/dist/chunk-YUX6RGLZ.js +1858 -0
  21. package/dist/chunk-YUX6RGLZ.js.map +1 -0
  22. package/dist/{chunk-Z3EJX3VG.js → chunk-Z456IHCB.js} +3 -3
  23. package/dist/hooks/index.js +2 -2
  24. package/dist/index.js +13 -13
  25. package/dist/index.native.d.ts +56 -2
  26. package/dist/index.native.js +13 -13
  27. package/dist/index.web.js +13 -13
  28. package/dist/mutation/index.js +3 -3
  29. package/dist/parser/index.js +3 -3
  30. package/dist/query/index.js +4 -4
  31. package/dist/realtime/index.js +3 -3
  32. package/dist/types/index.js +4 -4
  33. package/dist/with-auth/index.js +7 -7
  34. package/package.json +5 -3
  35. package/dist/chunk-BZSAPFFB.js.map +0 -1
  36. package/dist/chunk-CTRY7JDP.js +0 -4112
  37. package/dist/chunk-CTRY7JDP.js.map +0 -1
  38. package/dist/chunk-INEUG6MC.js +0 -521
  39. package/dist/chunk-INEUG6MC.js.map +0 -1
  40. package/dist/chunk-UJWETW36.js.map +0 -1
  41. package/dist/chunk-WQLIGVQR.js.map +0 -1
  42. /package/dist/{chunk-FIAXWEBK.js.map → chunk-7YGDT46S.js.map} +0 -0
  43. /package/dist/{chunk-3Q74DK5K.js.map → chunk-AKCNWHXV.js.map} +0 -0
  44. /package/dist/{chunk-FMYXG4VN.js.map → chunk-BRFFTGVJ.js.map} +0 -0
  45. /package/dist/{chunk-YA6MUTA7.js.map → chunk-FI6JAD5G.js.map} +0 -0
  46. /package/dist/{chunk-OKYHI6JG.js.map → chunk-LF3V3ERS.js.map} +0 -0
  47. /package/dist/{chunk-2XS2PM62.js.map → chunk-OC6S4XFL.js.map} +0 -0
  48. /package/dist/{chunk-DP3YEVSX.js.map → chunk-WILXD5X3.js.map} +0 -0
  49. /package/dist/{chunk-ZGQ7Q4ZU.js.map → chunk-WM25QE7E.js.map} +0 -0
  50. /package/dist/{chunk-Z3EJX3VG.js.map → chunk-Z456IHCB.js.map} +0 -0
@@ -11,11 +11,11 @@ import {
11
11
  useUserMetadataState,
12
12
  useUserMetadataValue,
13
13
  userMetadataContext
14
- } from "../chunk-DP3YEVSX.js";
15
- import "../chunk-WQLIGVQR.js";
14
+ } from "../chunk-WILXD5X3.js";
15
+ import "../chunk-WSKBZIEI.js";
16
16
  import "../chunk-J4ZVCXZ4.js";
17
- import "../chunk-CTRY7JDP.js";
18
- import "../chunk-INEUG6MC.js";
17
+ import "../chunk-YUX6RGLZ.js";
18
+ import "../chunk-AKIRHA4Q.js";
19
19
  import "../chunk-DMVUEJG2.js";
20
20
  import "../chunk-7D4SUZUM.js";
21
21
  export {
@@ -11,17 +11,17 @@ import {
11
11
  usePermissionLoading,
12
12
  usePermissionsBatch,
13
13
  useSetupAuth
14
- } from "../chunk-FMYXG4VN.js";
14
+ } from "../chunk-BRFFTGVJ.js";
15
15
  import {
16
16
  useSetUserMetadata,
17
17
  useUserMetadata,
18
18
  useUserMetadataState,
19
19
  useUserMetadataValue
20
- } from "../chunk-DP3YEVSX.js";
21
- import "../chunk-WQLIGVQR.js";
20
+ } from "../chunk-WILXD5X3.js";
21
+ import "../chunk-WSKBZIEI.js";
22
22
  import "../chunk-J4ZVCXZ4.js";
23
- import "../chunk-CTRY7JDP.js";
24
- import "../chunk-INEUG6MC.js";
23
+ import "../chunk-YUX6RGLZ.js";
24
+ import "../chunk-AKIRHA4Q.js";
25
25
  import "../chunk-DMVUEJG2.js";
26
26
  import "../chunk-7D4SUZUM.js";
27
27
  export {
@@ -12,7 +12,7 @@ import {
12
12
  usePermissionLoading,
13
13
  usePermissionsBatch,
14
14
  useSetupAuth
15
- } from "../chunk-FMYXG4VN.js";
15
+ } from "../chunk-BRFFTGVJ.js";
16
16
  import {
17
17
  AuthProvider,
18
18
  PermissionProvider,
@@ -26,8 +26,8 @@ import {
26
26
  useUserMetadataState,
27
27
  useUserMetadataValue,
28
28
  userMetadataContext
29
- } from "../chunk-DP3YEVSX.js";
30
- import "../chunk-WQLIGVQR.js";
29
+ } from "../chunk-WILXD5X3.js";
30
+ import "../chunk-WSKBZIEI.js";
31
31
  import {
32
32
  hasAccess,
33
33
  hasAllAccess,
@@ -39,8 +39,8 @@ import {
39
39
  isPermissionLoaded
40
40
  } from "../chunk-RT4O5H2E.js";
41
41
  import "../chunk-J4ZVCXZ4.js";
42
- import "../chunk-CTRY7JDP.js";
43
- import "../chunk-INEUG6MC.js";
42
+ import "../chunk-YUX6RGLZ.js";
43
+ import "../chunk-AKIRHA4Q.js";
44
44
  import "../chunk-DMVUEJG2.js";
45
45
  import "../chunk-7D4SUZUM.js";
46
46
  export {
@@ -1,15 +1,15 @@
1
1
  import {
2
2
  useDbUpsert
3
- } from "./chunk-3Q74DK5K.js";
3
+ } from "./chunk-AKCNWHXV.js";
4
4
  import {
5
5
  UserMetadata
6
6
  } from "./chunk-SM73S2DY.js";
7
7
  import {
8
8
  useSetupAuth
9
- } from "./chunk-FMYXG4VN.js";
9
+ } from "./chunk-BRFFTGVJ.js";
10
10
  import {
11
11
  useDbQuery
12
- } from "./chunk-DP3YEVSX.js";
12
+ } from "./chunk-WILXD5X3.js";
13
13
  import {
14
14
  useSupabase
15
15
  } from "./chunk-DMVUEJG2.js";
@@ -467,4 +467,4 @@ export {
467
467
  useSetUserMetadata,
468
468
  useUserMetadataState
469
469
  };
470
- //# sourceMappingURL=chunk-FIAXWEBK.js.map
470
+ //# sourceMappingURL=chunk-7YGDT46S.js.map
@@ -3,12 +3,13 @@ import {
3
3
  createAdapterRegistry,
4
4
  createSupabaseAdapter,
5
5
  stripSchemaPrefix
6
- } from "./chunk-2XS2PM62.js";
6
+ } from "./chunk-OC6S4XFL.js";
7
7
  import {
8
8
  DataLayerContext,
9
9
  DataLayerCoreContext,
10
+ DataLayerNestingContext,
10
11
  DataLayerStatusContext
11
- } from "./chunk-WQLIGVQR.js";
12
+ } from "./chunk-WSKBZIEI.js";
12
13
  import {
13
14
  QueryExecutor,
14
15
  extractRelationNames,
@@ -1104,19 +1105,27 @@ function transformWithRelations(row, schema, tableName) {
1104
1105
  }
1105
1106
 
1106
1107
  // src/adapters/powersync-adapter.ts
1108
+ import stringify from "fast-json-stable-stringify";
1109
+ var DEFAULT_MAX_SUBSCRIPTIONS = 100;
1107
1110
  var PowerSyncAdapter = class {
1108
1111
  /**
1109
1112
  * Create a new PowerSyncAdapter
1110
1113
  *
1111
1114
  * @param db - PowerSync database instance
1112
1115
  * @param schema - Database schema for relationship resolution
1113
- * @param tableNameResolver - Optional custom resolver for table names to PowerSync aliases
1116
+ * @param options - Optional configuration (tableNameResolver, maxSubscriptions)
1114
1117
  */
1115
- constructor(db, schema, tableNameResolver) {
1118
+ constructor(db, schema, options) {
1116
1119
  this.db = db;
1117
1120
  this.schema = schema;
1118
1121
  this.executor = new QueryExecutor(db, schema);
1119
- this.tableNameResolver = tableNameResolver;
1122
+ if (typeof options === "function") {
1123
+ this.tableNameResolver = options;
1124
+ this.maxSubscriptions = DEFAULT_MAX_SUBSCRIPTIONS;
1125
+ } else {
1126
+ this.tableNameResolver = options?.tableNameResolver;
1127
+ this.maxSubscriptions = options?.maxSubscriptions ?? DEFAULT_MAX_SUBSCRIPTIONS;
1128
+ }
1120
1129
  }
1121
1130
  /**
1122
1131
  * Unique identifier for this adapter type
@@ -1140,6 +1149,31 @@ var PowerSyncAdapter = class {
1140
1149
  * If not provided, uses default auto-alias generation.
1141
1150
  */
1142
1151
  tableNameResolver;
1152
+ /**
1153
+ * Maximum number of subscriptions to keep in the registry.
1154
+ */
1155
+ maxSubscriptions;
1156
+ /**
1157
+ * Subscription deduplication registry.
1158
+ * Maps cache keys (table + serialized options) to shared subscription entries.
1159
+ * This prevents duplicate PowerSync watch() calls when multiple components
1160
+ * subscribe to the same query.
1161
+ *
1162
+ * Uses Map insertion order for LRU eviction - most recently accessed entries
1163
+ * are moved to the end by deleting and re-adding.
1164
+ */
1165
+ subscriptionRegistry = /* @__PURE__ */ new Map();
1166
+ /**
1167
+ * Move a subscription entry to the end of the Map for LRU tracking.
1168
+ * The most recently accessed entries are at the end; oldest are at the start.
1169
+ *
1170
+ * @param key - The subscription cache key
1171
+ * @param entry - The subscription entry to touch
1172
+ */
1173
+ touchSubscription(key, entry) {
1174
+ this.subscriptionRegistry.delete(key);
1175
+ this.subscriptionRegistry.set(key, entry);
1176
+ }
1143
1177
  /**
1144
1178
  * Resolve a table name to its PowerSync alias.
1145
1179
  * Schema-qualified names like "chat.Conversation" become "Conversation" (schema stripped).
@@ -1193,12 +1227,31 @@ var PowerSyncAdapter = class {
1193
1227
  }
1194
1228
  return transformWithRelations(rawResult, this.schema, table);
1195
1229
  }
1230
+ /**
1231
+ * Generate a unique cache key for subscription deduplication.
1232
+ * Combines table name and serialized options to identify identical queries.
1233
+ * Uses sorted keys to ensure consistent serialization regardless of property order.
1234
+ *
1235
+ * @param table - The table name
1236
+ * @param options - Query options
1237
+ * @returns A unique string key for the subscription registry
1238
+ */
1239
+ generateSubscriptionKey(table, options) {
1240
+ return `${table}:${stringify(options)}`;
1241
+ }
1196
1242
  /**
1197
1243
  * Subscribe to changes on a query using PowerSync's native watch() API.
1198
1244
  *
1199
1245
  * This uses PowerSync's reactive query watching which efficiently detects
1200
1246
  * changes to the underlying data and re-executes the query only when needed.
1201
1247
  *
1248
+ * Subscription Deduplication:
1249
+ * Multiple components subscribing to the same query (same table + options)
1250
+ * will share a single underlying PowerSync watch. This optimization:
1251
+ * - Reduces database load by avoiding duplicate watches
1252
+ * - Provides instant data to new subscribers from cached results
1253
+ * - Properly cleans up when all subscribers unsubscribe
1254
+ *
1202
1255
  * If the database doesn't support watch(), falls back to polling every 5 seconds.
1203
1256
  *
1204
1257
  * @param table - The table name to watch
@@ -1211,6 +1264,33 @@ var PowerSyncAdapter = class {
1211
1264
  if (!this.db.watch) {
1212
1265
  return this.subscribeWithPolling(table, options, callback);
1213
1266
  }
1267
+ const cacheKey = this.generateSubscriptionKey(resolvedTable, options);
1268
+ const existingEntry = this.subscriptionRegistry.get(cacheKey);
1269
+ if (existingEntry) {
1270
+ existingEntry.subscribers.add(callback);
1271
+ this.touchSubscription(cacheKey, existingEntry);
1272
+ return () => {
1273
+ existingEntry.subscribers.delete(callback);
1274
+ if (existingEntry.subscribers.size === 0) {
1275
+ existingEntry.unsubscribe();
1276
+ this.subscriptionRegistry.delete(cacheKey);
1277
+ }
1278
+ };
1279
+ }
1280
+ if (this.subscriptionRegistry.size >= this.maxSubscriptions) {
1281
+ let evicted = false;
1282
+ for (const [key, entry2] of this.subscriptionRegistry) {
1283
+ if (entry2.subscribers.size === 0) {
1284
+ entry2.unsubscribe();
1285
+ this.subscriptionRegistry.delete(key);
1286
+ evicted = true;
1287
+ break;
1288
+ }
1289
+ }
1290
+ if (!evicted && typeof __DEV__ !== "undefined" && __DEV__) {
1291
+ console.warn(`[PowerSyncAdapter] Subscription registry exceeded max (${this.maxSubscriptions}) but all entries have active subscribers. Registry size: ${this.subscriptionRegistry.size + 1}`);
1292
+ }
1293
+ }
1214
1294
  const abortController = new AbortController();
1215
1295
  const parsed = parseSelect(options.select ?? "*");
1216
1296
  const builder = this.executor.getBuilder();
@@ -1225,16 +1305,22 @@ var PowerSyncAdapter = class {
1225
1305
  });
1226
1306
  let watchTables = [resolvedTable];
1227
1307
  if (options.select && options.select !== "*") {
1228
- const parsed2 = parseSelect(options.select);
1229
- const relationNames = extractRelationNames(parsed2);
1308
+ const relationNames = extractRelationNames(parsed);
1230
1309
  watchTables = [resolvedTable, ...relationNames.map((r) => this.resolveTableName(r))];
1231
1310
  }
1311
+ const entry = {
1312
+ subscribers: /* @__PURE__ */ new Set([callback]),
1313
+ unsubscribe: () => abortController.abort()
1314
+ };
1315
+ this.subscriptionRegistry.set(cacheKey, entry);
1232
1316
  const schema = this.schema;
1233
1317
  this.db.watch(sql, params, {
1234
1318
  onResult: (results) => {
1235
1319
  const rawData = results.rows?._array ?? [];
1236
1320
  const data = transformResultsFromStorage(rawData, schema, table);
1237
- callback(data);
1321
+ for (const subscriber of entry.subscribers) {
1322
+ subscriber(data);
1323
+ }
1238
1324
  },
1239
1325
  onError: (error) => {
1240
1326
  console.error(`PowerSync subscription error for ${resolvedTable}:`, error);
@@ -1246,7 +1332,11 @@ var PowerSyncAdapter = class {
1246
1332
  // Throttle to prevent excessive re-queries
1247
1333
  });
1248
1334
  return () => {
1249
- abortController.abort();
1335
+ entry.subscribers.delete(callback);
1336
+ if (entry.subscribers.size === 0) {
1337
+ entry.unsubscribe();
1338
+ this.subscriptionRegistry.delete(cacheKey);
1339
+ }
1250
1340
  };
1251
1341
  }
1252
1342
  /**
@@ -1407,7 +1497,7 @@ function createPowerSyncAdapter(db, schema) {
1407
1497
  }
1408
1498
 
1409
1499
  // src/providers/DataLayerProvider.tsx
1410
- import { useState, useEffect, useMemo, useCallback, useRef } from "react";
1500
+ import { useState, useEffect, useMemo, useCallback, useRef, useContext } from "react";
1411
1501
  import { jsx } from "react/jsx-runtime";
1412
1502
  var defaultSyncStatus = {
1413
1503
  isConnected: false,
@@ -1454,6 +1544,12 @@ function DataLayerProvider({
1454
1544
  powerSyncSyncStatus,
1455
1545
  syncControl: externalSyncControl
1456
1546
  }) {
1547
+ const isNested = useContext(DataLayerNestingContext);
1548
+ const hasWarnedNesting = useRef(false);
1549
+ if (isNested && !hasWarnedNesting.current && typeof __DEV__ !== "undefined" && __DEV__) {
1550
+ hasWarnedNesting.current = true;
1551
+ console.warn("[DataLayerProvider] Nested DataLayerProvider detected! This usually indicates a setup issue where DataLayerProvider is wrapped twice. Each DataLayerProvider creates its own registry, which can cause:\n - Queries using wrong adapter (e.g., Supabase instead of PowerSync)\n - Inconsistent cache state\n - Unexpected behavior with sync status\n\nCommon causes:\n - Using both DataLayerWrapper and OfflineDataProvider (OfflineDataProvider already includes DataLayerProvider)\n - Accidentally wrapping layout twice\n\nFix: Remove the outer DataLayerProvider wrapper.");
1552
+ }
1457
1553
  const [registry] = useState(() => createAdapterRegistry(config));
1458
1554
  const powerSyncInstanceRef = useRef(powerSyncInstance);
1459
1555
  powerSyncInstanceRef.current = powerSyncInstance;
@@ -1699,7 +1795,7 @@ function DataLayerProvider({
1699
1795
  const resolvedCore = coreContextValue ?? pendingCoreContextValue;
1700
1796
  const resolvedStatus = statusContextValue ?? pendingStatusContextValue;
1701
1797
  const resolvedContext = contextValue ?? pendingContextValue;
1702
- return /* @__PURE__ */ jsx(DataLayerContext.Provider, { value: resolvedContext, children: /* @__PURE__ */ jsx(DataLayerCoreContext.Provider, { value: resolvedCore, children: /* @__PURE__ */ jsx(DataLayerStatusContext.Provider, { value: resolvedStatus, children }) }) });
1798
+ return /* @__PURE__ */ jsx(DataLayerNestingContext.Provider, { value: true, children: /* @__PURE__ */ jsx(DataLayerContext.Provider, { value: resolvedContext, children: /* @__PURE__ */ jsx(DataLayerCoreContext.Provider, { value: resolvedCore, children: /* @__PURE__ */ jsx(DataLayerStatusContext.Provider, { value: resolvedStatus, children }) }) }) });
1703
1799
  }
1704
1800
 
1705
1801
  // src/storage/use-supabase-upload.tsx
@@ -4630,9 +4726,9 @@ function _temp(err) {
4630
4726
 
4631
4727
  // src/conflicts/useConflictState.ts
4632
4728
  import { c as _c2 } from "react/compiler-runtime";
4633
- import { useContext } from "react";
4729
+ import { useContext as useContext2 } from "react";
4634
4730
  function useConflictState() {
4635
- const context = useContext(ConflictContext);
4731
+ const context = useContext2(ConflictContext);
4636
4732
  if (!context) {
4637
4733
  throw new Error("useConflictState must be used within a ConflictProvider. Wrap your app with <ConflictProvider> to enable conflict management.");
4638
4734
  }
@@ -4640,7 +4736,7 @@ function useConflictState() {
4640
4736
  }
4641
4737
  function usePendingConflicts() {
4642
4738
  const $ = _c2(2);
4643
- const context = useContext(ConflictContext);
4739
+ const context = useContext2(ConflictContext);
4644
4740
  let t0;
4645
4741
  if ($[0] !== context?.pendingConflicts) {
4646
4742
  t0 = context?.pendingConflicts ?? [];
@@ -4652,7 +4748,7 @@ function usePendingConflicts() {
4652
4748
  return t0;
4653
4749
  }
4654
4750
  function useHasConflicts() {
4655
- const context = useContext(ConflictContext);
4751
+ const context = useContext2(ConflictContext);
4656
4752
  return context?.hasConflicts ?? false;
4657
4753
  }
4658
4754
  function useConflictForRecord(table, recordId) {
@@ -4968,4 +5064,4 @@ object-assign/index.js:
4968
5064
  @license MIT
4969
5065
  *)
4970
5066
  */
4971
- //# sourceMappingURL=chunk-BZSAPFFB.js.map
5067
+ //# sourceMappingURL=chunk-AA3VUWTP.js.map