@frontmcp/utils 1.9.2 → 1.9.4

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
@@ -117,6 +117,9 @@ async function fileExists(p) {
117
117
  return false;
118
118
  }
119
119
  }
120
+ function fileExistsSync(p) {
121
+ return getFs().existsSync(p);
122
+ }
120
123
  async function readJSON(jsonPath) {
121
124
  try {
122
125
  const fsp = getFsp();
@@ -2539,186 +2542,25 @@ var init_key_persistence2 = __esm({
2539
2542
  }
2540
2543
  });
2541
2544
 
2542
- // libs/utils/src/crypto/node.ts
2543
- var node_exports = {};
2544
- __export(node_exports, {
2545
- createSignedJwt: () => createSignedJwt,
2546
- cryptoProvider: () => nodeCrypto,
2547
- generateRsaKeyPair: () => generateRsaKeyPair,
2548
- isRsaPssAlg: () => isRsaPssAlg,
2549
- jwtAlgToNodeAlg: () => jwtAlgToNodeAlg,
2550
- nodeCrypto: () => nodeCrypto,
2551
- pemToPublicJwk: () => pemToPublicJwk,
2552
- rsaSign: () => rsaSign,
2553
- rsaSignBase64Url: () => rsaSignBase64Url,
2554
- rsaVerify: () => rsaVerify,
2555
- rsaVerifySync: () => rsaVerifySync
2556
- });
2557
- import crypto2 from "node:crypto";
2558
- function toUint8Array(buf) {
2559
- return new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength);
2560
- }
2561
- function toBuffer(data) {
2562
- if (typeof data === "string") {
2563
- return Buffer.from(data, "utf8");
2564
- }
2565
- return Buffer.from(data);
2566
- }
2567
- function generateRsaKeyPair(modulusLength = 2048, alg = "RS256") {
2568
- const kid = `rsa-key-${Date.now()}-${crypto2.randomBytes(8).toString("hex")}`;
2569
- const { privateKey, publicKey } = crypto2.generateKeyPairSync("rsa", {
2570
- modulusLength
2571
- });
2572
- const exported = publicKey.export({ format: "jwk" });
2573
- const publicJwk = {
2574
- ...exported,
2575
- kid,
2576
- alg,
2577
- use: "sig",
2578
- kty: "RSA"
2579
- };
2580
- return { privateKey, publicKey, publicJwk };
2581
- }
2582
- function rsaSign(algorithm, data, privateKey, options) {
2583
- const signingKey = options ? { key: privateKey, ...options } : privateKey;
2584
- return crypto2.sign(algorithm, data, signingKey);
2585
- }
2586
- function rsaVerify(jwtAlg, data, publicJwk, signature) {
2587
- const publicKey = crypto2.createPublicKey({ key: publicJwk, format: "jwk" });
2588
- const nodeAlgorithm = jwtAlgToNodeAlg(jwtAlg);
2589
- const verifyKey = isRsaPssAlg(jwtAlg) ? {
2590
- key: publicKey,
2591
- padding: crypto2.constants.RSA_PKCS1_PSS_PADDING,
2592
- saltLength: crypto2.constants.RSA_PSS_SALTLEN_DIGEST
2593
- } : publicKey;
2594
- return crypto2.verify(nodeAlgorithm, data, verifyKey, signature);
2595
- }
2596
- function rsaSignBase64Url(jwtAlg, data, privateJwk) {
2597
- const privateKey = crypto2.createPrivateKey({ key: privateJwk, format: "jwk" });
2598
- const nodeAlgorithm = jwtAlgToNodeAlg(jwtAlg);
2599
- const buf = Buffer.isBuffer(data) ? data : Buffer.from(data);
2600
- const sig = isRsaPssAlg(jwtAlg) ? rsaSign(nodeAlgorithm, buf, privateKey, {
2601
- padding: crypto2.constants.RSA_PKCS1_PSS_PADDING,
2602
- saltLength: crypto2.constants.RSA_PSS_SALTLEN_DIGEST
2603
- }) : rsaSign(nodeAlgorithm, buf, privateKey);
2604
- return sig.toString("base64url");
2605
- }
2606
- function rsaVerifySync(jwtAlg, data, publicJwk, signature) {
2607
- try {
2608
- const publicKey = crypto2.createPublicKey({ key: publicJwk, format: "jwk" });
2609
- const dataBuf = Buffer.isBuffer(data) ? data : Buffer.from(data);
2610
- const sigBuf = Buffer.isBuffer(signature) ? signature : Buffer.from(signature);
2611
- if (jwtAlg === "EdDSA") {
2612
- return crypto2.verify(null, dataBuf, publicKey, sigBuf);
2613
- }
2614
- const nodeAlgorithm = jwtAlgToNodeAlg(jwtAlg);
2615
- const verifyKey = isRsaPssAlg(jwtAlg) ? {
2616
- key: publicKey,
2617
- padding: crypto2.constants.RSA_PKCS1_PSS_PADDING,
2618
- saltLength: crypto2.constants.RSA_PSS_SALTLEN_DIGEST
2619
- } : publicKey;
2620
- return crypto2.verify(nodeAlgorithm, dataBuf, verifyKey, sigBuf);
2621
- } catch {
2622
- return false;
2623
- }
2624
- }
2625
- function pemToPublicJwk(pem) {
2626
- const key = crypto2.createPublicKey({ key: pem, format: "pem" });
2627
- return key.export({ format: "jwk" });
2628
- }
2629
- function createSignedJwt(payload, privateKey, kid, alg = "RS256") {
2630
- const header = { alg, typ: "JWT", kid };
2631
- const headerB64 = Buffer.from(JSON.stringify(header)).toString("base64url");
2632
- const payloadB64 = Buffer.from(JSON.stringify(payload)).toString("base64url");
2633
- const signatureInput = `${headerB64}.${payloadB64}`;
2634
- const nodeAlgorithm = jwtAlgToNodeAlg(alg);
2635
- const signature = rsaSign(
2636
- nodeAlgorithm,
2637
- Buffer.from(signatureInput),
2638
- privateKey,
2639
- isRsaPssAlg(alg) ? {
2640
- padding: crypto2.constants.RSA_PKCS1_PSS_PADDING,
2641
- saltLength: crypto2.constants.RSA_PSS_SALTLEN_DIGEST
2642
- } : void 0
2643
- );
2644
- const signatureB64 = signature.toString("base64url");
2645
- return `${headerB64}.${payloadB64}.${signatureB64}`;
2646
- }
2647
- var nodeCrypto;
2648
- var init_node = __esm({
2649
- "libs/utils/src/crypto/node.ts"() {
2650
- "use strict";
2651
- init_jwt_alg();
2652
- init_jwt_alg();
2653
- nodeCrypto = {
2654
- randomUUID() {
2655
- return crypto2.randomUUID();
2656
- },
2657
- randomBytes(length) {
2658
- return toUint8Array(crypto2.randomBytes(length));
2659
- },
2660
- sha256(data) {
2661
- const hash = crypto2.createHash("sha256").update(toBuffer(data)).digest();
2662
- return toUint8Array(hash);
2663
- },
2664
- sha256Hex(data) {
2665
- return crypto2.createHash("sha256").update(toBuffer(data)).digest("hex");
2666
- },
2667
- hmacSha256(key, data) {
2668
- const hmac2 = crypto2.createHmac("sha256", Buffer.from(key)).update(Buffer.from(data)).digest();
2669
- return toUint8Array(hmac2);
2670
- },
2671
- hkdfSha256(ikm, salt, info, length) {
2672
- const ikmBuf = Buffer.from(ikm);
2673
- const saltBuf = salt.length > 0 ? Buffer.from(salt) : Buffer.alloc(32);
2674
- const prk = crypto2.createHmac("sha256", saltBuf).update(ikmBuf).digest();
2675
- const hashLen = 32;
2676
- const n = Math.ceil(length / hashLen);
2677
- const chunks = [];
2678
- let prev = Buffer.alloc(0);
2679
- for (let i = 1; i <= n; i++) {
2680
- prev = crypto2.createHmac("sha256", prk).update(Buffer.concat([prev, Buffer.from(info), Buffer.from([i])])).digest();
2681
- chunks.push(prev);
2682
- }
2683
- return toUint8Array(Buffer.concat(chunks).subarray(0, length));
2684
- },
2685
- encryptAesGcm(key, plaintext, iv) {
2686
- const cipher = crypto2.createCipheriv("aes-256-gcm", Buffer.from(key), Buffer.from(iv));
2687
- const encrypted = Buffer.concat([cipher.update(Buffer.from(plaintext)), cipher.final()]);
2688
- const tag = cipher.getAuthTag();
2689
- return {
2690
- ciphertext: toUint8Array(encrypted),
2691
- tag: toUint8Array(tag)
2692
- };
2693
- },
2694
- decryptAesGcm(key, ciphertext, iv, tag) {
2695
- const decipher = crypto2.createDecipheriv("aes-256-gcm", Buffer.from(key), Buffer.from(iv));
2696
- decipher.setAuthTag(Buffer.from(tag));
2697
- const decrypted = Buffer.concat([decipher.update(Buffer.from(ciphertext)), decipher.final()]);
2698
- return toUint8Array(decrypted);
2699
- },
2700
- timingSafeEqual(a, b) {
2701
- if (a.length !== b.length) return false;
2702
- return crypto2.timingSafeEqual(Buffer.from(a), Buffer.from(b));
2703
- }
2704
- };
2705
- }
2706
- });
2707
-
2708
2545
  // libs/utils/src/crypto/browser.ts
2709
2546
  var browser_exports = {};
2710
2547
  __export(browser_exports, {
2711
2548
  browserCrypto: () => browserCrypto,
2712
2549
  cryptoProvider: () => browserCrypto,
2550
+ generateRsaKeyPair: () => generateRsaKeyPair,
2713
2551
  isRsaPssAlg: () => isRsaPssAlg,
2714
2552
  jwtAlgToWebCryptoAlg: () => jwtAlgToWebCryptoAlg,
2715
- rsaVerifyBrowser: () => rsaVerifyBrowser
2553
+ pemToPublicJwk: () => pemToPublicJwk,
2554
+ rsaSignBase64Url: () => rsaSignBase64Url,
2555
+ rsaVerify: () => rsaVerify,
2556
+ rsaVerifyBrowser: () => rsaVerifyBrowser,
2557
+ rsaVerifySync: () => rsaVerifySync
2716
2558
  });
2717
- import { sha256 as sha256Hash } from "@noble/hashes/sha2.js";
2718
- import { hmac } from "@noble/hashes/hmac.js";
2559
+ import { gcm } from "@noble/ciphers/aes.js";
2719
2560
  import { hkdf } from "@noble/hashes/hkdf.js";
2561
+ import { hmac } from "@noble/hashes/hmac.js";
2562
+ import { sha256 as sha256Hash } from "@noble/hashes/sha2.js";
2720
2563
  import { randomBytes as nobleRandomBytes } from "@noble/hashes/utils.js";
2721
- import { gcm } from "@noble/ciphers/aes.js";
2722
2564
  function toBytes(data) {
2723
2565
  if (typeof data === "string") {
2724
2566
  return new TextEncoder().encode(data);
@@ -2746,6 +2588,24 @@ function constantTimeEqual(a, b) {
2746
2588
  }
2747
2589
  return result === 0;
2748
2590
  }
2591
+ function nodeOnly(name) {
2592
+ throw new Error(`${name} is only available in Node.js runtimes`);
2593
+ }
2594
+ function rsaVerify() {
2595
+ return nodeOnly("rsaVerify");
2596
+ }
2597
+ function rsaSignBase64Url() {
2598
+ return nodeOnly("rsaSignBase64Url");
2599
+ }
2600
+ function rsaVerifySync() {
2601
+ return nodeOnly("rsaVerifySync");
2602
+ }
2603
+ function pemToPublicJwk() {
2604
+ return nodeOnly("pemToPublicJwk");
2605
+ }
2606
+ function generateRsaKeyPair() {
2607
+ return nodeOnly("generateRsaKeyPair");
2608
+ }
2749
2609
  async function rsaVerifyBrowser(jwtAlg, data, publicJwk, signature) {
2750
2610
  if (typeof globalThis.crypto?.subtle === "undefined") {
2751
2611
  throw new Error("WebCrypto API (crypto.subtle) is not available in this environment");
@@ -2825,40 +2685,40 @@ var init_browser = __esm({
2825
2685
  });
2826
2686
 
2827
2687
  // libs/utils/src/crypto/index.ts
2828
- import { cryptoProvider as cryptoProvider2 } from "#crypto-provider";
2688
+ import * as platformCrypto from "#crypto-provider";
2829
2689
  function getCrypto() {
2830
- return cryptoProvider2;
2690
+ return platformCrypto.cryptoProvider;
2831
2691
  }
2832
- function rsaVerify2(jwtAlg, data, publicJwk, signature) {
2692
+ function rsaVerify3(jwtAlg, data, publicJwk, signature) {
2833
2693
  if (isNode()) {
2834
- return Promise.resolve((init_node(), __toCommonJS(node_exports)).rsaVerify(jwtAlg, data, publicJwk, signature));
2694
+ return Promise.resolve(platformCrypto.rsaVerify(jwtAlg, data, publicJwk, signature));
2835
2695
  }
2836
2696
  const { rsaVerifyBrowser: rsaVerifyBrowser2 } = (init_browser(), __toCommonJS(browser_exports));
2837
2697
  return rsaVerifyBrowser2(jwtAlg, data, publicJwk, signature);
2838
2698
  }
2839
- function rsaSignBase64Url2(jwtAlg, data, privateJwk) {
2699
+ function rsaSignBase64Url3(jwtAlg, data, privateJwk) {
2840
2700
  if (!isNode()) {
2841
2701
  throw new Error("rsaSignBase64Url is only available in Node.js runtimes");
2842
2702
  }
2843
- return (init_node(), __toCommonJS(node_exports)).rsaSignBase64Url(jwtAlg, data, privateJwk);
2703
+ return platformCrypto.rsaSignBase64Url(jwtAlg, data, privateJwk);
2844
2704
  }
2845
- function rsaVerifySync2(jwtAlg, data, publicJwk, signature) {
2705
+ function rsaVerifySync3(jwtAlg, data, publicJwk, signature) {
2846
2706
  if (!isNode()) {
2847
2707
  throw new Error("rsaVerifySync is only available in Node.js runtimes; use the async rsaVerify in browsers");
2848
2708
  }
2849
- return (init_node(), __toCommonJS(node_exports)).rsaVerifySync(jwtAlg, data, publicJwk, signature);
2709
+ return platformCrypto.rsaVerifySync(jwtAlg, data, publicJwk, signature);
2850
2710
  }
2851
- function pemToPublicJwk2(pem) {
2711
+ function pemToPublicJwk3(pem) {
2852
2712
  if (!isNode()) {
2853
2713
  throw new Error("pemToPublicJwk is only available in Node.js runtimes");
2854
2714
  }
2855
- return (init_node(), __toCommonJS(node_exports)).pemToPublicJwk(pem);
2715
+ return platformCrypto.pemToPublicJwk(pem);
2856
2716
  }
2857
- function generateRsaKeyPair2(modulusLength, alg) {
2717
+ function generateRsaKeyPair3(modulusLength, alg) {
2858
2718
  if (!isNode()) {
2859
2719
  throw new Error("generateRsaKeyPair is only available in Node.js runtimes");
2860
2720
  }
2861
- return (init_node(), __toCommonJS(node_exports)).generateRsaKeyPair(modulusLength, alg);
2721
+ return platformCrypto.generateRsaKeyPair(modulusLength, alg);
2862
2722
  }
2863
2723
  function randomUUID() {
2864
2724
  return getCrypto().randomUUID();
@@ -3023,37 +2883,55 @@ function decodeOrRaw(encoded) {
3023
2883
  return encoded;
3024
2884
  }
3025
2885
  }
3026
- function mergeRedisUrlFields(rawUrl, fields) {
2886
+ function integerOrUndefined(text) {
2887
+ const value = Number.parseInt(text ?? "", 10);
2888
+ return Number.isNaN(value) ? void 0 : value;
2889
+ }
2890
+ function readRedisUrl(rawUrl) {
3027
2891
  let url;
3028
2892
  try {
3029
2893
  url = new URL(rawUrl);
3030
2894
  } catch {
3031
2895
  return void 0;
3032
2896
  }
3033
- const urlHost = url.hostname.replace(/^\[(.*)\]$/, "$1");
3034
- const urlPort = url.port ? Number(url.port) : void 0;
3035
- const urlPassword = url.password ? decodeOrRaw(url.password) : void 0;
3036
- const urlDbText = url.pathname.replace(/^\/+/, "") || url.searchParams.get("db") || void 0;
3037
- const urlDb = urlDbText === void 0 ? void 0 : Number(urlDbText);
3038
- const urlUsesTls = url.protocol === "rediss:";
2897
+ if (url.protocol !== "redis:" && url.protocol !== "rediss:") return void 0;
2898
+ const query = Object.fromEntries(url.searchParams);
2899
+ const { host, port, username, password, db, ...otherOptions } = query;
2900
+ const queryOptions = {};
2901
+ for (const [name, value = ""] of Object.entries(otherOptions)) {
2902
+ queryOptions[name] = name === "family" ? integerOrUndefined(value) ?? value : value;
2903
+ }
2904
+ return {
2905
+ host: url.hostname.replace(/^\[(.*)\]$/, "$1") || host,
2906
+ port: integerOrUndefined(url.port || port),
2907
+ username: decodeOrRaw(url.username) || username || void 0,
2908
+ password: decodeOrRaw(url.password) || password || void 0,
2909
+ db: integerOrUndefined(url.pathname.replace(/^\/+/, "") || db),
2910
+ tls: url.protocol === "rediss:",
2911
+ queryOptions
2912
+ };
2913
+ }
2914
+ function mergeRedisUrlFields(rawUrl, fields) {
2915
+ const connection = readRedisUrl(rawUrl);
2916
+ if (!connection) return void 0;
3039
2917
  const fillIns = {};
3040
2918
  const conflicts = [];
3041
- if (fields.host !== void 0 && fields.host !== urlHost) conflicts.push("host");
2919
+ if (fields.host !== void 0 && fields.host !== connection.host) conflicts.push("host");
3042
2920
  if (fields.port !== void 0) {
3043
- if (urlPort === void 0) fillIns.port = fields.port;
3044
- else if (fields.port !== urlPort) conflicts.push("port");
2921
+ if (connection.port === void 0) fillIns.port = fields.port;
2922
+ else if (fields.port !== connection.port) conflicts.push("port");
3045
2923
  }
3046
2924
  if (fields.password !== void 0) {
3047
- if (urlPassword === void 0) fillIns.password = fields.password;
3048
- else if (fields.password !== urlPassword) conflicts.push("password");
2925
+ if (connection.password === void 0) fillIns.password = fields.password;
2926
+ else if (fields.password !== connection.password) conflicts.push("password");
3049
2927
  }
3050
2928
  if (fields.db !== void 0) {
3051
- if (urlDb === void 0) fillIns.db = fields.db;
3052
- else if (fields.db !== urlDb) conflicts.push("db");
2929
+ if (connection.db === void 0) fillIns.db = fields.db;
2930
+ else if (fields.db !== connection.db) conflicts.push("db");
3053
2931
  }
3054
- if (fields.tls === true && !urlUsesTls) fillIns.tls = true;
3055
- if (fields.tls === false && urlUsesTls) conflicts.push("tls");
3056
- return { fillIns, conflicts };
2932
+ if (fields.tls === true && !connection.tls) fillIns.tls = true;
2933
+ if (fields.tls === false && connection.tls) conflicts.push("tls");
2934
+ return { connection, fillIns, conflicts };
3057
2935
  }
3058
2936
  function describeRedisUrlConflicts(conflicts) {
3059
2937
  return `redis ${conflicts.join(", ")} contradict${conflicts.length === 1 ? "s" : ""} redis.url. Fields beside a url only fill in what the URL leaves out (port, password, db, tls); put the value in the URL or drop the field.`;
@@ -3103,28 +2981,49 @@ function getRedisClass() {
3103
2981
  });
3104
2982
  }
3105
2983
  }
3106
- function resolveUrlFillIns(connectionUrl, options) {
2984
+ function resolveUrlOptions(connectionUrl, options) {
3107
2985
  const { url: configUrl, ...siblingFields } = { url: void 0, ...options.config };
3108
2986
  if (options.url && configUrl && configUrl !== options.url) {
3109
2987
  throw new StorageConfigError("redis", "redis.url and redis.config.url name different servers; set one of them.");
3110
2988
  }
3111
- const merge = mergeRedisUrlFields(connectionUrl, siblingFields);
3112
- if (merge && merge.conflicts.length > 0) {
2989
+ return urlConnectionOptions(connectionUrl, siblingFields);
2990
+ }
2991
+ function urlConnectionOptions(url, fields) {
2992
+ const merge = mergeRedisUrlFields(url, fields);
2993
+ if (!merge) return void 0;
2994
+ if (merge.conflicts.length > 0) {
3113
2995
  throw new StorageConfigError("redis", describeRedisUrlConflicts(merge.conflicts));
3114
2996
  }
3115
- return merge?.fillIns ?? {};
2997
+ const { queryOptions, tls, ...stated } = merge.connection;
2998
+ return { ...queryOptions, ...stated, ...toFillInOptions(merge.fillIns), ...tls ? { tls: {} } : {} };
2999
+ }
3000
+ function toFillInOptions({ port, password, db, tls }) {
3001
+ return {
3002
+ ...port !== void 0 ? { port } : {},
3003
+ ...password !== void 0 ? { password } : {},
3004
+ ...db !== void 0 ? { db } : {},
3005
+ ...tls ? { tls: {} } : {}
3006
+ };
3116
3007
  }
3117
3008
  function createRedisClient(options) {
3009
+ const urlOptions = options.url ? urlConnectionOptions(options.url, options) : void 0;
3118
3010
  const RedisClass = getRedisClass();
3119
3011
  const baseOptions = { lazyConnect: false, maxRetriesPerRequest: 3 };
3120
- const client = options.url ? new RedisClass(options.url, baseOptions) : new RedisClass({
3121
- ...baseOptions,
3122
- host: options.host ?? "localhost",
3123
- port: options.port ?? 6379,
3124
- password: options.password,
3125
- db: options.db ?? 0,
3126
- tls: options.tls ? {} : void 0
3127
- });
3012
+ let client;
3013
+ if (urlOptions) {
3014
+ client = new RedisClass({ ...baseOptions, ...urlOptions });
3015
+ } else if (options.url) {
3016
+ client = new RedisClass(options.url, baseOptions);
3017
+ } else {
3018
+ client = new RedisClass({
3019
+ ...baseOptions,
3020
+ host: options.host ?? "localhost",
3021
+ port: options.port ?? 6379,
3022
+ password: options.password,
3023
+ db: options.db ?? 0,
3024
+ tls: options.tls ? {} : void 0
3025
+ });
3026
+ }
3128
3027
  attachRedisErrorListener(client, { label: options.label ?? "redis", logger: options.logger });
3129
3028
  return client;
3130
3029
  }
@@ -3149,7 +3048,8 @@ var init_redis = __esm({
3149
3048
  keyPrefix;
3150
3049
  subscriptionHandlers = /* @__PURE__ */ new Map();
3151
3050
  connectionUrl;
3152
- urlFillIns;
3051
+ /** The connection options of a URL this adapter reads itself; undefined for one only ioredis reads. */
3052
+ urlOptions;
3153
3053
  constructor(options = {}) {
3154
3054
  super();
3155
3055
  const hasClient = options.client !== void 0;
@@ -3173,7 +3073,7 @@ var init_redis = __esm({
3173
3073
  this.keyPrefix = options.keyPrefix ?? "";
3174
3074
  const configUrl = options.config?.url;
3175
3075
  this.connectionUrl = options.url ?? (typeof configUrl === "string" ? configUrl : void 0);
3176
- this.urlFillIns = this.connectionUrl ? resolveUrlFillIns(this.connectionUrl, options) : {};
3076
+ this.urlOptions = this.connectionUrl ? resolveUrlOptions(this.connectionUrl, options) : void 0;
3177
3077
  }
3178
3078
  // ============================================
3179
3079
  // Connection Lifecycle
@@ -3195,12 +3095,7 @@ var init_redis = __esm({
3195
3095
  if (this.options.client) {
3196
3096
  client = this.options.client;
3197
3097
  } else {
3198
- const RedisClass = getRedisClass();
3199
- if (this.connectionUrl) {
3200
- client = new RedisClass(this.connectionUrl, this.buildRedisOptions());
3201
- } else {
3202
- client = new RedisClass(this.buildRedisOptions());
3203
- }
3098
+ client = this.newClient();
3204
3099
  client.on("error", recordSocketError);
3205
3100
  }
3206
3101
  await client.ping();
@@ -3434,15 +3329,7 @@ var init_redis = __esm({
3434
3329
  */
3435
3330
  buildRedisOptions() {
3436
3331
  if (this.connectionUrl) {
3437
- const { port, password, db, tls } = this.urlFillIns;
3438
- return {
3439
- ...port !== void 0 ? { port } : {},
3440
- ...password !== void 0 ? { password } : {},
3441
- ...db !== void 0 ? { db } : {},
3442
- ...tls ? { tls: {} } : {},
3443
- lazyConnect: false,
3444
- maxRetriesPerRequest: 3
3445
- };
3332
+ return { lazyConnect: false, maxRetriesPerRequest: 3, ...this.urlOptions };
3446
3333
  }
3447
3334
  const config = this.options.config;
3448
3335
  if (!config || typeof config.url === "string" || config.host === void 0) {
@@ -3458,16 +3345,23 @@ var init_redis = __esm({
3458
3345
  maxRetriesPerRequest: 3
3459
3346
  };
3460
3347
  }
3348
+ /**
3349
+ * Create a client this adapter owns. A URL only ioredis reads goes to it as is.
3350
+ */
3351
+ newClient() {
3352
+ const RedisClass = getRedisClass();
3353
+ if (this.connectionUrl && !this.urlOptions) {
3354
+ return new RedisClass(this.connectionUrl, this.buildRedisOptions());
3355
+ }
3356
+ return new RedisClass(this.buildRedisOptions());
3357
+ }
3461
3358
  /**
3462
3359
  * Create subscriber connection.
3463
3360
  */
3464
3361
  async createSubscriber() {
3465
- const RedisClass = getRedisClass();
3466
3362
  let subscriber;
3467
- if (this.connectionUrl) {
3468
- subscriber = new RedisClass(this.connectionUrl, this.buildRedisOptions());
3469
- } else if (this.options.config) {
3470
- subscriber = new RedisClass(this.buildRedisOptions());
3363
+ if (this.connectionUrl || this.options.config) {
3364
+ subscriber = this.newClient();
3471
3365
  } else if (this.options.client) {
3472
3366
  subscriber = this.options.client.duplicate();
3473
3367
  } else {
@@ -4992,6 +4886,30 @@ function safeJsonForScript(value) {
4992
4886
  }
4993
4887
  }
4994
4888
 
4889
+ // libs/utils/src/class-brand/class-brand.ts
4890
+ var CLASS_BRAND = /* @__PURE__ */ Symbol.for("@frontmcp/class-brand");
4891
+ var ordinaryHasInstance = Function.prototype[Symbol.hasInstance];
4892
+ function ownBrandOf(klass) {
4893
+ if (typeof klass !== "function" || !Object.prototype.hasOwnProperty.call(klass, CLASS_BRAND)) return void 0;
4894
+ return klass[CLASS_BRAND];
4895
+ }
4896
+ function classOfPrototype(proto) {
4897
+ return Object.getOwnPropertyDescriptor(proto, "constructor")?.value;
4898
+ }
4899
+ function brandClass(klass, brand) {
4900
+ Object.defineProperty(klass, CLASS_BRAND, { value: brand, enumerable: false, writable: false, configurable: false });
4901
+ }
4902
+ function isBrandedInstance(klass, value) {
4903
+ if (ordinaryHasInstance.call(klass, value)) return true;
4904
+ if (typeof value !== "object" || value === null) return false;
4905
+ const brand = ownBrandOf(klass);
4906
+ if (brand === void 0) return false;
4907
+ for (let proto = Object.getPrototypeOf(value); proto !== null; proto = Object.getPrototypeOf(proto)) {
4908
+ if (ownBrandOf(classOfPrototype(proto)) === brand) return true;
4909
+ }
4910
+ return false;
4911
+ }
4912
+
4995
4913
  // libs/utils/src/serialization/serialization.ts
4996
4914
  function safeStringify(value, space) {
4997
4915
  const seen = /* @__PURE__ */ new WeakSet();
@@ -6016,6 +5934,7 @@ export {
6016
5934
  base64urlDecode,
6017
5935
  base64urlEncode,
6018
5936
  basename,
5937
+ brandClass,
6019
5938
  buildPrefix,
6020
5939
  buildSetCookie,
6021
5940
  bytesToHex,
@@ -6066,11 +5985,12 @@ export {
6066
5985
  extractTemplateParams,
6067
5986
  extractUriScheme,
6068
5987
  fileExists,
5988
+ fileExistsSync,
6069
5989
  findNonFiniteNumber,
6070
5990
  generateCodeChallenge,
6071
5991
  generateCodeVerifier,
6072
5992
  generatePkcePair,
6073
- generateRsaKeyPair2 as generateRsaKeyPair,
5993
+ generateRsaKeyPair3 as generateRsaKeyPair,
6074
5994
  generateSecret,
6075
5995
  getAsyncContextMode,
6076
5996
  getCookie,
@@ -6092,6 +6012,7 @@ export {
6092
6012
  inferMimeType,
6093
6013
  isAbsolute,
6094
6014
  isAsymmetricKeyData,
6015
+ isBrandedInstance,
6095
6016
  isBrowser,
6096
6017
  isDebug,
6097
6018
  isDevelopment,
@@ -6135,7 +6056,7 @@ export {
6135
6056
  join as pathJoin,
6136
6057
  resolve as pathResolve,
6137
6058
  pathToFileURL,
6138
- pemToPublicJwk2 as pemToPublicJwk,
6059
+ pemToPublicJwk3 as pemToPublicJwk,
6139
6060
  processPlatformToolCalls,
6140
6061
  randomBytes,
6141
6062
  randomUUID,
@@ -6150,9 +6071,9 @@ export {
6150
6071
  resetRuntimeContext,
6151
6072
  resolveSecretPath,
6152
6073
  rm,
6153
- rsaSignBase64Url2 as rsaSignBase64Url,
6154
- rsaVerify2 as rsaVerify,
6155
- rsaVerifySync2 as rsaVerifySync,
6074
+ rsaSignBase64Url3 as rsaSignBase64Url,
6075
+ rsaVerify3 as rsaVerify,
6076
+ rsaVerifySync3 as rsaVerifySync,
6156
6077
  runCmd,
6157
6078
  runRequestExclusive,
6158
6079
  safeExec,
package/fs/fs.d.ts CHANGED
@@ -137,6 +137,21 @@ export declare function unlink(p: string): Promise<void>;
137
137
  * await fileExists('/path/to/file.txt') // true or false
138
138
  */
139
139
  export declare function fileExists(p: string): Promise<boolean>;
140
+ /**
141
+ * Check whether a file or directory exists, synchronously.
142
+ *
143
+ * **Node.js only** - throws an error if called in browser.
144
+ *
145
+ * Use this only where async is not possible (e.g. resolving a command line
146
+ * before a synchronous `spawn`). Prefer {@link fileExists} otherwise.
147
+ *
148
+ * @param p - Path to check
149
+ * @returns true if the path exists, false otherwise
150
+ *
151
+ * @example
152
+ * fileExistsSync('/path/to/file.txt') // true or false
153
+ */
154
+ export declare function fileExistsSync(p: string): boolean;
140
155
  /**
141
156
  * Read and parse a JSON file.
142
157
  *
@@ -343,6 +358,11 @@ export declare function access(p: string, mode?: number): Promise<void>;
343
358
  export declare function runCmd(cmd: string, args: string[], opts?: {
344
359
  cwd?: string;
345
360
  env?: NodeJS.ProcessEnv;
361
+ /**
362
+ * Pass `args` to the child unquoted (Windows only). Set it when the arguments
363
+ * are already quoted for `cmd.exe /d /s /c`; ignored on other platforms.
364
+ */
365
+ windowsVerbatimArguments?: boolean;
346
366
  }): Promise<void>;
347
367
  /**
348
368
  * Handle returned by {@link watchFile}. `close()` stops the watch and is safe
package/fs/index.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- export { readFile, readFileSync, readFileBuffer, writeFile, mkdir, rename, unlink, stat, copyFile, cp, readdir, readdirSync, realpath, rm, mkdtemp, symlink, access, fileExists, readJSON, writeJSON, ensureDir, ensureDirSync, isDirEmpty, runCmd, watchFile, getSpawnFn, } from './fs';
1
+ export { readFile, readFileSync, readFileBuffer, writeFile, mkdir, rename, unlink, stat, copyFile, cp, readdir, readdirSync, realpath, rm, mkdtemp, symlink, access, fileExists, fileExistsSync, readJSON, writeJSON, ensureDir, ensureDirSync, isDirEmpty, runCmd, watchFile, getSpawnFn, } from './fs';
2
2
  export type { FileWatcherHandle, SymlinkType } from './fs';
package/index.d.ts CHANGED
@@ -15,9 +15,10 @@ export { validateBaseUrl, buildSetCookie, parseCookies, getCookie, isLocalhost,
15
15
  export type { CookieOptions, SecureDetectionRequest } from './http';
16
16
  export { classifyIpAddress, expandIpv6, extractEmbeddedIpv4, parseIpv4, isRedirectResponse } from './net';
17
17
  export type { IpAddressClassification, IpAddressRange, SpecialPurposeIpRange, RedirectCandidate } from './net';
18
- export { readFile, readFileSync, readFileBuffer, writeFile, mkdir, rename, unlink, stat, copyFile, cp, readdir, readdirSync, realpath, rm, mkdtemp, symlink, access, fileExists, readJSON, writeJSON, ensureDir, ensureDirSync, isDirEmpty, runCmd, watchFile, getSpawnFn, } from './fs';
18
+ export { readFile, readFileSync, readFileBuffer, writeFile, mkdir, rename, unlink, stat, copyFile, cp, readdir, readdirSync, realpath, rm, mkdtemp, symlink, access, fileExists, fileExistsSync, readJSON, writeJSON, ensureDir, ensureDirSync, isDirEmpty, runCmd, watchFile, getSpawnFn, } from './fs';
19
19
  export type { FileWatcherHandle } from './fs';
20
20
  export { escapeHtml, escapeHtmlAttr, escapeJsString, escapeScriptClose, safeJsonForScript } from './escape';
21
+ export { brandClass, isBrandedInstance } from './class-brand';
21
22
  export { safeStringify } from './serialization';
22
23
  export { getCrypto, rsaVerify, rsaVerifySync, pemToPublicJwk, generateRsaKeyPair, rsaSignBase64Url, type RsaJwk, type RsaKeyPair, jwtAlgToNodeAlg, isRsaPssAlg, randomUUID, randomBytes, sha256, sha256Hex, sha256Base64url, hmacSha256, hkdfSha256, encryptAesGcm, decryptAesGcm, timingSafeEqual, bytesToHex, base64urlEncode, base64urlDecode, base64Encode, base64Decode, isNode, isBrowser, assertNode, EncryptedBlobError, encryptValue, decryptValue, tryDecryptValue, serializeBlob, deserializeBlob, tryDeserializeBlob, isValidEncryptedBlob, encryptAndSerialize, deserializeAndDecrypt, tryDeserializeAndDecrypt, generateCodeVerifier, generateCodeChallenge, verifyCodeChallenge, generatePkcePair, isValidCodeVerifier, isValidCodeChallenge, MIN_CODE_VERIFIER_LENGTH, MAX_CODE_VERIFIER_LENGTH, DEFAULT_CODE_VERIFIER_LENGTH, PkceError, type PkcePair, type SecretData, type SecretPersistenceOptions, type SecretValidationResult, secretDataSchema, validateSecretData, parseSecretData, isSecretPersistenceEnabled, resolveSecretPath, loadSecret, saveSecret, deleteSecret, generateSecret, createSecretData, getOrCreateSecret, clearCachedSecret, isSecretCached, type SignedData, type HmacSigningConfig, signData, verifyData, isSignedData, verifyOrParseData, type BaseKeyData, type SecretKeyData, type AsymmetricKeyData, type AnyKeyData, type KeyPersistenceOptions, type CreateKeyPersistenceOptions, type CreateSecretOptions, type CreateAsymmetricOptions, type KeyValidationResult, asymmetricAlgSchema, secretKeyDataSchema, asymmetricKeyDataSchema, anyKeyDataSchema, validateKeyData, parseKeyData, isSecretKeyData, isAsymmetricKeyData, KeyPersistence, createKeyPersistence, createKeyPersistenceWithStorage, } from './crypto';
23
24
  export type { CryptoProvider, EncBlob, EncryptedBlob } from './crypto';
@@ -27,7 +28,7 @@ export { getEnv, getNodeEnv, getCwd, isProduction, isDevelopment, getEnvFlag, is
27
28
  export type { RuntimeContext, EntryAvailability } from './env';
28
29
  export { analyzePattern, isPatternSafe, createSafeRegExp, safeTest, safeMatch, safeReplace, safeExec, isInputLengthSafe, DEFAULT_MAX_INPUT_LENGTH, REDOS_THRESHOLDS, trimLeading, trimTrailing, trimBoth, trimChars, extractBracedParams, expandTemplate, hasTemplatePlaceholders, collapseChar, collapseWhitespace, type SafeRegexOptions, type PatternAnalysisResult, } from './regex';
29
30
  export { createStorage, createMemoryStorage, getDetectedStorageType, NamespacedStorageImpl, createRootStorage, createNamespacedStorage, buildPrefix, NAMESPACE_SEPARATOR, StorageError, StorageConnectionError, StorageOperationError, StorageNotSupportedError, StorageConfigError, StorageTTLError, StoragePatternError, StorageNotConnectedError, EncryptedStorageError, BaseStorageAdapter, MemoryStorageAdapter, RedisStorageAdapter, createRedisClient, VercelKvStorageAdapter, createVercelKvClient, type VercelKvConnection, UpstashStorageAdapter, FileSystemStorageAdapter, type FileSystemAdapterOptions, TypedStorage, type TypedStorageOptions, type TypedSetOptions, type TypedSetEntry, EncryptedTypedStorage, type EncryptedTypedStorageOptions, type EncryptedSetOptions, type EncryptedSetEntry, type EncryptionKey, type StoredEncryptedBlob, type ClientKeyBinding, globToRegex, matchesPattern, validatePattern, escapeGlob, MAX_TTL_SECONDS, validateTTL, validateOptionalTTL, ttlToExpiresAt, expiresAtToTTL, isExpired, normalizeTTL, attachRedisErrorListener, DEFAULT_REDIS_ERROR_LOG_INTERVAL_MS, mergeRedisUrlFields, describeRedisUrlConflicts, } from './storage';
30
- export type { StorageAdapter, NamespacedStorage, RootStorage, SetOptions, SetEntry, MessageHandler, Unsubscribe, MemoryAdapterOptions, RedisAdapterOptions, RedisHostConnectionConfig, RedisUrlConnectionConfig, RedisUrlFillInConfig, VercelKvAdapterOptions, UpstashAdapterOptions, StorageType, StorageConfig, RedisErrorListenerOptions, RedisUrlMerge, RedisUrlSiblingFields, CreateRedisClientOptions, ErrorEmitterClient, } from './storage';
31
+ export type { StorageAdapter, NamespacedStorage, RootStorage, SetOptions, SetEntry, MessageHandler, Unsubscribe, MemoryAdapterOptions, RedisAdapterOptions, RedisHostConnectionConfig, RedisUrlConnectionConfig, RedisUrlFillInConfig, VercelKvAdapterOptions, UpstashAdapterOptions, StorageType, StorageConfig, RedisErrorListenerOptions, RedisUrlConnection, RedisUrlMerge, RedisUrlSiblingFields, CreateRedisClientOptions, ErrorEmitterClient, } from './storage';
31
32
  export { processPlatformToolCalls } from './llm';
32
33
  export type { CallToolFn, OpenAIToolCallItem, OpenAIToolResponse, ClaudeToolUseBlock, ClaudeToolResultBlock, VercelToolCallInfo, PlatformToolCallsInput, PlatformToolCallsOutput, SupportedPlatform, } from './llm';
33
34
  export { getMachineId, setMachineIdOverride } from './machine-id';