src/orbit-store.ts
- type Listener<T> = (state: Readonly<T>) => void;
- interface Patch<T> {
- name: string;
- apply: (draft: T) => void;
- }
- export class OrbitStore<T extends object> {
- private state: T;
- private history: Patch<T>[] = [];
- private listeners = new Set<Listener<T>>();
- constructor(initial: T) {
- this.state = structuredClone(initial);
- }
- read() {
- return Object.freeze(structuredClone(this.state));
- }
- commit(name: string, apply: Patch<T>["apply"]) {
- const draft = structuredClone(this.state);
- apply(draft);
- this.state = draft;
- this.history.push({ name, apply });
- this.emit();
- }
- subscribe(listener: Listener<T>) {
- this.listeners.add(listener); return () => this.listeners.delete(listener);
- }
- private emit() { this.listeners.forEach(l => l(this.read())); }
- }