Files
FamReynaBrain/projects/colanode-hermes-bridge/src/state.ts
T
2026-09-14 22:38:47 -04:00

54 lines
1.6 KiB
TypeScript

import { mkdir, open, readFile, writeFile } from 'node:fs/promises';
import { dirname } from 'node:path';
export type BridgeState = {
cursors: Record<string, string>;
processedMessages: Record<string, { repliedNodeId: string; at: string }>;
};
const EMPTY_STATE: BridgeState = { cursors: {}, processedMessages: {} };
export class StateStore {
private state: BridgeState = structuredClone(EMPTY_STATE);
constructor(private readonly path: string) {}
async load(): Promise<void> {
await mkdir(dirname(this.path), { recursive: true, mode: 0o700 });
try {
const text = await readFile(this.path, 'utf8');
this.state = { ...structuredClone(EMPTY_STATE), ...JSON.parse(text) };
} catch (error) {
if ((error as NodeJS.ErrnoException).code !== 'ENOENT') throw error;
await this.save();
}
}
getCursor(key: string): string {
return this.state.cursors[key] ?? '0';
}
async setCursor(key: string, cursor: string): Promise<void> {
this.state.cursors[key] = cursor;
await this.save();
}
hasProcessed(messageId: string): boolean {
return Boolean(this.state.processedMessages[messageId]);
}
async markProcessed(messageId: string, repliedNodeId: string): Promise<void> {
this.state.processedMessages[messageId] = { repliedNodeId, at: new Date().toISOString() };
await this.save();
}
private async save(): Promise<void> {
const handle = await open(this.path, 'w', 0o600);
try {
await handle.writeFile(`${JSON.stringify(this.state, null, 2)}\n`, 'utf8');
await handle.chmod(0o600);
} finally {
await handle.close();
}
}
}