@dexto/storage 1.8.11 → 1.9.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.
@@ -108,6 +108,25 @@ class MemoryDatabaseStore {
108
108
  }
109
109
  this.lists.get(key).push(item);
110
110
  }
111
+ async updateList(key, updater) {
112
+ this.checkConnection();
113
+ try {
114
+ const current = this.lists.get(key) ?? [];
115
+ const mutation = updater([...current]);
116
+ if (mutation.items.length === 0) {
117
+ this.lists.delete(key);
118
+ } else {
119
+ this.lists.set(key, [...mutation.items]);
120
+ }
121
+ return mutation.result;
122
+ } catch (error) {
123
+ throw import_core.StorageError.writeFailed(
124
+ "updateList",
125
+ error instanceof Error ? error.message : String(error),
126
+ { key }
127
+ );
128
+ }
129
+ }
111
130
  async getRange(key, start, count) {
112
131
  this.checkConnection();
113
132
  const list = this.lists.get(key) || [];
@@ -21,6 +21,10 @@ export declare class MemoryDatabaseStore implements Database {
21
21
  delete(key: string): Promise<void>;
22
22
  list(prefix: string): Promise<string[]>;
23
23
  append<T>(key: string, item: T): Promise<void>;
24
+ updateList<T, R>(key: string, updater: (items: T[]) => {
25
+ items: T[];
26
+ result: R;
27
+ }): Promise<R>;
24
28
  getRange<T>(key: string, start: number, count: number): Promise<T[]>;
25
29
  private checkConnection;
26
30
  clear(): Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"memory-database-store.d.ts","sourceRoot":"","sources":["../../src/database/memory-database-store.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAG3C;;;;GAIG;AACH,qBAAa,mBAAoB,YAAW,QAAQ;IAChD,OAAO,CAAC,IAAI,CAA8B;IAC1C,OAAO,CAAC,KAAK,CAAgC;IAC7C,OAAO,CAAC,SAAS,CAAS;IAEpB,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAKxB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAMjC,WAAW,IAAI,OAAO;IAItB,YAAY,IAAI,MAAM;IAIhB,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC;IAa3C,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAa5C,WAAW,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,GAAG,OAAO,CAAC;QAAE,KAAK,EAAE,CAAC,CAAC;QAAC,QAAQ,EAAE,OAAO,CAAA;KAAE,CAAC;IAiB/E,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAMlC,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAsBvC,MAAM,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAQ9C,QAAQ,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,EAAE,CAAC;IAO1E,OAAO,CAAC,eAAe;IAOjB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAKtB,IAAI,IAAI,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC,CAAA;KAAE,CAAC;CAM7F"}
1
+ {"version":3,"file":"memory-database-store.d.ts","sourceRoot":"","sources":["../../src/database/memory-database-store.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAG3C;;;;GAIG;AACH,qBAAa,mBAAoB,YAAW,QAAQ;IAChD,OAAO,CAAC,IAAI,CAA8B;IAC1C,OAAO,CAAC,KAAK,CAAgC;IAC7C,OAAO,CAAC,SAAS,CAAS;IAEpB,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAKxB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAMjC,WAAW,IAAI,OAAO;IAItB,YAAY,IAAI,MAAM;IAIhB,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC;IAa3C,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAa5C,WAAW,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,GAAG,OAAO,CAAC;QAAE,KAAK,EAAE,CAAC,CAAC;QAAC,QAAQ,EAAE,OAAO,CAAA;KAAE,CAAC;IAiB/E,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAMlC,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAsBvC,MAAM,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAQ9C,UAAU,CAAC,CAAC,EAAE,CAAC,EACjB,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,CAAC,KAAK,EAAE,CAAC,EAAE,KAAK;QAAE,KAAK,EAAE,CAAC,EAAE,CAAC;QAAC,MAAM,EAAE,CAAC,CAAA;KAAE,GACnD,OAAO,CAAC,CAAC,CAAC;IAoBP,QAAQ,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,EAAE,CAAC;IAO1E,OAAO,CAAC,eAAe;IAOjB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAKtB,IAAI,IAAI,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC,CAAA;KAAE,CAAC;CAM7F"}
@@ -85,6 +85,25 @@ class MemoryDatabaseStore {
85
85
  }
86
86
  this.lists.get(key).push(item);
87
87
  }
88
+ async updateList(key, updater) {
89
+ this.checkConnection();
90
+ try {
91
+ const current = this.lists.get(key) ?? [];
92
+ const mutation = updater([...current]);
93
+ if (mutation.items.length === 0) {
94
+ this.lists.delete(key);
95
+ } else {
96
+ this.lists.set(key, [...mutation.items]);
97
+ }
98
+ return mutation.result;
99
+ } catch (error) {
100
+ throw StorageError.writeFailed(
101
+ "updateList",
102
+ error instanceof Error ? error.message : String(error),
103
+ { key }
104
+ );
105
+ }
106
+ }
88
107
  async getRange(key, start, count) {
89
108
  this.checkConnection();
90
109
  const list = this.lists.get(key) || [];
@@ -235,10 +235,38 @@ class PostgresStore {
235
235
  );
236
236
  }
237
237
  }
238
+ async updateList(key, updater) {
239
+ try {
240
+ return await this.transactionOnce(async (client) => {
241
+ await client.query("SELECT pg_advisory_xact_lock(hashtext($1::text)::bigint)", [
242
+ key
243
+ ]);
244
+ const result = await client.query(
245
+ "SELECT item FROM lists WHERE key = $1 ORDER BY created_at ASC, id ASC",
246
+ [key]
247
+ );
248
+ const mutation = updater(result.rows.map((row) => row.item));
249
+ await client.query("DELETE FROM lists WHERE key = $1", [key]);
250
+ for (const item of mutation.items) {
251
+ await client.query(
252
+ "INSERT INTO lists (key, item, created_at) VALUES ($1, $2::jsonb, $3)",
253
+ [key, JSON.stringify(item), /* @__PURE__ */ new Date()]
254
+ );
255
+ }
256
+ return mutation.result;
257
+ });
258
+ } catch (error) {
259
+ throw import_core.StorageError.writeFailed(
260
+ "updateList",
261
+ error instanceof Error ? error.message : String(error),
262
+ { key }
263
+ );
264
+ }
265
+ }
238
266
  async getRange(key, start, count) {
239
267
  return await this.withRetry("getRange", async (client) => {
240
268
  const result = await client.query(
241
- "SELECT item FROM lists WHERE key = $1 ORDER BY created_at ASC LIMIT $2 OFFSET $3",
269
+ "SELECT item FROM lists WHERE key = $1 ORDER BY created_at ASC, id ASC LIMIT $2 OFFSET $3",
242
270
  [key, count, start]
243
271
  );
244
272
  return result.rows.map((row) => row.item);
@@ -339,6 +367,31 @@ class PostgresStore {
339
367
  }
340
368
  });
341
369
  }
370
+ async transactionOnce(callback) {
371
+ this.checkConnection();
372
+ const client = await this.pool.connect();
373
+ let began = false;
374
+ let releaseWithError = false;
375
+ try {
376
+ await client.query("BEGIN");
377
+ began = true;
378
+ const result = await callback(client);
379
+ await client.query("COMMIT");
380
+ return result;
381
+ } catch (error) {
382
+ releaseWithError = this.isConnectionError(error);
383
+ if (began && !releaseWithError) {
384
+ try {
385
+ await client.query("ROLLBACK");
386
+ } catch {
387
+ releaseWithError = true;
388
+ }
389
+ }
390
+ throw error;
391
+ } finally {
392
+ client.release(releaseWithError);
393
+ }
394
+ }
342
395
  async getStats() {
343
396
  return await this.withRetry("getStats", async (client) => {
344
397
  const kvResult = await client.query("SELECT COUNT(*) as count FROM kv");
@@ -30,6 +30,10 @@ export declare class PostgresStore implements Database {
30
30
  delete(key: string): Promise<void>;
31
31
  list(prefix: string): Promise<string[]>;
32
32
  append<T>(key: string, item: T): Promise<void>;
33
+ updateList<T, R>(key: string, updater: (items: T[]) => {
34
+ items: T[];
35
+ result: R;
36
+ }): Promise<R>;
33
37
  getRange<T>(key: string, start: number, count: number): Promise<T[]>;
34
38
  private createTables;
35
39
  private checkConnection;
@@ -49,6 +53,7 @@ export declare class PostgresStore implements Database {
49
53
  * Ensure callback operations are idempotent or use this only for read operations.
50
54
  */
51
55
  transaction<T>(callback: (client: PoolClient) => Promise<T>): Promise<T>;
56
+ private transactionOnce;
52
57
  getStats(): Promise<{
53
58
  kvCount: number;
54
59
  listCount: number;
@@ -1 +1 @@
1
- {"version":3,"file":"postgres-store.d.ts","sourceRoot":"","sources":["../../src/database/postgres-store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAQ,UAAU,EAAE,MAAM,IAAI,CAAC;AACtC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAC;AAC3D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAG1C;;;;GAIG;AACH,qBAAa,aAAc,YAAW,QAAQ;IAMtC,OAAO,CAAC,MAAM;IALlB,OAAO,CAAC,IAAI,CAAqB;IACjC,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,MAAM,CAAS;gBAGX,MAAM,EAAE,sBAAsB,EACtC,MAAM,EAAE,MAAM;IAKZ,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IA+F9B;;OAEG;YACW,YAAY;IAmBpB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAQjC,WAAW,IAAI,OAAO;IAItB,YAAY,IAAI,MAAM;IAKhB,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC;IAe3C,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAmB5C,WAAW,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,GAAG,OAAO,CAAC;QAAE,KAAK,EAAE,CAAC,CAAC;QAAC,QAAQ,EAAE,OAAO,CAAA;KAAE,CAAC;IA2B/E,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAelC,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAmBvC,MAAM,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAmB9C,QAAQ,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,EAAE,CAAC;YAW5D,YAAY;IA4B1B,OAAO,CAAC,eAAe;IAMvB;;;OAGG;IACH,OAAO,CAAC,iBAAiB;IAiBzB;;;OAGG;YACW,SAAS;IA8CvB;;;;OAIG;IACG,WAAW,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,MAAM,EAAE,UAAU,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAcxE,QAAQ,IAAI,OAAO,CAAC;QACtB,OAAO,EAAE,MAAM,CAAC;QAChB,SAAS,EAAE,MAAM,CAAC;QAClB,SAAS,EAAE,MAAM,CAAC;KACrB,CAAC;IAkBI,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;CAKhC"}
1
+ {"version":3,"file":"postgres-store.d.ts","sourceRoot":"","sources":["../../src/database/postgres-store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAQ,UAAU,EAAE,MAAM,IAAI,CAAC;AACtC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAC;AAC3D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAG1C;;;;GAIG;AACH,qBAAa,aAAc,YAAW,QAAQ;IAMtC,OAAO,CAAC,MAAM;IALlB,OAAO,CAAC,IAAI,CAAqB;IACjC,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,MAAM,CAAS;gBAGX,MAAM,EAAE,sBAAsB,EACtC,MAAM,EAAE,MAAM;IAKZ,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IA+F9B;;OAEG;YACW,YAAY;IAmBpB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAQjC,WAAW,IAAI,OAAO;IAItB,YAAY,IAAI,MAAM;IAKhB,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC;IAe3C,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAmB5C,WAAW,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,GAAG,OAAO,CAAC;QAAE,KAAK,EAAE,CAAC,CAAC;QAAC,QAAQ,EAAE,OAAO,CAAA;KAAE,CAAC;IA2B/E,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAelC,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAmBvC,MAAM,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAmB9C,UAAU,CAAC,CAAC,EAAE,CAAC,EACjB,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,CAAC,KAAK,EAAE,CAAC,EAAE,KAAK;QAAE,KAAK,EAAE,CAAC,EAAE,CAAC;QAAC,MAAM,EAAE,CAAC,CAAA;KAAE,GACnD,OAAO,CAAC,CAAC,CAAC;IA+BP,QAAQ,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,EAAE,CAAC;YAW5D,YAAY;IA4B1B,OAAO,CAAC,eAAe;IAMvB;;;OAGG;IACH,OAAO,CAAC,iBAAiB;IAiBzB;;;OAGG;YACW,SAAS;IA8CvB;;;;OAIG;IACG,WAAW,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,MAAM,EAAE,UAAU,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;YAchE,eAAe;IA2BvB,QAAQ,IAAI,OAAO,CAAC;QACtB,OAAO,EAAE,MAAM,CAAC;QAChB,SAAS,EAAE,MAAM,CAAC;QAClB,SAAS,EAAE,MAAM,CAAC;KACrB,CAAC;IAkBI,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;CAKhC"}
@@ -212,10 +212,38 @@ class PostgresStore {
212
212
  );
213
213
  }
214
214
  }
215
+ async updateList(key, updater) {
216
+ try {
217
+ return await this.transactionOnce(async (client) => {
218
+ await client.query("SELECT pg_advisory_xact_lock(hashtext($1::text)::bigint)", [
219
+ key
220
+ ]);
221
+ const result = await client.query(
222
+ "SELECT item FROM lists WHERE key = $1 ORDER BY created_at ASC, id ASC",
223
+ [key]
224
+ );
225
+ const mutation = updater(result.rows.map((row) => row.item));
226
+ await client.query("DELETE FROM lists WHERE key = $1", [key]);
227
+ for (const item of mutation.items) {
228
+ await client.query(
229
+ "INSERT INTO lists (key, item, created_at) VALUES ($1, $2::jsonb, $3)",
230
+ [key, JSON.stringify(item), /* @__PURE__ */ new Date()]
231
+ );
232
+ }
233
+ return mutation.result;
234
+ });
235
+ } catch (error) {
236
+ throw StorageError.writeFailed(
237
+ "updateList",
238
+ error instanceof Error ? error.message : String(error),
239
+ { key }
240
+ );
241
+ }
242
+ }
215
243
  async getRange(key, start, count) {
216
244
  return await this.withRetry("getRange", async (client) => {
217
245
  const result = await client.query(
218
- "SELECT item FROM lists WHERE key = $1 ORDER BY created_at ASC LIMIT $2 OFFSET $3",
246
+ "SELECT item FROM lists WHERE key = $1 ORDER BY created_at ASC, id ASC LIMIT $2 OFFSET $3",
219
247
  [key, count, start]
220
248
  );
221
249
  return result.rows.map((row) => row.item);
@@ -316,6 +344,31 @@ class PostgresStore {
316
344
  }
317
345
  });
318
346
  }
347
+ async transactionOnce(callback) {
348
+ this.checkConnection();
349
+ const client = await this.pool.connect();
350
+ let began = false;
351
+ let releaseWithError = false;
352
+ try {
353
+ await client.query("BEGIN");
354
+ began = true;
355
+ const result = await callback(client);
356
+ await client.query("COMMIT");
357
+ return result;
358
+ } catch (error) {
359
+ releaseWithError = this.isConnectionError(error);
360
+ if (began && !releaseWithError) {
361
+ try {
362
+ await client.query("ROLLBACK");
363
+ } catch {
364
+ releaseWithError = true;
365
+ }
366
+ }
367
+ throw error;
368
+ } finally {
369
+ client.release(releaseWithError);
370
+ }
371
+ }
319
372
  async getStats() {
320
373
  return await this.withRetry("getStats", async (client) => {
321
374
  const kvResult = await client.query("SELECT COUNT(*) as count FROM kv");
@@ -242,6 +242,33 @@ class SQLiteStore {
242
242
  );
243
243
  }
244
244
  }
245
+ async updateList(key, updater) {
246
+ this.checkConnection();
247
+ try {
248
+ const transaction = this.db.transaction(() => {
249
+ const rows = this.db.prepare("SELECT value FROM list_store WHERE key = ? ORDER BY sequence ASC").all(key);
250
+ const current = rows.map((row) => JSON.parse(row.value));
251
+ const mutation = updater(current);
252
+ this.db.prepare("DELETE FROM list_store WHERE key = ?").run(key);
253
+ if (mutation.items.length > 0) {
254
+ const insert = this.db.prepare(
255
+ "INSERT INTO list_store (key, value, sequence) VALUES (?, ?, ?)"
256
+ );
257
+ for (const [index, item] of mutation.items.entries()) {
258
+ insert.run(key, JSON.stringify(item), index + 1);
259
+ }
260
+ }
261
+ return mutation.result;
262
+ });
263
+ return transaction();
264
+ } catch (error) {
265
+ throw import_core.StorageError.writeFailed(
266
+ "updateList",
267
+ error instanceof Error ? error.message : String(error),
268
+ { key }
269
+ );
270
+ }
271
+ }
245
272
  async getRange(key, start, count) {
246
273
  this.checkConnection();
247
274
  try {
@@ -25,6 +25,10 @@ export declare class SQLiteStore implements Database {
25
25
  delete(key: string): Promise<void>;
26
26
  list(prefix: string): Promise<string[]>;
27
27
  append<T>(key: string, item: T): Promise<void>;
28
+ updateList<T, R>(key: string, updater: (items: T[]) => {
29
+ items: T[];
30
+ result: R;
31
+ }): Promise<R>;
28
32
  getRange<T>(key: string, start: number, count: number): Promise<T[]>;
29
33
  private checkConnection;
30
34
  vacuum(): Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"sqlite-store.d.ts","sourceRoot":"","sources":["../../src/database/sqlite-store.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAE1C,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAKzD;;;GAGG;AACH,qBAAa,WAAY,YAAW,QAAQ;IACxC,OAAO,CAAC,EAAE,CAAoB;IAC9B,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,MAAM,CAAS;gBAEX,MAAM,EAAE,oBAAoB,EAAE,MAAM,EAAE,MAAM;IAOxD,OAAO,CAAC,gBAAgB;IA8ClB,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IA2ExB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAOjC,WAAW,IAAI,OAAO;IAItB,YAAY,IAAI,MAAM;IAKhB,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC;IAgB3C,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAkB5C,WAAW,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,GAAG,OAAO,CAAC;QAAE,KAAK,EAAE,CAAC,CAAC;QAAC,QAAQ,EAAE,OAAO,CAAA;KAAE,CAAC;IAwB/E,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAelC,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IA0BvC,MAAM,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAqB9C,QAAQ,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,EAAE,CAAC;IAqB1E,OAAO,CAAC,eAAe;IAOjB,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;IAKvB,QAAQ,IAAI,OAAO,CAAC;QACtB,OAAO,EAAE,MAAM,CAAC;QAChB,SAAS,EAAE,MAAM,CAAC;QAClB,MAAM,EAAE,MAAM,CAAC;KAClB,CAAC;CAqBL"}
1
+ {"version":3,"file":"sqlite-store.d.ts","sourceRoot":"","sources":["../../src/database/sqlite-store.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAE1C,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAKzD;;;GAGG;AACH,qBAAa,WAAY,YAAW,QAAQ;IACxC,OAAO,CAAC,EAAE,CAAoB;IAC9B,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,MAAM,CAAS;gBAEX,MAAM,EAAE,oBAAoB,EAAE,MAAM,EAAE,MAAM;IAOxD,OAAO,CAAC,gBAAgB;IA8ClB,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IA2ExB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAOjC,WAAW,IAAI,OAAO;IAItB,YAAY,IAAI,MAAM;IAKhB,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC;IAgB3C,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAkB5C,WAAW,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,GAAG,OAAO,CAAC;QAAE,KAAK,EAAE,CAAC,CAAC;QAAC,QAAQ,EAAE,OAAO,CAAA;KAAE,CAAC;IAwB/E,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAelC,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IA0BvC,MAAM,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAqB9C,UAAU,CAAC,CAAC,EAAE,CAAC,EACjB,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,CAAC,KAAK,EAAE,CAAC,EAAE,KAAK;QAAE,KAAK,EAAE,CAAC,EAAE,CAAC;QAAC,MAAM,EAAE,CAAC,CAAA;KAAE,GACnD,OAAO,CAAC,CAAC,CAAC;IAiCP,QAAQ,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,EAAE,CAAC;IAqB1E,OAAO,CAAC,eAAe;IAOjB,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;IAKvB,QAAQ,IAAI,OAAO,CAAC;QACtB,OAAO,EAAE,MAAM,CAAC;QAChB,SAAS,EAAE,MAAM,CAAC;QAClB,MAAM,EAAE,MAAM,CAAC;KAClB,CAAC;CAqBL"}
@@ -209,6 +209,33 @@ class SQLiteStore {
209
209
  );
210
210
  }
211
211
  }
212
+ async updateList(key, updater) {
213
+ this.checkConnection();
214
+ try {
215
+ const transaction = this.db.transaction(() => {
216
+ const rows = this.db.prepare("SELECT value FROM list_store WHERE key = ? ORDER BY sequence ASC").all(key);
217
+ const current = rows.map((row) => JSON.parse(row.value));
218
+ const mutation = updater(current);
219
+ this.db.prepare("DELETE FROM list_store WHERE key = ?").run(key);
220
+ if (mutation.items.length > 0) {
221
+ const insert = this.db.prepare(
222
+ "INSERT INTO list_store (key, value, sequence) VALUES (?, ?, ?)"
223
+ );
224
+ for (const [index, item] of mutation.items.entries()) {
225
+ insert.run(key, JSON.stringify(item), index + 1);
226
+ }
227
+ }
228
+ return mutation.result;
229
+ });
230
+ return transaction();
231
+ } catch (error) {
232
+ throw StorageError.writeFailed(
233
+ "updateList",
234
+ error instanceof Error ? error.message : String(error),
235
+ { key }
236
+ );
237
+ }
238
+ }
212
239
  async getRange(key, start, count) {
213
240
  this.checkConnection();
214
241
  try {
package/dist/index.d.cts CHANGED
@@ -79,6 +79,10 @@ declare class MemoryDatabaseStore implements Database {
79
79
  delete(key: string): Promise<void>;
80
80
  list(prefix: string): Promise<string[]>;
81
81
  append<T>(key: string, item: T): Promise<void>;
82
+ updateList<T, R>(key: string, updater: (items: T[]) => {
83
+ items: T[];
84
+ result: R;
85
+ }): Promise<R>;
82
86
  getRange<T>(key: string, start: number, count: number): Promise<T[]>;
83
87
  private checkConnection;
84
88
  clear(): Promise<void>;
@@ -112,6 +116,10 @@ declare class SQLiteStore implements Database {
112
116
  delete(key: string): Promise<void>;
113
117
  list(prefix: string): Promise<string[]>;
114
118
  append<T>(key: string, item: T): Promise<void>;
119
+ updateList<T, R>(key: string, updater: (items: T[]) => {
120
+ items: T[];
121
+ result: R;
122
+ }): Promise<R>;
115
123
  getRange<T>(key: string, start: number, count: number): Promise<T[]>;
116
124
  private checkConnection;
117
125
  vacuum(): Promise<void>;
@@ -150,6 +158,10 @@ declare class PostgresStore implements Database {
150
158
  delete(key: string): Promise<void>;
151
159
  list(prefix: string): Promise<string[]>;
152
160
  append<T>(key: string, item: T): Promise<void>;
161
+ updateList<T, R>(key: string, updater: (items: T[]) => {
162
+ items: T[];
163
+ result: R;
164
+ }): Promise<R>;
153
165
  getRange<T>(key: string, start: number, count: number): Promise<T[]>;
154
166
  private createTables;
155
167
  private checkConnection;
@@ -169,6 +181,7 @@ declare class PostgresStore implements Database {
169
181
  * Ensure callback operations are idempotent or use this only for read operations.
170
182
  */
171
183
  transaction<T>(callback: (client: PoolClient) => Promise<T>): Promise<T>;
184
+ private transactionOnce;
172
185
  getStats(): Promise<{
173
186
  kvCount: number;
174
187
  listCount: number;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dexto/storage",
3
- "version": "1.8.11",
3
+ "version": "1.9.0",
4
4
  "description": "Storage backends and config schemas for Dexto agents",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -21,7 +21,7 @@
21
21
  ],
22
22
  "dependencies": {
23
23
  "zod": "^4.3.6",
24
- "@dexto/core": "1.8.11"
24
+ "@dexto/core": "1.9.0"
25
25
  },
26
26
  "peerDependencies": {
27
27
  "better-sqlite3": "^11.10.0",