@keepkit/core 0.28.4 → 0.28.5

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.
@@ -84,6 +84,9 @@ function isKeepItemArray(value) {
84
84
  function isKeepCollectionDefinition(value) {
85
85
  return isRecord(value) && typeof value.id === "string" && value.id.trim().length > 0 && typeof value.name === "string" && value.name.trim().length > 0 && (value.scope === void 0 || isSyncScope(value.scope));
86
86
  }
87
+ function isKeepCollectionMembership(value) {
88
+ return isRecord(value) && typeof value.collectionId === "string" && value.collectionId.trim().length > 0 && typeof value.itemId === "string" && value.itemId.trim().length > 0 && typeof value.order === "number" && Number.isInteger(value.order) && Number.isFinite(value.order) && value.order >= 0 && (value.scope === void 0 || isSyncScope(value.scope));
89
+ }
87
90
  function isRecord(value) {
88
91
  return typeof value === "object" && value !== null;
89
92
  }
@@ -116,6 +119,17 @@ var ScopedStorageAdapter = class {
116
119
  this.setCollection = (collection) => setCollection({ ...collection, ...this.scope ? { scope: this.scope } : {} });
117
120
  this.removeCollection = (id) => removeCollection(id, this.scope);
118
121
  }
122
+ if (base.getCollectionMemberships && base.setCollectionMembership && base.removeCollectionMembership) {
123
+ const getMemberships = base.getCollectionMemberships.bind(base);
124
+ const setMembership = base.setCollectionMembership.bind(base);
125
+ const removeMembership = base.removeCollectionMembership.bind(base);
126
+ this.getCollectionMemberships = async () => {
127
+ const memberships = await getMemberships();
128
+ return this.scope ? memberships.filter((membership) => isSameKeepScope(membership.scope, this.scope)) : memberships;
129
+ };
130
+ this.setCollectionMembership = (membership) => setMembership({ ...membership, ...this.scope ? { scope: this.scope } : {} });
131
+ this.removeCollectionMembership = (collectionId, itemId) => removeMembership(collectionId, itemId, this.scope);
132
+ }
119
133
  }
120
134
  async getAll() {
121
135
  const items = await this.base.getAll();
@@ -225,7 +239,7 @@ var LocalStorageSyncQueueAdapter = class {
225
239
  } catch (cause) {
226
240
  throw Object.assign(new Error("KeepKit sync queue contains invalid JSON."), { cause });
227
241
  }
228
- if (!Array.isArray(value) || !value.every(isSyncOperation)) {
242
+ if (!Array.isArray(value) || !value.every(isSyncQueueOperation)) {
229
243
  throw new Error("KeepKit sync queue contains invalid operations.");
230
244
  }
231
245
  return value;
@@ -255,7 +269,7 @@ var IndexedDBSyncQueueAdapter = class {
255
269
  if (!database) return [];
256
270
  const transaction = database.transaction(this.storeName, "readonly");
257
271
  const value = await requestToPromise(transaction.objectStore(this.storeName).getAll());
258
- if (!Array.isArray(value) || !value.every(isSyncOperation)) {
272
+ if (!Array.isArray(value) || !value.every(isSyncQueueOperation)) {
259
273
  throw new Error("KeepKit sync queue contains invalid operations.");
260
274
  }
261
275
  return value;
@@ -385,8 +399,59 @@ var SyncStorageAdapter = class {
385
399
  const scope = this.scope;
386
400
  return scope ? collections.filter((collection) => sameScope(collection.scope, scope)) : collections;
387
401
  };
388
- this.setCollection = (collection) => setCollection({ ...collection, ...this.scope ? { scope: this.scope } : {} });
389
- this.removeCollection = (id) => removeCollection(id, this.scope);
402
+ this.setCollection = async (collection) => {
403
+ const scopedCollection = { ...collection, ...this.scope ? { scope: this.scope } : {} };
404
+ if (this.remote.pushCollection) {
405
+ const operation = this.createCollectionOperation("upsert", scopedCollection.id, scopedCollection);
406
+ await this.enqueueBeforeLocalWrite(operation);
407
+ try {
408
+ await setCollection(scopedCollection);
409
+ } catch (cause) {
410
+ await this.removeQueued(operation.operationId);
411
+ throw cause;
412
+ }
413
+ this.notifyDataListeners();
414
+ this.setPendingState();
415
+ return;
416
+ }
417
+ await setCollection(scopedCollection);
418
+ this.notifyDataListeners();
419
+ };
420
+ this.removeCollection = async (id) => {
421
+ if (this.remote.pushCollection) {
422
+ const operation = this.createCollectionOperation("remove", id);
423
+ await this.enqueueBeforeLocalWrite(operation);
424
+ try {
425
+ await removeCollection(id, this.scope);
426
+ } catch (cause) {
427
+ await this.removeQueued(operation.operationId);
428
+ throw cause;
429
+ }
430
+ this.notifyDataListeners();
431
+ this.setPendingState();
432
+ return;
433
+ }
434
+ await removeCollection(id, this.scope);
435
+ this.notifyDataListeners();
436
+ };
437
+ }
438
+ if (this.local.getCollectionMemberships && this.local.setCollectionMembership && this.local.removeCollectionMembership) {
439
+ const getMemberships = this.local.getCollectionMemberships.bind(this.local);
440
+ const setMembership = this.local.setCollectionMembership.bind(this.local);
441
+ const removeMembership = this.local.removeCollectionMembership.bind(this.local);
442
+ this.getCollectionMemberships = async () => {
443
+ const memberships = await getMemberships();
444
+ const scope = this.scope;
445
+ return scope ? memberships.filter((membership) => sameScope(membership.scope, scope)) : memberships;
446
+ };
447
+ this.setCollectionMembership = async (membership) => {
448
+ await setMembership({ ...membership, ...this.scope ? { scope: this.scope } : {} });
449
+ this.notifyDataListeners();
450
+ };
451
+ this.removeCollectionMembership = async (collectionId, itemId) => {
452
+ await removeMembership(collectionId, itemId, this.scope);
453
+ this.notifyDataListeners();
454
+ };
390
455
  }
391
456
  if (typeof window !== "undefined") {
392
457
  this.onlineHandler = () => void this.flushSync();
@@ -522,6 +587,16 @@ var SyncStorageAdapter = class {
522
587
  for (const operation of [...this.queueItems]) {
523
588
  if (this.disposed) return;
524
589
  try {
590
+ if (isCollectionSyncOperation(operation)) {
591
+ if (!this.remote.pushCollection) throw new Error("Remote sync driver does not support collection sync.");
592
+ await this.pushCollectionWithRetry(operation);
593
+ await this.removeQueued(operation.operationId);
594
+ this.updateState({
595
+ status: this.queueItems.length > 0 ? "syncing" : "synced",
596
+ lastSyncedAt: this.now()
597
+ });
598
+ continue;
599
+ }
525
600
  const result = await this.pushWithRetry(operation);
526
601
  if (result.type === "conflict") {
527
602
  const local = operation.item;
@@ -586,6 +661,17 @@ var SyncStorageAdapter = class {
586
661
  ...this.scope ? { scope: this.scope } : {}
587
662
  };
588
663
  }
664
+ createCollectionOperation(type, id, collection) {
665
+ return {
666
+ operationId: `${this.clientId}:${this.now()}:${createId()}`,
667
+ type,
668
+ entity: "collection",
669
+ id,
670
+ ...collection ? { collection } : {},
671
+ createdAt: this.now(),
672
+ ...this.scope ? { scope: this.scope } : {}
673
+ };
674
+ }
589
675
  applyScope(item) {
590
676
  return this.scope ? { ...item, scope: this.scope } : item;
591
677
  }
@@ -602,6 +688,20 @@ var SyncStorageAdapter = class {
602
688
  }
603
689
  }
604
690
  }
691
+ async pushCollectionWithRetry(operation) {
692
+ let attempt = 0;
693
+ while (true) {
694
+ try {
695
+ await this.remote.pushCollection?.({ ...operation, attempts: attempt });
696
+ return;
697
+ } catch (error) {
698
+ if (isKeepSyncAuthError(error) || attempt >= this.maxRetries) throw error;
699
+ attempt += 1;
700
+ const delay = this.retryDelayMs * this.retryBackoff ** (attempt - 1);
701
+ if (delay > 0) await wait(delay);
702
+ }
703
+ }
704
+ }
605
705
  async enqueueBeforeLocalWrite(operation) {
606
706
  await this.enqueueManyBeforeLocalWrite([operation]);
607
707
  }
@@ -610,7 +710,8 @@ var SyncStorageAdapter = class {
610
710
  const next = [...this.queueItems];
611
711
  for (const operation of operations) {
612
712
  for (let index = next.length - 1; index >= 0; index -= 1) {
613
- if (next[index]?.id !== operation.id) continue;
713
+ const queued = next[index];
714
+ if (!queued || getQueueIdentity(queued) !== getQueueIdentity(operation)) continue;
614
715
  next.splice(index, 1);
615
716
  }
616
717
  next.push(operation);
@@ -670,30 +771,53 @@ var SyncStorageAdapter = class {
670
771
  });
671
772
  }
672
773
  async pullRemote() {
673
- if (!this.remote.pull) return true;
774
+ if (!this.remote.pull && !this.remote.pullCollections) return true;
674
775
  try {
675
- const remoteItems = await this.remote.pull();
676
- const pendingIds = new Set(this.queueItems.map((operation) => operation.id));
677
- const localItems = await this.getAll();
678
- const localById = new Map(localItems.map((item) => [item.id, item]));
679
- const remoteById = /* @__PURE__ */ new Map();
680
- for (const item of remoteItems) {
681
- if (this.scope && item.scope && !sameScope(item.scope, this.scope)) continue;
682
- if (pendingIds.has(item.id)) continue;
683
- const previous = remoteById.get(item.id);
684
- remoteById.set(item.id, previous ? mergeKeepItemLists([item], [previous])[0] ?? item : item);
776
+ if (this.remote.pull) {
777
+ const remoteItems = await this.remote.pull();
778
+ const pendingIds = new Set(
779
+ this.queueItems.filter((operation) => operation.entity !== "collection").map((operation) => operation.id)
780
+ );
781
+ const localItems = await this.getAll();
782
+ const localById = new Map(localItems.map((item) => [item.id, item]));
783
+ const remoteById = /* @__PURE__ */ new Map();
784
+ for (const item of remoteItems) {
785
+ if (this.scope && item.scope && !sameScope(item.scope, this.scope)) continue;
786
+ if (pendingIds.has(item.id)) continue;
787
+ const previous = remoteById.get(item.id);
788
+ remoteById.set(item.id, previous ? mergeKeepItemLists([item], [previous])[0] ?? item : item);
789
+ }
790
+ const incoming = [...remoteById.values()].flatMap((item) => {
791
+ const current = localById.get(item.id);
792
+ if (current && item.updatedAt < current.updatedAt && (item.lastOpenedAt ?? 0) <= (current.lastOpenedAt ?? 0)) {
793
+ return [];
794
+ }
795
+ const merged = current ? mergeKeepItemLists([item], [current])[0] ?? item : item;
796
+ return [this.applyScope(merged)];
797
+ });
798
+ if (incoming.length > 0) {
799
+ await persistKeepItems(this.local, incoming);
800
+ this.notifyDataListeners();
801
+ }
685
802
  }
686
- const incoming = [...remoteById.values()].flatMap((item) => {
687
- const current = localById.get(item.id);
688
- if (current && item.updatedAt < current.updatedAt && (item.lastOpenedAt ?? 0) <= (current.lastOpenedAt ?? 0)) {
689
- return [];
803
+ if (this.remote.pullCollections && this.local.getCollections && this.local.setCollection && this.local.removeCollection) {
804
+ const remoteCollections = await this.remote.pullCollections();
805
+ const localCollections = await this.local.getCollections();
806
+ const pendingIds = new Set(this.queueItems.filter(isCollectionSyncOperation).map((operation) => operation.id));
807
+ const remoteById = new Map(
808
+ remoteCollections.filter((collection) => !this.scope || sameScope(collection.scope, this.scope)).map((collection) => [collection.id, collection])
809
+ );
810
+ for (const collection of remoteById.values()) {
811
+ if (pendingIds.has(collection.id)) continue;
812
+ await this.local.setCollection({ ...collection, ...this.scope ? { scope: this.scope } : {} });
690
813
  }
691
- const merged = current ? mergeKeepItemLists([item], [current])[0] ?? item : item;
692
- return [this.applyScope(merged)];
693
- });
694
- if (incoming.length === 0) return true;
695
- await persistKeepItems(this.local, incoming);
696
- this.notifyDataListeners();
814
+ for (const collection of localCollections) {
815
+ if (pendingIds.has(collection.id) || remoteById.has(collection.id)) continue;
816
+ if (this.scope && !sameScope(collection.scope, this.scope)) continue;
817
+ await this.local.removeCollection(collection.id, this.scope);
818
+ }
819
+ this.notifyDataListeners();
820
+ }
697
821
  return true;
698
822
  } catch (error) {
699
823
  this.updateState({ status: "error", error });
@@ -714,7 +838,17 @@ var SyncStorageAdapter = class {
714
838
  };
715
839
  function isSyncOperation(value) {
716
840
  if (!isRecord(value)) return false;
717
- return typeof value.operationId === "string" && (value.type === "upsert" || value.type === "remove") && typeof value.id === "string" && typeof value.createdAt === "number";
841
+ return typeof value.operationId === "string" && (value.type === "upsert" || value.type === "remove") && typeof value.id === "string" && typeof value.createdAt === "number" && (value.entity === void 0 || value.entity === "item" || value.entity === "collection") && (value.collection === void 0 || isKeepCollectionDefinition(value.collection)) && (value.entity !== "collection" || value.type !== "upsert" || isKeepCollectionDefinition(value.collection));
842
+ }
843
+ function isCollectionSyncOperation(value) {
844
+ if (!isRecord(value)) return false;
845
+ return typeof value.operationId === "string" && value.entity === "collection" && (value.type === "upsert" || value.type === "remove") && typeof value.id === "string" && typeof value.createdAt === "number" && (value.collection === void 0 || isKeepCollectionDefinition(value.collection));
846
+ }
847
+ function isSyncQueueOperation(value) {
848
+ return isSyncOperation(value) || isCollectionSyncOperation(value);
849
+ }
850
+ function getQueueIdentity(operation) {
851
+ return `${operation.entity === "collection" ? "collection" : "item"}:${operation.id}`;
718
852
  }
719
853
  function createId() {
720
854
  if (typeof crypto !== "undefined" && "randomUUID" in crypto) return crypto.randomUUID();
@@ -820,6 +954,22 @@ var FallbackStorageAdapter = class {
820
954
  return adapter.removeCollection(id, scope);
821
955
  });
822
956
  }
957
+ if (this.primary.getCollectionMemberships && this.primary.setCollectionMembership && this.primary.removeCollectionMembership && this.fallback.getCollectionMemberships && this.fallback.setCollectionMembership && this.fallback.removeCollectionMembership) {
958
+ const fallbackGetMemberships = this.fallback.getCollectionMemberships.bind(this.fallback);
959
+ this.getCollectionMemberships = async () => {
960
+ const memberships = await this.execute(
961
+ (adapter) => adapter.getCollectionMemberships?.() ?? Promise.resolve([])
962
+ );
963
+ if (this.active !== "primary" || !this.migrateFallbackOnEmpty || memberships.length > 0) return memberships;
964
+ const fallbackMemberships = await fallbackGetMemberships();
965
+ for (const membership of fallbackMemberships) await this.setCollectionMembership?.(membership);
966
+ return fallbackMemberships;
967
+ };
968
+ this.setCollectionMembership = (membership) => this.executeWrite((adapter) => adapter.setCollectionMembership?.(membership) ?? Promise.resolve());
969
+ this.removeCollectionMembership = (collectionId, itemId, scope) => this.executeWrite(
970
+ (adapter) => adapter.removeCollectionMembership?.(collectionId, itemId, scope) ?? Promise.resolve()
971
+ );
972
+ }
823
973
  }
824
974
  get isUsingFallback() {
825
975
  return this.active === "fallback";
@@ -947,6 +1097,9 @@ function createStorageAdapter(options) {
947
1097
  const getCollections = options.getCollections;
948
1098
  const setCollection = options.setCollection;
949
1099
  const removeCollection = options.removeCollection;
1100
+ const getCollectionMemberships = options.getCollectionMemberships;
1101
+ const setCollectionMembership = options.setCollectionMembership;
1102
+ const removeCollectionMembership = options.removeCollectionMembership;
950
1103
  return {
951
1104
  getAll: async () => options.getAll(),
952
1105
  ...getCollections && setCollection && removeCollection ? {
@@ -954,6 +1107,11 @@ function createStorageAdapter(options) {
954
1107
  setCollection: async (collection) => setCollection(collection),
955
1108
  removeCollection: async (id, scope) => removeCollection(id, scope)
956
1109
  } : {},
1110
+ ...getCollectionMemberships && setCollectionMembership && removeCollectionMembership ? {
1111
+ getCollectionMemberships: async () => getCollectionMemberships(),
1112
+ setCollectionMembership: async (membership) => setCollectionMembership(membership),
1113
+ removeCollectionMembership: async (collectionId, itemId, scope) => removeCollectionMembership(collectionId, itemId, scope)
1114
+ } : {},
957
1115
  set: async (item) => options.set(item),
958
1116
  ...setMany ? { setMany: async (items) => setMany(items) } : {},
959
1117
  remove: async (id) => options.remove(id),
@@ -1040,6 +1198,47 @@ var LocalStorageAdapter = class {
1040
1198
  current.filter((entry) => entry.id !== id || !isSameKeepScope(entry.scope, scope)),
1041
1199
  "remove"
1042
1200
  );
1201
+ const memberships = await this.getCollectionMemberships();
1202
+ await this.writeMemberships(
1203
+ memberships.filter((membership) => membership.collectionId !== id || !isSameKeepScope(membership.scope, scope)),
1204
+ "remove"
1205
+ );
1206
+ }
1207
+ async getCollectionMemberships() {
1208
+ if (!this.storage) return [];
1209
+ const storageKey = `${this.storageKey}:memberships`;
1210
+ let raw;
1211
+ try {
1212
+ raw = this.storage.getItem(storageKey);
1213
+ } catch (cause) {
1214
+ throw new KeepStorageAccessError({ operation: "getAll", storageKey, cause });
1215
+ }
1216
+ if (!raw) return [];
1217
+ try {
1218
+ const value = JSON.parse(raw);
1219
+ if (!Array.isArray(value) || !value.every(isKeepCollectionMembership)) {
1220
+ throw new KeepStorageParseError({ operation: "getAll", storageKey });
1221
+ }
1222
+ return value;
1223
+ } catch (cause) {
1224
+ if (cause instanceof KeepStorageParseError) throw cause;
1225
+ throw new KeepStorageParseError({ operation: "getAll", storageKey, cause });
1226
+ }
1227
+ }
1228
+ async setCollectionMembership(membership) {
1229
+ if (!isKeepCollectionMembership(membership)) throw new Error("Collection membership is invalid.");
1230
+ const current = await this.getCollectionMemberships();
1231
+ const sameMembership = (entry) => entry.collectionId === membership.collectionId && entry.itemId === membership.itemId && isSameKeepScope(entry.scope, membership.scope);
1232
+ await this.writeMemberships([...current.filter((entry) => !sameMembership(entry)), membership], "set");
1233
+ }
1234
+ async removeCollectionMembership(collectionId, itemId, scope) {
1235
+ const current = await this.getCollectionMemberships();
1236
+ await this.writeMemberships(
1237
+ current.filter(
1238
+ (entry) => entry.collectionId !== collectionId || entry.itemId !== itemId || !isSameKeepScope(entry.scope, scope)
1239
+ ),
1240
+ "remove"
1241
+ );
1043
1242
  }
1044
1243
  async set(item) {
1045
1244
  await this.setMany([item]);
@@ -1081,7 +1280,8 @@ var LocalStorageAdapter = class {
1081
1280
  subscribe(listener) {
1082
1281
  if (typeof window === "undefined") return () => void 0;
1083
1282
  const handleStorage = (event) => {
1084
- if (event.key !== null && event.key !== this.storageKey && event.key !== `${this.storageKey}:collections`) return;
1283
+ if (event.key !== null && event.key !== this.storageKey && event.key !== `${this.storageKey}:collections` && event.key !== `${this.storageKey}:memberships`)
1284
+ return;
1085
1285
  listener();
1086
1286
  };
1087
1287
  window.addEventListener("storage", handleStorage);
@@ -1116,6 +1316,16 @@ var LocalStorageAdapter = class {
1116
1316
  throw new KeepStorageAccessError({ operation, storageKey, cause });
1117
1317
  }
1118
1318
  }
1319
+ async writeMemberships(memberships, operation) {
1320
+ if (!this.storage) return;
1321
+ const storageKey = `${this.storageKey}:memberships`;
1322
+ try {
1323
+ this.storage.setItem(storageKey, JSON.stringify(memberships));
1324
+ } catch (cause) {
1325
+ if (isQuotaExceededError(cause)) throw new KeepStorageQuotaError({ operation, storageKey, cause });
1326
+ throw new KeepStorageAccessError({ operation, storageKey, cause });
1327
+ }
1328
+ }
1119
1329
  };
1120
1330
  var IndexedDBAdapter = class {
1121
1331
  constructor(options = {}) {
@@ -1165,6 +1375,38 @@ var IndexedDBAdapter = class {
1165
1375
  }
1166
1376
  async removeCollection(id, scope) {
1167
1377
  await this.writeCollection("remove", (store) => store.delete(collectionKey(id, scope)));
1378
+ const memberships = await this.getCollectionMemberships();
1379
+ for (const membership of memberships) {
1380
+ if (membership.collectionId === id && isSameKeepScope(membership.scope, scope)) {
1381
+ await this.removeCollectionMembership(id, membership.itemId, scope);
1382
+ }
1383
+ }
1384
+ }
1385
+ async getCollectionMemberships() {
1386
+ const database = await this.openCollections("getAll");
1387
+ if (!database) return [];
1388
+ const storageKey = `${this.storageKey}:memberships`;
1389
+ try {
1390
+ const transaction = database.transaction("memberships", "readonly");
1391
+ const value = await requestToPromise2(transaction.objectStore("memberships").getAll());
1392
+ if (!Array.isArray(value) || !value.every((entry) => isRecord(entry) && typeof entry.key === "string" && isKeepCollectionMembership(entry))) {
1393
+ throw new KeepStorageParseError({ operation: "getAll", storageKey });
1394
+ }
1395
+ return value.map(({ key: _key, ...membership }) => membership);
1396
+ } catch (cause) {
1397
+ if (cause instanceof KeepStorageParseError) throw cause;
1398
+ throw new KeepStorageAccessError({ operation: "getAll", storageKey, cause });
1399
+ }
1400
+ }
1401
+ async setCollectionMembership(membership) {
1402
+ if (!isKeepCollectionMembership(membership)) throw new Error("Collection membership is invalid.");
1403
+ await this.writeCollectionMembership(
1404
+ "set",
1405
+ (store) => store.put({ ...membership, key: membershipKey(membership.collectionId, membership.itemId, membership.scope) })
1406
+ );
1407
+ }
1408
+ async removeCollectionMembership(collectionId, itemId, scope) {
1409
+ await this.writeCollectionMembership("remove", (store) => store.delete(membershipKey(collectionId, itemId, scope)));
1168
1410
  }
1169
1411
  async set(item) {
1170
1412
  return this.setMany([item]);
@@ -1249,6 +1491,20 @@ var IndexedDBAdapter = class {
1249
1491
  throw new KeepStorageAccessError({ operation, storageKey, cause });
1250
1492
  }
1251
1493
  }
1494
+ async writeCollectionMembership(operation, write) {
1495
+ const database = await this.openCollections(operation);
1496
+ if (!database) return;
1497
+ const storageKey = `${this.storageKey}:memberships`;
1498
+ try {
1499
+ const transaction = database.transaction("memberships", "readwrite");
1500
+ write(transaction.objectStore("memberships"));
1501
+ await transactionToPromise2(transaction);
1502
+ this.notifySubscribers();
1503
+ } catch (cause) {
1504
+ if (isQuotaExceededError(cause)) throw new KeepStorageQuotaError({ operation, storageKey, cause });
1505
+ throw new KeepStorageAccessError({ operation, storageKey, cause });
1506
+ }
1507
+ }
1252
1508
  openCollections(operation) {
1253
1509
  if (!this.indexedDB) return Promise.resolve(void 0);
1254
1510
  const storageKey = `${this.storageKey}:collections`;
@@ -1256,7 +1512,7 @@ var IndexedDBAdapter = class {
1256
1512
  this.collectionDatabasePromise = new Promise((resolve, reject) => {
1257
1513
  let request;
1258
1514
  try {
1259
- request = this.indexedDB?.open(storageKey, 1);
1515
+ request = this.indexedDB?.open(storageKey, 2);
1260
1516
  } catch (cause) {
1261
1517
  reject(cause);
1262
1518
  return;
@@ -1265,6 +1521,9 @@ var IndexedDBAdapter = class {
1265
1521
  if (!request.result.objectStoreNames.contains("collections")) {
1266
1522
  request.result.createObjectStore("collections", { keyPath: "key" });
1267
1523
  }
1524
+ if (!request.result.objectStoreNames.contains("memberships")) {
1525
+ request.result.createObjectStore("memberships", { keyPath: "key" });
1526
+ }
1268
1527
  };
1269
1528
  request.onsuccess = () => resolve(request.result);
1270
1529
  request.onerror = () => reject(request.error);
@@ -1307,6 +1566,9 @@ var IndexedDBAdapter = class {
1307
1566
  function collectionKey(id, scope) {
1308
1567
  return JSON.stringify([scope?.tenantId ?? null, scope?.userId ?? null, id]);
1309
1568
  }
1569
+ function membershipKey(collectionId, itemId, scope) {
1570
+ return JSON.stringify([scope?.tenantId ?? null, scope?.userId ?? null, collectionId, itemId]);
1571
+ }
1310
1572
  function getBrowserStorage2() {
1311
1573
  if (typeof window === "undefined") return void 0;
1312
1574
  try {
@@ -1352,6 +1614,8 @@ export {
1352
1614
  removeKeepItems,
1353
1615
  mergeKeepItemLists,
1354
1616
  isKeepItem,
1617
+ isKeepCollectionDefinition,
1618
+ isKeepCollectionMembership,
1355
1619
  isRecord,
1356
1620
  getKeepScopeKey,
1357
1621
  isSameKeepScope,
@@ -1374,4 +1638,4 @@ export {
1374
1638
  LocalStorageAdapter,
1375
1639
  IndexedDBAdapter
1376
1640
  };
1377
- //# sourceMappingURL=chunk-2TENUU7B.js.map
1641
+ //# sourceMappingURL=chunk-NZLAW4LY.js.map