@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/class-brand/class-brand.d.ts +37 -0
- package/class-brand/index.d.ts +1 -0
- package/crypto/browser.d.ts +5 -0
- package/crypto/browser.js +33 -5
- package/crypto/node.d.ts +1 -1
- package/esm/crypto/browser.mjs +27 -4
- package/esm/index.mjs +159 -238
- package/fs/fs.d.ts +20 -0
- package/fs/index.d.ts +1 -1
- package/index.d.ts +3 -2
- package/index.js +164 -240
- package/package.json +6 -2
- package/storage/adapters/redis.d.ts +9 -1
- package/storage/index.d.ts +1 -1
- package/storage/redis-url.d.ts +25 -3
package/index.js
CHANGED
|
@@ -119,6 +119,9 @@ async function fileExists(p) {
|
|
|
119
119
|
return false;
|
|
120
120
|
}
|
|
121
121
|
}
|
|
122
|
+
function fileExistsSync(p) {
|
|
123
|
+
return getFs().existsSync(p);
|
|
124
|
+
}
|
|
122
125
|
async function readJSON(jsonPath) {
|
|
123
126
|
try {
|
|
124
127
|
const fsp = getFsp();
|
|
@@ -2541,180 +2544,19 @@ var init_key_persistence2 = __esm({
|
|
|
2541
2544
|
}
|
|
2542
2545
|
});
|
|
2543
2546
|
|
|
2544
|
-
// libs/utils/src/crypto/node.ts
|
|
2545
|
-
var node_exports = {};
|
|
2546
|
-
__export(node_exports, {
|
|
2547
|
-
createSignedJwt: () => createSignedJwt,
|
|
2548
|
-
cryptoProvider: () => nodeCrypto,
|
|
2549
|
-
generateRsaKeyPair: () => generateRsaKeyPair,
|
|
2550
|
-
isRsaPssAlg: () => isRsaPssAlg,
|
|
2551
|
-
jwtAlgToNodeAlg: () => jwtAlgToNodeAlg,
|
|
2552
|
-
nodeCrypto: () => nodeCrypto,
|
|
2553
|
-
pemToPublicJwk: () => pemToPublicJwk,
|
|
2554
|
-
rsaSign: () => rsaSign,
|
|
2555
|
-
rsaSignBase64Url: () => rsaSignBase64Url,
|
|
2556
|
-
rsaVerify: () => rsaVerify,
|
|
2557
|
-
rsaVerifySync: () => rsaVerifySync
|
|
2558
|
-
});
|
|
2559
|
-
function toUint8Array(buf) {
|
|
2560
|
-
return new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength);
|
|
2561
|
-
}
|
|
2562
|
-
function toBuffer(data) {
|
|
2563
|
-
if (typeof data === "string") {
|
|
2564
|
-
return Buffer.from(data, "utf8");
|
|
2565
|
-
}
|
|
2566
|
-
return Buffer.from(data);
|
|
2567
|
-
}
|
|
2568
|
-
function generateRsaKeyPair(modulusLength = 2048, alg = "RS256") {
|
|
2569
|
-
const kid = `rsa-key-${Date.now()}-${import_node_crypto.default.randomBytes(8).toString("hex")}`;
|
|
2570
|
-
const { privateKey, publicKey } = import_node_crypto.default.generateKeyPairSync("rsa", {
|
|
2571
|
-
modulusLength
|
|
2572
|
-
});
|
|
2573
|
-
const exported = publicKey.export({ format: "jwk" });
|
|
2574
|
-
const publicJwk = {
|
|
2575
|
-
...exported,
|
|
2576
|
-
kid,
|
|
2577
|
-
alg,
|
|
2578
|
-
use: "sig",
|
|
2579
|
-
kty: "RSA"
|
|
2580
|
-
};
|
|
2581
|
-
return { privateKey, publicKey, publicJwk };
|
|
2582
|
-
}
|
|
2583
|
-
function rsaSign(algorithm, data, privateKey, options) {
|
|
2584
|
-
const signingKey = options ? { key: privateKey, ...options } : privateKey;
|
|
2585
|
-
return import_node_crypto.default.sign(algorithm, data, signingKey);
|
|
2586
|
-
}
|
|
2587
|
-
function rsaVerify(jwtAlg, data, publicJwk, signature) {
|
|
2588
|
-
const publicKey = import_node_crypto.default.createPublicKey({ key: publicJwk, format: "jwk" });
|
|
2589
|
-
const nodeAlgorithm = jwtAlgToNodeAlg(jwtAlg);
|
|
2590
|
-
const verifyKey = isRsaPssAlg(jwtAlg) ? {
|
|
2591
|
-
key: publicKey,
|
|
2592
|
-
padding: import_node_crypto.default.constants.RSA_PKCS1_PSS_PADDING,
|
|
2593
|
-
saltLength: import_node_crypto.default.constants.RSA_PSS_SALTLEN_DIGEST
|
|
2594
|
-
} : publicKey;
|
|
2595
|
-
return import_node_crypto.default.verify(nodeAlgorithm, data, verifyKey, signature);
|
|
2596
|
-
}
|
|
2597
|
-
function rsaSignBase64Url(jwtAlg, data, privateJwk) {
|
|
2598
|
-
const privateKey = import_node_crypto.default.createPrivateKey({ key: privateJwk, format: "jwk" });
|
|
2599
|
-
const nodeAlgorithm = jwtAlgToNodeAlg(jwtAlg);
|
|
2600
|
-
const buf = Buffer.isBuffer(data) ? data : Buffer.from(data);
|
|
2601
|
-
const sig = isRsaPssAlg(jwtAlg) ? rsaSign(nodeAlgorithm, buf, privateKey, {
|
|
2602
|
-
padding: import_node_crypto.default.constants.RSA_PKCS1_PSS_PADDING,
|
|
2603
|
-
saltLength: import_node_crypto.default.constants.RSA_PSS_SALTLEN_DIGEST
|
|
2604
|
-
}) : rsaSign(nodeAlgorithm, buf, privateKey);
|
|
2605
|
-
return sig.toString("base64url");
|
|
2606
|
-
}
|
|
2607
|
-
function rsaVerifySync(jwtAlg, data, publicJwk, signature) {
|
|
2608
|
-
try {
|
|
2609
|
-
const publicKey = import_node_crypto.default.createPublicKey({ key: publicJwk, format: "jwk" });
|
|
2610
|
-
const dataBuf = Buffer.isBuffer(data) ? data : Buffer.from(data);
|
|
2611
|
-
const sigBuf = Buffer.isBuffer(signature) ? signature : Buffer.from(signature);
|
|
2612
|
-
if (jwtAlg === "EdDSA") {
|
|
2613
|
-
return import_node_crypto.default.verify(null, dataBuf, publicKey, sigBuf);
|
|
2614
|
-
}
|
|
2615
|
-
const nodeAlgorithm = jwtAlgToNodeAlg(jwtAlg);
|
|
2616
|
-
const verifyKey = isRsaPssAlg(jwtAlg) ? {
|
|
2617
|
-
key: publicKey,
|
|
2618
|
-
padding: import_node_crypto.default.constants.RSA_PKCS1_PSS_PADDING,
|
|
2619
|
-
saltLength: import_node_crypto.default.constants.RSA_PSS_SALTLEN_DIGEST
|
|
2620
|
-
} : publicKey;
|
|
2621
|
-
return import_node_crypto.default.verify(nodeAlgorithm, dataBuf, verifyKey, sigBuf);
|
|
2622
|
-
} catch {
|
|
2623
|
-
return false;
|
|
2624
|
-
}
|
|
2625
|
-
}
|
|
2626
|
-
function pemToPublicJwk(pem) {
|
|
2627
|
-
const key = import_node_crypto.default.createPublicKey({ key: pem, format: "pem" });
|
|
2628
|
-
return key.export({ format: "jwk" });
|
|
2629
|
-
}
|
|
2630
|
-
function createSignedJwt(payload, privateKey, kid, alg = "RS256") {
|
|
2631
|
-
const header = { alg, typ: "JWT", kid };
|
|
2632
|
-
const headerB64 = Buffer.from(JSON.stringify(header)).toString("base64url");
|
|
2633
|
-
const payloadB64 = Buffer.from(JSON.stringify(payload)).toString("base64url");
|
|
2634
|
-
const signatureInput = `${headerB64}.${payloadB64}`;
|
|
2635
|
-
const nodeAlgorithm = jwtAlgToNodeAlg(alg);
|
|
2636
|
-
const signature = rsaSign(
|
|
2637
|
-
nodeAlgorithm,
|
|
2638
|
-
Buffer.from(signatureInput),
|
|
2639
|
-
privateKey,
|
|
2640
|
-
isRsaPssAlg(alg) ? {
|
|
2641
|
-
padding: import_node_crypto.default.constants.RSA_PKCS1_PSS_PADDING,
|
|
2642
|
-
saltLength: import_node_crypto.default.constants.RSA_PSS_SALTLEN_DIGEST
|
|
2643
|
-
} : void 0
|
|
2644
|
-
);
|
|
2645
|
-
const signatureB64 = signature.toString("base64url");
|
|
2646
|
-
return `${headerB64}.${payloadB64}.${signatureB64}`;
|
|
2647
|
-
}
|
|
2648
|
-
var import_node_crypto, nodeCrypto;
|
|
2649
|
-
var init_node = __esm({
|
|
2650
|
-
"libs/utils/src/crypto/node.ts"() {
|
|
2651
|
-
"use strict";
|
|
2652
|
-
import_node_crypto = __toESM(require("node:crypto"));
|
|
2653
|
-
init_jwt_alg();
|
|
2654
|
-
init_jwt_alg();
|
|
2655
|
-
nodeCrypto = {
|
|
2656
|
-
randomUUID() {
|
|
2657
|
-
return import_node_crypto.default.randomUUID();
|
|
2658
|
-
},
|
|
2659
|
-
randomBytes(length) {
|
|
2660
|
-
return toUint8Array(import_node_crypto.default.randomBytes(length));
|
|
2661
|
-
},
|
|
2662
|
-
sha256(data) {
|
|
2663
|
-
const hash = import_node_crypto.default.createHash("sha256").update(toBuffer(data)).digest();
|
|
2664
|
-
return toUint8Array(hash);
|
|
2665
|
-
},
|
|
2666
|
-
sha256Hex(data) {
|
|
2667
|
-
return import_node_crypto.default.createHash("sha256").update(toBuffer(data)).digest("hex");
|
|
2668
|
-
},
|
|
2669
|
-
hmacSha256(key, data) {
|
|
2670
|
-
const hmac2 = import_node_crypto.default.createHmac("sha256", Buffer.from(key)).update(Buffer.from(data)).digest();
|
|
2671
|
-
return toUint8Array(hmac2);
|
|
2672
|
-
},
|
|
2673
|
-
hkdfSha256(ikm, salt, info, length) {
|
|
2674
|
-
const ikmBuf = Buffer.from(ikm);
|
|
2675
|
-
const saltBuf = salt.length > 0 ? Buffer.from(salt) : Buffer.alloc(32);
|
|
2676
|
-
const prk = import_node_crypto.default.createHmac("sha256", saltBuf).update(ikmBuf).digest();
|
|
2677
|
-
const hashLen = 32;
|
|
2678
|
-
const n = Math.ceil(length / hashLen);
|
|
2679
|
-
const chunks = [];
|
|
2680
|
-
let prev = Buffer.alloc(0);
|
|
2681
|
-
for (let i = 1; i <= n; i++) {
|
|
2682
|
-
prev = import_node_crypto.default.createHmac("sha256", prk).update(Buffer.concat([prev, Buffer.from(info), Buffer.from([i])])).digest();
|
|
2683
|
-
chunks.push(prev);
|
|
2684
|
-
}
|
|
2685
|
-
return toUint8Array(Buffer.concat(chunks).subarray(0, length));
|
|
2686
|
-
},
|
|
2687
|
-
encryptAesGcm(key, plaintext, iv) {
|
|
2688
|
-
const cipher = import_node_crypto.default.createCipheriv("aes-256-gcm", Buffer.from(key), Buffer.from(iv));
|
|
2689
|
-
const encrypted = Buffer.concat([cipher.update(Buffer.from(plaintext)), cipher.final()]);
|
|
2690
|
-
const tag = cipher.getAuthTag();
|
|
2691
|
-
return {
|
|
2692
|
-
ciphertext: toUint8Array(encrypted),
|
|
2693
|
-
tag: toUint8Array(tag)
|
|
2694
|
-
};
|
|
2695
|
-
},
|
|
2696
|
-
decryptAesGcm(key, ciphertext, iv, tag) {
|
|
2697
|
-
const decipher = import_node_crypto.default.createDecipheriv("aes-256-gcm", Buffer.from(key), Buffer.from(iv));
|
|
2698
|
-
decipher.setAuthTag(Buffer.from(tag));
|
|
2699
|
-
const decrypted = Buffer.concat([decipher.update(Buffer.from(ciphertext)), decipher.final()]);
|
|
2700
|
-
return toUint8Array(decrypted);
|
|
2701
|
-
},
|
|
2702
|
-
timingSafeEqual(a, b) {
|
|
2703
|
-
if (a.length !== b.length) return false;
|
|
2704
|
-
return import_node_crypto.default.timingSafeEqual(Buffer.from(a), Buffer.from(b));
|
|
2705
|
-
}
|
|
2706
|
-
};
|
|
2707
|
-
}
|
|
2708
|
-
});
|
|
2709
|
-
|
|
2710
2547
|
// libs/utils/src/crypto/browser.ts
|
|
2711
2548
|
var browser_exports = {};
|
|
2712
2549
|
__export(browser_exports, {
|
|
2713
2550
|
browserCrypto: () => browserCrypto,
|
|
2714
2551
|
cryptoProvider: () => browserCrypto,
|
|
2552
|
+
generateRsaKeyPair: () => generateRsaKeyPair,
|
|
2715
2553
|
isRsaPssAlg: () => isRsaPssAlg,
|
|
2716
2554
|
jwtAlgToWebCryptoAlg: () => jwtAlgToWebCryptoAlg,
|
|
2717
|
-
|
|
2555
|
+
pemToPublicJwk: () => pemToPublicJwk,
|
|
2556
|
+
rsaSignBase64Url: () => rsaSignBase64Url,
|
|
2557
|
+
rsaVerify: () => rsaVerify,
|
|
2558
|
+
rsaVerifyBrowser: () => rsaVerifyBrowser,
|
|
2559
|
+
rsaVerifySync: () => rsaVerifySync
|
|
2718
2560
|
});
|
|
2719
2561
|
function toBytes(data) {
|
|
2720
2562
|
if (typeof data === "string") {
|
|
@@ -2743,6 +2585,24 @@ function constantTimeEqual(a, b) {
|
|
|
2743
2585
|
}
|
|
2744
2586
|
return result === 0;
|
|
2745
2587
|
}
|
|
2588
|
+
function nodeOnly(name) {
|
|
2589
|
+
throw new Error(`${name} is only available in Node.js runtimes`);
|
|
2590
|
+
}
|
|
2591
|
+
function rsaVerify() {
|
|
2592
|
+
return nodeOnly("rsaVerify");
|
|
2593
|
+
}
|
|
2594
|
+
function rsaSignBase64Url() {
|
|
2595
|
+
return nodeOnly("rsaSignBase64Url");
|
|
2596
|
+
}
|
|
2597
|
+
function rsaVerifySync() {
|
|
2598
|
+
return nodeOnly("rsaVerifySync");
|
|
2599
|
+
}
|
|
2600
|
+
function pemToPublicJwk() {
|
|
2601
|
+
return nodeOnly("pemToPublicJwk");
|
|
2602
|
+
}
|
|
2603
|
+
function generateRsaKeyPair() {
|
|
2604
|
+
return nodeOnly("generateRsaKeyPair");
|
|
2605
|
+
}
|
|
2746
2606
|
async function rsaVerifyBrowser(jwtAlg, data, publicJwk, signature) {
|
|
2747
2607
|
if (typeof globalThis.crypto?.subtle === "undefined") {
|
|
2748
2608
|
throw new Error("WebCrypto API (crypto.subtle) is not available in this environment");
|
|
@@ -2774,15 +2634,15 @@ function getSaltLength(jwtAlg) {
|
|
|
2774
2634
|
return 32;
|
|
2775
2635
|
}
|
|
2776
2636
|
}
|
|
2777
|
-
var
|
|
2637
|
+
var import_aes, import_hkdf, import_hmac, import_sha2, import_utils, browserCrypto;
|
|
2778
2638
|
var init_browser = __esm({
|
|
2779
2639
|
"libs/utils/src/crypto/browser.ts"() {
|
|
2780
2640
|
"use strict";
|
|
2781
|
-
|
|
2782
|
-
import_hmac = require("@noble/hashes/hmac.js");
|
|
2641
|
+
import_aes = require("@noble/ciphers/aes.js");
|
|
2783
2642
|
import_hkdf = require("@noble/hashes/hkdf.js");
|
|
2643
|
+
import_hmac = require("@noble/hashes/hmac.js");
|
|
2644
|
+
import_sha2 = require("@noble/hashes/sha2.js");
|
|
2784
2645
|
import_utils = require("@noble/hashes/utils.js");
|
|
2785
|
-
import_aes = require("@noble/ciphers/aes.js");
|
|
2786
2646
|
init_jwt_alg();
|
|
2787
2647
|
init_jwt_alg();
|
|
2788
2648
|
browserCrypto = {
|
|
@@ -2828,38 +2688,38 @@ var init_browser = __esm({
|
|
|
2828
2688
|
|
|
2829
2689
|
// libs/utils/src/crypto/index.ts
|
|
2830
2690
|
function getCrypto() {
|
|
2831
|
-
return
|
|
2691
|
+
return platformCrypto.cryptoProvider;
|
|
2832
2692
|
}
|
|
2833
|
-
function
|
|
2693
|
+
function rsaVerify3(jwtAlg, data, publicJwk, signature) {
|
|
2834
2694
|
if (isNode()) {
|
|
2835
|
-
return Promise.resolve(
|
|
2695
|
+
return Promise.resolve(platformCrypto.rsaVerify(jwtAlg, data, publicJwk, signature));
|
|
2836
2696
|
}
|
|
2837
2697
|
const { rsaVerifyBrowser: rsaVerifyBrowser2 } = (init_browser(), __toCommonJS(browser_exports));
|
|
2838
2698
|
return rsaVerifyBrowser2(jwtAlg, data, publicJwk, signature);
|
|
2839
2699
|
}
|
|
2840
|
-
function
|
|
2700
|
+
function rsaSignBase64Url3(jwtAlg, data, privateJwk) {
|
|
2841
2701
|
if (!isNode()) {
|
|
2842
2702
|
throw new Error("rsaSignBase64Url is only available in Node.js runtimes");
|
|
2843
2703
|
}
|
|
2844
|
-
return
|
|
2704
|
+
return platformCrypto.rsaSignBase64Url(jwtAlg, data, privateJwk);
|
|
2845
2705
|
}
|
|
2846
|
-
function
|
|
2706
|
+
function rsaVerifySync3(jwtAlg, data, publicJwk, signature) {
|
|
2847
2707
|
if (!isNode()) {
|
|
2848
2708
|
throw new Error("rsaVerifySync is only available in Node.js runtimes; use the async rsaVerify in browsers");
|
|
2849
2709
|
}
|
|
2850
|
-
return
|
|
2710
|
+
return platformCrypto.rsaVerifySync(jwtAlg, data, publicJwk, signature);
|
|
2851
2711
|
}
|
|
2852
|
-
function
|
|
2712
|
+
function pemToPublicJwk3(pem) {
|
|
2853
2713
|
if (!isNode()) {
|
|
2854
2714
|
throw new Error("pemToPublicJwk is only available in Node.js runtimes");
|
|
2855
2715
|
}
|
|
2856
|
-
return
|
|
2716
|
+
return platformCrypto.pemToPublicJwk(pem);
|
|
2857
2717
|
}
|
|
2858
|
-
function
|
|
2718
|
+
function generateRsaKeyPair3(modulusLength, alg) {
|
|
2859
2719
|
if (!isNode()) {
|
|
2860
2720
|
throw new Error("generateRsaKeyPair is only available in Node.js runtimes");
|
|
2861
2721
|
}
|
|
2862
|
-
return
|
|
2722
|
+
return platformCrypto.generateRsaKeyPair(modulusLength, alg);
|
|
2863
2723
|
}
|
|
2864
2724
|
function randomUUID() {
|
|
2865
2725
|
return getCrypto().randomUUID();
|
|
@@ -2965,11 +2825,11 @@ function base64Decode(data) {
|
|
|
2965
2825
|
function sha256Base64url(data) {
|
|
2966
2826
|
return base64urlEncode(sha256(data));
|
|
2967
2827
|
}
|
|
2968
|
-
var
|
|
2828
|
+
var platformCrypto, HKDF_SHA256_MAX_LENGTH;
|
|
2969
2829
|
var init_crypto = __esm({
|
|
2970
2830
|
"libs/utils/src/crypto/index.ts"() {
|
|
2971
2831
|
"use strict";
|
|
2972
|
-
|
|
2832
|
+
platformCrypto = __toESM(require("#crypto-provider"));
|
|
2973
2833
|
init_runtime();
|
|
2974
2834
|
init_jwt_alg();
|
|
2975
2835
|
init_runtime();
|
|
@@ -3025,37 +2885,55 @@ function decodeOrRaw(encoded) {
|
|
|
3025
2885
|
return encoded;
|
|
3026
2886
|
}
|
|
3027
2887
|
}
|
|
3028
|
-
function
|
|
2888
|
+
function integerOrUndefined(text) {
|
|
2889
|
+
const value = Number.parseInt(text ?? "", 10);
|
|
2890
|
+
return Number.isNaN(value) ? void 0 : value;
|
|
2891
|
+
}
|
|
2892
|
+
function readRedisUrl(rawUrl) {
|
|
3029
2893
|
let url;
|
|
3030
2894
|
try {
|
|
3031
2895
|
url = new URL(rawUrl);
|
|
3032
2896
|
} catch {
|
|
3033
2897
|
return void 0;
|
|
3034
2898
|
}
|
|
3035
|
-
|
|
3036
|
-
const
|
|
3037
|
-
const
|
|
3038
|
-
const
|
|
3039
|
-
const
|
|
3040
|
-
|
|
2899
|
+
if (url.protocol !== "redis:" && url.protocol !== "rediss:") return void 0;
|
|
2900
|
+
const query = Object.fromEntries(url.searchParams);
|
|
2901
|
+
const { host, port, username, password, db, ...otherOptions } = query;
|
|
2902
|
+
const queryOptions = {};
|
|
2903
|
+
for (const [name, value = ""] of Object.entries(otherOptions)) {
|
|
2904
|
+
queryOptions[name] = name === "family" ? integerOrUndefined(value) ?? value : value;
|
|
2905
|
+
}
|
|
2906
|
+
return {
|
|
2907
|
+
host: url.hostname.replace(/^\[(.*)\]$/, "$1") || host,
|
|
2908
|
+
port: integerOrUndefined(url.port || port),
|
|
2909
|
+
username: decodeOrRaw(url.username) || username || void 0,
|
|
2910
|
+
password: decodeOrRaw(url.password) || password || void 0,
|
|
2911
|
+
db: integerOrUndefined(url.pathname.replace(/^\/+/, "") || db),
|
|
2912
|
+
tls: url.protocol === "rediss:",
|
|
2913
|
+
queryOptions
|
|
2914
|
+
};
|
|
2915
|
+
}
|
|
2916
|
+
function mergeRedisUrlFields(rawUrl, fields) {
|
|
2917
|
+
const connection = readRedisUrl(rawUrl);
|
|
2918
|
+
if (!connection) return void 0;
|
|
3041
2919
|
const fillIns = {};
|
|
3042
2920
|
const conflicts = [];
|
|
3043
|
-
if (fields.host !== void 0 && fields.host !==
|
|
2921
|
+
if (fields.host !== void 0 && fields.host !== connection.host) conflicts.push("host");
|
|
3044
2922
|
if (fields.port !== void 0) {
|
|
3045
|
-
if (
|
|
3046
|
-
else if (fields.port !==
|
|
2923
|
+
if (connection.port === void 0) fillIns.port = fields.port;
|
|
2924
|
+
else if (fields.port !== connection.port) conflicts.push("port");
|
|
3047
2925
|
}
|
|
3048
2926
|
if (fields.password !== void 0) {
|
|
3049
|
-
if (
|
|
3050
|
-
else if (fields.password !==
|
|
2927
|
+
if (connection.password === void 0) fillIns.password = fields.password;
|
|
2928
|
+
else if (fields.password !== connection.password) conflicts.push("password");
|
|
3051
2929
|
}
|
|
3052
2930
|
if (fields.db !== void 0) {
|
|
3053
|
-
if (
|
|
3054
|
-
else if (fields.db !==
|
|
2931
|
+
if (connection.db === void 0) fillIns.db = fields.db;
|
|
2932
|
+
else if (fields.db !== connection.db) conflicts.push("db");
|
|
3055
2933
|
}
|
|
3056
|
-
if (fields.tls === true && !
|
|
3057
|
-
if (fields.tls === false &&
|
|
3058
|
-
return { fillIns, conflicts };
|
|
2934
|
+
if (fields.tls === true && !connection.tls) fillIns.tls = true;
|
|
2935
|
+
if (fields.tls === false && connection.tls) conflicts.push("tls");
|
|
2936
|
+
return { connection, fillIns, conflicts };
|
|
3059
2937
|
}
|
|
3060
2938
|
function describeRedisUrlConflicts(conflicts) {
|
|
3061
2939
|
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.`;
|
|
@@ -3105,28 +2983,49 @@ function getRedisClass() {
|
|
|
3105
2983
|
});
|
|
3106
2984
|
}
|
|
3107
2985
|
}
|
|
3108
|
-
function
|
|
2986
|
+
function resolveUrlOptions(connectionUrl, options) {
|
|
3109
2987
|
const { url: configUrl, ...siblingFields } = { url: void 0, ...options.config };
|
|
3110
2988
|
if (options.url && configUrl && configUrl !== options.url) {
|
|
3111
2989
|
throw new StorageConfigError("redis", "redis.url and redis.config.url name different servers; set one of them.");
|
|
3112
2990
|
}
|
|
3113
|
-
|
|
3114
|
-
|
|
2991
|
+
return urlConnectionOptions(connectionUrl, siblingFields);
|
|
2992
|
+
}
|
|
2993
|
+
function urlConnectionOptions(url, fields) {
|
|
2994
|
+
const merge = mergeRedisUrlFields(url, fields);
|
|
2995
|
+
if (!merge) return void 0;
|
|
2996
|
+
if (merge.conflicts.length > 0) {
|
|
3115
2997
|
throw new StorageConfigError("redis", describeRedisUrlConflicts(merge.conflicts));
|
|
3116
2998
|
}
|
|
3117
|
-
|
|
2999
|
+
const { queryOptions, tls, ...stated } = merge.connection;
|
|
3000
|
+
return { ...queryOptions, ...stated, ...toFillInOptions(merge.fillIns), ...tls ? { tls: {} } : {} };
|
|
3001
|
+
}
|
|
3002
|
+
function toFillInOptions({ port, password, db, tls }) {
|
|
3003
|
+
return {
|
|
3004
|
+
...port !== void 0 ? { port } : {},
|
|
3005
|
+
...password !== void 0 ? { password } : {},
|
|
3006
|
+
...db !== void 0 ? { db } : {},
|
|
3007
|
+
...tls ? { tls: {} } : {}
|
|
3008
|
+
};
|
|
3118
3009
|
}
|
|
3119
3010
|
function createRedisClient(options) {
|
|
3011
|
+
const urlOptions = options.url ? urlConnectionOptions(options.url, options) : void 0;
|
|
3120
3012
|
const RedisClass = getRedisClass();
|
|
3121
3013
|
const baseOptions = { lazyConnect: false, maxRetriesPerRequest: 3 };
|
|
3122
|
-
|
|
3123
|
-
|
|
3124
|
-
|
|
3125
|
-
|
|
3126
|
-
|
|
3127
|
-
|
|
3128
|
-
|
|
3129
|
-
|
|
3014
|
+
let client;
|
|
3015
|
+
if (urlOptions) {
|
|
3016
|
+
client = new RedisClass({ ...baseOptions, ...urlOptions });
|
|
3017
|
+
} else if (options.url) {
|
|
3018
|
+
client = new RedisClass(options.url, baseOptions);
|
|
3019
|
+
} else {
|
|
3020
|
+
client = new RedisClass({
|
|
3021
|
+
...baseOptions,
|
|
3022
|
+
host: options.host ?? "localhost",
|
|
3023
|
+
port: options.port ?? 6379,
|
|
3024
|
+
password: options.password,
|
|
3025
|
+
db: options.db ?? 0,
|
|
3026
|
+
tls: options.tls ? {} : void 0
|
|
3027
|
+
});
|
|
3028
|
+
}
|
|
3130
3029
|
attachRedisErrorListener(client, { label: options.label ?? "redis", logger: options.logger });
|
|
3131
3030
|
return client;
|
|
3132
3031
|
}
|
|
@@ -3151,7 +3050,8 @@ var init_redis = __esm({
|
|
|
3151
3050
|
keyPrefix;
|
|
3152
3051
|
subscriptionHandlers = /* @__PURE__ */ new Map();
|
|
3153
3052
|
connectionUrl;
|
|
3154
|
-
|
|
3053
|
+
/** The connection options of a URL this adapter reads itself; undefined for one only ioredis reads. */
|
|
3054
|
+
urlOptions;
|
|
3155
3055
|
constructor(options = {}) {
|
|
3156
3056
|
super();
|
|
3157
3057
|
const hasClient = options.client !== void 0;
|
|
@@ -3175,7 +3075,7 @@ var init_redis = __esm({
|
|
|
3175
3075
|
this.keyPrefix = options.keyPrefix ?? "";
|
|
3176
3076
|
const configUrl = options.config?.url;
|
|
3177
3077
|
this.connectionUrl = options.url ?? (typeof configUrl === "string" ? configUrl : void 0);
|
|
3178
|
-
this.
|
|
3078
|
+
this.urlOptions = this.connectionUrl ? resolveUrlOptions(this.connectionUrl, options) : void 0;
|
|
3179
3079
|
}
|
|
3180
3080
|
// ============================================
|
|
3181
3081
|
// Connection Lifecycle
|
|
@@ -3197,12 +3097,7 @@ var init_redis = __esm({
|
|
|
3197
3097
|
if (this.options.client) {
|
|
3198
3098
|
client = this.options.client;
|
|
3199
3099
|
} else {
|
|
3200
|
-
|
|
3201
|
-
if (this.connectionUrl) {
|
|
3202
|
-
client = new RedisClass(this.connectionUrl, this.buildRedisOptions());
|
|
3203
|
-
} else {
|
|
3204
|
-
client = new RedisClass(this.buildRedisOptions());
|
|
3205
|
-
}
|
|
3100
|
+
client = this.newClient();
|
|
3206
3101
|
client.on("error", recordSocketError);
|
|
3207
3102
|
}
|
|
3208
3103
|
await client.ping();
|
|
@@ -3436,15 +3331,7 @@ var init_redis = __esm({
|
|
|
3436
3331
|
*/
|
|
3437
3332
|
buildRedisOptions() {
|
|
3438
3333
|
if (this.connectionUrl) {
|
|
3439
|
-
|
|
3440
|
-
return {
|
|
3441
|
-
...port !== void 0 ? { port } : {},
|
|
3442
|
-
...password !== void 0 ? { password } : {},
|
|
3443
|
-
...db !== void 0 ? { db } : {},
|
|
3444
|
-
...tls ? { tls: {} } : {},
|
|
3445
|
-
lazyConnect: false,
|
|
3446
|
-
maxRetriesPerRequest: 3
|
|
3447
|
-
};
|
|
3334
|
+
return { lazyConnect: false, maxRetriesPerRequest: 3, ...this.urlOptions };
|
|
3448
3335
|
}
|
|
3449
3336
|
const config = this.options.config;
|
|
3450
3337
|
if (!config || typeof config.url === "string" || config.host === void 0) {
|
|
@@ -3460,16 +3347,23 @@ var init_redis = __esm({
|
|
|
3460
3347
|
maxRetriesPerRequest: 3
|
|
3461
3348
|
};
|
|
3462
3349
|
}
|
|
3350
|
+
/**
|
|
3351
|
+
* Create a client this adapter owns. A URL only ioredis reads goes to it as is.
|
|
3352
|
+
*/
|
|
3353
|
+
newClient() {
|
|
3354
|
+
const RedisClass = getRedisClass();
|
|
3355
|
+
if (this.connectionUrl && !this.urlOptions) {
|
|
3356
|
+
return new RedisClass(this.connectionUrl, this.buildRedisOptions());
|
|
3357
|
+
}
|
|
3358
|
+
return new RedisClass(this.buildRedisOptions());
|
|
3359
|
+
}
|
|
3463
3360
|
/**
|
|
3464
3361
|
* Create subscriber connection.
|
|
3465
3362
|
*/
|
|
3466
3363
|
async createSubscriber() {
|
|
3467
|
-
const RedisClass = getRedisClass();
|
|
3468
3364
|
let subscriber;
|
|
3469
|
-
if (this.connectionUrl) {
|
|
3470
|
-
subscriber =
|
|
3471
|
-
} else if (this.options.config) {
|
|
3472
|
-
subscriber = new RedisClass(this.buildRedisOptions());
|
|
3365
|
+
if (this.connectionUrl || this.options.config) {
|
|
3366
|
+
subscriber = this.newClient();
|
|
3473
3367
|
} else if (this.options.client) {
|
|
3474
3368
|
subscriber = this.options.client.duplicate();
|
|
3475
3369
|
} else {
|
|
@@ -4243,6 +4137,7 @@ __export(index_exports, {
|
|
|
4243
4137
|
base64urlDecode: () => base64urlDecode,
|
|
4244
4138
|
base64urlEncode: () => base64urlEncode,
|
|
4245
4139
|
basename: () => import_path2.basename,
|
|
4140
|
+
brandClass: () => brandClass,
|
|
4246
4141
|
buildPrefix: () => buildPrefix,
|
|
4247
4142
|
buildSetCookie: () => buildSetCookie,
|
|
4248
4143
|
bytesToHex: () => bytesToHex,
|
|
@@ -4293,11 +4188,12 @@ __export(index_exports, {
|
|
|
4293
4188
|
extractTemplateParams: () => extractTemplateParams,
|
|
4294
4189
|
extractUriScheme: () => extractUriScheme,
|
|
4295
4190
|
fileExists: () => fileExists,
|
|
4191
|
+
fileExistsSync: () => fileExistsSync,
|
|
4296
4192
|
findNonFiniteNumber: () => findNonFiniteNumber,
|
|
4297
4193
|
generateCodeChallenge: () => generateCodeChallenge,
|
|
4298
4194
|
generateCodeVerifier: () => generateCodeVerifier,
|
|
4299
4195
|
generatePkcePair: () => generatePkcePair,
|
|
4300
|
-
generateRsaKeyPair: () =>
|
|
4196
|
+
generateRsaKeyPair: () => generateRsaKeyPair3,
|
|
4301
4197
|
generateSecret: () => generateSecret,
|
|
4302
4198
|
getAsyncContextMode: () => import_async_context.getAsyncContextMode,
|
|
4303
4199
|
getCookie: () => getCookie,
|
|
@@ -4319,6 +4215,7 @@ __export(index_exports, {
|
|
|
4319
4215
|
inferMimeType: () => inferMimeType,
|
|
4320
4216
|
isAbsolute: () => import_path2.isAbsolute,
|
|
4321
4217
|
isAsymmetricKeyData: () => isAsymmetricKeyData,
|
|
4218
|
+
isBrandedInstance: () => isBrandedInstance,
|
|
4322
4219
|
isBrowser: () => isBrowser,
|
|
4323
4220
|
isDebug: () => import_env2.isDebug,
|
|
4324
4221
|
isDevelopment: () => import_env2.isDevelopment,
|
|
@@ -4362,7 +4259,7 @@ __export(index_exports, {
|
|
|
4362
4259
|
pathJoin: () => import_path2.join,
|
|
4363
4260
|
pathResolve: () => import_path2.resolve,
|
|
4364
4261
|
pathToFileURL: () => import_path2.pathToFileURL,
|
|
4365
|
-
pemToPublicJwk: () =>
|
|
4262
|
+
pemToPublicJwk: () => pemToPublicJwk3,
|
|
4366
4263
|
processPlatformToolCalls: () => processPlatformToolCalls,
|
|
4367
4264
|
randomBytes: () => randomBytes,
|
|
4368
4265
|
randomUUID: () => randomUUID,
|
|
@@ -4377,9 +4274,9 @@ __export(index_exports, {
|
|
|
4377
4274
|
resetRuntimeContext: () => import_runtime_context.resetRuntimeContext,
|
|
4378
4275
|
resolveSecretPath: () => resolveSecretPath,
|
|
4379
4276
|
rm: () => rm,
|
|
4380
|
-
rsaSignBase64Url: () =>
|
|
4381
|
-
rsaVerify: () =>
|
|
4382
|
-
rsaVerifySync: () =>
|
|
4277
|
+
rsaSignBase64Url: () => rsaSignBase64Url3,
|
|
4278
|
+
rsaVerify: () => rsaVerify3,
|
|
4279
|
+
rsaVerifySync: () => rsaVerifySync3,
|
|
4383
4280
|
runCmd: () => runCmd,
|
|
4384
4281
|
runRequestExclusive: () => import_async_context.runRequestExclusive,
|
|
4385
4282
|
safeExec: () => safeExec,
|
|
@@ -5223,6 +5120,30 @@ function safeJsonForScript(value) {
|
|
|
5223
5120
|
}
|
|
5224
5121
|
}
|
|
5225
5122
|
|
|
5123
|
+
// libs/utils/src/class-brand/class-brand.ts
|
|
5124
|
+
var CLASS_BRAND = /* @__PURE__ */ Symbol.for("@frontmcp/class-brand");
|
|
5125
|
+
var ordinaryHasInstance = Function.prototype[Symbol.hasInstance];
|
|
5126
|
+
function ownBrandOf(klass) {
|
|
5127
|
+
if (typeof klass !== "function" || !Object.prototype.hasOwnProperty.call(klass, CLASS_BRAND)) return void 0;
|
|
5128
|
+
return klass[CLASS_BRAND];
|
|
5129
|
+
}
|
|
5130
|
+
function classOfPrototype(proto) {
|
|
5131
|
+
return Object.getOwnPropertyDescriptor(proto, "constructor")?.value;
|
|
5132
|
+
}
|
|
5133
|
+
function brandClass(klass, brand) {
|
|
5134
|
+
Object.defineProperty(klass, CLASS_BRAND, { value: brand, enumerable: false, writable: false, configurable: false });
|
|
5135
|
+
}
|
|
5136
|
+
function isBrandedInstance(klass, value) {
|
|
5137
|
+
if (ordinaryHasInstance.call(klass, value)) return true;
|
|
5138
|
+
if (typeof value !== "object" || value === null) return false;
|
|
5139
|
+
const brand = ownBrandOf(klass);
|
|
5140
|
+
if (brand === void 0) return false;
|
|
5141
|
+
for (let proto = Object.getPrototypeOf(value); proto !== null; proto = Object.getPrototypeOf(proto)) {
|
|
5142
|
+
if (ownBrandOf(classOfPrototype(proto)) === brand) return true;
|
|
5143
|
+
}
|
|
5144
|
+
return false;
|
|
5145
|
+
}
|
|
5146
|
+
|
|
5226
5147
|
// libs/utils/src/serialization/serialization.ts
|
|
5227
5148
|
function safeStringify(value, space) {
|
|
5228
5149
|
const seen = /* @__PURE__ */ new WeakSet();
|
|
@@ -6223,6 +6144,7 @@ function setMachineIdOverride(id) {
|
|
|
6223
6144
|
base64urlDecode,
|
|
6224
6145
|
base64urlEncode,
|
|
6225
6146
|
basename,
|
|
6147
|
+
brandClass,
|
|
6226
6148
|
buildPrefix,
|
|
6227
6149
|
buildSetCookie,
|
|
6228
6150
|
bytesToHex,
|
|
@@ -6273,6 +6195,7 @@ function setMachineIdOverride(id) {
|
|
|
6273
6195
|
extractTemplateParams,
|
|
6274
6196
|
extractUriScheme,
|
|
6275
6197
|
fileExists,
|
|
6198
|
+
fileExistsSync,
|
|
6276
6199
|
findNonFiniteNumber,
|
|
6277
6200
|
generateCodeChallenge,
|
|
6278
6201
|
generateCodeVerifier,
|
|
@@ -6299,6 +6222,7 @@ function setMachineIdOverride(id) {
|
|
|
6299
6222
|
inferMimeType,
|
|
6300
6223
|
isAbsolute,
|
|
6301
6224
|
isAsymmetricKeyData,
|
|
6225
|
+
isBrandedInstance,
|
|
6302
6226
|
isBrowser,
|
|
6303
6227
|
isDebug,
|
|
6304
6228
|
isDevelopment,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@frontmcp/utils",
|
|
3
|
-
"version": "1.9.
|
|
3
|
+
"version": "1.9.4",
|
|
4
4
|
"description": "Shared utility functions for FrontMCP - string manipulation, URI handling, path utilities, and more",
|
|
5
5
|
"author": "AgentFront <info@agentfront.dev>",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -32,11 +32,15 @@
|
|
|
32
32
|
"@noble/hashes": "^2.0.1"
|
|
33
33
|
},
|
|
34
34
|
"peerDependencies": {
|
|
35
|
-
"@frontmcp/lazy-zod": "1.9.
|
|
35
|
+
"@frontmcp/lazy-zod": "1.9.4",
|
|
36
|
+
"@upstash/redis": "^1.34.0",
|
|
36
37
|
"@vercel/kv": "^2.0.0 || ^3.0.0",
|
|
37
38
|
"ioredis": "^5.0.0"
|
|
38
39
|
},
|
|
39
40
|
"peerDependenciesMeta": {
|
|
41
|
+
"@upstash/redis": {
|
|
42
|
+
"optional": true
|
|
43
|
+
},
|
|
40
44
|
"@vercel/kv": {
|
|
41
45
|
"optional": true
|
|
42
46
|
},
|
|
@@ -40,7 +40,8 @@ export declare class RedisStorageAdapter extends BaseStorageAdapter {
|
|
|
40
40
|
private readonly keyPrefix;
|
|
41
41
|
private readonly subscriptionHandlers;
|
|
42
42
|
private readonly connectionUrl?;
|
|
43
|
-
|
|
43
|
+
/** The connection options of a URL this adapter reads itself; undefined for one only ioredis reads. */
|
|
44
|
+
private readonly urlOptions?;
|
|
44
45
|
constructor(options?: RedisAdapterOptions);
|
|
45
46
|
connect(): Promise<void>;
|
|
46
47
|
private openConnection;
|
|
@@ -75,6 +76,10 @@ export declare class RedisStorageAdapter extends BaseStorageAdapter {
|
|
|
75
76
|
* Build Redis options from config.
|
|
76
77
|
*/
|
|
77
78
|
private buildRedisOptions;
|
|
79
|
+
/**
|
|
80
|
+
* Create a client this adapter owns. A URL only ioredis reads goes to it as is.
|
|
81
|
+
*/
|
|
82
|
+
private newClient;
|
|
78
83
|
/**
|
|
79
84
|
* Create subscriber connection.
|
|
80
85
|
*/
|
|
@@ -106,6 +111,9 @@ export interface CreateRedisClientOptions {
|
|
|
106
111
|
/**
|
|
107
112
|
* Create a plain ioredis client that reconnects on its own and never emits an unhandled
|
|
108
113
|
* 'error' event. The caller owns the client and must `quit()`/`disconnect()` it.
|
|
114
|
+
*
|
|
115
|
+
* With a `url`, the other connection fields fill in only what the URL leaves out (port,
|
|
116
|
+
* password, db, tls), and one that contradicts it throws a `StorageConfigError`.
|
|
109
117
|
*/
|
|
110
118
|
export declare function createRedisClient(options: CreateRedisClientOptions): Redis;
|
|
111
119
|
export {};
|