@frontmcp/plugin-remember 1.9.1 → 1.9.3

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 CHANGED
@@ -4,12 +4,6 @@ const require = __frontmcpModule ? __frontmcpModule.createRequire(import.meta.ur
4
4
  var __defProp = Object.defineProperty;
5
5
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
6
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
7
- var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
8
- get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
9
- }) : x)(function(x) {
10
- if (typeof require !== "undefined") return require.apply(this, arguments);
11
- throw Error('Dynamic require of "' + x + '" is not supported');
12
- });
13
7
  var __decorateClass = (decorators, target, key, kind) => {
14
8
  var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
15
9
  for (var i = decorators.length - 1, decorator; i >= 0; i--)
@@ -188,6 +182,9 @@ async function getBaseSecret() {
188
182
  }
189
183
  return getOrCreatePersistedSecret();
190
184
  }
185
+ async function secretFor(source) {
186
+ return source.secret ? source.secret : getBaseSecret();
187
+ }
191
188
  var textEncoder = new TextEncoder();
192
189
  async function deriveEncryptionKey(source) {
193
190
  const salt = textEncoder.encode("remember-plugin-v1");
@@ -195,19 +192,19 @@ async function deriveEncryptionKey(source) {
195
192
  let context;
196
193
  switch (source.type) {
197
194
  case "session":
198
- ikm = await getBaseSecret() + source.sessionId;
195
+ ikm = await secretFor(source) + source.sessionId;
199
196
  context = `remember:session:${source.sessionId}`;
200
197
  break;
201
198
  case "tool":
202
- ikm = await getBaseSecret() + source.sessionId;
199
+ ikm = await secretFor(source) + source.sessionId;
203
200
  context = `remember:tool:${source.toolName}:${source.sessionId}`;
204
201
  break;
205
202
  case "user":
206
- ikm = await getBaseSecret() + source.userId;
203
+ ikm = await secretFor(source) + source.userId;
207
204
  context = `remember:user:${source.userId}`;
208
205
  break;
209
206
  case "global":
210
- ikm = await getBaseSecret();
207
+ ikm = await secretFor(source);
211
208
  context = "remember:global";
212
209
  break;
213
210
  case "custom":
@@ -219,20 +216,21 @@ async function deriveEncryptionKey(source) {
219
216
  const info = textEncoder.encode(context);
220
217
  return hkdfSha256(ikmBytes, salt, info, 32);
221
218
  }
222
- function getKeySourceForScope(scope, context) {
219
+ function getKeySourceForScope(scope, context, secret) {
223
220
  switch (scope) {
224
221
  case "session":
225
- return { type: "session", sessionId: context.sessionId };
222
+ return { type: "session", sessionId: context.sessionId, secret };
226
223
  case "user":
227
- return { type: "user", userId: context.userId ?? "anonymous" };
224
+ return { type: "user", userId: context.userId ?? "anonymous", secret };
228
225
  case "tool":
229
226
  return {
230
227
  type: "tool",
231
228
  toolName: context.toolName ?? "unknown",
232
- sessionId: context.sessionId
229
+ sessionId: context.sessionId,
230
+ secret
233
231
  };
234
232
  case "global":
235
- return { type: "global" };
233
+ return { type: "global", secret };
236
234
  }
237
235
  }
238
236
  var textDecoder = new TextDecoder();
@@ -635,7 +633,7 @@ var RememberAccessor = class {
635
633
  * `'unknown'`.
636
634
  */
637
635
  get toolName() {
638
- return getRunningTool()?.fullName ?? this.ctx.flow?.name ?? "unknown";
636
+ return getRunningTool()?.fullName ?? "unknown";
639
637
  }
640
638
  /**
641
639
  * Build the scope-specific prefix.
@@ -669,11 +667,15 @@ var RememberAccessor = class {
669
667
  */
670
668
  getKeySource(scope) {
671
669
  const needsSessionIdentity = scope === "session" || scope === "tool";
672
- return getKeySourceForScope(scope, {
673
- sessionId: needsSessionIdentity ? this.resolveSessionIdentity() : this.ctx.sessionId,
674
- userId: this.userId,
675
- toolName: scope === "tool" ? this.toolName : void 0
676
- });
670
+ return getKeySourceForScope(
671
+ scope,
672
+ {
673
+ sessionId: needsSessionIdentity ? this.resolveSessionIdentity() : this.ctx.sessionId,
674
+ userId: this.userId,
675
+ toolName: scope === "tool" ? this.toolName : void 0
676
+ },
677
+ this.config.encryption?.customKey
678
+ );
677
679
  }
678
680
  /** The entry stored under `storageKey`, if readable and unexpired; an expired one is deleted. */
679
681
  async readEntry(storageKey, scope) {
@@ -885,10 +887,28 @@ RememberMemoryProvider = __decorateClass([
885
887
  // plugins/plugin-remember/src/providers/remember-redis.provider.ts
886
888
  import Redis from "ioredis";
887
889
  import { Provider as Provider3, ProviderScope as ProviderScope3 } from "@frontmcp/sdk";
890
+
891
+ // plugins/plugin-remember/src/providers/remember-key-prefix.ts
892
+ function prefixedStoreKey(keyPrefix, key) {
893
+ return keyPrefix && key.startsWith(keyPrefix) ? key : keyPrefix + key;
894
+ }
895
+ function doubledPrefixKey(keyPrefix, key) {
896
+ return keyPrefix && key.startsWith(keyPrefix) ? keyPrefix + key : void 0;
897
+ }
898
+ function callerKeyOf(keyPrefix, pattern, backendKey) {
899
+ return keyPrefix && pattern.startsWith(keyPrefix) ? backendKey : backendKey.slice(keyPrefix.length);
900
+ }
901
+ var SET_IF_NEITHER_KEY_EXISTS_SCRIPT = `
902
+ if redis.call('EXISTS', KEYS[1], KEYS[2]) > 0 then return 0 end
903
+ if ARGV[2] ~= '' then redis.call('SET', KEYS[1], ARGV[1], 'EX', ARGV[2]) else redis.call('SET', KEYS[1], ARGV[1]) end
904
+ return 1
905
+ `;
906
+
907
+ // plugins/plugin-remember/src/providers/remember-redis.provider.ts
888
908
  var RememberRedisProvider = class {
889
909
  client;
890
910
  /**
891
- * Prefix prepended to all Redis keys.
911
+ * Prefix prepended to Redis keys that don't already start with it.
892
912
  * Include any separator (e.g., "myapp:" or "user:123:") as part of the prefix.
893
913
  */
894
914
  keyPrefix;
@@ -942,7 +962,7 @@ var RememberRedisProvider = class {
942
962
  throw new Error(`Invalid TTL: must be an integer, got ${ttlSeconds}`);
943
963
  }
944
964
  }
945
- const fullKey = this.keyPrefix + key;
965
+ const fullKey = prefixedStoreKey(this.keyPrefix, key);
946
966
  const strValue = JSON.stringify(value);
947
967
  const ttl = ttlSeconds ?? this.defaultTTL;
948
968
  if (ttl !== void 0 && ttl > 0) {
@@ -950,18 +970,35 @@ var RememberRedisProvider = class {
950
970
  } else {
951
971
  await this.client.set(fullKey, strValue);
952
972
  }
973
+ await this.deleteDoubledPrefixKey(key);
953
974
  }
954
975
  /**
955
976
  * Store a value only if the key is absent, via Redis `SET ... NX`.
956
977
  *
957
978
  * `set` resolves to `'OK'` when it created the key and `null` when the key already existed,
958
979
  * so the whole check-and-write is one round trip and two callers racing cannot both win.
980
+ * A key that releases up to 1.9.1 may hold under the doubled prefix counts as present too: one
981
+ * script checks both keys and writes, so an entry still there is never shadowed.
959
982
  */
960
983
  async setIfAbsent(key, value, ttlSeconds) {
961
- const fullKey = this.keyPrefix + key;
984
+ const fullKey = prefixedStoreKey(this.keyPrefix, key);
962
985
  const strValue = JSON.stringify(value);
963
986
  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");
987
+ const hasTtl = ttl !== void 0 && ttl > 0;
988
+ const doubledKey = doubledPrefixKey(this.keyPrefix, key);
989
+ if (doubledKey) {
990
+ const ttlArgument = hasTtl ? String(ttl) : "";
991
+ const created = await this.client.eval(
992
+ SET_IF_NEITHER_KEY_EXISTS_SCRIPT,
993
+ 2,
994
+ fullKey,
995
+ doubledKey,
996
+ strValue,
997
+ ttlArgument
998
+ );
999
+ return created === 1;
1000
+ }
1001
+ const result = hasTtl ? await this.client.set(fullKey, strValue, "EX", ttl, "NX") : await this.client.set(fullKey, strValue, "NX");
965
1002
  return result === "OK";
966
1003
  }
967
1004
  /**
@@ -976,8 +1013,7 @@ var RememberRedisProvider = class {
976
1013
  * @returns The parsed value as T, or defaultValue/undefined
977
1014
  */
978
1015
  async getValue(key, defaultValue) {
979
- const fullKey = this.keyPrefix + key;
980
- const raw = await this.client.get(fullKey);
1016
+ const raw = await this.client.get(prefixedStoreKey(this.keyPrefix, key)) ?? await this.readDoubledPrefixValue(key);
981
1017
  if (raw === null) return defaultValue;
982
1018
  try {
983
1019
  return JSON.parse(raw);
@@ -989,32 +1025,55 @@ var RememberRedisProvider = class {
989
1025
  * Delete a key.
990
1026
  */
991
1027
  async delete(key) {
992
- const fullKey = this.keyPrefix + key;
993
- await this.client.del(fullKey);
1028
+ await this.client.del(prefixedStoreKey(this.keyPrefix, key));
1029
+ await this.deleteDoubledPrefixKey(key);
994
1030
  }
995
1031
  /**
996
1032
  * Check if a key exists.
997
1033
  */
998
1034
  async exists(key) {
999
- const fullKey = this.keyPrefix + key;
1000
- return await this.client.exists(fullKey) === 1;
1035
+ if (await this.client.exists(prefixedStoreKey(this.keyPrefix, key)) === 1) return true;
1036
+ const doubledKey = doubledPrefixKey(this.keyPrefix, key);
1037
+ return doubledKey !== void 0 && await this.client.exists(doubledKey) === 1;
1001
1038
  }
1002
1039
  /**
1003
1040
  * List keys matching a pattern.
1004
1041
  * Uses Redis SCAN for efficient iteration.
1005
1042
  */
1006
- async keys(pattern) {
1007
- const searchPattern = this.keyPrefix + (pattern ?? "*");
1008
- const result = [];
1043
+ async keys(pattern = "*") {
1044
+ const result = /* @__PURE__ */ new Set();
1045
+ for (const key of await this.scan(prefixedStoreKey(this.keyPrefix, pattern))) {
1046
+ result.add(callerKeyOf(this.keyPrefix, pattern, key));
1047
+ }
1048
+ const doubledPattern = doubledPrefixKey(this.keyPrefix, pattern);
1049
+ if (doubledPattern) {
1050
+ for (const key of await this.scan(doubledPattern)) result.add(key.slice(this.keyPrefix.length));
1051
+ }
1052
+ return [...result];
1053
+ }
1054
+ async scan(match) {
1055
+ const found = [];
1009
1056
  let cursor = "0";
1010
1057
  do {
1011
- const [nextCursor, keys] = await this.client.scan(cursor, "MATCH", searchPattern, "COUNT", 100);
1058
+ const [nextCursor, keys] = await this.client.scan(cursor, "MATCH", match, "COUNT", 100);
1012
1059
  cursor = nextCursor;
1013
- for (const key of keys) {
1014
- result.push(key.slice(this.keyPrefix.length));
1015
- }
1060
+ found.push(...keys);
1016
1061
  } while (cursor !== "0");
1017
- return result;
1062
+ return found;
1063
+ }
1064
+ /**
1065
+ * The stored text of an entry a release up to 1.9.1 wrote under the doubled key, or null. It is read
1066
+ * in place, not copied: the entry keeps its TTL, a rolled-back release still finds it, and a
1067
+ * concurrent `delete()` cannot be undone by a copy. The next write or delete of the key removes it.
1068
+ */
1069
+ async readDoubledPrefixValue(key) {
1070
+ const doubledKey = doubledPrefixKey(this.keyPrefix, key);
1071
+ return doubledKey ? this.client.get(doubledKey) : null;
1072
+ }
1073
+ /** Drops what releases up to 1.9.1 left under the doubled key, so it cannot come back once this key is gone. */
1074
+ async deleteDoubledPrefixKey(key) {
1075
+ const doubledKey = doubledPrefixKey(this.keyPrefix, key);
1076
+ if (doubledKey) await this.client.del(doubledKey);
1018
1077
  }
1019
1078
  /**
1020
1079
  * Gracefully close the Redis connection.
@@ -1037,15 +1096,13 @@ RememberRedisProvider = __decorateClass([
1037
1096
 
1038
1097
  // plugins/plugin-remember/src/providers/remember-vercel-kv.provider.ts
1039
1098
  import { Provider as Provider4, ProviderScope as ProviderScope4 } from "@frontmcp/sdk";
1040
- import { getEnv } from "@frontmcp/utils";
1099
+ import { createVercelKvClient } from "@frontmcp/utils";
1041
1100
  var RememberVercelKvProvider = class {
1042
- createClient;
1043
1101
  connection;
1044
1102
  client;
1045
1103
  keyPrefix;
1046
1104
  defaultTTL;
1047
1105
  constructor(options = {}) {
1048
- const vercelKv = __require("@vercel/kv");
1049
1106
  const hasUrl = options.url !== void 0;
1050
1107
  const hasToken = options.token !== void 0;
1051
1108
  if (hasUrl !== hasToken) {
@@ -1053,25 +1110,24 @@ var RememberVercelKvProvider = class {
1053
1110
  `RememberVercelKvProvider: Both 'url' and 'token' must be provided together, or neither. Received: url=${hasUrl ? "provided" : "missing"}, token=${hasToken ? "provided" : "missing"}`
1054
1111
  );
1055
1112
  }
1056
- this.createClient = vercelKv.createClient;
1057
1113
  this.connection = { url: options.url, token: options.token };
1058
1114
  this.keyPrefix = options.keyPrefix ?? "remember:";
1059
1115
  this.defaultTTL = options.defaultTTL;
1060
1116
  }
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
- }
1117
+ /**
1118
+ * The client, built on first use from the url and token (or KV_REST_API_URL / KV_REST_API_TOKEN)
1119
+ * by the shared loader, which a Cloudflare Worker can bundle (#711). Values are read back as
1120
+ * stored. A failed attempt is retried.
1121
+ */
1122
+ kv() {
1123
+ this.client ??= createVercelKvClient(this.connection).catch((error) => {
1124
+ this.client = void 0;
1125
+ throw error;
1126
+ });
1071
1127
  return this.client;
1072
1128
  }
1073
1129
  prefixKey(key) {
1074
- return `${this.keyPrefix}${key}`;
1130
+ return prefixedStoreKey(this.keyPrefix, key);
1075
1131
  }
1076
1132
  /**
1077
1133
  * Store a value with optional TTL.
@@ -1080,31 +1136,42 @@ var RememberVercelKvProvider = class {
1080
1136
  const fullKey = this.prefixKey(key);
1081
1137
  const strValue = JSON.stringify(value);
1082
1138
  const ttl = ttlSeconds ?? this.defaultTTL;
1139
+ const kv = await this.kv();
1083
1140
  if (ttl && ttl > 0) {
1084
- await this.kv.set(fullKey, strValue, { ex: ttl });
1141
+ await kv.set(fullKey, strValue, { ex: ttl });
1085
1142
  } else {
1086
- await this.kv.set(fullKey, strValue);
1143
+ await kv.set(fullKey, strValue);
1087
1144
  }
1145
+ await this.deleteDoubledPrefixKey(key);
1088
1146
  }
1089
1147
  /**
1090
1148
  * Store a value only if the key is absent, via the `nx` option.
1091
1149
  *
1092
1150
  * Resolves to `'OK'` when it created the key and `null` when the key already existed, so two
1093
- * callers racing cannot both win.
1151
+ * callers racing cannot both win. A key that releases up to 1.9.1 may hold under the doubled
1152
+ * prefix counts as present too: one script checks both keys and writes, so an entry still there
1153
+ * is never shadowed.
1094
1154
  */
1095
1155
  async setIfAbsent(key, value, ttlSeconds) {
1096
1156
  const fullKey = this.prefixKey(key);
1097
1157
  const strValue = JSON.stringify(value);
1098
1158
  const ttl = ttlSeconds ?? this.defaultTTL;
1099
- const result = ttl && ttl > 0 ? await this.kv.set(fullKey, strValue, { nx: true, ex: ttl }) : await this.kv.set(fullKey, strValue, { nx: true });
1159
+ const doubledKey = doubledPrefixKey(this.keyPrefix, key);
1160
+ const kv = await this.kv();
1161
+ if (doubledKey) {
1162
+ const ttlArgument = ttl && ttl > 0 ? String(ttl) : "";
1163
+ const created = await kv.eval(SET_IF_NEITHER_KEY_EXISTS_SCRIPT, [fullKey, doubledKey], [strValue, ttlArgument]);
1164
+ return Number(created) === 1;
1165
+ }
1166
+ const result = ttl && ttl > 0 ? await kv.set(fullKey, strValue, { nx: true, ex: ttl }) : await kv.set(fullKey, strValue, { nx: true });
1100
1167
  return result === "OK";
1101
1168
  }
1102
1169
  /**
1103
1170
  * Retrieve a value by key.
1104
1171
  */
1105
1172
  async getValue(key, defaultValue) {
1106
- const fullKey = this.prefixKey(key);
1107
- const raw = await this.kv.get(fullKey);
1173
+ const kv = await this.kv();
1174
+ const raw = await kv.get(this.prefixKey(key)) ?? await this.readDoubledPrefixValue(key);
1108
1175
  if (raw === null) return defaultValue;
1109
1176
  try {
1110
1177
  return JSON.parse(raw);
@@ -1116,46 +1183,70 @@ var RememberVercelKvProvider = class {
1116
1183
  * Delete a key.
1117
1184
  */
1118
1185
  async delete(key) {
1119
- const fullKey = this.prefixKey(key);
1120
- await this.kv.del(fullKey);
1186
+ const kv = await this.kv();
1187
+ await kv.del(this.prefixKey(key));
1188
+ await this.deleteDoubledPrefixKey(key);
1121
1189
  }
1122
1190
  /**
1123
1191
  * Check if a key exists.
1124
1192
  */
1125
1193
  async exists(key) {
1126
- const fullKey = this.prefixKey(key);
1127
- return await this.kv.exists(fullKey) === 1;
1194
+ const kv = await this.kv();
1195
+ if (await kv.exists(this.prefixKey(key)) === 1) return true;
1196
+ const doubledKey = doubledPrefixKey(this.keyPrefix, key);
1197
+ return doubledKey !== void 0 && await kv.exists(doubledKey) === 1;
1128
1198
  }
1129
1199
  /**
1130
1200
  * List keys matching a pattern.
1131
1201
  * Uses SCAN for efficient iteration.
1132
1202
  */
1133
- async keys(pattern) {
1134
- const searchPattern = this.prefixKey(pattern ?? "*");
1135
- const result = [];
1203
+ async keys(pattern = "*") {
1204
+ const result = /* @__PURE__ */ new Set();
1205
+ for (const key of await this.scan(this.prefixKey(pattern))) {
1206
+ result.add(callerKeyOf(this.keyPrefix, pattern, key));
1207
+ }
1208
+ const doubledPattern = doubledPrefixKey(this.keyPrefix, pattern);
1209
+ if (doubledPattern) {
1210
+ for (const key of await this.scan(doubledPattern)) result.add(key.slice(this.keyPrefix.length));
1211
+ }
1212
+ return [...result];
1213
+ }
1214
+ async scan(match) {
1215
+ const found = [];
1216
+ const kv = await this.kv();
1136
1217
  try {
1137
1218
  let cursor = 0;
1138
1219
  do {
1139
- const [nextCursor, keys] = await this.kv.scan(cursor, {
1140
- match: searchPattern,
1141
- count: 100
1142
- });
1220
+ const [nextCursor, keys] = await kv.scan(cursor, { match, count: 100 });
1143
1221
  cursor = nextCursor;
1144
- for (const key of keys) {
1145
- result.push(key.slice(this.keyPrefix.length));
1146
- }
1222
+ found.push(...keys);
1147
1223
  } while (String(cursor) !== "0");
1148
1224
  } catch {
1149
1225
  try {
1150
- const keys = await this.kv.keys(searchPattern);
1151
- for (const key of keys) {
1152
- result.push(key.slice(this.keyPrefix.length));
1153
- }
1226
+ found.push(...await kv.keys(match));
1154
1227
  } catch {
1155
1228
  console.warn("[RememberPlugin:VercelKV] keys() operation not supported");
1156
1229
  }
1157
1230
  }
1158
- return result;
1231
+ return found;
1232
+ }
1233
+ /**
1234
+ * The stored text of an entry a release up to 1.9.1 wrote under the doubled key, or null. It is read
1235
+ * in place, not copied: the entry keeps its TTL, a rolled-back release still finds it, and a
1236
+ * concurrent `delete()` cannot be undone by a copy. The next write or delete of the key removes it.
1237
+ */
1238
+ async readDoubledPrefixValue(key) {
1239
+ const doubledKey = doubledPrefixKey(this.keyPrefix, key);
1240
+ if (!doubledKey) return null;
1241
+ const kv = await this.kv();
1242
+ return kv.get(doubledKey);
1243
+ }
1244
+ /** Drops what releases up to 1.9.1 left under the doubled key, so it cannot come back once this key is gone. */
1245
+ async deleteDoubledPrefixKey(key) {
1246
+ const doubledKey = doubledPrefixKey(this.keyPrefix, key);
1247
+ if (!doubledKey) return;
1248
+ const kv = await this.kv();
1249
+ await kv.del(doubledKey);
1159
1250
  }
1160
1251
  /**
1161
1252
  * Gracefully close the provider.
@@ -1442,7 +1533,13 @@ function createRememberTools(prefix = "") {
1442
1533
  }
1443
1534
 
1444
1535
  // plugins/plugin-remember/src/remember.plugin.ts
1445
- function withCheckedDefaultTTL(options) {
1536
+ function withCheckedOptions(options) {
1537
+ const customKey = options.encryption?.customKey;
1538
+ if (customKey !== void 0 && customKey.trim() === "") {
1539
+ throw new RememberConfigurationError(
1540
+ "RememberPlugin encryption.customKey must not be empty; omit it to derive keys from the server secret"
1541
+ );
1542
+ }
1446
1543
  const { defaultTTL } = options;
1447
1544
  if (defaultTTL === void 0) return options;
1448
1545
  if (defaultTTL === 0) return { ...options, defaultTTL: void 0 };
@@ -1459,7 +1556,7 @@ var RememberPlugin = class extends DynamicPlugin {
1459
1556
  super();
1460
1557
  this.options = {
1461
1558
  ...RememberPlugin.defaultOptions,
1462
- ...withCheckedDefaultTTL(options)
1559
+ ...withCheckedOptions(options)
1463
1560
  };
1464
1561
  }
1465
1562
  };
@@ -1480,7 +1577,7 @@ __publicField(RememberPlugin, "dynamicProviders", (options) => {
1480
1577
  const providers = [];
1481
1578
  const config = {
1482
1579
  ...RememberPlugin.defaultOptions,
1483
- ...withCheckedDefaultTTL(options)
1580
+ ...withCheckedOptions(options)
1484
1581
  };
1485
1582
  switch (config.type) {
1486
1583
  case "global-store":
package/esm/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@frontmcp/plugin-remember",
3
- "version": "1.9.1",
3
+ "version": "1.9.3",
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.1",
53
- "@frontmcp/utils": "1.9.1",
52
+ "@frontmcp/sdk": "1.9.3",
53
+ "@frontmcp/utils": "1.9.3",
54
54
  "ioredis": "^5.8.0"
55
55
  },
56
56
  "peerDependencies": {
57
- "@frontmcp/lazy-zod": "1.9.1",
57
+ "@frontmcp/lazy-zod": "1.9.3",
58
58
  "@vercel/kv": "^2.0.0 || ^3.0.0"
59
59
  },
60
60
  "peerDependenciesMeta": {
package/index.js CHANGED
@@ -208,6 +208,9 @@ async function getBaseSecret() {
208
208
  }
209
209
  return getOrCreatePersistedSecret();
210
210
  }
211
+ async function secretFor(source) {
212
+ return source.secret ? source.secret : getBaseSecret();
213
+ }
211
214
  var textEncoder = new TextEncoder();
212
215
  async function deriveEncryptionKey(source) {
213
216
  const salt = textEncoder.encode("remember-plugin-v1");
@@ -215,19 +218,19 @@ async function deriveEncryptionKey(source) {
215
218
  let context;
216
219
  switch (source.type) {
217
220
  case "session":
218
- ikm = await getBaseSecret() + source.sessionId;
221
+ ikm = await secretFor(source) + source.sessionId;
219
222
  context = `remember:session:${source.sessionId}`;
220
223
  break;
221
224
  case "tool":
222
- ikm = await getBaseSecret() + source.sessionId;
225
+ ikm = await secretFor(source) + source.sessionId;
223
226
  context = `remember:tool:${source.toolName}:${source.sessionId}`;
224
227
  break;
225
228
  case "user":
226
- ikm = await getBaseSecret() + source.userId;
229
+ ikm = await secretFor(source) + source.userId;
227
230
  context = `remember:user:${source.userId}`;
228
231
  break;
229
232
  case "global":
230
- ikm = await getBaseSecret();
233
+ ikm = await secretFor(source);
231
234
  context = "remember:global";
232
235
  break;
233
236
  case "custom":
@@ -239,20 +242,21 @@ async function deriveEncryptionKey(source) {
239
242
  const info = textEncoder.encode(context);
240
243
  return (0, import_utils2.hkdfSha256)(ikmBytes, salt, info, 32);
241
244
  }
242
- function getKeySourceForScope(scope, context) {
245
+ function getKeySourceForScope(scope, context, secret) {
243
246
  switch (scope) {
244
247
  case "session":
245
- return { type: "session", sessionId: context.sessionId };
248
+ return { type: "session", sessionId: context.sessionId, secret };
246
249
  case "user":
247
- return { type: "user", userId: context.userId ?? "anonymous" };
250
+ return { type: "user", userId: context.userId ?? "anonymous", secret };
248
251
  case "tool":
249
252
  return {
250
253
  type: "tool",
251
254
  toolName: context.toolName ?? "unknown",
252
- sessionId: context.sessionId
255
+ sessionId: context.sessionId,
256
+ secret
253
257
  };
254
258
  case "global":
255
- return { type: "global" };
259
+ return { type: "global", secret };
256
260
  }
257
261
  }
258
262
  var textDecoder = new TextDecoder();
@@ -655,7 +659,7 @@ var RememberAccessor = class {
655
659
  * `'unknown'`.
656
660
  */
657
661
  get toolName() {
658
- return (0, import_sdk2.getRunningTool)()?.fullName ?? this.ctx.flow?.name ?? "unknown";
662
+ return (0, import_sdk2.getRunningTool)()?.fullName ?? "unknown";
659
663
  }
660
664
  /**
661
665
  * Build the scope-specific prefix.
@@ -689,11 +693,15 @@ var RememberAccessor = class {
689
693
  */
690
694
  getKeySource(scope) {
691
695
  const needsSessionIdentity = scope === "session" || scope === "tool";
692
- return getKeySourceForScope(scope, {
693
- sessionId: needsSessionIdentity ? this.resolveSessionIdentity() : this.ctx.sessionId,
694
- userId: this.userId,
695
- toolName: scope === "tool" ? this.toolName : void 0
696
- });
696
+ return getKeySourceForScope(
697
+ scope,
698
+ {
699
+ sessionId: needsSessionIdentity ? this.resolveSessionIdentity() : this.ctx.sessionId,
700
+ userId: this.userId,
701
+ toolName: scope === "tool" ? this.toolName : void 0
702
+ },
703
+ this.config.encryption?.customKey
704
+ );
697
705
  }
698
706
  /** The entry stored under `storageKey`, if readable and unexpired; an expired one is deleted. */
699
707
  async readEntry(storageKey, scope) {
@@ -905,10 +913,28 @@ RememberMemoryProvider = __decorateClass([
905
913
  // plugins/plugin-remember/src/providers/remember-redis.provider.ts
906
914
  var import_ioredis = __toESM(require("ioredis"));
907
915
  var import_sdk4 = require("@frontmcp/sdk");
916
+
917
+ // plugins/plugin-remember/src/providers/remember-key-prefix.ts
918
+ function prefixedStoreKey(keyPrefix, key) {
919
+ return keyPrefix && key.startsWith(keyPrefix) ? key : keyPrefix + key;
920
+ }
921
+ function doubledPrefixKey(keyPrefix, key) {
922
+ return keyPrefix && key.startsWith(keyPrefix) ? keyPrefix + key : void 0;
923
+ }
924
+ function callerKeyOf(keyPrefix, pattern, backendKey) {
925
+ return keyPrefix && pattern.startsWith(keyPrefix) ? backendKey : backendKey.slice(keyPrefix.length);
926
+ }
927
+ var SET_IF_NEITHER_KEY_EXISTS_SCRIPT = `
928
+ if redis.call('EXISTS', KEYS[1], KEYS[2]) > 0 then return 0 end
929
+ if ARGV[2] ~= '' then redis.call('SET', KEYS[1], ARGV[1], 'EX', ARGV[2]) else redis.call('SET', KEYS[1], ARGV[1]) end
930
+ return 1
931
+ `;
932
+
933
+ // plugins/plugin-remember/src/providers/remember-redis.provider.ts
908
934
  var RememberRedisProvider = class {
909
935
  client;
910
936
  /**
911
- * Prefix prepended to all Redis keys.
937
+ * Prefix prepended to Redis keys that don't already start with it.
912
938
  * Include any separator (e.g., "myapp:" or "user:123:") as part of the prefix.
913
939
  */
914
940
  keyPrefix;
@@ -962,7 +988,7 @@ var RememberRedisProvider = class {
962
988
  throw new Error(`Invalid TTL: must be an integer, got ${ttlSeconds}`);
963
989
  }
964
990
  }
965
- const fullKey = this.keyPrefix + key;
991
+ const fullKey = prefixedStoreKey(this.keyPrefix, key);
966
992
  const strValue = JSON.stringify(value);
967
993
  const ttl = ttlSeconds ?? this.defaultTTL;
968
994
  if (ttl !== void 0 && ttl > 0) {
@@ -970,18 +996,35 @@ var RememberRedisProvider = class {
970
996
  } else {
971
997
  await this.client.set(fullKey, strValue);
972
998
  }
999
+ await this.deleteDoubledPrefixKey(key);
973
1000
  }
974
1001
  /**
975
1002
  * Store a value only if the key is absent, via Redis `SET ... NX`.
976
1003
  *
977
1004
  * `set` resolves to `'OK'` when it created the key and `null` when the key already existed,
978
1005
  * so the whole check-and-write is one round trip and two callers racing cannot both win.
1006
+ * A key that releases up to 1.9.1 may hold under the doubled prefix counts as present too: one
1007
+ * script checks both keys and writes, so an entry still there is never shadowed.
979
1008
  */
980
1009
  async setIfAbsent(key, value, ttlSeconds) {
981
- const fullKey = this.keyPrefix + key;
1010
+ const fullKey = prefixedStoreKey(this.keyPrefix, key);
982
1011
  const strValue = JSON.stringify(value);
983
1012
  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");
1013
+ const hasTtl = ttl !== void 0 && ttl > 0;
1014
+ const doubledKey = doubledPrefixKey(this.keyPrefix, key);
1015
+ if (doubledKey) {
1016
+ const ttlArgument = hasTtl ? String(ttl) : "";
1017
+ const created = await this.client.eval(
1018
+ SET_IF_NEITHER_KEY_EXISTS_SCRIPT,
1019
+ 2,
1020
+ fullKey,
1021
+ doubledKey,
1022
+ strValue,
1023
+ ttlArgument
1024
+ );
1025
+ return created === 1;
1026
+ }
1027
+ const result = hasTtl ? await this.client.set(fullKey, strValue, "EX", ttl, "NX") : await this.client.set(fullKey, strValue, "NX");
985
1028
  return result === "OK";
986
1029
  }
987
1030
  /**
@@ -996,8 +1039,7 @@ var RememberRedisProvider = class {
996
1039
  * @returns The parsed value as T, or defaultValue/undefined
997
1040
  */
998
1041
  async getValue(key, defaultValue) {
999
- const fullKey = this.keyPrefix + key;
1000
- const raw = await this.client.get(fullKey);
1042
+ const raw = await this.client.get(prefixedStoreKey(this.keyPrefix, key)) ?? await this.readDoubledPrefixValue(key);
1001
1043
  if (raw === null) return defaultValue;
1002
1044
  try {
1003
1045
  return JSON.parse(raw);
@@ -1009,32 +1051,55 @@ var RememberRedisProvider = class {
1009
1051
  * Delete a key.
1010
1052
  */
1011
1053
  async delete(key) {
1012
- const fullKey = this.keyPrefix + key;
1013
- await this.client.del(fullKey);
1054
+ await this.client.del(prefixedStoreKey(this.keyPrefix, key));
1055
+ await this.deleteDoubledPrefixKey(key);
1014
1056
  }
1015
1057
  /**
1016
1058
  * Check if a key exists.
1017
1059
  */
1018
1060
  async exists(key) {
1019
- const fullKey = this.keyPrefix + key;
1020
- return await this.client.exists(fullKey) === 1;
1061
+ if (await this.client.exists(prefixedStoreKey(this.keyPrefix, key)) === 1) return true;
1062
+ const doubledKey = doubledPrefixKey(this.keyPrefix, key);
1063
+ return doubledKey !== void 0 && await this.client.exists(doubledKey) === 1;
1021
1064
  }
1022
1065
  /**
1023
1066
  * List keys matching a pattern.
1024
1067
  * Uses Redis SCAN for efficient iteration.
1025
1068
  */
1026
- async keys(pattern) {
1027
- const searchPattern = this.keyPrefix + (pattern ?? "*");
1028
- const result = [];
1069
+ async keys(pattern = "*") {
1070
+ const result = /* @__PURE__ */ new Set();
1071
+ for (const key of await this.scan(prefixedStoreKey(this.keyPrefix, pattern))) {
1072
+ result.add(callerKeyOf(this.keyPrefix, pattern, key));
1073
+ }
1074
+ const doubledPattern = doubledPrefixKey(this.keyPrefix, pattern);
1075
+ if (doubledPattern) {
1076
+ for (const key of await this.scan(doubledPattern)) result.add(key.slice(this.keyPrefix.length));
1077
+ }
1078
+ return [...result];
1079
+ }
1080
+ async scan(match) {
1081
+ const found = [];
1029
1082
  let cursor = "0";
1030
1083
  do {
1031
- const [nextCursor, keys] = await this.client.scan(cursor, "MATCH", searchPattern, "COUNT", 100);
1084
+ const [nextCursor, keys] = await this.client.scan(cursor, "MATCH", match, "COUNT", 100);
1032
1085
  cursor = nextCursor;
1033
- for (const key of keys) {
1034
- result.push(key.slice(this.keyPrefix.length));
1035
- }
1086
+ found.push(...keys);
1036
1087
  } while (cursor !== "0");
1037
- return result;
1088
+ return found;
1089
+ }
1090
+ /**
1091
+ * The stored text of an entry a release up to 1.9.1 wrote under the doubled key, or null. It is read
1092
+ * in place, not copied: the entry keeps its TTL, a rolled-back release still finds it, and a
1093
+ * concurrent `delete()` cannot be undone by a copy. The next write or delete of the key removes it.
1094
+ */
1095
+ async readDoubledPrefixValue(key) {
1096
+ const doubledKey = doubledPrefixKey(this.keyPrefix, key);
1097
+ return doubledKey ? this.client.get(doubledKey) : null;
1098
+ }
1099
+ /** Drops what releases up to 1.9.1 left under the doubled key, so it cannot come back once this key is gone. */
1100
+ async deleteDoubledPrefixKey(key) {
1101
+ const doubledKey = doubledPrefixKey(this.keyPrefix, key);
1102
+ if (doubledKey) await this.client.del(doubledKey);
1038
1103
  }
1039
1104
  /**
1040
1105
  * Gracefully close the Redis connection.
@@ -1059,13 +1124,11 @@ RememberRedisProvider = __decorateClass([
1059
1124
  var import_sdk5 = require("@frontmcp/sdk");
1060
1125
  var import_utils3 = require("@frontmcp/utils");
1061
1126
  var RememberVercelKvProvider = class {
1062
- createClient;
1063
1127
  connection;
1064
1128
  client;
1065
1129
  keyPrefix;
1066
1130
  defaultTTL;
1067
1131
  constructor(options = {}) {
1068
- const vercelKv = require("@vercel/kv");
1069
1132
  const hasUrl = options.url !== void 0;
1070
1133
  const hasToken = options.token !== void 0;
1071
1134
  if (hasUrl !== hasToken) {
@@ -1073,25 +1136,24 @@ var RememberVercelKvProvider = class {
1073
1136
  `RememberVercelKvProvider: Both 'url' and 'token' must be provided together, or neither. Received: url=${hasUrl ? "provided" : "missing"}, token=${hasToken ? "provided" : "missing"}`
1074
1137
  );
1075
1138
  }
1076
- this.createClient = vercelKv.createClient;
1077
1139
  this.connection = { url: options.url, token: options.token };
1078
1140
  this.keyPrefix = options.keyPrefix ?? "remember:";
1079
1141
  this.defaultTTL = options.defaultTTL;
1080
1142
  }
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
- }
1143
+ /**
1144
+ * The client, built on first use from the url and token (or KV_REST_API_URL / KV_REST_API_TOKEN)
1145
+ * by the shared loader, which a Cloudflare Worker can bundle (#711). Values are read back as
1146
+ * stored. A failed attempt is retried.
1147
+ */
1148
+ kv() {
1149
+ this.client ??= (0, import_utils3.createVercelKvClient)(this.connection).catch((error) => {
1150
+ this.client = void 0;
1151
+ throw error;
1152
+ });
1091
1153
  return this.client;
1092
1154
  }
1093
1155
  prefixKey(key) {
1094
- return `${this.keyPrefix}${key}`;
1156
+ return prefixedStoreKey(this.keyPrefix, key);
1095
1157
  }
1096
1158
  /**
1097
1159
  * Store a value with optional TTL.
@@ -1100,31 +1162,42 @@ var RememberVercelKvProvider = class {
1100
1162
  const fullKey = this.prefixKey(key);
1101
1163
  const strValue = JSON.stringify(value);
1102
1164
  const ttl = ttlSeconds ?? this.defaultTTL;
1165
+ const kv = await this.kv();
1103
1166
  if (ttl && ttl > 0) {
1104
- await this.kv.set(fullKey, strValue, { ex: ttl });
1167
+ await kv.set(fullKey, strValue, { ex: ttl });
1105
1168
  } else {
1106
- await this.kv.set(fullKey, strValue);
1169
+ await kv.set(fullKey, strValue);
1107
1170
  }
1171
+ await this.deleteDoubledPrefixKey(key);
1108
1172
  }
1109
1173
  /**
1110
1174
  * Store a value only if the key is absent, via the `nx` option.
1111
1175
  *
1112
1176
  * Resolves to `'OK'` when it created the key and `null` when the key already existed, so two
1113
- * callers racing cannot both win.
1177
+ * callers racing cannot both win. A key that releases up to 1.9.1 may hold under the doubled
1178
+ * prefix counts as present too: one script checks both keys and writes, so an entry still there
1179
+ * is never shadowed.
1114
1180
  */
1115
1181
  async setIfAbsent(key, value, ttlSeconds) {
1116
1182
  const fullKey = this.prefixKey(key);
1117
1183
  const strValue = JSON.stringify(value);
1118
1184
  const ttl = ttlSeconds ?? this.defaultTTL;
1119
- const result = ttl && ttl > 0 ? await this.kv.set(fullKey, strValue, { nx: true, ex: ttl }) : await this.kv.set(fullKey, strValue, { nx: true });
1185
+ const doubledKey = doubledPrefixKey(this.keyPrefix, key);
1186
+ const kv = await this.kv();
1187
+ if (doubledKey) {
1188
+ const ttlArgument = ttl && ttl > 0 ? String(ttl) : "";
1189
+ const created = await kv.eval(SET_IF_NEITHER_KEY_EXISTS_SCRIPT, [fullKey, doubledKey], [strValue, ttlArgument]);
1190
+ return Number(created) === 1;
1191
+ }
1192
+ const result = ttl && ttl > 0 ? await kv.set(fullKey, strValue, { nx: true, ex: ttl }) : await kv.set(fullKey, strValue, { nx: true });
1120
1193
  return result === "OK";
1121
1194
  }
1122
1195
  /**
1123
1196
  * Retrieve a value by key.
1124
1197
  */
1125
1198
  async getValue(key, defaultValue) {
1126
- const fullKey = this.prefixKey(key);
1127
- const raw = await this.kv.get(fullKey);
1199
+ const kv = await this.kv();
1200
+ const raw = await kv.get(this.prefixKey(key)) ?? await this.readDoubledPrefixValue(key);
1128
1201
  if (raw === null) return defaultValue;
1129
1202
  try {
1130
1203
  return JSON.parse(raw);
@@ -1136,46 +1209,70 @@ var RememberVercelKvProvider = class {
1136
1209
  * Delete a key.
1137
1210
  */
1138
1211
  async delete(key) {
1139
- const fullKey = this.prefixKey(key);
1140
- await this.kv.del(fullKey);
1212
+ const kv = await this.kv();
1213
+ await kv.del(this.prefixKey(key));
1214
+ await this.deleteDoubledPrefixKey(key);
1141
1215
  }
1142
1216
  /**
1143
1217
  * Check if a key exists.
1144
1218
  */
1145
1219
  async exists(key) {
1146
- const fullKey = this.prefixKey(key);
1147
- return await this.kv.exists(fullKey) === 1;
1220
+ const kv = await this.kv();
1221
+ if (await kv.exists(this.prefixKey(key)) === 1) return true;
1222
+ const doubledKey = doubledPrefixKey(this.keyPrefix, key);
1223
+ return doubledKey !== void 0 && await kv.exists(doubledKey) === 1;
1148
1224
  }
1149
1225
  /**
1150
1226
  * List keys matching a pattern.
1151
1227
  * Uses SCAN for efficient iteration.
1152
1228
  */
1153
- async keys(pattern) {
1154
- const searchPattern = this.prefixKey(pattern ?? "*");
1155
- const result = [];
1229
+ async keys(pattern = "*") {
1230
+ const result = /* @__PURE__ */ new Set();
1231
+ for (const key of await this.scan(this.prefixKey(pattern))) {
1232
+ result.add(callerKeyOf(this.keyPrefix, pattern, key));
1233
+ }
1234
+ const doubledPattern = doubledPrefixKey(this.keyPrefix, pattern);
1235
+ if (doubledPattern) {
1236
+ for (const key of await this.scan(doubledPattern)) result.add(key.slice(this.keyPrefix.length));
1237
+ }
1238
+ return [...result];
1239
+ }
1240
+ async scan(match) {
1241
+ const found = [];
1242
+ const kv = await this.kv();
1156
1243
  try {
1157
1244
  let cursor = 0;
1158
1245
  do {
1159
- const [nextCursor, keys] = await this.kv.scan(cursor, {
1160
- match: searchPattern,
1161
- count: 100
1162
- });
1246
+ const [nextCursor, keys] = await kv.scan(cursor, { match, count: 100 });
1163
1247
  cursor = nextCursor;
1164
- for (const key of keys) {
1165
- result.push(key.slice(this.keyPrefix.length));
1166
- }
1248
+ found.push(...keys);
1167
1249
  } while (String(cursor) !== "0");
1168
1250
  } catch {
1169
1251
  try {
1170
- const keys = await this.kv.keys(searchPattern);
1171
- for (const key of keys) {
1172
- result.push(key.slice(this.keyPrefix.length));
1173
- }
1252
+ found.push(...await kv.keys(match));
1174
1253
  } catch {
1175
1254
  console.warn("[RememberPlugin:VercelKV] keys() operation not supported");
1176
1255
  }
1177
1256
  }
1178
- return result;
1257
+ return found;
1258
+ }
1259
+ /**
1260
+ * The stored text of an entry a release up to 1.9.1 wrote under the doubled key, or null. It is read
1261
+ * in place, not copied: the entry keeps its TTL, a rolled-back release still finds it, and a
1262
+ * concurrent `delete()` cannot be undone by a copy. The next write or delete of the key removes it.
1263
+ */
1264
+ async readDoubledPrefixValue(key) {
1265
+ const doubledKey = doubledPrefixKey(this.keyPrefix, key);
1266
+ if (!doubledKey) return null;
1267
+ const kv = await this.kv();
1268
+ return kv.get(doubledKey);
1269
+ }
1270
+ /** Drops what releases up to 1.9.1 left under the doubled key, so it cannot come back once this key is gone. */
1271
+ async deleteDoubledPrefixKey(key) {
1272
+ const doubledKey = doubledPrefixKey(this.keyPrefix, key);
1273
+ if (!doubledKey) return;
1274
+ const kv = await this.kv();
1275
+ await kv.del(doubledKey);
1179
1276
  }
1180
1277
  /**
1181
1278
  * Gracefully close the provider.
@@ -1462,7 +1559,13 @@ function createRememberTools(prefix = "") {
1462
1559
  }
1463
1560
 
1464
1561
  // plugins/plugin-remember/src/remember.plugin.ts
1465
- function withCheckedDefaultTTL(options) {
1562
+ function withCheckedOptions(options) {
1563
+ const customKey = options.encryption?.customKey;
1564
+ if (customKey !== void 0 && customKey.trim() === "") {
1565
+ throw new RememberConfigurationError(
1566
+ "RememberPlugin encryption.customKey must not be empty; omit it to derive keys from the server secret"
1567
+ );
1568
+ }
1466
1569
  const { defaultTTL } = options;
1467
1570
  if (defaultTTL === void 0) return options;
1468
1571
  if (defaultTTL === 0) return { ...options, defaultTTL: void 0 };
@@ -1479,7 +1582,7 @@ var RememberPlugin = class extends import_sdk11.DynamicPlugin {
1479
1582
  super();
1480
1583
  this.options = {
1481
1584
  ...RememberPlugin.defaultOptions,
1482
- ...withCheckedDefaultTTL(options)
1585
+ ...withCheckedOptions(options)
1483
1586
  };
1484
1587
  }
1485
1588
  };
@@ -1500,7 +1603,7 @@ __publicField(RememberPlugin, "dynamicProviders", (options) => {
1500
1603
  const providers = [];
1501
1604
  const config = {
1502
1605
  ...RememberPlugin.defaultOptions,
1503
- ...withCheckedDefaultTTL(options)
1606
+ ...withCheckedOptions(options)
1504
1607
  };
1505
1608
  switch (config.type) {
1506
1609
  case "global-store":
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@frontmcp/plugin-remember",
3
- "version": "1.9.1",
3
+ "version": "1.9.3",
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.1",
53
- "@frontmcp/utils": "1.9.1",
52
+ "@frontmcp/sdk": "1.9.3",
53
+ "@frontmcp/utils": "1.9.3",
54
54
  "ioredis": "^5.8.0"
55
55
  },
56
56
  "peerDependencies": {
57
- "@frontmcp/lazy-zod": "1.9.1",
57
+ "@frontmcp/lazy-zod": "1.9.3",
58
58
  "@vercel/kv": "^2.0.0 || ^3.0.0"
59
59
  },
60
60
  "peerDependenciesMeta": {
@@ -1 +1 @@
1
- {"version":3,"file":"remember-accessor.provider.d.ts","sourceRoot":"","sources":["../../src/providers/remember-accessor.provider.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"remember-accessor.provider.d.ts","sourceRoot":"","sources":["../../src/providers/remember-accessor.provider.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Key prefixing for the stores that take a `keyPrefix` (Redis, Vercel KV).
3
+ *
4
+ * The Remember accessor hands a store keys that already start with the plugin's `keyPrefix`
5
+ * (`remember:v2:user:…`), and the plugin gives the store the same prefix. Up to 1.9.1 the store
6
+ * added it again, so entries lived under `remember:remember:v2:user:…` (#767). A key that already
7
+ * carries the prefix is now stored as is, and the doubled key is where such an entry may still be.
8
+ */
9
+ /** The backend key for a store key. */
10
+ export declare function prefixedStoreKey(keyPrefix: string, key: string): string;
11
+ /** Where releases up to 1.9.1 stored a key that carries the prefix: with the prefix twice. */
12
+ export declare function doubledPrefixKey(keyPrefix: string, key: string): string | undefined;
13
+ /** A backend key found by `keys(pattern)`, as the caller names it. */
14
+ export declare function callerKeyOf(keyPrefix: string, pattern: string, backendKey: string): string;
15
+ /**
16
+ * Sets KEYS[1] to ARGV[1], with ARGV[2] seconds of TTL when it is not empty, unless KEYS[1] or KEYS[2]
17
+ * exists. Run as one script, a value still under the doubled key keeps a conditional write out.
18
+ */
19
+ export declare const SET_IF_NEITHER_KEY_EXISTS_SCRIPT = "\nif redis.call('EXISTS', KEYS[1], KEYS[2]) > 0 then return 0 end\nif ARGV[2] ~= '' then redis.call('SET', KEYS[1], ARGV[1], 'EX', ARGV[2]) else redis.call('SET', KEYS[1], ARGV[1]) end\nreturn 1\n";
20
+ //# sourceMappingURL=remember-key-prefix.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"remember-key-prefix.d.ts","sourceRoot":"","sources":["../../src/providers/remember-key-prefix.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,uCAAuC;AACvC,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAEvE;AAED,8FAA8F;AAC9F,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAEnF;AAED,sEAAsE;AACtE,wBAAgB,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAE1F;AAED;;;GAGG;AACH,eAAO,MAAM,gCAAgC,yMAI5C,CAAC"}
@@ -11,7 +11,7 @@ export type RedisRememberOptions = RedisRememberPluginOptions | RedisClientRemem
11
11
  export default class RememberRedisProvider implements RememberStoreInterface {
12
12
  private readonly client;
13
13
  /**
14
- * Prefix prepended to all Redis keys.
14
+ * Prefix prepended to Redis keys that don't already start with it.
15
15
  * Include any separator (e.g., "myapp:" or "user:123:") as part of the prefix.
16
16
  */
17
17
  private readonly keyPrefix;
@@ -34,6 +34,8 @@ export default class RememberRedisProvider implements RememberStoreInterface {
34
34
  *
35
35
  * `set` resolves to `'OK'` when it created the key and `null` when the key already existed,
36
36
  * so the whole check-and-write is one round trip and two callers racing cannot both win.
37
+ * A key that releases up to 1.9.1 may hold under the doubled prefix counts as present too: one
38
+ * script checks both keys and writes, so an entry still there is never shadowed.
37
39
  */
38
40
  setIfAbsent(key: string, value: unknown, ttlSeconds?: number): Promise<boolean>;
39
41
  /**
@@ -61,6 +63,15 @@ export default class RememberRedisProvider implements RememberStoreInterface {
61
63
  * Uses Redis SCAN for efficient iteration.
62
64
  */
63
65
  keys(pattern?: string): Promise<string[]>;
66
+ private scan;
67
+ /**
68
+ * The stored text of an entry a release up to 1.9.1 wrote under the doubled key, or null. It is read
69
+ * in place, not copied: the entry keeps its TTL, a rolled-back release still finds it, and a
70
+ * concurrent `delete()` cannot be undone by a copy. The next write or delete of the key removes it.
71
+ */
72
+ private readDoubledPrefixValue;
73
+ /** Drops what releases up to 1.9.1 left under the doubled key, so it cannot come back once this key is gone. */
74
+ private deleteDoubledPrefixKey;
64
75
  /**
65
76
  * Gracefully close the Redis connection.
66
77
  * Only closes if this provider owns the client (created it internally).
@@ -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,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
+ {"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;AAOtG,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;IA+B/E;;;;;;;OAOG;IACG,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IA2BrF;;;;;;;;;;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;IAM3C;;;OAGG;IACG,IAAI,CAAC,OAAO,SAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;YAY9B,IAAI;IAWlB;;;;OAIG;YACW,sBAAsB;IAKpC,gHAAgH;YAClG,sBAAsB;IAKpC;;;;OAIG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAK7B"}
@@ -17,14 +17,17 @@ export interface RememberVercelKvProviderOptions {
17
17
  * Provides serverless-compatible, edge-ready storage.
18
18
  */
19
19
  export default class RememberVercelKvProvider implements RememberStoreInterface {
20
- private readonly createClient;
21
20
  private readonly connection;
22
21
  private client?;
23
22
  private readonly keyPrefix;
24
23
  private readonly defaultTTL?;
25
24
  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();
25
+ /**
26
+ * The client, built on first use from the url and token (or KV_REST_API_URL / KV_REST_API_TOKEN)
27
+ * by the shared loader, which a Cloudflare Worker can bundle (#711). Values are read back as
28
+ * stored. A failed attempt is retried.
29
+ */
30
+ private kv;
28
31
  private prefixKey;
29
32
  /**
30
33
  * Store a value with optional TTL.
@@ -34,7 +37,9 @@ export default class RememberVercelKvProvider implements RememberStoreInterface
34
37
  * Store a value only if the key is absent, via the `nx` option.
35
38
  *
36
39
  * Resolves to `'OK'` when it created the key and `null` when the key already existed, so two
37
- * callers racing cannot both win.
40
+ * callers racing cannot both win. A key that releases up to 1.9.1 may hold under the doubled
41
+ * prefix counts as present too: one script checks both keys and writes, so an entry still there
42
+ * is never shadowed.
38
43
  */
39
44
  setIfAbsent(key: string, value: unknown, ttlSeconds?: number): Promise<boolean>;
40
45
  /**
@@ -54,6 +59,15 @@ export default class RememberVercelKvProvider implements RememberStoreInterface
54
59
  * Uses SCAN for efficient iteration.
55
60
  */
56
61
  keys(pattern?: string): Promise<string[]>;
62
+ private scan;
63
+ /**
64
+ * The stored text of an entry a release up to 1.9.1 wrote under the doubled key, or null. It is read
65
+ * in place, not copied: the entry keeps its TTL, a rolled-back release still finds it, and a
66
+ * concurrent `delete()` cannot be undone by a copy. The next write or delete of the key removes it.
67
+ */
68
+ private readDoubledPrefixValue;
69
+ /** Drops what releases up to 1.9.1 left under the doubled key, so it cannot come back once this key is gone. */
70
+ private deleteDoubledPrefixKey;
57
71
  /**
58
72
  * Gracefully close the provider.
59
73
  * No-op for Vercel KV as it uses stateless REST API.
@@ -1 +1 @@
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"}
1
+ {"version":3,"file":"remember-vercel-kv.provider.d.ts","sourceRoot":"","sources":["../../src/providers/remember-vercel-kv.provider.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AAgBzE;;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,UAAU,CAAqB;IAChD,OAAO,CAAC,MAAM,CAAC,CAA0B;IACzC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAS;gBAEzB,OAAO,GAAE,+BAAoC;IAgBzD;;;;OAIG;IACH,OAAO,CAAC,EAAE;IAQV,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;IAc/E;;;;;;;OAOG;IACG,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAqBrF;;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;IAMxC;;OAEG;IACG,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAO3C;;;OAGG;IACG,IAAI,CAAC,OAAO,SAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;YAY9B,IAAI;IAuBlB;;;;OAIG;YACW,sBAAsB;IAOpC,gHAAgH;YAClG,sBAAsB;IAOpC;;;OAGG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAG7B"}
@@ -8,7 +8,14 @@ export type EncryptedBlob = EncBlob;
8
8
  /**
9
9
  * Key derivation source configuration.
10
10
  */
11
- export type EncryptionKeySource = {
11
+ export type EncryptionKeySource = (ScopeKeySource & {
12
+ /** The secret keys are derived from, in place of the server secret (`encryption.customKey`). */
13
+ secret?: string;
14
+ }) | {
15
+ type: 'custom';
16
+ key: string;
17
+ };
18
+ type ScopeKeySource = {
12
19
  type: 'session';
13
20
  sessionId: string;
14
21
  } | {
@@ -20,9 +27,6 @@ export type EncryptionKeySource = {
20
27
  sessionId: string;
21
28
  } | {
22
29
  type: 'global';
23
- } | {
24
- type: 'custom';
25
- key: string;
26
30
  };
27
31
  /**
28
32
  * Derive a 256-bit encryption key based on the source.
@@ -54,7 +58,7 @@ export declare function getKeySourceForScope(scope: RememberScope, context: {
54
58
  sessionId: string;
55
59
  userId?: string;
56
60
  toolName?: string;
57
- }): EncryptionKeySource;
61
+ }, secret?: string): EncryptionKeySource;
58
62
  /**
59
63
  * Encrypt a value using AES-256-GCM.
60
64
  * Uses @frontmcp/utils crypto for cross-platform support.
@@ -89,4 +93,5 @@ export declare function encryptAndSerialize(data: unknown, keySource: Encryption
89
93
  * Convenience function to deserialize and decrypt in one step.
90
94
  */
91
95
  export declare function deserializeAndDecrypt<T = unknown>(str: string, keySource: EncryptionKeySource): Promise<T | null>;
96
+ export {};
92
97
  //# sourceMappingURL=remember.crypto.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"remember.crypto.d.ts","sourceRoot":"","sources":["../src/remember.crypto.ts"],"names":[],"mappings":"AAAA,OAAO,EAOL,KAAK,OAAO,EACb,MAAM,iBAAiB,CAAC;AAGzB,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAMtD;;;GAGG;AACH,MAAM,MAAM,aAAa,GAAG,OAAO,CAAC;AAEpC;;GAEG;AACH,MAAM,MAAM,mBAAmB,GAC3B;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GACtC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAChC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GACrD;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,GAClB;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAAC;AA4BpC;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAsB,mBAAmB,CAAC,MAAM,EAAE,mBAAmB,GAAG,OAAO,CAAC,UAAU,CAAC,CAwC1F;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,aAAa,EACpB,OAAO,EAAE;IACP,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,GACA,mBAAmB,CAerB;AASD;;;;;;;GAOG;AACH,wBAAsB,YAAY,CAAC,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,mBAAmB,GAAG,OAAO,CAAC,aAAa,CAAC,CAaxG;AAED;;;;;;;GAOG;AACH,wBAAsB,YAAY,CAAC,CAAC,GAAG,OAAO,EAC5C,IAAI,EAAE,aAAa,EACnB,SAAS,EAAE,mBAAmB,GAC7B,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,CAmBnB;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,aAAa,GAAG,MAAM,CAEzD;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI,CAiBjE;AAED;;GAEG;AACH,wBAAsB,mBAAmB,CAAC,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,mBAAmB,GAAG,OAAO,CAAC,MAAM,CAAC,CAGxG;AAED;;GAEG;AACH,wBAAsB,qBAAqB,CAAC,CAAC,GAAG,OAAO,EACrD,GAAG,EAAE,MAAM,EACX,SAAS,EAAE,mBAAmB,GAC7B,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,CAInB"}
1
+ {"version":3,"file":"remember.crypto.d.ts","sourceRoot":"","sources":["../src/remember.crypto.ts"],"names":[],"mappings":"AAAA,OAAO,EAOL,KAAK,OAAO,EACb,MAAM,iBAAiB,CAAC;AAGzB,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAMtD;;;GAGG;AACH,MAAM,MAAM,aAAa,GAAG,OAAO,CAAC;AAEpC;;GAEG;AACH,MAAM,MAAM,mBAAmB,GAC3B,CAAC,cAAc,GAAG;IAChB,gGAAgG;IAChG,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC,GACF;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAAC;AAEpC,KAAK,cAAc,GACf;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GACtC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAChC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GACrD;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,CAAC;AAiCvB;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAsB,mBAAmB,CAAC,MAAM,EAAE,mBAAmB,GAAG,OAAO,CAAC,UAAU,CAAC,CAwC1F;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,aAAa,EACpB,OAAO,EAAE;IACP,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,EACD,MAAM,CAAC,EAAE,MAAM,GACd,mBAAmB,CAgBrB;AASD;;;;;;;GAOG;AACH,wBAAsB,YAAY,CAAC,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,mBAAmB,GAAG,OAAO,CAAC,aAAa,CAAC,CAaxG;AAED;;;;;;;GAOG;AACH,wBAAsB,YAAY,CAAC,CAAC,GAAG,OAAO,EAC5C,IAAI,EAAE,aAAa,EACnB,SAAS,EAAE,mBAAmB,GAC7B,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,CAmBnB;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,aAAa,GAAG,MAAM,CAEzD;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI,CAiBjE;AAED;;GAEG;AACH,wBAAsB,mBAAmB,CAAC,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,mBAAmB,GAAG,OAAO,CAAC,MAAM,CAAC,CAGxG;AAED;;GAEG;AACH,wBAAsB,qBAAqB,CAAC,CAAC,GAAG,OAAO,EACrD,GAAG,EAAE,MAAM,EACX,SAAS,EAAE,mBAAmB,GAC7B,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,CAInB"}
@@ -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;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
+ {"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;AAyB1F;;;;;;;;;;;;;;;;;;;;;;;;;;;;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"}
@@ -116,7 +116,10 @@ export interface BaseRememberPluginOptions {
116
116
  encryption?: {
117
117
  /** Whether encryption is enabled (default: true) */
118
118
  enabled?: boolean;
119
- /** Custom encryption key (overrides derived keys) */
119
+ /**
120
+ * Secret every encryption key is derived from, in place of `REMEMBER_SECRET` (or `MCP_MEMORY_SECRET` /
121
+ * `MCP_SESSION_SECRET`). Each scope, session and user still gets its own key.
122
+ */
120
123
  customKey?: string;
121
124
  };
122
125
  /** LLM tools configuration */
@@ -1 +1 @@
1
- {"version":3,"file":"remember.types.d.ts","sourceRoot":"","sources":["../src/remember.types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"remember.types.d.ts","sourceRoot":"","sources":["../src/remember.types.ts"],"names":[],"mappings":"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"}