@geolonia/geonicdb-sdk 0.12.0 → 0.14.0
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/README.md +60 -1
- package/geonicdb.cjs +302 -2
- package/geonicdb.cjs.map +3 -3
- package/geonicdb.iife.js +302 -2
- package/geonicdb.iife.js.map +3 -3
- package/geonicdb.mjs +302 -2
- package/geonicdb.mjs.map +3 -3
- package/ngsi-v2/index.cjs +3 -0
- package/ngsi-v2/index.cjs.map +2 -2
- package/ngsi-v2/index.d.ts +6 -0
- package/ngsi-v2/index.mjs +3 -0
- package/ngsi-v2/index.mjs.map +2 -2
- package/package.json +1 -1
package/geonicdb.mjs
CHANGED
|
@@ -51,6 +51,9 @@ var SDK_POLL_INTERVAL_MS_DEFAULT = 5e3;
|
|
|
51
51
|
var DPOP_IDB_NAME = "geonicdb-sdk";
|
|
52
52
|
var DPOP_IDB_STORE = "dpop-sessions";
|
|
53
53
|
var DPOP_IDB_VERSION = 1;
|
|
54
|
+
var SDK_CACHE_IDB_NAME = "geonicdb-sdk-cache";
|
|
55
|
+
var SDK_CACHE_IDB_STORE = "responses";
|
|
56
|
+
var SDK_CACHE_IDB_VERSION = 1;
|
|
54
57
|
|
|
55
58
|
// src/sdk/dpop.ts
|
|
56
59
|
var dpopSupported = typeof crypto !== "undefined" && !!crypto.subtle && !!crypto.subtle.generateKey;
|
|
@@ -330,11 +333,97 @@ var SdkCache = class {
|
|
|
330
333
|
constructor(maxEntries = SDK_CACHE_MAX_ENTRIES_DEFAULT) {
|
|
331
334
|
__publicField(this, "_store", /* @__PURE__ */ new Map());
|
|
332
335
|
__publicField(this, "_maxEntries");
|
|
336
|
+
/**
|
|
337
|
+
* Optional persistent backing store (IndexedDB) so cached validators survive
|
|
338
|
+
* a page reload (#1262). `null` in non-browser runtimes — the cache then
|
|
339
|
+
* behaves as a pure in-memory LRU.
|
|
340
|
+
*/
|
|
341
|
+
__publicField(this, "_persistence", null);
|
|
342
|
+
/**
|
|
343
|
+
* Auth-scope namespace for persisted entries. The auth layer sets this to a
|
|
344
|
+
* tenant + authenticated-principal identifier so that entries written by one
|
|
345
|
+
* principal are never read back by another sharing the same origin/tenant
|
|
346
|
+
* (different tabs / SDK instances each scope to their own principal).
|
|
347
|
+
*/
|
|
348
|
+
__publicField(this, "_scope", "");
|
|
349
|
+
/**
|
|
350
|
+
* Whether write-through persistence is currently active. Driven by the auth
|
|
351
|
+
* layer: enabled only for remembered sessions, so persisted entries belong to
|
|
352
|
+
* exactly one principal and are dropped on every credential change.
|
|
353
|
+
*/
|
|
354
|
+
__publicField(this, "_persistEnabled", false);
|
|
355
|
+
/**
|
|
356
|
+
* Serialises persistence writes so they complete in call order (#1262
|
|
357
|
+
* review). `set`/`delete`/`clearPersisted` are otherwise independent
|
|
358
|
+
* fire-and-forget ops; if a late `put()` resolved after a `remove()` /
|
|
359
|
+
* `clearScope()`, an evicted/deleted/logged-out entry could reappear in
|
|
360
|
+
* IndexedDB. Chaining them keeps the persisted store consistent with the
|
|
361
|
+
* in-memory state and with the auth-boundary flush.
|
|
362
|
+
*/
|
|
363
|
+
__publicField(this, "_persistQueue", Promise.resolve());
|
|
333
364
|
if (!Number.isInteger(maxEntries) || maxEntries <= 0) {
|
|
334
365
|
throw new Error(`SdkCache maxEntries must be a positive integer, got ${String(maxEntries)}`);
|
|
335
366
|
}
|
|
336
367
|
this._maxEntries = maxEntries;
|
|
337
368
|
}
|
|
369
|
+
/** Wire a persistence backend (called once at construction when available). */
|
|
370
|
+
attachPersistence(persistence) {
|
|
371
|
+
this._persistence = persistence;
|
|
372
|
+
}
|
|
373
|
+
/** Whether a persistence backend is attached. */
|
|
374
|
+
hasPersistence() {
|
|
375
|
+
return this._persistence !== null;
|
|
376
|
+
}
|
|
377
|
+
/** Set the auth-scope namespace used for persisted reads/writes. */
|
|
378
|
+
setScope(scope) {
|
|
379
|
+
this._scope = scope;
|
|
380
|
+
}
|
|
381
|
+
/** Enable or disable write-through persistence (driven by `rememberSession`). */
|
|
382
|
+
setPersistEnabled(enabled) {
|
|
383
|
+
this._persistEnabled = enabled && this._persistence !== null;
|
|
384
|
+
}
|
|
385
|
+
/** True when set/delete should propagate to the persistent store. */
|
|
386
|
+
get _persisting() {
|
|
387
|
+
return this._persistEnabled && this._persistence !== null;
|
|
388
|
+
}
|
|
389
|
+
/**
|
|
390
|
+
* Append a persistence operation to the serialised queue. The backend and
|
|
391
|
+
* scope are captured at enqueue time so a later scope change cannot retarget
|
|
392
|
+
* an already-queued op. A failing op is swallowed (persistence is
|
|
393
|
+
* best-effort) and does not stall the chain. Returns the tail so callers that
|
|
394
|
+
* need ordering (`clearPersisted`) can await it.
|
|
395
|
+
*/
|
|
396
|
+
_enqueuePersist(op) {
|
|
397
|
+
const persistence = this._persistence;
|
|
398
|
+
if (!persistence) return this._persistQueue;
|
|
399
|
+
const scope = this._scope;
|
|
400
|
+
this._persistQueue = this._persistQueue.catch(() => void 0).then(() => op(persistence, scope)).catch(() => void 0);
|
|
401
|
+
return this._persistQueue;
|
|
402
|
+
}
|
|
403
|
+
/**
|
|
404
|
+
* Load persisted entries for the current scope into memory, oldest first so
|
|
405
|
+
* the in-memory LRU recency order is preserved. Best-effort and idempotent —
|
|
406
|
+
* a no-op when no backend is attached. Called after a remembered session is
|
|
407
|
+
* restored so the very first request after a reload can send `If-None-Match`.
|
|
408
|
+
*/
|
|
409
|
+
async hydrate() {
|
|
410
|
+
if (!this._persistence) return;
|
|
411
|
+
const entries = await this._persistence.loadScope(this._scope, this._maxEntries);
|
|
412
|
+
for (const { key, entry } of entries) {
|
|
413
|
+
if (this._store.has(key)) this._store.delete(key);
|
|
414
|
+
this._store.set(key, entry);
|
|
415
|
+
}
|
|
416
|
+
while (this._store.size > this._maxEntries) {
|
|
417
|
+
const oldest = this._store.keys().next().value;
|
|
418
|
+
if (oldest === void 0) break;
|
|
419
|
+
this._store.delete(oldest);
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
/** Drop every persisted entry for the current scope (auth change / flush). */
|
|
423
|
+
async clearPersisted() {
|
|
424
|
+
if (!this._persistence) return;
|
|
425
|
+
await this._enqueuePersist((persistence, scope) => persistence.clearScope(scope));
|
|
426
|
+
}
|
|
338
427
|
/** Build a stable cache key. Method is upper-cased so casing differences do not produce duplicate entries. */
|
|
339
428
|
static keyFor(method, path) {
|
|
340
429
|
return `${method.toUpperCase()}:${path}`;
|
|
@@ -353,15 +442,27 @@ var SdkCache = class {
|
|
|
353
442
|
this._store.delete(key);
|
|
354
443
|
}
|
|
355
444
|
this._store.set(key, entry);
|
|
445
|
+
const evicted = [];
|
|
356
446
|
while (this._store.size > this._maxEntries) {
|
|
357
447
|
const oldest = this._store.keys().next().value;
|
|
358
448
|
if (oldest === void 0) break;
|
|
359
449
|
this._store.delete(oldest);
|
|
450
|
+
evicted.push(oldest);
|
|
451
|
+
}
|
|
452
|
+
if (this._persisting) {
|
|
453
|
+
void this._enqueuePersist(async (persistence, scope) => {
|
|
454
|
+
await persistence.put(scope, key, entry);
|
|
455
|
+
if (evicted.length > 0) await persistence.remove(scope, evicted);
|
|
456
|
+
});
|
|
360
457
|
}
|
|
361
458
|
}
|
|
362
459
|
/** Delete a specific entry. Returns whether anything was removed. */
|
|
363
460
|
delete(key) {
|
|
364
|
-
|
|
461
|
+
const removed = this._store.delete(key);
|
|
462
|
+
if (removed && this._persisting) {
|
|
463
|
+
void this._enqueuePersist((persistence, scope) => persistence.remove(scope, [key]));
|
|
464
|
+
}
|
|
465
|
+
return removed;
|
|
365
466
|
}
|
|
366
467
|
/**
|
|
367
468
|
* Delete every entry whose key matches a predicate. Returns the array of
|
|
@@ -499,6 +600,49 @@ var _AuthManager = class _AuthManager {
|
|
|
499
600
|
/** Wire an SdkCache instance (called by GeonicDB constructor when caching is enabled). */
|
|
500
601
|
setCache(cache) {
|
|
501
602
|
this._cache = cache;
|
|
603
|
+
cache?.setScope(this._cacheScope());
|
|
604
|
+
}
|
|
605
|
+
/**
|
|
606
|
+
* #1262: persistence scope for the SDK cache — tenant + authenticated
|
|
607
|
+
* principal (email when available). Keying on the principal, not just the
|
|
608
|
+
* tenant, prevents a different subject sharing the same origin/tenant (another
|
|
609
|
+
* tab, another SDK instance, a later login) from reading entries written by a
|
|
610
|
+
* previous principal. The principal segment is empty for sessions without a
|
|
611
|
+
* known email; such sessions never persist (persistence is gated on a
|
|
612
|
+
* remembered DPoP session that always carries an email), so the empty segment
|
|
613
|
+
* is not reachable as a write scope in practice.
|
|
614
|
+
*/
|
|
615
|
+
_cacheScope() {
|
|
616
|
+
return `${this._tenant}${this._email ?? ""}`;
|
|
617
|
+
}
|
|
618
|
+
/**
|
|
619
|
+
* #1262: enable write-through persistence for the SDK cache so it survives a
|
|
620
|
+
* reload. Always re-scopes to the current tenant + principal first.
|
|
621
|
+
*
|
|
622
|
+
* `clearFirst` drops any persisted entries left by a previous session of the
|
|
623
|
+
* same principal — used on a fresh `login()`. It is `false` on
|
|
624
|
+
* `restoreSession()`, where the persisted entries belong to the very session
|
|
625
|
+
* being restored and are about to be rehydrated.
|
|
626
|
+
*/
|
|
627
|
+
async _enablePersistentCache(clearFirst) {
|
|
628
|
+
if (!this._cache) return;
|
|
629
|
+
this._cache.setScope(this._cacheScope());
|
|
630
|
+
if (clearFirst) await this._cache.clearPersisted();
|
|
631
|
+
this._cache.setPersistEnabled(true);
|
|
632
|
+
}
|
|
633
|
+
/**
|
|
634
|
+
* #1262: disable write-through persistence and drop the persisted cache for
|
|
635
|
+
* the current principal. Called on credential changes that do not persist a
|
|
636
|
+
* session (`setCredentials()`, non-remembered `login()`, `logout()`),
|
|
637
|
+
* mirroring the in-memory invalidation so a stale body can never outlive its
|
|
638
|
+
* principal. Callers that null out `_email` must invoke this **before** doing
|
|
639
|
+
* so, otherwise the scope no longer resolves to the principal being dropped.
|
|
640
|
+
*/
|
|
641
|
+
_disablePersistentCache() {
|
|
642
|
+
if (!this._cache) return;
|
|
643
|
+
this._cache.setScope(this._cacheScope());
|
|
644
|
+
this._cache.setPersistEnabled(false);
|
|
645
|
+
void this._cache.clearPersisted();
|
|
502
646
|
}
|
|
503
647
|
/** Provide the cache event emitter (forwarded to the GeonicDB EventEmitter). */
|
|
504
648
|
setCacheEventEmitter(emitter) {
|
|
@@ -553,6 +697,7 @@ var _AuthManager = class _AuthManager {
|
|
|
553
697
|
this._email = email;
|
|
554
698
|
this._rememberSession = wantsRemember;
|
|
555
699
|
this._invalidateAuthScopedState();
|
|
700
|
+
this._cache?.setPersistEnabled(false);
|
|
556
701
|
if (!wantsRemember && this._tenant) {
|
|
557
702
|
void clearDPoPSession(this._tenant);
|
|
558
703
|
}
|
|
@@ -562,6 +707,9 @@ var _AuthManager = class _AuthManager {
|
|
|
562
707
|
const bound = await this._bindDpopSession();
|
|
563
708
|
if (this._rememberSession) {
|
|
564
709
|
await this._persistDpopSession();
|
|
710
|
+
await this._enablePersistentCache(true);
|
|
711
|
+
} else {
|
|
712
|
+
this._disablePersistentCache();
|
|
565
713
|
}
|
|
566
714
|
return bound;
|
|
567
715
|
} catch (err) {
|
|
@@ -570,12 +718,18 @@ var _AuthManager = class _AuthManager {
|
|
|
570
718
|
this._tokenType = "Bearer";
|
|
571
719
|
this._refreshToken = null;
|
|
572
720
|
this._tokenPromise = null;
|
|
721
|
+
this._invalidateAuthScopedState();
|
|
722
|
+
this._disablePersistentCache();
|
|
573
723
|
this._rememberSession = false;
|
|
574
724
|
this._email = null;
|
|
575
|
-
this._invalidateAuthScopedState();
|
|
576
725
|
throw err;
|
|
577
726
|
}
|
|
578
727
|
}
|
|
728
|
+
this._rememberSession = false;
|
|
729
|
+
if (this._tenant) {
|
|
730
|
+
void clearDPoPSession(this._tenant);
|
|
731
|
+
}
|
|
732
|
+
this._disablePersistentCache();
|
|
579
733
|
return data;
|
|
580
734
|
}
|
|
581
735
|
/**
|
|
@@ -660,6 +814,12 @@ var _AuthManager = class _AuthManager {
|
|
|
660
814
|
this._refreshToken = opts.refreshToken || null;
|
|
661
815
|
this._tokenPromise = null;
|
|
662
816
|
this._invalidateAuthScopedState();
|
|
817
|
+
this._disablePersistentCache();
|
|
818
|
+
this._rememberSession = false;
|
|
819
|
+
this._email = null;
|
|
820
|
+
if (this._tenant) {
|
|
821
|
+
void clearDPoPSession(this._tenant);
|
|
822
|
+
}
|
|
663
823
|
}
|
|
664
824
|
/** Clear all credentials. */
|
|
665
825
|
logout() {
|
|
@@ -667,6 +827,7 @@ var _AuthManager = class _AuthManager {
|
|
|
667
827
|
this._tokenExpiry = 0;
|
|
668
828
|
this._refreshToken = null;
|
|
669
829
|
this._tokenPromise = null;
|
|
830
|
+
this._disablePersistentCache();
|
|
670
831
|
this._email = null;
|
|
671
832
|
if (this._tenant) {
|
|
672
833
|
void clearDPoPSession(this._tenant);
|
|
@@ -712,6 +873,8 @@ var _AuthManager = class _AuthManager {
|
|
|
712
873
|
this._email = persisted.email ?? null;
|
|
713
874
|
this._tokenPromise = null;
|
|
714
875
|
this._invalidateAuthScopedState();
|
|
876
|
+
await this._enablePersistentCache(false);
|
|
877
|
+
await this._cache?.hydrate();
|
|
715
878
|
return true;
|
|
716
879
|
}
|
|
717
880
|
/**
|
|
@@ -1334,6 +1497,140 @@ var WebSocketManager = class {
|
|
|
1334
1497
|
}
|
|
1335
1498
|
};
|
|
1336
1499
|
|
|
1500
|
+
// src/sdk/cache-persistence.ts
|
|
1501
|
+
var cachePersistenceSupported = typeof globalThis.indexedDB !== "undefined" && typeof structuredClone !== "undefined";
|
|
1502
|
+
var SCOPE_SEP = "\0";
|
|
1503
|
+
var SCOPE_RANGE_END = "\uFFFF";
|
|
1504
|
+
function openCacheDB() {
|
|
1505
|
+
return new Promise((resolve, reject) => {
|
|
1506
|
+
const req = globalThis.indexedDB.open(
|
|
1507
|
+
SDK_CACHE_IDB_NAME,
|
|
1508
|
+
SDK_CACHE_IDB_VERSION
|
|
1509
|
+
);
|
|
1510
|
+
req.onupgradeneeded = () => {
|
|
1511
|
+
const db = req.result;
|
|
1512
|
+
if (!db.objectStoreNames.contains(SDK_CACHE_IDB_STORE)) {
|
|
1513
|
+
db.createObjectStore(SDK_CACHE_IDB_STORE, { keyPath: "id" });
|
|
1514
|
+
}
|
|
1515
|
+
};
|
|
1516
|
+
req.onsuccess = () => {
|
|
1517
|
+
resolve(req.result);
|
|
1518
|
+
};
|
|
1519
|
+
req.onerror = () => {
|
|
1520
|
+
reject(req.error ?? new Error("IndexedDB open failed"));
|
|
1521
|
+
};
|
|
1522
|
+
req.onblocked = () => {
|
|
1523
|
+
reject(req.error ?? new Error("IndexedDB open blocked"));
|
|
1524
|
+
};
|
|
1525
|
+
});
|
|
1526
|
+
}
|
|
1527
|
+
function recordId(scope, key) {
|
|
1528
|
+
return scope + SCOPE_SEP + key;
|
|
1529
|
+
}
|
|
1530
|
+
var IdbCachePersistence = class {
|
|
1531
|
+
async loadScope(scope, limit) {
|
|
1532
|
+
let db = null;
|
|
1533
|
+
try {
|
|
1534
|
+
db = await openCacheDB();
|
|
1535
|
+
const records = await new Promise((resolve, reject) => {
|
|
1536
|
+
const tx = db.transaction(SDK_CACHE_IDB_STORE, "readonly");
|
|
1537
|
+
const range = globalThis.IDBKeyRange.bound(
|
|
1538
|
+
scope + SCOPE_SEP,
|
|
1539
|
+
scope + SCOPE_SEP + SCOPE_RANGE_END
|
|
1540
|
+
);
|
|
1541
|
+
const req = tx.objectStore(SDK_CACHE_IDB_STORE).getAll(range);
|
|
1542
|
+
req.onsuccess = () => {
|
|
1543
|
+
resolve(req.result ?? []);
|
|
1544
|
+
};
|
|
1545
|
+
req.onerror = () => {
|
|
1546
|
+
reject(req.error ?? new Error("IndexedDB getAll failed"));
|
|
1547
|
+
};
|
|
1548
|
+
});
|
|
1549
|
+
return records.filter((r) => r && r.scope === scope && typeof r.key === "string" && r.entry).sort((a, b) => (a.entry.cachedAt ?? 0) - (b.entry.cachedAt ?? 0)).slice(-limit).map((r) => ({ key: r.key, entry: r.entry }));
|
|
1550
|
+
} catch {
|
|
1551
|
+
return [];
|
|
1552
|
+
} finally {
|
|
1553
|
+
db?.close();
|
|
1554
|
+
}
|
|
1555
|
+
}
|
|
1556
|
+
async put(scope, key, entry) {
|
|
1557
|
+
let db = null;
|
|
1558
|
+
try {
|
|
1559
|
+
db = await openCacheDB();
|
|
1560
|
+
await new Promise((resolve, reject) => {
|
|
1561
|
+
const tx = db.transaction(SDK_CACHE_IDB_STORE, "readwrite");
|
|
1562
|
+
const record = { id: recordId(scope, key), scope, key, entry };
|
|
1563
|
+
tx.objectStore(SDK_CACHE_IDB_STORE).put(record);
|
|
1564
|
+
tx.oncomplete = () => {
|
|
1565
|
+
resolve();
|
|
1566
|
+
};
|
|
1567
|
+
tx.onerror = () => {
|
|
1568
|
+
reject(tx.error ?? new Error("IndexedDB put failed"));
|
|
1569
|
+
};
|
|
1570
|
+
tx.onabort = () => {
|
|
1571
|
+
reject(tx.error ?? new Error("IndexedDB transaction aborted"));
|
|
1572
|
+
};
|
|
1573
|
+
});
|
|
1574
|
+
} catch {
|
|
1575
|
+
} finally {
|
|
1576
|
+
db?.close();
|
|
1577
|
+
}
|
|
1578
|
+
}
|
|
1579
|
+
async remove(scope, keys) {
|
|
1580
|
+
if (keys.length === 0) return;
|
|
1581
|
+
let db = null;
|
|
1582
|
+
try {
|
|
1583
|
+
db = await openCacheDB();
|
|
1584
|
+
await new Promise((resolve, reject) => {
|
|
1585
|
+
const tx = db.transaction(SDK_CACHE_IDB_STORE, "readwrite");
|
|
1586
|
+
const store = tx.objectStore(SDK_CACHE_IDB_STORE);
|
|
1587
|
+
for (const key of keys) store.delete(recordId(scope, key));
|
|
1588
|
+
tx.oncomplete = () => {
|
|
1589
|
+
resolve();
|
|
1590
|
+
};
|
|
1591
|
+
tx.onerror = () => {
|
|
1592
|
+
reject(tx.error ?? new Error("IndexedDB delete failed"));
|
|
1593
|
+
};
|
|
1594
|
+
tx.onabort = () => {
|
|
1595
|
+
reject(tx.error ?? new Error("IndexedDB transaction aborted"));
|
|
1596
|
+
};
|
|
1597
|
+
});
|
|
1598
|
+
} catch {
|
|
1599
|
+
} finally {
|
|
1600
|
+
db?.close();
|
|
1601
|
+
}
|
|
1602
|
+
}
|
|
1603
|
+
async clearScope(scope) {
|
|
1604
|
+
let db = null;
|
|
1605
|
+
try {
|
|
1606
|
+
db = await openCacheDB();
|
|
1607
|
+
await new Promise((resolve, reject) => {
|
|
1608
|
+
const tx = db.transaction(SDK_CACHE_IDB_STORE, "readwrite");
|
|
1609
|
+
const range = globalThis.IDBKeyRange.bound(
|
|
1610
|
+
scope + SCOPE_SEP,
|
|
1611
|
+
scope + SCOPE_SEP + SCOPE_RANGE_END
|
|
1612
|
+
);
|
|
1613
|
+
tx.objectStore(SDK_CACHE_IDB_STORE).delete(range);
|
|
1614
|
+
tx.oncomplete = () => {
|
|
1615
|
+
resolve();
|
|
1616
|
+
};
|
|
1617
|
+
tx.onerror = () => {
|
|
1618
|
+
reject(tx.error ?? new Error("IndexedDB clear failed"));
|
|
1619
|
+
};
|
|
1620
|
+
tx.onabort = () => {
|
|
1621
|
+
reject(tx.error ?? new Error("IndexedDB transaction aborted"));
|
|
1622
|
+
};
|
|
1623
|
+
});
|
|
1624
|
+
} catch {
|
|
1625
|
+
} finally {
|
|
1626
|
+
db?.close();
|
|
1627
|
+
}
|
|
1628
|
+
}
|
|
1629
|
+
};
|
|
1630
|
+
function createCachePersistence() {
|
|
1631
|
+
return cachePersistenceSupported ? new IdbCachePersistence() : null;
|
|
1632
|
+
}
|
|
1633
|
+
|
|
1337
1634
|
// src/sdk/index.ts
|
|
1338
1635
|
var GeonicDB = class extends EventEmitter {
|
|
1339
1636
|
constructor(options) {
|
|
@@ -1363,6 +1660,8 @@ var GeonicDB = class extends EventEmitter {
|
|
|
1363
1660
|
};
|
|
1364
1661
|
if (opts.cache !== false) {
|
|
1365
1662
|
const cache = new SdkCache(opts.cacheMaxEntries ?? SDK_CACHE_MAX_ENTRIES_DEFAULT);
|
|
1663
|
+
const persistence = createCachePersistence();
|
|
1664
|
+
if (persistence) cache.attachPersistence(persistence);
|
|
1366
1665
|
this._auth.setCache(cache);
|
|
1367
1666
|
this._auth.setCacheEventEmitter((name, payload) => this.emit(name, payload));
|
|
1368
1667
|
}
|
|
@@ -1391,6 +1690,7 @@ var GeonicDB = class extends EventEmitter {
|
|
|
1391
1690
|
for (const key of removed) {
|
|
1392
1691
|
this._auth.emitCacheEvent("cacheInvalidated", { key, path: key.split(":").slice(1).join(":") });
|
|
1393
1692
|
}
|
|
1693
|
+
void cache.clearPersisted();
|
|
1394
1694
|
}
|
|
1395
1695
|
// --- Authentication ---
|
|
1396
1696
|
/**
|