100 lines
2.3 KiB
TypeScript
100 lines
2.3 KiB
TypeScript
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<string, string | number | boolean> = {};
|
|
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<T = StoreValue>(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]();
|
|
}
|
|
}
|