@better-state/server 0.1.1 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,61 +2,66 @@ import { v4 as uuid } from "uuid";
2
2
  /**
3
3
  * Ensures a state row exists for the given namespace + key.
4
4
  * If it doesn't exist, creates one with the provided initial value.
5
- * Returns the state row.
6
5
  */
7
- export function ensureState(db, namespace, key, initialValue = null) {
8
- const existing = db
9
- .prepare("SELECT * FROM states WHERE namespace = ? AND key = ?")
10
- .get(namespace, key);
6
+ export async function ensureState(store, namespace, key, initialValue = null) {
7
+ const existing = await store.findState(namespace, key);
11
8
  if (existing)
12
9
  return existing;
13
10
  const now = Date.now();
14
11
  const serialized = JSON.stringify(initialValue);
15
12
  const id = uuid();
16
- db.prepare(`INSERT INTO states (id, namespace, key, initial, snapshot, version, created_at, updated_at)
17
- VALUES (?, ?, ?, ?, ?, 0, ?, ?)`).run(id, namespace, key, serialized, serialized, now, now);
18
- return db
19
- .prepare("SELECT * FROM states WHERE id = ?")
20
- .get(id);
13
+ await store.createState({
14
+ id,
15
+ namespace,
16
+ key,
17
+ initial: serialized,
18
+ snapshot: serialized,
19
+ version: 0,
20
+ created_at: now,
21
+ updated_at: now,
22
+ });
23
+ return (await store.findStateById(id));
21
24
  }
22
25
  /**
23
26
  * Processes a batch of mutations for a given state key.
24
27
  * Appends events to the log, replays to compute new snapshot,
25
28
  * persists the snapshot, and returns the new value + version.
26
29
  */
27
- export function processMutations(db, namespace, key, clientId, mutations) {
28
- const state = ensureState(db, namespace, key);
29
- const maxSeqRow = db
30
- .prepare("SELECT MAX(seq) as max_seq FROM event_log WHERE state_id = ?")
31
- .get(state.id);
32
- let seq = (maxSeqRow.max_seq ?? -1) + 1;
30
+ export async function processMutations(store, namespace, key, clientId, mutations) {
31
+ const state = await ensureState(store, namespace, key);
32
+ const maxSeq = await store.getMaxSeq(state.id);
33
+ let seq = (maxSeq ?? -1) + 1;
33
34
  const now = Date.now();
34
- const insertEvent = db.prepare(`INSERT INTO event_log (id, state_id, client_id, client_ts, server_ts, seq, mutation, meta, created_at)
35
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`);
36
35
  const mutationIds = [];
37
- const insertAll = db.transaction(() => {
38
- for (const mut of mutations) {
39
- const eventId = mut.id || uuid();
40
- const meta = mut.value !== undefined ? JSON.stringify({ fallbackValue: mut.value }) : null;
41
- insertEvent.run(eventId, state.id, clientId, mut.clientTs, now, seq, mut.fn, meta, now);
42
- mutationIds.push(eventId);
43
- seq++;
44
- }
36
+ const events = mutations.map((mut) => {
37
+ const eventId = mut.id || uuid();
38
+ mutationIds.push(eventId);
39
+ const meta = mut.value !== undefined
40
+ ? JSON.stringify({ fallbackValue: mut.value })
41
+ : null;
42
+ return {
43
+ id: eventId,
44
+ stateId: state.id,
45
+ clientId,
46
+ clientTs: mut.clientTs,
47
+ serverTs: now,
48
+ seq: seq++,
49
+ mutation: mut.fn,
50
+ meta,
51
+ };
45
52
  });
46
- insertAll();
47
- const newValue = replayState(db, state.id, state.initial);
53
+ await store.insertEvents(events);
54
+ const newValue = await replayState(store, state.id, state.initial);
48
55
  const newVersion = state.version + mutations.length;
49
- db.prepare("UPDATE states SET snapshot = ?, version = ?, updated_at = ? WHERE id = ?").run(JSON.stringify(newValue), newVersion, Date.now(), state.id);
56
+ await store.updateSnapshot(state.id, JSON.stringify(newValue), newVersion, Date.now());
50
57
  return { value: newValue, version: newVersion, mutationIds };
51
58
  }
52
59
  /**
53
60
  * Replays the full event log for a state to compute the current value.
54
61
  * This is the authoritative state computation.
55
62
  */
56
- export function replayState(db, stateId, initialJson) {
57
- const events = db
58
- .prepare("SELECT mutation, meta FROM event_log WHERE state_id = ? ORDER BY server_ts ASC, seq ASC")
59
- .all(stateId);
63
+ export async function replayState(store, stateId, initialJson) {
64
+ const events = await store.getEventsForReplay(stateId);
60
65
  let state = JSON.parse(initialJson);
61
66
  for (const event of events) {
62
67
  if (event.mutation === "__SET__") {
@@ -116,26 +121,7 @@ function applyMutation(state, mutationBody) {
116
121
  /**
117
122
  * Returns the event history for a state key (paginated).
118
123
  */
119
- export function getHistory(db, stateId, limit = 50, cursor) {
120
- let events;
121
- if (cursor) {
122
- events = db
123
- .prepare(`SELECT * FROM event_log
124
- WHERE state_id = ? AND (server_ts, seq) > (
125
- SELECT server_ts, seq FROM event_log WHERE id = ?
126
- )
127
- ORDER BY server_ts ASC, seq ASC
128
- LIMIT ?`)
129
- .all(stateId, cursor, limit + 1);
130
- }
131
- else {
132
- events = db
133
- .prepare("SELECT * FROM event_log WHERE state_id = ? ORDER BY server_ts ASC, seq ASC LIMIT ?")
134
- .all(stateId, limit + 1);
135
- }
136
- const hasMore = events.length > limit;
137
- if (hasMore)
138
- events.pop();
139
- return { events, hasMore };
124
+ export async function getHistory(store, stateId, limit = 50, cursor) {
125
+ return store.getEventHistory(stateId, limit, cursor);
140
126
  }
141
127
  //# sourceMappingURL=state-engine.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"state-engine.js","sourceRoot":"","sources":["../src/state-engine.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"state-engine.js","sourceRoot":"","sources":["../src/state-engine.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,IAAI,IAAI,EAAE,MAAM,MAAM,CAAC;AAYlC;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,KAAqB,EACrB,SAAiB,EACjB,GAAW,EACX,eAAwB,IAAI;IAE5B,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,SAAS,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;IACvD,IAAI,QAAQ;QAAE,OAAO,QAAQ,CAAC;IAE9B,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACvB,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC;IAChD,MAAM,EAAE,GAAG,IAAI,EAAE,CAAC;IAElB,MAAM,KAAK,CAAC,WAAW,CAAC;QACtB,EAAE;QACF,SAAS;QACT,GAAG;QACH,OAAO,EAAE,UAAU;QACnB,QAAQ,EAAE,UAAU;QACpB,OAAO,EAAE,CAAC;QACV,UAAU,EAAE,GAAG;QACf,UAAU,EAAE,GAAG;KAChB,CAAC,CAAC;IAEH,OAAO,CAAC,MAAM,KAAK,CAAC,aAAa,CAAC,EAAE,CAAC,CAAE,CAAC;AAC1C,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,KAAqB,EACrB,SAAiB,EACjB,GAAW,EACX,QAAgB,EAChB,SAA0B;IAE1B,MAAM,KAAK,GAAG,MAAM,WAAW,CAAC,KAAK,EAAE,SAAS,EAAE,GAAG,CAAC,CAAC;IAEvD,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IAC/C,IAAI,GAAG,GAAG,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IAE7B,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACvB,MAAM,WAAW,GAAa,EAAE,CAAC;IAEjC,MAAM,MAAM,GAAiB,SAAS,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE;QACjD,MAAM,OAAO,GAAG,GAAG,CAAC,EAAE,IAAI,IAAI,EAAE,CAAC;QACjC,WAAW,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAC1B,MAAM,IAAI,GACR,GAAG,CAAC,KAAK,KAAK,SAAS;YACrB,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,aAAa,EAAE,GAAG,CAAC,KAAK,EAAE,CAAC;YAC9C,CAAC,CAAC,IAAI,CAAC;QACX,OAAO;YACL,EAAE,EAAE,OAAO;YACX,OAAO,EAAE,KAAK,CAAC,EAAE;YACjB,QAAQ;YACR,QAAQ,EAAE,GAAG,CAAC,QAAQ;YACtB,QAAQ,EAAE,GAAG;YACb,GAAG,EAAE,GAAG,EAAE;YACV,QAAQ,EAAE,GAAG,CAAC,EAAE;YAChB,IAAI;SACL,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,MAAM,KAAK,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;IAEjC,MAAM,QAAQ,GAAG,MAAM,WAAW,CAAC,KAAK,EAAE,KAAK,CAAC,EAAE,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;IACnE,MAAM,UAAU,GAAG,KAAK,CAAC,OAAO,GAAG,SAAS,CAAC,MAAM,CAAC;IAEpD,MAAM,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,EAAE,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,EAAE,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;IAEvF,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,CAAC;AAC/D,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,KAAqB,EACrB,OAAe,EACf,WAAmB;IAEnB,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,kBAAkB,CAAC,OAAO,CAAC,CAAC;IAEvD,IAAI,KAAK,GAAY,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;IAE7C,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,IAAI,KAAK,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;YACjC,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC;gBACf,IAAI,CAAC;oBACH,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,aAAa,CAAC;gBAC/C,CAAC;gBAAC,MAAM,CAAC,CAAA,CAAC;YACZ,CAAC;YACD,SAAS;QACX,CAAC;QAED,IAAI,CAAC;YACH,KAAK,GAAG,aAAa,CAAC,KAAK,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAC;QAC/C,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC;gBACf,IAAI,CAAC;oBACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;oBACtC,IAAI,MAAM,CAAC,aAAa,KAAK,SAAS,EAAE,CAAC;wBACvC,KAAK,GAAG,MAAM,CAAC,aAAa,CAAC;wBAC7B,SAAS;oBACX,CAAC;gBACH,CAAC;gBAAC,MAAM,CAAC,CAAA,CAAC;YACZ,CAAC;YACD,OAAO,CAAC,KAAK,CAAC,+BAAgC,GAAa,CAAC,OAAO,EAAE,CAAC,CAAC;QACzE,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,YAAY,GAAG;IACnB,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ;IAC7D,QAAQ,EAAE,SAAS,EAAE,UAAU,EAAE,YAAY,EAAE,OAAO,EAAE,UAAU;IAClE,iBAAiB,EAAE,WAAW,EAAE,KAAK,EAAE,UAAU;CACzC,CAAC;AAEX,MAAM,cAAc,GAAG;IACrB,UAAU,CAAC,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM;IAC1D,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,KAAK,EAAE,QAAQ;IACtD,eAAe,EAAE,SAAS,EAAE,GAAG,EAAE,QAAQ;CAC1C,CAAC;AAEF;;;;;;;GAOG;AACH,SAAS,aAAa,CAAC,KAAc,EAAE,YAAoB;IACzD,MAAM,QAAQ,GAAG,0BAA0B,CAAC;IAC5C,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC;QACjC,MAAM,IAAI,KAAK,CAAC,oDAAoD,CAAC,CAAC;IACxE,CAAC;IAED,MAAM,EAAE,GAAG,IAAI,QAAQ,CACrB,WAAW,EACX,GAAG,YAAY,EACf,gCAAgC,YAAY,6BAA6B,CAC1E,CAAC;IACF,OAAO,EAAE,CAAC,eAAe,CAAC,KAAK,CAAC,EAAE,GAAG,cAAc,CAAC,CAAC;AACvD,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAC9B,KAAqB,EACrB,OAAe,EACf,KAAK,GAAG,EAAE,EACV,MAAe;IAEf,OAAO,KAAK,CAAC,eAAe,CAAC,OAAO,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;AACvD,CAAC"}
@@ -0,0 +1,100 @@
1
+ /**
2
+ * StorageAdapter — the contract any persistence backend must implement.
3
+ *
4
+ * All methods return Promises, enabling both synchronous backends (SQLite)
5
+ * and asynchronous backends (Postgres, Redis, etc.) to implement the same
6
+ * interface. For SQLite, the async overhead is negligible — the methods
7
+ * resolve immediately since better-sqlite3 is synchronous under the hood.
8
+ */
9
+ export interface NamespaceRecord {
10
+ id: string;
11
+ name: string;
12
+ api_key: string;
13
+ created_at: number;
14
+ }
15
+ export interface StateRecord {
16
+ id: string;
17
+ namespace: string;
18
+ key: string;
19
+ initial: string;
20
+ snapshot: string;
21
+ version: number;
22
+ created_at: number;
23
+ updated_at: number;
24
+ }
25
+ export interface EventRecord {
26
+ id: string;
27
+ state_id: string;
28
+ client_id: string;
29
+ client_ts: number;
30
+ server_ts: number;
31
+ seq: number;
32
+ mutation: string;
33
+ meta: string | null;
34
+ created_at: number;
35
+ }
36
+ export interface EventInput {
37
+ id: string;
38
+ stateId: string;
39
+ clientId: string;
40
+ clientTs: number;
41
+ serverTs: number;
42
+ seq: number;
43
+ mutation: string;
44
+ meta: string | null;
45
+ }
46
+ export interface StorageAdapter {
47
+ /** Run migrations / create tables. Called once at boot. */
48
+ init(): Promise<void>;
49
+ /** Clean shutdown (close connections, etc.) */
50
+ close(): Promise<void>;
51
+ /** List all namespaces (api_key excluded from result for safety). */
52
+ listNamespaces(): Promise<Pick<NamespaceRecord, "id" | "name" | "created_at">[]>;
53
+ /** Find a namespace by its hashed API key. Returns just the id, or null. */
54
+ findNamespaceByApiKey(apiKeyHash: string): Promise<{
55
+ id: string;
56
+ } | null>;
57
+ /** Find a namespace by name. Returns the full record, or null. */
58
+ findNamespaceByName(name: string): Promise<NamespaceRecord | null>;
59
+ /** Insert a new namespace. */
60
+ createNamespace(ns: NamespaceRecord): Promise<void>;
61
+ /** Find a state by (namespace, key). */
62
+ findState(namespace: string, key: string): Promise<StateRecord | null>;
63
+ /** Find a state by primary key. */
64
+ findStateById(id: string): Promise<StateRecord | null>;
65
+ /** List states for a namespace (snapshot included). */
66
+ listStates(namespace: string): Promise<StateRecord[]>;
67
+ /** Insert a new state row. */
68
+ createState(state: StateRecord): Promise<void>;
69
+ /** Update the snapshot, version, and updated_at for a state. */
70
+ updateSnapshot(stateId: string, snapshot: string, version: number, updatedAt: number): Promise<void>;
71
+ /** Get the current max sequence number for a state. null if no events. */
72
+ getMaxSeq(stateId: string): Promise<number | null>;
73
+ /** Insert a batch of events atomically (single transaction). */
74
+ insertEvents(events: EventInput[]): Promise<void>;
75
+ /** Get all events for replay: just mutation + meta, ordered by (server_ts, seq). */
76
+ getEventsForReplay(stateId: string): Promise<{
77
+ mutation: string;
78
+ meta: string | null;
79
+ }[]>;
80
+ /** Get paginated event history (full records). */
81
+ getEventHistory(stateId: string, limit: number, cursor?: string): Promise<{
82
+ events: EventRecord[];
83
+ hasMore: boolean;
84
+ }>;
85
+ /** Counts for the studio overview. */
86
+ getStats(): Promise<{
87
+ namespaces: number;
88
+ states: number;
89
+ events: number;
90
+ }>;
91
+ /** All states with their namespace name, ordered by last updated. */
92
+ listAllStatesWithNamespace(): Promise<(StateRecord & {
93
+ namespace_name: string;
94
+ })[]>;
95
+ /** Recent events across all states, with state key attached. */
96
+ getRecentEvents(limit: number): Promise<(EventRecord & {
97
+ state_key: string;
98
+ })[]>;
99
+ }
100
+ //# sourceMappingURL=adapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../../src/storage/adapter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * StorageAdapter — the contract any persistence backend must implement.
3
+ *
4
+ * All methods return Promises, enabling both synchronous backends (SQLite)
5
+ * and asynchronous backends (Postgres, Redis, etc.) to implement the same
6
+ * interface. For SQLite, the async overhead is negligible — the methods
7
+ * resolve immediately since better-sqlite3 is synchronous under the hood.
8
+ */
9
+ export {};
10
+ //# sourceMappingURL=adapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapter.js","sourceRoot":"","sources":["../../src/storage/adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG"}
@@ -0,0 +1,6 @@
1
+ export type { StorageAdapter, NamespaceRecord, StateRecord, EventRecord, EventInput, } from "./adapter.js";
2
+ export { SqliteAdapter } from "./sqlite.js";
3
+ export type { SqliteOptions } from "./sqlite.js";
4
+ export { PostgresAdapter } from "./postgres.js";
5
+ export type { PostgresOptions } from "./postgres.js";
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/storage/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,cAAc,EACd,eAAe,EACf,WAAW,EACX,WAAW,EACX,UAAU,GACX,MAAM,cAAc,CAAC;AAEtB,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,YAAY,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAEjD,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,YAAY,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC"}
@@ -0,0 +1,3 @@
1
+ export { SqliteAdapter } from "./sqlite.js";
2
+ export { PostgresAdapter } from "./postgres.js";
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/storage/index.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAG5C,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC"}
@@ -0,0 +1,48 @@
1
+ import type { StorageAdapter, NamespaceRecord, StateRecord, EventRecord, EventInput } from "./adapter.js";
2
+ export interface PostgresOptions {
3
+ /** Postgres connection string, e.g. postgres://user:pass@host:5432/mydb */
4
+ connectionString: string;
5
+ /** Max connections in the pool. Default: 10 */
6
+ maxConnections?: number;
7
+ }
8
+ export declare class PostgresAdapter implements StorageAdapter {
9
+ private opts;
10
+ private pool;
11
+ constructor(opts: PostgresOptions);
12
+ init(): Promise<void>;
13
+ close(): Promise<void>;
14
+ listNamespaces(): Promise<Pick<NamespaceRecord, "id" | "name" | "created_at">[]>;
15
+ findNamespaceByApiKey(apiKeyHash: string): Promise<{
16
+ id: string;
17
+ } | null>;
18
+ findNamespaceByName(name: string): Promise<NamespaceRecord | null>;
19
+ createNamespace(ns: NamespaceRecord): Promise<void>;
20
+ private rowToState;
21
+ findState(namespace: string, key: string): Promise<StateRecord | null>;
22
+ findStateById(id: string): Promise<StateRecord | null>;
23
+ listStates(namespace: string): Promise<StateRecord[]>;
24
+ createState(state: StateRecord): Promise<void>;
25
+ updateSnapshot(stateId: string, snapshot: string, version: number, updatedAt: number): Promise<void>;
26
+ getMaxSeq(stateId: string): Promise<number | null>;
27
+ insertEvents(events: EventInput[]): Promise<void>;
28
+ getEventsForReplay(stateId: string): Promise<{
29
+ mutation: string;
30
+ meta: string | null;
31
+ }[]>;
32
+ getEventHistory(stateId: string, limit: number, cursor?: string): Promise<{
33
+ events: EventRecord[];
34
+ hasMore: boolean;
35
+ }>;
36
+ getStats(): Promise<{
37
+ namespaces: number;
38
+ states: number;
39
+ events: number;
40
+ }>;
41
+ listAllStatesWithNamespace(): Promise<(StateRecord & {
42
+ namespace_name: string;
43
+ })[]>;
44
+ getRecentEvents(limit: number): Promise<(EventRecord & {
45
+ state_key: string;
46
+ })[]>;
47
+ }
48
+ //# sourceMappingURL=postgres.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"postgres.d.ts","sourceRoot":"","sources":["../../src/storage/postgres.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,cAAc,EACd,eAAe,EACf,WAAW,EACX,WAAW,EACX,UAAU,EACX,MAAM,cAAc,CAAC;AAItB,MAAM,WAAW,eAAe;IAC9B,2EAA2E;IAC3E,gBAAgB,EAAE,MAAM,CAAC;IACzB,+CAA+C;IAC/C,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,qBAAa,eAAgB,YAAW,cAAc;IAGxC,OAAO,CAAC,IAAI;IAFxB,OAAO,CAAC,IAAI,CAAU;gBAEF,IAAI,EAAE,eAAe;IASnC,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAyCrB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAMtB,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC,eAAe,EAAE,IAAI,GAAG,MAAM,GAAG,YAAY,CAAC,EAAE,CAAC;IAOhF,qBAAqB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IAQzE,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC;IASlE,eAAe,CAAC,EAAE,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC;IASzD,OAAO,CAAC,UAAU;IASZ,SAAS,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IAQtE,aAAa,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IAQtD,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IAQrD,WAAW,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAiB9C,cAAc,CAClB,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,IAAI,CAAC;IASV,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAQlD,YAAY,CAAC,MAAM,EAAE,UAAU,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAsBjD,kBAAkB,CACtB,OAAO,EAAE,MAAM,GACd,OAAO,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,EAAE,CAAC;IAQjD,eAAe,CACnB,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,EACb,MAAM,CAAC,EAAE,MAAM,GACd,OAAO,CAAC;QAAE,MAAM,EAAE,WAAW,EAAE,CAAC;QAAC,OAAO,EAAE,OAAO,CAAA;KAAE,CAAC;IAsCjD,QAAQ,IAAI,OAAO,CAAC;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IAa3E,0BAA0B,IAAI,OAAO,CAAC,CAAC,WAAW,GAAG;QAAE,cAAc,EAAE,MAAM,CAAA;KAAE,CAAC,EAAE,CAAC;IAanF,eAAe,CACnB,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,CAAC,WAAW,GAAG;QAAE,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC,EAAE,CAAC;CAkBpD"}
@@ -0,0 +1,207 @@
1
+ import pg from "pg";
2
+ const { Pool } = pg;
3
+ export class PostgresAdapter {
4
+ opts;
5
+ pool;
6
+ constructor(opts) {
7
+ this.opts = opts;
8
+ this.pool = new Pool({
9
+ connectionString: opts.connectionString,
10
+ max: opts.maxConnections ?? 10,
11
+ });
12
+ }
13
+ // ── Lifecycle ───────────────────────────────────────────────────────────
14
+ async init() {
15
+ await this.pool.query(`
16
+ CREATE TABLE IF NOT EXISTS namespaces (
17
+ id TEXT PRIMARY KEY,
18
+ name TEXT NOT NULL,
19
+ api_key TEXT NOT NULL UNIQUE,
20
+ created_at BIGINT NOT NULL
21
+ );
22
+
23
+ CREATE TABLE IF NOT EXISTS states (
24
+ id TEXT PRIMARY KEY,
25
+ namespace TEXT NOT NULL REFERENCES namespaces(id),
26
+ key TEXT NOT NULL,
27
+ initial TEXT NOT NULL,
28
+ snapshot TEXT NOT NULL,
29
+ version INTEGER NOT NULL DEFAULT 0,
30
+ created_at BIGINT NOT NULL,
31
+ updated_at BIGINT NOT NULL,
32
+ UNIQUE(namespace, key)
33
+ );
34
+
35
+ CREATE TABLE IF NOT EXISTS event_log (
36
+ id TEXT PRIMARY KEY,
37
+ state_id TEXT NOT NULL REFERENCES states(id),
38
+ client_id TEXT NOT NULL,
39
+ client_ts BIGINT NOT NULL,
40
+ server_ts BIGINT NOT NULL,
41
+ seq INTEGER NOT NULL,
42
+ mutation TEXT NOT NULL,
43
+ meta TEXT,
44
+ created_at BIGINT NOT NULL
45
+ );
46
+
47
+ CREATE INDEX IF NOT EXISTS idx_event_log_state_ts
48
+ ON event_log(state_id, server_ts, seq);
49
+
50
+ CREATE INDEX IF NOT EXISTS idx_states_namespace_key
51
+ ON states(namespace, key);
52
+ `);
53
+ }
54
+ async close() {
55
+ await this.pool.end();
56
+ }
57
+ // ── Namespaces ──────────────────────────────────────────────────────────
58
+ async listNamespaces() {
59
+ const { rows } = await this.pool.query("SELECT id, name, created_at FROM namespaces");
60
+ return rows.map((r) => ({ ...r, created_at: Number(r.created_at) }));
61
+ }
62
+ async findNamespaceByApiKey(apiKeyHash) {
63
+ const { rows } = await this.pool.query("SELECT id FROM namespaces WHERE api_key = $1", [apiKeyHash]);
64
+ return rows[0] ?? null;
65
+ }
66
+ async findNamespaceByName(name) {
67
+ const { rows } = await this.pool.query("SELECT * FROM namespaces WHERE name = $1", [name]);
68
+ if (!rows[0])
69
+ return null;
70
+ return { ...rows[0], created_at: Number(rows[0].created_at) };
71
+ }
72
+ async createNamespace(ns) {
73
+ await this.pool.query("INSERT INTO namespaces (id, name, api_key, created_at) VALUES ($1, $2, $3, $4)", [ns.id, ns.name, ns.api_key, ns.created_at]);
74
+ }
75
+ // ── States ──────────────────────────────────────────────────────────────
76
+ rowToState(r) {
77
+ return {
78
+ ...r,
79
+ version: Number(r.version),
80
+ created_at: Number(r.created_at),
81
+ updated_at: Number(r.updated_at),
82
+ };
83
+ }
84
+ async findState(namespace, key) {
85
+ const { rows } = await this.pool.query("SELECT * FROM states WHERE namespace = $1 AND key = $2", [namespace, key]);
86
+ return rows[0] ? this.rowToState(rows[0]) : null;
87
+ }
88
+ async findStateById(id) {
89
+ const { rows } = await this.pool.query("SELECT * FROM states WHERE id = $1", [id]);
90
+ return rows[0] ? this.rowToState(rows[0]) : null;
91
+ }
92
+ async listStates(namespace) {
93
+ const { rows } = await this.pool.query("SELECT id, key, snapshot, version, created_at, updated_at FROM states WHERE namespace = $1", [namespace]);
94
+ return rows.map((r) => this.rowToState(r));
95
+ }
96
+ async createState(state) {
97
+ await this.pool.query(`INSERT INTO states (id, namespace, key, initial, snapshot, version, created_at, updated_at)
98
+ VALUES ($1, $2, $3, $4, $5, $6, $7, $8)`, [
99
+ state.id,
100
+ state.namespace,
101
+ state.key,
102
+ state.initial,
103
+ state.snapshot,
104
+ state.version,
105
+ state.created_at,
106
+ state.updated_at,
107
+ ]);
108
+ }
109
+ async updateSnapshot(stateId, snapshot, version, updatedAt) {
110
+ await this.pool.query("UPDATE states SET snapshot = $1, version = $2, updated_at = $3 WHERE id = $4", [snapshot, version, updatedAt, stateId]);
111
+ }
112
+ // ── Event Log ───────────────────────────────────────────────────────────
113
+ async getMaxSeq(stateId) {
114
+ const { rows } = await this.pool.query("SELECT MAX(seq) as max_seq FROM event_log WHERE state_id = $1", [stateId]);
115
+ return rows[0]?.max_seq != null ? Number(rows[0].max_seq) : null;
116
+ }
117
+ async insertEvents(events) {
118
+ if (events.length === 0)
119
+ return;
120
+ const client = await this.pool.connect();
121
+ try {
122
+ await client.query("BEGIN");
123
+ for (const e of events) {
124
+ await client.query(`INSERT INTO event_log (id, state_id, client_id, client_ts, server_ts, seq, mutation, meta, created_at)
125
+ VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)`, [e.id, e.stateId, e.clientId, e.clientTs, e.serverTs, e.seq, e.mutation, e.meta, e.serverTs]);
126
+ }
127
+ await client.query("COMMIT");
128
+ }
129
+ catch (err) {
130
+ await client.query("ROLLBACK");
131
+ throw err;
132
+ }
133
+ finally {
134
+ client.release();
135
+ }
136
+ }
137
+ async getEventsForReplay(stateId) {
138
+ const { rows } = await this.pool.query("SELECT mutation, meta FROM event_log WHERE state_id = $1 ORDER BY server_ts ASC, seq ASC", [stateId]);
139
+ return rows;
140
+ }
141
+ async getEventHistory(stateId, limit, cursor) {
142
+ let rows;
143
+ if (cursor) {
144
+ const result = await this.pool.query(`SELECT * FROM event_log
145
+ WHERE state_id = $1 AND (server_ts, seq) > (
146
+ SELECT server_ts, seq FROM event_log WHERE id = $2
147
+ )
148
+ ORDER BY server_ts ASC, seq ASC
149
+ LIMIT $3`, [stateId, cursor, limit + 1]);
150
+ rows = result.rows;
151
+ }
152
+ else {
153
+ const result = await this.pool.query("SELECT * FROM event_log WHERE state_id = $1 ORDER BY server_ts ASC, seq ASC LIMIT $2", [stateId, limit + 1]);
154
+ rows = result.rows;
155
+ }
156
+ const events = rows.map((r) => ({
157
+ ...r,
158
+ client_ts: Number(r.client_ts),
159
+ server_ts: Number(r.server_ts),
160
+ seq: Number(r.seq),
161
+ created_at: Number(r.created_at),
162
+ }));
163
+ const hasMore = events.length > limit;
164
+ if (hasMore)
165
+ events.pop();
166
+ return { events, hasMore };
167
+ }
168
+ // ── Studio ──────────────────────────────────────────────────────────────
169
+ async getStats() {
170
+ const [ns, st, ev] = await Promise.all([
171
+ this.pool.query("SELECT COUNT(*)::int as count FROM namespaces"),
172
+ this.pool.query("SELECT COUNT(*)::int as count FROM states"),
173
+ this.pool.query("SELECT COUNT(*)::int as count FROM event_log"),
174
+ ]);
175
+ return {
176
+ namespaces: ns.rows[0].count,
177
+ states: st.rows[0].count,
178
+ events: ev.rows[0].count,
179
+ };
180
+ }
181
+ async listAllStatesWithNamespace() {
182
+ const { rows } = await this.pool.query(`SELECT s.id, s.namespace, s.key, s.snapshot, s.version, s.created_at, s.updated_at, n.name as namespace_name
183
+ FROM states s
184
+ JOIN namespaces n ON s.namespace = n.id
185
+ ORDER BY s.updated_at DESC`);
186
+ return rows.map((r) => ({
187
+ ...this.rowToState(r),
188
+ namespace_name: r.namespace_name,
189
+ }));
190
+ }
191
+ async getRecentEvents(limit) {
192
+ const { rows } = await this.pool.query(`SELECT e.id, e.state_id, e.client_id, e.client_ts, e.server_ts, e.mutation, e.meta, s.key as state_key
193
+ FROM event_log e
194
+ JOIN states s ON e.state_id = s.id
195
+ ORDER BY e.server_ts DESC, e.seq DESC
196
+ LIMIT $1`, [limit]);
197
+ return rows
198
+ .map((r) => ({
199
+ ...r,
200
+ client_ts: Number(r.client_ts),
201
+ server_ts: Number(r.server_ts),
202
+ created_at: Number(r.created_at),
203
+ }))
204
+ .reverse();
205
+ }
206
+ }
207
+ //# sourceMappingURL=postgres.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"postgres.js","sourceRoot":"","sources":["../../src/storage/postgres.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,49 @@
1
+ import Database from "better-sqlite3";
2
+ import type { StorageAdapter, NamespaceRecord, StateRecord, EventRecord, EventInput } from "./adapter.js";
3
+ export interface SqliteOptions {
4
+ /** Path to the .db file. Defaults to process.env.DATABASE_PATH or ./data/state.db */
5
+ dbPath?: string;
6
+ /** If true, uses an in-memory database (useful for tests). */
7
+ memory?: boolean;
8
+ }
9
+ export declare class SqliteAdapter implements StorageAdapter {
10
+ private db;
11
+ constructor(opts?: SqliteOptions);
12
+ /** Expose the raw database for edge cases (tests, legacy code). */
13
+ get raw(): Database.Database;
14
+ init(): Promise<void>;
15
+ close(): Promise<void>;
16
+ listNamespaces(): Promise<Pick<NamespaceRecord, "id" | "name" | "created_at">[]>;
17
+ findNamespaceByApiKey(apiKeyHash: string): Promise<{
18
+ id: string;
19
+ } | null>;
20
+ findNamespaceByName(name: string): Promise<NamespaceRecord | null>;
21
+ createNamespace(ns: NamespaceRecord): Promise<void>;
22
+ findState(namespace: string, key: string): Promise<StateRecord | null>;
23
+ findStateById(id: string): Promise<StateRecord | null>;
24
+ listStates(namespace: string): Promise<StateRecord[]>;
25
+ createState(state: StateRecord): Promise<void>;
26
+ updateSnapshot(stateId: string, snapshot: string, version: number, updatedAt: number): Promise<void>;
27
+ getMaxSeq(stateId: string): Promise<number | null>;
28
+ insertEvents(events: EventInput[]): Promise<void>;
29
+ getEventsForReplay(stateId: string): Promise<{
30
+ mutation: string;
31
+ meta: string | null;
32
+ }[]>;
33
+ getEventHistory(stateId: string, limit: number, cursor?: string): Promise<{
34
+ events: EventRecord[];
35
+ hasMore: boolean;
36
+ }>;
37
+ getStats(): Promise<{
38
+ namespaces: number;
39
+ states: number;
40
+ events: number;
41
+ }>;
42
+ listAllStatesWithNamespace(): Promise<(StateRecord & {
43
+ namespace_name: string;
44
+ })[]>;
45
+ getRecentEvents(limit: number): Promise<(EventRecord & {
46
+ state_key: string;
47
+ })[]>;
48
+ }
49
+ //# sourceMappingURL=sqlite.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sqlite.d.ts","sourceRoot":"","sources":["../../src/storage/sqlite.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AAGtC,OAAO,KAAK,EACV,cAAc,EACd,eAAe,EACf,WAAW,EACX,WAAW,EACX,UAAU,EACX,MAAM,cAAc,CAAC;AAEtB,MAAM,WAAW,aAAa;IAC5B,qFAAqF;IACrF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,8DAA8D;IAC9D,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,qBAAa,aAAc,YAAW,cAAc;IAClD,OAAO,CAAC,EAAE,CAAoB;gBAElB,IAAI,GAAE,aAAkB;IAepC,mEAAmE;IACnE,IAAI,GAAG,IAAI,QAAQ,CAAC,QAAQ,CAE3B;IAIK,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAyCrB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAMtB,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC,eAAe,EAAE,IAAI,GAAG,MAAM,GAAG,YAAY,CAAC,EAAE,CAAC;IAMhF,qBAAqB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IAQzE,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC;IAQlE,eAAe,CAAC,EAAE,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC;IAUnD,SAAS,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IAQtE,aAAa,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IAQtD,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IAQrD,WAAW,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAkB9C,cAAc,CAClB,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,IAAI,CAAC;IAUV,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAOlD,YAAY,CAAC,MAAM,EAAE,UAAU,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAyBjD,kBAAkB,CACtB,OAAO,EAAE,MAAM,GACd,OAAO,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,EAAE,CAAC;IAQjD,eAAe,CACnB,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,EACb,MAAM,CAAC,EAAE,MAAM,GACd,OAAO,CAAC;QAAE,MAAM,EAAE,WAAW,EAAE,CAAC;QAAC,OAAO,EAAE,OAAO,CAAA;KAAE,CAAC;IA8BjD,QAAQ,IAAI,OAAO,CAAC;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IAa3E,0BAA0B,IAAI,OAAO,CAAC,CAAC,WAAW,GAAG;QAAE,cAAc,EAAE,MAAM,CAAA;KAAE,CAAC,EAAE,CAAC;IAWnF,eAAe,CACnB,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,CAAC,WAAW,GAAG;QAAE,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC,EAAE,CAAC;CAYpD"}