@frontmcp/utils 1.8.6 → 1.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/env/browser-env.d.ts +1 -0
- package/env/browser-env.js +5 -0
- package/env/browser-runtime-context.d.ts +2 -1
- package/env/browser-runtime-context.js +104 -0
- package/env/index.d.ts +1 -1
- package/env/node-env.d.ts +11 -0
- package/env/node-env.js +8 -2
- package/env/runtime-context.d.ts +12 -5
- package/env/runtime-context.js +192 -0
- package/esm/async-context/browser-async-context.mjs +3 -2
- package/esm/async-context/node-async-context.mjs +3 -2
- package/esm/crypto/browser.mjs +3 -2
- package/esm/crypto/node.mjs +3 -2
- package/esm/env/browser-env.mjs +7 -2
- package/esm/env/browser-runtime-context.mjs +77 -0
- package/esm/env/node-env.mjs +10 -4
- package/esm/env/runtime-context.mjs +172 -0
- package/esm/event-emitter/browser-event-emitter.mjs +3 -2
- package/esm/event-emitter/node-event-emitter.mjs +3 -2
- package/esm/index.mjs +251 -250
- package/esm/path/browser-path.mjs +50 -0
- package/esm/path/node-path.mjs +16 -0
- package/index.d.ts +3 -3
- package/index.js +261 -274
- package/package.json +26 -8
- package/path/browser-path.js +79 -0
- package/path/node-path.js +45 -0
- package/storage/adapters/base.d.ts +6 -1
- package/storage/adapters/cloudflare-kv.d.ts +1 -0
- package/storage/adapters/index.d.ts +2 -1
- package/storage/adapters/memory.d.ts +2 -1
- package/storage/adapters/redis.d.ts +19 -0
- package/storage/adapters/upstash.d.ts +2 -1
- package/storage/adapters/vercel-kv.d.ts +2 -1
- package/storage/index.d.ts +4 -2
- package/storage/namespace.d.ts +2 -1
- package/storage/redis-error-listener.d.ts +27 -0
- package/storage/types.d.ts +11 -0
- package/storage/utils/compare-and-delete.d.ts +2 -0
package/esm/index.mjs
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
const require =
|
|
1
|
+
var __frontmcpModule = typeof process !== "undefined" && typeof process.getBuiltinModule === "function" ? process.getBuiltinModule("module") : undefined;
|
|
2
|
+
const require = __frontmcpModule ? __frontmcpModule.createRequire(import.meta.url || 'file:///') : undefined;
|
|
3
|
+
// __frontmcpCreateRequire
|
|
3
4
|
var __defProp = Object.defineProperty;
|
|
4
5
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
6
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
@@ -594,9 +595,9 @@ function createSecretData(options) {
|
|
|
594
595
|
}
|
|
595
596
|
async function getOrCreateSecret(options) {
|
|
596
597
|
const cacheKey = resolveSecretPath(options);
|
|
597
|
-
const
|
|
598
|
-
if (
|
|
599
|
-
return
|
|
598
|
+
const cached = secretCache.get(cacheKey);
|
|
599
|
+
if (cached) {
|
|
600
|
+
return cached;
|
|
600
601
|
}
|
|
601
602
|
const existing = generationPromises.get(cacheKey);
|
|
602
603
|
if (existing) {
|
|
@@ -833,8 +834,8 @@ var init_key_persistence = __esm({
|
|
|
833
834
|
*/
|
|
834
835
|
async get(kid) {
|
|
835
836
|
if (this.enableCache) {
|
|
836
|
-
const
|
|
837
|
-
if (
|
|
837
|
+
const cached = this.cache.get(kid);
|
|
838
|
+
if (cached) return cached;
|
|
838
839
|
}
|
|
839
840
|
const raw = await this.storage.get(kid);
|
|
840
841
|
if (!raw) return null;
|
|
@@ -1085,6 +1086,75 @@ var init_errors = __esm({
|
|
|
1085
1086
|
}
|
|
1086
1087
|
});
|
|
1087
1088
|
|
|
1089
|
+
// libs/utils/src/storage/utils/pattern.ts
|
|
1090
|
+
function globToRegex(pattern) {
|
|
1091
|
+
if (pattern.length > MAX_PATTERN_LENGTH) {
|
|
1092
|
+
throw new StoragePatternError(
|
|
1093
|
+
pattern.substring(0, 50) + "...",
|
|
1094
|
+
`Pattern exceeds maximum length of ${MAX_PATTERN_LENGTH} characters`
|
|
1095
|
+
);
|
|
1096
|
+
}
|
|
1097
|
+
const wildcardCount = (pattern.match(/[*?]/g) || []).length;
|
|
1098
|
+
if (wildcardCount > MAX_WILDCARDS) {
|
|
1099
|
+
throw new StoragePatternError(pattern, `Pattern has too many wildcards (max: ${MAX_WILDCARDS})`);
|
|
1100
|
+
}
|
|
1101
|
+
if (pattern === "" || pattern === "*") {
|
|
1102
|
+
return /^.*$/;
|
|
1103
|
+
}
|
|
1104
|
+
let regexStr = "^";
|
|
1105
|
+
let prevChar = "";
|
|
1106
|
+
for (let i = 0; i < pattern.length; i++) {
|
|
1107
|
+
const char = pattern[i];
|
|
1108
|
+
switch (char) {
|
|
1109
|
+
case "*":
|
|
1110
|
+
if (prevChar !== "*") {
|
|
1111
|
+
regexStr += ".*";
|
|
1112
|
+
}
|
|
1113
|
+
break;
|
|
1114
|
+
case "?":
|
|
1115
|
+
regexStr += ".";
|
|
1116
|
+
break;
|
|
1117
|
+
default:
|
|
1118
|
+
regexStr += char.replace(REGEX_SPECIAL_CHARS, "\\$&");
|
|
1119
|
+
}
|
|
1120
|
+
prevChar = char;
|
|
1121
|
+
}
|
|
1122
|
+
regexStr += "$";
|
|
1123
|
+
try {
|
|
1124
|
+
return new RegExp(regexStr);
|
|
1125
|
+
} catch {
|
|
1126
|
+
throw new StoragePatternError(pattern, "Failed to compile pattern to regex");
|
|
1127
|
+
}
|
|
1128
|
+
}
|
|
1129
|
+
function matchesPattern(key, pattern) {
|
|
1130
|
+
const regex = globToRegex(pattern);
|
|
1131
|
+
return regex.test(key);
|
|
1132
|
+
}
|
|
1133
|
+
function validatePattern(pattern) {
|
|
1134
|
+
try {
|
|
1135
|
+
globToRegex(pattern);
|
|
1136
|
+
return { valid: true };
|
|
1137
|
+
} catch (e) {
|
|
1138
|
+
return {
|
|
1139
|
+
valid: false,
|
|
1140
|
+
error: e instanceof Error ? e.message : "Invalid pattern"
|
|
1141
|
+
};
|
|
1142
|
+
}
|
|
1143
|
+
}
|
|
1144
|
+
function escapeGlob(literal) {
|
|
1145
|
+
return literal.replace(/[*?\\]/g, "\\$&");
|
|
1146
|
+
}
|
|
1147
|
+
var MAX_PATTERN_LENGTH, MAX_WILDCARDS, REGEX_SPECIAL_CHARS;
|
|
1148
|
+
var init_pattern = __esm({
|
|
1149
|
+
"libs/utils/src/storage/utils/pattern.ts"() {
|
|
1150
|
+
"use strict";
|
|
1151
|
+
init_errors();
|
|
1152
|
+
MAX_PATTERN_LENGTH = 500;
|
|
1153
|
+
MAX_WILDCARDS = 20;
|
|
1154
|
+
REGEX_SPECIAL_CHARS = /[.+^${}()|[\]\\]/g;
|
|
1155
|
+
}
|
|
1156
|
+
});
|
|
1157
|
+
|
|
1088
1158
|
// libs/utils/src/storage/utils/ttl.ts
|
|
1089
1159
|
function validateTTL(ttlSeconds) {
|
|
1090
1160
|
if (typeof ttlSeconds !== "number") {
|
|
@@ -1199,6 +1269,17 @@ var init_base = __esm({
|
|
|
1199
1269
|
const matchedKeys = await this.keys(pattern);
|
|
1200
1270
|
return matchedKeys.length;
|
|
1201
1271
|
}
|
|
1272
|
+
/**
|
|
1273
|
+
* Default: not supported, since a read followed by a delete is not atomic.
|
|
1274
|
+
* Override in adapters whose backend can compare and delete in one step.
|
|
1275
|
+
*/
|
|
1276
|
+
async deleteIfEquals(_key, _expectedValue) {
|
|
1277
|
+
throw new StorageNotSupportedError(
|
|
1278
|
+
"deleteIfEquals",
|
|
1279
|
+
this.backendName,
|
|
1280
|
+
"Use the memory, Redis, Upstash or Vercel KV adapter for an atomic compare-and-delete."
|
|
1281
|
+
);
|
|
1282
|
+
}
|
|
1202
1283
|
// ============================================
|
|
1203
1284
|
// Pub/Sub (default: not supported)
|
|
1204
1285
|
// ============================================
|
|
@@ -1247,85 +1328,16 @@ var init_base = __esm({
|
|
|
1247
1328
|
}
|
|
1248
1329
|
});
|
|
1249
1330
|
|
|
1250
|
-
// libs/utils/src/storage/utils/pattern.ts
|
|
1251
|
-
function globToRegex(pattern) {
|
|
1252
|
-
if (pattern.length > MAX_PATTERN_LENGTH) {
|
|
1253
|
-
throw new StoragePatternError(
|
|
1254
|
-
pattern.substring(0, 50) + "...",
|
|
1255
|
-
`Pattern exceeds maximum length of ${MAX_PATTERN_LENGTH} characters`
|
|
1256
|
-
);
|
|
1257
|
-
}
|
|
1258
|
-
const wildcardCount = (pattern.match(/[*?]/g) || []).length;
|
|
1259
|
-
if (wildcardCount > MAX_WILDCARDS) {
|
|
1260
|
-
throw new StoragePatternError(pattern, `Pattern has too many wildcards (max: ${MAX_WILDCARDS})`);
|
|
1261
|
-
}
|
|
1262
|
-
if (pattern === "" || pattern === "*") {
|
|
1263
|
-
return /^.*$/;
|
|
1264
|
-
}
|
|
1265
|
-
let regexStr = "^";
|
|
1266
|
-
let prevChar = "";
|
|
1267
|
-
for (let i = 0; i < pattern.length; i++) {
|
|
1268
|
-
const char = pattern[i];
|
|
1269
|
-
switch (char) {
|
|
1270
|
-
case "*":
|
|
1271
|
-
if (prevChar !== "*") {
|
|
1272
|
-
regexStr += ".*";
|
|
1273
|
-
}
|
|
1274
|
-
break;
|
|
1275
|
-
case "?":
|
|
1276
|
-
regexStr += ".";
|
|
1277
|
-
break;
|
|
1278
|
-
default:
|
|
1279
|
-
regexStr += char.replace(REGEX_SPECIAL_CHARS, "\\$&");
|
|
1280
|
-
}
|
|
1281
|
-
prevChar = char;
|
|
1282
|
-
}
|
|
1283
|
-
regexStr += "$";
|
|
1284
|
-
try {
|
|
1285
|
-
return new RegExp(regexStr);
|
|
1286
|
-
} catch {
|
|
1287
|
-
throw new StoragePatternError(pattern, "Failed to compile pattern to regex");
|
|
1288
|
-
}
|
|
1289
|
-
}
|
|
1290
|
-
function matchesPattern(key, pattern) {
|
|
1291
|
-
const regex = globToRegex(pattern);
|
|
1292
|
-
return regex.test(key);
|
|
1293
|
-
}
|
|
1294
|
-
function validatePattern(pattern) {
|
|
1295
|
-
try {
|
|
1296
|
-
globToRegex(pattern);
|
|
1297
|
-
return { valid: true };
|
|
1298
|
-
} catch (e) {
|
|
1299
|
-
return {
|
|
1300
|
-
valid: false,
|
|
1301
|
-
error: e instanceof Error ? e.message : "Invalid pattern"
|
|
1302
|
-
};
|
|
1303
|
-
}
|
|
1304
|
-
}
|
|
1305
|
-
function escapeGlob(literal) {
|
|
1306
|
-
return literal.replace(/[*?\\]/g, "\\$&");
|
|
1307
|
-
}
|
|
1308
|
-
var MAX_PATTERN_LENGTH, MAX_WILDCARDS, REGEX_SPECIAL_CHARS;
|
|
1309
|
-
var init_pattern = __esm({
|
|
1310
|
-
"libs/utils/src/storage/utils/pattern.ts"() {
|
|
1311
|
-
"use strict";
|
|
1312
|
-
init_errors();
|
|
1313
|
-
MAX_PATTERN_LENGTH = 500;
|
|
1314
|
-
MAX_WILDCARDS = 20;
|
|
1315
|
-
REGEX_SPECIAL_CHARS = /[.+^${}()|[\]\\]/g;
|
|
1316
|
-
}
|
|
1317
|
-
});
|
|
1318
|
-
|
|
1319
1331
|
// libs/utils/src/storage/adapters/memory.ts
|
|
1320
1332
|
import { EventEmitter } from "#event-emitter";
|
|
1321
1333
|
var DEFAULT_SWEEP_INTERVAL_SECONDS, MAX_TIMEOUT_MS, MemoryStorageAdapter;
|
|
1322
1334
|
var init_memory = __esm({
|
|
1323
1335
|
"libs/utils/src/storage/adapters/memory.ts"() {
|
|
1324
1336
|
"use strict";
|
|
1325
|
-
init_base();
|
|
1326
1337
|
init_errors();
|
|
1327
1338
|
init_pattern();
|
|
1328
1339
|
init_ttl();
|
|
1340
|
+
init_base();
|
|
1329
1341
|
DEFAULT_SWEEP_INTERVAL_SECONDS = 60;
|
|
1330
1342
|
MAX_TIMEOUT_MS = 2147483647;
|
|
1331
1343
|
MemoryStorageAdapter = class extends BaseStorageAdapter {
|
|
@@ -1417,6 +1429,12 @@ var init_memory = __esm({
|
|
|
1417
1429
|
this.ensureConnected();
|
|
1418
1430
|
return this.deleteEntry(key);
|
|
1419
1431
|
}
|
|
1432
|
+
async deleteIfEquals(key, expectedValue) {
|
|
1433
|
+
this.ensureConnected();
|
|
1434
|
+
const entry = this.store.get(key);
|
|
1435
|
+
if (!entry || isExpired(entry.expiresAt) || entry.value !== expectedValue) return false;
|
|
1436
|
+
return this.deleteEntry(key);
|
|
1437
|
+
}
|
|
1420
1438
|
async exists(key) {
|
|
1421
1439
|
this.ensureConnected();
|
|
1422
1440
|
const entry = this.store.get(key);
|
|
@@ -2962,6 +2980,41 @@ var init_crypto = __esm({
|
|
|
2962
2980
|
}
|
|
2963
2981
|
});
|
|
2964
2982
|
|
|
2983
|
+
// libs/utils/src/storage/redis-error-listener.ts
|
|
2984
|
+
function attachRedisErrorListener(client, options = {}) {
|
|
2985
|
+
const label = options.label ?? "redis";
|
|
2986
|
+
const intervalMs = options.intervalMs ?? DEFAULT_REDIS_ERROR_LOG_INTERVAL_MS;
|
|
2987
|
+
let lastLoggedAt = 0;
|
|
2988
|
+
let suppressed = 0;
|
|
2989
|
+
const listener = (error) => {
|
|
2990
|
+
const now = Date.now();
|
|
2991
|
+
if (lastLoggedAt !== 0 && now - lastLoggedAt < intervalMs) {
|
|
2992
|
+
suppressed++;
|
|
2993
|
+
return;
|
|
2994
|
+
}
|
|
2995
|
+
const extra = suppressed > 0 ? ` (${suppressed} similar error(s) suppressed)` : "";
|
|
2996
|
+
suppressed = 0;
|
|
2997
|
+
lastLoggedAt = now;
|
|
2998
|
+
const message = `[${label}] Redis connection error: ${error?.message ?? String(error)}${extra}`;
|
|
2999
|
+
if (options.logger) {
|
|
3000
|
+
options.logger.warn(message);
|
|
3001
|
+
} else {
|
|
3002
|
+
console.warn(message);
|
|
3003
|
+
}
|
|
3004
|
+
};
|
|
3005
|
+
client.on("error", listener);
|
|
3006
|
+
return () => {
|
|
3007
|
+
client.removeListener("error", listener);
|
|
3008
|
+
};
|
|
3009
|
+
}
|
|
3010
|
+
var DEFAULT_REDIS_ERROR_LOG_INTERVAL_MS;
|
|
3011
|
+
var init_redis_error_listener = __esm({
|
|
3012
|
+
"libs/utils/src/storage/redis-error-listener.ts"() {
|
|
3013
|
+
"use strict";
|
|
3014
|
+
DEFAULT_REDIS_ERROR_LOG_INTERVAL_MS = 3e4;
|
|
3015
|
+
}
|
|
3016
|
+
});
|
|
3017
|
+
|
|
2965
3018
|
// libs/utils/src/storage/utils/index.ts
|
|
2966
3019
|
var init_utils = __esm({
|
|
2967
3020
|
"libs/utils/src/storage/utils/index.ts"() {
|
|
@@ -2970,10 +3023,20 @@ var init_utils = __esm({
|
|
|
2970
3023
|
}
|
|
2971
3024
|
});
|
|
2972
3025
|
|
|
3026
|
+
// libs/utils/src/storage/utils/compare-and-delete.ts
|
|
3027
|
+
var COMPARE_AND_DELETE_SCRIPT;
|
|
3028
|
+
var init_compare_and_delete = __esm({
|
|
3029
|
+
"libs/utils/src/storage/utils/compare-and-delete.ts"() {
|
|
3030
|
+
"use strict";
|
|
3031
|
+
COMPARE_AND_DELETE_SCRIPT = `if redis.call('GET', KEYS[1]) == ARGV[1] then return redis.call('DEL', KEYS[1]) end return 0`;
|
|
3032
|
+
}
|
|
3033
|
+
});
|
|
3034
|
+
|
|
2973
3035
|
// libs/utils/src/storage/adapters/redis.ts
|
|
2974
3036
|
var redis_exports = {};
|
|
2975
3037
|
__export(redis_exports, {
|
|
2976
|
-
RedisStorageAdapter: () => RedisStorageAdapter
|
|
3038
|
+
RedisStorageAdapter: () => RedisStorageAdapter,
|
|
3039
|
+
createRedisClient: () => createRedisClient
|
|
2977
3040
|
});
|
|
2978
3041
|
function getRedisClass() {
|
|
2979
3042
|
try {
|
|
@@ -2991,12 +3054,28 @@ function getRedisClass() {
|
|
|
2991
3054
|
});
|
|
2992
3055
|
}
|
|
2993
3056
|
}
|
|
3057
|
+
function createRedisClient(options) {
|
|
3058
|
+
const RedisClass = getRedisClass();
|
|
3059
|
+
const baseOptions = { lazyConnect: false, maxRetriesPerRequest: 3 };
|
|
3060
|
+
const client = options.url ? new RedisClass(options.url, baseOptions) : new RedisClass({
|
|
3061
|
+
...baseOptions,
|
|
3062
|
+
host: options.host ?? "localhost",
|
|
3063
|
+
port: options.port ?? 6379,
|
|
3064
|
+
password: options.password,
|
|
3065
|
+
db: options.db ?? 0,
|
|
3066
|
+
tls: options.tls ? {} : void 0
|
|
3067
|
+
});
|
|
3068
|
+
attachRedisErrorListener(client, { label: options.label ?? "redis", logger: options.logger });
|
|
3069
|
+
return client;
|
|
3070
|
+
}
|
|
2994
3071
|
var RedisStorageAdapter;
|
|
2995
3072
|
var init_redis = __esm({
|
|
2996
3073
|
"libs/utils/src/storage/adapters/redis.ts"() {
|
|
2997
3074
|
"use strict";
|
|
2998
3075
|
init_errors();
|
|
3076
|
+
init_redis_error_listener();
|
|
2999
3077
|
init_utils();
|
|
3078
|
+
init_compare_and_delete();
|
|
3000
3079
|
init_base();
|
|
3001
3080
|
RedisStorageAdapter = class extends BaseStorageAdapter {
|
|
3002
3081
|
backendName = "redis";
|
|
@@ -3004,6 +3083,7 @@ var init_redis = __esm({
|
|
|
3004
3083
|
subscriber;
|
|
3005
3084
|
options;
|
|
3006
3085
|
ownsClient;
|
|
3086
|
+
detachErrorListener;
|
|
3007
3087
|
connecting;
|
|
3008
3088
|
keyPrefix;
|
|
3009
3089
|
subscriptionHandlers = /* @__PURE__ */ new Map();
|
|
@@ -3060,7 +3140,10 @@ var init_redis = __esm({
|
|
|
3060
3140
|
await client.ping();
|
|
3061
3141
|
this.client = client;
|
|
3062
3142
|
this.connected = true;
|
|
3063
|
-
if (this.ownsClient)
|
|
3143
|
+
if (this.ownsClient) {
|
|
3144
|
+
client.removeListener("error", recordSocketError);
|
|
3145
|
+
this.detachErrorListener = attachRedisErrorListener(client, { label: "RedisStorage" });
|
|
3146
|
+
}
|
|
3064
3147
|
} catch (e) {
|
|
3065
3148
|
if (this.ownsClient && client) {
|
|
3066
3149
|
try {
|
|
@@ -3081,6 +3164,8 @@ var init_redis = __esm({
|
|
|
3081
3164
|
if (this.ownsClient && this.client) {
|
|
3082
3165
|
await this.client.quit();
|
|
3083
3166
|
}
|
|
3167
|
+
this.detachErrorListener?.();
|
|
3168
|
+
this.detachErrorListener = void 0;
|
|
3084
3169
|
this.client = void 0;
|
|
3085
3170
|
this.connected = false;
|
|
3086
3171
|
this.subscriptionHandlers.clear();
|
|
@@ -3145,6 +3230,15 @@ var init_redis = __esm({
|
|
|
3145
3230
|
const result = await this.getConnectedClient().del(this.prefixKey(key));
|
|
3146
3231
|
return result > 0;
|
|
3147
3232
|
}
|
|
3233
|
+
async deleteIfEquals(key, expectedValue) {
|
|
3234
|
+
const deleted = await this.getConnectedClient().eval(
|
|
3235
|
+
COMPARE_AND_DELETE_SCRIPT,
|
|
3236
|
+
1,
|
|
3237
|
+
this.prefixKey(key),
|
|
3238
|
+
expectedValue
|
|
3239
|
+
);
|
|
3240
|
+
return deleted === 1;
|
|
3241
|
+
}
|
|
3148
3242
|
async exists(key) {
|
|
3149
3243
|
const result = await this.getConnectedClient().exists(this.prefixKey(key));
|
|
3150
3244
|
return result > 0;
|
|
@@ -3308,6 +3402,7 @@ var init_redis = __esm({
|
|
|
3308
3402
|
} else {
|
|
3309
3403
|
throw new StorageConfigError("redis", "Cannot create subscriber without url, config, or client");
|
|
3310
3404
|
}
|
|
3405
|
+
attachRedisErrorListener(subscriber, { label: "RedisStorage:subscriber" });
|
|
3311
3406
|
subscriber.on("message", (channel, message) => {
|
|
3312
3407
|
const handlers = this.subscriptionHandlers.get(channel);
|
|
3313
3408
|
if (handlers) {
|
|
@@ -3352,9 +3447,12 @@ var vercel_kv_exports = {};
|
|
|
3352
3447
|
__export(vercel_kv_exports, {
|
|
3353
3448
|
VercelKvStorageAdapter: () => VercelKvStorageAdapter
|
|
3354
3449
|
});
|
|
3355
|
-
function
|
|
3450
|
+
async function loadVercelKv() {
|
|
3356
3451
|
try {
|
|
3357
|
-
|
|
3452
|
+
const mod = await import("@vercel/kv");
|
|
3453
|
+
const resolved = typeof mod.createClient === "function" ? mod : mod.default;
|
|
3454
|
+
if (!resolved || typeof resolved.createClient !== "function") throw new Error("createClient missing");
|
|
3455
|
+
return resolved;
|
|
3358
3456
|
} catch {
|
|
3359
3457
|
throw new Error("@vercel/kv is required for Vercel KV storage adapter. Install it with: npm install @vercel/kv");
|
|
3360
3458
|
}
|
|
@@ -3363,9 +3461,10 @@ var VercelKvStorageAdapter;
|
|
|
3363
3461
|
var init_vercel_kv = __esm({
|
|
3364
3462
|
"libs/utils/src/storage/adapters/vercel-kv.ts"() {
|
|
3365
3463
|
"use strict";
|
|
3366
|
-
init_base();
|
|
3367
3464
|
init_errors();
|
|
3465
|
+
init_compare_and_delete();
|
|
3368
3466
|
init_ttl();
|
|
3467
|
+
init_base();
|
|
3369
3468
|
VercelKvStorageAdapter = class extends BaseStorageAdapter {
|
|
3370
3469
|
backendName = "vercel-kv";
|
|
3371
3470
|
client;
|
|
@@ -3390,17 +3489,13 @@ var init_vercel_kv = __esm({
|
|
|
3390
3489
|
async connect() {
|
|
3391
3490
|
if (this.connected) return;
|
|
3392
3491
|
try {
|
|
3393
|
-
const { createClient
|
|
3394
|
-
|
|
3395
|
-
|
|
3396
|
-
|
|
3397
|
-
|
|
3398
|
-
const token = this.options.token;
|
|
3399
|
-
if (!url || !token) {
|
|
3400
|
-
throw new StorageConfigError("vercel-kv", "URL and token are required");
|
|
3401
|
-
}
|
|
3402
|
-
this.client = createClient({ url, token });
|
|
3492
|
+
const { createClient } = await loadVercelKv();
|
|
3493
|
+
const url = this.options.url;
|
|
3494
|
+
const token = this.options.token;
|
|
3495
|
+
if (!url || !token) {
|
|
3496
|
+
throw new StorageConfigError("vercel-kv", "URL and token are required");
|
|
3403
3497
|
}
|
|
3498
|
+
this.client = createClient({ url, token, cache: void 0 });
|
|
3404
3499
|
await this.client.exists("__healthcheck__");
|
|
3405
3500
|
this.connected = true;
|
|
3406
3501
|
} catch (e) {
|
|
@@ -3462,6 +3557,14 @@ var init_vercel_kv = __esm({
|
|
|
3462
3557
|
const result = await this.getConnectedClient().del(this.prefixKey(key));
|
|
3463
3558
|
return result > 0;
|
|
3464
3559
|
}
|
|
3560
|
+
async deleteIfEquals(key, expectedValue) {
|
|
3561
|
+
const deleted = await this.getConnectedClient().eval(
|
|
3562
|
+
COMPARE_AND_DELETE_SCRIPT,
|
|
3563
|
+
[this.prefixKey(key)],
|
|
3564
|
+
[expectedValue]
|
|
3565
|
+
);
|
|
3566
|
+
return deleted === 1;
|
|
3567
|
+
}
|
|
3465
3568
|
async exists(key) {
|
|
3466
3569
|
const result = await this.getConnectedClient().exists(this.prefixKey(key));
|
|
3467
3570
|
return result > 0;
|
|
@@ -3579,9 +3682,10 @@ var PUBSUB_POLL_INTERVAL_MS, UpstashStorageAdapter;
|
|
|
3579
3682
|
var init_upstash = __esm({
|
|
3580
3683
|
"libs/utils/src/storage/adapters/upstash.ts"() {
|
|
3581
3684
|
"use strict";
|
|
3582
|
-
init_base();
|
|
3583
3685
|
init_errors();
|
|
3686
|
+
init_compare_and_delete();
|
|
3584
3687
|
init_ttl();
|
|
3688
|
+
init_base();
|
|
3585
3689
|
PUBSUB_POLL_INTERVAL_MS = 100;
|
|
3586
3690
|
UpstashStorageAdapter = class extends BaseStorageAdapter {
|
|
3587
3691
|
backendName = "upstash";
|
|
@@ -3686,6 +3790,14 @@ var init_upstash = __esm({
|
|
|
3686
3790
|
const result = await this.getConnectedClient().del(this.prefixKey(key));
|
|
3687
3791
|
return result > 0;
|
|
3688
3792
|
}
|
|
3793
|
+
async deleteIfEquals(key, expectedValue) {
|
|
3794
|
+
const deleted = await this.getConnectedClient().eval(
|
|
3795
|
+
COMPARE_AND_DELETE_SCRIPT,
|
|
3796
|
+
[this.prefixKey(key)],
|
|
3797
|
+
[expectedValue]
|
|
3798
|
+
);
|
|
3799
|
+
return deleted === 1;
|
|
3800
|
+
}
|
|
3689
3801
|
async exists(key) {
|
|
3690
3802
|
const result = await this.getConnectedClient().exists(this.prefixKey(key));
|
|
3691
3803
|
return result > 0;
|
|
@@ -3875,7 +3987,9 @@ var init_cloudflare_kv = __esm({
|
|
|
3875
3987
|
constructor(options) {
|
|
3876
3988
|
super();
|
|
3877
3989
|
if (!options?.namespace) {
|
|
3878
|
-
throw new Error(
|
|
3990
|
+
throw new Error(
|
|
3991
|
+
"CloudflareKvStorageAdapter: a bound KV `namespace` is required (resolve it from the Worker `env`)."
|
|
3992
|
+
);
|
|
3879
3993
|
}
|
|
3880
3994
|
this.kv = options.namespace;
|
|
3881
3995
|
this.keyPrefix = options.keyPrefix ?? "";
|
|
@@ -3969,6 +4083,13 @@ var init_cloudflare_kv = __esm({
|
|
|
3969
4083
|
"Cloudflare KV has no atomic increment (a get+put is racy under eventual consistency). Use a Durable Object for atomic counters."
|
|
3970
4084
|
);
|
|
3971
4085
|
}
|
|
4086
|
+
async deleteIfEquals(_key, _expectedValue) {
|
|
4087
|
+
throw new StorageNotSupportedError(
|
|
4088
|
+
"deleteIfEquals",
|
|
4089
|
+
this.backendName,
|
|
4090
|
+
"Cloudflare KV has no compare-and-set; use a Durable Object for an atomic compare-and-delete."
|
|
4091
|
+
);
|
|
4092
|
+
}
|
|
3972
4093
|
// ── Pub/Sub (unsupported) ────────────────────────────────────────────────
|
|
3973
4094
|
getPubSubSuggestion() {
|
|
3974
4095
|
return "Cloudflare KV does not support pub/sub. Use a Durable Object (or Queues) for fan-out.";
|
|
@@ -4397,9 +4518,17 @@ function joinPath(...parts) {
|
|
|
4397
4518
|
return cleaned.length ? `/${cleaned.join("/")}` : "";
|
|
4398
4519
|
}
|
|
4399
4520
|
|
|
4400
|
-
// libs/utils/src/path/
|
|
4401
|
-
import {
|
|
4402
|
-
|
|
4521
|
+
// libs/utils/src/path/index.ts
|
|
4522
|
+
import {
|
|
4523
|
+
resolve,
|
|
4524
|
+
join,
|
|
4525
|
+
basename,
|
|
4526
|
+
dirname,
|
|
4527
|
+
extname,
|
|
4528
|
+
isAbsolute,
|
|
4529
|
+
pathToFileURL,
|
|
4530
|
+
sep
|
|
4531
|
+
} from "#path";
|
|
4403
4532
|
|
|
4404
4533
|
// libs/utils/src/content/content.ts
|
|
4405
4534
|
function sanitizeToJson(value) {
|
|
@@ -4826,169 +4955,30 @@ import { EventEmitter as EventEmitter2 } from "#event-emitter";
|
|
|
4826
4955
|
import {
|
|
4827
4956
|
getEnv as getEnv2,
|
|
4828
4957
|
getCwd as getCwd2,
|
|
4958
|
+
getNodeEnv,
|
|
4829
4959
|
isProduction,
|
|
4830
4960
|
isDevelopment,
|
|
4831
4961
|
getEnvFlag,
|
|
4832
4962
|
isDebug,
|
|
4833
4963
|
setEnv,
|
|
4834
|
-
isEdgeRuntime
|
|
4835
|
-
isServerless
|
|
4964
|
+
isEdgeRuntime,
|
|
4965
|
+
isServerless,
|
|
4836
4966
|
supportsAnsi
|
|
4837
4967
|
} from "#env";
|
|
4838
|
-
|
|
4839
|
-
|
|
4840
|
-
|
|
4841
|
-
|
|
4842
|
-
|
|
4843
|
-
|
|
4844
|
-
|
|
4845
|
-
|
|
4846
|
-
if (cached) return cached;
|
|
4847
|
-
cached = resolveBuildTarget();
|
|
4848
|
-
return cached;
|
|
4849
|
-
}
|
|
4850
|
-
function resolveBuildTarget() {
|
|
4851
|
-
const globalAny = globalThis;
|
|
4852
|
-
const fromGlobal = globalAny.FRONTMCP_BUILD_TARGET;
|
|
4853
|
-
if (typeof fromGlobal === "string" && isKnownTarget(fromGlobal)) return fromGlobal;
|
|
4854
|
-
const fromEnv = typeof process !== "undefined" ? process.env?.["FRONTMCP_BUILD_TARGET"] : void 0;
|
|
4855
|
-
if (typeof fromEnv === "string" && isKnownTarget(fromEnv)) return fromEnv;
|
|
4856
|
-
return "unknown";
|
|
4857
|
-
}
|
|
4858
|
-
function isKnownTarget(value) {
|
|
4859
|
-
return value === "unknown" || value === "node" || value === "distributed" || value === "cli" || value === "vercel" || value === "lambda" || value === "cloudflare" || value === "browser" || value === "sdk" || value === "mcpb";
|
|
4860
|
-
}
|
|
4861
|
-
|
|
4862
|
-
// libs/utils/src/env/provider.ts
|
|
4863
|
-
var cached2;
|
|
4864
|
-
function detectProvider() {
|
|
4865
|
-
if (cached2) return cached2;
|
|
4866
|
-
cached2 = detectProviderUncached();
|
|
4867
|
-
return cached2;
|
|
4868
|
-
}
|
|
4869
|
-
function detectProviderUncached() {
|
|
4870
|
-
const explicit = process.env["FRONTMCP_PROVIDER"];
|
|
4871
|
-
if (explicit && isKnownProvider(explicit)) return explicit;
|
|
4872
|
-
if (process.env["VERCEL"]) return "vercel";
|
|
4873
|
-
if (process.env["AWS_LAMBDA_FUNCTION_NAME"]) return "lambda";
|
|
4874
|
-
if (process.env["CF_PAGES"]) return "cloudflare";
|
|
4875
|
-
if (process.env["NETLIFY"]) return "netlify";
|
|
4876
|
-
if (process.env["AZURE_FUNCTIONS_ENVIRONMENT"]) return "azure";
|
|
4877
|
-
if (process.env["K_SERVICE"]) return "gcp";
|
|
4878
|
-
if (process.env["FLY_APP_NAME"]) return "fly";
|
|
4879
|
-
if (process.env["RENDER"]) return "render";
|
|
4880
|
-
if (process.env["RAILWAY_ENVIRONMENT"]) return "railway";
|
|
4881
|
-
try {
|
|
4882
|
-
const nodeFs = __require("node:fs");
|
|
4883
|
-
if (nodeFs.existsSync("/.dockerenv")) return "docker";
|
|
4884
|
-
} catch {
|
|
4885
|
-
}
|
|
4886
|
-
return "bare";
|
|
4887
|
-
}
|
|
4888
|
-
function isKnownProvider(value) {
|
|
4889
|
-
return value === "bare" || value === "docker" || value === "vercel" || value === "lambda" || value === "cloudflare" || value === "netlify" || value === "azure" || value === "gcp" || value === "fly" || value === "render" || value === "railway";
|
|
4890
|
-
}
|
|
4891
|
-
|
|
4892
|
-
// libs/utils/src/env/runtime-context.ts
|
|
4893
|
-
var entryAvailabilitySchema = z3.object({
|
|
4894
|
-
os: z3.array(z3.string().min(1)).optional(),
|
|
4895
|
-
platform: z3.array(z3.string().min(1)).optional(),
|
|
4896
|
-
runtime: z3.array(z3.string().min(1)).optional(),
|
|
4897
|
-
deployment: z3.array(z3.string().min(1)).optional(),
|
|
4898
|
-
provider: z3.array(z3.string().min(1)).optional(),
|
|
4899
|
-
target: z3.array(z3.string().min(1)).optional(),
|
|
4900
|
-
surface: z3.array(z3.enum(["mcp", "cli", "http-trigger", "job", "agent"])).optional(),
|
|
4901
|
-
env: z3.array(z3.string().min(1)).optional()
|
|
4902
|
-
}).strict();
|
|
4903
|
-
var PROCESS_AXES = [
|
|
4904
|
-
// `os` and `platform` both compare against the same RuntimeContext value
|
|
4905
|
-
// — keeping `platform` as a deprecated alias lets pre-#417 metadata
|
|
4906
|
-
// continue to match without any code change.
|
|
4907
|
-
{ key: "os", ctxKey: "os" },
|
|
4908
|
-
{ key: "platform", ctxKey: "platform" },
|
|
4909
|
-
{ key: "runtime", ctxKey: "runtime" },
|
|
4910
|
-
{ key: "deployment", ctxKey: "deployment" },
|
|
4911
|
-
{ key: "provider", ctxKey: "provider" },
|
|
4912
|
-
{ key: "target", ctxKey: "target" },
|
|
4913
|
-
{ key: "env", ctxKey: "env" }
|
|
4914
|
-
];
|
|
4915
|
-
function isEntryAvailable(availability, ctx, callCtx) {
|
|
4916
|
-
if (!availability) return true;
|
|
4917
|
-
for (const { key, ctxKey } of PROCESS_AXES) {
|
|
4918
|
-
const allowed = availability[key];
|
|
4919
|
-
if (allowed === void 0) continue;
|
|
4920
|
-
if (allowed.length === 0) return false;
|
|
4921
|
-
if (!allowed.includes(ctx[ctxKey])) return false;
|
|
4922
|
-
}
|
|
4923
|
-
if (availability.surface !== void 0) {
|
|
4924
|
-
if (availability.surface.length === 0) return false;
|
|
4925
|
-
if (callCtx?.surface !== void 0 && !availability.surface.includes(callCtx.surface)) {
|
|
4926
|
-
return false;
|
|
4927
|
-
}
|
|
4928
|
-
}
|
|
4929
|
-
return true;
|
|
4930
|
-
}
|
|
4931
|
-
function checkEntryAvailability(availability, ctx, callCtx) {
|
|
4932
|
-
if (!availability) return { available: true, missingAxes: [] };
|
|
4933
|
-
const missing = [];
|
|
4934
|
-
for (const { key, ctxKey } of PROCESS_AXES) {
|
|
4935
|
-
const allowed = availability[key];
|
|
4936
|
-
if (allowed === void 0) continue;
|
|
4937
|
-
if (allowed.length === 0 || !allowed.includes(ctx[ctxKey])) {
|
|
4938
|
-
missing.push(key);
|
|
4939
|
-
}
|
|
4940
|
-
}
|
|
4941
|
-
if (availability.surface !== void 0) {
|
|
4942
|
-
if (availability.surface.length === 0) {
|
|
4943
|
-
missing.push("surface");
|
|
4944
|
-
} else if (callCtx?.surface !== void 0 && !availability.surface.includes(callCtx.surface)) {
|
|
4945
|
-
missing.push("surface");
|
|
4946
|
-
}
|
|
4947
|
-
}
|
|
4948
|
-
return { available: missing.length === 0, missingAxes: missing };
|
|
4949
|
-
}
|
|
4950
|
-
function detectRuntime() {
|
|
4951
|
-
if (typeof globalThis !== "undefined" && "Bun" in globalThis) return "bun";
|
|
4952
|
-
if (typeof globalThis !== "undefined" && "Deno" in globalThis) return "deno";
|
|
4953
|
-
if (isEdgeRuntime()) return "edge";
|
|
4954
|
-
return "node";
|
|
4955
|
-
}
|
|
4956
|
-
function detectDeployment(runtime) {
|
|
4957
|
-
const explicit = process.env["FRONTMCP_DEPLOYMENT_MODE"];
|
|
4958
|
-
if (explicit === "distributed") return "distributed";
|
|
4959
|
-
if (explicit === "serverless") return "serverless";
|
|
4960
|
-
if (runtime === "browser") return "browser";
|
|
4961
|
-
if (isServerless()) return "serverless";
|
|
4962
|
-
return "standalone";
|
|
4963
|
-
}
|
|
4964
|
-
function detectRuntimeContext() {
|
|
4965
|
-
const runtime = detectRuntime();
|
|
4966
|
-
const os = process.platform;
|
|
4967
|
-
return {
|
|
4968
|
-
os,
|
|
4969
|
-
platform: os,
|
|
4970
|
-
runtime,
|
|
4971
|
-
deployment: detectDeployment(runtime),
|
|
4972
|
-
provider: detectProvider(),
|
|
4973
|
-
target: getBuildTarget(),
|
|
4974
|
-
env: process.env["NODE_ENV"] || "development"
|
|
4975
|
-
};
|
|
4976
|
-
}
|
|
4977
|
-
var cached3;
|
|
4978
|
-
function getRuntimeContext() {
|
|
4979
|
-
if (!cached3) {
|
|
4980
|
-
cached3 = detectRuntimeContext();
|
|
4981
|
-
}
|
|
4982
|
-
return cached3;
|
|
4983
|
-
}
|
|
4984
|
-
function resetRuntimeContext() {
|
|
4985
|
-
cached3 = void 0;
|
|
4986
|
-
}
|
|
4968
|
+
import {
|
|
4969
|
+
getRuntimeContext,
|
|
4970
|
+
resetRuntimeContext,
|
|
4971
|
+
detectRuntimeContext,
|
|
4972
|
+
isEntryAvailable,
|
|
4973
|
+
checkEntryAvailability,
|
|
4974
|
+
entryAvailabilitySchema
|
|
4975
|
+
} from "#runtime-context";
|
|
4987
4976
|
|
|
4988
4977
|
// libs/utils/src/storage/factory.ts
|
|
4989
4978
|
init_errors();
|
|
4990
4979
|
|
|
4991
4980
|
// libs/utils/src/storage/namespace.ts
|
|
4981
|
+
init_errors();
|
|
4992
4982
|
var NAMESPACE_SEPARATOR = ":";
|
|
4993
4983
|
function buildPrefix(name, id) {
|
|
4994
4984
|
if (id) {
|
|
@@ -5120,6 +5110,12 @@ var NamespacedStorageImpl = class _NamespacedStorageImpl {
|
|
|
5120
5110
|
async incrBy(key, amount) {
|
|
5121
5111
|
return this.adapter.incrBy(this.prefixKey(key), amount);
|
|
5122
5112
|
}
|
|
5113
|
+
async deleteIfEquals(key, expectedValue) {
|
|
5114
|
+
if (!this.adapter.deleteIfEquals) {
|
|
5115
|
+
throw new StorageNotSupportedError("deleteIfEquals", "this storage adapter");
|
|
5116
|
+
}
|
|
5117
|
+
return this.adapter.deleteIfEquals(this.prefixKey(key), expectedValue);
|
|
5118
|
+
}
|
|
5123
5119
|
// ============================================
|
|
5124
5120
|
// Pub/Sub (with channel prefixing)
|
|
5125
5121
|
// ============================================
|
|
@@ -5248,6 +5244,7 @@ function getDetectedStorageType() {
|
|
|
5248
5244
|
}
|
|
5249
5245
|
|
|
5250
5246
|
// libs/utils/src/storage/index.ts
|
|
5247
|
+
init_redis_error_listener();
|
|
5251
5248
|
init_errors();
|
|
5252
5249
|
|
|
5253
5250
|
// libs/utils/src/storage/typed-storage.ts
|
|
@@ -5902,6 +5899,7 @@ export {
|
|
|
5902
5899
|
BaseStorageAdapter,
|
|
5903
5900
|
DEFAULT_CODE_VERIFIER_LENGTH,
|
|
5904
5901
|
DEFAULT_MAX_INPUT_LENGTH,
|
|
5902
|
+
DEFAULT_REDIS_ERROR_LOG_INTERVAL_MS,
|
|
5905
5903
|
EncryptedBlobError,
|
|
5906
5904
|
EncryptedStorageError,
|
|
5907
5905
|
EncryptedTypedStorage,
|
|
@@ -5934,6 +5932,7 @@ export {
|
|
|
5934
5932
|
assertNode,
|
|
5935
5933
|
asymmetricAlgSchema,
|
|
5936
5934
|
asymmetricKeyDataSchema,
|
|
5935
|
+
attachRedisErrorListener,
|
|
5937
5936
|
awaitOutsideRequest,
|
|
5938
5937
|
base64Decode,
|
|
5939
5938
|
base64Encode,
|
|
@@ -5954,6 +5953,7 @@ export {
|
|
|
5954
5953
|
createKeyPersistenceWithStorage,
|
|
5955
5954
|
createMemoryStorage,
|
|
5956
5955
|
createNamespacedStorage,
|
|
5956
|
+
createRedisClient,
|
|
5957
5957
|
createRootStorage,
|
|
5958
5958
|
createSafeRegExp,
|
|
5959
5959
|
createSecretData,
|
|
@@ -6001,6 +6001,7 @@ export {
|
|
|
6001
6001
|
getEnv2 as getEnv,
|
|
6002
6002
|
getEnvFlag,
|
|
6003
6003
|
getMachineId,
|
|
6004
|
+
getNodeEnv,
|
|
6004
6005
|
getOrCreateSecret,
|
|
6005
6006
|
getRuntimeContext,
|
|
6006
6007
|
getSpawnFn,
|
|
@@ -6016,7 +6017,7 @@ export {
|
|
|
6016
6017
|
isDebug,
|
|
6017
6018
|
isDevelopment,
|
|
6018
6019
|
isDirEmpty,
|
|
6019
|
-
|
|
6020
|
+
isEdgeRuntime,
|
|
6020
6021
|
isEntryAvailable,
|
|
6021
6022
|
isExpired,
|
|
6022
6023
|
isInputLengthSafe,
|
|
@@ -6030,7 +6031,7 @@ export {
|
|
|
6030
6031
|
isSecretKeyData,
|
|
6031
6032
|
isSecretPersistenceEnabled,
|
|
6032
6033
|
isSecureRequest,
|
|
6033
|
-
|
|
6034
|
+
isServerless,
|
|
6034
6035
|
isSignedData,
|
|
6035
6036
|
isUriTemplate,
|
|
6036
6037
|
isValidCodeChallenge,
|