From f520a9840613ae10d1b0733cbff60a0bc00524ba Mon Sep 17 00:00:00 2001 From: Joshua Horton Date: Mon, 18 Aug 2025 22:59:55 +0700 Subject: [PATCH 1/9] change(web): simplify unit tests, per code review Co-authored-by: Marc Durdin --- .../common/web-utils/src/tests/rewindableCache.tests.js | 6 ------ 1 file changed, 6 deletions(-) diff --git a/web/src/engine/common/web-utils/src/tests/rewindableCache.tests.js b/web/src/engine/common/web-utils/src/tests/rewindableCache.tests.js index 30ba5614d4..de7ea97c71 100644 --- a/web/src/engine/common/web-utils/src/tests/rewindableCache.tests.js +++ b/web/src/engine/common/web-utils/src/tests/rewindableCache.tests.js @@ -62,9 +62,6 @@ describe("RewindableCache", () => { cache.add(4, 'd'); cache.add(5, 'e'); - assert.sameMembers([...cache.keys()], [4, 5]); - assert.sameMembers([...cache.keys().map((k) => cache.peek(k))], ['d', 'e']); - assert.sameOrderedMembers([...cache.keys()], [5, 4]); assert.sameOrderedMembers([...cache.keys().map((k) => cache.peek(k))], ['e', 'd']); assert.equal(cache.size, 2); @@ -81,9 +78,6 @@ describe("RewindableCache", () => { cache.get(2); cache.rewindTo(3); - assert.sameMembers([...cache.keys()], [1, 3]); - assert.sameMembers([...cache.keys().map((k) => cache.peek(k))], ['a', 'c']); - assert.sameOrderedMembers([...cache.keys()], [3, 1]); assert.sameOrderedMembers([...cache.keys().map((k) => cache.peek(k))], ['c', 'a']); assert.equal(cache.size, 2); From 222fa814acbfda14b19ebc83b459d25237a300f6 Mon Sep 17 00:00:00 2001 From: Joshua Horton Date: Mon, 18 Aug 2025 23:11:45 +0700 Subject: [PATCH 2/9] change(web): apply suggestion from code-review Co-authored-by: Marc Durdin --- web/src/engine/common/web-utils/src/rewindable-cache.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/src/engine/common/web-utils/src/rewindable-cache.ts b/web/src/engine/common/web-utils/src/rewindable-cache.ts index 43290b07c2..32fd796dd3 100644 --- a/web/src/engine/common/web-utils/src/rewindable-cache.ts +++ b/web/src/engine/common/web-utils/src/rewindable-cache.ts @@ -89,7 +89,7 @@ export class RewindableCache { } } - this.transitionMap.set(key, value); + map.set(key, value); } /** From 3e9e638f9d28c8694a8e0f70ab2489ebca8a44c0 Mon Sep 17 00:00:00 2001 From: Joshua Horton Date: Mon, 18 Aug 2025 12:00:23 -0500 Subject: [PATCH 3/9] change(web): adjusts unit tests per review --- .../common/web-utils/src/rewindable-cache.ts | 2 +- .../src/tests/rewindableCache.tests.js | 17 ++++++++--------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/web/src/engine/common/web-utils/src/rewindable-cache.ts b/web/src/engine/common/web-utils/src/rewindable-cache.ts index 32fd796dd3..d7023c3617 100644 --- a/web/src/engine/common/web-utils/src/rewindable-cache.ts +++ b/web/src/engine/common/web-utils/src/rewindable-cache.ts @@ -57,7 +57,7 @@ export class RewindableCache { get(key: Key): Value { const set = this.cacheOrderSet; if(!set.has(key)) { - return null; + return undefined; } set.delete(key); diff --git a/web/src/engine/common/web-utils/src/tests/rewindableCache.tests.js b/web/src/engine/common/web-utils/src/tests/rewindableCache.tests.js index de7ea97c71..4524149ea5 100644 --- a/web/src/engine/common/web-utils/src/tests/rewindableCache.tests.js +++ b/web/src/engine/common/web-utils/src/tests/rewindableCache.tests.js @@ -87,11 +87,10 @@ describe("RewindableCache", () => { const cache = new RewindableCache(2); cache.add(1, 'a'); cache.add(2, 'b'); - cache.add(3, 'c'); - cache.add(4, 'd'); - cache.add(5, 'e'); + cache.add(3, 'c'); // Entry 1 no longer valid + cache.add(4, 'd'); // 2 + cache.add(5, 'e'); // 3 - assert.doesNotThrow(() => cache.get(2)); assert.throws(() => cache.rewindTo(3)); }); @@ -99,11 +98,11 @@ describe("RewindableCache", () => { const cache = new RewindableCache(2); cache.add(1, 'a'); cache.add(2, 'b'); - cache.add(3, 'c'); - cache.add(4, 'd'); - cache.add(5, 'e'); + cache.add(3, 'c'); // Entry 1 no longer valid + cache.add(4, 'd'); // 2 + cache.add(5, 'e'); // 3 - assert.doesNotThrow(() => cache.peek(2)); - assert.doesNotThrow(() => cache.get(2)); + assert.isUndefined(cache.peek(2), 'outdated cache entry should be forgotten'); + assert.isUndefined(cache.get(2), 'outdated cache entry should be forgotten'); }); }); \ No newline at end of file From 4d66ff671d7d889da1d70617bbff04fff8823392 Mon Sep 17 00:00:00 2001 From: Joshua Horton Date: Mon, 18 Aug 2025 12:05:39 -0500 Subject: [PATCH 4/9] change(web): drop redundant ordering-set (per review) Co-authored-by: Marc Durdin --- .../common/web-utils/src/rewindable-cache.ts | 50 ++++++++----------- 1 file changed, 22 insertions(+), 28 deletions(-) diff --git a/web/src/engine/common/web-utils/src/rewindable-cache.ts b/web/src/engine/common/web-utils/src/rewindable-cache.ts index d7023c3617..9e930d20ae 100644 --- a/web/src/engine/common/web-utils/src/rewindable-cache.ts +++ b/web/src/engine/common/web-utils/src/rewindable-cache.ts @@ -17,9 +17,7 @@ export class RewindableCache { static readonly DEFAULT_MAX_SIZE = 5; - private cacheOrderSet: Set = new Set(); - private transitionMap: Map = new Map(); - + private map: Map = new Map(); private maxSize: number; /** @@ -34,7 +32,7 @@ export class RewindableCache { * Gets the current number of entries in the cache. */ get size() { - return this.cacheOrderSet.size; + return this.map.size; } /** @@ -44,7 +42,7 @@ export class RewindableCache { * @returns */ peek(key: Key): Value { - const entry = this.transitionMap.get(key); + const entry = this.map.get(key); return entry; } @@ -55,13 +53,14 @@ export class RewindableCache { * @returns */ get(key: Key): Value { - const set = this.cacheOrderSet; - if(!set.has(key)) { + const map = this.map; + const entry = map.get(key); + if(!map.has(key)) { return undefined; } - set.delete(key); - set.add(key); + map.delete(key); + map.set(key, entry); return this.peek(key); } @@ -73,23 +72,20 @@ export class RewindableCache { * @returns */ add(key: Key, value: Value) { - const set = this.cacheOrderSet; - const map = this.transitionMap; + const map = this.map; - if(set.has(key)) { - set.delete(key); - set.add(key); + if(map.has(key)) { + map.delete(key); + map.set(key, value); } else { - set.add(key); + map.set(key, value); - if(set.size > this.maxSize) { - const oldest = set.keys().next().value as Key; - set.delete(oldest); + if(map.size > this.maxSize) { + const oldest = map.keys().next().value as Key; + map.delete(oldest); map.delete(oldest); } } - - map.set(key, value); } /** @@ -100,15 +96,14 @@ export class RewindableCache { * @returns */ keys(): Key[] { - return [...this.cacheOrderSet.keys()].reverse(); + return [...this.map.keys()].reverse(); } /** * Deletes all entries from the cache. */ clear() { - this.cacheOrderSet = new Set(); - this.transitionMap = new Map(); + this.map = new Map(); } /** @@ -117,17 +112,16 @@ export class RewindableCache { * @param key */ rewindTo(key: Key) { - const set = this.cacheOrderSet; - const map = this.transitionMap; + const map = this.map; - if(!set.has(key)) { + if(!map.has(key)) { throw new Error("Key not found; cannot clear entries appearing afterward."); } let keyFound: boolean = false; // Iteration: by insertion order // The most recent entries will appear after the specified key. - for(const k of set.keys()) { + for(const k of map.keys()) { if(!keyFound) { keyFound = k == key; continue; @@ -135,7 +129,7 @@ export class RewindableCache { // It is safe to delete a key from a Set while iterating over it in ES6+. // https://stackoverflow.com/a/28306768 - set.delete(k); + map.delete(k); map.delete(k); } } From d6d44c4d1dcfac2d9b75cf3be6752df0fbb68979 Mon Sep 17 00:00:00 2001 From: Joshua Horton Date: Mon, 18 Aug 2025 13:50:49 -0500 Subject: [PATCH 5/9] change(web): remove .get, force key type to number, base rewind on key value --- .../common/web-utils/src/rewindable-cache.ts | 49 +++++-------------- .../src/tests/rewindableCache.tests.js | 12 ++--- .../main/src/headless/inputProcessor.ts | 2 +- .../main/src/headless/languageProcessor.ts | 2 +- .../main/src/headless/transcriptionCache.ts | 4 +- .../src/main/correction/context-tracker.ts | 8 +-- .../src/main/model-compositor.ts | 2 +- 7 files changed, 28 insertions(+), 51 deletions(-) diff --git a/web/src/engine/common/web-utils/src/rewindable-cache.ts b/web/src/engine/common/web-utils/src/rewindable-cache.ts index 9e930d20ae..edba06256c 100644 --- a/web/src/engine/common/web-utils/src/rewindable-cache.ts +++ b/web/src/engine/common/web-utils/src/rewindable-cache.ts @@ -14,10 +14,10 @@ * reaching a specified capacity and that provides the ability to * forget _all_ entries more recent than a specified entry. */ -export class RewindableCache { +export class RewindableCache { static readonly DEFAULT_MAX_SIZE = 5; - private map: Map = new Map(); + private map: Map = new Map(); private maxSize: number; /** @@ -41,37 +41,18 @@ export class RewindableCache { * @param key * @returns */ - peek(key: Key): Value { + get(key: number): Value { const entry = this.map.get(key); return entry; } - /** - * Fetches the cache entry with the specified key and also updates its - * most recent access time. - * @param key - * @returns - */ - get(key: Key): Value { - const map = this.map; - const entry = map.get(key); - if(!map.has(key)) { - return undefined; - } - - map.delete(key); - map.set(key, entry); - - return this.peek(key); - } - /** * Adds the specified key-value pair as a cache entry, overwriting any * previous value for the specified key. * @param key * @returns */ - add(key: Key, value: Value) { + add(key: number, value: Value) { const map = this.map; if(map.has(key)) { @@ -81,7 +62,7 @@ export class RewindableCache { map.set(key, value); if(map.size > this.maxSize) { - const oldest = map.keys().next().value as Key; + const oldest = map.keys().next().value as number; map.delete(oldest); map.delete(oldest); } @@ -95,7 +76,7 @@ export class RewindableCache { * Note: returns an Array and is accordingly O(N). * @returns */ - keys(): Key[] { + keys(): number[] { return [...this.map.keys()].reverse(); } @@ -107,30 +88,26 @@ export class RewindableCache { } /** - * Deletes all entries more recent than the specified key, leaving + * Deletes all entries with a key less than the specified key, leaving * the specified key as the most recent entry. * @param key */ - rewindTo(key: Key) { + rewindTo(key: number) { const map = this.map; if(!map.has(key)) { throw new Error("Key not found; cannot clear entries appearing afterward."); } - let keyFound: boolean = false; // Iteration: by insertion order // The most recent entries will appear after the specified key. for(const k of map.keys()) { - if(!keyFound) { - keyFound = k == key; - continue; + if(k > key) { + // It is safe to delete a key from a Set or Map while iterating over it in ES6+. + // https://stackoverflow.com/a/28306768 + map.delete(k); + map.delete(k); } - - // It is safe to delete a key from a Set while iterating over it in ES6+. - // https://stackoverflow.com/a/28306768 - map.delete(k); - map.delete(k); } } } \ No newline at end of file diff --git a/web/src/engine/common/web-utils/src/tests/rewindableCache.tests.js b/web/src/engine/common/web-utils/src/tests/rewindableCache.tests.js index 4524149ea5..f0093347ef 100644 --- a/web/src/engine/common/web-utils/src/tests/rewindableCache.tests.js +++ b/web/src/engine/common/web-utils/src/tests/rewindableCache.tests.js @@ -63,7 +63,7 @@ describe("RewindableCache", () => { cache.add(5, 'e'); assert.sameOrderedMembers([...cache.keys()], [5, 4]); - assert.sameOrderedMembers([...cache.keys().map((k) => cache.peek(k))], ['e', 'd']); + assert.sameOrderedMembers([...cache.keys().map((k) => cache.get(k))], ['e', 'd']); assert.equal(cache.size, 2); }); @@ -75,12 +75,13 @@ describe("RewindableCache", () => { cache.add(4, 'd'); cache.add(5, 'e'); - cache.get(2); + // make it more recently-accessed, but don't remove it. cache.rewindTo(3); - assert.sameOrderedMembers([...cache.keys()], [3, 1]); - assert.sameOrderedMembers([...cache.keys().map((k) => cache.peek(k))], ['c', 'a']); - assert.equal(cache.size, 2); + cache.add(2, 'b'); // 2 is still ORIGINALLY older than 3, even if accessed more recently. + assert.sameOrderedMembers([...cache.keys()], [2, 3, 1]); + assert.sameOrderedMembers([...cache.keys().map((k) => cache.get(k))], ['b', 'c', 'a']); + assert.equal(cache.size, 3); }); it("forgets no entries if invalid key is provided", () => { @@ -102,7 +103,6 @@ describe("RewindableCache", () => { cache.add(4, 'd'); // 2 cache.add(5, 'e'); // 3 - assert.isUndefined(cache.peek(2), 'outdated cache entry should be forgotten'); assert.isUndefined(cache.get(2), 'outdated cache entry should be forgotten'); }); }); \ No newline at end of file diff --git a/web/src/engine/main/src/headless/inputProcessor.ts b/web/src/engine/main/src/headless/inputProcessor.ts index 891eec0b3c..e3c204ab17 100644 --- a/web/src/engine/main/src/headless/inputProcessor.ts +++ b/web/src/engine/main/src/headless/inputProcessor.ts @@ -103,7 +103,7 @@ export class InputProcessor { // Support for multitap context reversion; multitap keys should act as if they were // the first thing typed since `preInput`, the state before the original base key. if(keyEvent.baseTranscriptionToken) { - const transcription = this.contextCache.peek(keyEvent.baseTranscriptionToken); + const transcription = this.contextCache.get(keyEvent.baseTranscriptionToken); if(transcription) { this.contextCache.rewindTo(keyEvent.baseTranscriptionToken); // Has there been a context change at any point during the multitap? If so, we need diff --git a/web/src/engine/main/src/headless/languageProcessor.ts b/web/src/engine/main/src/headless/languageProcessor.ts index e81e523284..f4486a5145 100644 --- a/web/src/engine/main/src/headless/languageProcessor.ts +++ b/web/src/engine/main/src/headless/languageProcessor.ts @@ -377,7 +377,7 @@ export class LanguageProcessor extends EventEmitter { * @returns The matching `Transcription`, or `null` none is found. */ public getPredictionState(id: number): Transcription { - return this.recentTranscriptions.peek(id); + return this.recentTranscriptions.get(id); } public shutdown() { diff --git a/web/src/engine/main/src/headless/transcriptionCache.ts b/web/src/engine/main/src/headless/transcriptionCache.ts index 3ac7810a11..f1cc20a73f 100644 --- a/web/src/engine/main/src/headless/transcriptionCache.ts +++ b/web/src/engine/main/src/headless/transcriptionCache.ts @@ -3,7 +3,7 @@ import { RewindableCache } from "@keymanapp/web-utils"; const TRANSCRIPTION_BUFFER_SIZE = 10; -export class TranscriptionCache extends RewindableCache { +export class TranscriptionCache extends RewindableCache { constructor() { super(TRANSCRIPTION_BUFFER_SIZE); } @@ -17,7 +17,7 @@ export class TranscriptionCache extends RewindableCache { const entries = [...this.keys()].map((key) => { return { key: key, - entry: this.peek(key) + entry: this.get(key) } }); diff --git a/web/src/engine/predictive-text/worker-thread/src/main/correction/context-tracker.ts b/web/src/engine/predictive-text/worker-thread/src/main/correction/context-tracker.ts index e4d3f4f319..457ef0a570 100644 --- a/web/src/engine/predictive-text/worker-thread/src/main/correction/context-tracker.ts +++ b/web/src/engine/predictive-text/worker-thread/src/main/correction/context-tracker.ts @@ -15,7 +15,7 @@ import { ContextState } from './context-state.js'; import { ContextTransition } from './context-transition.js'; export class ContextTracker { - readonly cache = new RewindableCache(5); + readonly cache = new RewindableCache(5); // Aim: relocate to ContextTransition in some form? // Or can we split it up in some manner across the different types? @@ -275,7 +275,7 @@ export class ContextTracker { if(tokenizedPostContext.left.length > 0) { for(const id of this.cache.keys()) { - const priorMatchState = this.cache.peek(id); + const priorMatchState = this.cache.get(id); // Skip intermediate multitap-produced contexts. // When multitapping, we skip all contexts from prior taps within the same interaction, @@ -303,7 +303,7 @@ export class ContextTracker { if(transitionId !== undefined) { if(priorMatchState.transitionId != transitionId) { // Already has a taggedContext. - this.cache.get(transformDistribution.find((entry) => entry.sample.id !== undefined).sample.id); + this.cache.add(priorMatchState.transitionId, priorMatchState); } this.cache.add(transitionId, result); } @@ -332,7 +332,7 @@ export class ContextTracker { if(key === undefined) { return undefined; } else { - return this.cache.peek(key); + return this.cache.get(key); } } diff --git a/web/src/engine/predictive-text/worker-thread/src/main/model-compositor.ts b/web/src/engine/predictive-text/worker-thread/src/main/model-compositor.ts index 048d839371..108fa08396 100644 --- a/web/src/engine/predictive-text/worker-thread/src/main/model-compositor.ts +++ b/web/src/engine/predictive-text/worker-thread/src/main/model-compositor.ts @@ -293,7 +293,7 @@ export class ModelCompositor { } // When the context is tracked, we prefer the tracked information. - let contextMatchFound = this.contextTracker.cache.peek(-reversion.transformId); + let contextMatchFound = this.contextTracker.cache.get(-reversion.transformId); if(!contextMatchFound) { return fallbackSuggestions(); From e3c498303168c7a7822d70c7ded0cca77f35f61a Mon Sep 17 00:00:00 2001 From: Joshua Horton Date: Mon, 18 Aug 2025 13:51:00 -0500 Subject: [PATCH 6/9] fix(web): temporarily disable unit test --- .../worker-thread/worker-model-compositor.tests.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/src/test/auto/headless/engine/predictive-text/worker-thread/worker-model-compositor.tests.ts b/web/src/test/auto/headless/engine/predictive-text/worker-thread/worker-model-compositor.tests.ts index 8f289a72b6..11ee5bb586 100644 --- a/web/src/test/auto/headless/engine/predictive-text/worker-thread/worker-model-compositor.tests.ts +++ b/web/src/test/auto/headless/engine/predictive-text/worker-thread/worker-model-compositor.tests.ts @@ -824,7 +824,7 @@ describe('ModelCompositor', function() { }); }); - it('model with traversals: returns appropriate suggestions upon reversion', async function() { + it.skip('model with traversals: returns appropriate suggestions upon reversion', async function() { // This setup matches 'acceptSuggestion' the test case // it('first word of context + postTransform provided, .deleteLeft > 0') // seen earlier in the file. From 6dd1ff39a2beb7485020968552f6bb21f347ee97 Mon Sep 17 00:00:00 2001 From: Joshua Horton Date: Mon, 18 Aug 2025 14:03:47 -0500 Subject: [PATCH 7/9] fix(web): restore temp-disabled unit test --- .../worker-thread/worker-model-compositor.tests.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/web/src/test/auto/headless/engine/predictive-text/worker-thread/worker-model-compositor.tests.ts b/web/src/test/auto/headless/engine/predictive-text/worker-thread/worker-model-compositor.tests.ts index 048c6e5579..43d8c8db2b 100644 --- a/web/src/test/auto/headless/engine/predictive-text/worker-thread/worker-model-compositor.tests.ts +++ b/web/src/test/auto/headless/engine/predictive-text/worker-thread/worker-model-compositor.tests.ts @@ -826,7 +826,7 @@ describe('ModelCompositor', function() { }); }); - it.skip('model with traversals: returns appropriate suggestions upon reversion', async function() { + it('model with traversals: returns appropriate suggestions upon reversion', async function() { // This setup matches 'acceptSuggestion' the test case // it('first word of context + postTransform provided, .deleteLeft > 0') // seen earlier in the file. @@ -894,7 +894,7 @@ describe('ModelCompositor', function() { assert.equal(compositor.contextTracker.cache.size, 2); let contextIds = compositor.contextTracker.cache.keys(); - let transitionInstances = compositor.contextTracker.cache.keys().map((key) => compositor.contextTracker.cache.peek(key)); + let transitionInstances = compositor.contextTracker.cache.keys().map((key) => compositor.contextTracker.cache.get(key)); let baseSuggestion = initialSuggestions[1]; let reversion = compositor.acceptSuggestion(baseSuggestion, baseContext, postTransform); @@ -907,7 +907,7 @@ describe('ModelCompositor', function() { // Accepting the suggestion rewrites the latest context transition. assert.equal(compositor.contextTracker.cache.size, 2); assert.sameMembers(compositor.contextTracker.cache.keys(), contextIds); - assert.notSameDeepMembers(compositor.contextTracker.cache.keys().map((key) => compositor.contextTracker.cache.peek(key)), transitionInstances); + assert.notSameDeepMembers(compositor.contextTracker.cache.keys().map((key) => compositor.contextTracker.cache.get(key)), transitionInstances); // The replacement should be marked on the context-tracking token for the applied version of the results. assert.equal(suggestionContextState.final.appliedSuggestionId, undefined); @@ -915,7 +915,7 @@ describe('ModelCompositor', function() { let appliedContext = models.applyTransform(baseSuggestion.transform, baseContext); await compositor.applyReversion(reversion, appliedContext); - assert.isUndefined(compositor.contextTracker.cache.peek(13).final.appliedSuggestionId); + assert.isUndefined(compositor.contextTracker.cache.get(13).final.appliedSuggestionId); }); }); }); From 109f216c7bd8403f3078ed59af8164cfc675532b Mon Sep 17 00:00:00 2001 From: Joshua Horton Date: Tue, 19 Aug 2025 08:17:10 -0500 Subject: [PATCH 8/9] change(web): adjustments per PR review Removes duplicate line, fixes doc-comment. --- web/src/engine/common/web-utils/src/rewindable-cache.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/web/src/engine/common/web-utils/src/rewindable-cache.ts b/web/src/engine/common/web-utils/src/rewindable-cache.ts index edba06256c..eb439cde1a 100644 --- a/web/src/engine/common/web-utils/src/rewindable-cache.ts +++ b/web/src/engine/common/web-utils/src/rewindable-cache.ts @@ -88,8 +88,9 @@ export class RewindableCache { } /** - * Deletes all entries with a key less than the specified key, leaving - * the specified key as the most recent entry. + * Deletes all entries with a key greater than the specified key (which indicates + * the entry was first created more recently), leaving the specified key as + * the most recent entry. * @param key */ rewindTo(key: number) { @@ -106,7 +107,6 @@ export class RewindableCache { // It is safe to delete a key from a Set or Map while iterating over it in ES6+. // https://stackoverflow.com/a/28306768 map.delete(k); - map.delete(k); } } } From 5b379a82f4aa9d93f343bbc50d2410337a75e380 Mon Sep 17 00:00:00 2001 From: Joshua Horton Date: Tue, 19 Aug 2025 10:52:48 -0500 Subject: [PATCH 9/9] chore(web): remove extra duplicated line --- web/src/engine/common/web-utils/src/rewindable-cache.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/web/src/engine/common/web-utils/src/rewindable-cache.ts b/web/src/engine/common/web-utils/src/rewindable-cache.ts index eb439cde1a..c334e7f9d2 100644 --- a/web/src/engine/common/web-utils/src/rewindable-cache.ts +++ b/web/src/engine/common/web-utils/src/rewindable-cache.ts @@ -64,7 +64,6 @@ export class RewindableCache { if(map.size > this.maxSize) { const oldest = map.keys().next().value as number; map.delete(oldest); - map.delete(oldest); } } }