@earendil-works/pi-session-backend-sqlite-node 0.84.4 → 0.85.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/CHANGELOG.md +2 -0
- package/README.md +26 -15
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -1
- package/dist/sqlite/index.d.ts +3 -4
- package/dist/sqlite/index.d.ts.map +1 -1
- package/dist/sqlite/index.js +2 -3
- package/dist/sqlite/index.js.map +1 -1
- package/dist/sqlite/migrations/001_initial.sql +88 -89
- package/dist/sqlite/migrations.d.ts +1 -7
- package/dist/sqlite/migrations.d.ts.map +1 -1
- package/dist/sqlite/migrations.js +3 -35
- package/dist/sqlite/migrations.js.map +1 -1
- package/dist/sqlite/repo.d.ts +38 -38
- package/dist/sqlite/repo.d.ts.map +1 -1
- package/dist/sqlite/repo.js +353 -695
- package/dist/sqlite/repo.js.map +1 -1
- package/dist/sqlite/session/branch-entries.d.ts +6 -0
- package/dist/sqlite/session/branch-entries.d.ts.map +1 -0
- package/dist/sqlite/session/branch-entries.js +213 -0
- package/dist/sqlite/session/branch-entries.js.map +1 -0
- package/dist/sqlite/session/entries.d.ts +24 -0
- package/dist/sqlite/session/entries.d.ts.map +1 -0
- package/dist/sqlite/session/entries.js +126 -0
- package/dist/sqlite/session/entries.js.map +1 -0
- package/dist/sqlite/session/session-row.d.ts +23 -0
- package/dist/sqlite/session/session-row.d.ts.map +1 -0
- package/dist/sqlite/session/session-row.js +69 -0
- package/dist/sqlite/session/session-row.js.map +1 -0
- package/dist/sqlite/session/session-sequences.d.ts +4 -0
- package/dist/sqlite/session/session-sequences.d.ts.map +1 -0
- package/dist/sqlite/session/session-sequences.js +13 -0
- package/dist/sqlite/session/session-sequences.js.map +1 -0
- package/dist/sqlite/session/session-stats.d.ts +6 -0
- package/dist/sqlite/session/session-stats.d.ts.map +1 -0
- package/dist/sqlite/session/session-stats.js +39 -0
- package/dist/sqlite/session/session-stats.js.map +1 -0
- package/dist/sqlite/session/usage-ledger.d.ts +20 -0
- package/dist/sqlite/session/usage-ledger.d.ts.map +1 -0
- package/dist/sqlite/session/usage-ledger.js +50 -0
- package/dist/sqlite/session/usage-ledger.js.map +1 -0
- package/dist/sqlite/session/values.d.ts +23 -0
- package/dist/sqlite/session/values.d.ts.map +1 -0
- package/dist/sqlite/session/values.js +91 -0
- package/dist/sqlite/session/values.js.map +1 -0
- package/dist/sqlite/session.d.ts +42 -0
- package/dist/sqlite/session.d.ts.map +1 -0
- package/dist/sqlite/session.js +163 -0
- package/dist/sqlite/session.js.map +1 -0
- package/dist/sqlite/storage.d.ts +38 -0
- package/dist/sqlite/storage.d.ts.map +1 -0
- package/dist/sqlite/storage.js +161 -0
- package/dist/sqlite/storage.js.map +1 -0
- package/dist/sqlite/types.d.ts +6 -22
- package/dist/sqlite/types.d.ts.map +1 -1
- package/dist/sqlite/types.js.map +1 -1
- package/package.json +5 -4
- package/dist/sqlite/branch-cache.d.ts +0 -6
- package/dist/sqlite/branch-cache.d.ts.map +0 -1
- package/dist/sqlite/branch-cache.js +0 -70
- package/dist/sqlite/branch-cache.js.map +0 -1
- package/dist/sqlite/search-backend.d.ts +0 -14
- package/dist/sqlite/search-backend.d.ts.map +0 -1
- package/dist/sqlite/search-backend.js +0 -153
- package/dist/sqlite/search-backend.js.map +0 -1
- package/dist/sqlite/storage/branch-entries.d.ts +0 -41
- package/dist/sqlite/storage/branch-entries.d.ts.map +0 -1
- package/dist/sqlite/storage/branch-entries.js +0 -112
- package/dist/sqlite/storage/branch-entries.js.map +0 -1
- package/dist/sqlite/storage/branch-tips.d.ts +0 -7
- package/dist/sqlite/storage/branch-tips.d.ts.map +0 -1
- package/dist/sqlite/storage/branch-tips.js +0 -22
- package/dist/sqlite/storage/branch-tips.js.map +0 -1
- package/dist/sqlite/storage/entries.d.ts +0 -34
- package/dist/sqlite/storage/entries.d.ts.map +0 -1
- package/dist/sqlite/storage/entries.js +0 -37
- package/dist/sqlite/storage/entries.js.map +0 -1
- package/dist/sqlite/storage/facts.d.ts +0 -20
- package/dist/sqlite/storage/facts.d.ts.map +0 -1
- package/dist/sqlite/storage/facts.js +0 -38
- package/dist/sqlite/storage/facts.js.map +0 -1
- package/dist/sqlite/storage/lanes.d.ts +0 -35
- package/dist/sqlite/storage/lanes.d.ts.map +0 -1
- package/dist/sqlite/storage/lanes.js +0 -95
- package/dist/sqlite/storage/lanes.js.map +0 -1
- package/dist/sqlite/storage/records.d.ts +0 -38
- package/dist/sqlite/storage/records.d.ts.map +0 -1
- package/dist/sqlite/storage/records.js +0 -49
- package/dist/sqlite/storage/records.js.map +0 -1
- package/dist/sqlite/storage/session-sequences.d.ts +0 -7
- package/dist/sqlite/storage/session-sequences.d.ts.map +0 -1
- package/dist/sqlite/storage/session-sequences.js +0 -22
- package/dist/sqlite/storage/session-sequences.js.map +0 -1
- package/dist/sqlite/storage/session-stats.d.ts +0 -17
- package/dist/sqlite/storage/session-stats.d.ts.map +0 -1
- package/dist/sqlite/storage/session-stats.js +0 -40
- package/dist/sqlite/storage/session-stats.js.map +0 -1
- package/dist/sqlite/storage/sessions.d.ts +0 -26
- package/dist/sqlite/storage/sessions.d.ts.map +0 -1
- package/dist/sqlite/storage/sessions.js +0 -99
- package/dist/sqlite/storage/sessions.js.map +0 -1
- package/dist/sqlite/storage/writer-leases.d.ts +0 -15
- package/dist/sqlite/storage/writer-leases.d.ts.map +0 -1
- package/dist/sqlite/storage/writer-leases.js +0 -31
- package/dist/sqlite/storage/writer-leases.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"values.js","sourceRoot":"","sources":["../../../src/sqlite/session/values.ts"],"names":[],"mappings":"AAAA,OAAO,EAGN,sBAAsB,EAItB,KAAK,GACL,MAAM,+BAA+B,CAAC;AACvC,OAAO,EAAiB,GAAG,EAAE,MAAM,WAAW,CAAC;AAe/C,MAAM,UAAU,iBAAiB,CAChC,EAAkB,EAClB,SAAiB,EACjB,SAAiB,EACjB,GAAW,EACX,GAAW,EACX,WAAoB,EACb;IACP,GAAG,CAAA;YACQ,SAAS,KAAK,SAAS,KAAK,GAAG,KAAK,GAAG,KAAK,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC;mGACgB,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;AAAA,CAC3G;AAED,MAAM,UAAU,oBAAoB,CAAC,EAAkB,EAAE,SAAiB,EAAE,SAAiB,EAAE,GAAW,EAAQ;IACjH,GAAG,CAAA;uBACmB,SAAS,oBAAoB,SAAS,cAAc,GAAG,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;AAAA,CACxF;AAED,MAAM,UAAU,kBAAkB,CACjC,EAAkB,EAClB,SAAiB,EACjB,SAAiB,EACjB,GAAW,EACX,GAAW,EACX,OAAgB,EACT;IACP,GAAG,CAAA;YACQ,SAAS,KAAK,SAAS,KAAK,GAAG,KAAK,GAAG,KAAK,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;AAAA,CAC1F;AAED,MAAM,UAAU,mBAAmB,CAAC,EAAkB,EAAE,SAAiB,EAAE,SAAiB,EAAE,GAAW,EAAQ;IAChH,GAAG,CAAA;uBACmB,SAAS,oBAAoB,SAAS,cAAc,GAAG,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;AAAA,CACxF;AAED,SAAS,oBAAoB,CAAI,OAAiB,EAAE,GAAmB,EAAkB;IACxF,IAAI,GAAG,CAAC,SAAS,KAAK,OAAO,CAAC,SAAS,IAAI,GAAG,CAAC,GAAG,KAAK,OAAO,CAAC,GAAG,EAAE,CAAC;QACpE,MAAM,IAAI,KAAK,CAAC,kBAAkB,OAAO,CAAC,SAAS,IAAI,OAAO,CAAC,GAAG,WAAW,GAAG,CAAC,SAAS,IAAI,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC;IAC1G,CAAC;IACD,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,GAAG,CAAC,GAAG,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAM,EAAE,CAAC;AAAA,CACpE;AAED,MAAM,UAAU,kBAAkB,CACjC,EAAkB,EAClB,SAAiB,EACjB,OAAiB,EACY;IAC7B,MAAM,GAAG,GAAG,GAAG,CAAA;uBACO,SAAS,oBAAoB,OAAO,CAAC,SAAS,cAAc,OAAO,CAAC,GAAG,EAAE,CAAC,GAAG,CAClG,EAAE,CACF,CAAC;IACF,OAAO,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,oBAAoB,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;AAAA,CAC1E;AAED,MAAM,UAAU,sBAAsB,CAAC,EAAkB,EAAE,SAAiB,EAA0B;IACrG,OAAO,GAAG,CAAA;uBACY,SAAS,mBAAmB;SAChD,GAAG,CAAiB,EAAE,CAAC;SACvB,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;QACd,OAAO,EAAE,KAAK,CAAU,GAAG,CAAC,SAAS,EAAE,GAAG,CAAC,GAAG,CAAC;QAC/C,GAAG,EAAE,GAAG,CAAC,GAAG;QACZ,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC;KAC5B,CAAC,CAAC,CAAC;AAAA,CACL;AAED,SAAS,kBAAkB,CAAC,MAAc,EAAsB;IAC/D,IAAI,MAAM,KAAK,EAAE;QAAE,OAAO,SAAS,CAAC;IACpC,MAAM,UAAU,GAAG,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACtC,KAAK,IAAI,KAAK,GAAG,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,KAAK,IAAI,CAAC,EAAE,KAAK,EAAE,EAAE,CAAC;QAC7D,MAAM,SAAS,GAAG,UAAU,CAAC,KAAK,CAAC,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC;QACpD,IAAI,SAAS,KAAK,SAAS;YAAE,MAAM,IAAI,KAAK,CAAC,0BAA0B,CAAC,CAAC;QACzE,IAAI,SAAS,GAAG,QAAQ,EAAE,CAAC;YAC1B,MAAM,aAAa,GAAG,SAAS,IAAI,MAAM,IAAI,SAAS,GAAG,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,GAAG,CAAC,CAAC;YACzF,OAAO,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,aAAa,CAAC,aAAa,CAAC,EAAE,CAAC;QACvF,CAAC;IACF,CAAC;IACD,OAAO,SAAS,CAAC;AAAA,CACjB;AAED,MAAM,UAAU,mBAAmB,CAAI,EAAkB,EAAE,SAAiB,EAAE,MAAgB,EAAoB;IACjH,MAAM,UAAU,GAAG,kBAAkB,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IAClD,MAAM,IAAI,GACT,UAAU,KAAK,SAAS;QACvB,CAAC,CAAC,GAAG,CAAA;yBACiB,SAAS,oBAAoB,MAAM,CAAC,SAAS,eAAe,MAAM,CAAC,GAAG;qBAC1E,CAAC,GAAG,CAAiB,EAAE,CAAC;QAC1C,CAAC,CAAC,GAAG,CAAA;yBACiB,SAAS,oBAAoB,MAAM,CAAC,SAAS,eAAe,MAAM,CAAC,GAAG,cAAc,UAAU;qBAClG,CAAC,GAAG,CAAiB,EAAE,CAAC,CAAC;IAC7C,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,oBAAoB,CAAC,KAAK,CAAI,GAAG,CAAC,SAAS,EAAE,GAAG,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;AAAA,CACtF;AAED,MAAM,UAAU,kBAAkB,CAAI,SAAiB,EAAE,OAAqB,EAAE,OAAyB,EAAY;IACpH,MAAM,QAAQ,GAAG,sBAAsB,CAAC,OAAO,CAAC,CAAC;IACjD,IAAI,QAAQ,CAAC,KAAK,KAAK,KAAK,EAAE,CAAC;QAC9B,OAAO,QAAQ,CAAC,MAAM,KAAK,SAAS;YACnC,CAAC,CAAC,GAAG,CAAA;yBACiB,SAAS,oBAAoB,OAAO,CAAC,SAAS,cAAc,OAAO,CAAC,GAAG;6BACnE,QAAQ,CAAC,KAAK,EAAE;YAC1C,CAAC,CAAC,GAAG,CAAA;yBACiB,SAAS,oBAAoB,OAAO,CAAC,SAAS,cAAc,OAAO,CAAC,GAAG,cAAc,QAAQ,CAAC,MAAM,CAAC,GAAG;6BACpG,QAAQ,CAAC,KAAK,EAAE,CAAC;IAC7C,CAAC;IACD,OAAO,QAAQ,CAAC,MAAM,KAAK,SAAS;QACnC,CAAC,CAAC,GAAG,CAAA;wBACiB,SAAS,oBAAoB,OAAO,CAAC,SAAS,cAAc,OAAO,CAAC,GAAG;6BAClE,QAAQ,CAAC,KAAK,EAAE;QAC3C,CAAC,CAAC,GAAG,CAAA;wBACiB,SAAS,oBAAoB,OAAO,CAAC,SAAS,cAAc,OAAO,CAAC,GAAG,cAAc,QAAQ,CAAC,MAAM,CAAC,GAAG;6BACnG,QAAQ,CAAC,KAAK,EAAE,CAAC;AAAA,CAC7C;AAED,MAAM,UAAU,iBAAiB,CAChC,EAAkB,EAClB,SAAiB,EACjB,OAAqB,EACrB,OAAyB,EACN;IACnB,OAAO,kBAAkB,CAAC,SAAS,EAAE,OAAO,EAAE,OAAO,CAAC;SACpD,GAAG,CAAe,EAAE,CAAC;SACrB,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC,GAAG,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAM,EAAE,CAAC,CAAC,CAAC;AAAA,CACtE","sourcesContent":["import {\n\ttype ListElement,\n\ttype ListReadOptions,\n\tresolveListReadOptions,\n\ttype StoredValue,\n\ttype Value,\n\ttype ValueList,\n\tvalue,\n} from \"@earendil-works/pi-agent-core\";\nimport { type SqlQuery, sql } from \"../sql.ts\";\nimport type { SqliteDatabase } from \"../types.ts\";\n\nexport interface ScalarValueRow {\n\tnamespace: string;\n\tkey: string;\n\tseq: number;\n\tvalue: string;\n}\n\nexport interface ListValueRow {\n\tseq: number;\n\tvalue: string;\n}\n\nexport function setScalarValueRow(\n\tdb: SqliteDatabase,\n\tsessionId: string,\n\tnamespace: string,\n\tkey: string,\n\tseq: number,\n\tstoredValue: unknown,\n): void {\n\tsql`INSERT INTO scalar_values (session_id, namespace, key, seq, value)\n\t\tVALUES (${sessionId}, ${namespace}, ${key}, ${seq}, ${JSON.stringify(storedValue)})\n\t\tON CONFLICT(session_id, namespace, key) DO UPDATE SET seq = excluded.seq, value = excluded.value`.run(db);\n}\n\nexport function deleteScalarValueRow(db: SqliteDatabase, sessionId: string, namespace: string, key: string): void {\n\tsql`DELETE FROM scalar_values\n\t\tWHERE session_id = ${sessionId} AND namespace = ${namespace} AND key = ${key}`.run(db);\n}\n\nexport function appendListValueRow(\n\tdb: SqliteDatabase,\n\tsessionId: string,\n\tnamespace: string,\n\tkey: string,\n\tseq: number,\n\telement: unknown,\n): void {\n\tsql`INSERT INTO list_values (session_id, namespace, key, seq, value)\n\t\tVALUES (${sessionId}, ${namespace}, ${key}, ${seq}, ${JSON.stringify(element)})`.run(db);\n}\n\nexport function deleteListValueRows(db: SqliteDatabase, sessionId: string, namespace: string, key: string): void {\n\tsql`DELETE FROM list_values\n\t\tWHERE session_id = ${sessionId} AND namespace = ${namespace} AND key = ${key}`.run(db);\n}\n\nfunction decodeScalarValueRow<T>(address: Value<T>, row: ScalarValueRow): StoredValue<T> {\n\tif (row.namespace !== address.namespace || row.key !== address.key) {\n\t\tthrow new Error(`Expected value ${address.namespace}:${address.key}, found ${row.namespace}:${row.key}`);\n\t}\n\treturn { address, seq: row.seq, value: JSON.parse(row.value) as T };\n}\n\nexport function readScalarValueRow<T>(\n\tdb: SqliteDatabase,\n\tsessionId: string,\n\taddress: Value<T>,\n): StoredValue<T> | undefined {\n\tconst row = sql`SELECT namespace, key, seq, value FROM scalar_values\n\t\tWHERE session_id = ${sessionId} AND namespace = ${address.namespace} AND key = ${address.key}`.get<ScalarValueRow>(\n\t\tdb,\n\t);\n\treturn row === undefined ? undefined : decodeScalarValueRow(address, row);\n}\n\nexport function readAllScalarValueRows(db: SqliteDatabase, sessionId: string): StoredValue<unknown>[] {\n\treturn sql`SELECT namespace, key, seq, value FROM scalar_values\n\t\tWHERE session_id = ${sessionId} ORDER BY seq ASC`\n\t\t.all<ScalarValueRow>(db)\n\t\t.map((row) => ({\n\t\t\taddress: value<unknown>(row.namespace, row.key),\n\t\t\tseq: row.seq,\n\t\t\tvalue: JSON.parse(row.value),\n\t\t}));\n}\n\nfunction nextPrefixBoundary(prefix: string): string | undefined {\n\tif (prefix === \"\") return undefined;\n\tconst codePoints = Array.from(prefix);\n\tfor (let index = codePoints.length - 1; index >= 0; index--) {\n\t\tconst codePoint = codePoints[index]?.codePointAt(0);\n\t\tif (codePoint === undefined) throw new Error(\"Invalid value key prefix\");\n\t\tif (codePoint < 0x10ffff) {\n\t\t\tconst nextCodePoint = codePoint >= 0xd7ff && codePoint < 0xe000 ? 0xe000 : codePoint + 1;\n\t\t\treturn `${codePoints.slice(0, index).join(\"\")}${String.fromCodePoint(nextCodePoint)}`;\n\t\t}\n\t}\n\treturn undefined;\n}\n\nexport function scanScalarValueRows<T>(db: SqliteDatabase, sessionId: string, prefix: Value<T>): StoredValue<T>[] {\n\tconst upperBound = nextPrefixBoundary(prefix.key);\n\tconst rows =\n\t\tupperBound === undefined\n\t\t\t? sql`SELECT namespace, key, seq, value FROM scalar_values\n\t\t\t\tWHERE session_id = ${sessionId} AND namespace = ${prefix.namespace} AND key >= ${prefix.key}\n\t\t\t\tORDER BY key ASC`.all<ScalarValueRow>(db)\n\t\t\t: sql`SELECT namespace, key, seq, value FROM scalar_values\n\t\t\t\tWHERE session_id = ${sessionId} AND namespace = ${prefix.namespace} AND key >= ${prefix.key} AND key < ${upperBound}\n\t\t\t\tORDER BY key ASC`.all<ScalarValueRow>(db);\n\treturn rows.map((row) => decodeScalarValueRow(value<T>(row.namespace, row.key), row));\n}\n\nexport function listValueReadQuery<T>(sessionId: string, address: ValueList<T>, options?: ListReadOptions): SqlQuery {\n\tconst resolved = resolveListReadOptions(options);\n\tif (resolved.order === \"asc\") {\n\t\treturn resolved.cursor === undefined\n\t\t\t? sql`SELECT seq, value FROM list_values\n\t\t\t\tWHERE session_id = ${sessionId} AND namespace = ${address.namespace} AND key = ${address.key}\n\t\t\t\tORDER BY seq ASC LIMIT ${resolved.limit}`\n\t\t\t: sql`SELECT seq, value FROM list_values\n\t\t\t\tWHERE session_id = ${sessionId} AND namespace = ${address.namespace} AND key = ${address.key} AND seq > ${resolved.cursor.seq}\n\t\t\t\tORDER BY seq ASC LIMIT ${resolved.limit}`;\n\t}\n\treturn resolved.cursor === undefined\n\t\t? sql`SELECT seq, value FROM list_values\n\t\t\tWHERE session_id = ${sessionId} AND namespace = ${address.namespace} AND key = ${address.key}\n\t\t\tORDER BY seq DESC LIMIT ${resolved.limit}`\n\t\t: sql`SELECT seq, value FROM list_values\n\t\t\tWHERE session_id = ${sessionId} AND namespace = ${address.namespace} AND key = ${address.key} AND seq < ${resolved.cursor.seq}\n\t\t\tORDER BY seq DESC LIMIT ${resolved.limit}`;\n}\n\nexport function readListValueRows<T>(\n\tdb: SqliteDatabase,\n\tsessionId: string,\n\taddress: ValueList<T>,\n\toptions?: ListReadOptions,\n): ListElement<T>[] {\n\treturn listValueReadQuery(sessionId, address, options)\n\t\t.all<ListValueRow>(db)\n\t\t.map((row) => ({ seq: row.seq, value: JSON.parse(row.value) as T }));\n}\n"]}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { Branch, Context, Entry, EntryQuery, ListElement, ListReadOptions, Session, SessionMutation, SessionMutationCallback, SessionStats, StorageBranchScan, StoredValue, Value, ValueList } from "@earendil-works/pi-agent-core";
|
|
2
|
+
import type { SqliteSessionMetadata } from "./session/session-row.ts";
|
|
3
|
+
export interface SqliteOpenSessionOptions {
|
|
4
|
+
onClose: () => void;
|
|
5
|
+
}
|
|
6
|
+
/** SQLite-specific open-session lifecycle wrapper. */
|
|
7
|
+
export declare class SqliteOpenSession implements Session<SqliteSessionMetadata> {
|
|
8
|
+
readonly metadata: SqliteSessionMetadata;
|
|
9
|
+
readonly idGenerator: Session<SqliteSessionMetadata>["idGenerator"];
|
|
10
|
+
private readonly session;
|
|
11
|
+
private readonly onClose;
|
|
12
|
+
private readonly admitted;
|
|
13
|
+
private readonly closedError;
|
|
14
|
+
private state;
|
|
15
|
+
private closePromise;
|
|
16
|
+
constructor(session: Session<SqliteSessionMetadata>, options: SqliteOpenSessionOptions);
|
|
17
|
+
beginMutation(context: Context): Promise<SessionMutation>;
|
|
18
|
+
mutate<T>(mutation: SessionMutationCallback<T>, context: Context): Promise<T>;
|
|
19
|
+
getEntries(ids: string[], context: Context): Promise<Map<string, Entry>>;
|
|
20
|
+
getEntry(id: string, context: Context): Promise<Entry | undefined>;
|
|
21
|
+
getValue<T>(address: Value<T>, context: Context): Promise<StoredValue<T> | undefined>;
|
|
22
|
+
scanValues<T>(prefix: Value<T>, context: Context): Promise<StoredValue<T>[]>;
|
|
23
|
+
readList<T>(address: ValueList<T>, options: ListReadOptions | undefined, context: Context): Promise<ListElement<T>[]>;
|
|
24
|
+
scanBranch(query: StorageBranchScan, context: Context): Promise<Entry[]>;
|
|
25
|
+
getStats(context: Context): Promise<SessionStats>;
|
|
26
|
+
getName(context: Context): Promise<string | undefined>;
|
|
27
|
+
getLabel(targetId: string, context: Context): Promise<string | undefined>;
|
|
28
|
+
findEntries(query: EntryQuery | undefined, context: Context): Promise<Entry[]>;
|
|
29
|
+
findEntry(query: EntryQuery | undefined, context: Context): Promise<Entry | undefined>;
|
|
30
|
+
branch(name: string, context: Context): Promise<Branch | undefined>;
|
|
31
|
+
createBranch(name: string, at: string | null, context: Context): Promise<Branch>;
|
|
32
|
+
setValue<T>(address: Value<T>, next: NoInfer<T>, context: Context): Promise<void>;
|
|
33
|
+
deleteValue<T>(address: Value<T>, context: Context): Promise<void>;
|
|
34
|
+
appendList<T>(address: ValueList<T>, element: NoInfer<T>, context: Context): Promise<void>;
|
|
35
|
+
deleteList<T>(address: ValueList<T>, context: Context): Promise<void>;
|
|
36
|
+
setName(name: string | undefined, context: Context): Promise<void>;
|
|
37
|
+
setLabel(targetId: string, label: string | undefined, context: Context): Promise<void>;
|
|
38
|
+
close(context: Context): Promise<void>;
|
|
39
|
+
private wrapBranch;
|
|
40
|
+
private admit;
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=session.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../src/sqlite/session.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n\tBranch,\n\tContext,\n\tEntry,\n\tEntryQuery,\n\tListElement,\n\tListReadOptions,\n\tSession,\n\tSessionMutation,\n\tSessionMutationCallback,\n\tSessionStats,\n\tStorageBranchScan,\n\tStoredValue,\n\tValue,\n\tValueList,\n} from \"@earendil-works/pi-agent-core\";\nimport type { SqliteSessionMetadata } from \"./session/session-row.ts\";\n\nexport interface SqliteOpenSessionOptions {\n\tonClose: () => void;\n}\n\n/** SQLite-specific open-session lifecycle wrapper. */\nexport class SqliteOpenSession implements Session<SqliteSessionMetadata> {\n\treadonly metadata: SqliteSessionMetadata;\n\treadonly idGenerator: Session<SqliteSessionMetadata>[\"idGenerator\"];\n\tprivate readonly session: Session<SqliteSessionMetadata>;\n\tprivate readonly onClose: () => void;\n\tprivate readonly admitted = new Set<Promise<unknown>>();\n\tprivate readonly closedError = new Error(\"Session is closed\");\n\tprivate state: \"open\" | \"closing\" | \"closed\" = \"open\";\n\tprivate closePromise: Promise<void> | undefined;\n\n\tconstructor(session: Session<SqliteSessionMetadata>, options: SqliteOpenSessionOptions) {\n\t\tthis.session = session;\n\t\tthis.metadata = session.metadata;\n\t\tthis.idGenerator = session.idGenerator;\n\t\tthis.onClose = options.onClose;\n\t}\n\n\tasync beginMutation(context: Context): Promise<SessionMutation> {\n\t\tlet resolveFinished!: () => void;\n\t\tconst finished = new Promise<void>((resolve) => {\n\t\t\tresolveFinished = resolve;\n\t\t});\n\t\tthis.admitted.add(finished);\n\t\tlet source: SessionMutation;\n\t\ttry {\n\t\t\tsource = await this.admit(() => this.session.beginMutation(context));\n\t\t} catch (error) {\n\t\t\tthis.admitted.delete(finished);\n\t\t\tresolveFinished();\n\t\t\tthrow error;\n\t\t}\n\t\tif (this.state !== \"open\") {\n\t\t\tawait source.end(context);\n\t\t\tthis.admitted.delete(finished);\n\t\t\tresolveFinished();\n\t\t\tthrow this.closedError;\n\t\t}\n\t\tlet ended = false;\n\t\treturn {\n\t\t\tcommit: (writes, commitContext) => source.commit(writes, commitContext),\n\t\t\tend: async (endContext) => {\n\t\t\t\ttry {\n\t\t\t\t\tawait source.end(endContext);\n\t\t\t\t} finally {\n\t\t\t\t\tif (!ended) {\n\t\t\t\t\t\tended = true;\n\t\t\t\t\t\tthis.admitted.delete(finished);\n\t\t\t\t\t\tresolveFinished();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\tgetEntries: (ids, readContext) => source.getEntries(ids, readContext),\n\t\t\tgetStats: (readContext) => source.getStats(readContext),\n\t\t\tgetValue: (address, readContext) => source.getValue(address, readContext),\n\t\t\tscanValues: (prefix, readContext) => source.scanValues(prefix, readContext),\n\t\t\treadList: (address, options, readContext) => source.readList(address, options, readContext),\n\t\t\tscanBranch: (query, readContext) => source.scanBranch(query, readContext),\n\t\t};\n\t}\n\n\tmutate<T>(mutation: SessionMutationCallback<T>, context: Context): Promise<T> {\n\t\treturn this.admit(() =>\n\t\t\tthis.session.mutate((mutator, mutationContext) => {\n\t\t\t\tif (this.state !== \"open\") throw this.closedError;\n\t\t\t\treturn mutation(mutator, mutationContext);\n\t\t\t}, context),\n\t\t);\n\t}\n\n\tgetEntries(ids: string[], context: Context): Promise<Map<string, Entry>> {\n\t\treturn this.admit(() => this.session.getEntries(ids, context));\n\t}\n\n\tgetEntry(id: string, context: Context): Promise<Entry | undefined> {\n\t\treturn this.admit(() => this.session.getEntry(id, context));\n\t}\n\n\tgetValue<T>(address: Value<T>, context: Context): Promise<StoredValue<T> | undefined> {\n\t\treturn this.admit(() => this.session.getValue(address, context));\n\t}\n\n\tscanValues<T>(prefix: Value<T>, context: Context): Promise<StoredValue<T>[]> {\n\t\treturn this.admit(() => this.session.scanValues(prefix, context));\n\t}\n\n\treadList<T>(\n\t\taddress: ValueList<T>,\n\t\toptions: ListReadOptions | undefined,\n\t\tcontext: Context,\n\t): Promise<ListElement<T>[]> {\n\t\treturn this.admit(() => this.session.readList(address, options, context));\n\t}\n\n\tscanBranch(query: StorageBranchScan, context: Context): Promise<Entry[]> {\n\t\treturn this.admit(() => this.session.scanBranch(query, context));\n\t}\n\n\tgetStats(context: Context): Promise<SessionStats> {\n\t\treturn this.admit(() => this.session.getStats(context));\n\t}\n\n\tgetName(context: Context): Promise<string | undefined> {\n\t\treturn this.admit(() => this.session.getName(context));\n\t}\n\n\tgetLabel(targetId: string, context: Context): Promise<string | undefined> {\n\t\treturn this.admit(() => this.session.getLabel(targetId, context));\n\t}\n\n\tfindEntries(query: EntryQuery | undefined, context: Context): Promise<Entry[]> {\n\t\treturn this.admit(() => this.session.findEntries(query, context));\n\t}\n\n\tfindEntry(query: EntryQuery | undefined, context: Context): Promise<Entry | undefined> {\n\t\treturn this.admit(() => this.session.findEntry(query, context));\n\t}\n\n\tasync branch(name: string, context: Context): Promise<Branch | undefined> {\n\t\tconst branch = await this.admit(() => this.session.branch(name, context));\n\t\treturn branch === undefined ? undefined : this.wrapBranch(branch);\n\t}\n\n\tasync createBranch(name: string, at: string | null, context: Context): Promise<Branch> {\n\t\treturn this.wrapBranch(await this.admit(() => this.session.createBranch(name, at, context)));\n\t}\n\n\tsetValue<T>(address: Value<T>, next: NoInfer<T>, context: Context): Promise<void> {\n\t\treturn this.admit(() => this.session.setValue(address, next, context));\n\t}\n\n\tdeleteValue<T>(address: Value<T>, context: Context): Promise<void> {\n\t\treturn this.admit(() => this.session.deleteValue(address, context));\n\t}\n\n\tappendList<T>(address: ValueList<T>, element: NoInfer<T>, context: Context): Promise<void> {\n\t\treturn this.admit(() => this.session.appendList(address, element, context));\n\t}\n\n\tdeleteList<T>(address: ValueList<T>, context: Context): Promise<void> {\n\t\treturn this.admit(() => this.session.deleteList(address, context));\n\t}\n\n\tsetName(name: string | undefined, context: Context): Promise<void> {\n\t\treturn this.admit(() => this.session.setName(name, context));\n\t}\n\n\tsetLabel(targetId: string, label: string | undefined, context: Context): Promise<void> {\n\t\treturn this.admit(() => this.session.setLabel(targetId, label, context));\n\t}\n\n\tclose(context: Context): Promise<void> {\n\t\tif (this.closePromise !== undefined) return this.closePromise;\n\t\tthis.state = \"closing\";\n\t\tthis.closePromise = Promise.allSettled([...this.admitted])\n\t\t\t.then(() => this.session.close(context))\n\t\t\t.finally(() => {\n\t\t\t\tthis.state = \"closed\";\n\t\t\t\tthis.onClose();\n\t\t\t});\n\t\treturn this.closePromise;\n\t}\n\n\tprivate wrapBranch(branch: Branch): Branch {\n\t\treturn {\n\t\t\tname: branch.name,\n\t\t\tgetTipId: (context) => this.admit(() => branch.getTipId(context)),\n\t\t\tfindEntries: (query, context) => this.admit(() => branch.findEntries(query, context)),\n\t\t\tfindEntry: (query, context) => this.admit(() => branch.findEntry(query, context)),\n\t\t\tappendMessage: (message, context) => this.admit(() => branch.appendMessage(message, context)),\n\t\t\tappendCustomEntry: (customType, data, context) =>\n\t\t\t\tthis.admit(() => branch.appendCustomEntry(customType, data, context)),\n\t\t};\n\t}\n\n\tprivate admit<T>(operation: () => Promise<T>): Promise<T> {\n\t\tif (this.state !== \"open\") return Promise.reject(this.closedError);\n\t\tlet result: Promise<T>;\n\t\ttry {\n\t\t\tresult = operation();\n\t\t} catch (error) {\n\t\t\tresult = Promise.reject(error);\n\t\t}\n\t\tthis.admitted.add(result);\n\t\tvoid result.then(\n\t\t\t() => this.admitted.delete(result),\n\t\t\t() => this.admitted.delete(result),\n\t\t);\n\t\treturn result;\n\t}\n}\n"]}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
/** SQLite-specific open-session lifecycle wrapper. */
|
|
2
|
+
export class SqliteOpenSession {
|
|
3
|
+
metadata;
|
|
4
|
+
idGenerator;
|
|
5
|
+
session;
|
|
6
|
+
onClose;
|
|
7
|
+
admitted = new Set();
|
|
8
|
+
closedError = new Error("Session is closed");
|
|
9
|
+
state = "open";
|
|
10
|
+
closePromise;
|
|
11
|
+
constructor(session, options) {
|
|
12
|
+
this.session = session;
|
|
13
|
+
this.metadata = session.metadata;
|
|
14
|
+
this.idGenerator = session.idGenerator;
|
|
15
|
+
this.onClose = options.onClose;
|
|
16
|
+
}
|
|
17
|
+
async beginMutation(context) {
|
|
18
|
+
let resolveFinished;
|
|
19
|
+
const finished = new Promise((resolve) => {
|
|
20
|
+
resolveFinished = resolve;
|
|
21
|
+
});
|
|
22
|
+
this.admitted.add(finished);
|
|
23
|
+
let source;
|
|
24
|
+
try {
|
|
25
|
+
source = await this.admit(() => this.session.beginMutation(context));
|
|
26
|
+
}
|
|
27
|
+
catch (error) {
|
|
28
|
+
this.admitted.delete(finished);
|
|
29
|
+
resolveFinished();
|
|
30
|
+
throw error;
|
|
31
|
+
}
|
|
32
|
+
if (this.state !== "open") {
|
|
33
|
+
await source.end(context);
|
|
34
|
+
this.admitted.delete(finished);
|
|
35
|
+
resolveFinished();
|
|
36
|
+
throw this.closedError;
|
|
37
|
+
}
|
|
38
|
+
let ended = false;
|
|
39
|
+
return {
|
|
40
|
+
commit: (writes, commitContext) => source.commit(writes, commitContext),
|
|
41
|
+
end: async (endContext) => {
|
|
42
|
+
try {
|
|
43
|
+
await source.end(endContext);
|
|
44
|
+
}
|
|
45
|
+
finally {
|
|
46
|
+
if (!ended) {
|
|
47
|
+
ended = true;
|
|
48
|
+
this.admitted.delete(finished);
|
|
49
|
+
resolveFinished();
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
getEntries: (ids, readContext) => source.getEntries(ids, readContext),
|
|
54
|
+
getStats: (readContext) => source.getStats(readContext),
|
|
55
|
+
getValue: (address, readContext) => source.getValue(address, readContext),
|
|
56
|
+
scanValues: (prefix, readContext) => source.scanValues(prefix, readContext),
|
|
57
|
+
readList: (address, options, readContext) => source.readList(address, options, readContext),
|
|
58
|
+
scanBranch: (query, readContext) => source.scanBranch(query, readContext),
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
mutate(mutation, context) {
|
|
62
|
+
return this.admit(() => this.session.mutate((mutator, mutationContext) => {
|
|
63
|
+
if (this.state !== "open")
|
|
64
|
+
throw this.closedError;
|
|
65
|
+
return mutation(mutator, mutationContext);
|
|
66
|
+
}, context));
|
|
67
|
+
}
|
|
68
|
+
getEntries(ids, context) {
|
|
69
|
+
return this.admit(() => this.session.getEntries(ids, context));
|
|
70
|
+
}
|
|
71
|
+
getEntry(id, context) {
|
|
72
|
+
return this.admit(() => this.session.getEntry(id, context));
|
|
73
|
+
}
|
|
74
|
+
getValue(address, context) {
|
|
75
|
+
return this.admit(() => this.session.getValue(address, context));
|
|
76
|
+
}
|
|
77
|
+
scanValues(prefix, context) {
|
|
78
|
+
return this.admit(() => this.session.scanValues(prefix, context));
|
|
79
|
+
}
|
|
80
|
+
readList(address, options, context) {
|
|
81
|
+
return this.admit(() => this.session.readList(address, options, context));
|
|
82
|
+
}
|
|
83
|
+
scanBranch(query, context) {
|
|
84
|
+
return this.admit(() => this.session.scanBranch(query, context));
|
|
85
|
+
}
|
|
86
|
+
getStats(context) {
|
|
87
|
+
return this.admit(() => this.session.getStats(context));
|
|
88
|
+
}
|
|
89
|
+
getName(context) {
|
|
90
|
+
return this.admit(() => this.session.getName(context));
|
|
91
|
+
}
|
|
92
|
+
getLabel(targetId, context) {
|
|
93
|
+
return this.admit(() => this.session.getLabel(targetId, context));
|
|
94
|
+
}
|
|
95
|
+
findEntries(query, context) {
|
|
96
|
+
return this.admit(() => this.session.findEntries(query, context));
|
|
97
|
+
}
|
|
98
|
+
findEntry(query, context) {
|
|
99
|
+
return this.admit(() => this.session.findEntry(query, context));
|
|
100
|
+
}
|
|
101
|
+
async branch(name, context) {
|
|
102
|
+
const branch = await this.admit(() => this.session.branch(name, context));
|
|
103
|
+
return branch === undefined ? undefined : this.wrapBranch(branch);
|
|
104
|
+
}
|
|
105
|
+
async createBranch(name, at, context) {
|
|
106
|
+
return this.wrapBranch(await this.admit(() => this.session.createBranch(name, at, context)));
|
|
107
|
+
}
|
|
108
|
+
setValue(address, next, context) {
|
|
109
|
+
return this.admit(() => this.session.setValue(address, next, context));
|
|
110
|
+
}
|
|
111
|
+
deleteValue(address, context) {
|
|
112
|
+
return this.admit(() => this.session.deleteValue(address, context));
|
|
113
|
+
}
|
|
114
|
+
appendList(address, element, context) {
|
|
115
|
+
return this.admit(() => this.session.appendList(address, element, context));
|
|
116
|
+
}
|
|
117
|
+
deleteList(address, context) {
|
|
118
|
+
return this.admit(() => this.session.deleteList(address, context));
|
|
119
|
+
}
|
|
120
|
+
setName(name, context) {
|
|
121
|
+
return this.admit(() => this.session.setName(name, context));
|
|
122
|
+
}
|
|
123
|
+
setLabel(targetId, label, context) {
|
|
124
|
+
return this.admit(() => this.session.setLabel(targetId, label, context));
|
|
125
|
+
}
|
|
126
|
+
close(context) {
|
|
127
|
+
if (this.closePromise !== undefined)
|
|
128
|
+
return this.closePromise;
|
|
129
|
+
this.state = "closing";
|
|
130
|
+
this.closePromise = Promise.allSettled([...this.admitted])
|
|
131
|
+
.then(() => this.session.close(context))
|
|
132
|
+
.finally(() => {
|
|
133
|
+
this.state = "closed";
|
|
134
|
+
this.onClose();
|
|
135
|
+
});
|
|
136
|
+
return this.closePromise;
|
|
137
|
+
}
|
|
138
|
+
wrapBranch(branch) {
|
|
139
|
+
return {
|
|
140
|
+
name: branch.name,
|
|
141
|
+
getTipId: (context) => this.admit(() => branch.getTipId(context)),
|
|
142
|
+
findEntries: (query, context) => this.admit(() => branch.findEntries(query, context)),
|
|
143
|
+
findEntry: (query, context) => this.admit(() => branch.findEntry(query, context)),
|
|
144
|
+
appendMessage: (message, context) => this.admit(() => branch.appendMessage(message, context)),
|
|
145
|
+
appendCustomEntry: (customType, data, context) => this.admit(() => branch.appendCustomEntry(customType, data, context)),
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
admit(operation) {
|
|
149
|
+
if (this.state !== "open")
|
|
150
|
+
return Promise.reject(this.closedError);
|
|
151
|
+
let result;
|
|
152
|
+
try {
|
|
153
|
+
result = operation();
|
|
154
|
+
}
|
|
155
|
+
catch (error) {
|
|
156
|
+
result = Promise.reject(error);
|
|
157
|
+
}
|
|
158
|
+
this.admitted.add(result);
|
|
159
|
+
void result.then(() => this.admitted.delete(result), () => this.admitted.delete(result));
|
|
160
|
+
return result;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
//# sourceMappingURL=session.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session.js","sourceRoot":"","sources":["../../src/sqlite/session.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n\tBranch,\n\tContext,\n\tEntry,\n\tEntryQuery,\n\tListElement,\n\tListReadOptions,\n\tSession,\n\tSessionMutation,\n\tSessionMutationCallback,\n\tSessionStats,\n\tStorageBranchScan,\n\tStoredValue,\n\tValue,\n\tValueList,\n} from \"@earendil-works/pi-agent-core\";\nimport type { SqliteSessionMetadata } from \"./session/session-row.ts\";\n\nexport interface SqliteOpenSessionOptions {\n\tonClose: () => void;\n}\n\n/** SQLite-specific open-session lifecycle wrapper. */\nexport class SqliteOpenSession implements Session<SqliteSessionMetadata> {\n\treadonly metadata: SqliteSessionMetadata;\n\treadonly idGenerator: Session<SqliteSessionMetadata>[\"idGenerator\"];\n\tprivate readonly session: Session<SqliteSessionMetadata>;\n\tprivate readonly onClose: () => void;\n\tprivate readonly admitted = new Set<Promise<unknown>>();\n\tprivate readonly closedError = new Error(\"Session is closed\");\n\tprivate state: \"open\" | \"closing\" | \"closed\" = \"open\";\n\tprivate closePromise: Promise<void> | undefined;\n\n\tconstructor(session: Session<SqliteSessionMetadata>, options: SqliteOpenSessionOptions) {\n\t\tthis.session = session;\n\t\tthis.metadata = session.metadata;\n\t\tthis.idGenerator = session.idGenerator;\n\t\tthis.onClose = options.onClose;\n\t}\n\n\tasync beginMutation(context: Context): Promise<SessionMutation> {\n\t\tlet resolveFinished!: () => void;\n\t\tconst finished = new Promise<void>((resolve) => {\n\t\t\tresolveFinished = resolve;\n\t\t});\n\t\tthis.admitted.add(finished);\n\t\tlet source: SessionMutation;\n\t\ttry {\n\t\t\tsource = await this.admit(() => this.session.beginMutation(context));\n\t\t} catch (error) {\n\t\t\tthis.admitted.delete(finished);\n\t\t\tresolveFinished();\n\t\t\tthrow error;\n\t\t}\n\t\tif (this.state !== \"open\") {\n\t\t\tawait source.end(context);\n\t\t\tthis.admitted.delete(finished);\n\t\t\tresolveFinished();\n\t\t\tthrow this.closedError;\n\t\t}\n\t\tlet ended = false;\n\t\treturn {\n\t\t\tcommit: (writes, commitContext) => source.commit(writes, commitContext),\n\t\t\tend: async (endContext) => {\n\t\t\t\ttry {\n\t\t\t\t\tawait source.end(endContext);\n\t\t\t\t} finally {\n\t\t\t\t\tif (!ended) {\n\t\t\t\t\t\tended = true;\n\t\t\t\t\t\tthis.admitted.delete(finished);\n\t\t\t\t\t\tresolveFinished();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\tgetEntries: (ids, readContext) => source.getEntries(ids, readContext),\n\t\t\tgetStats: (readContext) => source.getStats(readContext),\n\t\t\tgetValue: (address, readContext) => source.getValue(address, readContext),\n\t\t\tscanValues: (prefix, readContext) => source.scanValues(prefix, readContext),\n\t\t\treadList: (address, options, readContext) => source.readList(address, options, readContext),\n\t\t\tscanBranch: (query, readContext) => source.scanBranch(query, readContext),\n\t\t};\n\t}\n\n\tmutate<T>(mutation: SessionMutationCallback<T>, context: Context): Promise<T> {\n\t\treturn this.admit(() =>\n\t\t\tthis.session.mutate((mutator, mutationContext) => {\n\t\t\t\tif (this.state !== \"open\") throw this.closedError;\n\t\t\t\treturn mutation(mutator, mutationContext);\n\t\t\t}, context),\n\t\t);\n\t}\n\n\tgetEntries(ids: string[], context: Context): Promise<Map<string, Entry>> {\n\t\treturn this.admit(() => this.session.getEntries(ids, context));\n\t}\n\n\tgetEntry(id: string, context: Context): Promise<Entry | undefined> {\n\t\treturn this.admit(() => this.session.getEntry(id, context));\n\t}\n\n\tgetValue<T>(address: Value<T>, context: Context): Promise<StoredValue<T> | undefined> {\n\t\treturn this.admit(() => this.session.getValue(address, context));\n\t}\n\n\tscanValues<T>(prefix: Value<T>, context: Context): Promise<StoredValue<T>[]> {\n\t\treturn this.admit(() => this.session.scanValues(prefix, context));\n\t}\n\n\treadList<T>(\n\t\taddress: ValueList<T>,\n\t\toptions: ListReadOptions | undefined,\n\t\tcontext: Context,\n\t): Promise<ListElement<T>[]> {\n\t\treturn this.admit(() => this.session.readList(address, options, context));\n\t}\n\n\tscanBranch(query: StorageBranchScan, context: Context): Promise<Entry[]> {\n\t\treturn this.admit(() => this.session.scanBranch(query, context));\n\t}\n\n\tgetStats(context: Context): Promise<SessionStats> {\n\t\treturn this.admit(() => this.session.getStats(context));\n\t}\n\n\tgetName(context: Context): Promise<string | undefined> {\n\t\treturn this.admit(() => this.session.getName(context));\n\t}\n\n\tgetLabel(targetId: string, context: Context): Promise<string | undefined> {\n\t\treturn this.admit(() => this.session.getLabel(targetId, context));\n\t}\n\n\tfindEntries(query: EntryQuery | undefined, context: Context): Promise<Entry[]> {\n\t\treturn this.admit(() => this.session.findEntries(query, context));\n\t}\n\n\tfindEntry(query: EntryQuery | undefined, context: Context): Promise<Entry | undefined> {\n\t\treturn this.admit(() => this.session.findEntry(query, context));\n\t}\n\n\tasync branch(name: string, context: Context): Promise<Branch | undefined> {\n\t\tconst branch = await this.admit(() => this.session.branch(name, context));\n\t\treturn branch === undefined ? undefined : this.wrapBranch(branch);\n\t}\n\n\tasync createBranch(name: string, at: string | null, context: Context): Promise<Branch> {\n\t\treturn this.wrapBranch(await this.admit(() => this.session.createBranch(name, at, context)));\n\t}\n\n\tsetValue<T>(address: Value<T>, next: NoInfer<T>, context: Context): Promise<void> {\n\t\treturn this.admit(() => this.session.setValue(address, next, context));\n\t}\n\n\tdeleteValue<T>(address: Value<T>, context: Context): Promise<void> {\n\t\treturn this.admit(() => this.session.deleteValue(address, context));\n\t}\n\n\tappendList<T>(address: ValueList<T>, element: NoInfer<T>, context: Context): Promise<void> {\n\t\treturn this.admit(() => this.session.appendList(address, element, context));\n\t}\n\n\tdeleteList<T>(address: ValueList<T>, context: Context): Promise<void> {\n\t\treturn this.admit(() => this.session.deleteList(address, context));\n\t}\n\n\tsetName(name: string | undefined, context: Context): Promise<void> {\n\t\treturn this.admit(() => this.session.setName(name, context));\n\t}\n\n\tsetLabel(targetId: string, label: string | undefined, context: Context): Promise<void> {\n\t\treturn this.admit(() => this.session.setLabel(targetId, label, context));\n\t}\n\n\tclose(context: Context): Promise<void> {\n\t\tif (this.closePromise !== undefined) return this.closePromise;\n\t\tthis.state = \"closing\";\n\t\tthis.closePromise = Promise.allSettled([...this.admitted])\n\t\t\t.then(() => this.session.close(context))\n\t\t\t.finally(() => {\n\t\t\t\tthis.state = \"closed\";\n\t\t\t\tthis.onClose();\n\t\t\t});\n\t\treturn this.closePromise;\n\t}\n\n\tprivate wrapBranch(branch: Branch): Branch {\n\t\treturn {\n\t\t\tname: branch.name,\n\t\t\tgetTipId: (context) => this.admit(() => branch.getTipId(context)),\n\t\t\tfindEntries: (query, context) => this.admit(() => branch.findEntries(query, context)),\n\t\t\tfindEntry: (query, context) => this.admit(() => branch.findEntry(query, context)),\n\t\t\tappendMessage: (message, context) => this.admit(() => branch.appendMessage(message, context)),\n\t\t\tappendCustomEntry: (customType, data, context) =>\n\t\t\t\tthis.admit(() => branch.appendCustomEntry(customType, data, context)),\n\t\t};\n\t}\n\n\tprivate admit<T>(operation: () => Promise<T>): Promise<T> {\n\t\tif (this.state !== \"open\") return Promise.reject(this.closedError);\n\t\tlet result: Promise<T>;\n\t\ttry {\n\t\t\tresult = operation();\n\t\t} catch (error) {\n\t\t\tresult = Promise.reject(error);\n\t\t}\n\t\tthis.admitted.add(result);\n\t\tvoid result.then(\n\t\t\t() => this.admitted.delete(result),\n\t\t\t() => this.admitted.delete(result),\n\t\t);\n\t\treturn result;\n\t}\n}\n"]}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { CommitResult, Context, Entry, EntryScan, EntryStructure, ForkOptions, ListElement, ListReadOptions, SessionStats, Storage, StorageBranchScan, StoredValue, UsageRow, UsageScan, Value, ValueList, Write } from "@earendil-works/pi-agent-core";
|
|
2
|
+
import type { SqliteDatabase } from "./types.ts";
|
|
3
|
+
export interface SqliteStorageOptions {
|
|
4
|
+
sessionId: string;
|
|
5
|
+
now?: () => number;
|
|
6
|
+
}
|
|
7
|
+
export interface SqliteStorageSnapshot {
|
|
8
|
+
entries: Entry[];
|
|
9
|
+
scalarValues: StoredValue<unknown>[];
|
|
10
|
+
entriesComplete: boolean;
|
|
11
|
+
}
|
|
12
|
+
export declare class SqliteStorage implements Storage {
|
|
13
|
+
private readonly db;
|
|
14
|
+
private readonly sessionId;
|
|
15
|
+
private readonly now;
|
|
16
|
+
private readonly entryWriter;
|
|
17
|
+
private readonly usageWriter;
|
|
18
|
+
private commitQueue;
|
|
19
|
+
private state;
|
|
20
|
+
private closePromise;
|
|
21
|
+
constructor(db: SqliteDatabase, options: SqliteStorageOptions);
|
|
22
|
+
commit(writes: Write[], _context: Context): Promise<CommitResult>;
|
|
23
|
+
getEntries(ids: string[], _context: Context): Promise<Map<string, Entry>>;
|
|
24
|
+
getValue<T>(address: Value<T>, _context: Context): Promise<StoredValue<T> | undefined>;
|
|
25
|
+
scanValues<T>(prefix: Value<T>, _context: Context): Promise<StoredValue<T>[]>;
|
|
26
|
+
readList<T>(address: ValueList<T>, options: ListReadOptions | undefined, _context: Context): Promise<ListElement<T>[]>;
|
|
27
|
+
scanBranch(query: StorageBranchScan, _context: Context): Promise<Entry[]>;
|
|
28
|
+
scanBranchStructure(query: StorageBranchScan, _context: Context): Promise<EntryStructure[]>;
|
|
29
|
+
scanEntries(query: EntryScan, _context: Context): Promise<Entry[]>;
|
|
30
|
+
scanUsage(query: UsageScan, _context: Context): Promise<UsageRow[]>;
|
|
31
|
+
getStats(_context: Context): Promise<SessionStats>;
|
|
32
|
+
snapshot(options: ForkOptions, _context: Context): Promise<SqliteStorageSnapshot>;
|
|
33
|
+
private readSnapshot;
|
|
34
|
+
private readSnapshotEntries;
|
|
35
|
+
private applyCommit;
|
|
36
|
+
close(_context: Context): Promise<void>;
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=storage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../src/sqlite/storage.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n\tCommitResult,\n\tContext,\n\tEntry,\n\tEntryScan,\n\tEntryStructure,\n\tForkOptions,\n\tListElement,\n\tListReadOptions,\n\tSessionStats,\n\tStorage,\n\tStorageBranchScan,\n\tStoredValue,\n\tUsageRow,\n\tUsageScan,\n\tValue,\n\tValueList,\n\tWrite,\n} from \"@earendil-works/pi-agent-core\";\nimport { branchTip, prepareStorageCommit } from \"@earendil-works/pi-agent-core\";\nimport { appendEntryToBranchIndex, scanBranchEntries, scanBranchEntryStructures } from \"./session/branch-entries.ts\";\nimport { decodeEntryRow, EntryRowWriter, readAllEntryRows, readEntryRows, scanEntryRows } from \"./session/entries.ts\";\nimport { advanceNextSeq, readNextSeq } from \"./session/session-sequences.ts\";\nimport { addUsageToSessionStats, incrementMessageCount, readSessionStats } from \"./session/session-stats.ts\";\nimport { decodeUsageLedgerRow, scanUsageLedgerRows, UsageLedgerRowWriter } from \"./session/usage-ledger.ts\";\nimport {\n\tappendListValueRow,\n\tdeleteListValueRows,\n\tdeleteScalarValueRow,\n\treadAllScalarValueRows,\n\treadListValueRows,\n\treadScalarValueRow,\n\tscanScalarValueRows,\n\tsetScalarValueRow,\n} from \"./session/values.ts\";\nimport type { SqliteDatabase } from \"./types.ts\";\n\nexport interface SqliteStorageOptions {\n\tsessionId: string;\n\tnow?: () => number;\n}\n\nexport interface SqliteStorageSnapshot {\n\tentries: Entry[];\n\tscalarValues: StoredValue<unknown>[];\n\tentriesComplete: boolean;\n}\n\nexport class SqliteStorage implements Storage {\n\tprivate readonly db: SqliteDatabase;\n\tprivate readonly sessionId: string;\n\tprivate readonly now: () => number;\n\tprivate readonly entryWriter: EntryRowWriter;\n\tprivate readonly usageWriter: UsageLedgerRowWriter;\n\tprivate commitQueue: Promise<void> = Promise.resolve();\n\tprivate state: \"open\" | \"closing\" | \"closed\" = \"open\";\n\tprivate closePromise: Promise<void> | undefined;\n\n\tconstructor(db: SqliteDatabase, options: SqliteStorageOptions) {\n\t\tthis.db = db;\n\t\tthis.sessionId = options.sessionId;\n\t\tthis.now = options.now ?? Date.now;\n\t\tthis.entryWriter = new EntryRowWriter(db, this.sessionId);\n\t\tthis.usageWriter = new UsageLedgerRowWriter(db, this.sessionId);\n\t}\n\n\tasync commit(writes: Write[], _context: Context): Promise<CommitResult> {\n\t\tif (this.state !== \"open\") throw new Error(\"SqliteStorage is closed\");\n\t\tconst result = this.commitQueue.then(() => this.applyCommit(writes));\n\t\tthis.commitQueue = result.then(\n\t\t\t() => undefined,\n\t\t\t() => undefined,\n\t\t);\n\t\treturn result;\n\t}\n\n\tgetEntries(ids: string[], _context: Context): Promise<Map<string, Entry>> {\n\t\tif (this.state !== \"open\") return Promise.reject(new Error(\"SqliteStorage is closed\"));\n\t\tconst rowsById = new Map(readEntryRows(this.db, this.sessionId, ids).map((row) => [row.id, row]));\n\t\tconst entries = new Map<string, Entry>();\n\t\tfor (const id of ids) {\n\t\t\tconst row = rowsById.get(id);\n\t\t\tif (row !== undefined) entries.set(id, decodeEntryRow(row));\n\t\t}\n\t\treturn Promise.resolve(entries);\n\t}\n\n\tgetValue<T>(address: Value<T>, _context: Context): Promise<StoredValue<T> | undefined> {\n\t\tif (this.state !== \"open\") return Promise.reject(new Error(\"SqliteStorage is closed\"));\n\t\treturn Promise.resolve(readScalarValueRow(this.db, this.sessionId, address));\n\t}\n\n\tscanValues<T>(prefix: Value<T>, _context: Context): Promise<StoredValue<T>[]> {\n\t\tif (this.state !== \"open\") return Promise.reject(new Error(\"SqliteStorage is closed\"));\n\t\treturn Promise.resolve(scanScalarValueRows(this.db, this.sessionId, prefix));\n\t}\n\n\tasync readList<T>(\n\t\taddress: ValueList<T>,\n\t\toptions: ListReadOptions | undefined,\n\t\t_context: Context,\n\t): Promise<ListElement<T>[]> {\n\t\tif (this.state !== \"open\") throw new Error(\"SqliteStorage is closed\");\n\t\treturn readListValueRows(this.db, this.sessionId, address, options);\n\t}\n\n\tscanBranch(query: StorageBranchScan, _context: Context): Promise<Entry[]> {\n\t\tif (this.state !== \"open\") return Promise.reject(new Error(\"SqliteStorage is closed\"));\n\t\treturn Promise.resolve().then(() => scanBranchEntries(this.db, this.sessionId, query));\n\t}\n\n\tscanBranchStructure(query: StorageBranchScan, _context: Context): Promise<EntryStructure[]> {\n\t\tif (this.state !== \"open\") return Promise.reject(new Error(\"SqliteStorage is closed\"));\n\t\treturn Promise.resolve().then(() => scanBranchEntryStructures(this.db, this.sessionId, query));\n\t}\n\n\tscanEntries(query: EntryScan, _context: Context): Promise<Entry[]> {\n\t\tif (this.state !== \"open\") return Promise.reject(new Error(\"SqliteStorage is closed\"));\n\t\treturn Promise.resolve(scanEntryRows(this.db, this.sessionId, query).map(decodeEntryRow));\n\t}\n\n\tscanUsage(query: UsageScan, _context: Context): Promise<UsageRow[]> {\n\t\tif (this.state !== \"open\") return Promise.reject(new Error(\"SqliteStorage is closed\"));\n\t\treturn Promise.resolve(scanUsageLedgerRows(this.db, this.sessionId, query).map(decodeUsageLedgerRow));\n\t}\n\n\tgetStats(_context: Context): Promise<SessionStats> {\n\t\tif (this.state !== \"open\") return Promise.reject(new Error(\"SqliteStorage is closed\"));\n\t\treturn Promise.resolve(readSessionStats(this.db, this.sessionId));\n\t}\n\n\tsnapshot(options: ForkOptions, _context: Context): Promise<SqliteStorageSnapshot> {\n\t\tif (this.state !== \"open\") return Promise.reject(new Error(\"SqliteStorage is closed\"));\n\t\tconst result = this.commitQueue.then(() => this.readSnapshot(options));\n\t\tthis.commitQueue = result.then(\n\t\t\t() => undefined,\n\t\t\t() => undefined,\n\t\t);\n\t\treturn result;\n\t}\n\n\tprivate readSnapshot(options: ForkOptions): SqliteStorageSnapshot {\n\t\tconst scalarValues = readAllScalarValueRows(this.db, this.sessionId);\n\t\treturn {\n\t\t\tentries: this.readSnapshotEntries(options, scalarValues),\n\t\t\tscalarValues,\n\t\t\tentriesComplete: options.scope === \"tree\",\n\t\t};\n\t}\n\n\tprivate readSnapshotEntries(options: ForkOptions, scalarValues: readonly StoredValue<unknown>[]): Entry[] {\n\t\tif (options.scope === \"tree\") return readAllEntryRows(this.db, this.sessionId).map(decodeEntryRow);\n\t\tconst sourceAddress = branchTip(options.branch);\n\t\tconst sourceTip = scalarValues.find(\n\t\t\t(stored) => stored.address.namespace === sourceAddress.namespace && stored.address.key === sourceAddress.key,\n\t\t) as StoredValue<string | null> | undefined;\n\t\tif (sourceTip === undefined) throw new Error(`Unknown source branch: ${options.branch}`);\n\t\treturn sourceTip.value === null\n\t\t\t? []\n\t\t\t: scanBranchEntries(this.db, this.sessionId, { start: sourceTip.value, order: \"oldestFirst\" });\n\t}\n\n\tprivate applyCommit(writes: Write[]): CommitResult {\n\t\treturn this.db.transaction(() => {\n\t\t\tconst firstSeq = readNextSeq(this.db, this.sessionId);\n\t\t\tconst prepared = prepareStorageCommit(writes, firstSeq, this.now());\n\t\t\tfor (const write of prepared.writes) {\n\t\t\t\tswitch (write.kind) {\n\t\t\t\t\tcase \"entry\": {\n\t\t\t\t\t\tconst { kind: _kind, ...entry } = write;\n\t\t\t\t\t\tthis.entryWriter.insert(entry);\n\t\t\t\t\t\tappendEntryToBranchIndex(this.db, this.sessionId, entry);\n\t\t\t\t\t\tif (entry.type === \"message\") incrementMessageCount(this.db, this.sessionId);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tcase \"usage\": {\n\t\t\t\t\t\tconst { kind: _kind, ...row } = write;\n\t\t\t\t\t\tthis.usageWriter.insert(row);\n\t\t\t\t\t\taddUsageToSessionStats(this.db, this.sessionId, row.usage);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tcase \"value\":\n\t\t\t\t\t\tif (write.op === \"delete\") {\n\t\t\t\t\t\t\tdeleteScalarValueRow(this.db, this.sessionId, write.namespace, write.key);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tsetScalarValueRow(this.db, this.sessionId, write.namespace, write.key, write.seq, write.value);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"list\":\n\t\t\t\t\t\tif (write.op === \"delete\") {\n\t\t\t\t\t\t\tdeleteListValueRows(this.db, this.sessionId, write.namespace, write.key);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tappendListValueRow(this.db, this.sessionId, write.namespace, write.key, write.seq, write.value);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tadvanceNextSeq(this.db, this.sessionId, firstSeq + prepared.writes.length);\n\t\t\treturn { ...prepared.result, stats: readSessionStats(this.db, this.sessionId) };\n\t\t});\n\t}\n\n\tclose(_context: Context): Promise<void> {\n\t\tif (this.closePromise !== undefined) return this.closePromise;\n\t\tthis.state = \"closing\";\n\t\tthis.closePromise = this.commitQueue.then(() => {\n\t\t\tthis.state = \"closed\";\n\t\t});\n\t\treturn this.closePromise;\n\t}\n}\n"]}
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import { branchTip, prepareStorageCommit } from "@earendil-works/pi-agent-core";
|
|
2
|
+
import { appendEntryToBranchIndex, scanBranchEntries, scanBranchEntryStructures } from "./session/branch-entries.js";
|
|
3
|
+
import { decodeEntryRow, EntryRowWriter, readAllEntryRows, readEntryRows, scanEntryRows } from "./session/entries.js";
|
|
4
|
+
import { advanceNextSeq, readNextSeq } from "./session/session-sequences.js";
|
|
5
|
+
import { addUsageToSessionStats, incrementMessageCount, readSessionStats } from "./session/session-stats.js";
|
|
6
|
+
import { decodeUsageLedgerRow, scanUsageLedgerRows, UsageLedgerRowWriter } from "./session/usage-ledger.js";
|
|
7
|
+
import { appendListValueRow, deleteListValueRows, deleteScalarValueRow, readAllScalarValueRows, readListValueRows, readScalarValueRow, scanScalarValueRows, setScalarValueRow, } from "./session/values.js";
|
|
8
|
+
export class SqliteStorage {
|
|
9
|
+
db;
|
|
10
|
+
sessionId;
|
|
11
|
+
now;
|
|
12
|
+
entryWriter;
|
|
13
|
+
usageWriter;
|
|
14
|
+
commitQueue = Promise.resolve();
|
|
15
|
+
state = "open";
|
|
16
|
+
closePromise;
|
|
17
|
+
constructor(db, options) {
|
|
18
|
+
this.db = db;
|
|
19
|
+
this.sessionId = options.sessionId;
|
|
20
|
+
this.now = options.now ?? Date.now;
|
|
21
|
+
this.entryWriter = new EntryRowWriter(db, this.sessionId);
|
|
22
|
+
this.usageWriter = new UsageLedgerRowWriter(db, this.sessionId);
|
|
23
|
+
}
|
|
24
|
+
async commit(writes, _context) {
|
|
25
|
+
if (this.state !== "open")
|
|
26
|
+
throw new Error("SqliteStorage is closed");
|
|
27
|
+
const result = this.commitQueue.then(() => this.applyCommit(writes));
|
|
28
|
+
this.commitQueue = result.then(() => undefined, () => undefined);
|
|
29
|
+
return result;
|
|
30
|
+
}
|
|
31
|
+
getEntries(ids, _context) {
|
|
32
|
+
if (this.state !== "open")
|
|
33
|
+
return Promise.reject(new Error("SqliteStorage is closed"));
|
|
34
|
+
const rowsById = new Map(readEntryRows(this.db, this.sessionId, ids).map((row) => [row.id, row]));
|
|
35
|
+
const entries = new Map();
|
|
36
|
+
for (const id of ids) {
|
|
37
|
+
const row = rowsById.get(id);
|
|
38
|
+
if (row !== undefined)
|
|
39
|
+
entries.set(id, decodeEntryRow(row));
|
|
40
|
+
}
|
|
41
|
+
return Promise.resolve(entries);
|
|
42
|
+
}
|
|
43
|
+
getValue(address, _context) {
|
|
44
|
+
if (this.state !== "open")
|
|
45
|
+
return Promise.reject(new Error("SqliteStorage is closed"));
|
|
46
|
+
return Promise.resolve(readScalarValueRow(this.db, this.sessionId, address));
|
|
47
|
+
}
|
|
48
|
+
scanValues(prefix, _context) {
|
|
49
|
+
if (this.state !== "open")
|
|
50
|
+
return Promise.reject(new Error("SqliteStorage is closed"));
|
|
51
|
+
return Promise.resolve(scanScalarValueRows(this.db, this.sessionId, prefix));
|
|
52
|
+
}
|
|
53
|
+
async readList(address, options, _context) {
|
|
54
|
+
if (this.state !== "open")
|
|
55
|
+
throw new Error("SqliteStorage is closed");
|
|
56
|
+
return readListValueRows(this.db, this.sessionId, address, options);
|
|
57
|
+
}
|
|
58
|
+
scanBranch(query, _context) {
|
|
59
|
+
if (this.state !== "open")
|
|
60
|
+
return Promise.reject(new Error("SqliteStorage is closed"));
|
|
61
|
+
return Promise.resolve().then(() => scanBranchEntries(this.db, this.sessionId, query));
|
|
62
|
+
}
|
|
63
|
+
scanBranchStructure(query, _context) {
|
|
64
|
+
if (this.state !== "open")
|
|
65
|
+
return Promise.reject(new Error("SqliteStorage is closed"));
|
|
66
|
+
return Promise.resolve().then(() => scanBranchEntryStructures(this.db, this.sessionId, query));
|
|
67
|
+
}
|
|
68
|
+
scanEntries(query, _context) {
|
|
69
|
+
if (this.state !== "open")
|
|
70
|
+
return Promise.reject(new Error("SqliteStorage is closed"));
|
|
71
|
+
return Promise.resolve(scanEntryRows(this.db, this.sessionId, query).map(decodeEntryRow));
|
|
72
|
+
}
|
|
73
|
+
scanUsage(query, _context) {
|
|
74
|
+
if (this.state !== "open")
|
|
75
|
+
return Promise.reject(new Error("SqliteStorage is closed"));
|
|
76
|
+
return Promise.resolve(scanUsageLedgerRows(this.db, this.sessionId, query).map(decodeUsageLedgerRow));
|
|
77
|
+
}
|
|
78
|
+
getStats(_context) {
|
|
79
|
+
if (this.state !== "open")
|
|
80
|
+
return Promise.reject(new Error("SqliteStorage is closed"));
|
|
81
|
+
return Promise.resolve(readSessionStats(this.db, this.sessionId));
|
|
82
|
+
}
|
|
83
|
+
snapshot(options, _context) {
|
|
84
|
+
if (this.state !== "open")
|
|
85
|
+
return Promise.reject(new Error("SqliteStorage is closed"));
|
|
86
|
+
const result = this.commitQueue.then(() => this.readSnapshot(options));
|
|
87
|
+
this.commitQueue = result.then(() => undefined, () => undefined);
|
|
88
|
+
return result;
|
|
89
|
+
}
|
|
90
|
+
readSnapshot(options) {
|
|
91
|
+
const scalarValues = readAllScalarValueRows(this.db, this.sessionId);
|
|
92
|
+
return {
|
|
93
|
+
entries: this.readSnapshotEntries(options, scalarValues),
|
|
94
|
+
scalarValues,
|
|
95
|
+
entriesComplete: options.scope === "tree",
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
readSnapshotEntries(options, scalarValues) {
|
|
99
|
+
if (options.scope === "tree")
|
|
100
|
+
return readAllEntryRows(this.db, this.sessionId).map(decodeEntryRow);
|
|
101
|
+
const sourceAddress = branchTip(options.branch);
|
|
102
|
+
const sourceTip = scalarValues.find((stored) => stored.address.namespace === sourceAddress.namespace && stored.address.key === sourceAddress.key);
|
|
103
|
+
if (sourceTip === undefined)
|
|
104
|
+
throw new Error(`Unknown source branch: ${options.branch}`);
|
|
105
|
+
return sourceTip.value === null
|
|
106
|
+
? []
|
|
107
|
+
: scanBranchEntries(this.db, this.sessionId, { start: sourceTip.value, order: "oldestFirst" });
|
|
108
|
+
}
|
|
109
|
+
applyCommit(writes) {
|
|
110
|
+
return this.db.transaction(() => {
|
|
111
|
+
const firstSeq = readNextSeq(this.db, this.sessionId);
|
|
112
|
+
const prepared = prepareStorageCommit(writes, firstSeq, this.now());
|
|
113
|
+
for (const write of prepared.writes) {
|
|
114
|
+
switch (write.kind) {
|
|
115
|
+
case "entry": {
|
|
116
|
+
const { kind: _kind, ...entry } = write;
|
|
117
|
+
this.entryWriter.insert(entry);
|
|
118
|
+
appendEntryToBranchIndex(this.db, this.sessionId, entry);
|
|
119
|
+
if (entry.type === "message")
|
|
120
|
+
incrementMessageCount(this.db, this.sessionId);
|
|
121
|
+
break;
|
|
122
|
+
}
|
|
123
|
+
case "usage": {
|
|
124
|
+
const { kind: _kind, ...row } = write;
|
|
125
|
+
this.usageWriter.insert(row);
|
|
126
|
+
addUsageToSessionStats(this.db, this.sessionId, row.usage);
|
|
127
|
+
break;
|
|
128
|
+
}
|
|
129
|
+
case "value":
|
|
130
|
+
if (write.op === "delete") {
|
|
131
|
+
deleteScalarValueRow(this.db, this.sessionId, write.namespace, write.key);
|
|
132
|
+
}
|
|
133
|
+
else {
|
|
134
|
+
setScalarValueRow(this.db, this.sessionId, write.namespace, write.key, write.seq, write.value);
|
|
135
|
+
}
|
|
136
|
+
break;
|
|
137
|
+
case "list":
|
|
138
|
+
if (write.op === "delete") {
|
|
139
|
+
deleteListValueRows(this.db, this.sessionId, write.namespace, write.key);
|
|
140
|
+
}
|
|
141
|
+
else {
|
|
142
|
+
appendListValueRow(this.db, this.sessionId, write.namespace, write.key, write.seq, write.value);
|
|
143
|
+
}
|
|
144
|
+
break;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
advanceNextSeq(this.db, this.sessionId, firstSeq + prepared.writes.length);
|
|
148
|
+
return { ...prepared.result, stats: readSessionStats(this.db, this.sessionId) };
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
close(_context) {
|
|
152
|
+
if (this.closePromise !== undefined)
|
|
153
|
+
return this.closePromise;
|
|
154
|
+
this.state = "closing";
|
|
155
|
+
this.closePromise = this.commitQueue.then(() => {
|
|
156
|
+
this.state = "closed";
|
|
157
|
+
});
|
|
158
|
+
return this.closePromise;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
//# sourceMappingURL=storage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage.js","sourceRoot":"","sources":["../../src/sqlite/storage.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n\tCommitResult,\n\tContext,\n\tEntry,\n\tEntryScan,\n\tEntryStructure,\n\tForkOptions,\n\tListElement,\n\tListReadOptions,\n\tSessionStats,\n\tStorage,\n\tStorageBranchScan,\n\tStoredValue,\n\tUsageRow,\n\tUsageScan,\n\tValue,\n\tValueList,\n\tWrite,\n} from \"@earendil-works/pi-agent-core\";\nimport { branchTip, prepareStorageCommit } from \"@earendil-works/pi-agent-core\";\nimport { appendEntryToBranchIndex, scanBranchEntries, scanBranchEntryStructures } from \"./session/branch-entries.ts\";\nimport { decodeEntryRow, EntryRowWriter, readAllEntryRows, readEntryRows, scanEntryRows } from \"./session/entries.ts\";\nimport { advanceNextSeq, readNextSeq } from \"./session/session-sequences.ts\";\nimport { addUsageToSessionStats, incrementMessageCount, readSessionStats } from \"./session/session-stats.ts\";\nimport { decodeUsageLedgerRow, scanUsageLedgerRows, UsageLedgerRowWriter } from \"./session/usage-ledger.ts\";\nimport {\n\tappendListValueRow,\n\tdeleteListValueRows,\n\tdeleteScalarValueRow,\n\treadAllScalarValueRows,\n\treadListValueRows,\n\treadScalarValueRow,\n\tscanScalarValueRows,\n\tsetScalarValueRow,\n} from \"./session/values.ts\";\nimport type { SqliteDatabase } from \"./types.ts\";\n\nexport interface SqliteStorageOptions {\n\tsessionId: string;\n\tnow?: () => number;\n}\n\nexport interface SqliteStorageSnapshot {\n\tentries: Entry[];\n\tscalarValues: StoredValue<unknown>[];\n\tentriesComplete: boolean;\n}\n\nexport class SqliteStorage implements Storage {\n\tprivate readonly db: SqliteDatabase;\n\tprivate readonly sessionId: string;\n\tprivate readonly now: () => number;\n\tprivate readonly entryWriter: EntryRowWriter;\n\tprivate readonly usageWriter: UsageLedgerRowWriter;\n\tprivate commitQueue: Promise<void> = Promise.resolve();\n\tprivate state: \"open\" | \"closing\" | \"closed\" = \"open\";\n\tprivate closePromise: Promise<void> | undefined;\n\n\tconstructor(db: SqliteDatabase, options: SqliteStorageOptions) {\n\t\tthis.db = db;\n\t\tthis.sessionId = options.sessionId;\n\t\tthis.now = options.now ?? Date.now;\n\t\tthis.entryWriter = new EntryRowWriter(db, this.sessionId);\n\t\tthis.usageWriter = new UsageLedgerRowWriter(db, this.sessionId);\n\t}\n\n\tasync commit(writes: Write[], _context: Context): Promise<CommitResult> {\n\t\tif (this.state !== \"open\") throw new Error(\"SqliteStorage is closed\");\n\t\tconst result = this.commitQueue.then(() => this.applyCommit(writes));\n\t\tthis.commitQueue = result.then(\n\t\t\t() => undefined,\n\t\t\t() => undefined,\n\t\t);\n\t\treturn result;\n\t}\n\n\tgetEntries(ids: string[], _context: Context): Promise<Map<string, Entry>> {\n\t\tif (this.state !== \"open\") return Promise.reject(new Error(\"SqliteStorage is closed\"));\n\t\tconst rowsById = new Map(readEntryRows(this.db, this.sessionId, ids).map((row) => [row.id, row]));\n\t\tconst entries = new Map<string, Entry>();\n\t\tfor (const id of ids) {\n\t\t\tconst row = rowsById.get(id);\n\t\t\tif (row !== undefined) entries.set(id, decodeEntryRow(row));\n\t\t}\n\t\treturn Promise.resolve(entries);\n\t}\n\n\tgetValue<T>(address: Value<T>, _context: Context): Promise<StoredValue<T> | undefined> {\n\t\tif (this.state !== \"open\") return Promise.reject(new Error(\"SqliteStorage is closed\"));\n\t\treturn Promise.resolve(readScalarValueRow(this.db, this.sessionId, address));\n\t}\n\n\tscanValues<T>(prefix: Value<T>, _context: Context): Promise<StoredValue<T>[]> {\n\t\tif (this.state !== \"open\") return Promise.reject(new Error(\"SqliteStorage is closed\"));\n\t\treturn Promise.resolve(scanScalarValueRows(this.db, this.sessionId, prefix));\n\t}\n\n\tasync readList<T>(\n\t\taddress: ValueList<T>,\n\t\toptions: ListReadOptions | undefined,\n\t\t_context: Context,\n\t): Promise<ListElement<T>[]> {\n\t\tif (this.state !== \"open\") throw new Error(\"SqliteStorage is closed\");\n\t\treturn readListValueRows(this.db, this.sessionId, address, options);\n\t}\n\n\tscanBranch(query: StorageBranchScan, _context: Context): Promise<Entry[]> {\n\t\tif (this.state !== \"open\") return Promise.reject(new Error(\"SqliteStorage is closed\"));\n\t\treturn Promise.resolve().then(() => scanBranchEntries(this.db, this.sessionId, query));\n\t}\n\n\tscanBranchStructure(query: StorageBranchScan, _context: Context): Promise<EntryStructure[]> {\n\t\tif (this.state !== \"open\") return Promise.reject(new Error(\"SqliteStorage is closed\"));\n\t\treturn Promise.resolve().then(() => scanBranchEntryStructures(this.db, this.sessionId, query));\n\t}\n\n\tscanEntries(query: EntryScan, _context: Context): Promise<Entry[]> {\n\t\tif (this.state !== \"open\") return Promise.reject(new Error(\"SqliteStorage is closed\"));\n\t\treturn Promise.resolve(scanEntryRows(this.db, this.sessionId, query).map(decodeEntryRow));\n\t}\n\n\tscanUsage(query: UsageScan, _context: Context): Promise<UsageRow[]> {\n\t\tif (this.state !== \"open\") return Promise.reject(new Error(\"SqliteStorage is closed\"));\n\t\treturn Promise.resolve(scanUsageLedgerRows(this.db, this.sessionId, query).map(decodeUsageLedgerRow));\n\t}\n\n\tgetStats(_context: Context): Promise<SessionStats> {\n\t\tif (this.state !== \"open\") return Promise.reject(new Error(\"SqliteStorage is closed\"));\n\t\treturn Promise.resolve(readSessionStats(this.db, this.sessionId));\n\t}\n\n\tsnapshot(options: ForkOptions, _context: Context): Promise<SqliteStorageSnapshot> {\n\t\tif (this.state !== \"open\") return Promise.reject(new Error(\"SqliteStorage is closed\"));\n\t\tconst result = this.commitQueue.then(() => this.readSnapshot(options));\n\t\tthis.commitQueue = result.then(\n\t\t\t() => undefined,\n\t\t\t() => undefined,\n\t\t);\n\t\treturn result;\n\t}\n\n\tprivate readSnapshot(options: ForkOptions): SqliteStorageSnapshot {\n\t\tconst scalarValues = readAllScalarValueRows(this.db, this.sessionId);\n\t\treturn {\n\t\t\tentries: this.readSnapshotEntries(options, scalarValues),\n\t\t\tscalarValues,\n\t\t\tentriesComplete: options.scope === \"tree\",\n\t\t};\n\t}\n\n\tprivate readSnapshotEntries(options: ForkOptions, scalarValues: readonly StoredValue<unknown>[]): Entry[] {\n\t\tif (options.scope === \"tree\") return readAllEntryRows(this.db, this.sessionId).map(decodeEntryRow);\n\t\tconst sourceAddress = branchTip(options.branch);\n\t\tconst sourceTip = scalarValues.find(\n\t\t\t(stored) => stored.address.namespace === sourceAddress.namespace && stored.address.key === sourceAddress.key,\n\t\t) as StoredValue<string | null> | undefined;\n\t\tif (sourceTip === undefined) throw new Error(`Unknown source branch: ${options.branch}`);\n\t\treturn sourceTip.value === null\n\t\t\t? []\n\t\t\t: scanBranchEntries(this.db, this.sessionId, { start: sourceTip.value, order: \"oldestFirst\" });\n\t}\n\n\tprivate applyCommit(writes: Write[]): CommitResult {\n\t\treturn this.db.transaction(() => {\n\t\t\tconst firstSeq = readNextSeq(this.db, this.sessionId);\n\t\t\tconst prepared = prepareStorageCommit(writes, firstSeq, this.now());\n\t\t\tfor (const write of prepared.writes) {\n\t\t\t\tswitch (write.kind) {\n\t\t\t\t\tcase \"entry\": {\n\t\t\t\t\t\tconst { kind: _kind, ...entry } = write;\n\t\t\t\t\t\tthis.entryWriter.insert(entry);\n\t\t\t\t\t\tappendEntryToBranchIndex(this.db, this.sessionId, entry);\n\t\t\t\t\t\tif (entry.type === \"message\") incrementMessageCount(this.db, this.sessionId);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tcase \"usage\": {\n\t\t\t\t\t\tconst { kind: _kind, ...row } = write;\n\t\t\t\t\t\tthis.usageWriter.insert(row);\n\t\t\t\t\t\taddUsageToSessionStats(this.db, this.sessionId, row.usage);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tcase \"value\":\n\t\t\t\t\t\tif (write.op === \"delete\") {\n\t\t\t\t\t\t\tdeleteScalarValueRow(this.db, this.sessionId, write.namespace, write.key);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tsetScalarValueRow(this.db, this.sessionId, write.namespace, write.key, write.seq, write.value);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"list\":\n\t\t\t\t\t\tif (write.op === \"delete\") {\n\t\t\t\t\t\t\tdeleteListValueRows(this.db, this.sessionId, write.namespace, write.key);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tappendListValueRow(this.db, this.sessionId, write.namespace, write.key, write.seq, write.value);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tadvanceNextSeq(this.db, this.sessionId, firstSeq + prepared.writes.length);\n\t\t\treturn { ...prepared.result, stats: readSessionStats(this.db, this.sessionId) };\n\t\t});\n\t}\n\n\tclose(_context: Context): Promise<void> {\n\t\tif (this.closePromise !== undefined) return this.closePromise;\n\t\tthis.state = \"closing\";\n\t\tthis.closePromise = this.commitQueue.then(() => {\n\t\t\tthis.state = \"closed\";\n\t\t});\n\t\treturn this.closePromise;\n\t}\n}\n"]}
|
package/dist/sqlite/types.d.ts
CHANGED
|
@@ -1,9 +1,6 @@
|
|
|
1
|
-
import type { FileSystem, SessionCreateOptions, SessionMetadata } from "@earendil-works/pi-agent-core";
|
|
2
1
|
/** Result of a prepared SQLite statement execution. */
|
|
3
2
|
export interface SqliteRunResult {
|
|
4
|
-
/** Number of rows changed by the statement. */
|
|
5
3
|
changes: number;
|
|
6
|
-
/** Inserted row id when the backend exposes one. */
|
|
7
4
|
lastInsertRowid?: number;
|
|
8
5
|
}
|
|
9
6
|
/** Prepared SQLite statement capability used by the SQLite session backend. */
|
|
@@ -18,28 +15,15 @@ export interface SqliteDatabase {
|
|
|
18
15
|
exec(sql: string): void;
|
|
19
16
|
prepare(sql: string): SqliteStatement;
|
|
20
17
|
/** Runs a synchronous write transaction. The callback must not return a promise. */
|
|
21
|
-
transaction<T>(
|
|
18
|
+
transaction<T>(callback: () => T): T;
|
|
22
19
|
close(): void;
|
|
23
20
|
}
|
|
24
21
|
export interface SqliteDatabaseFactory {
|
|
22
|
+
/** Open a writable database, creating it when absent. */
|
|
25
23
|
open(path: string): Promise<SqliteDatabase>;
|
|
24
|
+
/** Open a writable database without creating it. */
|
|
25
|
+
openExisting(path: string): Promise<SqliteDatabase>;
|
|
26
|
+
/** Open an existing database read-only. */
|
|
27
|
+
openReadOnly(path: string): Promise<SqliteDatabase>;
|
|
26
28
|
}
|
|
27
|
-
export interface SqliteSessionMetadata extends SessionMetadata {
|
|
28
|
-
cwd: string;
|
|
29
|
-
path: string;
|
|
30
|
-
parentSessionId?: string;
|
|
31
|
-
/** Current session name projected from SQLite global facts. */
|
|
32
|
-
name?: string;
|
|
33
|
-
/** Opaque application-owned metadata. */
|
|
34
|
-
metadata?: Record<string, unknown>;
|
|
35
|
-
}
|
|
36
|
-
export interface SqliteSessionCreateOptions extends SessionCreateOptions {
|
|
37
|
-
cwd: string;
|
|
38
|
-
parentSessionId?: string;
|
|
39
|
-
metadata?: Record<string, unknown>;
|
|
40
|
-
}
|
|
41
|
-
export interface SqliteSessionListOptions {
|
|
42
|
-
cwd?: string;
|
|
43
|
-
}
|
|
44
|
-
export type SqliteSessionRepositoryEnv = Pick<FileSystem, "absolutePath" | "createDir" | "exists">;
|
|
45
29
|
//# sourceMappingURL=types.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/sqlite/types.ts"],"names":[],"mappings":"AAAA,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/sqlite/types.ts"],"names":[],"mappings":"AAAA,uDAAuD;AACvD,MAAM,WAAW,eAAe;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,eAAe,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,+EAA+E;AAC/E,MAAM,WAAW,eAAe;IAC/B,GAAG,CAAC,GAAG,MAAM,EAAE,OAAO,EAAE,GAAG,eAAe,CAAC;IAC3C,GAAG,CAAC,IAAI,SAAS,MAAM,EAAE,GAAG,MAAM,EAAE,OAAO,EAAE,GAAG,IAAI,GAAG,SAAS,CAAC;IACjE,GAAG,CAAC,IAAI,SAAS,MAAM,EAAE,GAAG,MAAM,EAAE,OAAO,EAAE,GAAG,IAAI,EAAE,CAAC;IACvD,OAAO,CAAC,IAAI,SAAS,MAAM,EAAE,GAAG,MAAM,EAAE,OAAO,EAAE,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;CACnE;AAED,qEAAqE;AACrE,MAAM,WAAW,cAAc;IAC9B,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,eAAe,CAAC;IACtC,oFAAoF;IACpF,WAAW,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC;IACrC,KAAK,IAAI,IAAI,CAAC;CACd;AAED,MAAM,WAAW,qBAAqB;IACrC,yDAAyD;IACzD,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;IAC5C,oDAAoD;IACpD,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;IACpD,2CAA2C;IAC3C,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;CACpD","sourcesContent":["/** Result of a prepared SQLite statement execution. */\nexport interface SqliteRunResult {\n\tchanges: number;\n\tlastInsertRowid?: number;\n}\n\n/** Prepared SQLite statement capability used by the SQLite session backend. */\nexport interface SqliteStatement {\n\trun(...params: unknown[]): SqliteRunResult;\n\tget<TRow extends object>(...params: unknown[]): TRow | undefined;\n\tall<TRow extends object>(...params: unknown[]): TRow[];\n\titerate<TRow extends object>(...params: unknown[]): Iterable<TRow>;\n}\n\n/** SQLite database capability used by the SQLite session backend. */\nexport interface SqliteDatabase {\n\texec(sql: string): void;\n\tprepare(sql: string): SqliteStatement;\n\t/** Runs a synchronous write transaction. The callback must not return a promise. */\n\ttransaction<T>(callback: () => T): T;\n\tclose(): void;\n}\n\nexport interface SqliteDatabaseFactory {\n\t/** Open a writable database, creating it when absent. */\n\topen(path: string): Promise<SqliteDatabase>;\n\t/** Open a writable database without creating it. */\n\topenExisting(path: string): Promise<SqliteDatabase>;\n\t/** Open an existing database read-only. */\n\topenReadOnly(path: string): Promise<SqliteDatabase>;\n}\n"]}
|