import { ensureFileSync } from "@std/fs"; const REFRESH_EVENT = "bm:refresh-store"; type StoreValue = string | number | boolean; /** * A no-dep, lightweight, simple store for storing data in a JSON file. * usage: * ```ts * import { BearMetalStore } from "@bearmetal/store"; * * const store = new BearMetalStore(); * * store.set("key", "value"); * * console.log(store.get("key")); * * store.close(); * ``` * * It's recommended to use the `using` syntax to ensure the store is disposed * of when it's no longer needed. * ```ts * using store = new BearMetalStore(); * * store.set("key", "value"); * * console.log(store.get("key")); * ``` */ export class BearMetalStore { private store: Record = {}; private storePath: string; /** * @description The name of the event that is dispatched when the store is updated. */ public readonly EVENT_NAME: string; constructor(storePath?: string) { this.storePath = storePath || Deno.env.get("BEAR_METAL_STORE_PATH") || "./BearMetal/store.json"; ensureFileSync(this.storePath); this.EVENT_NAME = REFRESH_EVENT + this.storePath; this.readIn(); globalThis.addEventListener(this.EVENT_NAME, this.readIn); } /** * @param key * @returns The value stored at the key, or undefined if the key doesn't exist. */ public get(key: string): T { return this.store[key] as T; } /** * @description Sets the value of the key to the value. * @param key * @param value */ public set(key: string, value: StoreValue): void { this.store[key] = value; this.writeOut(); } /** * @description Deletes the key and its value. * @param key */ public delete(key: string): void { delete this.store[key]; this.writeOut(); } private readIn = () => { this.store = JSON.parse(Deno.readTextFileSync(this.storePath) || "{}"); }; private writeOut() { Deno.writeTextFileSync(this.storePath, JSON.stringify(this.store)); globalThis.dispatchEvent(new CustomEvent(this.EVENT_NAME)); } [Symbol.dispose]() { this.writeOut(); globalThis.removeEventListener(this.EVENT_NAME, this.readIn); } /** * @description Closes the store and disposes of the event listener. */ public close() { this[Symbol.dispose](); } }