// Copyright (c) 2025 Joseph Hale // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at https://mozilla.org/MPL/2.0/. import { debounce, type DebouncedFunc } from 'lodash'; export interface ExternalKeyValueStore { get: (key: string) => Promise; set: (key: string, value: string) => Promise; } export default class KeyValueStore { private external: ExternalKeyValueStore; private setters = new Map< string, DebouncedFunc<(value: string) => Promise> >(); constructor(external?: ExternalKeyValueStore) { this.external = external ?? new InMemoryKeyValueStore(); } async put(key: string, value: string): Promise { if (!this.setters.has(key)) { const setter = async (newVal: string) => await this.external.set(key, newVal); this.setters.set(key, debounce(setter, 1000, { trailing: true })); return setter(value); } else { return this.setters.get(key)!(value); } } async read(key: string, defaultValue: string = ''): Promise { const value = await this.external.get(key); return value ?? defaultValue; } } class InMemoryKeyValueStore implements ExternalKeyValueStore { private store = new Map(); async get(key: string): Promise { return this.store.get(key) ?? null; } async set(key: string, value: string): Promise { this.store.set(key, value); } }