@frontmcp/plugin-dashboard 1.8.7 → 1.9.1-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/esm/index.mjs +169 -118
- package/esm/package.json +3 -3
- package/index.js +166 -118
- package/package.json +3 -3
package/esm/index.mjs
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
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
|
|
1
4
|
var __create = Object.create;
|
|
2
5
|
var __defProp = Object.defineProperty;
|
|
3
6
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
@@ -443,7 +446,6 @@ import { hkdf } from "@noble/hashes/hkdf.js";
|
|
|
443
446
|
import { randomBytes as nobleRandomBytes } from "@noble/hashes/utils.js";
|
|
444
447
|
import { gcm } from "@noble/ciphers/aes.js";
|
|
445
448
|
import { analyzeForReDoS, REDOS_THRESHOLDS } from "@enclave-vm/ast";
|
|
446
|
-
import { z as z3 } from "@frontmcp/lazy-zod";
|
|
447
449
|
var __frontmcpModule = typeof process !== "undefined" && typeof process.getBuiltinModule === "function" ? process.getBuiltinModule("module") : void 0;
|
|
448
450
|
var require2 = __frontmcpModule ? __frontmcpModule.createRequire(import.meta.url || "file:///") : void 0;
|
|
449
451
|
var __defProp2 = Object.defineProperty;
|
|
@@ -781,8 +783,8 @@ var init_key_persistence = __esm({
|
|
|
781
783
|
*/
|
|
782
784
|
async get(kid) {
|
|
783
785
|
if (this.enableCache) {
|
|
784
|
-
const
|
|
785
|
-
if (
|
|
786
|
+
const cached = this.cache.get(kid);
|
|
787
|
+
if (cached) return cached;
|
|
786
788
|
}
|
|
787
789
|
const raw = await this.storage.get(kid);
|
|
788
790
|
if (!raw) return null;
|
|
@@ -1038,6 +1040,61 @@ var init_errors = __esm({
|
|
|
1038
1040
|
};
|
|
1039
1041
|
}
|
|
1040
1042
|
});
|
|
1043
|
+
function globToRegex(pattern) {
|
|
1044
|
+
if (pattern.length > MAX_PATTERN_LENGTH) {
|
|
1045
|
+
throw new StoragePatternError(
|
|
1046
|
+
pattern.substring(0, 50) + "...",
|
|
1047
|
+
`Pattern exceeds maximum length of ${MAX_PATTERN_LENGTH} characters`
|
|
1048
|
+
);
|
|
1049
|
+
}
|
|
1050
|
+
const wildcardCount = (pattern.match(/[*?]/g) || []).length;
|
|
1051
|
+
if (wildcardCount > MAX_WILDCARDS) {
|
|
1052
|
+
throw new StoragePatternError(pattern, `Pattern has too many wildcards (max: ${MAX_WILDCARDS})`);
|
|
1053
|
+
}
|
|
1054
|
+
if (pattern === "" || pattern === "*") {
|
|
1055
|
+
return /^.*$/;
|
|
1056
|
+
}
|
|
1057
|
+
let regexStr = "^";
|
|
1058
|
+
let prevChar = "";
|
|
1059
|
+
for (let i = 0; i < pattern.length; i++) {
|
|
1060
|
+
const char = pattern[i];
|
|
1061
|
+
switch (char) {
|
|
1062
|
+
case "*":
|
|
1063
|
+
if (prevChar !== "*") {
|
|
1064
|
+
regexStr += ".*";
|
|
1065
|
+
}
|
|
1066
|
+
break;
|
|
1067
|
+
case "?":
|
|
1068
|
+
regexStr += ".";
|
|
1069
|
+
break;
|
|
1070
|
+
default:
|
|
1071
|
+
regexStr += char.replace(REGEX_SPECIAL_CHARS, "\\$&");
|
|
1072
|
+
}
|
|
1073
|
+
prevChar = char;
|
|
1074
|
+
}
|
|
1075
|
+
regexStr += "$";
|
|
1076
|
+
try {
|
|
1077
|
+
return new RegExp(regexStr);
|
|
1078
|
+
} catch {
|
|
1079
|
+
throw new StoragePatternError(pattern, "Failed to compile pattern to regex");
|
|
1080
|
+
}
|
|
1081
|
+
}
|
|
1082
|
+
function matchesPattern(key, pattern) {
|
|
1083
|
+
const regex = globToRegex(pattern);
|
|
1084
|
+
return regex.test(key);
|
|
1085
|
+
}
|
|
1086
|
+
var MAX_PATTERN_LENGTH;
|
|
1087
|
+
var MAX_WILDCARDS;
|
|
1088
|
+
var REGEX_SPECIAL_CHARS;
|
|
1089
|
+
var init_pattern = __esm({
|
|
1090
|
+
"libs/utils/src/storage/utils/pattern.ts"() {
|
|
1091
|
+
"use strict";
|
|
1092
|
+
init_errors();
|
|
1093
|
+
MAX_PATTERN_LENGTH = 500;
|
|
1094
|
+
MAX_WILDCARDS = 20;
|
|
1095
|
+
REGEX_SPECIAL_CHARS = /[.+^${}()|[\]\\]/g;
|
|
1096
|
+
}
|
|
1097
|
+
});
|
|
1041
1098
|
function validateTTL(ttlSeconds) {
|
|
1042
1099
|
if (typeof ttlSeconds !== "number") {
|
|
1043
1100
|
throw new StorageTTLError(ttlSeconds, `TTL must be a number, got ${typeof ttlSeconds}`);
|
|
@@ -1146,6 +1203,17 @@ var init_base = __esm({
|
|
|
1146
1203
|
const matchedKeys = await this.keys(pattern);
|
|
1147
1204
|
return matchedKeys.length;
|
|
1148
1205
|
}
|
|
1206
|
+
/**
|
|
1207
|
+
* Default: not supported, since a read followed by a delete is not atomic.
|
|
1208
|
+
* Override in adapters whose backend can compare and delete in one step.
|
|
1209
|
+
*/
|
|
1210
|
+
async deleteIfEquals(_key, _expectedValue) {
|
|
1211
|
+
throw new StorageNotSupportedError(
|
|
1212
|
+
"deleteIfEquals",
|
|
1213
|
+
this.backendName,
|
|
1214
|
+
"Use the memory, Redis, Upstash or Vercel KV adapter for an atomic compare-and-delete."
|
|
1215
|
+
);
|
|
1216
|
+
}
|
|
1149
1217
|
// ============================================
|
|
1150
1218
|
// Pub/Sub (default: not supported)
|
|
1151
1219
|
// ============================================
|
|
@@ -1193,71 +1261,16 @@ var init_base = __esm({
|
|
|
1193
1261
|
};
|
|
1194
1262
|
}
|
|
1195
1263
|
});
|
|
1196
|
-
function globToRegex(pattern) {
|
|
1197
|
-
if (pattern.length > MAX_PATTERN_LENGTH) {
|
|
1198
|
-
throw new StoragePatternError(
|
|
1199
|
-
pattern.substring(0, 50) + "...",
|
|
1200
|
-
`Pattern exceeds maximum length of ${MAX_PATTERN_LENGTH} characters`
|
|
1201
|
-
);
|
|
1202
|
-
}
|
|
1203
|
-
const wildcardCount = (pattern.match(/[*?]/g) || []).length;
|
|
1204
|
-
if (wildcardCount > MAX_WILDCARDS) {
|
|
1205
|
-
throw new StoragePatternError(pattern, `Pattern has too many wildcards (max: ${MAX_WILDCARDS})`);
|
|
1206
|
-
}
|
|
1207
|
-
if (pattern === "" || pattern === "*") {
|
|
1208
|
-
return /^.*$/;
|
|
1209
|
-
}
|
|
1210
|
-
let regexStr = "^";
|
|
1211
|
-
let prevChar = "";
|
|
1212
|
-
for (let i = 0; i < pattern.length; i++) {
|
|
1213
|
-
const char = pattern[i];
|
|
1214
|
-
switch (char) {
|
|
1215
|
-
case "*":
|
|
1216
|
-
if (prevChar !== "*") {
|
|
1217
|
-
regexStr += ".*";
|
|
1218
|
-
}
|
|
1219
|
-
break;
|
|
1220
|
-
case "?":
|
|
1221
|
-
regexStr += ".";
|
|
1222
|
-
break;
|
|
1223
|
-
default:
|
|
1224
|
-
regexStr += char.replace(REGEX_SPECIAL_CHARS, "\\$&");
|
|
1225
|
-
}
|
|
1226
|
-
prevChar = char;
|
|
1227
|
-
}
|
|
1228
|
-
regexStr += "$";
|
|
1229
|
-
try {
|
|
1230
|
-
return new RegExp(regexStr);
|
|
1231
|
-
} catch {
|
|
1232
|
-
throw new StoragePatternError(pattern, "Failed to compile pattern to regex");
|
|
1233
|
-
}
|
|
1234
|
-
}
|
|
1235
|
-
function matchesPattern(key, pattern) {
|
|
1236
|
-
const regex = globToRegex(pattern);
|
|
1237
|
-
return regex.test(key);
|
|
1238
|
-
}
|
|
1239
|
-
var MAX_PATTERN_LENGTH;
|
|
1240
|
-
var MAX_WILDCARDS;
|
|
1241
|
-
var REGEX_SPECIAL_CHARS;
|
|
1242
|
-
var init_pattern = __esm({
|
|
1243
|
-
"libs/utils/src/storage/utils/pattern.ts"() {
|
|
1244
|
-
"use strict";
|
|
1245
|
-
init_errors();
|
|
1246
|
-
MAX_PATTERN_LENGTH = 500;
|
|
1247
|
-
MAX_WILDCARDS = 20;
|
|
1248
|
-
REGEX_SPECIAL_CHARS = /[.+^${}()|[\]\\]/g;
|
|
1249
|
-
}
|
|
1250
|
-
});
|
|
1251
1264
|
var DEFAULT_SWEEP_INTERVAL_SECONDS;
|
|
1252
1265
|
var MAX_TIMEOUT_MS;
|
|
1253
1266
|
var MemoryStorageAdapter;
|
|
1254
1267
|
var init_memory = __esm({
|
|
1255
1268
|
"libs/utils/src/storage/adapters/memory.ts"() {
|
|
1256
1269
|
"use strict";
|
|
1257
|
-
init_base();
|
|
1258
1270
|
init_errors();
|
|
1259
1271
|
init_pattern();
|
|
1260
1272
|
init_ttl();
|
|
1273
|
+
init_base();
|
|
1261
1274
|
DEFAULT_SWEEP_INTERVAL_SECONDS = 60;
|
|
1262
1275
|
MAX_TIMEOUT_MS = 2147483647;
|
|
1263
1276
|
MemoryStorageAdapter = class extends BaseStorageAdapter {
|
|
@@ -1349,6 +1362,12 @@ var init_memory = __esm({
|
|
|
1349
1362
|
this.ensureConnected();
|
|
1350
1363
|
return this.deleteEntry(key);
|
|
1351
1364
|
}
|
|
1365
|
+
async deleteIfEquals(key, expectedValue) {
|
|
1366
|
+
this.ensureConnected();
|
|
1367
|
+
const entry = this.store.get(key);
|
|
1368
|
+
if (!entry || isExpired(entry.expiresAt) || entry.value !== expectedValue) return false;
|
|
1369
|
+
return this.deleteEntry(key);
|
|
1370
|
+
}
|
|
1352
1371
|
async exists(key) {
|
|
1353
1372
|
this.ensureConnected();
|
|
1354
1373
|
const entry = this.store.get(key);
|
|
@@ -2726,6 +2745,13 @@ var init_utils = __esm({
|
|
|
2726
2745
|
init_ttl();
|
|
2727
2746
|
}
|
|
2728
2747
|
});
|
|
2748
|
+
var COMPARE_AND_DELETE_SCRIPT;
|
|
2749
|
+
var init_compare_and_delete = __esm({
|
|
2750
|
+
"libs/utils/src/storage/utils/compare-and-delete.ts"() {
|
|
2751
|
+
"use strict";
|
|
2752
|
+
COMPARE_AND_DELETE_SCRIPT = `if redis.call('GET', KEYS[1]) == ARGV[1] then return redis.call('DEL', KEYS[1]) end return 0`;
|
|
2753
|
+
}
|
|
2754
|
+
});
|
|
2729
2755
|
var redis_exports = {};
|
|
2730
2756
|
__export(redis_exports, {
|
|
2731
2757
|
RedisStorageAdapter: () => RedisStorageAdapter,
|
|
@@ -2768,6 +2794,7 @@ var init_redis = __esm({
|
|
|
2768
2794
|
init_errors();
|
|
2769
2795
|
init_redis_error_listener();
|
|
2770
2796
|
init_utils();
|
|
2797
|
+
init_compare_and_delete();
|
|
2771
2798
|
init_base();
|
|
2772
2799
|
RedisStorageAdapter = class extends BaseStorageAdapter {
|
|
2773
2800
|
backendName = "redis";
|
|
@@ -2922,6 +2949,15 @@ var init_redis = __esm({
|
|
|
2922
2949
|
const result = await this.getConnectedClient().del(this.prefixKey(key));
|
|
2923
2950
|
return result > 0;
|
|
2924
2951
|
}
|
|
2952
|
+
async deleteIfEquals(key, expectedValue) {
|
|
2953
|
+
const deleted = await this.getConnectedClient().eval(
|
|
2954
|
+
COMPARE_AND_DELETE_SCRIPT,
|
|
2955
|
+
1,
|
|
2956
|
+
this.prefixKey(key),
|
|
2957
|
+
expectedValue
|
|
2958
|
+
);
|
|
2959
|
+
return deleted === 1;
|
|
2960
|
+
}
|
|
2925
2961
|
async exists(key) {
|
|
2926
2962
|
const result = await this.getConnectedClient().exists(this.prefixKey(key));
|
|
2927
2963
|
return result > 0;
|
|
@@ -3128,9 +3164,12 @@ var vercel_kv_exports = {};
|
|
|
3128
3164
|
__export(vercel_kv_exports, {
|
|
3129
3165
|
VercelKvStorageAdapter: () => VercelKvStorageAdapter
|
|
3130
3166
|
});
|
|
3131
|
-
function
|
|
3167
|
+
async function loadVercelKv() {
|
|
3132
3168
|
try {
|
|
3133
|
-
|
|
3169
|
+
const mod = await import("@vercel/kv");
|
|
3170
|
+
const resolved = typeof mod.createClient === "function" ? mod : mod.default;
|
|
3171
|
+
if (!resolved || typeof resolved.createClient !== "function") throw new Error("createClient missing");
|
|
3172
|
+
return resolved;
|
|
3134
3173
|
} catch {
|
|
3135
3174
|
throw new Error("@vercel/kv is required for Vercel KV storage adapter. Install it with: npm install @vercel/kv");
|
|
3136
3175
|
}
|
|
@@ -3139,9 +3178,10 @@ var VercelKvStorageAdapter;
|
|
|
3139
3178
|
var init_vercel_kv = __esm({
|
|
3140
3179
|
"libs/utils/src/storage/adapters/vercel-kv.ts"() {
|
|
3141
3180
|
"use strict";
|
|
3142
|
-
init_base();
|
|
3143
3181
|
init_errors();
|
|
3182
|
+
init_compare_and_delete();
|
|
3144
3183
|
init_ttl();
|
|
3184
|
+
init_base();
|
|
3145
3185
|
VercelKvStorageAdapter = class extends BaseStorageAdapter {
|
|
3146
3186
|
backendName = "vercel-kv";
|
|
3147
3187
|
client;
|
|
@@ -3166,17 +3206,13 @@ var init_vercel_kv = __esm({
|
|
|
3166
3206
|
async connect() {
|
|
3167
3207
|
if (this.connected) return;
|
|
3168
3208
|
try {
|
|
3169
|
-
const { createClient
|
|
3170
|
-
|
|
3171
|
-
|
|
3172
|
-
|
|
3173
|
-
|
|
3174
|
-
const token = this.options.token;
|
|
3175
|
-
if (!url || !token) {
|
|
3176
|
-
throw new StorageConfigError("vercel-kv", "URL and token are required");
|
|
3177
|
-
}
|
|
3178
|
-
this.client = createClient({ url, token });
|
|
3209
|
+
const { createClient } = await loadVercelKv();
|
|
3210
|
+
const url = this.options.url;
|
|
3211
|
+
const token = this.options.token;
|
|
3212
|
+
if (!url || !token) {
|
|
3213
|
+
throw new StorageConfigError("vercel-kv", "URL and token are required");
|
|
3179
3214
|
}
|
|
3215
|
+
this.client = createClient({ url, token, cache: void 0, automaticDeserialization: false });
|
|
3180
3216
|
await this.client.exists("__healthcheck__");
|
|
3181
3217
|
this.connected = true;
|
|
3182
3218
|
} catch (e) {
|
|
@@ -3217,8 +3253,7 @@ var init_vercel_kv = __esm({
|
|
|
3217
3253
|
// Core Operations
|
|
3218
3254
|
// ============================================
|
|
3219
3255
|
async get(key) {
|
|
3220
|
-
|
|
3221
|
-
return result;
|
|
3256
|
+
return this.getConnectedClient().get(this.prefixKey(key));
|
|
3222
3257
|
}
|
|
3223
3258
|
async doSet(key, value, options) {
|
|
3224
3259
|
const client = this.getConnectedClient();
|
|
@@ -3238,6 +3273,14 @@ var init_vercel_kv = __esm({
|
|
|
3238
3273
|
const result = await this.getConnectedClient().del(this.prefixKey(key));
|
|
3239
3274
|
return result > 0;
|
|
3240
3275
|
}
|
|
3276
|
+
async deleteIfEquals(key, expectedValue) {
|
|
3277
|
+
const deleted = await this.getConnectedClient().eval(
|
|
3278
|
+
COMPARE_AND_DELETE_SCRIPT,
|
|
3279
|
+
[this.prefixKey(key)],
|
|
3280
|
+
[expectedValue]
|
|
3281
|
+
);
|
|
3282
|
+
return deleted === 1;
|
|
3283
|
+
}
|
|
3241
3284
|
async exists(key) {
|
|
3242
3285
|
const result = await this.getConnectedClient().exists(this.prefixKey(key));
|
|
3243
3286
|
return result > 0;
|
|
@@ -3354,9 +3397,10 @@ var UpstashStorageAdapter;
|
|
|
3354
3397
|
var init_upstash = __esm({
|
|
3355
3398
|
"libs/utils/src/storage/adapters/upstash.ts"() {
|
|
3356
3399
|
"use strict";
|
|
3357
|
-
init_base();
|
|
3358
3400
|
init_errors();
|
|
3401
|
+
init_compare_and_delete();
|
|
3359
3402
|
init_ttl();
|
|
3403
|
+
init_base();
|
|
3360
3404
|
PUBSUB_POLL_INTERVAL_MS = 100;
|
|
3361
3405
|
UpstashStorageAdapter = class extends BaseStorageAdapter {
|
|
3362
3406
|
backendName = "upstash";
|
|
@@ -3393,7 +3437,7 @@ var init_upstash = __esm({
|
|
|
3393
3437
|
if (!url || !token) {
|
|
3394
3438
|
throw new StorageConfigError("upstash", "URL and token are required");
|
|
3395
3439
|
}
|
|
3396
|
-
this.client = new Redis({ url, token });
|
|
3440
|
+
this.client = new Redis({ url, token, automaticDeserialization: false });
|
|
3397
3441
|
await this.client.exists("__healthcheck__");
|
|
3398
3442
|
this.connected = true;
|
|
3399
3443
|
} catch (e) {
|
|
@@ -3440,8 +3484,7 @@ var init_upstash = __esm({
|
|
|
3440
3484
|
// Core Operations
|
|
3441
3485
|
// ============================================
|
|
3442
3486
|
async get(key) {
|
|
3443
|
-
|
|
3444
|
-
return result;
|
|
3487
|
+
return this.getConnectedClient().get(this.prefixKey(key));
|
|
3445
3488
|
}
|
|
3446
3489
|
async doSet(key, value, options) {
|
|
3447
3490
|
const client = this.getConnectedClient();
|
|
@@ -3461,6 +3504,14 @@ var init_upstash = __esm({
|
|
|
3461
3504
|
const result = await this.getConnectedClient().del(this.prefixKey(key));
|
|
3462
3505
|
return result > 0;
|
|
3463
3506
|
}
|
|
3507
|
+
async deleteIfEquals(key, expectedValue) {
|
|
3508
|
+
const deleted = await this.getConnectedClient().eval(
|
|
3509
|
+
COMPARE_AND_DELETE_SCRIPT,
|
|
3510
|
+
[this.prefixKey(key)],
|
|
3511
|
+
[expectedValue]
|
|
3512
|
+
);
|
|
3513
|
+
return deleted === 1;
|
|
3514
|
+
}
|
|
3464
3515
|
async exists(key) {
|
|
3465
3516
|
const result = await this.getConnectedClient().exists(this.prefixKey(key));
|
|
3466
3517
|
return result > 0;
|
|
@@ -3649,7 +3700,9 @@ var init_cloudflare_kv = __esm({
|
|
|
3649
3700
|
constructor(options) {
|
|
3650
3701
|
super();
|
|
3651
3702
|
if (!options?.namespace) {
|
|
3652
|
-
throw new Error(
|
|
3703
|
+
throw new Error(
|
|
3704
|
+
"CloudflareKvStorageAdapter: a bound KV `namespace` is required (resolve it from the Worker `env`)."
|
|
3705
|
+
);
|
|
3653
3706
|
}
|
|
3654
3707
|
this.kv = options.namespace;
|
|
3655
3708
|
this.keyPrefix = options.keyPrefix ?? "";
|
|
@@ -3743,6 +3796,13 @@ var init_cloudflare_kv = __esm({
|
|
|
3743
3796
|
"Cloudflare KV has no atomic increment (a get+put is racy under eventual consistency). Use a Durable Object for atomic counters."
|
|
3744
3797
|
);
|
|
3745
3798
|
}
|
|
3799
|
+
async deleteIfEquals(_key, _expectedValue) {
|
|
3800
|
+
throw new StorageNotSupportedError(
|
|
3801
|
+
"deleteIfEquals",
|
|
3802
|
+
this.backendName,
|
|
3803
|
+
"Cloudflare KV has no compare-and-set; use a Durable Object for an atomic compare-and-delete."
|
|
3804
|
+
);
|
|
3805
|
+
}
|
|
3746
3806
|
// ── Pub/Sub (unsupported) ────────────────────────────────────────────────
|
|
3747
3807
|
getPubSubSuggestion() {
|
|
3748
3808
|
return "Cloudflare KV does not support pub/sub. Use a Durable Object (or Queues) for fan-out.";
|
|
@@ -3856,16 +3916,7 @@ function compileBlocks(entries, parseNetwork) {
|
|
|
3856
3916
|
}
|
|
3857
3917
|
init_fs2();
|
|
3858
3918
|
init_crypto();
|
|
3859
|
-
|
|
3860
|
-
os: z3.array(z3.string().min(1)).optional(),
|
|
3861
|
-
platform: z3.array(z3.string().min(1)).optional(),
|
|
3862
|
-
runtime: z3.array(z3.string().min(1)).optional(),
|
|
3863
|
-
deployment: z3.array(z3.string().min(1)).optional(),
|
|
3864
|
-
provider: z3.array(z3.string().min(1)).optional(),
|
|
3865
|
-
target: z3.array(z3.string().min(1)).optional(),
|
|
3866
|
-
surface: z3.array(z3.enum(["mcp", "cli", "http-trigger", "job", "agent"])).optional(),
|
|
3867
|
-
env: z3.array(z3.string().min(1)).optional()
|
|
3868
|
-
}).strict();
|
|
3919
|
+
init_errors();
|
|
3869
3920
|
init_errors();
|
|
3870
3921
|
init_memory();
|
|
3871
3922
|
init_redis_error_listener();
|
|
@@ -4838,11 +4889,11 @@ GraphDataProvider = __decorateClass([
|
|
|
4838
4889
|
], GraphDataProvider);
|
|
4839
4890
|
|
|
4840
4891
|
// plugins/plugin-dashboard/src/tools/graph.tool.ts
|
|
4841
|
-
import { z as
|
|
4892
|
+
import { z as z3 } from "@frontmcp/lazy-zod";
|
|
4842
4893
|
import { Tool, ToolContext } from "@frontmcp/sdk";
|
|
4843
4894
|
var graphToolInputSchema = {
|
|
4844
|
-
includeSchemas:
|
|
4845
|
-
refresh:
|
|
4895
|
+
includeSchemas: z3.boolean().optional().default(false).describe("Include full input/output schemas in the response"),
|
|
4896
|
+
refresh: z3.boolean().optional().default(false).describe("Force refresh the graph data (bypass cache)")
|
|
4846
4897
|
};
|
|
4847
4898
|
var GraphTool = class extends ToolContext {
|
|
4848
4899
|
async execute(input) {
|
|
@@ -4880,7 +4931,7 @@ GraphTool = __decorateClass([
|
|
|
4880
4931
|
], GraphTool);
|
|
4881
4932
|
|
|
4882
4933
|
// plugins/plugin-dashboard/src/tools/list-resources.tool.ts
|
|
4883
|
-
import { z as
|
|
4934
|
+
import { z as z4 } from "@frontmcp/lazy-zod";
|
|
4884
4935
|
import { Tool as Tool2, ToolContext as ToolContext2 } from "@frontmcp/sdk";
|
|
4885
4936
|
|
|
4886
4937
|
// plugins/plugin-dashboard/src/shared/safe-regex.ts
|
|
@@ -4899,20 +4950,20 @@ function safeRegex(pattern) {
|
|
|
4899
4950
|
|
|
4900
4951
|
// plugins/plugin-dashboard/src/tools/list-resources.tool.ts
|
|
4901
4952
|
var listResourcesInputSchema = {
|
|
4902
|
-
filter:
|
|
4903
|
-
includeTemplates:
|
|
4953
|
+
filter: z4.string().optional().describe("Filter resources by name or URI pattern (regex supported)"),
|
|
4954
|
+
includeTemplates: z4.boolean().default(true).describe("Include resource templates in the response")
|
|
4904
4955
|
};
|
|
4905
|
-
var listResourcesOutputSchema =
|
|
4906
|
-
resources:
|
|
4907
|
-
|
|
4908
|
-
name:
|
|
4909
|
-
uri:
|
|
4910
|
-
description:
|
|
4911
|
-
mimeType:
|
|
4912
|
-
isTemplate:
|
|
4956
|
+
var listResourcesOutputSchema = z4.object({
|
|
4957
|
+
resources: z4.array(
|
|
4958
|
+
z4.object({
|
|
4959
|
+
name: z4.string(),
|
|
4960
|
+
uri: z4.string(),
|
|
4961
|
+
description: z4.string().optional(),
|
|
4962
|
+
mimeType: z4.string().optional(),
|
|
4963
|
+
isTemplate: z4.boolean()
|
|
4913
4964
|
})
|
|
4914
4965
|
),
|
|
4915
|
-
count:
|
|
4966
|
+
count: z4.number()
|
|
4916
4967
|
});
|
|
4917
4968
|
var ListResourcesTool = class extends ToolContext2 {
|
|
4918
4969
|
async execute(input) {
|
|
@@ -4974,25 +5025,25 @@ ListResourcesTool = __decorateClass([
|
|
|
4974
5025
|
], ListResourcesTool);
|
|
4975
5026
|
|
|
4976
5027
|
// plugins/plugin-dashboard/src/tools/list-tools.tool.ts
|
|
4977
|
-
import { z as
|
|
5028
|
+
import { z as z5 } from "@frontmcp/lazy-zod";
|
|
4978
5029
|
import { Tool as Tool3, ToolContext as ToolContext3 } from "@frontmcp/sdk";
|
|
4979
5030
|
var listToolsInputSchema = {
|
|
4980
|
-
filter:
|
|
4981
|
-
includePlugins:
|
|
4982
|
-
includeSchemas:
|
|
5031
|
+
filter: z5.string().optional().describe("Filter tools by name pattern (regex supported)"),
|
|
5032
|
+
includePlugins: z5.boolean().default(true).describe("Include tools from plugins"),
|
|
5033
|
+
includeSchemas: z5.boolean().default(false).describe("Include input/output schemas in the response")
|
|
4983
5034
|
};
|
|
4984
|
-
var listToolsOutputSchema =
|
|
4985
|
-
tools:
|
|
4986
|
-
|
|
4987
|
-
name:
|
|
4988
|
-
fullName:
|
|
4989
|
-
description:
|
|
4990
|
-
tags:
|
|
4991
|
-
inputSchema:
|
|
4992
|
-
outputSchema:
|
|
5035
|
+
var listToolsOutputSchema = z5.object({
|
|
5036
|
+
tools: z5.array(
|
|
5037
|
+
z5.object({
|
|
5038
|
+
name: z5.string(),
|
|
5039
|
+
fullName: z5.string(),
|
|
5040
|
+
description: z5.string().optional(),
|
|
5041
|
+
tags: z5.array(z5.string()).optional(),
|
|
5042
|
+
inputSchema: z5.unknown().optional(),
|
|
5043
|
+
outputSchema: z5.unknown().optional()
|
|
4993
5044
|
})
|
|
4994
5045
|
),
|
|
4995
|
-
count:
|
|
5046
|
+
count: z5.number()
|
|
4996
5047
|
});
|
|
4997
5048
|
var ListToolsTool = class extends ToolContext3 {
|
|
4998
5049
|
async execute(input) {
|
package/esm/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@frontmcp/plugin-dashboard",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.9.1-rc.1",
|
|
4
4
|
"description": "Dashboard plugin for FrontMCP - visual monitoring and introspection of MCP servers",
|
|
5
5
|
"author": "AgentFront <info@agentfront.dev>",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -47,12 +47,12 @@
|
|
|
47
47
|
}
|
|
48
48
|
},
|
|
49
49
|
"dependencies": {
|
|
50
|
-
"@frontmcp/sdk": "1.
|
|
50
|
+
"@frontmcp/sdk": "1.9.1-rc.1"
|
|
51
51
|
},
|
|
52
52
|
"devDependencies": {
|
|
53
53
|
"reflect-metadata": "^0.2.2"
|
|
54
54
|
},
|
|
55
55
|
"peerDependencies": {
|
|
56
|
-
"@frontmcp/lazy-zod": "1.
|
|
56
|
+
"@frontmcp/lazy-zod": "1.9.1-rc.1"
|
|
57
57
|
}
|
|
58
58
|
}
|
package/index.js
CHANGED
|
@@ -454,7 +454,6 @@ var import_utils = require("@noble/hashes/utils.js");
|
|
|
454
454
|
var import_aes = require("@noble/ciphers/aes.js");
|
|
455
455
|
var import_crypto_provider = __toESM(require_node(), 1);
|
|
456
456
|
var import_ast = require("@enclave-vm/ast");
|
|
457
|
-
var import_lazy_zod4 = require("@frontmcp/lazy-zod");
|
|
458
457
|
var import_meta = {};
|
|
459
458
|
var __frontmcpModule = typeof process !== "undefined" && typeof process.getBuiltinModule === "function" ? process.getBuiltinModule("module") : void 0;
|
|
460
459
|
var require2 = __frontmcpModule ? __frontmcpModule.createRequire(import_meta.url || "file:///") : void 0;
|
|
@@ -793,8 +792,8 @@ var init_key_persistence = __esm({
|
|
|
793
792
|
*/
|
|
794
793
|
async get(kid) {
|
|
795
794
|
if (this.enableCache) {
|
|
796
|
-
const
|
|
797
|
-
if (
|
|
795
|
+
const cached = this.cache.get(kid);
|
|
796
|
+
if (cached) return cached;
|
|
798
797
|
}
|
|
799
798
|
const raw = await this.storage.get(kid);
|
|
800
799
|
if (!raw) return null;
|
|
@@ -1050,6 +1049,61 @@ var init_errors = __esm({
|
|
|
1050
1049
|
};
|
|
1051
1050
|
}
|
|
1052
1051
|
});
|
|
1052
|
+
function globToRegex(pattern) {
|
|
1053
|
+
if (pattern.length > MAX_PATTERN_LENGTH) {
|
|
1054
|
+
throw new StoragePatternError(
|
|
1055
|
+
pattern.substring(0, 50) + "...",
|
|
1056
|
+
`Pattern exceeds maximum length of ${MAX_PATTERN_LENGTH} characters`
|
|
1057
|
+
);
|
|
1058
|
+
}
|
|
1059
|
+
const wildcardCount = (pattern.match(/[*?]/g) || []).length;
|
|
1060
|
+
if (wildcardCount > MAX_WILDCARDS) {
|
|
1061
|
+
throw new StoragePatternError(pattern, `Pattern has too many wildcards (max: ${MAX_WILDCARDS})`);
|
|
1062
|
+
}
|
|
1063
|
+
if (pattern === "" || pattern === "*") {
|
|
1064
|
+
return /^.*$/;
|
|
1065
|
+
}
|
|
1066
|
+
let regexStr = "^";
|
|
1067
|
+
let prevChar = "";
|
|
1068
|
+
for (let i = 0; i < pattern.length; i++) {
|
|
1069
|
+
const char = pattern[i];
|
|
1070
|
+
switch (char) {
|
|
1071
|
+
case "*":
|
|
1072
|
+
if (prevChar !== "*") {
|
|
1073
|
+
regexStr += ".*";
|
|
1074
|
+
}
|
|
1075
|
+
break;
|
|
1076
|
+
case "?":
|
|
1077
|
+
regexStr += ".";
|
|
1078
|
+
break;
|
|
1079
|
+
default:
|
|
1080
|
+
regexStr += char.replace(REGEX_SPECIAL_CHARS, "\\$&");
|
|
1081
|
+
}
|
|
1082
|
+
prevChar = char;
|
|
1083
|
+
}
|
|
1084
|
+
regexStr += "$";
|
|
1085
|
+
try {
|
|
1086
|
+
return new RegExp(regexStr);
|
|
1087
|
+
} catch {
|
|
1088
|
+
throw new StoragePatternError(pattern, "Failed to compile pattern to regex");
|
|
1089
|
+
}
|
|
1090
|
+
}
|
|
1091
|
+
function matchesPattern(key, pattern) {
|
|
1092
|
+
const regex = globToRegex(pattern);
|
|
1093
|
+
return regex.test(key);
|
|
1094
|
+
}
|
|
1095
|
+
var MAX_PATTERN_LENGTH;
|
|
1096
|
+
var MAX_WILDCARDS;
|
|
1097
|
+
var REGEX_SPECIAL_CHARS;
|
|
1098
|
+
var init_pattern = __esm({
|
|
1099
|
+
"libs/utils/src/storage/utils/pattern.ts"() {
|
|
1100
|
+
"use strict";
|
|
1101
|
+
init_errors();
|
|
1102
|
+
MAX_PATTERN_LENGTH = 500;
|
|
1103
|
+
MAX_WILDCARDS = 20;
|
|
1104
|
+
REGEX_SPECIAL_CHARS = /[.+^${}()|[\]\\]/g;
|
|
1105
|
+
}
|
|
1106
|
+
});
|
|
1053
1107
|
function validateTTL(ttlSeconds) {
|
|
1054
1108
|
if (typeof ttlSeconds !== "number") {
|
|
1055
1109
|
throw new StorageTTLError(ttlSeconds, `TTL must be a number, got ${typeof ttlSeconds}`);
|
|
@@ -1158,6 +1212,17 @@ var init_base = __esm({
|
|
|
1158
1212
|
const matchedKeys = await this.keys(pattern);
|
|
1159
1213
|
return matchedKeys.length;
|
|
1160
1214
|
}
|
|
1215
|
+
/**
|
|
1216
|
+
* Default: not supported, since a read followed by a delete is not atomic.
|
|
1217
|
+
* Override in adapters whose backend can compare and delete in one step.
|
|
1218
|
+
*/
|
|
1219
|
+
async deleteIfEquals(_key, _expectedValue) {
|
|
1220
|
+
throw new StorageNotSupportedError(
|
|
1221
|
+
"deleteIfEquals",
|
|
1222
|
+
this.backendName,
|
|
1223
|
+
"Use the memory, Redis, Upstash or Vercel KV adapter for an atomic compare-and-delete."
|
|
1224
|
+
);
|
|
1225
|
+
}
|
|
1161
1226
|
// ============================================
|
|
1162
1227
|
// Pub/Sub (default: not supported)
|
|
1163
1228
|
// ============================================
|
|
@@ -1205,71 +1270,16 @@ var init_base = __esm({
|
|
|
1205
1270
|
};
|
|
1206
1271
|
}
|
|
1207
1272
|
});
|
|
1208
|
-
function globToRegex(pattern) {
|
|
1209
|
-
if (pattern.length > MAX_PATTERN_LENGTH) {
|
|
1210
|
-
throw new StoragePatternError(
|
|
1211
|
-
pattern.substring(0, 50) + "...",
|
|
1212
|
-
`Pattern exceeds maximum length of ${MAX_PATTERN_LENGTH} characters`
|
|
1213
|
-
);
|
|
1214
|
-
}
|
|
1215
|
-
const wildcardCount = (pattern.match(/[*?]/g) || []).length;
|
|
1216
|
-
if (wildcardCount > MAX_WILDCARDS) {
|
|
1217
|
-
throw new StoragePatternError(pattern, `Pattern has too many wildcards (max: ${MAX_WILDCARDS})`);
|
|
1218
|
-
}
|
|
1219
|
-
if (pattern === "" || pattern === "*") {
|
|
1220
|
-
return /^.*$/;
|
|
1221
|
-
}
|
|
1222
|
-
let regexStr = "^";
|
|
1223
|
-
let prevChar = "";
|
|
1224
|
-
for (let i = 0; i < pattern.length; i++) {
|
|
1225
|
-
const char = pattern[i];
|
|
1226
|
-
switch (char) {
|
|
1227
|
-
case "*":
|
|
1228
|
-
if (prevChar !== "*") {
|
|
1229
|
-
regexStr += ".*";
|
|
1230
|
-
}
|
|
1231
|
-
break;
|
|
1232
|
-
case "?":
|
|
1233
|
-
regexStr += ".";
|
|
1234
|
-
break;
|
|
1235
|
-
default:
|
|
1236
|
-
regexStr += char.replace(REGEX_SPECIAL_CHARS, "\\$&");
|
|
1237
|
-
}
|
|
1238
|
-
prevChar = char;
|
|
1239
|
-
}
|
|
1240
|
-
regexStr += "$";
|
|
1241
|
-
try {
|
|
1242
|
-
return new RegExp(regexStr);
|
|
1243
|
-
} catch {
|
|
1244
|
-
throw new StoragePatternError(pattern, "Failed to compile pattern to regex");
|
|
1245
|
-
}
|
|
1246
|
-
}
|
|
1247
|
-
function matchesPattern(key, pattern) {
|
|
1248
|
-
const regex = globToRegex(pattern);
|
|
1249
|
-
return regex.test(key);
|
|
1250
|
-
}
|
|
1251
|
-
var MAX_PATTERN_LENGTH;
|
|
1252
|
-
var MAX_WILDCARDS;
|
|
1253
|
-
var REGEX_SPECIAL_CHARS;
|
|
1254
|
-
var init_pattern = __esm({
|
|
1255
|
-
"libs/utils/src/storage/utils/pattern.ts"() {
|
|
1256
|
-
"use strict";
|
|
1257
|
-
init_errors();
|
|
1258
|
-
MAX_PATTERN_LENGTH = 500;
|
|
1259
|
-
MAX_WILDCARDS = 20;
|
|
1260
|
-
REGEX_SPECIAL_CHARS = /[.+^${}()|[\]\\]/g;
|
|
1261
|
-
}
|
|
1262
|
-
});
|
|
1263
1273
|
var DEFAULT_SWEEP_INTERVAL_SECONDS;
|
|
1264
1274
|
var MAX_TIMEOUT_MS;
|
|
1265
1275
|
var MemoryStorageAdapter;
|
|
1266
1276
|
var init_memory = __esm({
|
|
1267
1277
|
"libs/utils/src/storage/adapters/memory.ts"() {
|
|
1268
1278
|
"use strict";
|
|
1269
|
-
init_base();
|
|
1270
1279
|
init_errors();
|
|
1271
1280
|
init_pattern();
|
|
1272
1281
|
init_ttl();
|
|
1282
|
+
init_base();
|
|
1273
1283
|
DEFAULT_SWEEP_INTERVAL_SECONDS = 60;
|
|
1274
1284
|
MAX_TIMEOUT_MS = 2147483647;
|
|
1275
1285
|
MemoryStorageAdapter = class extends BaseStorageAdapter {
|
|
@@ -1361,6 +1371,12 @@ var init_memory = __esm({
|
|
|
1361
1371
|
this.ensureConnected();
|
|
1362
1372
|
return this.deleteEntry(key);
|
|
1363
1373
|
}
|
|
1374
|
+
async deleteIfEquals(key, expectedValue) {
|
|
1375
|
+
this.ensureConnected();
|
|
1376
|
+
const entry = this.store.get(key);
|
|
1377
|
+
if (!entry || isExpired(entry.expiresAt) || entry.value !== expectedValue) return false;
|
|
1378
|
+
return this.deleteEntry(key);
|
|
1379
|
+
}
|
|
1364
1380
|
async exists(key) {
|
|
1365
1381
|
this.ensureConnected();
|
|
1366
1382
|
const entry = this.store.get(key);
|
|
@@ -2738,6 +2754,13 @@ var init_utils = __esm({
|
|
|
2738
2754
|
init_ttl();
|
|
2739
2755
|
}
|
|
2740
2756
|
});
|
|
2757
|
+
var COMPARE_AND_DELETE_SCRIPT;
|
|
2758
|
+
var init_compare_and_delete = __esm({
|
|
2759
|
+
"libs/utils/src/storage/utils/compare-and-delete.ts"() {
|
|
2760
|
+
"use strict";
|
|
2761
|
+
COMPARE_AND_DELETE_SCRIPT = `if redis.call('GET', KEYS[1]) == ARGV[1] then return redis.call('DEL', KEYS[1]) end return 0`;
|
|
2762
|
+
}
|
|
2763
|
+
});
|
|
2741
2764
|
var redis_exports = {};
|
|
2742
2765
|
__export2(redis_exports, {
|
|
2743
2766
|
RedisStorageAdapter: () => RedisStorageAdapter,
|
|
@@ -2780,6 +2803,7 @@ var init_redis = __esm({
|
|
|
2780
2803
|
init_errors();
|
|
2781
2804
|
init_redis_error_listener();
|
|
2782
2805
|
init_utils();
|
|
2806
|
+
init_compare_and_delete();
|
|
2783
2807
|
init_base();
|
|
2784
2808
|
RedisStorageAdapter = class extends BaseStorageAdapter {
|
|
2785
2809
|
backendName = "redis";
|
|
@@ -2934,6 +2958,15 @@ var init_redis = __esm({
|
|
|
2934
2958
|
const result = await this.getConnectedClient().del(this.prefixKey(key));
|
|
2935
2959
|
return result > 0;
|
|
2936
2960
|
}
|
|
2961
|
+
async deleteIfEquals(key, expectedValue) {
|
|
2962
|
+
const deleted = await this.getConnectedClient().eval(
|
|
2963
|
+
COMPARE_AND_DELETE_SCRIPT,
|
|
2964
|
+
1,
|
|
2965
|
+
this.prefixKey(key),
|
|
2966
|
+
expectedValue
|
|
2967
|
+
);
|
|
2968
|
+
return deleted === 1;
|
|
2969
|
+
}
|
|
2937
2970
|
async exists(key) {
|
|
2938
2971
|
const result = await this.getConnectedClient().exists(this.prefixKey(key));
|
|
2939
2972
|
return result > 0;
|
|
@@ -3140,9 +3173,12 @@ var vercel_kv_exports = {};
|
|
|
3140
3173
|
__export2(vercel_kv_exports, {
|
|
3141
3174
|
VercelKvStorageAdapter: () => VercelKvStorageAdapter
|
|
3142
3175
|
});
|
|
3143
|
-
function
|
|
3176
|
+
async function loadVercelKv() {
|
|
3144
3177
|
try {
|
|
3145
|
-
|
|
3178
|
+
const mod = await import("@vercel/kv");
|
|
3179
|
+
const resolved = typeof mod.createClient === "function" ? mod : mod.default;
|
|
3180
|
+
if (!resolved || typeof resolved.createClient !== "function") throw new Error("createClient missing");
|
|
3181
|
+
return resolved;
|
|
3146
3182
|
} catch {
|
|
3147
3183
|
throw new Error("@vercel/kv is required for Vercel KV storage adapter. Install it with: npm install @vercel/kv");
|
|
3148
3184
|
}
|
|
@@ -3151,9 +3187,10 @@ var VercelKvStorageAdapter;
|
|
|
3151
3187
|
var init_vercel_kv = __esm({
|
|
3152
3188
|
"libs/utils/src/storage/adapters/vercel-kv.ts"() {
|
|
3153
3189
|
"use strict";
|
|
3154
|
-
init_base();
|
|
3155
3190
|
init_errors();
|
|
3191
|
+
init_compare_and_delete();
|
|
3156
3192
|
init_ttl();
|
|
3193
|
+
init_base();
|
|
3157
3194
|
VercelKvStorageAdapter = class extends BaseStorageAdapter {
|
|
3158
3195
|
backendName = "vercel-kv";
|
|
3159
3196
|
client;
|
|
@@ -3178,17 +3215,13 @@ var init_vercel_kv = __esm({
|
|
|
3178
3215
|
async connect() {
|
|
3179
3216
|
if (this.connected) return;
|
|
3180
3217
|
try {
|
|
3181
|
-
const { createClient
|
|
3182
|
-
|
|
3183
|
-
|
|
3184
|
-
|
|
3185
|
-
|
|
3186
|
-
const token = this.options.token;
|
|
3187
|
-
if (!url || !token) {
|
|
3188
|
-
throw new StorageConfigError("vercel-kv", "URL and token are required");
|
|
3189
|
-
}
|
|
3190
|
-
this.client = createClient({ url, token });
|
|
3218
|
+
const { createClient } = await loadVercelKv();
|
|
3219
|
+
const url = this.options.url;
|
|
3220
|
+
const token = this.options.token;
|
|
3221
|
+
if (!url || !token) {
|
|
3222
|
+
throw new StorageConfigError("vercel-kv", "URL and token are required");
|
|
3191
3223
|
}
|
|
3224
|
+
this.client = createClient({ url, token, cache: void 0, automaticDeserialization: false });
|
|
3192
3225
|
await this.client.exists("__healthcheck__");
|
|
3193
3226
|
this.connected = true;
|
|
3194
3227
|
} catch (e) {
|
|
@@ -3229,8 +3262,7 @@ var init_vercel_kv = __esm({
|
|
|
3229
3262
|
// Core Operations
|
|
3230
3263
|
// ============================================
|
|
3231
3264
|
async get(key) {
|
|
3232
|
-
|
|
3233
|
-
return result;
|
|
3265
|
+
return this.getConnectedClient().get(this.prefixKey(key));
|
|
3234
3266
|
}
|
|
3235
3267
|
async doSet(key, value, options) {
|
|
3236
3268
|
const client = this.getConnectedClient();
|
|
@@ -3250,6 +3282,14 @@ var init_vercel_kv = __esm({
|
|
|
3250
3282
|
const result = await this.getConnectedClient().del(this.prefixKey(key));
|
|
3251
3283
|
return result > 0;
|
|
3252
3284
|
}
|
|
3285
|
+
async deleteIfEquals(key, expectedValue) {
|
|
3286
|
+
const deleted = await this.getConnectedClient().eval(
|
|
3287
|
+
COMPARE_AND_DELETE_SCRIPT,
|
|
3288
|
+
[this.prefixKey(key)],
|
|
3289
|
+
[expectedValue]
|
|
3290
|
+
);
|
|
3291
|
+
return deleted === 1;
|
|
3292
|
+
}
|
|
3253
3293
|
async exists(key) {
|
|
3254
3294
|
const result = await this.getConnectedClient().exists(this.prefixKey(key));
|
|
3255
3295
|
return result > 0;
|
|
@@ -3366,9 +3406,10 @@ var UpstashStorageAdapter;
|
|
|
3366
3406
|
var init_upstash = __esm({
|
|
3367
3407
|
"libs/utils/src/storage/adapters/upstash.ts"() {
|
|
3368
3408
|
"use strict";
|
|
3369
|
-
init_base();
|
|
3370
3409
|
init_errors();
|
|
3410
|
+
init_compare_and_delete();
|
|
3371
3411
|
init_ttl();
|
|
3412
|
+
init_base();
|
|
3372
3413
|
PUBSUB_POLL_INTERVAL_MS = 100;
|
|
3373
3414
|
UpstashStorageAdapter = class extends BaseStorageAdapter {
|
|
3374
3415
|
backendName = "upstash";
|
|
@@ -3405,7 +3446,7 @@ var init_upstash = __esm({
|
|
|
3405
3446
|
if (!url || !token) {
|
|
3406
3447
|
throw new StorageConfigError("upstash", "URL and token are required");
|
|
3407
3448
|
}
|
|
3408
|
-
this.client = new Redis({ url, token });
|
|
3449
|
+
this.client = new Redis({ url, token, automaticDeserialization: false });
|
|
3409
3450
|
await this.client.exists("__healthcheck__");
|
|
3410
3451
|
this.connected = true;
|
|
3411
3452
|
} catch (e) {
|
|
@@ -3452,8 +3493,7 @@ var init_upstash = __esm({
|
|
|
3452
3493
|
// Core Operations
|
|
3453
3494
|
// ============================================
|
|
3454
3495
|
async get(key) {
|
|
3455
|
-
|
|
3456
|
-
return result;
|
|
3496
|
+
return this.getConnectedClient().get(this.prefixKey(key));
|
|
3457
3497
|
}
|
|
3458
3498
|
async doSet(key, value, options) {
|
|
3459
3499
|
const client = this.getConnectedClient();
|
|
@@ -3473,6 +3513,14 @@ var init_upstash = __esm({
|
|
|
3473
3513
|
const result = await this.getConnectedClient().del(this.prefixKey(key));
|
|
3474
3514
|
return result > 0;
|
|
3475
3515
|
}
|
|
3516
|
+
async deleteIfEquals(key, expectedValue) {
|
|
3517
|
+
const deleted = await this.getConnectedClient().eval(
|
|
3518
|
+
COMPARE_AND_DELETE_SCRIPT,
|
|
3519
|
+
[this.prefixKey(key)],
|
|
3520
|
+
[expectedValue]
|
|
3521
|
+
);
|
|
3522
|
+
return deleted === 1;
|
|
3523
|
+
}
|
|
3476
3524
|
async exists(key) {
|
|
3477
3525
|
const result = await this.getConnectedClient().exists(this.prefixKey(key));
|
|
3478
3526
|
return result > 0;
|
|
@@ -3661,7 +3709,9 @@ var init_cloudflare_kv = __esm({
|
|
|
3661
3709
|
constructor(options) {
|
|
3662
3710
|
super();
|
|
3663
3711
|
if (!options?.namespace) {
|
|
3664
|
-
throw new Error(
|
|
3712
|
+
throw new Error(
|
|
3713
|
+
"CloudflareKvStorageAdapter: a bound KV `namespace` is required (resolve it from the Worker `env`)."
|
|
3714
|
+
);
|
|
3665
3715
|
}
|
|
3666
3716
|
this.kv = options.namespace;
|
|
3667
3717
|
this.keyPrefix = options.keyPrefix ?? "";
|
|
@@ -3755,6 +3805,13 @@ var init_cloudflare_kv = __esm({
|
|
|
3755
3805
|
"Cloudflare KV has no atomic increment (a get+put is racy under eventual consistency). Use a Durable Object for atomic counters."
|
|
3756
3806
|
);
|
|
3757
3807
|
}
|
|
3808
|
+
async deleteIfEquals(_key, _expectedValue) {
|
|
3809
|
+
throw new StorageNotSupportedError(
|
|
3810
|
+
"deleteIfEquals",
|
|
3811
|
+
this.backendName,
|
|
3812
|
+
"Cloudflare KV has no compare-and-set; use a Durable Object for an atomic compare-and-delete."
|
|
3813
|
+
);
|
|
3814
|
+
}
|
|
3758
3815
|
// ── Pub/Sub (unsupported) ────────────────────────────────────────────────
|
|
3759
3816
|
getPubSubSuggestion() {
|
|
3760
3817
|
return "Cloudflare KV does not support pub/sub. Use a Durable Object (or Queues) for fan-out.";
|
|
@@ -3868,16 +3925,7 @@ function compileBlocks(entries, parseNetwork) {
|
|
|
3868
3925
|
}
|
|
3869
3926
|
init_fs2();
|
|
3870
3927
|
init_crypto();
|
|
3871
|
-
|
|
3872
|
-
os: import_lazy_zod4.z.array(import_lazy_zod4.z.string().min(1)).optional(),
|
|
3873
|
-
platform: import_lazy_zod4.z.array(import_lazy_zod4.z.string().min(1)).optional(),
|
|
3874
|
-
runtime: import_lazy_zod4.z.array(import_lazy_zod4.z.string().min(1)).optional(),
|
|
3875
|
-
deployment: import_lazy_zod4.z.array(import_lazy_zod4.z.string().min(1)).optional(),
|
|
3876
|
-
provider: import_lazy_zod4.z.array(import_lazy_zod4.z.string().min(1)).optional(),
|
|
3877
|
-
target: import_lazy_zod4.z.array(import_lazy_zod4.z.string().min(1)).optional(),
|
|
3878
|
-
surface: import_lazy_zod4.z.array(import_lazy_zod4.z.enum(["mcp", "cli", "http-trigger", "job", "agent"])).optional(),
|
|
3879
|
-
env: import_lazy_zod4.z.array(import_lazy_zod4.z.string().min(1)).optional()
|
|
3880
|
-
}).strict();
|
|
3928
|
+
init_errors();
|
|
3881
3929
|
init_errors();
|
|
3882
3930
|
init_memory();
|
|
3883
3931
|
init_redis_error_listener();
|
|
@@ -4850,11 +4898,11 @@ GraphDataProvider = __decorateClass([
|
|
|
4850
4898
|
], GraphDataProvider);
|
|
4851
4899
|
|
|
4852
4900
|
// plugins/plugin-dashboard/src/tools/graph.tool.ts
|
|
4853
|
-
var
|
|
4901
|
+
var import_lazy_zod4 = require("@frontmcp/lazy-zod");
|
|
4854
4902
|
var import_sdk4 = require("@frontmcp/sdk");
|
|
4855
4903
|
var graphToolInputSchema = {
|
|
4856
|
-
includeSchemas:
|
|
4857
|
-
refresh:
|
|
4904
|
+
includeSchemas: import_lazy_zod4.z.boolean().optional().default(false).describe("Include full input/output schemas in the response"),
|
|
4905
|
+
refresh: import_lazy_zod4.z.boolean().optional().default(false).describe("Force refresh the graph data (bypass cache)")
|
|
4858
4906
|
};
|
|
4859
4907
|
var GraphTool = class extends import_sdk4.ToolContext {
|
|
4860
4908
|
async execute(input) {
|
|
@@ -4892,7 +4940,7 @@ GraphTool = __decorateClass([
|
|
|
4892
4940
|
], GraphTool);
|
|
4893
4941
|
|
|
4894
4942
|
// plugins/plugin-dashboard/src/tools/list-resources.tool.ts
|
|
4895
|
-
var
|
|
4943
|
+
var import_lazy_zod5 = require("@frontmcp/lazy-zod");
|
|
4896
4944
|
var import_sdk5 = require("@frontmcp/sdk");
|
|
4897
4945
|
|
|
4898
4946
|
// plugins/plugin-dashboard/src/shared/safe-regex.ts
|
|
@@ -4911,20 +4959,20 @@ function safeRegex(pattern) {
|
|
|
4911
4959
|
|
|
4912
4960
|
// plugins/plugin-dashboard/src/tools/list-resources.tool.ts
|
|
4913
4961
|
var listResourcesInputSchema = {
|
|
4914
|
-
filter:
|
|
4915
|
-
includeTemplates:
|
|
4962
|
+
filter: import_lazy_zod5.z.string().optional().describe("Filter resources by name or URI pattern (regex supported)"),
|
|
4963
|
+
includeTemplates: import_lazy_zod5.z.boolean().default(true).describe("Include resource templates in the response")
|
|
4916
4964
|
};
|
|
4917
|
-
var listResourcesOutputSchema =
|
|
4918
|
-
resources:
|
|
4919
|
-
|
|
4920
|
-
name:
|
|
4921
|
-
uri:
|
|
4922
|
-
description:
|
|
4923
|
-
mimeType:
|
|
4924
|
-
isTemplate:
|
|
4965
|
+
var listResourcesOutputSchema = import_lazy_zod5.z.object({
|
|
4966
|
+
resources: import_lazy_zod5.z.array(
|
|
4967
|
+
import_lazy_zod5.z.object({
|
|
4968
|
+
name: import_lazy_zod5.z.string(),
|
|
4969
|
+
uri: import_lazy_zod5.z.string(),
|
|
4970
|
+
description: import_lazy_zod5.z.string().optional(),
|
|
4971
|
+
mimeType: import_lazy_zod5.z.string().optional(),
|
|
4972
|
+
isTemplate: import_lazy_zod5.z.boolean()
|
|
4925
4973
|
})
|
|
4926
4974
|
),
|
|
4927
|
-
count:
|
|
4975
|
+
count: import_lazy_zod5.z.number()
|
|
4928
4976
|
});
|
|
4929
4977
|
var ListResourcesTool = class extends import_sdk5.ToolContext {
|
|
4930
4978
|
async execute(input) {
|
|
@@ -4986,25 +5034,25 @@ ListResourcesTool = __decorateClass([
|
|
|
4986
5034
|
], ListResourcesTool);
|
|
4987
5035
|
|
|
4988
5036
|
// plugins/plugin-dashboard/src/tools/list-tools.tool.ts
|
|
4989
|
-
var
|
|
5037
|
+
var import_lazy_zod6 = require("@frontmcp/lazy-zod");
|
|
4990
5038
|
var import_sdk6 = require("@frontmcp/sdk");
|
|
4991
5039
|
var listToolsInputSchema = {
|
|
4992
|
-
filter:
|
|
4993
|
-
includePlugins:
|
|
4994
|
-
includeSchemas:
|
|
5040
|
+
filter: import_lazy_zod6.z.string().optional().describe("Filter tools by name pattern (regex supported)"),
|
|
5041
|
+
includePlugins: import_lazy_zod6.z.boolean().default(true).describe("Include tools from plugins"),
|
|
5042
|
+
includeSchemas: import_lazy_zod6.z.boolean().default(false).describe("Include input/output schemas in the response")
|
|
4995
5043
|
};
|
|
4996
|
-
var listToolsOutputSchema =
|
|
4997
|
-
tools:
|
|
4998
|
-
|
|
4999
|
-
name:
|
|
5000
|
-
fullName:
|
|
5001
|
-
description:
|
|
5002
|
-
tags:
|
|
5003
|
-
inputSchema:
|
|
5004
|
-
outputSchema:
|
|
5044
|
+
var listToolsOutputSchema = import_lazy_zod6.z.object({
|
|
5045
|
+
tools: import_lazy_zod6.z.array(
|
|
5046
|
+
import_lazy_zod6.z.object({
|
|
5047
|
+
name: import_lazy_zod6.z.string(),
|
|
5048
|
+
fullName: import_lazy_zod6.z.string(),
|
|
5049
|
+
description: import_lazy_zod6.z.string().optional(),
|
|
5050
|
+
tags: import_lazy_zod6.z.array(import_lazy_zod6.z.string()).optional(),
|
|
5051
|
+
inputSchema: import_lazy_zod6.z.unknown().optional(),
|
|
5052
|
+
outputSchema: import_lazy_zod6.z.unknown().optional()
|
|
5005
5053
|
})
|
|
5006
5054
|
),
|
|
5007
|
-
count:
|
|
5055
|
+
count: import_lazy_zod6.z.number()
|
|
5008
5056
|
});
|
|
5009
5057
|
var ListToolsTool = class extends import_sdk6.ToolContext {
|
|
5010
5058
|
async execute(input) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@frontmcp/plugin-dashboard",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.9.1-rc.1",
|
|
4
4
|
"description": "Dashboard plugin for FrontMCP - visual monitoring and introspection of MCP servers",
|
|
5
5
|
"author": "AgentFront <info@agentfront.dev>",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -47,12 +47,12 @@
|
|
|
47
47
|
}
|
|
48
48
|
},
|
|
49
49
|
"dependencies": {
|
|
50
|
-
"@frontmcp/sdk": "1.
|
|
50
|
+
"@frontmcp/sdk": "1.9.1-rc.1"
|
|
51
51
|
},
|
|
52
52
|
"devDependencies": {
|
|
53
53
|
"reflect-metadata": "^0.2.2"
|
|
54
54
|
},
|
|
55
55
|
"peerDependencies": {
|
|
56
|
-
"@frontmcp/lazy-zod": "1.
|
|
56
|
+
"@frontmcp/lazy-zod": "1.9.1-rc.1"
|
|
57
57
|
}
|
|
58
58
|
}
|