@m4ike1/ion-session-backend-sqlite-node 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/CHANGELOG.md +69 -0
  2. package/README.md +62 -0
  3. package/dist/index.d.ts +6 -0
  4. package/dist/index.d.ts.map +1 -0
  5. package/dist/index.js +103 -0
  6. package/dist/index.js.map +1 -0
  7. package/dist/sqlite/index.d.ts +5 -0
  8. package/dist/sqlite/index.d.ts.map +1 -0
  9. package/dist/sqlite/index.js +4 -0
  10. package/dist/sqlite/index.js.map +1 -0
  11. package/dist/sqlite/migrations/001_initial.sql +121 -0
  12. package/dist/sqlite/migrations.d.ts +3 -0
  13. package/dist/sqlite/migrations.d.ts.map +1 -0
  14. package/dist/sqlite/migrations.js +7 -0
  15. package/dist/sqlite/migrations.js.map +1 -0
  16. package/dist/sqlite/repo.d.ts +41 -0
  17. package/dist/sqlite/repo.d.ts.map +1 -0
  18. package/dist/sqlite/repo.js +408 -0
  19. package/dist/sqlite/repo.js.map +1 -0
  20. package/dist/sqlite/session/branch-entries.d.ts +6 -0
  21. package/dist/sqlite/session/branch-entries.d.ts.map +1 -0
  22. package/dist/sqlite/session/branch-entries.js +213 -0
  23. package/dist/sqlite/session/branch-entries.js.map +1 -0
  24. package/dist/sqlite/session/entries.d.ts +24 -0
  25. package/dist/sqlite/session/entries.d.ts.map +1 -0
  26. package/dist/sqlite/session/entries.js +126 -0
  27. package/dist/sqlite/session/entries.js.map +1 -0
  28. package/dist/sqlite/session/session-row.d.ts +23 -0
  29. package/dist/sqlite/session/session-row.d.ts.map +1 -0
  30. package/dist/sqlite/session/session-row.js +69 -0
  31. package/dist/sqlite/session/session-row.js.map +1 -0
  32. package/dist/sqlite/session/session-sequences.d.ts +4 -0
  33. package/dist/sqlite/session/session-sequences.d.ts.map +1 -0
  34. package/dist/sqlite/session/session-sequences.js +13 -0
  35. package/dist/sqlite/session/session-sequences.js.map +1 -0
  36. package/dist/sqlite/session/session-stats.d.ts +6 -0
  37. package/dist/sqlite/session/session-stats.d.ts.map +1 -0
  38. package/dist/sqlite/session/session-stats.js +39 -0
  39. package/dist/sqlite/session/session-stats.js.map +1 -0
  40. package/dist/sqlite/session/usage-ledger.d.ts +20 -0
  41. package/dist/sqlite/session/usage-ledger.d.ts.map +1 -0
  42. package/dist/sqlite/session/usage-ledger.js +50 -0
  43. package/dist/sqlite/session/usage-ledger.js.map +1 -0
  44. package/dist/sqlite/session/values.d.ts +23 -0
  45. package/dist/sqlite/session/values.d.ts.map +1 -0
  46. package/dist/sqlite/session/values.js +91 -0
  47. package/dist/sqlite/session/values.js.map +1 -0
  48. package/dist/sqlite/session.d.ts +42 -0
  49. package/dist/sqlite/session.d.ts.map +1 -0
  50. package/dist/sqlite/session.js +163 -0
  51. package/dist/sqlite/session.js.map +1 -0
  52. package/dist/sqlite/sql.d.ts +19 -0
  53. package/dist/sqlite/sql.d.ts.map +1 -0
  54. package/dist/sqlite/sql.js +58 -0
  55. package/dist/sqlite/sql.js.map +1 -0
  56. package/dist/sqlite/storage.d.ts +38 -0
  57. package/dist/sqlite/storage.d.ts.map +1 -0
  58. package/dist/sqlite/storage.js +161 -0
  59. package/dist/sqlite/storage.js.map +1 -0
  60. package/dist/sqlite/types.d.ts +29 -0
  61. package/dist/sqlite/types.d.ts.map +1 -0
  62. package/dist/sqlite/types.js +2 -0
  63. package/dist/sqlite/types.js.map +1 -0
  64. package/package.json +45 -0
@@ -0,0 +1,58 @@
1
+ /** A parameterized SQLite query produced by {@link sql}. */
2
+ export class SqlQuery {
3
+ queryText;
4
+ params;
5
+ constructor(queryText, params = []) {
6
+ this.queryText = queryText;
7
+ this.params = params;
8
+ }
9
+ exec(db) {
10
+ if (this.params.length > 0)
11
+ throw new TypeError("SQLite exec queries cannot have parameters");
12
+ db.exec(this.queryText);
13
+ }
14
+ run(db) {
15
+ return db.prepare(this.queryText).run(...this.params);
16
+ }
17
+ get(db) {
18
+ return db.prepare(this.queryText).get(...this.params);
19
+ }
20
+ all(db) {
21
+ return db.prepare(this.queryText).all(...this.params);
22
+ }
23
+ iterate(db) {
24
+ return db.prepare(this.queryText).iterate(...this.params);
25
+ }
26
+ }
27
+ /** Builds a parameterized query. Nested queries are inlined; other interpolations become `?` parameters. */
28
+ export function sql(strings, ...values) {
29
+ let queryText = strings[0] ?? "";
30
+ const params = [];
31
+ for (let index = 0; index < values.length; index++) {
32
+ const value = values[index];
33
+ if (value instanceof SqlQuery) {
34
+ queryText += value.queryText;
35
+ params.push(...value.params);
36
+ }
37
+ else {
38
+ queryText += "?";
39
+ params.push(value);
40
+ }
41
+ queryText += strings[index + 1] ?? "";
42
+ }
43
+ return new SqlQuery(queryText, params);
44
+ }
45
+ /** Joins trusted query fragments while preserving their parameter order. */
46
+ export function joinSqlFragments(fragments, separator) {
47
+ let queryText = "";
48
+ const params = [];
49
+ for (let index = 0; index < fragments.length; index++) {
50
+ if (index > 0)
51
+ queryText += separator;
52
+ const fragment = fragments[index];
53
+ queryText += fragment.queryText;
54
+ params.push(...fragment.params);
55
+ }
56
+ return new SqlQuery(queryText, params);
57
+ }
58
+ //# sourceMappingURL=sql.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sql.js","sourceRoot":"","sources":["../../src/sqlite/sql.ts"],"names":[],"mappings":"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","sourcesContent":["import type { SqliteDatabase, SqliteRunResult } from \"./types.ts\";\n\ntype SqlTemplateValue = unknown | SqlQuery;\n\n/** A parameterized SQLite query produced by {@link sql}. */\nexport class SqlQuery {\n\treadonly queryText: string;\n\treadonly params: readonly unknown[];\n\n\tconstructor(queryText: string, params: readonly unknown[] = []) {\n\t\tthis.queryText = queryText;\n\t\tthis.params = params;\n\t}\n\n\texec(db: SqliteDatabase): void {\n\t\tif (this.params.length > 0) throw new TypeError(\"SQLite exec queries cannot have parameters\");\n\t\tdb.exec(this.queryText);\n\t}\n\n\trun(db: SqliteDatabase): SqliteRunResult {\n\t\treturn db.prepare(this.queryText).run(...this.params);\n\t}\n\n\tget<TRow extends object>(db: SqliteDatabase): TRow | undefined {\n\t\treturn db.prepare(this.queryText).get<TRow>(...this.params);\n\t}\n\n\tall<TRow extends object>(db: SqliteDatabase): TRow[] {\n\t\treturn db.prepare(this.queryText).all<TRow>(...this.params);\n\t}\n\n\titerate<TRow extends object>(db: SqliteDatabase): Iterable<TRow> {\n\t\treturn db.prepare(this.queryText).iterate<TRow>(...this.params);\n\t}\n}\n\n/** Builds a parameterized query. Nested queries are inlined; other interpolations become `?` parameters. */\nexport function sql(strings: TemplateStringsArray, ...values: SqlTemplateValue[]): SqlQuery {\n\tlet queryText = strings[0] ?? \"\";\n\tconst params: unknown[] = [];\n\tfor (let index = 0; index < values.length; index++) {\n\t\tconst value = values[index];\n\t\tif (value instanceof SqlQuery) {\n\t\t\tqueryText += value.queryText;\n\t\t\tparams.push(...value.params);\n\t\t} else {\n\t\t\tqueryText += \"?\";\n\t\t\tparams.push(value);\n\t\t}\n\t\tqueryText += strings[index + 1] ?? \"\";\n\t}\n\treturn new SqlQuery(queryText, params);\n}\n\n/** Joins trusted query fragments while preserving their parameter order. */\nexport function joinSqlFragments(fragments: readonly SqlQuery[], separator: string): SqlQuery {\n\tlet queryText = \"\";\n\tconst params: unknown[] = [];\n\tfor (let index = 0; index < fragments.length; index++) {\n\t\tif (index > 0) queryText += separator;\n\t\tconst fragment = fragments[index]!;\n\t\tqueryText += fragment.queryText;\n\t\tparams.push(...fragment.params);\n\t}\n\treturn new SqlQuery(queryText, params);\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 "@m4ike1/ion-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 \"@m4ike1/ion-agent-core\";\nimport { branchTip, prepareStorageCommit } from \"@m4ike1/ion-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 "@m4ike1/ion-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 \"@m4ike1/ion-agent-core\";\nimport { branchTip, prepareStorageCommit } from \"@m4ike1/ion-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,29 @@
1
+ /** Result of a prepared SQLite statement execution. */
2
+ export interface SqliteRunResult {
3
+ changes: number;
4
+ lastInsertRowid?: number;
5
+ }
6
+ /** Prepared SQLite statement capability used by the SQLite session backend. */
7
+ export interface SqliteStatement {
8
+ run(...params: unknown[]): SqliteRunResult;
9
+ get<TRow extends object>(...params: unknown[]): TRow | undefined;
10
+ all<TRow extends object>(...params: unknown[]): TRow[];
11
+ iterate<TRow extends object>(...params: unknown[]): Iterable<TRow>;
12
+ }
13
+ /** SQLite database capability used by the SQLite session backend. */
14
+ export interface SqliteDatabase {
15
+ exec(sql: string): void;
16
+ prepare(sql: string): SqliteStatement;
17
+ /** Runs a synchronous write transaction. The callback must not return a promise. */
18
+ transaction<T>(callback: () => T): T;
19
+ close(): void;
20
+ }
21
+ export interface SqliteDatabaseFactory {
22
+ /** Open a writable database, creating it when absent. */
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>;
28
+ }
29
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
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"]}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/sqlite/types.ts"],"names":[],"mappings":"","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"]}
package/package.json ADDED
@@ -0,0 +1,45 @@
1
+ {
2
+ "name": "@m4ike1/ion-session-backend-sqlite-node",
3
+ "version": "0.1.0",
4
+ "description": "Node sqlite session backend for @m4ike1/ion-agent-core sessions",
5
+ "license": "MIT",
6
+ "author": "Earendil Works",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/maikel/ion.git",
10
+ "directory": "packages/session-backends/sqlite-node"
11
+ },
12
+ "files": [
13
+ "dist",
14
+ "README.md",
15
+ "CHANGELOG.md"
16
+ ],
17
+ "type": "module",
18
+ "main": "./dist/index.js",
19
+ "types": "./dist/index.d.ts",
20
+ "exports": {
21
+ ".": {
22
+ "types": "./dist/index.d.ts",
23
+ "import": "./dist/index.js"
24
+ }
25
+ },
26
+ "scripts": {
27
+ "clean": "node -e \"import('node:fs/promises').then(fs=>fs.rm('dist',{recursive:true,force:true}))\"",
28
+ "build": "tsgo -p tsconfig.build.json && node scripts/copy-migrations.mjs",
29
+ "bench:session:timing": "vp test bench --config vitest.benchmark.config.ts",
30
+ "test": "vp test --run",
31
+ "coverage": "vp test --run --coverage",
32
+ "prepublishOnly": "npm run clean && npm run build"
33
+ },
34
+ "dependencies": {
35
+ "@m4ike1/ion-agent-core": "^0.1.0",
36
+ "@m4ike1/ion-ai": "^0.1.0"
37
+ },
38
+ "devDependencies": {
39
+ "@vitest/coverage-v8": "4.1.11",
40
+ "vitest": "4.1.11"
41
+ },
42
+ "engines": {
43
+ "node": ">=22.19.0"
44
+ }
45
+ }