@tessar/sqlite 0.0.0-stage → 0.1.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.
package/README.md CHANGED
@@ -1,3 +1,55 @@
1
- # Temporary Holding Version
2
-
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
1
+ # @tessar/sqlite
2
+
3
+ SQLite persistence for Tessar's state and checkpoint contracts, using Node's
4
+ built-in SQLite API. Requires Node 24.14 or newer.
5
+
6
+ ```sh
7
+ npm install @tessar/core @tessar/sqlite
8
+ ```
9
+
10
+ ```ts
11
+ import { SqliteStoragePlugin } from "@tessar/sqlite";
12
+
13
+ const storage = new SqliteStoragePlugin({ filename: "./state.db" });
14
+ // Include storage in new Controller({ id, agent, plugins: [storage, ...] }).
15
+ ```
16
+
17
+ Core owns state/checkpoint behavior; this plugin supplies physical persistence.
18
+ Choose the backend before Controller initialization. Scope filters bind queries
19
+ to application-selected metadata; applications own authentication and authorization.
20
+
21
+ Node's SQLite API is experimental. This backend uses synchronous database
22
+ operations and is a reference implementation, not a server throughput claim.
23
+
24
+ This is an early 0.x release. See the
25
+ [repository](https://github.com/hphucdev-04/tessar) for usage and contracts.
26
+
27
+ ## Schema v2
28
+
29
+ Initialization transactionally migrates v1 databases, preserving checkpoint IDs,
30
+ historical message/trace views, plugin snapshots, leases and commit receipts.
31
+ Inconsistent source data (including nonempty legacy `plugin_states` projections
32
+ or receipts without their original staged batches) aborts and rolls back. There
33
+ is no automatic reset or lossy fallback. No Sessions are invented for old threads.
34
+
35
+ Messages and trace records have revision intervals instead of one copy per
36
+ checkpoint. Public checkpoints still hydrate complete logical history. Successful
37
+ publication removes staging; receipt fingerprints continue rejecting a changed
38
+ payload with the same commit ID. Session selection writes use transactional CAS.
39
+ There is no `agents` table.
40
+
41
+ History and record pages use bounded SQL queries and indexed parent/date/ID
42
+ columns. Arbitrary scalar scope keys are bound JSON predicates and may require
43
+ scanning candidates; there is no automatic index per scope key. SQLite uses
44
+ synchronous operations, so large writes can still block the Node event loop.
45
+
46
+ Delete remains soft. Purge is explicit, guarded by ownership and retained fork
47
+ lineage, and never removes plugin-owned tables. Plugins needing independent job
48
+ claims or scheduling indexes own their database/schema and migrations; the core
49
+ state API exposes JSON state, not raw SQL access.
50
+
51
+ Lease fencing counters survive purge. A stale lease cannot regain ownership when
52
+ the same thread ID and owner token are reused. Publication checks ownership again
53
+ before committing; an expired lease rolls back the complete publication.
54
+
55
+ See [the database map](../../SQLITE-STATE.md) for tables and actual fixture rows.
@@ -0,0 +1,5 @@
1
+ import { type StorageBackend } from "@tessar/core";
2
+ export interface SqliteStorageOptions {
3
+ filename: string;
4
+ }
5
+ export declare function createSqliteBackend(options: SqliteStorageOptions): Promise<StorageBackend>;
@@ -0,0 +1,277 @@
1
+ import { DatabaseSync } from "node:sqlite";
2
+ import { canonicalJson, buildThreadInfo, recordBinding, validateSession, commitFingerprint, validateBatch, fail, immutable, matchesScope, } from "@tessar/core";
3
+ import { initializeSchema, recordTables } from "./schema.js";
4
+ import { sqlPage, scopePredicate, historyPage, checkpointPage, } from "./queries.js";
5
+ import { readVersions, writeVersions, writeCheckpoint, hydrateCheckpoint, } from "./versions.js";
6
+ import { databaseNow, assertOwnership, createOwnership, transaction, } from "./ownership.js";
7
+ export async function createSqliteBackend(options) {
8
+ const db = new DatabaseSync(options.filename);
9
+ try {
10
+ await initializeSchema(db);
11
+ }
12
+ catch (error) {
13
+ db.close();
14
+ throw error;
15
+ }
16
+ let closed = false;
17
+ const getJson = (sql, ...values) => {
18
+ const row = db.prepare(sql).get(...values);
19
+ return row ? immutable(JSON.parse(row.body)) : null;
20
+ };
21
+ const head = (id) => getJson("SELECT body FROM threads WHERE id=?", id);
22
+ const checkpointRow = (id) => db
23
+ .prepare("SELECT thread_id,revision,body FROM checkpoints WHERE id=?")
24
+ .get(id);
25
+ const records = (kind, threadId, cp) => {
26
+ const row = checkpointRow(cp ?? head(threadId)?.currentCheckpointId ?? "");
27
+ return row && row.thread_id === threadId
28
+ ? readVersions(db, kind, threadId, row.revision)
29
+ : [];
30
+ };
31
+ const ownerKey = (key) => canonicalJson([key.ownerType, key.ownerId, key.pluginId, key.namespace]);
32
+ return {
33
+ sessions: {
34
+ get: async (id, query = {}) => {
35
+ const row = getJson("SELECT body FROM sessions WHERE id=?", id);
36
+ return row && matchesScope(row.scope, query.scope) ? row : null;
37
+ },
38
+ page: async (query) => {
39
+ const scope = scopePredicate(query.scope);
40
+ return sqlPage(db, "sessions", "agent_id=? AND " + scope.sql, [query.agentId, ...scope.values], query, canonicalJson({ agentId: query.agentId, scope: query.scope ?? {} }), "created_at");
41
+ },
42
+ compareAndSet: async (value, expected) => transaction(db, () => {
43
+ const old = getJson("SELECT body FROM sessions WHERE id=?", value.id);
44
+ validateSession(value, old, expected, value.selectedThreadId ? head(value.selectedThreadId) : null);
45
+ db.prepare("INSERT INTO sessions VALUES(?,?,?,?,?,?,?) ON CONFLICT(id) DO UPDATE SET selected_thread_id=excluded.selected_thread_id,revision=excluded.revision,updated_at=excluded.updated_at,body=excluded.body").run(value.id, value.agentId, value.selectedThreadId, value.revision, value.createdAt, value.updatedAt, canonicalJson(value));
46
+ }),
47
+ },
48
+ id: "sqlite",
49
+ capabilities: {
50
+ durable: true,
51
+ atomicPublish: true,
52
+ coordination: "multi-process",
53
+ },
54
+ threads: {
55
+ purge: async (id, query = {}) => transaction(db, () => {
56
+ const info = head(id);
57
+ if (!info || !matchesScope(info.scope, query.scope))
58
+ fail("ThreadNotFound", "Thread does not match query");
59
+ if (!info.deleted)
60
+ fail("ThreadNotDeleted", "Soft-delete the thread before purging");
61
+ if (info.activeStreamId ||
62
+ db
63
+ .prepare("SELECT 1 FROM leases WHERE thread_id=? AND expires_at>?")
64
+ .get(id, databaseNow(db)))
65
+ fail("ThreadBusy", "Thread has active execution or ownership");
66
+ if (db
67
+ .prepare("SELECT 1 FROM threads WHERE json_extract(body,'$.parentThreadId')=? OR json_extract(body,'$.sourceCheckpointId') IN (SELECT id FROM checkpoints WHERE thread_id=?) LIMIT 1")
68
+ .get(id, id))
69
+ fail("ThreadReferenced", "Retained fork references this thread");
70
+ for (const table of [
71
+ ...recordTables,
72
+ "messages",
73
+ "checkpoints",
74
+ "commits",
75
+ ])
76
+ db.prepare("DELETE FROM " + table + " WHERE thread_id=?").run(id);
77
+ db.prepare("DELETE FROM staging WHERE json_extract(body,'$.threadId')=?").run(id);
78
+ db.prepare("DELETE FROM threads WHERE id=?").run(id);
79
+ }),
80
+ page: async (query) => {
81
+ const scope = scopePredicate(query.scope);
82
+ return sqlPage(db, "threads", "deleted=0 AND " + scope.sql, scope.values, query, canonicalJson(query.scope ?? {}), "created_at");
83
+ },
84
+ get: async (id, options) => {
85
+ const value = head(id);
86
+ return value && (!value.deleted || options?.includeDeleted)
87
+ ? value
88
+ : null;
89
+ },
90
+ list: async (query) => db.prepare("SELECT body FROM threads").all()
91
+ .map((r) => immutable(JSON.parse(r.body)))
92
+ .filter((r) => !r.deleted && matchesScope(r.scope, query?.scope)),
93
+ },
94
+ checkpoints: {
95
+ page: async (threadId, options) => checkpointPage(db, threadId, options),
96
+ history: async (threadId, options, query) => historyPage(db, threadId, options, query),
97
+ get: async (id) => checkpointRow(id)
98
+ ? hydrateCheckpoint(db, checkpointRow(id).body)
99
+ : null,
100
+ list: async (threadId) => db
101
+ .prepare("SELECT body FROM checkpoints WHERE thread_id=? ORDER BY revision")
102
+ .all(threadId).map((r) => hydrateCheckpoint(db, r.body)),
103
+ },
104
+ executions: {
105
+ page: async (kind, threadId, query) => {
106
+ if (!recordTables.includes(kind))
107
+ fail("InvalidConfiguration", "Unknown record kind");
108
+ const cp = checkpointRow(query.atCheckpointId ?? head(threadId)?.currentCheckpointId ?? "");
109
+ if (!cp || cp.thread_id !== threadId)
110
+ fail("CheckpointNotFound", "No checkpoint for records");
111
+ const values = [
112
+ threadId,
113
+ cp.revision,
114
+ cp.revision,
115
+ ];
116
+ let where = "thread_id=? AND from_revision<=? AND (to_revision IS NULL OR ?<to_revision)";
117
+ for (const [field, column] of [
118
+ ["streamId", "stream_id"],
119
+ ["turnId", "turn_id"],
120
+ ["status", "status"],
121
+ ])
122
+ if (query[field] !== undefined) {
123
+ where += " AND " + column + "=?";
124
+ values.push(query[field]);
125
+ }
126
+ return sqlPage(db, kind, where, values, query, recordBinding(kind, threadId, query), "sort_date");
127
+ },
128
+ get: async (kind, id, query) => {
129
+ if (!recordTables.includes(kind))
130
+ fail("InvalidConfiguration", "Unknown record kind");
131
+ if (query?.threadId)
132
+ return (records(kind, query.threadId, query.atCheckpointId).find((r) => r.id === id) ?? null);
133
+ if (query?.atCheckpointId) {
134
+ const row = checkpointRow(query.atCheckpointId);
135
+ return (row
136
+ ? (records(kind, row.thread_id, query.atCheckpointId).find((r) => r.id === id) ?? null)
137
+ : null);
138
+ }
139
+ return getJson("SELECT r.body FROM " +
140
+ kind +
141
+ " r JOIN threads t ON r.thread_id=t.id WHERE r.id=? AND r.to_revision IS NULL AND t.deleted=0", id);
142
+ },
143
+ listRecords: async (kind, threadId, query) => records(kind, threadId, query?.atCheckpointId),
144
+ },
145
+ ownedState: {
146
+ get: async (key) => getJson("SELECT body FROM owned_states WHERE owner_key=?", ownerKey(key)),
147
+ compareAndSet: async (state, expected) => transaction(db, () => {
148
+ if (!["agent", "session"].includes(state.ownerType))
149
+ fail("InvalidConfiguration", "Execution state must use checkpoints");
150
+ const key = ownerKey(state), old = getJson("SELECT body FROM owned_states WHERE owner_key=?", key);
151
+ if ((old?.revision ?? 0) !== expected ||
152
+ state.revision !== expected + 1)
153
+ fail("CommitConflict", "Owned state revision changed");
154
+ db.prepare("INSERT INTO owned_states VALUES(?,?,?) ON CONFLICT(owner_key) DO UPDATE SET revision=excluded.revision,body=excluded.body").run(key, state.revision, canonicalJson(state));
155
+ }),
156
+ },
157
+ ownership: createOwnership(db),
158
+ commits: {
159
+ stage: async (batch) => {
160
+ validateBatch(batch);
161
+ const fingerprint = await commitFingerprint(batch);
162
+ transaction(db, () => {
163
+ const published = db
164
+ .prepare("SELECT fingerprint FROM commits WHERE id=?")
165
+ .get(batch.commitId);
166
+ if (published) {
167
+ if (published.fingerprint !== fingerprint)
168
+ fail("CommitConflict", "commitId payload mismatch");
169
+ return;
170
+ }
171
+ const old = getJson("SELECT body FROM staging WHERE id=?", batch.commitId);
172
+ if (old && canonicalJson(old) !== canonicalJson(batch))
173
+ fail("CommitConflict", "commitId payload mismatch");
174
+ if (!old)
175
+ db.prepare("INSERT INTO staging VALUES(?,?,?)").run(batch.commitId, canonicalJson(batch), fingerprint);
176
+ });
177
+ },
178
+ lookupCommit: async (id) => getJson("SELECT body FROM commits WHERE id=?", id),
179
+ publish: async (request) => transaction(db, () => {
180
+ const prior = getJson("SELECT body FROM commits WHERE id=?", request.commitId);
181
+ if (prior) {
182
+ if (prior.threadId !== request.threadId ||
183
+ prior.revision !== request.expectedRevision + 1)
184
+ fail("CommitConflict", "Commit request mismatch");
185
+ return prior;
186
+ }
187
+ if (request.lease.threadId !== request.threadId)
188
+ fail("OwnershipLost", "Lease belongs to another thread");
189
+ assertOwnership(db, request.lease);
190
+ const batch = getJson("SELECT body FROM staging WHERE id=?", request.commitId);
191
+ if (!batch ||
192
+ batch.threadId !== request.threadId ||
193
+ batch.expectedRevision !== request.expectedRevision)
194
+ fail("CommitConflict", "Missing staged batch");
195
+ if (batch.lineage) {
196
+ const parent = head(batch.lineage.parentThreadId);
197
+ if (!parent ||
198
+ parent.deleted ||
199
+ checkpointRow(batch.lineage.sourceCheckpointId)?.thread_id !==
200
+ parent.id)
201
+ fail("ThreadNotFound", "Fork source is no longer available");
202
+ }
203
+ const old = head(batch.threadId), cp = batch.checkpoint;
204
+ if ((old?.revision ?? 0) !== batch.expectedRevision ||
205
+ old?.deleted ||
206
+ cp.parentCheckpointId !== (old?.currentCheckpointId ?? null))
207
+ fail("CommitConflict", "Head changed");
208
+ if (checkpointRow(cp.id))
209
+ fail("CommitConflict", "Checkpoint ID already exists");
210
+ const merged = new Map();
211
+ for (const kind of recordTables)
212
+ for (const data of records(kind, batch.threadId))
213
+ merged.set(kind + ":" + data.id, {
214
+ kind,
215
+ id: data.id,
216
+ threadId: batch.threadId,
217
+ data,
218
+ });
219
+ for (const entry of batch.records)
220
+ merged.set(entry.kind + ":" + entry.id, entry);
221
+ if (cp.execution && !merged.has("streams:" + cp.execution.streamId))
222
+ fail("CommitConflict", "Missing stream reference");
223
+ if (cp.execution?.pendingInterruptId &&
224
+ !merged.has("interrupts:" + cp.execution.pendingInterruptId))
225
+ fail("CommitConflict", "Missing interrupt reference");
226
+ writeCheckpoint(db, cp);
227
+ for (const kind of recordTables)
228
+ writeVersions(db, kind, cp.threadId, cp.revision, batch.records
229
+ .filter((entry) => entry.kind === kind)
230
+ .map((entry) => ({
231
+ id: entry.id,
232
+ body: canonicalJson(entry.data),
233
+ })));
234
+ const stream = cp.execution
235
+ ? merged.get("streams:" + cp.execution.streamId)
236
+ ?.data
237
+ : null;
238
+ const info = buildThreadInfo(batch, old, stream);
239
+ db.prepare("INSERT INTO threads VALUES(?,?,?,?) ON CONFLICT(id) DO UPDATE SET body=excluded.body,created_at=excluded.created_at,deleted=excluded.deleted").run(info.id, canonicalJson(info), info.createdAt, Number(info.deleted));
240
+ if (info.deleted) {
241
+ const selections = db
242
+ .prepare("SELECT body FROM sessions WHERE selected_thread_id=?")
243
+ .all(info.id);
244
+ for (const row of selections) {
245
+ const session = JSON.parse(String(row.body));
246
+ const next = {
247
+ ...session,
248
+ selectedThreadId: null,
249
+ revision: session.revision + 1,
250
+ updatedAt: cp.createdAt,
251
+ };
252
+ db.prepare("UPDATE sessions SET selected_thread_id=NULL,revision=?,updated_at=?,body=? WHERE id=?").run(next.revision, next.updatedAt, canonicalJson(next), next.id);
253
+ }
254
+ }
255
+ const receipt = {
256
+ commitId: batch.commitId,
257
+ threadId: batch.threadId,
258
+ revision: cp.revision,
259
+ checkpointId: cp.id,
260
+ };
261
+ db.prepare("INSERT INTO commits VALUES(?,?,?,?)").run(batch.commitId, canonicalJson(receipt), String(db
262
+ .prepare("SELECT fingerprint FROM staging WHERE id=?")
263
+ .get(batch.commitId).fingerprint), cp.threadId);
264
+ db.prepare("DELETE FROM staging WHERE id=?").run(batch.commitId);
265
+ assertOwnership(db, request.lease);
266
+ return receipt;
267
+ }),
268
+ },
269
+ close: async () => {
270
+ if (!closed) {
271
+ closed = true;
272
+ db.close();
273
+ }
274
+ },
275
+ };
276
+ }
277
+ //# sourceMappingURL=backend.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"backend.js","sourceRoot":"","sources":["../src/backend.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ export * from "./backend.js";
2
+ import type { Plugin, PluginContext } from "@tessar/core";
3
+ import { type SqliteStorageOptions } from "./backend.js";
4
+ export declare class SqliteStoragePlugin implements Plugin {
5
+ private readonly options;
6
+ readonly id = "storage.sqlite";
7
+ constructor(options: SqliteStorageOptions);
8
+ setup(tessar: PluginContext): Promise<void>;
9
+ }
package/dist/index.js ADDED
@@ -0,0 +1,20 @@
1
+ export * from "./backend.js";
2
+ import { createSqliteBackend } from "./backend.js";
3
+ export class SqliteStoragePlugin {
4
+ options;
5
+ id = "storage.sqlite";
6
+ constructor(options) {
7
+ this.options = options;
8
+ }
9
+ async setup(tessar) {
10
+ const backend = await createSqliteBackend(this.options);
11
+ try {
12
+ tessar.storage.register(backend);
13
+ }
14
+ catch (error) {
15
+ await backend.close().catch(() => { });
16
+ throw error;
17
+ }
18
+ }
19
+ }
20
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC;AAE7B,OAAO,EAAE,mBAAmB,EAA6B,MAAM,cAAc,CAAC;AAC9E,MAAM,OAAO,mBAAmB;IAED,OAAO;IAD3B,EAAE,GAAG,gBAAgB,CAAC;IAC/B,YAA6B,OAA6B;uBAA7B,OAAO;IAAyB,CAAC;IAC9D,KAAK,CAAC,KAAK,CAAC,MAAqB;QAC/B,MAAM,OAAO,GAAG,MAAM,mBAAmB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACxD,IAAI,CAAC;YACH,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;QACnC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,OAAO,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;YACtC,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;CACF"}
@@ -0,0 +1,3 @@
1
+ import type { DatabaseSync } from "node:sqlite";
2
+ /** Called inside initialization's write transaction. No async work while locked. */
3
+ export declare function migrateV1(db: DatabaseSync, createSchema: (db: DatabaseSync) => void): void;
@@ -0,0 +1,67 @@
1
+ import { createHash } from "node:crypto";
2
+ import { canonicalJson, validateBatch, } from "@tessar/core";
3
+ import { recordTables, writeCheckpoint, writeVersions } from "./versions.js";
4
+ /** Called inside initialization's write transaction. No async work while locked. */
5
+ export function migrateV1(db, createSchema) {
6
+ if (Number(db.prepare("SELECT count(*) n FROM plugin_states").get().n))
7
+ throw Error("Migration refuses nonempty legacy plugin_states; export and reconcile custom records first");
8
+ const tables = [
9
+ "threads",
10
+ "checkpoints",
11
+ "messages",
12
+ ...recordTables,
13
+ "plugin_states",
14
+ "staging",
15
+ "commits",
16
+ "leases",
17
+ "owned_states",
18
+ ];
19
+ for (const table of tables)
20
+ db.exec(`ALTER TABLE ${table} RENAME TO _v1_${table}`);
21
+ createSchema(db);
22
+ for (const row of db.prepare("SELECT body FROM _v1_threads").iterate()) {
23
+ const head = JSON.parse(String(row.body));
24
+ db.prepare("INSERT INTO threads VALUES(?,?,?,?)").run(head.id, canonicalJson(head), head.createdAt, Number(head.deleted));
25
+ }
26
+ for (const row of db
27
+ .prepare("SELECT body FROM _v1_checkpoints ORDER BY thread_id,revision")
28
+ .iterate()) {
29
+ const cp = JSON.parse(String(row.body));
30
+ writeCheckpoint(db, cp);
31
+ for (const kind of recordTables) {
32
+ const entries = db
33
+ .prepare(`SELECT id,body FROM _v1_${kind} WHERE thread_id=? AND checkpoint_id=?`)
34
+ .all(cp.threadId, cp.id);
35
+ writeVersions(db, kind, cp.threadId, cp.revision, entries.map((entry) => ({
36
+ id: entry.id,
37
+ body: canonicalJson(JSON.parse(entry.body)),
38
+ })), true);
39
+ }
40
+ }
41
+ for (const row of db.prepare("SELECT id,body FROM _v1_staging").iterate()) {
42
+ const batch = JSON.parse(String(row.body));
43
+ validateBatch(batch);
44
+ const body = canonicalJson(batch), fingerprint = createHash("sha256").update(body).digest("hex");
45
+ const receipt = db
46
+ .prepare("SELECT body FROM _v1_commits WHERE id=?")
47
+ .get(String(row.id));
48
+ if (receipt) {
49
+ const value = JSON.parse(String(receipt.body));
50
+ if (value.threadId !== batch.threadId ||
51
+ value.checkpointId !== batch.checkpoint.id ||
52
+ value.revision !== batch.checkpoint.revision)
53
+ throw Error("Migration found inconsistent commit receipt");
54
+ db.prepare("INSERT INTO commits VALUES(?,?,?,?)").run(String(row.id), canonicalJson(value), fingerprint, batch.threadId);
55
+ }
56
+ else
57
+ db.prepare("INSERT INTO staging VALUES(?,?,?)").run(String(row.id), body, fingerprint);
58
+ }
59
+ if (db.prepare("SELECT id FROM _v1_commits EXCEPT SELECT id FROM commits").get())
60
+ throw Error("Migration found a receipt without its original staged payload");
61
+ db.exec("INSERT INTO leases SELECT * FROM _v1_leases; INSERT INTO owned_states SELECT * FROM _v1_owned_states;");
62
+ if (db.prepare("PRAGMA foreign_key_check").get())
63
+ throw Error("Migration found invalid foreign keys");
64
+ for (const table of tables.toReversed())
65
+ db.exec(`DROP TABLE _v1_${table}`);
66
+ }
67
+ //# sourceMappingURL=migration.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migration.js","sourceRoot":"","sources":["../src/migration.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import type { DatabaseSync } from "node:sqlite";
2
+ import { type Lease, type OwnershipPort } from "@tessar/core";
3
+ export declare function databaseNow(db: DatabaseSync): number;
4
+ export declare function transaction<T>(db: DatabaseSync, action: () => T): T;
5
+ export declare function assertOwnership(db: DatabaseSync, lease: Lease): void;
6
+ export declare function createOwnership(db: DatabaseSync): OwnershipPort;
@@ -0,0 +1,67 @@
1
+ import { fail } from "@tessar/core";
2
+ export function databaseNow(db) {
3
+ return db
4
+ .prepare("SELECT CAST((julianday('now') - 2440587.5)*86400000 AS INTEGER) AS now")
5
+ .get().now;
6
+ }
7
+ export function transaction(db, action) {
8
+ db.exec("BEGIN IMMEDIATE");
9
+ try {
10
+ const result = action();
11
+ db.exec("COMMIT");
12
+ return result;
13
+ }
14
+ catch (error) {
15
+ db.exec("ROLLBACK");
16
+ throw error;
17
+ }
18
+ }
19
+ export function assertOwnership(db, lease) {
20
+ const row = db
21
+ .prepare("SELECT * FROM leases WHERE thread_id=?")
22
+ .get(lease.threadId);
23
+ if (!row ||
24
+ row.owner_token !== lease.ownerToken ||
25
+ row.fencing_token !== lease.fencingToken ||
26
+ row.expires_at <= databaseNow(db))
27
+ fail("OwnershipLost", "Lease no longer owns thread");
28
+ }
29
+ const toLease = (row) => ({
30
+ threadId: row.thread_id,
31
+ ownerToken: row.owner_token,
32
+ fencingToken: row.fencing_token,
33
+ expiresAt: new Date(row.expires_at).toISOString(),
34
+ });
35
+ export function createOwnership(db) {
36
+ return {
37
+ acquire: async (request) => transaction(db, () => {
38
+ if (!Number.isFinite(request.ttlMs) || request.ttlMs <= 0)
39
+ fail("InvalidConfiguration", "Invalid lease duration");
40
+ const previous = db
41
+ .prepare("SELECT * FROM leases WHERE thread_id=?")
42
+ .get(request.threadId), now = databaseNow(db);
43
+ if (previous && previous.expires_at > now)
44
+ fail("OwnerActive", "Thread has active owner");
45
+ const row = {
46
+ thread_id: request.threadId,
47
+ owner_token: request.ownerToken,
48
+ fencing_token: (previous?.fencing_token ?? 0) + 1,
49
+ expires_at: now + request.ttlMs,
50
+ };
51
+ db.prepare("INSERT INTO leases VALUES(?,?,?,?) ON CONFLICT(thread_id) DO UPDATE SET owner_token=excluded.owner_token,fencing_token=excluded.fencing_token,expires_at=excluded.expires_at").run(row.thread_id, row.owner_token, row.fencing_token, row.expires_at);
52
+ return toLease(row);
53
+ }),
54
+ renew: async (lease, ttlMs) => transaction(db, () => {
55
+ assertOwnership(db, lease);
56
+ if (!Number.isFinite(ttlMs) || ttlMs <= 0)
57
+ fail("InvalidConfiguration", "Invalid lease duration");
58
+ const expires = databaseNow(db) + ttlMs;
59
+ db.prepare("UPDATE leases SET expires_at=? WHERE thread_id=?").run(expires, lease.threadId);
60
+ return { ...lease, expiresAt: new Date(expires).toISOString() };
61
+ }),
62
+ release: async (lease) => {
63
+ db.prepare("UPDATE leases SET expires_at=0 WHERE thread_id=? AND owner_token=? AND fencing_token=?").run(lease.threadId, lease.ownerToken, lease.fencingToken);
64
+ },
65
+ };
66
+ }
67
+ //# sourceMappingURL=ownership.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ownership.js","sourceRoot":"","sources":["../src/ownership.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAkC,MAAM,cAAc,CAAC;AAOpE,MAAM,UAAU,WAAW,CAAC,EAAgB;IAC1C,OACE,EAAE;SACC,OAAO,CACN,wEAAwE,CACzE;SACA,GAAG,EACP,CAAC,GAAG,CAAC;AACR,CAAC;AACD,MAAM,UAAU,WAAW,CAAI,EAAgB,EAAE,MAAe;IAC9D,EAAE,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;IAC3B,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC;QACxB,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAClB,OAAO,MAAM,CAAC;IAChB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QACpB,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC;AACD,MAAM,UAAU,eAAe,CAAC,EAAgB,EAAE,KAAY;IAC5D,MAAM,GAAG,GAAG,EAAE;SACX,OAAO,CAAC,wCAAwC,CAAC;SACjD,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAyB,CAAC;IAC/C,IACE,CAAC,GAAG;QACJ,GAAG,CAAC,WAAW,KAAK,KAAK,CAAC,UAAU;QACpC,GAAG,CAAC,aAAa,KAAK,KAAK,CAAC,YAAY;QACxC,GAAG,CAAC,UAAU,IAAI,WAAW,CAAC,EAAE,CAAC;QAEjC,IAAI,CAAC,eAAe,EAAE,6BAA6B,CAAC,CAAC;AACzD,CAAC;AACD,MAAM,OAAO,GAAG,CAAC,GAAa,EAAS,EAAE,CAAC,CAAC;IACzC,QAAQ,EAAE,GAAG,CAAC,SAAS;IACvB,UAAU,EAAE,GAAG,CAAC,WAAW;IAC3B,YAAY,EAAE,GAAG,CAAC,aAAa;IAC/B,SAAS,EAAE,IAAI,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,WAAW,EAAE;CAClD,CAAC,CAAC;AACH,MAAM,UAAU,eAAe,CAAC,EAAgB;IAC9C,OAAO;QACL,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,CACzB,WAAW,CAAC,EAAE,EAAE,GAAG,EAAE;YACnB,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,OAAO,CAAC,KAAK,IAAI,CAAC;gBACvD,IAAI,CAAC,sBAAsB,EAAE,wBAAwB,CAAC,CAAC;YACzD,MAAM,QAAQ,GAAG,EAAE;iBACd,OAAO,CAAC,wCAAwC,CAAC;iBACjD,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAyB,EAChD,GAAG,GAAG,WAAW,CAAC,EAAE,CAAC,CAAC;YACxB,IAAI,QAAQ,IAAI,QAAQ,CAAC,UAAU,GAAG,GAAG;gBACvC,IAAI,CAAC,aAAa,EAAE,yBAAyB,CAAC,CAAC;YACjD,MAAM,GAAG,GAAG;gBACV,SAAS,EAAE,OAAO,CAAC,QAAQ;gBAC3B,WAAW,EAAE,OAAO,CAAC,UAAU;gBAC/B,aAAa,EAAE,CAAC,QAAQ,EAAE,aAAa,IAAI,CAAC,CAAC,GAAG,CAAC;gBACjD,UAAU,EAAE,GAAG,GAAG,OAAO,CAAC,KAAK;aAChC,CAAC;YACF,EAAE,CAAC,OAAO,CACR,8KAA8K,CAC/K,CAAC,GAAG,CACH,GAAG,CAAC,SAAS,EACb,GAAG,CAAC,WAAW,EACf,GAAG,CAAC,aAAa,EACjB,GAAG,CAAC,UAAU,CACf,CAAC;YACF,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC;QACtB,CAAC,CAAC;QACJ,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,CAC5B,WAAW,CAAC,EAAE,EAAE,GAAG,EAAE;YACnB,eAAe,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;YAC3B,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,KAAK,IAAI,CAAC;gBACvC,IAAI,CAAC,sBAAsB,EAAE,wBAAwB,CAAC,CAAC;YACzD,MAAM,OAAO,GAAG,WAAW,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC;YACxC,EAAE,CAAC,OAAO,CAAC,kDAAkD,CAAC,CAAC,GAAG,CAChE,OAAO,EACP,KAAK,CAAC,QAAQ,CACf,CAAC;YACF,OAAO,EAAE,GAAG,KAAK,EAAE,SAAS,EAAE,IAAI,IAAI,CAAC,OAAO,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC;QAClE,CAAC,CAAC;QACJ,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE;YACvB,EAAE,CAAC,OAAO,CACR,wFAAwF,CACzF,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,EAAE,KAAK,CAAC,UAAU,EAAE,KAAK,CAAC,YAAY,CAAC,CAAC;QAC9D,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,10 @@
1
+ import type { DatabaseSync, SQLInputValue } from "node:sqlite";
2
+ import { type PageOptions, type Page, type Scope, type HistoryOptions, type HistoryDataPage, type StateQuery, type CheckpointInfo } from "@tessar/core";
3
+ /** Values and keys are parameters, including keys containing JSON-path punctuation. */
4
+ export declare function scopePredicate(scope?: Scope, column?: string): {
5
+ sql: string;
6
+ values: SQLInputValue[];
7
+ };
8
+ export declare function sqlPage<T>(db: DatabaseSync, table: string, where: string, values: SQLInputValue[], options: PageOptions, binding: string, dateColumn: string, map?: (row: Record<string, any>) => T, columns?: string): Page<T>;
9
+ export declare function historyPage(db: DatabaseSync, id: string, options: HistoryOptions, query?: StateQuery): HistoryDataPage;
10
+ export declare function checkpointPage(db: DatabaseSync, threadId: string, options: PageOptions): Page<CheckpointInfo>;
@@ -0,0 +1,76 @@
1
+ import { normalizeScope, canonicalJson, immutable, fail, pageAfter, limitOf, encodeCursor, historyCursor, matchesScope, } from "@tessar/core";
2
+ /** Values and keys are parameters, including keys containing JSON-path punctuation. */
3
+ export function scopePredicate(scope = {}, column = "body") {
4
+ normalizeScope(scope);
5
+ const values = [];
6
+ const parts = Object.entries(scope).map(([key, value]) => {
7
+ values.push(key);
8
+ if (typeof value === "boolean") {
9
+ values.push(value ? "true" : "false");
10
+ return `EXISTS(SELECT 1 FROM json_each(json_extract(${column},'$.scope')) s WHERE s.key=? AND s.type=?)`;
11
+ }
12
+ values.push(value);
13
+ return `EXISTS(SELECT 1 FROM json_each(json_extract(${column},'$.scope')) s WHERE s.key=? AND s.type ${typeof value === "number" ? "IN ('integer','real')" : "='text'"} AND s.value=?)`;
14
+ });
15
+ return { sql: parts.length ? parts.join(" AND ") : "1", values };
16
+ }
17
+ export function sqlPage(db, table, where, values, options, binding, dateColumn, map = (row) => immutable(JSON.parse(row.body)), columns = "*") {
18
+ const after = pageAfter(options, binding), limit = limitOf(options.limit);
19
+ const filter = after
20
+ ? ` AND (${dateColumn}>? OR (${dateColumn}=? AND id COLLATE BINARY>?))`
21
+ : "";
22
+ const rows = db
23
+ .prepare(`SELECT ${columns},${dateColumn} AS page_date FROM ${table} WHERE ${where}${filter} ORDER BY ${dateColumn},id COLLATE BINARY LIMIT ?`)
24
+ .all(...values, ...(after ? [after[0], after[0], after[1]] : []), limit + 1);
25
+ const selected = rows.slice(0, limit), last = selected.at(-1);
26
+ return {
27
+ items: selected.map(map),
28
+ nextCursor: rows.length > limit
29
+ ? encodeCursor({ v: 2, binding, after: [last.page_date, last.id] })
30
+ : null,
31
+ };
32
+ }
33
+ export function historyPage(db, id, options, query = {}) {
34
+ const row = db
35
+ .prepare("SELECT body FROM threads WHERE id=? AND deleted=0")
36
+ .get(id);
37
+ const head = row ? JSON.parse(String(row.body)) : null;
38
+ if (!head || !matchesScope(head.scope, query.scope))
39
+ fail("ThreadNotFound", "Thread does not match query");
40
+ const { binding, cursor } = historyCursor(id, options, query), limit = limitOf(options.limit);
41
+ const cp = db
42
+ .prepare("SELECT id,revision,message_count FROM checkpoints WHERE thread_id=? AND id=?")
43
+ .get(id, cursor?.checkpointId ??
44
+ options.atCheckpointId ??
45
+ head.currentCheckpointId);
46
+ if (!cp)
47
+ fail("CheckpointNotFound", "No checkpoint for history");
48
+ const end = cursor?.end ?? Number(cp.message_count);
49
+ if (end > Number(cp.message_count))
50
+ fail("InvalidCursor", "Invalid history position");
51
+ const begin = Math.max(0, end - limit), revision = Number(cp.revision);
52
+ const items = db
53
+ .prepare("SELECT body FROM messages WHERE thread_id=? AND position>=? AND position<? AND from_revision<=? AND (to_revision IS NULL OR ?<to_revision) ORDER BY position LIMIT ?")
54
+ .all(id, begin, end, revision, revision, limit)
55
+ .map((row) => immutable(JSON.parse(String(row.body))));
56
+ return {
57
+ items,
58
+ checkpointId: String(cp.id),
59
+ revision,
60
+ nextCursor: begin
61
+ ? encodeCursor({ v: 1, binding, checkpointId: cp.id, end: begin })
62
+ : null,
63
+ };
64
+ }
65
+ export function checkpointPage(db, threadId, options) {
66
+ return sqlPage(db, "checkpoints", "thread_id=?", [threadId], options, "checkpoints:" + threadId, "created_at", (row) => ({
67
+ id: row.id,
68
+ threadId,
69
+ revision: row.revision,
70
+ createdAt: row.created_at,
71
+ cause: row.cause,
72
+ forkable: !!row.forkable,
73
+ unsafeReason: row.unsafe_reason,
74
+ }), "id,revision,created_at,cause,forkable,unsafe_reason");
75
+ }
76
+ //# sourceMappingURL=queries.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"queries.js","sourceRoot":"","sources":["../src/queries.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import type { DatabaseSync } from "node:sqlite";
2
+ import { recordTables } from "./versions.js";
3
+ export { recordTables };
4
+ export declare function initializeSchema(db: DatabaseSync): Promise<void>;
5
+ export declare function createSchema(db: DatabaseSync): void;
package/dist/schema.js ADDED
@@ -0,0 +1,66 @@
1
+ import { setTimeout } from "node:timers/promises";
2
+ import { migrateV1 } from "./migration.js";
3
+ import { recordTables } from "./versions.js";
4
+ import { fail } from "@tessar/core";
5
+ export { recordTables };
6
+ export async function initializeSchema(db) {
7
+ db.exec("PRAGMA busy_timeout=5000; PRAGMA foreign_keys=ON;");
8
+ const deadline = Date.now() + 5000;
9
+ for (;;) {
10
+ try {
11
+ db.exec("PRAGMA journal_mode=WAL;");
12
+ break;
13
+ }
14
+ catch (error) {
15
+ // SQLite can return BUSY immediately while concurrent connections enable WAL.
16
+ if (![5, 6].includes(error.errcode ?? 0) ||
17
+ Date.now() >= deadline)
18
+ throw error;
19
+ await setTimeout(10);
20
+ }
21
+ }
22
+ db.exec("BEGIN IMMEDIATE");
23
+ try {
24
+ const version = Number(db.prepare("PRAGMA user_version").get().user_version);
25
+ if (![0, 1, 2].includes(version))
26
+ fail("InvalidConfiguration", "Unsupported SQLite schema version");
27
+ if (version === 1)
28
+ migrateV1(db, createSchema);
29
+ else
30
+ createSchema(db);
31
+ db.exec("PRAGMA user_version=2; COMMIT");
32
+ }
33
+ catch (error) {
34
+ db.exec("ROLLBACK");
35
+ throw error;
36
+ }
37
+ }
38
+ export function createSchema(db) {
39
+ db.exec(`
40
+ CREATE TABLE IF NOT EXISTS threads(id TEXT PRIMARY KEY,body TEXT NOT NULL,created_at TEXT NOT NULL,deleted INTEGER NOT NULL);
41
+ CREATE TABLE IF NOT EXISTS checkpoints(id TEXT PRIMARY KEY,thread_id TEXT NOT NULL REFERENCES threads(id) DEFERRABLE INITIALLY DEFERRED,revision INTEGER NOT NULL,created_at TEXT NOT NULL,cause TEXT NOT NULL,message_count INTEGER NOT NULL,forkable INTEGER NOT NULL,unsafe_reason TEXT,body TEXT NOT NULL,UNIQUE(thread_id,revision));
42
+ CREATE INDEX IF NOT EXISTS checkpoints_page ON checkpoints(thread_id,created_at,id);
43
+ CREATE INDEX IF NOT EXISTS threads_page ON threads(deleted,created_at,id);
44
+ CREATE TABLE IF NOT EXISTS staging(id TEXT PRIMARY KEY,body TEXT NOT NULL,fingerprint TEXT NOT NULL);
45
+ CREATE TABLE IF NOT EXISTS commits(id TEXT PRIMARY KEY,body TEXT NOT NULL,fingerprint TEXT NOT NULL,thread_id TEXT NOT NULL REFERENCES threads(id));
46
+ CREATE INDEX IF NOT EXISTS commits_thread ON commits(thread_id);
47
+ CREATE TABLE IF NOT EXISTS leases(thread_id TEXT PRIMARY KEY,owner_token TEXT NOT NULL,fencing_token INTEGER NOT NULL,expires_at INTEGER NOT NULL);
48
+ CREATE TABLE IF NOT EXISTS owned_states(owner_key TEXT PRIMARY KEY,revision INTEGER NOT NULL,body TEXT NOT NULL);
49
+ CREATE TABLE IF NOT EXISTS sessions(id TEXT PRIMARY KEY,agent_id TEXT NOT NULL,selected_thread_id TEXT REFERENCES threads(id),revision INTEGER NOT NULL,created_at TEXT NOT NULL,updated_at TEXT NOT NULL,body TEXT NOT NULL);
50
+ CREATE INDEX IF NOT EXISTS sessions_page ON sessions(agent_id,created_at,id);
51
+ CREATE INDEX IF NOT EXISTS sessions_thread ON sessions(selected_thread_id);
52
+ `);
53
+ for (const table of ["messages", ...recordTables]) {
54
+ db.exec(`CREATE TABLE IF NOT EXISTS ${table}(
55
+ thread_id TEXT NOT NULL REFERENCES threads(id) DEFERRABLE INITIALLY DEFERRED,id TEXT NOT NULL,
56
+ from_revision INTEGER NOT NULL,to_revision INTEGER,position INTEGER,stream_id TEXT,turn_id TEXT,status TEXT,sort_date TEXT NOT NULL,body TEXT NOT NULL,
57
+ PRIMARY KEY(thread_id,id,from_revision), CHECK(to_revision IS NULL OR to_revision>from_revision));
58
+ CREATE UNIQUE INDEX IF NOT EXISTS ${table}_current ON ${table}(thread_id,id) WHERE to_revision IS NULL;
59
+ CREATE INDEX IF NOT EXISTS ${table}_page ON ${table}(thread_id,sort_date,id,from_revision);
60
+ CREATE INDEX IF NOT EXISTS ${table}_stream ON ${table}(thread_id,stream_id,sort_date,id);
61
+ CREATE INDEX IF NOT EXISTS ${table}_turn ON ${table}(thread_id,turn_id,sort_date,id);
62
+ `);
63
+ }
64
+ db.exec("CREATE INDEX IF NOT EXISTS messages_history ON messages(thread_id,position,from_revision)");
65
+ }
66
+ //# sourceMappingURL=schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAClD,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AACpC,OAAO,EAAE,YAAY,EAAE,CAAC;AACxB,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,EAAgB;IACrD,EAAE,CAAC,IAAI,CAAC,mDAAmD,CAAC,CAAC;IAC7D,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC;IACnC,SAAS,CAAC;QACR,IAAI,CAAC;YACH,EAAE,CAAC,IAAI,CAAC,0BAA0B,CAAC,CAAC;YACpC,MAAM;QACR,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,8EAA8E;YAC9E,IACE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAE,KAA8B,CAAC,OAAO,IAAI,CAAC,CAAC;gBAC9D,IAAI,CAAC,GAAG,EAAE,IAAI,QAAQ;gBAEtB,MAAM,KAAK,CAAC;YACd,MAAM,UAAU,CAAC,EAAE,CAAC,CAAC;QACvB,CAAC;IACH,CAAC;IACD,EAAE,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;IAC3B,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,CACpB,EAAE,CAAC,OAAO,CAAC,qBAAqB,CAAC,CAAC,GAAG,EAAG,CAAC,YAAY,CACtD,CAAC;QACF,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC;YAC9B,IAAI,CAAC,sBAAsB,EAAE,mCAAmC,CAAC,CAAC;QACpE,IAAI,OAAO,KAAK,CAAC;YAAE,SAAS,CAAC,EAAE,EAAE,YAAY,CAAC,CAAC;;YAC1C,YAAY,CAAC,EAAE,CAAC,CAAC;QACtB,EAAE,CAAC,IAAI,CAAC,+BAA+B,CAAC,CAAC;IAC3C,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QACpB,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,EAAgB;IAC3C,EAAE,CAAC,IAAI,CAAC;;;;;;;;;;;;;GAaP,CAAC,CAAC;IACH,KAAK,MAAM,KAAK,IAAI,CAAC,UAAU,EAAE,GAAG,YAAY,CAAC,EAAE,CAAC;QAClD,EAAE,CAAC,IAAI,CAAC,8BAA8B,KAAK;;;;0CAIL,KAAK,eAAe,KAAK;mCAChC,KAAK,YAAY,KAAK;mCACtB,KAAK,cAAc,KAAK;mCACxB,KAAK,YAAY,KAAK;KACpD,CAAC,CAAC;IACL,CAAC;IACD,EAAE,CAAC,IAAI,CACL,2FAA2F,CAC5F,CAAC;AACJ,CAAC"}
@@ -0,0 +1,14 @@
1
+ import type { DatabaseSync } from "node:sqlite";
2
+ import { type Checkpoint, type RecordKind } from "@tessar/core";
3
+ export declare const recordTables: readonly ["streams", "turns", "model_attempts", "tool_executions", "interrupts"];
4
+ export type VersionTable = RecordKind | "messages";
5
+ type VersionInput = {
6
+ id: string;
7
+ body: string;
8
+ position?: number;
9
+ };
10
+ export declare function writeVersions(db: DatabaseSync, table: VersionTable, threadId: string, revision: number, entries: readonly VersionInput[], replace?: boolean): void;
11
+ export declare function readVersions<T>(db: DatabaseSync, table: VersionTable, threadId: string, revision: number): T[];
12
+ export declare function writeCheckpoint(db: DatabaseSync, cp: Checkpoint): void;
13
+ export declare function hydrateCheckpoint(db: DatabaseSync, body: string): Checkpoint;
14
+ export {};
@@ -0,0 +1,54 @@
1
+ import { canonicalJson, immutable, checkpointSafety, } from "@tessar/core";
2
+ export const recordTables = [
3
+ "streams",
4
+ "turns",
5
+ "model_attempts",
6
+ "tool_executions",
7
+ "interrupts",
8
+ ];
9
+ export function writeVersions(db, table, threadId, revision, entries, replace = false) {
10
+ const current = new Map(db
11
+ .prepare(`SELECT id,body,position FROM ${table} WHERE thread_id=? AND to_revision IS NULL`)
12
+ .all(threadId).map((row) => [row.id, row]));
13
+ for (const entry of entries) {
14
+ const old = current.get(entry.id);
15
+ current.delete(entry.id);
16
+ if (old &&
17
+ old.body === entry.body &&
18
+ old.position === (entry.position ?? null))
19
+ continue;
20
+ if (old)
21
+ db.prepare(`UPDATE ${table} SET to_revision=? WHERE thread_id=? AND id=? AND to_revision IS NULL`).run(revision, threadId, entry.id);
22
+ const value = JSON.parse(entry.body);
23
+ db.prepare(`INSERT INTO ${table}(thread_id,id,from_revision,to_revision,position,stream_id,turn_id,status,sort_date,body) VALUES(?,?,?,NULL,?,?,?,?,?,?)`).run(threadId, entry.id, revision, entry.position ?? null, value.streamId ?? null, value.turnId ?? null, value.status ?? null, value.createdAt ?? value.startedAt ?? "", entry.body);
24
+ }
25
+ if (replace)
26
+ for (const id of current.keys())
27
+ db.prepare(`UPDATE ${table} SET to_revision=? WHERE thread_id=? AND id=? AND to_revision IS NULL`).run(revision, threadId, id);
28
+ }
29
+ export function readVersions(db, table, threadId, revision) {
30
+ return db
31
+ .prepare(`SELECT body FROM ${table} WHERE thread_id=? AND from_revision<=? AND (to_revision IS NULL OR ?<to_revision) ORDER BY ${table === "messages" ? "position" : "sort_date,id COLLATE BINARY"}`)
32
+ .all(threadId, revision, revision).map((row) => immutable(JSON.parse(row.body)));
33
+ }
34
+ export function writeCheckpoint(db, cp) {
35
+ writeVersions(db, "messages", cp.threadId, cp.revision, cp.state.messages.map((message, position) => ({
36
+ id: message.id,
37
+ position,
38
+ body: canonicalJson(message),
39
+ })), true);
40
+ const { messages, ...state } = cp.state;
41
+ const safety = checkpointSafety(cp);
42
+ db.prepare("INSERT INTO checkpoints(id,thread_id,revision,created_at,cause,message_count,forkable,unsafe_reason,body) VALUES(?,?,?,?,?,?,?,?,?)").run(cp.id, cp.threadId, cp.revision, cp.createdAt, cp.cause, messages.length, Number(safety.forkable), safety.unsafeReason, canonicalJson({ ...cp, state }));
43
+ }
44
+ export function hydrateCheckpoint(db, body) {
45
+ const cp = JSON.parse(body);
46
+ return immutable({
47
+ ...cp,
48
+ state: {
49
+ ...cp.state,
50
+ messages: readVersions(db, "messages", cp.threadId, cp.revision),
51
+ },
52
+ });
53
+ }
54
+ //# sourceMappingURL=versions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"versions.js","sourceRoot":"","sources":["../src/versions.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,34 @@
1
1
  {
2
2
  "name": "@tessar/sqlite",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
3
+ "version": "0.1.0",
4
+ "description": "SQLite persistence for Tessar state and checkpoints using Node's built-in SQLite API.",
5
+ "type": "module",
6
+ "files": [
7
+ "dist"
8
+ ],
9
+ "engines": {
10
+ "node": ">=24.14.0"
11
+ },
12
+ "repository": {
13
+ "type": "git",
14
+ "url": "git+https://github.com/hphucdev-04/tessar.git",
15
+ "directory": "packages/sqlite"
16
+ },
17
+ "publishConfig": {
18
+ "access": "public",
19
+ "registry": "https://registry.npmjs.org/"
20
+ },
21
+ "exports": {
22
+ ".": {
23
+ "types": "./dist/index.d.ts",
24
+ "import": "./dist/index.js"
25
+ }
26
+ },
27
+ "dependencies": {
28
+ "@tessar/core": "0.1.0"
29
+ },
30
+ "scripts": {
31
+ "build": "tsc -p tsconfig.json",
32
+ "typecheck": "tsc --noEmit -p tsconfig.json"
33
+ }
6
34
  }