@frontmcp/storage-sqlite 1.3.0 → 1.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/better-sqlite3-loader.d.ts +32 -0
- package/better-sqlite3-loader.d.ts.map +1 -0
- package/esm/index.mjs +176 -22
- package/esm/package.json +3 -3
- package/index.d.ts +3 -0
- package/index.d.ts.map +1 -1
- package/index.js +179 -24
- package/open-database.d.ts +25 -0
- package/open-database.d.ts.map +1 -0
- package/package.json +3 -3
- package/sqlite-event.store.d.ts.map +1 -1
- package/sqlite-kv.store.d.ts.map +1 -1
- package/sqlite-storage.adapter.d.ts +51 -0
- package/sqlite-storage.adapter.d.ts.map +1 -0
- package/sqlite-task.store.d.ts.map +1 -1
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* better-sqlite3 loader
|
|
3
|
+
*
|
|
4
|
+
* Resolving `better-sqlite3` is tricky because this package ships in BOTH
|
|
5
|
+
* CommonJS (`dist/index.js`) and ESM (`dist/esm/index.mjs`) flavors via esbuild
|
|
6
|
+
* with `better-sqlite3` marked `external`.
|
|
7
|
+
*
|
|
8
|
+
* In the ESM bundle, a bare `require(...)` is rewritten by esbuild into a
|
|
9
|
+
* `__require` shim that throws **"Dynamic require of \"fs\" is not supported"**
|
|
10
|
+
* the moment better-sqlite3 (a native addon) reaches for `fs`/`path`/`bindings`
|
|
11
|
+
* internally — UNLESS a real `require` exists in module scope for the shim to
|
|
12
|
+
* delegate to. The ESM build therefore injects a banner that defines
|
|
13
|
+
*
|
|
14
|
+
* ```js
|
|
15
|
+
* import { createRequire } from 'module';
|
|
16
|
+
* const require = createRequire(import.meta.url);
|
|
17
|
+
* ```
|
|
18
|
+
*
|
|
19
|
+
* (see `scripts/inject-esm-require-banner.js`). With that banner in place, the
|
|
20
|
+
* plain `require('better-sqlite3')` below resolves the addon **relative to the
|
|
21
|
+
* emitted bundle file** in both the CJS and ESM outputs, and better-sqlite3's
|
|
22
|
+
* own transitive `require('fs')` resolves natively.
|
|
23
|
+
*/
|
|
24
|
+
import type Database from 'better-sqlite3';
|
|
25
|
+
/**
|
|
26
|
+
* Resolve the `better-sqlite3` constructor in a way that works under both the
|
|
27
|
+
* CommonJS and ESM builds of this package.
|
|
28
|
+
*
|
|
29
|
+
* @throws Error if `better-sqlite3` cannot be resolved/loaded.
|
|
30
|
+
*/
|
|
31
|
+
export declare function loadBetterSqlite3(): typeof Database;
|
|
32
|
+
//# sourceMappingURL=better-sqlite3-loader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"better-sqlite3-loader.d.ts","sourceRoot":"","sources":["../src/better-sqlite3-loader.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAI3C;;;;;GAKG;AACH,wBAAgB,iBAAiB,IAAI,OAAO,QAAQ,CAWnD"}
|
package/esm/index.mjs
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { createRequire as __frontmcpCreateRequire } from 'module';
|
|
2
|
+
const require = __frontmcpCreateRequire(import.meta.url);
|
|
1
3
|
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
2
4
|
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
3
5
|
}) : x)(function(x) {
|
|
@@ -40,6 +42,43 @@ function decryptValue(key, encrypted) {
|
|
|
40
42
|
return new TextDecoder().decode(plaintext);
|
|
41
43
|
}
|
|
42
44
|
|
|
45
|
+
// libs/storage-sqlite/src/open-database.ts
|
|
46
|
+
import { dirname, ensureDirSync } from "@frontmcp/utils";
|
|
47
|
+
|
|
48
|
+
// libs/storage-sqlite/src/better-sqlite3-loader.ts
|
|
49
|
+
var cached = null;
|
|
50
|
+
function loadBetterSqlite3() {
|
|
51
|
+
if (cached) {
|
|
52
|
+
return cached;
|
|
53
|
+
}
|
|
54
|
+
const mod = __require("better-sqlite3");
|
|
55
|
+
cached = mod;
|
|
56
|
+
return mod;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// libs/storage-sqlite/src/open-database.ts
|
|
60
|
+
var MEMORY_PATH = ":memory:";
|
|
61
|
+
function openDatabase(path, storeName) {
|
|
62
|
+
const BetterSqlite3 = loadBetterSqlite3();
|
|
63
|
+
if (path !== MEMORY_PATH && path !== "") {
|
|
64
|
+
const dir = dirname(path);
|
|
65
|
+
if (dir && dir !== ".") {
|
|
66
|
+
try {
|
|
67
|
+
ensureDirSync(dir);
|
|
68
|
+
} catch (err) {
|
|
69
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
70
|
+
throw new Error(`${storeName}: failed to create directory "${dir}" for database "${path}": ${message}`);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
try {
|
|
75
|
+
return new BetterSqlite3(path);
|
|
76
|
+
} catch (err) {
|
|
77
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
78
|
+
throw new Error(`${storeName}: failed to open database at "${path}": ${message}`);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
43
82
|
// libs/storage-sqlite/src/sqlite-kv.store.ts
|
|
44
83
|
var SqliteKvStore = class {
|
|
45
84
|
db;
|
|
@@ -47,13 +86,7 @@ var SqliteKvStore = class {
|
|
|
47
86
|
cleanupTimer = null;
|
|
48
87
|
stmts = null;
|
|
49
88
|
constructor(options) {
|
|
50
|
-
|
|
51
|
-
try {
|
|
52
|
-
this.db = new BetterSqlite3(options.path);
|
|
53
|
-
} catch (err) {
|
|
54
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
55
|
-
throw new Error(`SqliteKvStore: failed to open database at "${options.path}": ${message}`);
|
|
56
|
-
}
|
|
89
|
+
this.db = openDatabase(options.path, "SqliteKvStore");
|
|
57
90
|
if (options.walMode !== false) {
|
|
58
91
|
this.db.pragma("journal_mode = WAL");
|
|
59
92
|
}
|
|
@@ -87,7 +120,11 @@ var SqliteKvStore = class {
|
|
|
87
120
|
del: this.db.prepare("DELETE FROM kv WHERE key = ?"),
|
|
88
121
|
has: this.db.prepare("SELECT 1 FROM kv WHERE key = ? AND (expires_at IS NULL OR expires_at > ?)"),
|
|
89
122
|
keys: this.db.prepare("SELECT key FROM kv WHERE (expires_at IS NULL OR expires_at > ?)"),
|
|
90
|
-
keysPattern: this.db.prepare(
|
|
123
|
+
keysPattern: this.db.prepare(
|
|
124
|
+
// ESCAPE '\' lets callers (e.g. SqliteStorageAdapter.keys) escape literal
|
|
125
|
+
// `%`/`_` as `\%`/`\_`; without it SQLite treats the backslash literally.
|
|
126
|
+
"SELECT key FROM kv WHERE key LIKE ? ESCAPE '\\' AND (expires_at IS NULL OR expires_at > ?)"
|
|
127
|
+
),
|
|
91
128
|
cleanup: this.db.prepare("DELETE FROM kv WHERE expires_at IS NOT NULL AND expires_at <= ?"),
|
|
92
129
|
ttl: this.db.prepare("SELECT expires_at FROM kv WHERE key = ?"),
|
|
93
130
|
expire: this.db.prepare("UPDATE kv SET expires_at = ? WHERE key = ?")
|
|
@@ -235,6 +272,132 @@ var SqliteKvStore = class {
|
|
|
235
272
|
}
|
|
236
273
|
};
|
|
237
274
|
|
|
275
|
+
// libs/storage-sqlite/src/sqlite-storage.adapter.ts
|
|
276
|
+
import { BaseStorageAdapter } from "@frontmcp/utils";
|
|
277
|
+
var SqliteStorageAdapter = class extends BaseStorageAdapter {
|
|
278
|
+
backendName = "sqlite";
|
|
279
|
+
kv;
|
|
280
|
+
/**
|
|
281
|
+
* Whether this adapter created (and therefore owns the lifecycle of) `kv`.
|
|
282
|
+
* When the store is passed in by the caller, closing it is the caller's
|
|
283
|
+
* responsibility — `disconnect()` must not pull the rug out from under it.
|
|
284
|
+
*/
|
|
285
|
+
ownsKvStore;
|
|
286
|
+
constructor(options) {
|
|
287
|
+
super();
|
|
288
|
+
this.ownsKvStore = !(options instanceof SqliteKvStore);
|
|
289
|
+
this.kv = options instanceof SqliteKvStore ? options : new SqliteKvStore(options);
|
|
290
|
+
}
|
|
291
|
+
// ============================================
|
|
292
|
+
// Connection Lifecycle
|
|
293
|
+
// ============================================
|
|
294
|
+
async connect() {
|
|
295
|
+
this.connected = true;
|
|
296
|
+
}
|
|
297
|
+
async disconnect() {
|
|
298
|
+
if (!this.connected) return;
|
|
299
|
+
this.connected = false;
|
|
300
|
+
if (this.ownsKvStore && this.kv) {
|
|
301
|
+
this.kv.close();
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
async ping() {
|
|
305
|
+
if (!this.connected) return false;
|
|
306
|
+
try {
|
|
307
|
+
this.kv.has("__frontmcp_ping__");
|
|
308
|
+
return true;
|
|
309
|
+
} catch {
|
|
310
|
+
return false;
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
// ============================================
|
|
314
|
+
// Core Operations
|
|
315
|
+
// ============================================
|
|
316
|
+
async get(key) {
|
|
317
|
+
this.ensureConnected();
|
|
318
|
+
return this.kv.get(key);
|
|
319
|
+
}
|
|
320
|
+
async doSet(key, value, options) {
|
|
321
|
+
if (options?.ifNotExists && this.kv.has(key)) {
|
|
322
|
+
return;
|
|
323
|
+
}
|
|
324
|
+
if (options?.ifExists && !this.kv.has(key)) {
|
|
325
|
+
return;
|
|
326
|
+
}
|
|
327
|
+
const ttlMs = options?.ttlSeconds !== void 0 ? options.ttlSeconds * 1e3 : void 0;
|
|
328
|
+
this.kv.set(key, value, ttlMs);
|
|
329
|
+
}
|
|
330
|
+
async delete(key) {
|
|
331
|
+
this.ensureConnected();
|
|
332
|
+
const existed = this.kv.has(key);
|
|
333
|
+
this.kv.del(key);
|
|
334
|
+
return existed;
|
|
335
|
+
}
|
|
336
|
+
async exists(key) {
|
|
337
|
+
this.ensureConnected();
|
|
338
|
+
return this.kv.has(key);
|
|
339
|
+
}
|
|
340
|
+
// ============================================
|
|
341
|
+
// TTL Operations
|
|
342
|
+
// ============================================
|
|
343
|
+
async expire(key, ttlSeconds) {
|
|
344
|
+
this.ensureConnected();
|
|
345
|
+
return this.kv.expire(key, ttlSeconds * 1e3);
|
|
346
|
+
}
|
|
347
|
+
async ttl(key) {
|
|
348
|
+
this.ensureConnected();
|
|
349
|
+
const ms = this.kv.ttl(key);
|
|
350
|
+
if (ms === -2) return null;
|
|
351
|
+
if (ms === -1) return -1;
|
|
352
|
+
return Math.max(0, Math.ceil(ms / 1e3));
|
|
353
|
+
}
|
|
354
|
+
// ============================================
|
|
355
|
+
// Key Enumeration
|
|
356
|
+
// ============================================
|
|
357
|
+
async keys(pattern = "*") {
|
|
358
|
+
this.ensureConnected();
|
|
359
|
+
if (pattern === "*" || pattern === void 0) {
|
|
360
|
+
return this.kv.keys();
|
|
361
|
+
}
|
|
362
|
+
const like = pattern.replace(/[%_]/g, (c) => `\\${c}`).replace(/\*/g, "%").replace(/\?/g, "_");
|
|
363
|
+
return this.kv.keys(like);
|
|
364
|
+
}
|
|
365
|
+
// ============================================
|
|
366
|
+
// Atomic Operations (read-modify-write; single-process local file)
|
|
367
|
+
// ============================================
|
|
368
|
+
async incr(key) {
|
|
369
|
+
return this.incrBy(key, 1);
|
|
370
|
+
}
|
|
371
|
+
async decr(key) {
|
|
372
|
+
return this.incrBy(key, -1);
|
|
373
|
+
}
|
|
374
|
+
async incrBy(key, amount) {
|
|
375
|
+
this.ensureConnected();
|
|
376
|
+
const current = this.kv.get(key);
|
|
377
|
+
let base = 0;
|
|
378
|
+
if (current !== null) {
|
|
379
|
+
const parsed = Number.parseInt(current, 10);
|
|
380
|
+
if (Number.isNaN(parsed)) {
|
|
381
|
+
throw new Error(`SqliteStorageAdapter: value at "${key}" is not an integer`);
|
|
382
|
+
}
|
|
383
|
+
base = parsed;
|
|
384
|
+
}
|
|
385
|
+
const next = base + amount;
|
|
386
|
+
const remainingMs = this.kv.ttl(key);
|
|
387
|
+
this.kv.set(key, String(next), remainingMs > 0 ? remainingMs : void 0);
|
|
388
|
+
return next;
|
|
389
|
+
}
|
|
390
|
+
/**
|
|
391
|
+
* Expose the underlying KV store (advanced use / tests).
|
|
392
|
+
*/
|
|
393
|
+
getKvStore() {
|
|
394
|
+
return this.kv;
|
|
395
|
+
}
|
|
396
|
+
getPubSubSuggestion() {
|
|
397
|
+
return "SQLite adapter does not support pub/sub. Use Redis or Upstash for pub/sub support.";
|
|
398
|
+
}
|
|
399
|
+
};
|
|
400
|
+
|
|
238
401
|
// libs/storage-sqlite/src/sqlite-session.store.ts
|
|
239
402
|
import { randomUUID } from "@frontmcp/utils";
|
|
240
403
|
var SqliteSessionStore = class {
|
|
@@ -397,13 +560,7 @@ var SqliteTaskStore = class {
|
|
|
397
560
|
encryptionKey = null;
|
|
398
561
|
stmts = null;
|
|
399
562
|
constructor(options) {
|
|
400
|
-
|
|
401
|
-
try {
|
|
402
|
-
this.db = new BetterSqlite3(options.path);
|
|
403
|
-
} catch (err) {
|
|
404
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
405
|
-
throw new Error(`SqliteTaskStore: failed to open database at "${options.path}": ${message}`);
|
|
406
|
-
}
|
|
563
|
+
this.db = openDatabase(options.path, "SqliteTaskStore");
|
|
407
564
|
if (options.walMode !== false) {
|
|
408
565
|
this.db.pragma("journal_mode = WAL");
|
|
409
566
|
}
|
|
@@ -652,13 +809,7 @@ var SqliteEventStore = class {
|
|
|
652
809
|
cleanupTimer = null;
|
|
653
810
|
stmts = null;
|
|
654
811
|
constructor(options) {
|
|
655
|
-
|
|
656
|
-
try {
|
|
657
|
-
this.db = new BetterSqlite3(options.path);
|
|
658
|
-
} catch (err) {
|
|
659
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
660
|
-
throw new Error(`SqliteEventStore: failed to open database at "${options.path}": ${message}`);
|
|
661
|
-
}
|
|
812
|
+
this.db = openDatabase(options.path, "SqliteEventStore");
|
|
662
813
|
if (options.walMode !== false) {
|
|
663
814
|
this.db.pragma("journal_mode = WAL");
|
|
664
815
|
}
|
|
@@ -804,9 +955,12 @@ export {
|
|
|
804
955
|
SqliteEventStore,
|
|
805
956
|
SqliteKvStore,
|
|
806
957
|
SqliteSessionStore,
|
|
958
|
+
SqliteStorageAdapter,
|
|
807
959
|
SqliteTaskStore,
|
|
808
960
|
decryptValue,
|
|
809
961
|
deriveEncryptionKey,
|
|
810
962
|
encryptValue,
|
|
963
|
+
loadBetterSqlite3,
|
|
964
|
+
openDatabase,
|
|
811
965
|
sqliteStorageOptionsSchema
|
|
812
966
|
};
|
package/esm/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@frontmcp/storage-sqlite",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.1",
|
|
4
4
|
"description": "SQLite storage backend for FrontMCP - local session, elicitation, and event persistence without Redis",
|
|
5
5
|
"author": "AgentFront <info@agentfront.dev>",
|
|
6
6
|
"homepage": "https://docs.agentfront.dev",
|
|
@@ -44,11 +44,11 @@
|
|
|
44
44
|
"node": ">=24.0.0"
|
|
45
45
|
},
|
|
46
46
|
"dependencies": {
|
|
47
|
-
"@frontmcp/utils": "1.
|
|
47
|
+
"@frontmcp/utils": "1.4.1",
|
|
48
48
|
"better-sqlite3": "^12.6.2"
|
|
49
49
|
},
|
|
50
50
|
"peerDependencies": {
|
|
51
|
-
"@frontmcp/lazy-zod": "1.
|
|
51
|
+
"@frontmcp/lazy-zod": "1.4.1"
|
|
52
52
|
},
|
|
53
53
|
"devDependencies": {
|
|
54
54
|
"@types/better-sqlite3": "^7.6.13",
|
package/index.d.ts
CHANGED
|
@@ -5,6 +5,9 @@
|
|
|
5
5
|
* Provides local session, elicitation, and event persistence without Redis.
|
|
6
6
|
*/
|
|
7
7
|
export { SqliteKvStore } from './sqlite-kv.store';
|
|
8
|
+
export { SqliteStorageAdapter } from './sqlite-storage.adapter';
|
|
9
|
+
export { openDatabase } from './open-database';
|
|
10
|
+
export { loadBetterSqlite3 } from './better-sqlite3-loader';
|
|
8
11
|
export { SqliteSessionStore } from './sqlite-session.store';
|
|
9
12
|
export type { SqliteSessionStoreOptions, SessionStoreInterface, StoredSessionData } from './sqlite-session.store';
|
|
10
13
|
export { SqliteElicitationStore } from './sqlite-elicitation.store';
|
package/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAC5D,YAAY,EAAE,yBAAyB,EAAE,qBAAqB,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAClH,OAAO,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AACpE,YAAY,EAAE,6BAA6B,EAAE,yBAAyB,EAAE,MAAM,4BAA4B,CAAC;AAC3G,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACtD,YAAY,EACV,sBAAsB,EACtB,kBAAkB,EAClB,UAAU,IAAI,gBAAgB,EAC9B,UAAU,IAAI,gBAAgB,EAC9B,WAAW,IAAI,iBAAiB,EAChC,YAAY,IAAI,kBAAkB,EAClC,oBAAoB,EACpB,gBAAgB,GACjB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACxD,YAAY,EAAE,uBAAuB,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AACzF,OAAO,EAAE,mBAAmB,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC/E,OAAO,EAAE,0BAA0B,EAAE,MAAM,kBAAkB,CAAC;AAC9D,YAAY,EAAE,oBAAoB,EAAE,yBAAyB,EAAE,0BAA0B,EAAE,MAAM,kBAAkB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAChE,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAC5D,YAAY,EAAE,yBAAyB,EAAE,qBAAqB,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAClH,OAAO,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AACpE,YAAY,EAAE,6BAA6B,EAAE,yBAAyB,EAAE,MAAM,4BAA4B,CAAC;AAC3G,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACtD,YAAY,EACV,sBAAsB,EACtB,kBAAkB,EAClB,UAAU,IAAI,gBAAgB,EAC9B,UAAU,IAAI,gBAAgB,EAC9B,WAAW,IAAI,iBAAiB,EAChC,YAAY,IAAI,kBAAkB,EAClC,oBAAoB,EACpB,gBAAgB,GACjB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACxD,YAAY,EAAE,uBAAuB,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AACzF,OAAO,EAAE,mBAAmB,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC/E,OAAO,EAAE,0BAA0B,EAAE,MAAM,kBAAkB,CAAC;AAC9D,YAAY,EAAE,oBAAoB,EAAE,yBAAyB,EAAE,0BAA0B,EAAE,MAAM,kBAAkB,CAAC"}
|
package/index.js
CHANGED
|
@@ -24,10 +24,13 @@ __export(index_exports, {
|
|
|
24
24
|
SqliteEventStore: () => SqliteEventStore,
|
|
25
25
|
SqliteKvStore: () => SqliteKvStore,
|
|
26
26
|
SqliteSessionStore: () => SqliteSessionStore,
|
|
27
|
+
SqliteStorageAdapter: () => SqliteStorageAdapter,
|
|
27
28
|
SqliteTaskStore: () => SqliteTaskStore,
|
|
28
29
|
decryptValue: () => decryptValue,
|
|
29
30
|
deriveEncryptionKey: () => deriveEncryptionKey,
|
|
30
31
|
encryptValue: () => encryptValue,
|
|
32
|
+
loadBetterSqlite3: () => loadBetterSqlite3,
|
|
33
|
+
openDatabase: () => openDatabase,
|
|
31
34
|
sqliteStorageOptionsSchema: () => sqliteStorageOptionsSchema
|
|
32
35
|
});
|
|
33
36
|
module.exports = __toCommonJS(index_exports);
|
|
@@ -60,6 +63,43 @@ function decryptValue(key, encrypted) {
|
|
|
60
63
|
return new TextDecoder().decode(plaintext);
|
|
61
64
|
}
|
|
62
65
|
|
|
66
|
+
// libs/storage-sqlite/src/open-database.ts
|
|
67
|
+
var import_utils2 = require("@frontmcp/utils");
|
|
68
|
+
|
|
69
|
+
// libs/storage-sqlite/src/better-sqlite3-loader.ts
|
|
70
|
+
var cached = null;
|
|
71
|
+
function loadBetterSqlite3() {
|
|
72
|
+
if (cached) {
|
|
73
|
+
return cached;
|
|
74
|
+
}
|
|
75
|
+
const mod = require("better-sqlite3");
|
|
76
|
+
cached = mod;
|
|
77
|
+
return mod;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// libs/storage-sqlite/src/open-database.ts
|
|
81
|
+
var MEMORY_PATH = ":memory:";
|
|
82
|
+
function openDatabase(path, storeName) {
|
|
83
|
+
const BetterSqlite3 = loadBetterSqlite3();
|
|
84
|
+
if (path !== MEMORY_PATH && path !== "") {
|
|
85
|
+
const dir = (0, import_utils2.dirname)(path);
|
|
86
|
+
if (dir && dir !== ".") {
|
|
87
|
+
try {
|
|
88
|
+
(0, import_utils2.ensureDirSync)(dir);
|
|
89
|
+
} catch (err) {
|
|
90
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
91
|
+
throw new Error(`${storeName}: failed to create directory "${dir}" for database "${path}": ${message}`);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
try {
|
|
96
|
+
return new BetterSqlite3(path);
|
|
97
|
+
} catch (err) {
|
|
98
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
99
|
+
throw new Error(`${storeName}: failed to open database at "${path}": ${message}`);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
63
103
|
// libs/storage-sqlite/src/sqlite-kv.store.ts
|
|
64
104
|
var SqliteKvStore = class {
|
|
65
105
|
db;
|
|
@@ -67,13 +107,7 @@ var SqliteKvStore = class {
|
|
|
67
107
|
cleanupTimer = null;
|
|
68
108
|
stmts = null;
|
|
69
109
|
constructor(options) {
|
|
70
|
-
|
|
71
|
-
try {
|
|
72
|
-
this.db = new BetterSqlite3(options.path);
|
|
73
|
-
} catch (err) {
|
|
74
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
75
|
-
throw new Error(`SqliteKvStore: failed to open database at "${options.path}": ${message}`);
|
|
76
|
-
}
|
|
110
|
+
this.db = openDatabase(options.path, "SqliteKvStore");
|
|
77
111
|
if (options.walMode !== false) {
|
|
78
112
|
this.db.pragma("journal_mode = WAL");
|
|
79
113
|
}
|
|
@@ -107,7 +141,11 @@ var SqliteKvStore = class {
|
|
|
107
141
|
del: this.db.prepare("DELETE FROM kv WHERE key = ?"),
|
|
108
142
|
has: this.db.prepare("SELECT 1 FROM kv WHERE key = ? AND (expires_at IS NULL OR expires_at > ?)"),
|
|
109
143
|
keys: this.db.prepare("SELECT key FROM kv WHERE (expires_at IS NULL OR expires_at > ?)"),
|
|
110
|
-
keysPattern: this.db.prepare(
|
|
144
|
+
keysPattern: this.db.prepare(
|
|
145
|
+
// ESCAPE '\' lets callers (e.g. SqliteStorageAdapter.keys) escape literal
|
|
146
|
+
// `%`/`_` as `\%`/`\_`; without it SQLite treats the backslash literally.
|
|
147
|
+
"SELECT key FROM kv WHERE key LIKE ? ESCAPE '\\' AND (expires_at IS NULL OR expires_at > ?)"
|
|
148
|
+
),
|
|
111
149
|
cleanup: this.db.prepare("DELETE FROM kv WHERE expires_at IS NOT NULL AND expires_at <= ?"),
|
|
112
150
|
ttl: this.db.prepare("SELECT expires_at FROM kv WHERE key = ?"),
|
|
113
151
|
expire: this.db.prepare("UPDATE kv SET expires_at = ? WHERE key = ?")
|
|
@@ -255,8 +293,134 @@ var SqliteKvStore = class {
|
|
|
255
293
|
}
|
|
256
294
|
};
|
|
257
295
|
|
|
296
|
+
// libs/storage-sqlite/src/sqlite-storage.adapter.ts
|
|
297
|
+
var import_utils3 = require("@frontmcp/utils");
|
|
298
|
+
var SqliteStorageAdapter = class extends import_utils3.BaseStorageAdapter {
|
|
299
|
+
backendName = "sqlite";
|
|
300
|
+
kv;
|
|
301
|
+
/**
|
|
302
|
+
* Whether this adapter created (and therefore owns the lifecycle of) `kv`.
|
|
303
|
+
* When the store is passed in by the caller, closing it is the caller's
|
|
304
|
+
* responsibility — `disconnect()` must not pull the rug out from under it.
|
|
305
|
+
*/
|
|
306
|
+
ownsKvStore;
|
|
307
|
+
constructor(options) {
|
|
308
|
+
super();
|
|
309
|
+
this.ownsKvStore = !(options instanceof SqliteKvStore);
|
|
310
|
+
this.kv = options instanceof SqliteKvStore ? options : new SqliteKvStore(options);
|
|
311
|
+
}
|
|
312
|
+
// ============================================
|
|
313
|
+
// Connection Lifecycle
|
|
314
|
+
// ============================================
|
|
315
|
+
async connect() {
|
|
316
|
+
this.connected = true;
|
|
317
|
+
}
|
|
318
|
+
async disconnect() {
|
|
319
|
+
if (!this.connected) return;
|
|
320
|
+
this.connected = false;
|
|
321
|
+
if (this.ownsKvStore && this.kv) {
|
|
322
|
+
this.kv.close();
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
async ping() {
|
|
326
|
+
if (!this.connected) return false;
|
|
327
|
+
try {
|
|
328
|
+
this.kv.has("__frontmcp_ping__");
|
|
329
|
+
return true;
|
|
330
|
+
} catch {
|
|
331
|
+
return false;
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
// ============================================
|
|
335
|
+
// Core Operations
|
|
336
|
+
// ============================================
|
|
337
|
+
async get(key) {
|
|
338
|
+
this.ensureConnected();
|
|
339
|
+
return this.kv.get(key);
|
|
340
|
+
}
|
|
341
|
+
async doSet(key, value, options) {
|
|
342
|
+
if (options?.ifNotExists && this.kv.has(key)) {
|
|
343
|
+
return;
|
|
344
|
+
}
|
|
345
|
+
if (options?.ifExists && !this.kv.has(key)) {
|
|
346
|
+
return;
|
|
347
|
+
}
|
|
348
|
+
const ttlMs = options?.ttlSeconds !== void 0 ? options.ttlSeconds * 1e3 : void 0;
|
|
349
|
+
this.kv.set(key, value, ttlMs);
|
|
350
|
+
}
|
|
351
|
+
async delete(key) {
|
|
352
|
+
this.ensureConnected();
|
|
353
|
+
const existed = this.kv.has(key);
|
|
354
|
+
this.kv.del(key);
|
|
355
|
+
return existed;
|
|
356
|
+
}
|
|
357
|
+
async exists(key) {
|
|
358
|
+
this.ensureConnected();
|
|
359
|
+
return this.kv.has(key);
|
|
360
|
+
}
|
|
361
|
+
// ============================================
|
|
362
|
+
// TTL Operations
|
|
363
|
+
// ============================================
|
|
364
|
+
async expire(key, ttlSeconds) {
|
|
365
|
+
this.ensureConnected();
|
|
366
|
+
return this.kv.expire(key, ttlSeconds * 1e3);
|
|
367
|
+
}
|
|
368
|
+
async ttl(key) {
|
|
369
|
+
this.ensureConnected();
|
|
370
|
+
const ms = this.kv.ttl(key);
|
|
371
|
+
if (ms === -2) return null;
|
|
372
|
+
if (ms === -1) return -1;
|
|
373
|
+
return Math.max(0, Math.ceil(ms / 1e3));
|
|
374
|
+
}
|
|
375
|
+
// ============================================
|
|
376
|
+
// Key Enumeration
|
|
377
|
+
// ============================================
|
|
378
|
+
async keys(pattern = "*") {
|
|
379
|
+
this.ensureConnected();
|
|
380
|
+
if (pattern === "*" || pattern === void 0) {
|
|
381
|
+
return this.kv.keys();
|
|
382
|
+
}
|
|
383
|
+
const like = pattern.replace(/[%_]/g, (c) => `\\${c}`).replace(/\*/g, "%").replace(/\?/g, "_");
|
|
384
|
+
return this.kv.keys(like);
|
|
385
|
+
}
|
|
386
|
+
// ============================================
|
|
387
|
+
// Atomic Operations (read-modify-write; single-process local file)
|
|
388
|
+
// ============================================
|
|
389
|
+
async incr(key) {
|
|
390
|
+
return this.incrBy(key, 1);
|
|
391
|
+
}
|
|
392
|
+
async decr(key) {
|
|
393
|
+
return this.incrBy(key, -1);
|
|
394
|
+
}
|
|
395
|
+
async incrBy(key, amount) {
|
|
396
|
+
this.ensureConnected();
|
|
397
|
+
const current = this.kv.get(key);
|
|
398
|
+
let base = 0;
|
|
399
|
+
if (current !== null) {
|
|
400
|
+
const parsed = Number.parseInt(current, 10);
|
|
401
|
+
if (Number.isNaN(parsed)) {
|
|
402
|
+
throw new Error(`SqliteStorageAdapter: value at "${key}" is not an integer`);
|
|
403
|
+
}
|
|
404
|
+
base = parsed;
|
|
405
|
+
}
|
|
406
|
+
const next = base + amount;
|
|
407
|
+
const remainingMs = this.kv.ttl(key);
|
|
408
|
+
this.kv.set(key, String(next), remainingMs > 0 ? remainingMs : void 0);
|
|
409
|
+
return next;
|
|
410
|
+
}
|
|
411
|
+
/**
|
|
412
|
+
* Expose the underlying KV store (advanced use / tests).
|
|
413
|
+
*/
|
|
414
|
+
getKvStore() {
|
|
415
|
+
return this.kv;
|
|
416
|
+
}
|
|
417
|
+
getPubSubSuggestion() {
|
|
418
|
+
return "SQLite adapter does not support pub/sub. Use Redis or Upstash for pub/sub support.";
|
|
419
|
+
}
|
|
420
|
+
};
|
|
421
|
+
|
|
258
422
|
// libs/storage-sqlite/src/sqlite-session.store.ts
|
|
259
|
-
var
|
|
423
|
+
var import_utils4 = require("@frontmcp/utils");
|
|
260
424
|
var SqliteSessionStore = class {
|
|
261
425
|
kv;
|
|
262
426
|
keyPrefix;
|
|
@@ -282,7 +446,7 @@ var SqliteSessionStore = class {
|
|
|
282
446
|
return this.kv.has(this.sessionKey(sessionId));
|
|
283
447
|
}
|
|
284
448
|
allocId() {
|
|
285
|
-
return (0,
|
|
449
|
+
return (0, import_utils4.randomUUID)();
|
|
286
450
|
}
|
|
287
451
|
/**
|
|
288
452
|
* Close the underlying SQLite connection.
|
|
@@ -417,13 +581,7 @@ var SqliteTaskStore = class {
|
|
|
417
581
|
encryptionKey = null;
|
|
418
582
|
stmts = null;
|
|
419
583
|
constructor(options) {
|
|
420
|
-
|
|
421
|
-
try {
|
|
422
|
-
this.db = new BetterSqlite3(options.path);
|
|
423
|
-
} catch (err) {
|
|
424
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
425
|
-
throw new Error(`SqliteTaskStore: failed to open database at "${options.path}": ${message}`);
|
|
426
|
-
}
|
|
584
|
+
this.db = openDatabase(options.path, "SqliteTaskStore");
|
|
427
585
|
if (options.walMode !== false) {
|
|
428
586
|
this.db.pragma("journal_mode = WAL");
|
|
429
587
|
}
|
|
@@ -672,13 +830,7 @@ var SqliteEventStore = class {
|
|
|
672
830
|
cleanupTimer = null;
|
|
673
831
|
stmts = null;
|
|
674
832
|
constructor(options) {
|
|
675
|
-
|
|
676
|
-
try {
|
|
677
|
-
this.db = new BetterSqlite3(options.path);
|
|
678
|
-
} catch (err) {
|
|
679
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
680
|
-
throw new Error(`SqliteEventStore: failed to open database at "${options.path}": ${message}`);
|
|
681
|
-
}
|
|
833
|
+
this.db = openDatabase(options.path, "SqliteEventStore");
|
|
682
834
|
if (options.walMode !== false) {
|
|
683
835
|
this.db.pragma("journal_mode = WAL");
|
|
684
836
|
}
|
|
@@ -825,9 +977,12 @@ var sqliteStorageOptionsSchema = import_lazy_zod.z.object({
|
|
|
825
977
|
SqliteEventStore,
|
|
826
978
|
SqliteKvStore,
|
|
827
979
|
SqliteSessionStore,
|
|
980
|
+
SqliteStorageAdapter,
|
|
828
981
|
SqliteTaskStore,
|
|
829
982
|
decryptValue,
|
|
830
983
|
deriveEncryptionKey,
|
|
831
984
|
encryptValue,
|
|
985
|
+
loadBetterSqlite3,
|
|
986
|
+
openDatabase,
|
|
832
987
|
sqliteStorageOptionsSchema
|
|
833
988
|
});
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* openDatabase
|
|
3
|
+
*
|
|
4
|
+
* Shared helper to open a better-sqlite3 database file. Centralizes two
|
|
5
|
+
* concerns that every file-backed SQLite store needs:
|
|
6
|
+
*
|
|
7
|
+
* 1. **Parent-directory creation.** better-sqlite3 will NOT create missing
|
|
8
|
+
* parent directories — opening `~/.frontmcp/data/auth.sqlite` when
|
|
9
|
+
* `~/.frontmcp/data` does not exist throws `SQLITE_CANTOPEN`. We create the
|
|
10
|
+
* parent dir synchronously first (skipping the special `:memory:` path).
|
|
11
|
+
*
|
|
12
|
+
* 2. **ESM-safe native module load.** See {@link loadBetterSqlite3}.
|
|
13
|
+
*/
|
|
14
|
+
import type Database from 'better-sqlite3';
|
|
15
|
+
/**
|
|
16
|
+
* Open (or create) a better-sqlite3 database at `path`, creating the parent
|
|
17
|
+
* directory if necessary.
|
|
18
|
+
*
|
|
19
|
+
* @param path - Filesystem path to the `.sqlite` file, or `:memory:`.
|
|
20
|
+
* @param storeName - Name used in error messages (e.g. `'SqliteKvStore'`).
|
|
21
|
+
* @returns An open better-sqlite3 `Database` instance.
|
|
22
|
+
* @throws Error wrapping the underlying failure with the store name and path.
|
|
23
|
+
*/
|
|
24
|
+
export declare function openDatabase(path: string, storeName: string): Database.Database;
|
|
25
|
+
//# sourceMappingURL=open-database.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"open-database.d.ts","sourceRoot":"","sources":["../src/open-database.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAS3C;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,QAAQ,CAAC,QAAQ,CAwB/E"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@frontmcp/storage-sqlite",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.1",
|
|
4
4
|
"description": "SQLite storage backend for FrontMCP - local session, elicitation, and event persistence without Redis",
|
|
5
5
|
"author": "AgentFront <info@agentfront.dev>",
|
|
6
6
|
"homepage": "https://docs.agentfront.dev",
|
|
@@ -44,11 +44,11 @@
|
|
|
44
44
|
"node": ">=24.0.0"
|
|
45
45
|
},
|
|
46
46
|
"dependencies": {
|
|
47
|
-
"@frontmcp/utils": "1.
|
|
47
|
+
"@frontmcp/utils": "1.4.1",
|
|
48
48
|
"better-sqlite3": "^12.6.2"
|
|
49
49
|
},
|
|
50
50
|
"peerDependencies": {
|
|
51
|
-
"@frontmcp/lazy-zod": "1.
|
|
51
|
+
"@frontmcp/lazy-zod": "1.4.1"
|
|
52
52
|
},
|
|
53
53
|
"devDependencies": {
|
|
54
54
|
"@types/better-sqlite3": "^7.6.13",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sqlite-event.store.d.ts","sourceRoot":"","sources":["../src/sqlite-event.store.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"sqlite-event.store.d.ts","sourceRoot":"","sources":["../src/sqlite-event.store.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAG3C,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAE7D;;;GAGG;AACH,MAAM,WAAW,mBAAmB;IAClC,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAChE,iBAAiB,CACf,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE;QAAE,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;KAAE,GACxE,OAAO,CAAC,MAAM,CAAC,CAAC;CACpB;AAED,MAAM,WAAW,uBAAwB,SAAQ,oBAAoB;IACnE,wEAAwE;IACxE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,yEAAyE;IACzE,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAaD;;;;;;;;;;;;GAYG;AACH,qBAAa,gBAAiB,YAAW,mBAAmB;IAC1D,OAAO,CAAC,EAAE,CAAoB;IAC9B,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,QAAQ,CAA6B;IAC7C,OAAO,CAAC,YAAY,CAA+C;IACnE,OAAO,CAAC,KAAK,CAAmC;gBAEpC,OAAO,EAAE,uBAAuB;IAwB5C,OAAO,CAAC,UAAU;IAalB,OAAO,CAAC,iBAAiB;IAgBzB;;OAEG;IACH,OAAO,CAAC,QAAQ;IAOhB;;OAEG;IACH,OAAO,CAAC,cAAc;IAmBhB,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC;IAoB/D,iBAAiB,CACrB,WAAW,EAAE,MAAM,EACnB,EAAE,IAAI,EAAE,EAAE;QAAE,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;KAAE,GACvE,OAAO,CAAC,MAAM,CAAC;IAyBlB,OAAO,CAAC,YAAY;IAMpB;;OAEG;IACH,KAAK,IAAI,IAAI;IAQb;;OAEG;IACH,WAAW,IAAI,QAAQ,CAAC,QAAQ;IAIhC;;OAEG;IACH,IAAI,IAAI,IAAI,MAAM,CAIjB;CACF"}
|
package/sqlite-kv.store.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sqlite-kv.store.d.ts","sourceRoot":"","sources":["../src/sqlite-kv.store.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"sqlite-kv.store.d.ts","sourceRoot":"","sources":["../src/sqlite-kv.store.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAI3C,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAe7D;;;;;;;;;;;GAWG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,EAAE,CAAoB;IAC9B,OAAO,CAAC,aAAa,CAA2B;IAChD,OAAO,CAAC,YAAY,CAA+C;IACnE,OAAO,CAAC,KAAK,CAAqC;gBAEtC,OAAO,EAAE,oBAAoB;IA4BzC,OAAO,CAAC,UAAU;IAWlB,OAAO,CAAC,iBAAiB;IAkBzB;;OAEG;IACH,OAAO,CAAC,QAAQ;IAOhB;;;OAGG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAmB/B;;OAEG;IACH,OAAO,CAAC,CAAC,GAAG,OAAO,EAAE,GAAG,EAAE,MAAM,GAAG,CAAC,GAAG,IAAI;IAW3C;;;;;;OAMG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI;IASrD;;OAEG;IACH,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI;IAI1D;;OAEG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAItB;;OAEG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAKzB;;;;;;OAMG;IACH,IAAI,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE;IAchC;;;;;;OAMG;IACH,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO;IAM3C;;;;OAIG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM;IAexB;;;OAGG;IACH,YAAY,IAAI,MAAM;IAKtB;;OAEG;IACH,KAAK,IAAI,IAAI;IAQb;;OAEG;IACH,WAAW,IAAI,QAAQ,CAAC,QAAQ;CAGjC"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SqliteStorageAdapter
|
|
3
|
+
*
|
|
4
|
+
* Adapts the synchronous {@link SqliteKvStore} to the async `StorageAdapter`
|
|
5
|
+
* contract from `@frontmcp/utils`, so SQLite can be used anywhere a
|
|
6
|
+
* StorageAdapter is expected (e.g. `StorageTokenStore`, `StorageAuthorizationVault`,
|
|
7
|
+
* and the auth token-storage factory).
|
|
8
|
+
*
|
|
9
|
+
* Extends `BaseStorageAdapter` to inherit the batch (`mget`/`mset`/`mdelete`),
|
|
10
|
+
* `count`, and "pub/sub not supported" defaults. Only the SQLite-specific core
|
|
11
|
+
* is implemented here.
|
|
12
|
+
*
|
|
13
|
+
* Notes:
|
|
14
|
+
* - All operations are backed by a single local SQLite file; "async" here just
|
|
15
|
+
* wraps synchronous better-sqlite3 calls in resolved promises.
|
|
16
|
+
* - Pub/sub is NOT supported (single-process local file). Callers needing
|
|
17
|
+
* pub/sub must use Redis/Upstash.
|
|
18
|
+
*/
|
|
19
|
+
import { BaseStorageAdapter, type SetOptions } from '@frontmcp/utils';
|
|
20
|
+
import { SqliteKvStore } from './sqlite-kv.store';
|
|
21
|
+
import { type SqliteStorageOptions } from './sqlite.options';
|
|
22
|
+
export declare class SqliteStorageAdapter extends BaseStorageAdapter {
|
|
23
|
+
protected readonly backendName = "sqlite";
|
|
24
|
+
private readonly kv;
|
|
25
|
+
/**
|
|
26
|
+
* Whether this adapter created (and therefore owns the lifecycle of) `kv`.
|
|
27
|
+
* When the store is passed in by the caller, closing it is the caller's
|
|
28
|
+
* responsibility — `disconnect()` must not pull the rug out from under it.
|
|
29
|
+
*/
|
|
30
|
+
private readonly ownsKvStore;
|
|
31
|
+
constructor(options: SqliteStorageOptions | SqliteKvStore);
|
|
32
|
+
connect(): Promise<void>;
|
|
33
|
+
disconnect(): Promise<void>;
|
|
34
|
+
ping(): Promise<boolean>;
|
|
35
|
+
get(key: string): Promise<string | null>;
|
|
36
|
+
protected doSet(key: string, value: string, options?: SetOptions): Promise<void>;
|
|
37
|
+
delete(key: string): Promise<boolean>;
|
|
38
|
+
exists(key: string): Promise<boolean>;
|
|
39
|
+
expire(key: string, ttlSeconds: number): Promise<boolean>;
|
|
40
|
+
ttl(key: string): Promise<number | null>;
|
|
41
|
+
keys(pattern?: string): Promise<string[]>;
|
|
42
|
+
incr(key: string): Promise<number>;
|
|
43
|
+
decr(key: string): Promise<number>;
|
|
44
|
+
incrBy(key: string, amount: number): Promise<number>;
|
|
45
|
+
/**
|
|
46
|
+
* Expose the underlying KV store (advanced use / tests).
|
|
47
|
+
*/
|
|
48
|
+
getKvStore(): SqliteKvStore;
|
|
49
|
+
protected getPubSubSuggestion(): string;
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=sqlite-storage.adapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sqlite-storage.adapter.d.ts","sourceRoot":"","sources":["../src/sqlite-storage.adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EAAE,kBAAkB,EAAE,KAAK,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAEtE,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,EAAE,KAAK,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAE7D,qBAAa,oBAAqB,SAAQ,kBAAkB;IAC1D,SAAS,CAAC,QAAQ,CAAC,WAAW,YAAY;IAE1C,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAgB;IAEnC;;;;OAIG;IACH,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAU;gBAE1B,OAAO,EAAE,oBAAoB,GAAG,aAAa;IAWnD,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAKxB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAW3B,IAAI,IAAI,OAAO,CAAC,OAAO,CAAC;IAexB,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;cAK9B,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAchF,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAOrC,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IASrC,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAKzD,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAaxC,IAAI,CAAC,OAAO,SAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAmBtC,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAIlC,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAIlC,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAkB1D;;OAEG;IACH,UAAU,IAAI,aAAa;cAIR,mBAAmB,IAAI,MAAM;CAGjD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sqlite-task.store.d.ts","sourceRoot":"","sources":["../src/sqlite-task.store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAIH,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"sqlite-task.store.d.ts","sourceRoot":"","sources":["../src/sqlite-task.store.ts"],"names":[],"mappings":"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"}
|