e(`v1-${this.source}\t${timestamp}`); } } /** * Retrieve the stored history entries for a certain source, sorted by * timestamp descending. * * @returns {Array} a list of objects */ async list() { const rkv = await this.#init(); const entries = []; // The "from" and "to" key parameters to nsIKeyValueStore.enumerate() // are inclusive and exclusive, respectively, and keys are tuples // of source and datetime joined by a tab (\t), which is character code 9; // so enumerating ["source", "source\n"), where the line feed (\n) // is character code 10, enumerates all pairs with the given source. for (const { value } of await rkv.enumerate( `v1-${this.source}`, `v1-${this.source}\n` )) { try { const stored = JSON.parse(value); entries.push({ ...stored, datetime: new Date(stored.timestamp) }); } catch (e) { // Ignore malformed entries. console.error(e); } } // Sort entries by `timestamp` descending. entries.sort((a, b) => (a.timestamp > b.timestamp ? -1 : 1)); return entries; } /** * Return the most recent entry. */ async last() { // List is sorted from newer to older. return (await this.list())[0]; } /** * Wipe out the **whole** store. */ async clear() { const rkv = await this.#init(); await rkv.clear(); } /** * Initialize the rkv store in the user profile. * * @returns {object} the underlying `KeyValueService` instance. */ async #init() { if (!this.#store) { // Get and cache a handle to the kvstore. const dir = PathUtils.join(PathUtils.profileDir, "settings"); await IOUtils.makeDirectory(dir); this.#store = await lazy.KeyValueService.getOrCreate(dir, "synchistory"); } return this.#store; } } PK