@abraca/dabra 2.0.7 → 2.0.8
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.
|
@@ -2294,6 +2294,7 @@ var AbracadabraBaseProvider = class extends EventEmitter {
|
|
|
2294
2294
|
this.isSynced = false;
|
|
2295
2295
|
this.unsyncedChanges = 0;
|
|
2296
2296
|
this.isAuthenticated = false;
|
|
2297
|
+
this._hasEverAuthenticated = false;
|
|
2297
2298
|
this.authorizedScope = void 0;
|
|
2298
2299
|
this.manageSocket = false;
|
|
2299
2300
|
this._isAttached = false;
|
|
@@ -2504,6 +2505,7 @@ var AbracadabraBaseProvider = class extends EventEmitter {
|
|
|
2504
2505
|
onClose() {
|
|
2505
2506
|
this.isAuthenticated = false;
|
|
2506
2507
|
this.synced = false;
|
|
2508
|
+
this._hasEverAuthenticated = false;
|
|
2507
2509
|
if (this.awareness) removeAwarenessStates(this.awareness, Array.from(this.awareness.getStates().keys()).filter((client) => client !== this.document.clientID), this);
|
|
2508
2510
|
}
|
|
2509
2511
|
destroy() {
|
|
@@ -2560,12 +2562,13 @@ var AbracadabraBaseProvider = class extends EventEmitter {
|
|
|
2560
2562
|
permissionDeniedHandler(reason) {
|
|
2561
2563
|
this.emit("authenticationFailed", { reason });
|
|
2562
2564
|
this.isAuthenticated = false;
|
|
2563
|
-
if (this.manageSocket) try {
|
|
2565
|
+
if (this.manageSocket && !this._hasEverAuthenticated) try {
|
|
2564
2566
|
this.configuration.websocketProvider.disconnect();
|
|
2565
2567
|
} catch {}
|
|
2566
2568
|
}
|
|
2567
2569
|
authenticatedHandler(scope) {
|
|
2568
2570
|
this.isAuthenticated = true;
|
|
2571
|
+
this._hasEverAuthenticated = true;
|
|
2569
2572
|
this.authorizedScope = scope;
|
|
2570
2573
|
this.emit("authenticated", { scope });
|
|
2571
2574
|
}
|
|
@@ -2803,7 +2806,7 @@ function isValidDocId(id) {
|
|
|
2803
2806
|
*/
|
|
2804
2807
|
var AbracadabraProvider = class AbracadabraProvider extends AbracadabraBaseProvider {
|
|
2805
2808
|
static {
|
|
2806
|
-
this.DEFAULT_MAX_CHILDREN =
|
|
2809
|
+
this.DEFAULT_MAX_CHILDREN = 64;
|
|
2807
2810
|
}
|
|
2808
2811
|
constructor(configuration) {
|
|
2809
2812
|
const resolved = { ...configuration };
|
|
@@ -2819,6 +2822,7 @@ var AbracadabraProvider = class AbracadabraProvider extends AbracadabraBaseProvi
|
|
|
2819
2822
|
this.pendingLoads = /* @__PURE__ */ new Map();
|
|
2820
2823
|
this.childAccessTimes = /* @__PURE__ */ new Map();
|
|
2821
2824
|
this.pinnedChildren = /* @__PURE__ */ new Set();
|
|
2825
|
+
this.transientChildren = /* @__PURE__ */ new Set();
|
|
2822
2826
|
this.boundHandleYSubdocsChange = this.handleYSubdocsChange.bind(this);
|
|
2823
2827
|
this.hasCachedContent = false;
|
|
2824
2828
|
this._client = client;
|
|
@@ -3016,22 +3020,34 @@ var AbracadabraProvider = class AbracadabraProvider extends AbracadabraBaseProvi
|
|
|
3016
3020
|
}
|
|
3017
3021
|
/**
|
|
3018
3022
|
* Create (or return cached) a child AbracadabraProvider for a given
|
|
3019
|
-
* child document id. Each child
|
|
3020
|
-
*
|
|
3023
|
+
* child document id. Each child shares the parent's WebSocket via
|
|
3024
|
+
* multiplexing.
|
|
3025
|
+
*
|
|
3026
|
+
* `evictable` (default `true`) controls whether the child enters the
|
|
3027
|
+
* LRU pool. Pass `evictable: false` for transient loads — typically
|
|
3028
|
+
* batch indexers (search, file extraction) that touch every doc in
|
|
3029
|
+
* the tree and would otherwise blow out the cache, silently evicting
|
|
3030
|
+
* subdocs the UI is actively using. Transient children are excluded
|
|
3031
|
+
* from the LRU budget AND don't trigger eviction of other children.
|
|
3032
|
+
* Callers MUST pair `loadChild(id, { evictable: false })` with an
|
|
3033
|
+
* explicit `unloadChild(id)` once they're done.
|
|
3021
3034
|
*/
|
|
3022
|
-
loadChild(childId) {
|
|
3035
|
+
loadChild(childId, options = {}) {
|
|
3023
3036
|
if (!isValidDocId(childId)) return Promise.reject(/* @__PURE__ */ new Error(`loadChild: "${childId}" is not a valid document ID (must be a UUID). If this node was created with an older version of the app, delete it and recreate it.`));
|
|
3037
|
+
if (childId === this.configuration.name) return Promise.resolve(this);
|
|
3038
|
+
const evictable = options.evictable !== false;
|
|
3024
3039
|
if (this.childProviders.has(childId)) {
|
|
3025
3040
|
this.childAccessTimes.set(childId, Date.now());
|
|
3041
|
+
if (evictable) this.transientChildren.delete(childId);
|
|
3026
3042
|
return Promise.resolve(this.childProviders.get(childId));
|
|
3027
3043
|
}
|
|
3028
3044
|
if (this.pendingLoads.has(childId)) return this.pendingLoads.get(childId);
|
|
3029
|
-
const load = this._doLoadChild(childId);
|
|
3045
|
+
const load = this._doLoadChild(childId, evictable);
|
|
3030
3046
|
this.pendingLoads.set(childId, load);
|
|
3031
3047
|
load.finally(() => this.pendingLoads.delete(childId));
|
|
3032
3048
|
return load;
|
|
3033
3049
|
}
|
|
3034
|
-
async _doLoadChild(childId) {
|
|
3050
|
+
async _doLoadChild(childId, evictable) {
|
|
3035
3051
|
const childDoc = new yjs.Doc({ guid: childId });
|
|
3036
3052
|
this.registerSubdoc(childDoc);
|
|
3037
3053
|
const childProvider = new AbracadabraProvider({
|
|
@@ -3050,7 +3066,8 @@ var AbracadabraProvider = class AbracadabraProvider extends AbracadabraBaseProvi
|
|
|
3050
3066
|
childProvider.attach();
|
|
3051
3067
|
this.childProviders.set(childId, childProvider);
|
|
3052
3068
|
this.childAccessTimes.set(childId, Date.now());
|
|
3053
|
-
this.
|
|
3069
|
+
if (!evictable) this.transientChildren.add(childId);
|
|
3070
|
+
if (evictable) this.evictLRU();
|
|
3054
3071
|
this.emit("subdocLoaded", {
|
|
3055
3072
|
childId,
|
|
3056
3073
|
provider: childProvider
|
|
@@ -3064,6 +3081,7 @@ var AbracadabraProvider = class AbracadabraProvider extends AbracadabraBaseProvi
|
|
|
3064
3081
|
this.childProviders.delete(childId);
|
|
3065
3082
|
this.childAccessTimes.delete(childId);
|
|
3066
3083
|
this.pinnedChildren.delete(childId);
|
|
3084
|
+
this.transientChildren.delete(childId);
|
|
3067
3085
|
}
|
|
3068
3086
|
}
|
|
3069
3087
|
/**
|
|
@@ -3081,21 +3099,27 @@ var AbracadabraProvider = class AbracadabraProvider extends AbracadabraBaseProvi
|
|
|
3081
3099
|
this.evictLRU();
|
|
3082
3100
|
}
|
|
3083
3101
|
/**
|
|
3084
|
-
* Evict least-recently-used unpinned child providers
|
|
3085
|
-
* at or below MAX_CHILDREN.
|
|
3102
|
+
* Evict least-recently-used unpinned, non-transient child providers
|
|
3103
|
+
* until the cache is at or below MAX_CHILDREN. Transient children
|
|
3104
|
+
* (loaded with `{ evictable: false }`) are excluded from both the
|
|
3105
|
+
* budget *and* the eviction list — they're invisible to the LRU and
|
|
3106
|
+
* only go away when their loader explicitly calls `unloadChild`.
|
|
3086
3107
|
*/
|
|
3087
3108
|
evictLRU() {
|
|
3088
|
-
|
|
3109
|
+
let nonTransientCount = 0;
|
|
3110
|
+
for (const id of this.childProviders.keys()) if (!this.transientChildren.has(id)) nonTransientCount++;
|
|
3111
|
+
if (nonTransientCount <= this.maxChildren) return;
|
|
3089
3112
|
const evictable = [];
|
|
3090
3113
|
for (const [id] of this.childProviders) {
|
|
3091
3114
|
if (this.pinnedChildren.has(id)) continue;
|
|
3115
|
+
if (this.transientChildren.has(id)) continue;
|
|
3092
3116
|
evictable.push({
|
|
3093
3117
|
id,
|
|
3094
3118
|
accessTime: this.childAccessTimes.get(id) ?? 0
|
|
3095
3119
|
});
|
|
3096
3120
|
}
|
|
3097
3121
|
evictable.sort((a, b) => a.accessTime - b.accessTime);
|
|
3098
|
-
let toEvict =
|
|
3122
|
+
let toEvict = nonTransientCount - this.maxChildren;
|
|
3099
3123
|
for (const entry of evictable) {
|
|
3100
3124
|
if (toEvict <= 0) break;
|
|
3101
3125
|
this.unloadChild(entry.id);
|