@earendil-works/pi-session-backend-sqlite-node 0.84.4 → 0.85.1

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.
Files changed (106) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/README.md +26 -15
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.js +9 -0
  5. package/dist/index.js.map +1 -1
  6. package/dist/sqlite/index.d.ts +3 -4
  7. package/dist/sqlite/index.d.ts.map +1 -1
  8. package/dist/sqlite/index.js +2 -3
  9. package/dist/sqlite/index.js.map +1 -1
  10. package/dist/sqlite/migrations/001_initial.sql +88 -89
  11. package/dist/sqlite/migrations.d.ts +1 -7
  12. package/dist/sqlite/migrations.d.ts.map +1 -1
  13. package/dist/sqlite/migrations.js +3 -35
  14. package/dist/sqlite/migrations.js.map +1 -1
  15. package/dist/sqlite/repo.d.ts +38 -38
  16. package/dist/sqlite/repo.d.ts.map +1 -1
  17. package/dist/sqlite/repo.js +353 -695
  18. package/dist/sqlite/repo.js.map +1 -1
  19. package/dist/sqlite/session/branch-entries.d.ts +6 -0
  20. package/dist/sqlite/session/branch-entries.d.ts.map +1 -0
  21. package/dist/sqlite/session/branch-entries.js +213 -0
  22. package/dist/sqlite/session/branch-entries.js.map +1 -0
  23. package/dist/sqlite/session/entries.d.ts +24 -0
  24. package/dist/sqlite/session/entries.d.ts.map +1 -0
  25. package/dist/sqlite/session/entries.js +126 -0
  26. package/dist/sqlite/session/entries.js.map +1 -0
  27. package/dist/sqlite/session/session-row.d.ts +23 -0
  28. package/dist/sqlite/session/session-row.d.ts.map +1 -0
  29. package/dist/sqlite/session/session-row.js +69 -0
  30. package/dist/sqlite/session/session-row.js.map +1 -0
  31. package/dist/sqlite/session/session-sequences.d.ts +4 -0
  32. package/dist/sqlite/session/session-sequences.d.ts.map +1 -0
  33. package/dist/sqlite/session/session-sequences.js +13 -0
  34. package/dist/sqlite/session/session-sequences.js.map +1 -0
  35. package/dist/sqlite/session/session-stats.d.ts +6 -0
  36. package/dist/sqlite/session/session-stats.d.ts.map +1 -0
  37. package/dist/sqlite/session/session-stats.js +39 -0
  38. package/dist/sqlite/session/session-stats.js.map +1 -0
  39. package/dist/sqlite/session/usage-ledger.d.ts +20 -0
  40. package/dist/sqlite/session/usage-ledger.d.ts.map +1 -0
  41. package/dist/sqlite/session/usage-ledger.js +50 -0
  42. package/dist/sqlite/session/usage-ledger.js.map +1 -0
  43. package/dist/sqlite/session/values.d.ts +23 -0
  44. package/dist/sqlite/session/values.d.ts.map +1 -0
  45. package/dist/sqlite/session/values.js +91 -0
  46. package/dist/sqlite/session/values.js.map +1 -0
  47. package/dist/sqlite/session.d.ts +42 -0
  48. package/dist/sqlite/session.d.ts.map +1 -0
  49. package/dist/sqlite/session.js +163 -0
  50. package/dist/sqlite/session.js.map +1 -0
  51. package/dist/sqlite/storage.d.ts +38 -0
  52. package/dist/sqlite/storage.d.ts.map +1 -0
  53. package/dist/sqlite/storage.js +161 -0
  54. package/dist/sqlite/storage.js.map +1 -0
  55. package/dist/sqlite/types.d.ts +6 -22
  56. package/dist/sqlite/types.d.ts.map +1 -1
  57. package/dist/sqlite/types.js.map +1 -1
  58. package/package.json +5 -4
  59. package/dist/sqlite/branch-cache.d.ts +0 -6
  60. package/dist/sqlite/branch-cache.d.ts.map +0 -1
  61. package/dist/sqlite/branch-cache.js +0 -70
  62. package/dist/sqlite/branch-cache.js.map +0 -1
  63. package/dist/sqlite/search-backend.d.ts +0 -14
  64. package/dist/sqlite/search-backend.d.ts.map +0 -1
  65. package/dist/sqlite/search-backend.js +0 -153
  66. package/dist/sqlite/search-backend.js.map +0 -1
  67. package/dist/sqlite/storage/branch-entries.d.ts +0 -41
  68. package/dist/sqlite/storage/branch-entries.d.ts.map +0 -1
  69. package/dist/sqlite/storage/branch-entries.js +0 -112
  70. package/dist/sqlite/storage/branch-entries.js.map +0 -1
  71. package/dist/sqlite/storage/branch-tips.d.ts +0 -7
  72. package/dist/sqlite/storage/branch-tips.d.ts.map +0 -1
  73. package/dist/sqlite/storage/branch-tips.js +0 -22
  74. package/dist/sqlite/storage/branch-tips.js.map +0 -1
  75. package/dist/sqlite/storage/entries.d.ts +0 -34
  76. package/dist/sqlite/storage/entries.d.ts.map +0 -1
  77. package/dist/sqlite/storage/entries.js +0 -37
  78. package/dist/sqlite/storage/entries.js.map +0 -1
  79. package/dist/sqlite/storage/facts.d.ts +0 -20
  80. package/dist/sqlite/storage/facts.d.ts.map +0 -1
  81. package/dist/sqlite/storage/facts.js +0 -38
  82. package/dist/sqlite/storage/facts.js.map +0 -1
  83. package/dist/sqlite/storage/lanes.d.ts +0 -35
  84. package/dist/sqlite/storage/lanes.d.ts.map +0 -1
  85. package/dist/sqlite/storage/lanes.js +0 -95
  86. package/dist/sqlite/storage/lanes.js.map +0 -1
  87. package/dist/sqlite/storage/records.d.ts +0 -38
  88. package/dist/sqlite/storage/records.d.ts.map +0 -1
  89. package/dist/sqlite/storage/records.js +0 -49
  90. package/dist/sqlite/storage/records.js.map +0 -1
  91. package/dist/sqlite/storage/session-sequences.d.ts +0 -7
  92. package/dist/sqlite/storage/session-sequences.d.ts.map +0 -1
  93. package/dist/sqlite/storage/session-sequences.js +0 -22
  94. package/dist/sqlite/storage/session-sequences.js.map +0 -1
  95. package/dist/sqlite/storage/session-stats.d.ts +0 -17
  96. package/dist/sqlite/storage/session-stats.d.ts.map +0 -1
  97. package/dist/sqlite/storage/session-stats.js +0 -40
  98. package/dist/sqlite/storage/session-stats.js.map +0 -1
  99. package/dist/sqlite/storage/sessions.d.ts +0 -26
  100. package/dist/sqlite/storage/sessions.d.ts.map +0 -1
  101. package/dist/sqlite/storage/sessions.js +0 -99
  102. package/dist/sqlite/storage/sessions.js.map +0 -1
  103. package/dist/sqlite/storage/writer-leases.d.ts +0 -15
  104. package/dist/sqlite/storage/writer-leases.d.ts.map +0 -1
  105. package/dist/sqlite/storage/writer-leases.js +0 -31
  106. package/dist/sqlite/storage/writer-leases.js.map +0 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.85.1] - 2026-09-05
4
+
5
+ ## [0.85.0] - 2026-09-04
6
+
3
7
  ## [0.84.4] - 2026-08-28
4
8
 
5
9
  ## [0.84.3] - 2026-08-24
package/README.md CHANGED
@@ -1,22 +1,33 @@
1
1
  # @earendil-works/pi-session-backend-sqlite-node
2
2
 
3
- Node sqlite session backend for `@earendil-works/pi-agent-core` sessions. Provides the
4
- `node:sqlite` adapter (`SqliteDatabase` implementation), SQLite session repository,
5
- migrations, materialized views, and optional FTS search.
3
+ Node `node:sqlite` Session backend for `@earendil-works/pi-agent-core`.
6
4
 
7
5
  ```ts
8
- await using repository = new SqliteSessionRepository(options);
9
- const search = createSqliteSessionSearch(options);
10
- const session = await repository.create({ cwd });
11
- await session.appendMessage(message);
6
+ import { BACKGROUND_CONTEXT } from "@earendil-works/pi-agent-core";
7
+ import {
8
+ createNodeSqliteFactory,
9
+ SqliteSessionRepo,
10
+ } from "@earendil-works/pi-session-backend-sqlite-node";
12
11
 
13
- const hits = [];
14
- for await (const hit of search.search("needle")) hits.push(hit);
12
+ const repository = new SqliteSessionRepo({
13
+ directory: "/var/lib/pi/sessions",
14
+ databaseFactory: createNodeSqliteFactory(),
15
+ });
16
+
17
+ const session = await repository.create({}, BACKGROUND_CONTEXT);
18
+ const main = await session.createBranch("main", null, BACKGROUND_CONTEXT);
19
+ await main.appendMessage(
20
+ { role: "user", content: "hello", timestamp: Date.now() },
21
+ BACKGROUND_CONTEXT,
22
+ );
23
+ await session.close(BACKGROUND_CONTEXT);
24
+ await repository.close(BACKGROUND_CONTEXT);
15
25
  ```
16
26
 
17
- The repository lazily owns one shared database connection. Search is an independent
18
- service over the same canonical database: repositories do not expose `search()`.
19
- The FTS table and triggers are created lazily on the first non-blank search; when
20
- FTS is first created, search performs a one-time rebuild from canonical entries.
21
- After that, SQLite triggers keep FTS in sync with canonical entry inserts, deletes,
22
- and payload updates.
27
+ The default layout creates one file per Session under `directory`. IDs containing only ASCII letters, digits, `_`, and `-` retain `{sessionId}.sqlite`; every other ID uses a `~`-prefixed base64url encoding of its UTF-16 code units. The durable ID is unchanged, and returned/listed metadata contains the canonical physical path. Pass `databasePath` to place multiple Sessions in one supported shared container; its parent is created when needed.
28
+
29
+ The database factory distinguishes intentional creation, no-create read-write open, and no-create read-only open. Session `open()` and deletion reject metadata outside the configured repository and never create a missing database. Listing is read-only and best-effort. Forking deliberately permits a foreign source metadata path: it reads that exact existing container read-only and never substitutes an active local Session with the same ID.
30
+
31
+ The host lifecycle, not this backend, guarantees one writable owner per Session. Directly opening the same Session for writes in another process is unsupported. The repository rejects overlapping local create/open/fork/delete ownership for one ID, but implements no cross-process lease, lock, fence, heartbeat, or takeover. The host must close a worker before deletion.
32
+
33
+ A fork of a source open in the same repository queues its snapshot on that source's commit queue. Any other source, including one held open by a live Session worker, uses an independent read-only connection and one deferred WAL transaction; later worker commits may complete while that snapshot remains open. Shared-container deletion removes only the selected Session's rows. Repository close waits for every open Session cleanup attempt before reporting errors. The package does not export a search service or FTS index; search is the separate S3 projection.
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,OAAO,KAAK,EAAE,cAAc,EAAE,qBAAqB,EAAoC,MAAM,mBAAmB,CAAC;AAiGjH,wBAAgB,sBAAsB,CAAC,EAAE,EAAE,YAAY,GAAG,cAAc,CAEvE;AAED,wBAAgB,uBAAuB,IAAI,qBAAqB,CAM/D;AAGD,cAAc,mBAAmB,CAAC","sourcesContent":["import type { SQLInputValue } from \"node:sqlite\";\nimport { DatabaseSync } from \"node:sqlite\";\nimport { sql } from \"./sqlite/sql.ts\";\nimport type { SqliteDatabase, SqliteDatabaseFactory, SqliteRunResult, SqliteStatement } from \"./sqlite/types.ts\";\n\nfunction isNamedParameters(value: unknown): value is Record<string, SQLInputValue> {\n\tif (value === null || typeof value !== \"object\") return false;\n\tif (Array.isArray(value) || ArrayBuffer.isView(value)) return false;\n\treturn true;\n}\n\nfunction isAsyncResult(value: unknown): boolean {\n\treturn value !== null && (typeof value === \"object\" || typeof value === \"function\") && \"then\" in value;\n}\n\nclass NodeSqliteStatement implements SqliteStatement {\n\tprivate readonly statement: ReturnType<DatabaseSync[\"prepare\"]>;\n\n\tconstructor(statement: ReturnType<DatabaseSync[\"prepare\"]>) {\n\t\tthis.statement = statement;\n\t}\n\n\trun(...params: unknown[]): SqliteRunResult {\n\t\tconst [first, ...rest] = params;\n\t\tconst result = isNamedParameters(first)\n\t\t\t? this.statement.run(first, ...(rest as SQLInputValue[]))\n\t\t\t: this.statement.run(...(params as SQLInputValue[]));\n\t\treturn {\n\t\t\tchanges: Number(result.changes),\n\t\t\tlastInsertRowid: result.lastInsertRowid === undefined ? undefined : Number(result.lastInsertRowid),\n\t\t};\n\t}\n\n\tget<TRow extends object>(...params: unknown[]): TRow | undefined {\n\t\tconst [first, ...rest] = params;\n\t\treturn (\n\t\t\tisNamedParameters(first)\n\t\t\t\t? this.statement.get(first, ...(rest as SQLInputValue[]))\n\t\t\t\t: this.statement.get(...(params as SQLInputValue[]))\n\t\t) as TRow | undefined;\n\t}\n\n\tall<TRow extends object>(...params: unknown[]): TRow[] {\n\t\tconst [first, ...rest] = params;\n\t\treturn (\n\t\t\tisNamedParameters(first)\n\t\t\t\t? this.statement.all(first, ...(rest as SQLInputValue[]))\n\t\t\t\t: this.statement.all(...(params as SQLInputValue[]))\n\t\t) as TRow[];\n\t}\n\n\titerate<TRow extends object>(...params: unknown[]): Iterable<TRow> {\n\t\tconst [first, ...rest] = params;\n\t\treturn (\n\t\t\tisNamedParameters(first)\n\t\t\t\t? this.statement.iterate(first, ...(rest as SQLInputValue[]))\n\t\t\t\t: this.statement.iterate(...(params as SQLInputValue[]))\n\t\t) as Iterable<TRow>;\n\t}\n}\n\nclass NodeSqliteDatabase implements SqliteDatabase {\n\tprivate readonly db: DatabaseSync;\n\n\tconstructor(db: DatabaseSync) {\n\t\tthis.db = db;\n\t}\n\n\texec(sql: string): void {\n\t\tthis.db.exec(sql);\n\t}\n\n\tprepare(sql: string): SqliteStatement {\n\t\treturn new NodeSqliteStatement(this.db.prepare(sql));\n\t}\n\n\ttransaction<T>(fn: () => T): T {\n\t\tsql`BEGIN IMMEDIATE`.exec(this);\n\t\ttry {\n\t\t\tconst result = fn();\n\t\t\tif (isAsyncResult(result)) {\n\t\t\t\tthrow new TypeError(\"SQLite transaction callbacks must be synchronous\");\n\t\t\t}\n\t\t\tsql`COMMIT`.exec(this);\n\t\t\treturn result;\n\t\t} catch (error) {\n\t\t\ttry {\n\t\t\t\tsql`ROLLBACK`.exec(this);\n\t\t\t} catch {\n\t\t\t\t// Ignore rollback errors to rethrow original error.\n\t\t\t}\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\tclose(): void {\n\t\tthis.db.close();\n\t}\n}\n\nexport function wrapNodeSqliteDatabase(db: DatabaseSync): SqliteDatabase {\n\treturn new NodeSqliteDatabase(db);\n}\n\nexport function createNodeSqliteFactory(): SqliteDatabaseFactory {\n\treturn {\n\t\tasync open(path: string): Promise<SqliteDatabase> {\n\t\t\treturn new NodeSqliteDatabase(new DatabaseSync(path));\n\t\t},\n\t};\n}\n\n// Re-export the SQLite session backend and types so this package is a complete node-sqlite backend.\nexport * from \"./sqlite/index.ts\";\n"]}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAG3C,OAAO,KAAK,EAAE,cAAc,EAAE,qBAAqB,EAAoC,MAAM,mBAAmB,CAAC;AAiGjH,wBAAgB,sBAAsB,CAAC,EAAE,EAAE,YAAY,GAAG,cAAc,CAEvE;AAED,wBAAgB,uBAAuB,IAAI,qBAAqB,CAc/D;AAGD,cAAc,mBAAmB,CAAC","sourcesContent":["import type { SQLInputValue } from \"node:sqlite\";\nimport { DatabaseSync } from \"node:sqlite\";\nimport { pathToFileURL } from \"node:url\";\nimport { sql } from \"./sqlite/sql.ts\";\nimport type { SqliteDatabase, SqliteDatabaseFactory, SqliteRunResult, SqliteStatement } from \"./sqlite/types.ts\";\n\nfunction isNamedParameters(value: unknown): value is Record<string, SQLInputValue> {\n\tif (value === null || typeof value !== \"object\") return false;\n\tif (Array.isArray(value) || ArrayBuffer.isView(value)) return false;\n\treturn true;\n}\n\nfunction isAsyncResult(value: unknown): boolean {\n\treturn value !== null && (typeof value === \"object\" || typeof value === \"function\") && \"then\" in value;\n}\n\nclass NodeSqliteStatement implements SqliteStatement {\n\tprivate readonly statement: ReturnType<DatabaseSync[\"prepare\"]>;\n\n\tconstructor(statement: ReturnType<DatabaseSync[\"prepare\"]>) {\n\t\tthis.statement = statement;\n\t}\n\n\trun(...params: unknown[]): SqliteRunResult {\n\t\tconst [first, ...rest] = params;\n\t\tconst result = isNamedParameters(first)\n\t\t\t? this.statement.run(first, ...(rest as SQLInputValue[]))\n\t\t\t: this.statement.run(...(params as SQLInputValue[]));\n\t\treturn {\n\t\t\tchanges: Number(result.changes),\n\t\t\tlastInsertRowid: result.lastInsertRowid === undefined ? undefined : Number(result.lastInsertRowid),\n\t\t};\n\t}\n\n\tget<TRow extends object>(...params: unknown[]): TRow | undefined {\n\t\tconst [first, ...rest] = params;\n\t\treturn (\n\t\t\tisNamedParameters(first)\n\t\t\t\t? this.statement.get(first, ...(rest as SQLInputValue[]))\n\t\t\t\t: this.statement.get(...(params as SQLInputValue[]))\n\t\t) as TRow | undefined;\n\t}\n\n\tall<TRow extends object>(...params: unknown[]): TRow[] {\n\t\tconst [first, ...rest] = params;\n\t\treturn (\n\t\t\tisNamedParameters(first)\n\t\t\t\t? this.statement.all(first, ...(rest as SQLInputValue[]))\n\t\t\t\t: this.statement.all(...(params as SQLInputValue[]))\n\t\t) as TRow[];\n\t}\n\n\titerate<TRow extends object>(...params: unknown[]): Iterable<TRow> {\n\t\tconst [first, ...rest] = params;\n\t\treturn (\n\t\t\tisNamedParameters(first)\n\t\t\t\t? this.statement.iterate(first, ...(rest as SQLInputValue[]))\n\t\t\t\t: this.statement.iterate(...(params as SQLInputValue[]))\n\t\t) as Iterable<TRow>;\n\t}\n}\n\nclass NodeSqliteDatabase implements SqliteDatabase {\n\tprivate readonly db: DatabaseSync;\n\n\tconstructor(db: DatabaseSync) {\n\t\tthis.db = db;\n\t}\n\n\texec(sql: string): void {\n\t\tthis.db.exec(sql);\n\t}\n\n\tprepare(sql: string): SqliteStatement {\n\t\treturn new NodeSqliteStatement(this.db.prepare(sql));\n\t}\n\n\ttransaction<T>(fn: () => T): T {\n\t\tsql`BEGIN IMMEDIATE`.exec(this);\n\t\ttry {\n\t\t\tconst result = fn();\n\t\t\tif (isAsyncResult(result)) {\n\t\t\t\tthrow new TypeError(\"SQLite transaction callbacks must be synchronous\");\n\t\t\t}\n\t\t\tsql`COMMIT`.exec(this);\n\t\t\treturn result;\n\t\t} catch (error) {\n\t\t\ttry {\n\t\t\t\tsql`ROLLBACK`.exec(this);\n\t\t\t} catch {\n\t\t\t\t// Ignore rollback errors to rethrow original error.\n\t\t\t}\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\tclose(): void {\n\t\tthis.db.close();\n\t}\n}\n\nexport function wrapNodeSqliteDatabase(db: DatabaseSync): SqliteDatabase {\n\treturn new NodeSqliteDatabase(db);\n}\n\nexport function createNodeSqliteFactory(): SqliteDatabaseFactory {\n\treturn {\n\t\tasync open(path: string): Promise<SqliteDatabase> {\n\t\t\treturn new NodeSqliteDatabase(new DatabaseSync(path));\n\t\t},\n\t\tasync openExisting(path: string): Promise<SqliteDatabase> {\n\t\t\tconst url = pathToFileURL(path);\n\t\t\turl.searchParams.set(\"mode\", \"rw\");\n\t\t\treturn new NodeSqliteDatabase(new DatabaseSync(url));\n\t\t},\n\t\tasync openReadOnly(path: string): Promise<SqliteDatabase> {\n\t\t\treturn new NodeSqliteDatabase(new DatabaseSync(path, { readOnly: true }));\n\t\t},\n\t};\n}\n\n// Re-export the SQLite session backend and types so this package is a complete node-sqlite backend.\nexport * from \"./sqlite/index.ts\";\n"]}
package/dist/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { DatabaseSync } from "node:sqlite";
2
+ import { pathToFileURL } from "node:url";
2
3
  import { sql } from "./sqlite/sql.js";
3
4
  function isNamedParameters(value) {
4
5
  if (value === null || typeof value !== "object")
@@ -87,6 +88,14 @@ export function createNodeSqliteFactory() {
87
88
  async open(path) {
88
89
  return new NodeSqliteDatabase(new DatabaseSync(path));
89
90
  },
91
+ async openExisting(path) {
92
+ const url = pathToFileURL(path);
93
+ url.searchParams.set("mode", "rw");
94
+ return new NodeSqliteDatabase(new DatabaseSync(url));
95
+ },
96
+ async openReadOnly(path) {
97
+ return new NodeSqliteDatabase(new DatabaseSync(path, { readOnly: true }));
98
+ },
90
99
  };
91
100
  }
92
101
  // Re-export the SQLite session backend and types so this package is a complete node-sqlite backend.
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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","sourcesContent":["import type { SQLInputValue } from \"node:sqlite\";\nimport { DatabaseSync } from \"node:sqlite\";\nimport { sql } from \"./sqlite/sql.ts\";\nimport type { SqliteDatabase, SqliteDatabaseFactory, SqliteRunResult, SqliteStatement } from \"./sqlite/types.ts\";\n\nfunction isNamedParameters(value: unknown): value is Record<string, SQLInputValue> {\n\tif (value === null || typeof value !== \"object\") return false;\n\tif (Array.isArray(value) || ArrayBuffer.isView(value)) return false;\n\treturn true;\n}\n\nfunction isAsyncResult(value: unknown): boolean {\n\treturn value !== null && (typeof value === \"object\" || typeof value === \"function\") && \"then\" in value;\n}\n\nclass NodeSqliteStatement implements SqliteStatement {\n\tprivate readonly statement: ReturnType<DatabaseSync[\"prepare\"]>;\n\n\tconstructor(statement: ReturnType<DatabaseSync[\"prepare\"]>) {\n\t\tthis.statement = statement;\n\t}\n\n\trun(...params: unknown[]): SqliteRunResult {\n\t\tconst [first, ...rest] = params;\n\t\tconst result = isNamedParameters(first)\n\t\t\t? this.statement.run(first, ...(rest as SQLInputValue[]))\n\t\t\t: this.statement.run(...(params as SQLInputValue[]));\n\t\treturn {\n\t\t\tchanges: Number(result.changes),\n\t\t\tlastInsertRowid: result.lastInsertRowid === undefined ? undefined : Number(result.lastInsertRowid),\n\t\t};\n\t}\n\n\tget<TRow extends object>(...params: unknown[]): TRow | undefined {\n\t\tconst [first, ...rest] = params;\n\t\treturn (\n\t\t\tisNamedParameters(first)\n\t\t\t\t? this.statement.get(first, ...(rest as SQLInputValue[]))\n\t\t\t\t: this.statement.get(...(params as SQLInputValue[]))\n\t\t) as TRow | undefined;\n\t}\n\n\tall<TRow extends object>(...params: unknown[]): TRow[] {\n\t\tconst [first, ...rest] = params;\n\t\treturn (\n\t\t\tisNamedParameters(first)\n\t\t\t\t? this.statement.all(first, ...(rest as SQLInputValue[]))\n\t\t\t\t: this.statement.all(...(params as SQLInputValue[]))\n\t\t) as TRow[];\n\t}\n\n\titerate<TRow extends object>(...params: unknown[]): Iterable<TRow> {\n\t\tconst [first, ...rest] = params;\n\t\treturn (\n\t\t\tisNamedParameters(first)\n\t\t\t\t? this.statement.iterate(first, ...(rest as SQLInputValue[]))\n\t\t\t\t: this.statement.iterate(...(params as SQLInputValue[]))\n\t\t) as Iterable<TRow>;\n\t}\n}\n\nclass NodeSqliteDatabase implements SqliteDatabase {\n\tprivate readonly db: DatabaseSync;\n\n\tconstructor(db: DatabaseSync) {\n\t\tthis.db = db;\n\t}\n\n\texec(sql: string): void {\n\t\tthis.db.exec(sql);\n\t}\n\n\tprepare(sql: string): SqliteStatement {\n\t\treturn new NodeSqliteStatement(this.db.prepare(sql));\n\t}\n\n\ttransaction<T>(fn: () => T): T {\n\t\tsql`BEGIN IMMEDIATE`.exec(this);\n\t\ttry {\n\t\t\tconst result = fn();\n\t\t\tif (isAsyncResult(result)) {\n\t\t\t\tthrow new TypeError(\"SQLite transaction callbacks must be synchronous\");\n\t\t\t}\n\t\t\tsql`COMMIT`.exec(this);\n\t\t\treturn result;\n\t\t} catch (error) {\n\t\t\ttry {\n\t\t\t\tsql`ROLLBACK`.exec(this);\n\t\t\t} catch {\n\t\t\t\t// Ignore rollback errors to rethrow original error.\n\t\t\t}\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\tclose(): void {\n\t\tthis.db.close();\n\t}\n}\n\nexport function wrapNodeSqliteDatabase(db: DatabaseSync): SqliteDatabase {\n\treturn new NodeSqliteDatabase(db);\n}\n\nexport function createNodeSqliteFactory(): SqliteDatabaseFactory {\n\treturn {\n\t\tasync open(path: string): Promise<SqliteDatabase> {\n\t\t\treturn new NodeSqliteDatabase(new DatabaseSync(path));\n\t\t},\n\t};\n}\n\n// Re-export the SQLite session backend and types so this package is a complete node-sqlite backend.\nexport * from \"./sqlite/index.ts\";\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,GAAG,EAAE,MAAM,iBAAiB,CAAC;AAGtC,SAAS,iBAAiB,CAAC,KAAc,EAA0C;IAClF,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IAC9D,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,WAAW,CAAC,MAAM,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IACpE,OAAO,IAAI,CAAC;AAAA,CACZ;AAED,SAAS,aAAa,CAAC,KAAc,EAAW;IAC/C,OAAO,KAAK,KAAK,IAAI,IAAI,CAAC,OAAO,KAAK,KAAK,QAAQ,IAAI,OAAO,KAAK,KAAK,UAAU,CAAC,IAAI,MAAM,IAAI,KAAK,CAAC;AAAA,CACvG;AAED,MAAM,mBAAmB;IACP,SAAS,CAAsC;IAEhE,YAAY,SAA8C,EAAE;QAC3D,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;IAAA,CAC3B;IAED,GAAG,CAAC,GAAG,MAAiB,EAAmB;QAC1C,MAAM,CAAC,KAAK,EAAE,GAAG,IAAI,CAAC,GAAG,MAAM,CAAC;QAChC,MAAM,MAAM,GAAG,iBAAiB,CAAC,KAAK,CAAC;YACtC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,EAAE,GAAI,IAAwB,CAAC;YACzD,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,GAAI,MAA0B,CAAC,CAAC;QACtD,OAAO;YACN,OAAO,EAAE,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC;YAC/B,eAAe,EAAE,MAAM,CAAC,eAAe,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,eAAe,CAAC;SAClG,CAAC;IAAA,CACF;IAED,GAAG,CAAsB,GAAG,MAAiB,EAAoB;QAChE,MAAM,CAAC,KAAK,EAAE,GAAG,IAAI,CAAC,GAAG,MAAM,CAAC;QAChC,OAAO,CACN,iBAAiB,CAAC,KAAK,CAAC;YACvB,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,EAAE,GAAI,IAAwB,CAAC;YACzD,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,GAAI,MAA0B,CAAC,CACjC,CAAC;IAAA,CACtB;IAED,GAAG,CAAsB,GAAG,MAAiB,EAAU;QACtD,MAAM,CAAC,KAAK,EAAE,GAAG,IAAI,CAAC,GAAG,MAAM,CAAC;QAChC,OAAO,CACN,iBAAiB,CAAC,KAAK,CAAC;YACvB,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,EAAE,GAAI,IAAwB,CAAC;YACzD,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,GAAI,MAA0B,CAAC,CAC3C,CAAC;IAAA,CACZ;IAED,OAAO,CAAsB,GAAG,MAAiB,EAAkB;QAClE,MAAM,CAAC,KAAK,EAAE,GAAG,IAAI,CAAC,GAAG,MAAM,CAAC;QAChC,OAAO,CACN,iBAAiB,CAAC,KAAK,CAAC;YACvB,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,KAAK,EAAE,GAAI,IAAwB,CAAC;YAC7D,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,GAAI,MAA0B,CAAC,CACvC,CAAC;IAAA,CACpB;CACD;AAED,MAAM,kBAAkB;IACN,EAAE,CAAe;IAElC,YAAY,EAAgB,EAAE;QAC7B,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC;IAAA,CACb;IAED,IAAI,CAAC,GAAW,EAAQ;QACvB,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAAA,CAClB;IAED,OAAO,CAAC,GAAW,EAAmB;QACrC,OAAO,IAAI,mBAAmB,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC;IAAA,CACrD;IAED,WAAW,CAAI,EAAW,EAAK;QAC9B,GAAG,CAAA,iBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAChC,IAAI,CAAC;YACJ,MAAM,MAAM,GAAG,EAAE,EAAE,CAAC;YACpB,IAAI,aAAa,CAAC,MAAM,CAAC,EAAE,CAAC;gBAC3B,MAAM,IAAI,SAAS,CAAC,kDAAkD,CAAC,CAAC;YACzE,CAAC;YACD,GAAG,CAAA,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACvB,OAAO,MAAM,CAAC;QACf,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB,IAAI,CAAC;gBACJ,GAAG,CAAA,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC1B,CAAC;YAAC,MAAM,CAAC;gBACR,oDAAoD;YACrD,CAAC;YACD,MAAM,KAAK,CAAC;QACb,CAAC;IAAA,CACD;IAED,KAAK,GAAS;QACb,IAAI,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC;IAAA,CAChB;CACD;AAED,MAAM,UAAU,sBAAsB,CAAC,EAAgB,EAAkB;IACxE,OAAO,IAAI,kBAAkB,CAAC,EAAE,CAAC,CAAC;AAAA,CAClC;AAED,MAAM,UAAU,uBAAuB,GAA0B;IAChE,OAAO;QACN,KAAK,CAAC,IAAI,CAAC,IAAY,EAA2B;YACjD,OAAO,IAAI,kBAAkB,CAAC,IAAI,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC;QAAA,CACtD;QACD,KAAK,CAAC,YAAY,CAAC,IAAY,EAA2B;YACzD,MAAM,GAAG,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC;YAChC,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;YACnC,OAAO,IAAI,kBAAkB,CAAC,IAAI,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC;QAAA,CACrD;QACD,KAAK,CAAC,YAAY,CAAC,IAAY,EAA2B;YACzD,OAAO,IAAI,kBAAkB,CAAC,IAAI,YAAY,CAAC,IAAI,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;QAAA,CAC1E;KACD,CAAC;AAAA,CACF;AAED,oGAAoG;AACpG,cAAc,mBAAmB,CAAC","sourcesContent":["import type { SQLInputValue } from \"node:sqlite\";\nimport { DatabaseSync } from \"node:sqlite\";\nimport { pathToFileURL } from \"node:url\";\nimport { sql } from \"./sqlite/sql.ts\";\nimport type { SqliteDatabase, SqliteDatabaseFactory, SqliteRunResult, SqliteStatement } from \"./sqlite/types.ts\";\n\nfunction isNamedParameters(value: unknown): value is Record<string, SQLInputValue> {\n\tif (value === null || typeof value !== \"object\") return false;\n\tif (Array.isArray(value) || ArrayBuffer.isView(value)) return false;\n\treturn true;\n}\n\nfunction isAsyncResult(value: unknown): boolean {\n\treturn value !== null && (typeof value === \"object\" || typeof value === \"function\") && \"then\" in value;\n}\n\nclass NodeSqliteStatement implements SqliteStatement {\n\tprivate readonly statement: ReturnType<DatabaseSync[\"prepare\"]>;\n\n\tconstructor(statement: ReturnType<DatabaseSync[\"prepare\"]>) {\n\t\tthis.statement = statement;\n\t}\n\n\trun(...params: unknown[]): SqliteRunResult {\n\t\tconst [first, ...rest] = params;\n\t\tconst result = isNamedParameters(first)\n\t\t\t? this.statement.run(first, ...(rest as SQLInputValue[]))\n\t\t\t: this.statement.run(...(params as SQLInputValue[]));\n\t\treturn {\n\t\t\tchanges: Number(result.changes),\n\t\t\tlastInsertRowid: result.lastInsertRowid === undefined ? undefined : Number(result.lastInsertRowid),\n\t\t};\n\t}\n\n\tget<TRow extends object>(...params: unknown[]): TRow | undefined {\n\t\tconst [first, ...rest] = params;\n\t\treturn (\n\t\t\tisNamedParameters(first)\n\t\t\t\t? this.statement.get(first, ...(rest as SQLInputValue[]))\n\t\t\t\t: this.statement.get(...(params as SQLInputValue[]))\n\t\t) as TRow | undefined;\n\t}\n\n\tall<TRow extends object>(...params: unknown[]): TRow[] {\n\t\tconst [first, ...rest] = params;\n\t\treturn (\n\t\t\tisNamedParameters(first)\n\t\t\t\t? this.statement.all(first, ...(rest as SQLInputValue[]))\n\t\t\t\t: this.statement.all(...(params as SQLInputValue[]))\n\t\t) as TRow[];\n\t}\n\n\titerate<TRow extends object>(...params: unknown[]): Iterable<TRow> {\n\t\tconst [first, ...rest] = params;\n\t\treturn (\n\t\t\tisNamedParameters(first)\n\t\t\t\t? this.statement.iterate(first, ...(rest as SQLInputValue[]))\n\t\t\t\t: this.statement.iterate(...(params as SQLInputValue[]))\n\t\t) as Iterable<TRow>;\n\t}\n}\n\nclass NodeSqliteDatabase implements SqliteDatabase {\n\tprivate readonly db: DatabaseSync;\n\n\tconstructor(db: DatabaseSync) {\n\t\tthis.db = db;\n\t}\n\n\texec(sql: string): void {\n\t\tthis.db.exec(sql);\n\t}\n\n\tprepare(sql: string): SqliteStatement {\n\t\treturn new NodeSqliteStatement(this.db.prepare(sql));\n\t}\n\n\ttransaction<T>(fn: () => T): T {\n\t\tsql`BEGIN IMMEDIATE`.exec(this);\n\t\ttry {\n\t\t\tconst result = fn();\n\t\t\tif (isAsyncResult(result)) {\n\t\t\t\tthrow new TypeError(\"SQLite transaction callbacks must be synchronous\");\n\t\t\t}\n\t\t\tsql`COMMIT`.exec(this);\n\t\t\treturn result;\n\t\t} catch (error) {\n\t\t\ttry {\n\t\t\t\tsql`ROLLBACK`.exec(this);\n\t\t\t} catch {\n\t\t\t\t// Ignore rollback errors to rethrow original error.\n\t\t\t}\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\tclose(): void {\n\t\tthis.db.close();\n\t}\n}\n\nexport function wrapNodeSqliteDatabase(db: DatabaseSync): SqliteDatabase {\n\treturn new NodeSqliteDatabase(db);\n}\n\nexport function createNodeSqliteFactory(): SqliteDatabaseFactory {\n\treturn {\n\t\tasync open(path: string): Promise<SqliteDatabase> {\n\t\t\treturn new NodeSqliteDatabase(new DatabaseSync(path));\n\t\t},\n\t\tasync openExisting(path: string): Promise<SqliteDatabase> {\n\t\t\tconst url = pathToFileURL(path);\n\t\t\turl.searchParams.set(\"mode\", \"rw\");\n\t\t\treturn new NodeSqliteDatabase(new DatabaseSync(url));\n\t\t},\n\t\tasync openReadOnly(path: string): Promise<SqliteDatabase> {\n\t\t\treturn new NodeSqliteDatabase(new DatabaseSync(path, { readOnly: true }));\n\t\t},\n\t};\n}\n\n// Re-export the SQLite session backend and types so this package is a complete node-sqlite backend.\nexport * from \"./sqlite/index.ts\";\n"]}
@@ -1,6 +1,5 @@
1
- export * from "./migrations.ts";
2
- export { SqliteSessionRepository, type SqliteSessionRepositoryOptions, type SqliteWriterLeaseOptions, } from "./repo.ts";
3
- export * from "./search-backend.ts";
1
+ export * from "./repo.ts";
4
2
  export * from "./sql.ts";
5
- export type { SqliteDatabase, SqliteDatabaseFactory, SqliteRunResult, SqliteSessionCreateOptions, SqliteSessionListOptions, SqliteSessionMetadata, SqliteSessionRepositoryEnv, SqliteStatement, } from "./types.ts";
3
+ export * from "./storage.ts";
4
+ export type { SqliteDatabase, SqliteDatabaseFactory, SqliteRunResult, SqliteStatement, } from "./types.ts";
6
5
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/sqlite/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC;AAChC,OAAO,EACN,uBAAuB,EACvB,KAAK,8BAA8B,EACnC,KAAK,wBAAwB,GAC7B,MAAM,WAAW,CAAC;AACnB,cAAc,qBAAqB,CAAC;AACpC,cAAc,UAAU,CAAC;AACzB,YAAY,EACX,cAAc,EACd,qBAAqB,EACrB,eAAe,EACf,0BAA0B,EAC1B,wBAAwB,EACxB,qBAAqB,EACrB,0BAA0B,EAC1B,eAAe,GACf,MAAM,YAAY,CAAC","sourcesContent":["export * from \"./migrations.ts\";\nexport {\n\tSqliteSessionRepository,\n\ttype SqliteSessionRepositoryOptions,\n\ttype SqliteWriterLeaseOptions,\n} from \"./repo.ts\";\nexport * from \"./search-backend.ts\";\nexport * from \"./sql.ts\";\nexport type {\n\tSqliteDatabase,\n\tSqliteDatabaseFactory,\n\tSqliteRunResult,\n\tSqliteSessionCreateOptions,\n\tSqliteSessionListOptions,\n\tSqliteSessionMetadata,\n\tSqliteSessionRepositoryEnv,\n\tSqliteStatement,\n} from \"./types.ts\";\n"]}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/sqlite/index.ts"],"names":[],"mappings":"AAAA,cAAc,WAAW,CAAC;AAC1B,cAAc,UAAU,CAAC;AACzB,cAAc,cAAc,CAAC;AAC7B,YAAY,EACX,cAAc,EACd,qBAAqB,EACrB,eAAe,EACf,eAAe,GACf,MAAM,YAAY,CAAC","sourcesContent":["export * from \"./repo.ts\";\nexport * from \"./sql.ts\";\nexport * from \"./storage.ts\";\nexport type {\n\tSqliteDatabase,\n\tSqliteDatabaseFactory,\n\tSqliteRunResult,\n\tSqliteStatement,\n} from \"./types.ts\";\n"]}
@@ -1,5 +1,4 @@
1
- export * from "./migrations.js";
2
- export { SqliteSessionRepository, } from "./repo.js";
3
- export * from "./search-backend.js";
1
+ export * from "./repo.js";
4
2
  export * from "./sql.js";
3
+ export * from "./storage.js";
5
4
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/sqlite/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC;AAChC,OAAO,EACN,uBAAuB,GAGvB,MAAM,WAAW,CAAC;AACnB,cAAc,qBAAqB,CAAC;AACpC,cAAc,UAAU,CAAC","sourcesContent":["export * from \"./migrations.ts\";\nexport {\n\tSqliteSessionRepository,\n\ttype SqliteSessionRepositoryOptions,\n\ttype SqliteWriterLeaseOptions,\n} from \"./repo.ts\";\nexport * from \"./search-backend.ts\";\nexport * from \"./sql.ts\";\nexport type {\n\tSqliteDatabase,\n\tSqliteDatabaseFactory,\n\tSqliteRunResult,\n\tSqliteSessionCreateOptions,\n\tSqliteSessionListOptions,\n\tSqliteSessionMetadata,\n\tSqliteSessionRepositoryEnv,\n\tSqliteStatement,\n} from \"./types.ts\";\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/sqlite/index.ts"],"names":[],"mappings":"AAAA,cAAc,WAAW,CAAC;AAC1B,cAAc,UAAU,CAAC;AACzB,cAAc,cAAc,CAAC","sourcesContent":["export * from \"./repo.ts\";\nexport * from \"./sql.ts\";\nexport * from \"./storage.ts\";\nexport type {\n\tSqliteDatabase,\n\tSqliteDatabaseFactory,\n\tSqliteRunResult,\n\tSqliteStatement,\n} from \"./types.ts\";\n"]}
@@ -1,122 +1,121 @@
1
+ -- AgentHarness storage format 4 / storageVersion 1.
2
+ -- A SQLite database file is a session container. The current default repo
3
+ -- placement still creates one file per session, but the schema supports any
4
+ -- number of sessions per file by scoping every durable row with session_id.
5
+ -- Authoritative durable state is entries + scalar_values + list_values +
6
+ -- usage_ledger; branch_* and stats columns on sessions are maintained
7
+ -- projections/caches.
8
+
1
9
  CREATE TABLE IF NOT EXISTS sessions (
2
10
  id TEXT PRIMARY KEY,
3
11
  created_at INTEGER NOT NULL,
4
- cwd TEXT NOT NULL,
5
- parent_session_id TEXT NULL,
6
- metadata TEXT NULL
12
+ parent_session_id TEXT,
13
+ storage_version INTEGER NOT NULL,
14
+ metadata TEXT,
15
+ message_count INTEGER NOT NULL,
16
+ usage_payload TEXT NOT NULL,
17
+ next_seq INTEGER NOT NULL
7
18
  ) WITHOUT ROWID;
8
19
 
9
- CREATE INDEX IF NOT EXISTS idx_sessions_created_at ON sessions(created_at DESC);
10
- CREATE INDEX IF NOT EXISTS idx_sessions_cwd_created_at ON sessions(cwd, created_at DESC);
11
-
12
20
  CREATE TABLE IF NOT EXISTS entries (
13
21
  session_id TEXT NOT NULL,
14
- seq INTEGER NOT NULL,
15
22
  id TEXT NOT NULL,
16
- parent_id TEXT NULL,
23
+ parent_id TEXT,
24
+ seq INTEGER NOT NULL,
17
25
  type TEXT NOT NULL,
26
+ custom_type TEXT,
18
27
  timestamp INTEGER NOT NULL,
19
28
  payload TEXT NOT NULL,
20
- PRIMARY KEY (session_id, id),
21
- UNIQUE (session_id, seq)
22
- );
23
-
24
- CREATE INDEX IF NOT EXISTS idx_entries_session_parent ON entries(session_id, parent_id);
25
- CREATE INDEX IF NOT EXISTS idx_entries_session_type_seq ON entries(session_id, type, seq);
26
-
27
- CREATE TABLE IF NOT EXISTS session_sequences (
28
- session_id TEXT PRIMARY KEY,
29
- next_seq INTEGER NOT NULL
29
+ PRIMARY KEY (session_id, id)
30
30
  ) WITHOUT ROWID;
31
31
 
32
- CREATE TABLE IF NOT EXISTS session_stats (
33
- session_id TEXT PRIMARY KEY,
34
- message_count INTEGER NOT NULL,
35
- cached_tokens REAL NOT NULL,
36
- uncached_tokens REAL NOT NULL,
37
- total_tokens REAL NOT NULL,
38
- cost_total REAL NOT NULL
39
- ) WITHOUT ROWID;
32
+ CREATE INDEX IF NOT EXISTS ix_entry_parent ON entries(session_id, parent_id);
33
+ CREATE INDEX IF NOT EXISTS ix_entry_seq ON entries(session_id, seq, type);
40
34
 
41
- -- Derived branch cache. Parent links in entries remain canonical; this cache
42
- -- exists only to make branch scans cheap.
43
- CREATE TABLE IF NOT EXISTS branch_entries (
35
+ CREATE TABLE IF NOT EXISTS scalar_values (
44
36
  session_id TEXT NOT NULL,
45
- branch_id TEXT NOT NULL,
46
- entry_id TEXT NOT NULL,
47
- entry_seq INTEGER NOT NULL,
48
- entry_type TEXT NULL,
49
- custom_type TEXT NULL,
50
- PRIMARY KEY (session_id, branch_id, entry_id)
51
- ) WITHOUT ROWID;
52
-
53
- CREATE INDEX IF NOT EXISTS idx_branch_entries_session_branch_seq ON branch_entries(session_id, branch_id, entry_seq);
54
- CREATE INDEX IF NOT EXISTS idx_branch_entries_session_entry ON branch_entries(session_id, entry_id, branch_id, entry_seq);
55
- CREATE INDEX IF NOT EXISTS idx_branch_entries_session_branch_type_seq ON branch_entries(session_id, branch_id, entry_type, entry_seq);
56
- CREATE INDEX IF NOT EXISTS idx_branch_entries_session_branch_custom_seq ON branch_entries(session_id, branch_id, custom_type, entry_seq);
57
-
58
- CREATE TABLE IF NOT EXISTS lanes (
59
- session_id TEXT NOT NULL,
60
- lane TEXT NOT NULL,
61
- leaf_id TEXT NULL,
62
- open_operation_id TEXT NULL,
63
- PRIMARY KEY (session_id, lane)
37
+ namespace TEXT NOT NULL,
38
+ key TEXT NOT NULL,
39
+ seq INTEGER NOT NULL,
40
+ value TEXT NOT NULL,
41
+ PRIMARY KEY (session_id, namespace, key)
64
42
  ) WITHOUT ROWID;
65
43
 
66
- CREATE TABLE IF NOT EXISTS records (
44
+ CREATE TABLE IF NOT EXISTS list_values (
67
45
  session_id TEXT NOT NULL,
46
+ namespace TEXT NOT NULL,
47
+ key TEXT NOT NULL,
68
48
  seq INTEGER NOT NULL,
69
- id TEXT NOT NULL,
70
- lane TEXT NOT NULL,
71
- run_id TEXT NULL,
72
- type TEXT NOT NULL,
73
- op_kind TEXT NULL,
74
- timestamp INTEGER NOT NULL,
75
- payload TEXT NOT NULL,
76
- PRIMARY KEY (session_id, id),
77
- UNIQUE (session_id, seq)
49
+ value TEXT NOT NULL,
50
+ PRIMARY KEY (session_id, namespace, key, seq)
78
51
  ) WITHOUT ROWID;
79
52
 
80
- CREATE INDEX IF NOT EXISTS idx_records_session_lane_seq ON records(session_id, lane, seq);
81
- CREATE INDEX IF NOT EXISTS idx_records_session_type_seq ON records(session_id, type, seq);
82
- CREATE INDEX IF NOT EXISTS idx_records_session_type_op_kind_seq ON records(session_id, type, op_kind, seq);
83
- CREATE INDEX IF NOT EXISTS idx_records_session_lane_type_seq ON records(session_id, lane, type, seq);
84
- CREATE INDEX IF NOT EXISTS idx_records_session_lane_type_op_kind_seq ON records(session_id, lane, type, op_kind, seq);
85
- CREATE INDEX IF NOT EXISTS idx_records_session_run_id_seq ON records(session_id, run_id, seq);
86
-
87
- CREATE TABLE IF NOT EXISTS lane_moves (
53
+ CREATE TABLE IF NOT EXISTS usage_ledger (
88
54
  session_id TEXT NOT NULL,
55
+ id TEXT NOT NULL,
89
56
  seq INTEGER NOT NULL,
90
- lane TEXT NOT NULL,
91
- leaf_id TEXT NULL,
92
- PRIMARY KEY (session_id, seq)
57
+ entry_id TEXT,
58
+ adjustment INTEGER NOT NULL,
59
+ usage TEXT NOT NULL,
60
+ details TEXT,
61
+ PRIMARY KEY (session_id, id)
93
62
  ) WITHOUT ROWID;
94
63
 
95
-
96
- CREATE TABLE IF NOT EXISTS facts (
64
+ CREATE INDEX IF NOT EXISTS ix_usage_seq ON usage_ledger(session_id, seq);
65
+
66
+ -- Storage-level integrity that spans rows/tables. Primary keys enforce
67
+ -- same-table duplicate ids; these triggers enforce the shared entry/usage id
68
+ -- namespace and ordered parent insertion without a TypeScript preflight pass.
69
+ CREATE TRIGGER IF NOT EXISTS trg_entries_validate
70
+ BEFORE INSERT ON entries
71
+ BEGIN
72
+ SELECT RAISE(ABORT, 'missing parent entry')
73
+ WHERE NEW.parent_id IS NOT NULL
74
+ AND NOT EXISTS (
75
+ SELECT 1 FROM entries WHERE session_id = NEW.session_id AND id = NEW.parent_id
76
+ );
77
+
78
+ SELECT RAISE(ABORT, 'duplicate entry or usage id')
79
+ WHERE EXISTS (
80
+ SELECT 1 FROM usage_ledger WHERE session_id = NEW.session_id AND id = NEW.id
81
+ );
82
+ END;
83
+
84
+ CREATE TRIGGER IF NOT EXISTS trg_usage_ledger_validate
85
+ BEFORE INSERT ON usage_ledger
86
+ BEGIN
87
+ SELECT RAISE(ABORT, 'duplicate entry or usage id')
88
+ WHERE EXISTS (
89
+ SELECT 1 FROM entries WHERE session_id = NEW.session_id AND id = NEW.id
90
+ );
91
+ END;
92
+
93
+ -- Private branch index. Not values/lists; no equivalent in the other backends.
94
+ CREATE TABLE IF NOT EXISTS branch_entries (
97
95
  session_id TEXT NOT NULL,
98
- seq INTEGER NOT NULL,
99
- kind TEXT NOT NULL,
100
- key TEXT NULL,
101
- value TEXT NULL,
102
- PRIMARY KEY (session_id, seq)
96
+ branch_id TEXT NOT NULL,
97
+ entry_id TEXT NOT NULL,
98
+ entry_seq INTEGER NOT NULL,
99
+ entry_type TEXT NOT NULL,
100
+ PRIMARY KEY (session_id, branch_id, entry_id)
103
101
  ) WITHOUT ROWID;
104
102
 
105
- CREATE INDEX IF NOT EXISTS idx_facts_session_kind_key_seq ON facts(session_id, kind, key, seq);
103
+ -- Ordered scans. entry_seq must follow session_id, branch_id directly or ORDER
104
+ -- BY needs a temp b-tree; entry_id and entry_type trail so the index covers
105
+ -- id-only reads.
106
+ CREATE INDEX IF NOT EXISTS ix_be_seq ON branch_entries(session_id, branch_id, entry_seq, entry_id, entry_type);
107
+ -- Type-filtered scans.
108
+ CREATE INDEX IF NOT EXISTS ix_be_type ON branch_entries(session_id, branch_id, entry_type, entry_seq, entry_id);
109
+ CREATE INDEX IF NOT EXISTS ix_be_entry ON branch_entries(session_id, entry_id);
106
110
 
107
- CREATE TABLE IF NOT EXISTS branch_tips (
111
+ CREATE TABLE IF NOT EXISTS branch_meta (
108
112
  session_id TEXT NOT NULL,
109
113
  branch_id TEXT NOT NULL,
110
- tip_id TEXT NOT NULL,
111
- PRIMARY KEY (session_id, tip_id),
112
- UNIQUE (session_id, branch_id)
114
+ tip_entry_id TEXT NOT NULL,
115
+ tip_seq INTEGER NOT NULL,
116
+ base_branch_id TEXT,
117
+ base_seq INTEGER,
118
+ PRIMARY KEY (session_id, branch_id)
113
119
  ) WITHOUT ROWID;
114
120
 
115
- -- Per-session writer claim. The fence prevents an expired owner from writing
116
- -- after a new owner takes over the session.
117
- CREATE TABLE IF NOT EXISTS writer_leases (
118
- session_id TEXT PRIMARY KEY,
119
- owner_id TEXT NOT NULL,
120
- fence INTEGER NOT NULL,
121
- expires_at_ms INTEGER NOT NULL
122
- ) WITHOUT ROWID;
121
+ CREATE UNIQUE INDEX IF NOT EXISTS ix_bm_tip ON branch_meta(session_id, tip_entry_id);
@@ -1,9 +1,3 @@
1
1
  import type { SqliteDatabase } from "./types.ts";
2
- export interface SqliteMigration {
3
- id: string;
4
- order: number;
5
- sql: string;
6
- }
7
- export declare function loadMigrations(): Promise<SqliteMigration[]>;
8
- export declare function applyMigrations(db: SqliteDatabase): Promise<void>;
2
+ export declare function applyInitialSchema(db: SqliteDatabase): Promise<void>;
9
3
  //# sourceMappingURL=migrations.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"migrations.d.ts","sourceRoot":"","sources":["../../src/sqlite/migrations.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjD,MAAM,WAAW,eAAe;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;CACZ;AAMD,wBAAsB,cAAc,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC,CAQjE;AAWD,wBAAsB,eAAe,CAAC,EAAE,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAcvE","sourcesContent":["import { readFile } from \"node:fs/promises\";\nimport { fileURLToPath } from \"node:url\";\nimport { sql } from \"./sql.ts\";\nimport type { SqliteDatabase } from \"./types.ts\";\n\nexport interface SqliteMigration {\n\tid: string;\n\torder: number;\n\tsql: string;\n}\n\nasync function loadMigrationSql(relativePath: string): Promise<string> {\n\treturn readFile(fileURLToPath(new URL(relativePath, import.meta.url)), \"utf8\");\n}\n\nexport async function loadMigrations(): Promise<SqliteMigration[]> {\n\treturn [\n\t\t{\n\t\t\tid: \"001_initial.sql\",\n\t\t\torder: 1,\n\t\t\tsql: await loadMigrationSql(\"./migrations/001_initial.sql\"),\n\t\t},\n\t];\n}\n\nfunction ensureMigrationsTable(db: SqliteDatabase): void {\n\tsql`\nCREATE TABLE IF NOT EXISTS migrations (\n\tid TEXT PRIMARY KEY,\n\tapplied_at TEXT NOT NULL\n);\n`.exec(db);\n}\n\nexport async function applyMigrations(db: SqliteDatabase): Promise<void> {\n\tensureMigrationsTable(db);\n\tconst migrations = await loadMigrations();\n\tconst appliedRows = sql`SELECT id FROM migrations ORDER BY applied_at, id`.all<{ id: string }>(db);\n\tconst applied = new Set(appliedRows.map((row) => row.id));\n\n\tfor (const migration of migrations) {\n\t\tif (applied.has(migration.id)) continue;\n\t\tdb.transaction(() => {\n\t\t\tdb.exec(migration.sql);\n\t\t\tsql`INSERT INTO migrations (id, applied_at) VALUES (${migration.id}, ${new Date().toISOString()})`.run(db);\n\t\t});\n\t\tapplied.add(migration.id);\n\t}\n}\n"]}
1
+ {"version":3,"file":"migrations.d.ts","sourceRoot":"","sources":["../../src/sqlite/migrations.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjD,wBAAsB,kBAAkB,CAAC,EAAE,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAG1E","sourcesContent":["import { readFile } from \"node:fs/promises\";\nimport { fileURLToPath } from \"node:url\";\nimport type { SqliteDatabase } from \"./types.ts\";\n\nexport async function applyInitialSchema(db: SqliteDatabase): Promise<void> {\n\tconst migration = await readFile(fileURLToPath(new URL(\"./migrations/001_initial.sql\", import.meta.url)), \"utf8\");\n\tdb.exec(migration);\n}\n"]}
@@ -1,39 +1,7 @@
1
1
  import { readFile } from "node:fs/promises";
2
2
  import { fileURLToPath } from "node:url";
3
- import { sql } from "./sql.js";
4
- async function loadMigrationSql(relativePath) {
5
- return readFile(fileURLToPath(new URL(relativePath, import.meta.url)), "utf8");
6
- }
7
- export async function loadMigrations() {
8
- return [
9
- {
10
- id: "001_initial.sql",
11
- order: 1,
12
- sql: await loadMigrationSql("./migrations/001_initial.sql"),
13
- },
14
- ];
15
- }
16
- function ensureMigrationsTable(db) {
17
- sql `
18
- CREATE TABLE IF NOT EXISTS migrations (
19
- id TEXT PRIMARY KEY,
20
- applied_at TEXT NOT NULL
21
- );
22
- `.exec(db);
23
- }
24
- export async function applyMigrations(db) {
25
- ensureMigrationsTable(db);
26
- const migrations = await loadMigrations();
27
- const appliedRows = sql `SELECT id FROM migrations ORDER BY applied_at, id`.all(db);
28
- const applied = new Set(appliedRows.map((row) => row.id));
29
- for (const migration of migrations) {
30
- if (applied.has(migration.id))
31
- continue;
32
- db.transaction(() => {
33
- db.exec(migration.sql);
34
- sql `INSERT INTO migrations (id, applied_at) VALUES (${migration.id}, ${new Date().toISOString()})`.run(db);
35
- });
36
- applied.add(migration.id);
37
- }
3
+ export async function applyInitialSchema(db) {
4
+ const migration = await readFile(fileURLToPath(new URL("./migrations/001_initial.sql", import.meta.url)), "utf8");
5
+ db.exec(migration);
38
6
  }
39
7
  //# sourceMappingURL=migrations.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"migrations.js","sourceRoot":"","sources":["../../src/sqlite/migrations.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAS/B,KAAK,UAAU,gBAAgB,CAAC,YAAoB,EAAmB;IACtE,OAAO,QAAQ,CAAC,aAAa,CAAC,IAAI,GAAG,CAAC,YAAY,EAAE,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;AAAA,CAC/E;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,GAA+B;IAClE,OAAO;QACN;YACC,EAAE,EAAE,iBAAiB;YACrB,KAAK,EAAE,CAAC;YACR,GAAG,EAAE,MAAM,gBAAgB,CAAC,8BAA8B,CAAC;SAC3D;KACD,CAAC;AAAA,CACF;AAED,SAAS,qBAAqB,CAAC,EAAkB,EAAQ;IACxD,GAAG,CAAA;;;;;CAKH,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AAAA,CACV;AAED,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,EAAkB,EAAiB;IACxE,qBAAqB,CAAC,EAAE,CAAC,CAAC;IAC1B,MAAM,UAAU,GAAG,MAAM,cAAc,EAAE,CAAC;IAC1C,MAAM,WAAW,GAAG,GAAG,CAAA,mDAAmD,CAAC,GAAG,CAAiB,EAAE,CAAC,CAAC;IACnG,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;IAE1D,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;QACpC,IAAI,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC;YAAE,SAAS;QACxC,EAAE,CAAC,WAAW,CAAC,GAAG,EAAE,CAAC;YACpB,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;YACvB,GAAG,CAAA,mDAAmD,SAAS,CAAC,EAAE,KAAK,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAAA,CAC3G,CAAC,CAAC;QACH,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;IAC3B,CAAC;AAAA,CACD","sourcesContent":["import { readFile } from \"node:fs/promises\";\nimport { fileURLToPath } from \"node:url\";\nimport { sql } from \"./sql.ts\";\nimport type { SqliteDatabase } from \"./types.ts\";\n\nexport interface SqliteMigration {\n\tid: string;\n\torder: number;\n\tsql: string;\n}\n\nasync function loadMigrationSql(relativePath: string): Promise<string> {\n\treturn readFile(fileURLToPath(new URL(relativePath, import.meta.url)), \"utf8\");\n}\n\nexport async function loadMigrations(): Promise<SqliteMigration[]> {\n\treturn [\n\t\t{\n\t\t\tid: \"001_initial.sql\",\n\t\t\torder: 1,\n\t\t\tsql: await loadMigrationSql(\"./migrations/001_initial.sql\"),\n\t\t},\n\t];\n}\n\nfunction ensureMigrationsTable(db: SqliteDatabase): void {\n\tsql`\nCREATE TABLE IF NOT EXISTS migrations (\n\tid TEXT PRIMARY KEY,\n\tapplied_at TEXT NOT NULL\n);\n`.exec(db);\n}\n\nexport async function applyMigrations(db: SqliteDatabase): Promise<void> {\n\tensureMigrationsTable(db);\n\tconst migrations = await loadMigrations();\n\tconst appliedRows = sql`SELECT id FROM migrations ORDER BY applied_at, id`.all<{ id: string }>(db);\n\tconst applied = new Set(appliedRows.map((row) => row.id));\n\n\tfor (const migration of migrations) {\n\t\tif (applied.has(migration.id)) continue;\n\t\tdb.transaction(() => {\n\t\t\tdb.exec(migration.sql);\n\t\t\tsql`INSERT INTO migrations (id, applied_at) VALUES (${migration.id}, ${new Date().toISOString()})`.run(db);\n\t\t});\n\t\tapplied.add(migration.id);\n\t}\n}\n"]}
1
+ {"version":3,"file":"migrations.js","sourceRoot":"","sources":["../../src/sqlite/migrations.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAGzC,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,EAAkB,EAAiB;IAC3E,MAAM,SAAS,GAAG,MAAM,QAAQ,CAAC,aAAa,CAAC,IAAI,GAAG,CAAC,8BAA8B,EAAE,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;IAClH,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;AAAA,CACnB","sourcesContent":["import { readFile } from \"node:fs/promises\";\nimport { fileURLToPath } from \"node:url\";\nimport type { SqliteDatabase } from \"./types.ts\";\n\nexport async function applyInitialSchema(db: SqliteDatabase): Promise<void> {\n\tconst migration = await readFile(fileURLToPath(new URL(\"./migrations/001_initial.sql\", import.meta.url)), \"utf8\");\n\tdb.exec(migration);\n}\n"]}
@@ -1,41 +1,41 @@
1
- import { type ForkOptions, Session, type SessionRepo as SessionRepository } from "@earendil-works/pi-agent-core";
2
- import type { SqliteDatabaseFactory, SqliteSessionCreateOptions, SqliteSessionListOptions, SqliteSessionMetadata, SqliteSessionRepositoryEnv } from "./types.ts";
3
- export interface SqliteWriterLeaseOptions {
4
- /** Time without a successful heartbeat before another writer may take over. Default: 30 seconds. */
5
- ttlMs?: number;
6
- /** Idle heartbeat cadence. Default: 10 seconds. Must be less than ttlMs. */
7
- heartbeatIntervalMs?: number;
1
+ import type { Context, ForkOptions, SessionCreateOptions } from "@earendil-works/pi-agent-core";
2
+ import { type SqliteSessionMetadata } from "./session/session-row.ts";
3
+ import { SqliteOpenSession } from "./session.ts";
4
+ import type { SqliteDatabaseFactory } from "./types.ts";
5
+ export declare const SQLITE_STORAGE_VERSION = 1;
6
+ export declare const SQLITE_SESSION_EXTENSION = ".sqlite";
7
+ export type SqliteSessionCreateOptions = SessionCreateOptions;
8
+ export interface SqliteSessionRepoOptions {
9
+ directory: string;
10
+ /** Optional single container path. Defaults to one encoded `${id}.sqlite` file per session under directory. */
11
+ databasePath?: string;
12
+ databaseFactory: SqliteDatabaseFactory;
13
+ now?: () => number;
8
14
  }
9
- export interface SqliteSessionRepositoryOptions {
10
- env: SqliteSessionRepositoryEnv;
11
- sqlite: SqliteDatabaseFactory;
12
- databasePath: string;
13
- writerLease?: SqliteWriterLeaseOptions;
14
- }
15
- export declare class SqliteSessionRepository implements SessionRepository<SqliteSessionMetadata, SqliteSessionCreateOptions, SqliteSessionListOptions>, AsyncDisposable {
16
- private databasePath;
17
- private database;
18
- private databasePromise;
19
- private readonly operations;
20
- private readonly activeStorages;
21
- private readonly options;
22
- private readonly leaseOptions;
23
- constructor(options: SqliteSessionRepositoryOptions);
24
- private releaseStoragesForSession;
25
- private sessionFromLease;
26
- private claimSession;
27
- create(options: SqliteSessionCreateOptions): Promise<Session<SqliteSessionMetadata>>;
28
- open(metadata: SqliteSessionMetadata): Promise<Session<SqliteSessionMetadata>>;
29
- /** Rebuilds this session's private branch-read cache from canonical entry parent links. */
30
- repairBranchCache(metadata: SqliteSessionMetadata): Promise<void>;
31
- /** Reads the session catalog without acquiring or renewing per-session writer leases. */
32
- list(options?: SqliteSessionListOptions): Promise<SqliteSessionMetadata[]>;
33
- delete(metadata: SqliteSessionMetadata): Promise<void>;
34
- fork(source: SqliteSessionMetadata, options: ForkOptions & SqliteSessionCreateOptions): Promise<Session<SqliteSessionMetadata>>;
35
- close(): Promise<void>;
36
- [Symbol.asyncDispose](): Promise<void>;
37
- private getDatabasePath;
38
- private getDatabase;
39
- private openDatabase;
15
+ export declare class SqliteSessionRepo {
16
+ private readonly directory;
17
+ private readonly databasePath;
18
+ private readonly databaseFactory;
19
+ private readonly now;
20
+ private readonly pendingIds;
21
+ private readonly openStorages;
22
+ private readonly openSessions;
23
+ private closed;
24
+ private closePromise;
25
+ constructor(options: SqliteSessionRepoOptions);
26
+ create(options: SqliteSessionCreateOptions | undefined, _context: Context): Promise<SqliteOpenSession>;
27
+ open(metadata: SqliteSessionMetadata, _context: Context): Promise<SqliteOpenSession>;
28
+ list(_options: undefined, _context: Context): Promise<SqliteSessionMetadata[]>;
29
+ delete(metadata: SqliteSessionMetadata, _context: Context): Promise<void>;
30
+ fork(source: SqliteSessionMetadata, options: ForkOptions, context: Context): Promise<SqliteOpenSession>;
31
+ close(context: Context): Promise<void>;
32
+ private createForkSnapshotFromExternalSource;
33
+ private closeOpenSessions;
34
+ private openStorageBackedSession;
35
+ private repositoryPathForMetadata;
36
+ private reserveId;
37
+ private pathForSession;
38
+ private usesSharedDatabase;
39
+ private assertOpen;
40
40
  }
41
41
  //# sourceMappingURL=repo.d.ts.map