@frontmcp/plugin-remember 1.9.0 → 1.9.1-rc.2
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/esm/index.mjs +100 -51
- package/esm/package.json +4 -4
- package/index.d.ts +1 -1
- package/index.d.ts.map +1 -1
- package/index.js +100 -50
- package/package.json +4 -4
- package/providers/remember-accessor.provider.d.ts +5 -1
- package/providers/remember-accessor.provider.d.ts.map +1 -1
- package/providers/remember-memory.provider.d.ts +2 -1
- package/providers/remember-memory.provider.d.ts.map +1 -1
- package/providers/remember-redis.provider.d.ts +2 -0
- package/providers/remember-redis.provider.d.ts.map +1 -1
- package/providers/remember-storage.provider.d.ts +1 -1
- package/providers/remember-storage.provider.d.ts.map +1 -1
- package/providers/remember-vercel-kv.provider.d.ts +5 -1
- package/providers/remember-vercel-kv.provider.d.ts.map +1 -1
- package/remember.errors.d.ts +6 -1
- package/remember.errors.d.ts.map +1 -1
- package/remember.legacy-purge.d.ts +2 -1
- package/remember.legacy-purge.d.ts.map +1 -1
- package/remember.plugin.d.ts.map +1 -1
- package/tools/remember-this.tool.d.ts.map +1 -1
package/esm/index.mjs
CHANGED
|
@@ -285,7 +285,7 @@ async function deserializeAndDecrypt(str, keySource) {
|
|
|
285
285
|
}
|
|
286
286
|
|
|
287
287
|
// plugins/plugin-remember/src/remember.errors.ts
|
|
288
|
-
import { PublicMcpError } from "@frontmcp/sdk";
|
|
288
|
+
import { InternalMcpError, PublicMcpError } from "@frontmcp/sdk";
|
|
289
289
|
var RememberIdentityError = class extends PublicMcpError {
|
|
290
290
|
name = "RememberIdentityError";
|
|
291
291
|
constructor(message) {
|
|
@@ -302,6 +302,12 @@ var RememberScopeNotAllowedError = class extends PublicMcpError {
|
|
|
302
302
|
);
|
|
303
303
|
}
|
|
304
304
|
};
|
|
305
|
+
var RememberConfigurationError = class extends InternalMcpError {
|
|
306
|
+
name = "RememberConfigurationError";
|
|
307
|
+
constructor(message) {
|
|
308
|
+
super(message, "REMEMBER_CONFIGURATION");
|
|
309
|
+
}
|
|
310
|
+
};
|
|
305
311
|
|
|
306
312
|
// plugins/plugin-remember/src/remember.legacy-purge.ts
|
|
307
313
|
var LEGACY_SCOPES = ["session", "tool", "user"];
|
|
@@ -320,7 +326,7 @@ function parseFirstSeenAt(raw) {
|
|
|
320
326
|
return void 0;
|
|
321
327
|
}
|
|
322
328
|
}
|
|
323
|
-
async function readLayoutFirstSeenAt(store, keyPrefix, logger) {
|
|
329
|
+
async function readLayoutFirstSeenAt(store, keyPrefix, logger, markerTtlSeconds) {
|
|
324
330
|
const key = `${keyPrefix}${LAYOUT_MARKER_KEY}`;
|
|
325
331
|
const standDown = (reason, extra = {}) => {
|
|
326
332
|
logger?.debug?.(`remember: ${reason}, legacy purge stood down`, { key, ...extra });
|
|
@@ -334,10 +340,10 @@ async function readLayoutFirstSeenAt(store, keyPrefix, logger) {
|
|
|
334
340
|
const marker = { version: LAYOUT_VERSION, firstSeenAt: Date.now() };
|
|
335
341
|
const serialized = JSON.stringify(marker);
|
|
336
342
|
if (!store.setIfAbsent) {
|
|
337
|
-
await store.setValue(key, serialized);
|
|
343
|
+
await store.setValue(key, serialized, markerTtlSeconds);
|
|
338
344
|
return marker.firstSeenAt;
|
|
339
345
|
}
|
|
340
|
-
if (await store.setIfAbsent(key, serialized)) {
|
|
346
|
+
if (await store.setIfAbsent(key, serialized, markerTtlSeconds)) {
|
|
341
347
|
return marker.firstSeenAt;
|
|
342
348
|
}
|
|
343
349
|
const winner = await store.getValue(key);
|
|
@@ -381,6 +387,7 @@ function scheduleLegacyRememberPurge(store, keyPrefix, options = {}) {
|
|
|
381
387
|
if (scheduled.has(store)) return;
|
|
382
388
|
scheduled.add(store);
|
|
383
389
|
const delayMs = options.delayMs ?? DEFAULT_LEGACY_PURGE_DELAY_MS;
|
|
390
|
+
const markerTtlSeconds = options.defaultTTL ? Math.max(options.defaultTTL, Math.ceil(2 * delayMs / 1e3)) : void 0;
|
|
384
391
|
const arm = (waitMs) => {
|
|
385
392
|
const timer = setTimeout(
|
|
386
393
|
() => {
|
|
@@ -391,7 +398,7 @@ function scheduleLegacyRememberPurge(store, keyPrefix, options = {}) {
|
|
|
391
398
|
timer.unref?.();
|
|
392
399
|
};
|
|
393
400
|
const attempt = async () => {
|
|
394
|
-
const firstSeenAt = await readLayoutFirstSeenAt(store, keyPrefix, options.logger);
|
|
401
|
+
const firstSeenAt = await readLayoutFirstSeenAt(store, keyPrefix, options.logger, markerTtlSeconds);
|
|
395
402
|
if (firstSeenAt === void 0) return;
|
|
396
403
|
const remainingMs = firstSeenAt + delayMs - Date.now();
|
|
397
404
|
if (remainingMs > 0) {
|
|
@@ -411,6 +418,9 @@ function encodeKeyPart(value) {
|
|
|
411
418
|
function remainingSeconds(expiresAt, now) {
|
|
412
419
|
return Math.max(1, Math.ceil((expiresAt - now) / 1e3));
|
|
413
420
|
}
|
|
421
|
+
function expiryAfter(ttlSeconds, now) {
|
|
422
|
+
return ttlSeconds ? now + ttlSeconds * 1e3 : void 0;
|
|
423
|
+
}
|
|
414
424
|
var RememberAccessor = class {
|
|
415
425
|
store;
|
|
416
426
|
ctx;
|
|
@@ -424,7 +434,11 @@ var RememberAccessor = class {
|
|
|
424
434
|
this.keyPrefix = config.keyPrefix ?? "remember:";
|
|
425
435
|
this.encryptionEnabled = config.encryption?.enabled !== false;
|
|
426
436
|
if (!config.skipLegacyPurge) {
|
|
427
|
-
scheduleLegacyRememberPurge(store, this.keyPrefix, {
|
|
437
|
+
scheduleLegacyRememberPurge(store, this.keyPrefix, {
|
|
438
|
+
delayMs: config.legacyPurgeDelayMs,
|
|
439
|
+
defaultTTL: config.defaultTTL,
|
|
440
|
+
logger
|
|
441
|
+
});
|
|
428
442
|
}
|
|
429
443
|
}
|
|
430
444
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
@@ -433,23 +447,29 @@ var RememberAccessor = class {
|
|
|
433
447
|
/**
|
|
434
448
|
* Store a value in memory.
|
|
435
449
|
*
|
|
450
|
+
* Without a `ttl`, the plugin's `defaultTTL` applies, and the entry records the deadline either one sets.
|
|
451
|
+
*
|
|
436
452
|
* @param key - The key to store under
|
|
437
453
|
* @param value - The value to store (any JSON-serializable data)
|
|
438
454
|
* @param options - Storage options (scope, ttl, brand, metadata)
|
|
455
|
+
* @returns The stored entry, with its `expiresAt` deadline
|
|
439
456
|
*/
|
|
440
457
|
async set(key, value, options = {}) {
|
|
441
458
|
const scope = options.scope ?? "session";
|
|
442
459
|
const storageKey = this.buildStorageKey(key, scope);
|
|
460
|
+
const now = Date.now();
|
|
461
|
+
const ttlSeconds = options.ttl ?? this.config.defaultTTL;
|
|
443
462
|
const entry = {
|
|
444
463
|
value,
|
|
445
464
|
brand: options.brand,
|
|
446
|
-
createdAt:
|
|
447
|
-
updatedAt:
|
|
448
|
-
expiresAt:
|
|
465
|
+
createdAt: now,
|
|
466
|
+
updatedAt: now,
|
|
467
|
+
expiresAt: expiryAfter(ttlSeconds, now),
|
|
449
468
|
metadata: options.metadata
|
|
450
469
|
};
|
|
451
470
|
const serialized = this.encryptionEnabled ? await encryptAndSerialize(entry, this.getKeySource(scope)) : JSON.stringify(entry);
|
|
452
|
-
await this.store.setValue(storageKey, serialized,
|
|
471
|
+
await this.store.setValue(storageKey, serialized, ttlSeconds);
|
|
472
|
+
return entry;
|
|
453
473
|
}
|
|
454
474
|
/**
|
|
455
475
|
* Retrieve a value from memory.
|
|
@@ -514,6 +534,7 @@ var RememberAccessor = class {
|
|
|
514
534
|
*
|
|
515
535
|
* With a `ttl` the entry expires that many seconds from now; without one it keeps its current
|
|
516
536
|
* expiry, in the store as well, so the store does not keep it past that (rounded up to a second).
|
|
537
|
+
* An entry with no recorded expiry gets the plugin's `defaultTTL` from now, as the store would give it.
|
|
517
538
|
*
|
|
518
539
|
* @param key - The key to update
|
|
519
540
|
* @param value - The new value
|
|
@@ -524,7 +545,7 @@ var RememberAccessor = class {
|
|
|
524
545
|
const existing = await this.getEntry(key, { scope });
|
|
525
546
|
if (!existing) return false;
|
|
526
547
|
const now = Date.now();
|
|
527
|
-
const expiresAt = options.ttl
|
|
548
|
+
const expiresAt = expiryAfter(options.ttl, now) ?? existing.expiresAt ?? expiryAfter(this.config.defaultTTL, now);
|
|
528
549
|
const entry = {
|
|
529
550
|
...existing,
|
|
530
551
|
value,
|
|
@@ -533,7 +554,9 @@ var RememberAccessor = class {
|
|
|
533
554
|
};
|
|
534
555
|
const storageKey = this.buildStorageKey(key, scope);
|
|
535
556
|
const serialized = this.encryptionEnabled ? await encryptAndSerialize(entry, this.getKeySource(scope)) : JSON.stringify(entry);
|
|
536
|
-
const
|
|
557
|
+
const writtenAt = Date.now();
|
|
558
|
+
if (expiresAt !== void 0 && expiresAt <= writtenAt) return false;
|
|
559
|
+
const storageTtl = expiresAt !== void 0 ? remainingSeconds(expiresAt, writtenAt) : void 0;
|
|
537
560
|
await this.store.setValue(storageKey, serialized, storageTtl);
|
|
538
561
|
return true;
|
|
539
562
|
}
|
|
@@ -654,8 +677,9 @@ var RememberAccessor = class {
|
|
|
654
677
|
}
|
|
655
678
|
/** The entry stored under `storageKey`, if readable and unexpired; an expired one is deleted. */
|
|
656
679
|
async readEntry(storageKey, scope) {
|
|
657
|
-
const
|
|
658
|
-
if (!
|
|
680
|
+
const stored = await this.store.getValue(storageKey);
|
|
681
|
+
if (!stored) return void 0;
|
|
682
|
+
const raw = typeof stored === "string" ? stored : JSON.stringify(stored);
|
|
659
683
|
const entry = this.encryptionEnabled ? await deserializeAndDecrypt(raw, this.getKeySource(scope)) : this.parseEntry(raw);
|
|
660
684
|
if (!entry) return void 0;
|
|
661
685
|
if (entry.expiresAt && Date.now() > entry.expiresAt) {
|
|
@@ -690,12 +714,14 @@ function createRememberAccessor(store, ctx, config, logger) {
|
|
|
690
714
|
import { Provider as Provider2, ProviderScope as ProviderScope2 } from "@frontmcp/sdk";
|
|
691
715
|
var MAX_TIMEOUT_MS = 2 ** 31 - 1;
|
|
692
716
|
var RememberMemoryProvider = class {
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
constructor(sweepIntervalSeconds = 60) {
|
|
717
|
+
constructor(sweepIntervalSeconds = 60, defaultTTL) {
|
|
718
|
+
this.defaultTTL = defaultTTL;
|
|
696
719
|
this.sweeper = setInterval(() => this.sweep(), sweepIntervalSeconds * 1e3);
|
|
697
720
|
this.sweeper.unref?.();
|
|
698
721
|
}
|
|
722
|
+
defaultTTL;
|
|
723
|
+
memory = /* @__PURE__ */ new Map();
|
|
724
|
+
sweeper;
|
|
699
725
|
/**
|
|
700
726
|
* Store a value with optional TTL.
|
|
701
727
|
* Always JSON-serializes the value for consistent storage/retrieval.
|
|
@@ -705,8 +731,9 @@ var RememberMemoryProvider = class {
|
|
|
705
731
|
const existing = this.memory.get(key);
|
|
706
732
|
if (existing?.timeout) clearTimeout(existing.timeout);
|
|
707
733
|
const entry = { value: strValue };
|
|
708
|
-
|
|
709
|
-
|
|
734
|
+
const ttl = ttlSeconds ?? this.defaultTTL;
|
|
735
|
+
if (ttl && ttl > 0) {
|
|
736
|
+
const ttlMs = ttl * 1e3;
|
|
710
737
|
entry.expiresAt = Date.now() + ttlMs;
|
|
711
738
|
if (ttlMs <= MAX_TIMEOUT_MS) {
|
|
712
739
|
entry.timeout = setTimeout(() => {
|
|
@@ -865,10 +892,13 @@ var RememberRedisProvider = class {
|
|
|
865
892
|
* Include any separator (e.g., "myapp:" or "user:123:") as part of the prefix.
|
|
866
893
|
*/
|
|
867
894
|
keyPrefix;
|
|
895
|
+
/** TTL in seconds for values stored without one. */
|
|
896
|
+
defaultTTL;
|
|
868
897
|
/** True if this provider created the client (and should close it), false if externally provided */
|
|
869
898
|
ownsClient;
|
|
870
899
|
constructor(options) {
|
|
871
900
|
this.keyPrefix = options.keyPrefix ?? "";
|
|
901
|
+
this.defaultTTL = options.defaultTTL;
|
|
872
902
|
if (options.type === "redis-client") {
|
|
873
903
|
this.client = options.client;
|
|
874
904
|
this.ownsClient = false;
|
|
@@ -913,9 +943,10 @@ var RememberRedisProvider = class {
|
|
|
913
943
|
}
|
|
914
944
|
}
|
|
915
945
|
const fullKey = this.keyPrefix + key;
|
|
916
|
-
const strValue =
|
|
917
|
-
|
|
918
|
-
|
|
946
|
+
const strValue = JSON.stringify(value);
|
|
947
|
+
const ttl = ttlSeconds ?? this.defaultTTL;
|
|
948
|
+
if (ttl !== void 0 && ttl > 0) {
|
|
949
|
+
await this.client.set(fullKey, strValue, "EX", ttl);
|
|
919
950
|
} else {
|
|
920
951
|
await this.client.set(fullKey, strValue);
|
|
921
952
|
}
|
|
@@ -928,8 +959,9 @@ var RememberRedisProvider = class {
|
|
|
928
959
|
*/
|
|
929
960
|
async setIfAbsent(key, value, ttlSeconds) {
|
|
930
961
|
const fullKey = this.keyPrefix + key;
|
|
931
|
-
const strValue =
|
|
932
|
-
const
|
|
962
|
+
const strValue = JSON.stringify(value);
|
|
963
|
+
const ttl = ttlSeconds ?? this.defaultTTL;
|
|
964
|
+
const result = ttl !== void 0 && ttl > 0 ? await this.client.set(fullKey, strValue, "EX", ttl, "NX") : await this.client.set(fullKey, strValue, "NX");
|
|
933
965
|
return result === "OK";
|
|
934
966
|
}
|
|
935
967
|
/**
|
|
@@ -1005,8 +1037,11 @@ RememberRedisProvider = __decorateClass([
|
|
|
1005
1037
|
|
|
1006
1038
|
// plugins/plugin-remember/src/providers/remember-vercel-kv.provider.ts
|
|
1007
1039
|
import { Provider as Provider4, ProviderScope as ProviderScope4 } from "@frontmcp/sdk";
|
|
1040
|
+
import { getEnv } from "@frontmcp/utils";
|
|
1008
1041
|
var RememberVercelKvProvider = class {
|
|
1009
|
-
|
|
1042
|
+
createClient;
|
|
1043
|
+
connection;
|
|
1044
|
+
client;
|
|
1010
1045
|
keyPrefix;
|
|
1011
1046
|
defaultTTL;
|
|
1012
1047
|
constructor(options = {}) {
|
|
@@ -1018,17 +1053,23 @@ var RememberVercelKvProvider = class {
|
|
|
1018
1053
|
`RememberVercelKvProvider: Both 'url' and 'token' must be provided together, or neither. Received: url=${hasUrl ? "provided" : "missing"}, token=${hasToken ? "provided" : "missing"}`
|
|
1019
1054
|
);
|
|
1020
1055
|
}
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
url: options.url,
|
|
1024
|
-
token: options.token
|
|
1025
|
-
});
|
|
1026
|
-
} else {
|
|
1027
|
-
this.kv = vercelKv.kv;
|
|
1028
|
-
}
|
|
1056
|
+
this.createClient = vercelKv.createClient;
|
|
1057
|
+
this.connection = { url: options.url, token: options.token };
|
|
1029
1058
|
this.keyPrefix = options.keyPrefix ?? "remember:";
|
|
1030
1059
|
this.defaultTTL = options.defaultTTL;
|
|
1031
1060
|
}
|
|
1061
|
+
/** Built on first use, like the module's `kv` singleton, which would JSON-parse what it reads. */
|
|
1062
|
+
get kv() {
|
|
1063
|
+
if (!this.client) {
|
|
1064
|
+
const url = this.connection.url ?? getEnv("KV_REST_API_URL");
|
|
1065
|
+
const token = this.connection.token ?? getEnv("KV_REST_API_TOKEN");
|
|
1066
|
+
if (!url || !token) {
|
|
1067
|
+
throw new Error("RememberVercelKvProvider: pass url and token, or set KV_REST_API_URL and KV_REST_API_TOKEN.");
|
|
1068
|
+
}
|
|
1069
|
+
this.client = this.createClient({ url, token, automaticDeserialization: false });
|
|
1070
|
+
}
|
|
1071
|
+
return this.client;
|
|
1072
|
+
}
|
|
1032
1073
|
prefixKey(key) {
|
|
1033
1074
|
return `${this.keyPrefix}${key}`;
|
|
1034
1075
|
}
|
|
@@ -1037,7 +1078,7 @@ var RememberVercelKvProvider = class {
|
|
|
1037
1078
|
*/
|
|
1038
1079
|
async setValue(key, value, ttlSeconds) {
|
|
1039
1080
|
const fullKey = this.prefixKey(key);
|
|
1040
|
-
const strValue =
|
|
1081
|
+
const strValue = JSON.stringify(value);
|
|
1041
1082
|
const ttl = ttlSeconds ?? this.defaultTTL;
|
|
1042
1083
|
if (ttl && ttl > 0) {
|
|
1043
1084
|
await this.kv.set(fullKey, strValue, { ex: ttl });
|
|
@@ -1053,7 +1094,7 @@ var RememberVercelKvProvider = class {
|
|
|
1053
1094
|
*/
|
|
1054
1095
|
async setIfAbsent(key, value, ttlSeconds) {
|
|
1055
1096
|
const fullKey = this.prefixKey(key);
|
|
1056
|
-
const strValue =
|
|
1097
|
+
const strValue = JSON.stringify(value);
|
|
1057
1098
|
const ttl = ttlSeconds ?? this.defaultTTL;
|
|
1058
1099
|
const result = ttl && ttl > 0 ? await this.kv.set(fullKey, strValue, { nx: true, ex: ttl }) : await this.kv.set(fullKey, strValue, { nx: true });
|
|
1059
1100
|
return result === "OK";
|
|
@@ -1064,15 +1105,12 @@ var RememberVercelKvProvider = class {
|
|
|
1064
1105
|
async getValue(key, defaultValue) {
|
|
1065
1106
|
const fullKey = this.prefixKey(key);
|
|
1066
1107
|
const raw = await this.kv.get(fullKey);
|
|
1067
|
-
if (raw === null
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
return raw;
|
|
1073
|
-
}
|
|
1108
|
+
if (raw === null) return defaultValue;
|
|
1109
|
+
try {
|
|
1110
|
+
return JSON.parse(raw);
|
|
1111
|
+
} catch {
|
|
1112
|
+
return raw;
|
|
1074
1113
|
}
|
|
1075
|
-
return raw;
|
|
1076
1114
|
}
|
|
1077
1115
|
/**
|
|
1078
1116
|
* Delete a key.
|
|
@@ -1106,7 +1144,7 @@ var RememberVercelKvProvider = class {
|
|
|
1106
1144
|
for (const key of keys) {
|
|
1107
1145
|
result.push(key.slice(this.keyPrefix.length));
|
|
1108
1146
|
}
|
|
1109
|
-
} while (cursor !== 0);
|
|
1147
|
+
} while (String(cursor) !== "0");
|
|
1110
1148
|
} catch {
|
|
1111
1149
|
try {
|
|
1112
1150
|
const keys = await this.kv.keys(searchPattern);
|
|
@@ -1329,7 +1367,7 @@ var rememberThisInputSchema = {
|
|
|
1329
1367
|
key: z5.string().min(1).describe('What to call this memory (e.g., "user_preference", "last_action")'),
|
|
1330
1368
|
value: z5.unknown().describe("The value to remember (any JSON-serializable data)"),
|
|
1331
1369
|
scope: z5.enum(["session", "user", "tool", "global"]).optional().describe(REMEMBER_SCOPE_DESCRIPTION),
|
|
1332
|
-
ttl: z5.number().positive().optional().describe("Forget after this many seconds"),
|
|
1370
|
+
ttl: z5.number().int().positive().optional().describe("Forget after this many whole seconds"),
|
|
1333
1371
|
brand: z5.enum(["preference", "cache", "state", "conversation", "custom"]).optional().describe("Type hint for the stored value")
|
|
1334
1372
|
};
|
|
1335
1373
|
var rememberThisOutputSchema = z5.object({
|
|
@@ -1359,17 +1397,16 @@ var RememberThisTool = class extends ToolContext4 {
|
|
|
1359
1397
|
if (!allowedScopes.includes(scope)) {
|
|
1360
1398
|
throw this.fail(new RememberScopeNotAllowedError(scope, allowedScopes));
|
|
1361
1399
|
}
|
|
1362
|
-
await remember.set(input.key, input.value, {
|
|
1400
|
+
const entry = await remember.set(input.key, input.value, {
|
|
1363
1401
|
scope,
|
|
1364
1402
|
ttl: input.ttl,
|
|
1365
1403
|
brand: input.brand
|
|
1366
1404
|
});
|
|
1367
|
-
const expiresAt = input.ttl ? Date.now() + input.ttl * 1e3 : void 0;
|
|
1368
1405
|
return {
|
|
1369
1406
|
success: true,
|
|
1370
1407
|
key: input.key,
|
|
1371
1408
|
scope,
|
|
1372
|
-
expiresAt
|
|
1409
|
+
expiresAt: entry.expiresAt
|
|
1373
1410
|
};
|
|
1374
1411
|
}
|
|
1375
1412
|
};
|
|
@@ -1405,13 +1442,24 @@ function createRememberTools(prefix = "") {
|
|
|
1405
1442
|
}
|
|
1406
1443
|
|
|
1407
1444
|
// plugins/plugin-remember/src/remember.plugin.ts
|
|
1445
|
+
function withCheckedDefaultTTL(options) {
|
|
1446
|
+
const { defaultTTL } = options;
|
|
1447
|
+
if (defaultTTL === void 0) return options;
|
|
1448
|
+
if (defaultTTL === 0) return { ...options, defaultTTL: void 0 };
|
|
1449
|
+
if (!Number.isInteger(defaultTTL) || defaultTTL < 0) {
|
|
1450
|
+
throw new RememberConfigurationError(
|
|
1451
|
+
`RememberPlugin defaultTTL must be a whole number of seconds (0 for no default expiry), got ${defaultTTL}`
|
|
1452
|
+
);
|
|
1453
|
+
}
|
|
1454
|
+
return options;
|
|
1455
|
+
}
|
|
1408
1456
|
var RememberPlugin = class extends DynamicPlugin {
|
|
1409
1457
|
options;
|
|
1410
1458
|
constructor(options = {}) {
|
|
1411
1459
|
super();
|
|
1412
1460
|
this.options = {
|
|
1413
1461
|
...RememberPlugin.defaultOptions,
|
|
1414
|
-
...options
|
|
1462
|
+
...withCheckedDefaultTTL(options)
|
|
1415
1463
|
};
|
|
1416
1464
|
}
|
|
1417
1465
|
};
|
|
@@ -1432,7 +1480,7 @@ __publicField(RememberPlugin, "dynamicProviders", (options) => {
|
|
|
1432
1480
|
const providers = [];
|
|
1433
1481
|
const config = {
|
|
1434
1482
|
...RememberPlugin.defaultOptions,
|
|
1435
|
-
...options
|
|
1483
|
+
...withCheckedDefaultTTL(options)
|
|
1436
1484
|
};
|
|
1437
1485
|
switch (config.type) {
|
|
1438
1486
|
case "global-store":
|
|
@@ -1511,7 +1559,7 @@ __publicField(RememberPlugin, "dynamicProviders", (options) => {
|
|
|
1511
1559
|
provide: RememberStoreToken,
|
|
1512
1560
|
// Built per server: `init()` runs once, so a value here would be shared by every server using it.
|
|
1513
1561
|
inject: () => [],
|
|
1514
|
-
useFactory: () => new RememberMemoryProvider()
|
|
1562
|
+
useFactory: () => new RememberMemoryProvider(void 0, config.defaultTTL)
|
|
1515
1563
|
});
|
|
1516
1564
|
break;
|
|
1517
1565
|
}
|
|
@@ -1587,6 +1635,7 @@ export {
|
|
|
1587
1635
|
RememberAccessor,
|
|
1588
1636
|
RememberAccessorToken,
|
|
1589
1637
|
RememberConfigToken,
|
|
1638
|
+
RememberConfigurationError,
|
|
1590
1639
|
RememberIdentityError,
|
|
1591
1640
|
RememberMemoryProvider,
|
|
1592
1641
|
RememberPlugin,
|
package/esm/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@frontmcp/plugin-remember",
|
|
3
|
-
"version": "1.9.
|
|
3
|
+
"version": "1.9.1-rc.2",
|
|
4
4
|
"description": "Remember plugin for FrontMCP - encrypted session memory with approval system for secure tool authorization",
|
|
5
5
|
"author": "AgentFront <info@agentfront.dev>",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -49,12 +49,12 @@
|
|
|
49
49
|
}
|
|
50
50
|
},
|
|
51
51
|
"dependencies": {
|
|
52
|
-
"@frontmcp/sdk": "1.9.
|
|
53
|
-
"@frontmcp/utils": "1.9.
|
|
52
|
+
"@frontmcp/sdk": "1.9.1-rc.2",
|
|
53
|
+
"@frontmcp/utils": "1.9.1-rc.2",
|
|
54
54
|
"ioredis": "^5.8.0"
|
|
55
55
|
},
|
|
56
56
|
"peerDependencies": {
|
|
57
|
-
"@frontmcp/lazy-zod": "1.9.
|
|
57
|
+
"@frontmcp/lazy-zod": "1.9.1-rc.2",
|
|
58
58
|
"@vercel/kv": "^2.0.0 || ^3.0.0"
|
|
59
59
|
},
|
|
60
60
|
"peerDependenciesMeta": {
|
package/index.d.ts
CHANGED
|
@@ -45,7 +45,7 @@ export type { RememberScope, RememberEntry, RememberPluginOptions, RememberPlugi
|
|
|
45
45
|
export { brand } from './remember.types';
|
|
46
46
|
export type { RememberStoreInterface } from './providers/remember-store.interface';
|
|
47
47
|
export { RememberAccessor } from './providers/remember-accessor.provider';
|
|
48
|
-
export { RememberIdentityError, RememberScopeNotAllowedError } from './remember.errors';
|
|
48
|
+
export { RememberConfigurationError, RememberIdentityError, RememberScopeNotAllowedError } from './remember.errors';
|
|
49
49
|
export { default as RememberMemoryProvider } from './providers/remember-memory.provider';
|
|
50
50
|
export { default as RememberRedisProvider } from './providers/remember-redis.provider';
|
|
51
51
|
export { default as RememberVercelKvProvider } from './providers/remember-vercel-kv.provider';
|
package/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AAGH,OAAO,EAAE,OAAO,EAAE,OAAO,IAAI,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAGvE,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAGpG,YAAY,EACV,aAAa,EACb,aAAa,EACb,qBAAqB,EACrB,0BAA0B,EAC1B,kBAAkB,EAClB,kBAAkB,EAClB,qBAAqB,EACrB,oBAAoB,EACpB,mBAAmB,EACnB,cAAc,EACd,eAAe,EACf,iBAAiB,EACjB,YAAY,EACZ,YAAY,EACZ,mBAAmB,EACnB,aAAa,EACb,gBAAgB,GACjB,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAGzC,YAAY,EAAE,sBAAsB,EAAE,MAAM,sCAAsC,CAAC;AACnF,OAAO,EAAE,gBAAgB,EAAE,MAAM,wCAAwC,CAAC;AAC1E,OAAO,EAAE,qBAAqB,EAAE,4BAA4B,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AAGH,OAAO,EAAE,OAAO,EAAE,OAAO,IAAI,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAGvE,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAGpG,YAAY,EACV,aAAa,EACb,aAAa,EACb,qBAAqB,EACrB,0BAA0B,EAC1B,kBAAkB,EAClB,kBAAkB,EAClB,qBAAqB,EACrB,oBAAoB,EACpB,mBAAmB,EACnB,cAAc,EACd,eAAe,EACf,iBAAiB,EACjB,YAAY,EACZ,YAAY,EACZ,mBAAmB,EACnB,aAAa,EACb,gBAAgB,GACjB,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAGzC,YAAY,EAAE,sBAAsB,EAAE,MAAM,sCAAsC,CAAC;AACnF,OAAO,EAAE,gBAAgB,EAAE,MAAM,wCAAwC,CAAC;AAC1E,OAAO,EAAE,0BAA0B,EAAE,qBAAqB,EAAE,4BAA4B,EAAE,MAAM,mBAAmB,CAAC;AACpH,OAAO,EAAE,OAAO,IAAI,sBAAsB,EAAE,MAAM,sCAAsC,CAAC;AACzF,OAAO,EAAE,OAAO,IAAI,qBAAqB,EAAE,MAAM,qCAAqC,CAAC;AACvF,OAAO,EAAE,OAAO,IAAI,wBAAwB,EAAE,MAAM,yCAAyC,CAAC;AAG9F,OAAO,EAAE,gBAAgB,EAAE,UAAU,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAKrF,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC"}
|
package/index.js
CHANGED
|
@@ -46,6 +46,7 @@ __export(index_exports, {
|
|
|
46
46
|
RememberAccessor: () => RememberAccessor,
|
|
47
47
|
RememberAccessorToken: () => RememberAccessorToken,
|
|
48
48
|
RememberConfigToken: () => RememberConfigToken,
|
|
49
|
+
RememberConfigurationError: () => RememberConfigurationError,
|
|
49
50
|
RememberIdentityError: () => RememberIdentityError,
|
|
50
51
|
RememberMemoryProvider: () => RememberMemoryProvider,
|
|
51
52
|
RememberPlugin: () => RememberPlugin,
|
|
@@ -321,6 +322,12 @@ var RememberScopeNotAllowedError = class extends import_sdk.PublicMcpError {
|
|
|
321
322
|
);
|
|
322
323
|
}
|
|
323
324
|
};
|
|
325
|
+
var RememberConfigurationError = class extends import_sdk.InternalMcpError {
|
|
326
|
+
name = "RememberConfigurationError";
|
|
327
|
+
constructor(message) {
|
|
328
|
+
super(message, "REMEMBER_CONFIGURATION");
|
|
329
|
+
}
|
|
330
|
+
};
|
|
324
331
|
|
|
325
332
|
// plugins/plugin-remember/src/remember.legacy-purge.ts
|
|
326
333
|
var LEGACY_SCOPES = ["session", "tool", "user"];
|
|
@@ -339,7 +346,7 @@ function parseFirstSeenAt(raw) {
|
|
|
339
346
|
return void 0;
|
|
340
347
|
}
|
|
341
348
|
}
|
|
342
|
-
async function readLayoutFirstSeenAt(store, keyPrefix, logger) {
|
|
349
|
+
async function readLayoutFirstSeenAt(store, keyPrefix, logger, markerTtlSeconds) {
|
|
343
350
|
const key = `${keyPrefix}${LAYOUT_MARKER_KEY}`;
|
|
344
351
|
const standDown = (reason, extra = {}) => {
|
|
345
352
|
logger?.debug?.(`remember: ${reason}, legacy purge stood down`, { key, ...extra });
|
|
@@ -353,10 +360,10 @@ async function readLayoutFirstSeenAt(store, keyPrefix, logger) {
|
|
|
353
360
|
const marker = { version: LAYOUT_VERSION, firstSeenAt: Date.now() };
|
|
354
361
|
const serialized = JSON.stringify(marker);
|
|
355
362
|
if (!store.setIfAbsent) {
|
|
356
|
-
await store.setValue(key, serialized);
|
|
363
|
+
await store.setValue(key, serialized, markerTtlSeconds);
|
|
357
364
|
return marker.firstSeenAt;
|
|
358
365
|
}
|
|
359
|
-
if (await store.setIfAbsent(key, serialized)) {
|
|
366
|
+
if (await store.setIfAbsent(key, serialized, markerTtlSeconds)) {
|
|
360
367
|
return marker.firstSeenAt;
|
|
361
368
|
}
|
|
362
369
|
const winner = await store.getValue(key);
|
|
@@ -400,6 +407,7 @@ function scheduleLegacyRememberPurge(store, keyPrefix, options = {}) {
|
|
|
400
407
|
if (scheduled.has(store)) return;
|
|
401
408
|
scheduled.add(store);
|
|
402
409
|
const delayMs = options.delayMs ?? DEFAULT_LEGACY_PURGE_DELAY_MS;
|
|
410
|
+
const markerTtlSeconds = options.defaultTTL ? Math.max(options.defaultTTL, Math.ceil(2 * delayMs / 1e3)) : void 0;
|
|
403
411
|
const arm = (waitMs) => {
|
|
404
412
|
const timer = setTimeout(
|
|
405
413
|
() => {
|
|
@@ -410,7 +418,7 @@ function scheduleLegacyRememberPurge(store, keyPrefix, options = {}) {
|
|
|
410
418
|
timer.unref?.();
|
|
411
419
|
};
|
|
412
420
|
const attempt = async () => {
|
|
413
|
-
const firstSeenAt = await readLayoutFirstSeenAt(store, keyPrefix, options.logger);
|
|
421
|
+
const firstSeenAt = await readLayoutFirstSeenAt(store, keyPrefix, options.logger, markerTtlSeconds);
|
|
414
422
|
if (firstSeenAt === void 0) return;
|
|
415
423
|
const remainingMs = firstSeenAt + delayMs - Date.now();
|
|
416
424
|
if (remainingMs > 0) {
|
|
@@ -430,6 +438,9 @@ function encodeKeyPart(value) {
|
|
|
430
438
|
function remainingSeconds(expiresAt, now) {
|
|
431
439
|
return Math.max(1, Math.ceil((expiresAt - now) / 1e3));
|
|
432
440
|
}
|
|
441
|
+
function expiryAfter(ttlSeconds, now) {
|
|
442
|
+
return ttlSeconds ? now + ttlSeconds * 1e3 : void 0;
|
|
443
|
+
}
|
|
433
444
|
var RememberAccessor = class {
|
|
434
445
|
store;
|
|
435
446
|
ctx;
|
|
@@ -443,7 +454,11 @@ var RememberAccessor = class {
|
|
|
443
454
|
this.keyPrefix = config.keyPrefix ?? "remember:";
|
|
444
455
|
this.encryptionEnabled = config.encryption?.enabled !== false;
|
|
445
456
|
if (!config.skipLegacyPurge) {
|
|
446
|
-
scheduleLegacyRememberPurge(store, this.keyPrefix, {
|
|
457
|
+
scheduleLegacyRememberPurge(store, this.keyPrefix, {
|
|
458
|
+
delayMs: config.legacyPurgeDelayMs,
|
|
459
|
+
defaultTTL: config.defaultTTL,
|
|
460
|
+
logger
|
|
461
|
+
});
|
|
447
462
|
}
|
|
448
463
|
}
|
|
449
464
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
@@ -452,23 +467,29 @@ var RememberAccessor = class {
|
|
|
452
467
|
/**
|
|
453
468
|
* Store a value in memory.
|
|
454
469
|
*
|
|
470
|
+
* Without a `ttl`, the plugin's `defaultTTL` applies, and the entry records the deadline either one sets.
|
|
471
|
+
*
|
|
455
472
|
* @param key - The key to store under
|
|
456
473
|
* @param value - The value to store (any JSON-serializable data)
|
|
457
474
|
* @param options - Storage options (scope, ttl, brand, metadata)
|
|
475
|
+
* @returns The stored entry, with its `expiresAt` deadline
|
|
458
476
|
*/
|
|
459
477
|
async set(key, value, options = {}) {
|
|
460
478
|
const scope = options.scope ?? "session";
|
|
461
479
|
const storageKey = this.buildStorageKey(key, scope);
|
|
480
|
+
const now = Date.now();
|
|
481
|
+
const ttlSeconds = options.ttl ?? this.config.defaultTTL;
|
|
462
482
|
const entry = {
|
|
463
483
|
value,
|
|
464
484
|
brand: options.brand,
|
|
465
|
-
createdAt:
|
|
466
|
-
updatedAt:
|
|
467
|
-
expiresAt:
|
|
485
|
+
createdAt: now,
|
|
486
|
+
updatedAt: now,
|
|
487
|
+
expiresAt: expiryAfter(ttlSeconds, now),
|
|
468
488
|
metadata: options.metadata
|
|
469
489
|
};
|
|
470
490
|
const serialized = this.encryptionEnabled ? await encryptAndSerialize(entry, this.getKeySource(scope)) : JSON.stringify(entry);
|
|
471
|
-
await this.store.setValue(storageKey, serialized,
|
|
491
|
+
await this.store.setValue(storageKey, serialized, ttlSeconds);
|
|
492
|
+
return entry;
|
|
472
493
|
}
|
|
473
494
|
/**
|
|
474
495
|
* Retrieve a value from memory.
|
|
@@ -533,6 +554,7 @@ var RememberAccessor = class {
|
|
|
533
554
|
*
|
|
534
555
|
* With a `ttl` the entry expires that many seconds from now; without one it keeps its current
|
|
535
556
|
* expiry, in the store as well, so the store does not keep it past that (rounded up to a second).
|
|
557
|
+
* An entry with no recorded expiry gets the plugin's `defaultTTL` from now, as the store would give it.
|
|
536
558
|
*
|
|
537
559
|
* @param key - The key to update
|
|
538
560
|
* @param value - The new value
|
|
@@ -543,7 +565,7 @@ var RememberAccessor = class {
|
|
|
543
565
|
const existing = await this.getEntry(key, { scope });
|
|
544
566
|
if (!existing) return false;
|
|
545
567
|
const now = Date.now();
|
|
546
|
-
const expiresAt = options.ttl
|
|
568
|
+
const expiresAt = expiryAfter(options.ttl, now) ?? existing.expiresAt ?? expiryAfter(this.config.defaultTTL, now);
|
|
547
569
|
const entry = {
|
|
548
570
|
...existing,
|
|
549
571
|
value,
|
|
@@ -552,7 +574,9 @@ var RememberAccessor = class {
|
|
|
552
574
|
};
|
|
553
575
|
const storageKey = this.buildStorageKey(key, scope);
|
|
554
576
|
const serialized = this.encryptionEnabled ? await encryptAndSerialize(entry, this.getKeySource(scope)) : JSON.stringify(entry);
|
|
555
|
-
const
|
|
577
|
+
const writtenAt = Date.now();
|
|
578
|
+
if (expiresAt !== void 0 && expiresAt <= writtenAt) return false;
|
|
579
|
+
const storageTtl = expiresAt !== void 0 ? remainingSeconds(expiresAt, writtenAt) : void 0;
|
|
556
580
|
await this.store.setValue(storageKey, serialized, storageTtl);
|
|
557
581
|
return true;
|
|
558
582
|
}
|
|
@@ -673,8 +697,9 @@ var RememberAccessor = class {
|
|
|
673
697
|
}
|
|
674
698
|
/** The entry stored under `storageKey`, if readable and unexpired; an expired one is deleted. */
|
|
675
699
|
async readEntry(storageKey, scope) {
|
|
676
|
-
const
|
|
677
|
-
if (!
|
|
700
|
+
const stored = await this.store.getValue(storageKey);
|
|
701
|
+
if (!stored) return void 0;
|
|
702
|
+
const raw = typeof stored === "string" ? stored : JSON.stringify(stored);
|
|
678
703
|
const entry = this.encryptionEnabled ? await deserializeAndDecrypt(raw, this.getKeySource(scope)) : this.parseEntry(raw);
|
|
679
704
|
if (!entry) return void 0;
|
|
680
705
|
if (entry.expiresAt && Date.now() > entry.expiresAt) {
|
|
@@ -709,12 +734,14 @@ function createRememberAccessor(store, ctx, config, logger) {
|
|
|
709
734
|
var import_sdk3 = require("@frontmcp/sdk");
|
|
710
735
|
var MAX_TIMEOUT_MS = 2 ** 31 - 1;
|
|
711
736
|
var RememberMemoryProvider = class {
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
constructor(sweepIntervalSeconds = 60) {
|
|
737
|
+
constructor(sweepIntervalSeconds = 60, defaultTTL) {
|
|
738
|
+
this.defaultTTL = defaultTTL;
|
|
715
739
|
this.sweeper = setInterval(() => this.sweep(), sweepIntervalSeconds * 1e3);
|
|
716
740
|
this.sweeper.unref?.();
|
|
717
741
|
}
|
|
742
|
+
defaultTTL;
|
|
743
|
+
memory = /* @__PURE__ */ new Map();
|
|
744
|
+
sweeper;
|
|
718
745
|
/**
|
|
719
746
|
* Store a value with optional TTL.
|
|
720
747
|
* Always JSON-serializes the value for consistent storage/retrieval.
|
|
@@ -724,8 +751,9 @@ var RememberMemoryProvider = class {
|
|
|
724
751
|
const existing = this.memory.get(key);
|
|
725
752
|
if (existing?.timeout) clearTimeout(existing.timeout);
|
|
726
753
|
const entry = { value: strValue };
|
|
727
|
-
|
|
728
|
-
|
|
754
|
+
const ttl = ttlSeconds ?? this.defaultTTL;
|
|
755
|
+
if (ttl && ttl > 0) {
|
|
756
|
+
const ttlMs = ttl * 1e3;
|
|
729
757
|
entry.expiresAt = Date.now() + ttlMs;
|
|
730
758
|
if (ttlMs <= MAX_TIMEOUT_MS) {
|
|
731
759
|
entry.timeout = setTimeout(() => {
|
|
@@ -884,10 +912,13 @@ var RememberRedisProvider = class {
|
|
|
884
912
|
* Include any separator (e.g., "myapp:" or "user:123:") as part of the prefix.
|
|
885
913
|
*/
|
|
886
914
|
keyPrefix;
|
|
915
|
+
/** TTL in seconds for values stored without one. */
|
|
916
|
+
defaultTTL;
|
|
887
917
|
/** True if this provider created the client (and should close it), false if externally provided */
|
|
888
918
|
ownsClient;
|
|
889
919
|
constructor(options) {
|
|
890
920
|
this.keyPrefix = options.keyPrefix ?? "";
|
|
921
|
+
this.defaultTTL = options.defaultTTL;
|
|
891
922
|
if (options.type === "redis-client") {
|
|
892
923
|
this.client = options.client;
|
|
893
924
|
this.ownsClient = false;
|
|
@@ -932,9 +963,10 @@ var RememberRedisProvider = class {
|
|
|
932
963
|
}
|
|
933
964
|
}
|
|
934
965
|
const fullKey = this.keyPrefix + key;
|
|
935
|
-
const strValue =
|
|
936
|
-
|
|
937
|
-
|
|
966
|
+
const strValue = JSON.stringify(value);
|
|
967
|
+
const ttl = ttlSeconds ?? this.defaultTTL;
|
|
968
|
+
if (ttl !== void 0 && ttl > 0) {
|
|
969
|
+
await this.client.set(fullKey, strValue, "EX", ttl);
|
|
938
970
|
} else {
|
|
939
971
|
await this.client.set(fullKey, strValue);
|
|
940
972
|
}
|
|
@@ -947,8 +979,9 @@ var RememberRedisProvider = class {
|
|
|
947
979
|
*/
|
|
948
980
|
async setIfAbsent(key, value, ttlSeconds) {
|
|
949
981
|
const fullKey = this.keyPrefix + key;
|
|
950
|
-
const strValue =
|
|
951
|
-
const
|
|
982
|
+
const strValue = JSON.stringify(value);
|
|
983
|
+
const ttl = ttlSeconds ?? this.defaultTTL;
|
|
984
|
+
const result = ttl !== void 0 && ttl > 0 ? await this.client.set(fullKey, strValue, "EX", ttl, "NX") : await this.client.set(fullKey, strValue, "NX");
|
|
952
985
|
return result === "OK";
|
|
953
986
|
}
|
|
954
987
|
/**
|
|
@@ -1024,8 +1057,11 @@ RememberRedisProvider = __decorateClass([
|
|
|
1024
1057
|
|
|
1025
1058
|
// plugins/plugin-remember/src/providers/remember-vercel-kv.provider.ts
|
|
1026
1059
|
var import_sdk5 = require("@frontmcp/sdk");
|
|
1060
|
+
var import_utils3 = require("@frontmcp/utils");
|
|
1027
1061
|
var RememberVercelKvProvider = class {
|
|
1028
|
-
|
|
1062
|
+
createClient;
|
|
1063
|
+
connection;
|
|
1064
|
+
client;
|
|
1029
1065
|
keyPrefix;
|
|
1030
1066
|
defaultTTL;
|
|
1031
1067
|
constructor(options = {}) {
|
|
@@ -1037,17 +1073,23 @@ var RememberVercelKvProvider = class {
|
|
|
1037
1073
|
`RememberVercelKvProvider: Both 'url' and 'token' must be provided together, or neither. Received: url=${hasUrl ? "provided" : "missing"}, token=${hasToken ? "provided" : "missing"}`
|
|
1038
1074
|
);
|
|
1039
1075
|
}
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
url: options.url,
|
|
1043
|
-
token: options.token
|
|
1044
|
-
});
|
|
1045
|
-
} else {
|
|
1046
|
-
this.kv = vercelKv.kv;
|
|
1047
|
-
}
|
|
1076
|
+
this.createClient = vercelKv.createClient;
|
|
1077
|
+
this.connection = { url: options.url, token: options.token };
|
|
1048
1078
|
this.keyPrefix = options.keyPrefix ?? "remember:";
|
|
1049
1079
|
this.defaultTTL = options.defaultTTL;
|
|
1050
1080
|
}
|
|
1081
|
+
/** Built on first use, like the module's `kv` singleton, which would JSON-parse what it reads. */
|
|
1082
|
+
get kv() {
|
|
1083
|
+
if (!this.client) {
|
|
1084
|
+
const url = this.connection.url ?? (0, import_utils3.getEnv)("KV_REST_API_URL");
|
|
1085
|
+
const token = this.connection.token ?? (0, import_utils3.getEnv)("KV_REST_API_TOKEN");
|
|
1086
|
+
if (!url || !token) {
|
|
1087
|
+
throw new Error("RememberVercelKvProvider: pass url and token, or set KV_REST_API_URL and KV_REST_API_TOKEN.");
|
|
1088
|
+
}
|
|
1089
|
+
this.client = this.createClient({ url, token, automaticDeserialization: false });
|
|
1090
|
+
}
|
|
1091
|
+
return this.client;
|
|
1092
|
+
}
|
|
1051
1093
|
prefixKey(key) {
|
|
1052
1094
|
return `${this.keyPrefix}${key}`;
|
|
1053
1095
|
}
|
|
@@ -1056,7 +1098,7 @@ var RememberVercelKvProvider = class {
|
|
|
1056
1098
|
*/
|
|
1057
1099
|
async setValue(key, value, ttlSeconds) {
|
|
1058
1100
|
const fullKey = this.prefixKey(key);
|
|
1059
|
-
const strValue =
|
|
1101
|
+
const strValue = JSON.stringify(value);
|
|
1060
1102
|
const ttl = ttlSeconds ?? this.defaultTTL;
|
|
1061
1103
|
if (ttl && ttl > 0) {
|
|
1062
1104
|
await this.kv.set(fullKey, strValue, { ex: ttl });
|
|
@@ -1072,7 +1114,7 @@ var RememberVercelKvProvider = class {
|
|
|
1072
1114
|
*/
|
|
1073
1115
|
async setIfAbsent(key, value, ttlSeconds) {
|
|
1074
1116
|
const fullKey = this.prefixKey(key);
|
|
1075
|
-
const strValue =
|
|
1117
|
+
const strValue = JSON.stringify(value);
|
|
1076
1118
|
const ttl = ttlSeconds ?? this.defaultTTL;
|
|
1077
1119
|
const result = ttl && ttl > 0 ? await this.kv.set(fullKey, strValue, { nx: true, ex: ttl }) : await this.kv.set(fullKey, strValue, { nx: true });
|
|
1078
1120
|
return result === "OK";
|
|
@@ -1083,15 +1125,12 @@ var RememberVercelKvProvider = class {
|
|
|
1083
1125
|
async getValue(key, defaultValue) {
|
|
1084
1126
|
const fullKey = this.prefixKey(key);
|
|
1085
1127
|
const raw = await this.kv.get(fullKey);
|
|
1086
|
-
if (raw === null
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
return raw;
|
|
1092
|
-
}
|
|
1128
|
+
if (raw === null) return defaultValue;
|
|
1129
|
+
try {
|
|
1130
|
+
return JSON.parse(raw);
|
|
1131
|
+
} catch {
|
|
1132
|
+
return raw;
|
|
1093
1133
|
}
|
|
1094
|
-
return raw;
|
|
1095
1134
|
}
|
|
1096
1135
|
/**
|
|
1097
1136
|
* Delete a key.
|
|
@@ -1125,7 +1164,7 @@ var RememberVercelKvProvider = class {
|
|
|
1125
1164
|
for (const key of keys) {
|
|
1126
1165
|
result.push(key.slice(this.keyPrefix.length));
|
|
1127
1166
|
}
|
|
1128
|
-
} while (cursor !== 0);
|
|
1167
|
+
} while (String(cursor) !== "0");
|
|
1129
1168
|
} catch {
|
|
1130
1169
|
try {
|
|
1131
1170
|
const keys = await this.kv.keys(searchPattern);
|
|
@@ -1348,7 +1387,7 @@ var rememberThisInputSchema = {
|
|
|
1348
1387
|
key: import_lazy_zod5.z.string().min(1).describe('What to call this memory (e.g., "user_preference", "last_action")'),
|
|
1349
1388
|
value: import_lazy_zod5.z.unknown().describe("The value to remember (any JSON-serializable data)"),
|
|
1350
1389
|
scope: import_lazy_zod5.z.enum(["session", "user", "tool", "global"]).optional().describe(REMEMBER_SCOPE_DESCRIPTION),
|
|
1351
|
-
ttl: import_lazy_zod5.z.number().positive().optional().describe("Forget after this many seconds"),
|
|
1390
|
+
ttl: import_lazy_zod5.z.number().int().positive().optional().describe("Forget after this many whole seconds"),
|
|
1352
1391
|
brand: import_lazy_zod5.z.enum(["preference", "cache", "state", "conversation", "custom"]).optional().describe("Type hint for the stored value")
|
|
1353
1392
|
};
|
|
1354
1393
|
var rememberThisOutputSchema = import_lazy_zod5.z.object({
|
|
@@ -1378,17 +1417,16 @@ var RememberThisTool = class extends import_sdk9.ToolContext {
|
|
|
1378
1417
|
if (!allowedScopes.includes(scope)) {
|
|
1379
1418
|
throw this.fail(new RememberScopeNotAllowedError(scope, allowedScopes));
|
|
1380
1419
|
}
|
|
1381
|
-
await remember.set(input.key, input.value, {
|
|
1420
|
+
const entry = await remember.set(input.key, input.value, {
|
|
1382
1421
|
scope,
|
|
1383
1422
|
ttl: input.ttl,
|
|
1384
1423
|
brand: input.brand
|
|
1385
1424
|
});
|
|
1386
|
-
const expiresAt = input.ttl ? Date.now() + input.ttl * 1e3 : void 0;
|
|
1387
1425
|
return {
|
|
1388
1426
|
success: true,
|
|
1389
1427
|
key: input.key,
|
|
1390
1428
|
scope,
|
|
1391
|
-
expiresAt
|
|
1429
|
+
expiresAt: entry.expiresAt
|
|
1392
1430
|
};
|
|
1393
1431
|
}
|
|
1394
1432
|
};
|
|
@@ -1424,13 +1462,24 @@ function createRememberTools(prefix = "") {
|
|
|
1424
1462
|
}
|
|
1425
1463
|
|
|
1426
1464
|
// plugins/plugin-remember/src/remember.plugin.ts
|
|
1465
|
+
function withCheckedDefaultTTL(options) {
|
|
1466
|
+
const { defaultTTL } = options;
|
|
1467
|
+
if (defaultTTL === void 0) return options;
|
|
1468
|
+
if (defaultTTL === 0) return { ...options, defaultTTL: void 0 };
|
|
1469
|
+
if (!Number.isInteger(defaultTTL) || defaultTTL < 0) {
|
|
1470
|
+
throw new RememberConfigurationError(
|
|
1471
|
+
`RememberPlugin defaultTTL must be a whole number of seconds (0 for no default expiry), got ${defaultTTL}`
|
|
1472
|
+
);
|
|
1473
|
+
}
|
|
1474
|
+
return options;
|
|
1475
|
+
}
|
|
1427
1476
|
var RememberPlugin = class extends import_sdk11.DynamicPlugin {
|
|
1428
1477
|
options;
|
|
1429
1478
|
constructor(options = {}) {
|
|
1430
1479
|
super();
|
|
1431
1480
|
this.options = {
|
|
1432
1481
|
...RememberPlugin.defaultOptions,
|
|
1433
|
-
...options
|
|
1482
|
+
...withCheckedDefaultTTL(options)
|
|
1434
1483
|
};
|
|
1435
1484
|
}
|
|
1436
1485
|
};
|
|
@@ -1451,7 +1500,7 @@ __publicField(RememberPlugin, "dynamicProviders", (options) => {
|
|
|
1451
1500
|
const providers = [];
|
|
1452
1501
|
const config = {
|
|
1453
1502
|
...RememberPlugin.defaultOptions,
|
|
1454
|
-
...options
|
|
1503
|
+
...withCheckedDefaultTTL(options)
|
|
1455
1504
|
};
|
|
1456
1505
|
switch (config.type) {
|
|
1457
1506
|
case "global-store":
|
|
@@ -1530,7 +1579,7 @@ __publicField(RememberPlugin, "dynamicProviders", (options) => {
|
|
|
1530
1579
|
provide: RememberStoreToken,
|
|
1531
1580
|
// Built per server: `init()` runs once, so a value here would be shared by every server using it.
|
|
1532
1581
|
inject: () => [],
|
|
1533
|
-
useFactory: () => new RememberMemoryProvider()
|
|
1582
|
+
useFactory: () => new RememberMemoryProvider(void 0, config.defaultTTL)
|
|
1534
1583
|
});
|
|
1535
1584
|
break;
|
|
1536
1585
|
}
|
|
@@ -1607,6 +1656,7 @@ function tryGetRemember(ctx) {
|
|
|
1607
1656
|
RememberAccessor,
|
|
1608
1657
|
RememberAccessorToken,
|
|
1609
1658
|
RememberConfigToken,
|
|
1659
|
+
RememberConfigurationError,
|
|
1610
1660
|
RememberIdentityError,
|
|
1611
1661
|
RememberMemoryProvider,
|
|
1612
1662
|
RememberPlugin,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@frontmcp/plugin-remember",
|
|
3
|
-
"version": "1.9.
|
|
3
|
+
"version": "1.9.1-rc.2",
|
|
4
4
|
"description": "Remember plugin for FrontMCP - encrypted session memory with approval system for secure tool authorization",
|
|
5
5
|
"author": "AgentFront <info@agentfront.dev>",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -49,12 +49,12 @@
|
|
|
49
49
|
}
|
|
50
50
|
},
|
|
51
51
|
"dependencies": {
|
|
52
|
-
"@frontmcp/sdk": "1.9.
|
|
53
|
-
"@frontmcp/utils": "1.9.
|
|
52
|
+
"@frontmcp/sdk": "1.9.1-rc.2",
|
|
53
|
+
"@frontmcp/utils": "1.9.1-rc.2",
|
|
54
54
|
"ioredis": "^5.8.0"
|
|
55
55
|
},
|
|
56
56
|
"peerDependencies": {
|
|
57
|
-
"@frontmcp/lazy-zod": "1.9.
|
|
57
|
+
"@frontmcp/lazy-zod": "1.9.1-rc.2",
|
|
58
58
|
"@vercel/kv": "^2.0.0 || ^3.0.0"
|
|
59
59
|
},
|
|
60
60
|
"peerDependenciesMeta": {
|
|
@@ -35,11 +35,14 @@ export declare class RememberAccessor {
|
|
|
35
35
|
/**
|
|
36
36
|
* Store a value in memory.
|
|
37
37
|
*
|
|
38
|
+
* Without a `ttl`, the plugin's `defaultTTL` applies, and the entry records the deadline either one sets.
|
|
39
|
+
*
|
|
38
40
|
* @param key - The key to store under
|
|
39
41
|
* @param value - The value to store (any JSON-serializable data)
|
|
40
42
|
* @param options - Storage options (scope, ttl, brand, metadata)
|
|
43
|
+
* @returns The stored entry, with its `expiresAt` deadline
|
|
41
44
|
*/
|
|
42
|
-
set<T>(key: string, value: T, options?: RememberSetOptions): Promise<
|
|
45
|
+
set<T>(key: string, value: T, options?: RememberSetOptions): Promise<RememberEntry<T>>;
|
|
43
46
|
/**
|
|
44
47
|
* Retrieve a value from memory.
|
|
45
48
|
*
|
|
@@ -85,6 +88,7 @@ export declare class RememberAccessor {
|
|
|
85
88
|
*
|
|
86
89
|
* With a `ttl` the entry expires that many seconds from now; without one it keeps its current
|
|
87
90
|
* expiry, in the store as well, so the store does not keep it past that (rounded up to a second).
|
|
91
|
+
* An entry with no recorded expiry gets the plugin's `defaultTTL` from now, as the store would give it.
|
|
88
92
|
*
|
|
89
93
|
* @param key - The key to update
|
|
90
94
|
* @param value - The new value
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"remember-accessor.provider.d.ts","sourceRoot":"","sources":["../../src/providers/remember-accessor.provider.ts"],"names":[],"mappings":"AAAA,OAAO,EAML,KAAK,eAAe,EACpB,KAAK,cAAc,EACpB,MAAM,eAAe,CAAC;AAKvB,OAAO,KAAK,EACV,aAAa,EACb,qBAAqB,EACrB,kBAAkB,EAClB,oBAAoB,EACpB,mBAAmB,EACnB,qBAAqB,EACrB,aAAa,EACb,kBAAkB,EACnB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;
|
|
1
|
+
{"version":3,"file":"remember-accessor.provider.d.ts","sourceRoot":"","sources":["../../src/providers/remember-accessor.provider.ts"],"names":[],"mappings":"AAAA,OAAO,EAML,KAAK,eAAe,EACpB,KAAK,cAAc,EACpB,MAAM,eAAe,CAAC;AAKvB,OAAO,KAAK,EACV,aAAa,EACb,qBAAqB,EACrB,kBAAkB,EAClB,oBAAoB,EACpB,mBAAmB,EACnB,qBAAqB,EACrB,aAAa,EACb,kBAAkB,EACnB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AAmCzE;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,qBAKa,gBAAgB;IAC3B,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAyB;IAC/C,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAkB;IACtC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAwB;IAC/C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAU;gBAG1C,KAAK,EAAE,sBAAsB,EAC7B,GAAG,EAAE,eAAe,EACpB,MAAM,EAAE,qBAAqB,EAC7B,MAAM,CAAC,EAAE,IAAI,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC;IAwBjD;;;;;;;;;OASG;IACG,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,GAAE,kBAAuB,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;IAuBhG;;;;;;OAMG;IACG,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,GAAE,kBAAkB,CAAC,CAAC,CAAM,GAAG,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC;IAMtF;;;;;;OAMG;IACG,QAAQ,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,GAAE;QAAE,KAAK,CAAC,EAAE,aAAa,CAAA;KAAO,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC;IAK9G;;;;;OAKG;IACG,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,GAAE,qBAA0B,GAAG,OAAO,CAAC,IAAI,CAAC;IAM7E;;;;;;OAMG;IACG,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,GAAE,oBAAyB,GAAG,OAAO,CAAC,OAAO,CAAC;IAK9E;;;;;OAKG;IACG,IAAI,CAAC,OAAO,GAAE,mBAAwB,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAWhE;;;;;;;;;;OAUG;IACG,MAAM,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,GAAE;QAAE,KAAK,CAAC,EAAE,aAAa,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAA;KAAO,GAAG,OAAO,CAAC,OAAO,CAAC;IAiC/G;;;;;OAKG;IACH,IAAI,SAAS,IAAI,MAAM,CAEtB;IAED;;OAEG;IACH,IAAI,MAAM,IAAI,MAAM,GAAG,SAAS,CAS/B;IAMD;;OAEG;IACH,OAAO,CAAC,eAAe;IAIvB;;;;;;;;OAQG;IACH,OAAO,KAAK,iBAAiB,GAQ5B;IAED;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,sBAAsB;IAmB9B;;;;;OAKG;IACH,OAAO,KAAK,QAAQ,GAEnB;IAED;;;;;;;OAOG;IACH,OAAO,CAAC,gBAAgB;IA4BxB;;OAEG;IACH,OAAO,CAAC,YAAY;IAYpB,iGAAiG;YACnF,SAAS;IAkBvB;;OAEG;IACH,OAAO,CAAC,UAAU;CAOnB;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,sBAAsB,EAC7B,GAAG,EAAE,eAAe,EACpB,MAAM,EAAE,qBAAqB,EAC7B,MAAM,CAAC,EAAE,IAAI,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,GAC9C,gBAAgB,CAElB"}
|
|
@@ -4,9 +4,10 @@ import type { RememberStoreInterface } from './remember-store.interface';
|
|
|
4
4
|
* Provides fast, local storage with automatic TTL expiration.
|
|
5
5
|
*/
|
|
6
6
|
export default class RememberMemoryProvider implements RememberStoreInterface {
|
|
7
|
+
private readonly defaultTTL?;
|
|
7
8
|
private readonly memory;
|
|
8
9
|
private sweeper?;
|
|
9
|
-
constructor(sweepIntervalSeconds?: number);
|
|
10
|
+
constructor(sweepIntervalSeconds?: number, defaultTTL?: number | undefined);
|
|
10
11
|
/**
|
|
11
12
|
* Store a value with optional TTL.
|
|
12
13
|
* Always JSON-serializes the value for consistent storage/retrieval.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"remember-memory.provider.d.ts","sourceRoot":"","sources":["../../src/providers/remember-memory.provider.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AAgBzE;;;GAGG;AAMH,MAAM,CAAC,OAAO,OAAO,sBAAuB,YAAW,sBAAsB;
|
|
1
|
+
{"version":3,"file":"remember-memory.provider.d.ts","sourceRoot":"","sources":["../../src/providers/remember-memory.provider.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AAgBzE;;;GAGG;AAMH,MAAM,CAAC,OAAO,OAAO,sBAAuB,YAAW,sBAAsB;IAMzE,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC;IAL9B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA4B;IACnD,OAAO,CAAC,OAAO,CAAC,CAAiB;gBAG/B,oBAAoB,SAAK,EACR,UAAU,CAAC,EAAE,MAAM,YAAA;IAOtC;;;OAGG;IACG,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IA+B/E;;;;;OAKG;IACG,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAQrF;;;OAGG;IACG,QAAQ,CAAC,CAAC,GAAG,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC;IAkBlF;;OAEG;IACG,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAMxC;;OAEG;IACG,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAU3C;;;OAGG;IACG,IAAI,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAiC/C;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAY5B,OAAO,CAAC,SAAS;IAIjB;;OAEG;IACH,OAAO,CAAC,KAAK;IAYb,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,kBAAkB,CAAO;IACjD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,aAAa,CAAM;IAE3C;;;;;;OAMG;IACH,OAAO,CAAC,cAAc;CAkBvB"}
|
|
@@ -15,6 +15,8 @@ export default class RememberRedisProvider implements RememberStoreInterface {
|
|
|
15
15
|
* Include any separator (e.g., "myapp:" or "user:123:") as part of the prefix.
|
|
16
16
|
*/
|
|
17
17
|
private readonly keyPrefix;
|
|
18
|
+
/** TTL in seconds for values stored without one. */
|
|
19
|
+
private readonly defaultTTL?;
|
|
18
20
|
/** True if this provider created the client (and should close it), false if externally provided */
|
|
19
21
|
private readonly ownsClient;
|
|
20
22
|
constructor(options: RedisRememberOptions);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"remember-redis.provider.d.ts","sourceRoot":"","sources":["../../src/providers/remember-redis.provider.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,gCAAgC,EAAE,0BAA0B,EAAE,MAAM,mBAAmB,CAAC;AACtG,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AAEzE;;GAEG;AACH,MAAM,MAAM,oBAAoB,GAAG,0BAA0B,GAAG,gCAAgC,CAAC;AAEjG;;;GAGG;AAMH,MAAM,CAAC,OAAO,OAAO,qBAAsB,YAAW,sBAAsB;IAC1E,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAc;IACrC;;;OAGG;IACH,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,mGAAmG;IACnG,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAU;gBAEzB,OAAO,EAAE,oBAAoB;
|
|
1
|
+
{"version":3,"file":"remember-redis.provider.d.ts","sourceRoot":"","sources":["../../src/providers/remember-redis.provider.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,gCAAgC,EAAE,0BAA0B,EAAE,MAAM,mBAAmB,CAAC;AACtG,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AAEzE;;GAEG;AACH,MAAM,MAAM,oBAAoB,GAAG,0BAA0B,GAAG,gCAAgC,CAAC;AAEjG;;;GAGG;AAMH,MAAM,CAAC,OAAO,OAAO,qBAAsB,YAAW,sBAAsB;IAC1E,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAc;IACrC;;;OAGG;IACH,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,oDAAoD;IACpD,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAS;IACrC,mGAAmG;IACnG,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAU;gBAEzB,OAAO,EAAE,oBAAoB;IA8BzC;;;;;;;OAOG;IACG,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IA8B/E;;;;;OAKG;IACG,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAarF;;;;;;;;;;OAUG;IACG,QAAQ,CAAC,CAAC,GAAG,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC;IAclF;;OAEG;IACG,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAKxC;;OAEG;IACG,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAK3C;;;OAGG;IACG,IAAI,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAkB/C;;;;OAIG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAK7B"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type
|
|
1
|
+
import { type NamespacedStorage, type RootStorage, type StorageConfig } from '@frontmcp/utils';
|
|
2
2
|
import type { RememberStoreInterface } from './remember-store.interface';
|
|
3
3
|
/**
|
|
4
4
|
* Configuration options for RememberStorageProvider.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"remember-storage.provider.d.ts","sourceRoot":"","sources":["../../src/providers/remember-storage.provider.ts"],"names":[],"mappings":"AACA,OAAO,
|
|
1
|
+
{"version":3,"file":"remember-storage.provider.d.ts","sourceRoot":"","sources":["../../src/providers/remember-storage.provider.ts"],"names":[],"mappings":"AACA,OAAO,EAAiB,KAAK,iBAAiB,EAAE,KAAK,WAAW,EAAE,KAAK,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAE9G,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AAMzE;;GAEG;AACH,MAAM,WAAW,8BAA8B;IAC7C;;;OAGG;IACH,OAAO,CAAC,EAAE,aAAa,CAAC;IAExB;;;OAGG;IACH,eAAe,CAAC,EAAE,WAAW,GAAG,iBAAiB,CAAC;IAElD;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;;OAGG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAMD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,qBAKa,uBAAwB,YAAW,sBAAsB;IACpE,OAAO,CAAC,OAAO,CAAqB;IACpC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAGtB;IACF,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,YAAY,CAAS;gBAEjB,OAAO,GAAE,8BAAmC;IASxD;;;OAGG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAkBjC;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAMzB;;;;;OAKG;IACG,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAgC/E;;;;;OAKG;IACG,QAAQ,CAAC,CAAC,GAAG,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC;IAelF;;;OAGG;IACG,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAKxC;;;;OAIG;IACG,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAK3C;;;;OAIG;IACG,IAAI,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAK/C;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAQ7B;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,4BAA4B,CAC1C,OAAO,GAAE,IAAI,CAAC,8BAA8B,EAAE,SAAS,GAAG,iBAAiB,CAAM,GAChF,uBAAuB,CAKzB"}
|
|
@@ -17,10 +17,14 @@ export interface RememberVercelKvProviderOptions {
|
|
|
17
17
|
* Provides serverless-compatible, edge-ready storage.
|
|
18
18
|
*/
|
|
19
19
|
export default class RememberVercelKvProvider implements RememberStoreInterface {
|
|
20
|
-
private
|
|
20
|
+
private readonly createClient;
|
|
21
|
+
private readonly connection;
|
|
22
|
+
private client?;
|
|
21
23
|
private readonly keyPrefix;
|
|
22
24
|
private readonly defaultTTL?;
|
|
23
25
|
constructor(options?: RememberVercelKvProviderOptions);
|
|
26
|
+
/** Built on first use, like the module's `kv` singleton, which would JSON-parse what it reads. */
|
|
27
|
+
private get kv();
|
|
24
28
|
private prefixKey;
|
|
25
29
|
/**
|
|
26
30
|
* Store a value with optional TTL.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"remember-vercel-kv.provider.d.ts","sourceRoot":"","sources":["../../src/providers/remember-vercel-kv.provider.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"remember-vercel-kv.provider.d.ts","sourceRoot":"","sources":["../../src/providers/remember-vercel-kv.provider.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AAmBzE;;GAEG;AACH,MAAM,WAAW,+BAA+B;IAC9C,0DAA0D;IAC1D,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,8DAA8D;IAC9D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,sCAAsC;IACtC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,6BAA6B;IAC7B,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;GAGG;AAMH,MAAM,CAAC,OAAO,OAAO,wBAAyB,YAAW,sBAAsB;IAC7E,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAiC;IAC9D,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAmC;IAC9D,OAAO,CAAC,MAAM,CAAC,CAAiB;IAChC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAS;gBAEzB,OAAO,GAAE,+BAAoC;IAoBzD,kGAAkG;IAClG,OAAO,KAAK,EAAE,GAUb;IAED,OAAO,CAAC,SAAS;IAIjB;;OAEG;IACG,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAY/E;;;;;OAKG;IACG,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAarF;;OAEG;IACG,QAAQ,CAAC,CAAC,GAAG,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC;IAalF;;OAEG;IACG,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAKxC;;OAEG;IACG,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAK3C;;;OAGG;IACG,IAAI,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAmC/C;;;OAGG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAG7B"}
|
package/remember.errors.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { PublicMcpError } from '@frontmcp/sdk';
|
|
1
|
+
import { InternalMcpError, PublicMcpError } from '@frontmcp/sdk';
|
|
2
2
|
/**
|
|
3
3
|
* Raised when Remember has no per-client identity to namespace storage with
|
|
4
4
|
* (GHSA-225p-f8jh-f3rh).
|
|
@@ -20,4 +20,9 @@ export declare class RememberScopeNotAllowedError extends PublicMcpError {
|
|
|
20
20
|
readonly name = "RememberScopeNotAllowedError";
|
|
21
21
|
constructor(scope: string, allowedScopes: readonly string[]);
|
|
22
22
|
}
|
|
23
|
+
/** Raised at startup for a plugin option that cannot work, such as a fractional or negative `defaultTTL`. */
|
|
24
|
+
export declare class RememberConfigurationError extends InternalMcpError {
|
|
25
|
+
readonly name = "RememberConfigurationError";
|
|
26
|
+
constructor(message: string);
|
|
27
|
+
}
|
|
23
28
|
//# sourceMappingURL=remember.errors.d.ts.map
|
package/remember.errors.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"remember.errors.d.ts","sourceRoot":"","sources":["../src/remember.errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"remember.errors.d.ts","sourceRoot":"","sources":["../src/remember.errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAEjE;;;;;;;GAOG;AACH,qBAAa,qBAAsB,SAAQ,cAAc;IACvD,SAAkB,IAAI,2BAA2B;gBAErC,OAAO,EAAE,MAAM;CAG5B;AAED;;;;GAIG;AACH,qBAAa,4BAA6B,SAAQ,cAAc;IAC9D,SAAkB,IAAI,kCAAkC;gBAE5C,KAAK,EAAE,MAAM,EAAE,aAAa,EAAE,SAAS,MAAM,EAAE;CAO5D;AAED,6GAA6G;AAC7G,qBAAa,0BAA2B,SAAQ,gBAAgB;IAC9D,SAAkB,IAAI,gCAAgC;gBAE1C,OAAO,EAAE,MAAM;CAG5B"}
|
|
@@ -16,7 +16,7 @@ import type { RememberStoreInterface } from './providers/remember-store.interfac
|
|
|
16
16
|
* `undefined` means the clock could not be established, and the caller must not delete anything
|
|
17
17
|
* on it.
|
|
18
18
|
*/
|
|
19
|
-
export declare function readLayoutFirstSeenAt(store: RememberStoreInterface, keyPrefix: string, logger?: Pick<FrontMcpLogger, 'warn' | 'debug'
|
|
19
|
+
export declare function readLayoutFirstSeenAt(store: RememberStoreInterface, keyPrefix: string, logger?: Pick<FrontMcpLogger, 'warn' | 'debug'>, markerTtlSeconds?: number): Promise<number | undefined>;
|
|
20
20
|
/**
|
|
21
21
|
* Delete entries that the key-derivation and namespace-encoding changes orphaned.
|
|
22
22
|
*
|
|
@@ -38,6 +38,7 @@ export declare function purgeLegacyRememberEntries(store: RememberStoreInterface
|
|
|
38
38
|
*/
|
|
39
39
|
export declare function scheduleLegacyRememberPurge(store: RememberStoreInterface, keyPrefix: string, options?: {
|
|
40
40
|
delayMs?: number;
|
|
41
|
+
defaultTTL?: number;
|
|
41
42
|
logger?: Pick<FrontMcpLogger, 'warn' | 'debug'>;
|
|
42
43
|
}): void;
|
|
43
44
|
/** Test seam: forget which stores have a sweep armed. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"remember.legacy-purge.d.ts","sourceRoot":"","sources":["../src/remember.legacy-purge.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAEpD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,sCAAsC,CAAC;AAiEnF;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,qBAAqB,CACzC,KAAK,EAAE,sBAAsB,EAC7B,SAAS,EAAE,MAAM,EACjB,MAAM,CAAC,EAAE,IAAI,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,
|
|
1
|
+
{"version":3,"file":"remember.legacy-purge.d.ts","sourceRoot":"","sources":["../src/remember.legacy-purge.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAEpD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,sCAAsC,CAAC;AAiEnF;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,qBAAqB,CACzC,KAAK,EAAE,sBAAsB,EAC7B,SAAS,EAAE,MAAM,EACjB,MAAM,CAAC,EAAE,IAAI,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,EAC/C,gBAAgB,CAAC,EAAE,MAAM,GACxB,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAiC7B;AAED;;;;;;GAMG;AACH,wBAAsB,0BAA0B,CAC9C,KAAK,EAAE,sBAAsB,EAC7B,SAAS,EAAE,MAAM,EACjB,MAAM,CAAC,EAAE,IAAI,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,GAC9C,OAAO,CAAC,MAAM,CAAC,CAqCjB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,2BAA2B,CACzC,KAAK,EAAE,sBAAsB,EAC7B,SAAS,EAAE,MAAM,EACjB,OAAO,GAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,IAAI,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,CAAA;CAAO,GACvG,IAAI,CA0CN;AAED,yDAAyD;AACzD,wBAAgB,6BAA6B,CAAC,KAAK,EAAE,sBAAsB,GAAG,IAAI,CAEjF"}
|
package/remember.plugin.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"remember.plugin.d.ts","sourceRoot":"","sources":["../src/remember.plugin.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EASb,KAAK,YAAY,EACjB,KAAK,QAAQ,EACd,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"remember.plugin.d.ts","sourceRoot":"","sources":["../src/remember.plugin.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EASb,KAAK,YAAY,EACjB,KAAK,QAAQ,EACd,MAAM,eAAe,CAAC;AAQvB,OAAO,KAAK,EAAE,qBAAqB,EAAE,0BAA0B,EAAE,MAAM,kBAAkB,CAAC;AAgB1F;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAwBH,MAAM,CAAC,OAAO,OAAO,cAAe,SAAQ,aAAa,CAAC,qBAAqB,EAAE,0BAA0B,CAAC;IAC1G,MAAM,CAAC,cAAc,EAAE,qBAAqB,CAI1C;IAEF,OAAO,EAAE,qBAAqB,CAAC;gBAEnB,OAAO,GAAE,0BAA+B;IAQpD;;;OAGG;IACH,OAAgB,YAAY,GAAI,SAAS,0BAA0B,KAAG,SAAS,QAAQ,EAAE,CACf;IAE1E;;OAEG;IACH,OAAgB,gBAAgB,GAAI,SAAS,0BAA0B,KAAG,YAAY,EAAE,CA2HtF;CACH"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"remember-this.tool.d.ts","sourceRoot":"","sources":["../../src/tools/remember-this.tool.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,oBAAoB,CAAC;AACvC,OAAO,EAAQ,WAAW,EAAE,MAAM,eAAe,CAAC;AAKlD,OAAO,EAAqB,KAAK,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAElF;;GAEG;AACH,eAAO,MAAM,uBAAuB;;;;;;;;;;;;;;;;;CASnC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,wBAAwB;;;;;gCAKnC,CAAC;AAEH,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,OAAO,uBAAuB,CAAC,CAAC,CAAC;AAErF,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAE1E,wBAAgB,uBAAuB,CAAC,KAAK,GAAE,iBAAuC,GAAG,MAAM,CAO9F;AAED,wBAAgB,wBAAwB,CAAC,KAAK,GAAE,iBAAuC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAQtF;AAED;;;GAGG;AAEH,MAAM,CAAC,OAAO,OAAO,gBAAiB,SAAQ,WAAW;IACjD,OAAO,CAAC,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAAC,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"remember-this.tool.d.ts","sourceRoot":"","sources":["../../src/tools/remember-this.tool.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,oBAAoB,CAAC;AACvC,OAAO,EAAQ,WAAW,EAAE,MAAM,eAAe,CAAC;AAKlD,OAAO,EAAqB,KAAK,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAElF;;GAEG;AACH,eAAO,MAAM,uBAAuB;;;;;;;;;;;;;;;;;CASnC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,wBAAwB;;;;;gCAKnC,CAAC;AAEH,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,OAAO,uBAAuB,CAAC,CAAC,CAAC;AAErF,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAE1E,wBAAgB,uBAAuB,CAAC,KAAK,GAAE,iBAAuC,GAAG,MAAM,CAO9F;AAED,wBAAgB,wBAAwB,CAAC,KAAK,GAAE,iBAAuC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAQtF;AAED;;;GAGG;AAEH,MAAM,CAAC,OAAO,OAAO,gBAAiB,SAAQ,WAAW;IACjD,OAAO,CAAC,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAAC,kBAAkB,CAAC;CAyBrE"}
|