@frontmcp/utils 1.9.1 → 1.9.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/crypto/browser.d.ts +5 -0
- package/crypto/browser.js +33 -5
- package/crypto/node.d.ts +1 -1
- package/env/browser-env.d.ts +6 -0
- package/env/browser-env.js +12 -3
- package/env/browser-runtime-context.d.ts +4 -0
- package/env/browser-runtime-context.js +29 -3
- package/esm/crypto/browser.mjs +27 -4
- package/esm/env/browser-env.mjs +12 -3
- package/esm/env/browser-runtime-context.mjs +29 -3
- package/esm/index.mjs +196 -223
- package/index.d.ts +2 -2
- package/index.js +201 -225
- package/package.json +6 -2
- package/storage/adapters/index.d.ts +1 -1
- package/storage/adapters/redis.d.ts +10 -0
- package/storage/adapters/vercel-kv.d.ts +41 -0
- package/storage/index.d.ts +5 -3
- package/storage/redis-url.d.ts +50 -0
- package/storage/types.d.ts +31 -9
package/esm/index.mjs
CHANGED
|
@@ -2539,186 +2539,25 @@ var init_key_persistence2 = __esm({
|
|
|
2539
2539
|
}
|
|
2540
2540
|
});
|
|
2541
2541
|
|
|
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
2542
|
// libs/utils/src/crypto/browser.ts
|
|
2709
2543
|
var browser_exports = {};
|
|
2710
2544
|
__export(browser_exports, {
|
|
2711
2545
|
browserCrypto: () => browserCrypto,
|
|
2712
2546
|
cryptoProvider: () => browserCrypto,
|
|
2547
|
+
generateRsaKeyPair: () => generateRsaKeyPair,
|
|
2713
2548
|
isRsaPssAlg: () => isRsaPssAlg,
|
|
2714
2549
|
jwtAlgToWebCryptoAlg: () => jwtAlgToWebCryptoAlg,
|
|
2715
|
-
|
|
2550
|
+
pemToPublicJwk: () => pemToPublicJwk,
|
|
2551
|
+
rsaSignBase64Url: () => rsaSignBase64Url,
|
|
2552
|
+
rsaVerify: () => rsaVerify,
|
|
2553
|
+
rsaVerifyBrowser: () => rsaVerifyBrowser,
|
|
2554
|
+
rsaVerifySync: () => rsaVerifySync
|
|
2716
2555
|
});
|
|
2717
|
-
import {
|
|
2718
|
-
import { hmac } from "@noble/hashes/hmac.js";
|
|
2556
|
+
import { gcm } from "@noble/ciphers/aes.js";
|
|
2719
2557
|
import { hkdf } from "@noble/hashes/hkdf.js";
|
|
2558
|
+
import { hmac } from "@noble/hashes/hmac.js";
|
|
2559
|
+
import { sha256 as sha256Hash } from "@noble/hashes/sha2.js";
|
|
2720
2560
|
import { randomBytes as nobleRandomBytes } from "@noble/hashes/utils.js";
|
|
2721
|
-
import { gcm } from "@noble/ciphers/aes.js";
|
|
2722
2561
|
function toBytes(data) {
|
|
2723
2562
|
if (typeof data === "string") {
|
|
2724
2563
|
return new TextEncoder().encode(data);
|
|
@@ -2746,6 +2585,24 @@ function constantTimeEqual(a, b) {
|
|
|
2746
2585
|
}
|
|
2747
2586
|
return result === 0;
|
|
2748
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
|
+
}
|
|
2749
2606
|
async function rsaVerifyBrowser(jwtAlg, data, publicJwk, signature) {
|
|
2750
2607
|
if (typeof globalThis.crypto?.subtle === "undefined") {
|
|
2751
2608
|
throw new Error("WebCrypto API (crypto.subtle) is not available in this environment");
|
|
@@ -2825,40 +2682,40 @@ var init_browser = __esm({
|
|
|
2825
2682
|
});
|
|
2826
2683
|
|
|
2827
2684
|
// libs/utils/src/crypto/index.ts
|
|
2828
|
-
import
|
|
2685
|
+
import * as platformCrypto from "#crypto-provider";
|
|
2829
2686
|
function getCrypto() {
|
|
2830
|
-
return
|
|
2687
|
+
return platformCrypto.cryptoProvider;
|
|
2831
2688
|
}
|
|
2832
|
-
function
|
|
2689
|
+
function rsaVerify3(jwtAlg, data, publicJwk, signature) {
|
|
2833
2690
|
if (isNode()) {
|
|
2834
|
-
return Promise.resolve(
|
|
2691
|
+
return Promise.resolve(platformCrypto.rsaVerify(jwtAlg, data, publicJwk, signature));
|
|
2835
2692
|
}
|
|
2836
2693
|
const { rsaVerifyBrowser: rsaVerifyBrowser2 } = (init_browser(), __toCommonJS(browser_exports));
|
|
2837
2694
|
return rsaVerifyBrowser2(jwtAlg, data, publicJwk, signature);
|
|
2838
2695
|
}
|
|
2839
|
-
function
|
|
2696
|
+
function rsaSignBase64Url3(jwtAlg, data, privateJwk) {
|
|
2840
2697
|
if (!isNode()) {
|
|
2841
2698
|
throw new Error("rsaSignBase64Url is only available in Node.js runtimes");
|
|
2842
2699
|
}
|
|
2843
|
-
return
|
|
2700
|
+
return platformCrypto.rsaSignBase64Url(jwtAlg, data, privateJwk);
|
|
2844
2701
|
}
|
|
2845
|
-
function
|
|
2702
|
+
function rsaVerifySync3(jwtAlg, data, publicJwk, signature) {
|
|
2846
2703
|
if (!isNode()) {
|
|
2847
2704
|
throw new Error("rsaVerifySync is only available in Node.js runtimes; use the async rsaVerify in browsers");
|
|
2848
2705
|
}
|
|
2849
|
-
return
|
|
2706
|
+
return platformCrypto.rsaVerifySync(jwtAlg, data, publicJwk, signature);
|
|
2850
2707
|
}
|
|
2851
|
-
function
|
|
2708
|
+
function pemToPublicJwk3(pem) {
|
|
2852
2709
|
if (!isNode()) {
|
|
2853
2710
|
throw new Error("pemToPublicJwk is only available in Node.js runtimes");
|
|
2854
2711
|
}
|
|
2855
|
-
return
|
|
2712
|
+
return platformCrypto.pemToPublicJwk(pem);
|
|
2856
2713
|
}
|
|
2857
|
-
function
|
|
2714
|
+
function generateRsaKeyPair3(modulusLength, alg) {
|
|
2858
2715
|
if (!isNode()) {
|
|
2859
2716
|
throw new Error("generateRsaKeyPair is only available in Node.js runtimes");
|
|
2860
2717
|
}
|
|
2861
|
-
return
|
|
2718
|
+
return platformCrypto.generateRsaKeyPair(modulusLength, alg);
|
|
2862
2719
|
}
|
|
2863
2720
|
function randomUUID() {
|
|
2864
2721
|
return getCrypto().randomUUID();
|
|
@@ -3015,6 +2872,73 @@ var init_redis_error_listener = __esm({
|
|
|
3015
2872
|
}
|
|
3016
2873
|
});
|
|
3017
2874
|
|
|
2875
|
+
// libs/utils/src/storage/redis-url.ts
|
|
2876
|
+
function decodeOrRaw(encoded) {
|
|
2877
|
+
try {
|
|
2878
|
+
return decodeURIComponent(encoded);
|
|
2879
|
+
} catch {
|
|
2880
|
+
return encoded;
|
|
2881
|
+
}
|
|
2882
|
+
}
|
|
2883
|
+
function integerOrUndefined(text) {
|
|
2884
|
+
const value = Number.parseInt(text ?? "", 10);
|
|
2885
|
+
return Number.isNaN(value) ? void 0 : value;
|
|
2886
|
+
}
|
|
2887
|
+
function readRedisUrl(rawUrl) {
|
|
2888
|
+
let url;
|
|
2889
|
+
try {
|
|
2890
|
+
url = new URL(rawUrl);
|
|
2891
|
+
} catch {
|
|
2892
|
+
return void 0;
|
|
2893
|
+
}
|
|
2894
|
+
if (url.protocol !== "redis:" && url.protocol !== "rediss:") return void 0;
|
|
2895
|
+
const query = Object.fromEntries(url.searchParams);
|
|
2896
|
+
const { host, port, username, password, db, ...otherOptions } = query;
|
|
2897
|
+
const queryOptions = {};
|
|
2898
|
+
for (const [name, value = ""] of Object.entries(otherOptions)) {
|
|
2899
|
+
queryOptions[name] = name === "family" ? integerOrUndefined(value) ?? value : value;
|
|
2900
|
+
}
|
|
2901
|
+
return {
|
|
2902
|
+
host: url.hostname.replace(/^\[(.*)\]$/, "$1") || host,
|
|
2903
|
+
port: integerOrUndefined(url.port || port),
|
|
2904
|
+
username: decodeOrRaw(url.username) || username || void 0,
|
|
2905
|
+
password: decodeOrRaw(url.password) || password || void 0,
|
|
2906
|
+
db: integerOrUndefined(url.pathname.replace(/^\/+/, "") || db),
|
|
2907
|
+
tls: url.protocol === "rediss:",
|
|
2908
|
+
queryOptions
|
|
2909
|
+
};
|
|
2910
|
+
}
|
|
2911
|
+
function mergeRedisUrlFields(rawUrl, fields) {
|
|
2912
|
+
const connection = readRedisUrl(rawUrl);
|
|
2913
|
+
if (!connection) return void 0;
|
|
2914
|
+
const fillIns = {};
|
|
2915
|
+
const conflicts = [];
|
|
2916
|
+
if (fields.host !== void 0 && fields.host !== connection.host) conflicts.push("host");
|
|
2917
|
+
if (fields.port !== void 0) {
|
|
2918
|
+
if (connection.port === void 0) fillIns.port = fields.port;
|
|
2919
|
+
else if (fields.port !== connection.port) conflicts.push("port");
|
|
2920
|
+
}
|
|
2921
|
+
if (fields.password !== void 0) {
|
|
2922
|
+
if (connection.password === void 0) fillIns.password = fields.password;
|
|
2923
|
+
else if (fields.password !== connection.password) conflicts.push("password");
|
|
2924
|
+
}
|
|
2925
|
+
if (fields.db !== void 0) {
|
|
2926
|
+
if (connection.db === void 0) fillIns.db = fields.db;
|
|
2927
|
+
else if (fields.db !== connection.db) conflicts.push("db");
|
|
2928
|
+
}
|
|
2929
|
+
if (fields.tls === true && !connection.tls) fillIns.tls = true;
|
|
2930
|
+
if (fields.tls === false && connection.tls) conflicts.push("tls");
|
|
2931
|
+
return { connection, fillIns, conflicts };
|
|
2932
|
+
}
|
|
2933
|
+
function describeRedisUrlConflicts(conflicts) {
|
|
2934
|
+
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.`;
|
|
2935
|
+
}
|
|
2936
|
+
var init_redis_url = __esm({
|
|
2937
|
+
"libs/utils/src/storage/redis-url.ts"() {
|
|
2938
|
+
"use strict";
|
|
2939
|
+
}
|
|
2940
|
+
});
|
|
2941
|
+
|
|
3018
2942
|
// libs/utils/src/storage/utils/index.ts
|
|
3019
2943
|
var init_utils = __esm({
|
|
3020
2944
|
"libs/utils/src/storage/utils/index.ts"() {
|
|
@@ -3054,17 +2978,49 @@ function getRedisClass() {
|
|
|
3054
2978
|
});
|
|
3055
2979
|
}
|
|
3056
2980
|
}
|
|
2981
|
+
function resolveUrlOptions(connectionUrl, options) {
|
|
2982
|
+
const { url: configUrl, ...siblingFields } = { url: void 0, ...options.config };
|
|
2983
|
+
if (options.url && configUrl && configUrl !== options.url) {
|
|
2984
|
+
throw new StorageConfigError("redis", "redis.url and redis.config.url name different servers; set one of them.");
|
|
2985
|
+
}
|
|
2986
|
+
return urlConnectionOptions(connectionUrl, siblingFields);
|
|
2987
|
+
}
|
|
2988
|
+
function urlConnectionOptions(url, fields) {
|
|
2989
|
+
const merge = mergeRedisUrlFields(url, fields);
|
|
2990
|
+
if (!merge) return void 0;
|
|
2991
|
+
if (merge.conflicts.length > 0) {
|
|
2992
|
+
throw new StorageConfigError("redis", describeRedisUrlConflicts(merge.conflicts));
|
|
2993
|
+
}
|
|
2994
|
+
const { queryOptions, tls, ...stated } = merge.connection;
|
|
2995
|
+
return { ...queryOptions, ...stated, ...toFillInOptions(merge.fillIns), ...tls ? { tls: {} } : {} };
|
|
2996
|
+
}
|
|
2997
|
+
function toFillInOptions({ port, password, db, tls }) {
|
|
2998
|
+
return {
|
|
2999
|
+
...port !== void 0 ? { port } : {},
|
|
3000
|
+
...password !== void 0 ? { password } : {},
|
|
3001
|
+
...db !== void 0 ? { db } : {},
|
|
3002
|
+
...tls ? { tls: {} } : {}
|
|
3003
|
+
};
|
|
3004
|
+
}
|
|
3057
3005
|
function createRedisClient(options) {
|
|
3006
|
+
const urlOptions = options.url ? urlConnectionOptions(options.url, options) : void 0;
|
|
3058
3007
|
const RedisClass = getRedisClass();
|
|
3059
3008
|
const baseOptions = { lazyConnect: false, maxRetriesPerRequest: 3 };
|
|
3060
|
-
|
|
3061
|
-
|
|
3062
|
-
|
|
3063
|
-
|
|
3064
|
-
|
|
3065
|
-
|
|
3066
|
-
|
|
3067
|
-
|
|
3009
|
+
let client;
|
|
3010
|
+
if (urlOptions) {
|
|
3011
|
+
client = new RedisClass({ ...baseOptions, ...urlOptions });
|
|
3012
|
+
} else if (options.url) {
|
|
3013
|
+
client = new RedisClass(options.url, baseOptions);
|
|
3014
|
+
} else {
|
|
3015
|
+
client = new RedisClass({
|
|
3016
|
+
...baseOptions,
|
|
3017
|
+
host: options.host ?? "localhost",
|
|
3018
|
+
port: options.port ?? 6379,
|
|
3019
|
+
password: options.password,
|
|
3020
|
+
db: options.db ?? 0,
|
|
3021
|
+
tls: options.tls ? {} : void 0
|
|
3022
|
+
});
|
|
3023
|
+
}
|
|
3068
3024
|
attachRedisErrorListener(client, { label: options.label ?? "redis", logger: options.logger });
|
|
3069
3025
|
return client;
|
|
3070
3026
|
}
|
|
@@ -3074,6 +3030,7 @@ var init_redis = __esm({
|
|
|
3074
3030
|
"use strict";
|
|
3075
3031
|
init_errors();
|
|
3076
3032
|
init_redis_error_listener();
|
|
3033
|
+
init_redis_url();
|
|
3077
3034
|
init_utils();
|
|
3078
3035
|
init_compare_and_delete();
|
|
3079
3036
|
init_base();
|
|
@@ -3087,6 +3044,9 @@ var init_redis = __esm({
|
|
|
3087
3044
|
connecting;
|
|
3088
3045
|
keyPrefix;
|
|
3089
3046
|
subscriptionHandlers = /* @__PURE__ */ new Map();
|
|
3047
|
+
connectionUrl;
|
|
3048
|
+
/** The connection options of a URL this adapter reads itself; undefined for one only ioredis reads. */
|
|
3049
|
+
urlOptions;
|
|
3090
3050
|
constructor(options = {}) {
|
|
3091
3051
|
super();
|
|
3092
3052
|
const hasClient = options.client !== void 0;
|
|
@@ -3108,6 +3068,9 @@ var init_redis = __esm({
|
|
|
3108
3068
|
this.options = options;
|
|
3109
3069
|
this.ownsClient = !hasClient;
|
|
3110
3070
|
this.keyPrefix = options.keyPrefix ?? "";
|
|
3071
|
+
const configUrl = options.config?.url;
|
|
3072
|
+
this.connectionUrl = options.url ?? (typeof configUrl === "string" ? configUrl : void 0);
|
|
3073
|
+
this.urlOptions = this.connectionUrl ? resolveUrlOptions(this.connectionUrl, options) : void 0;
|
|
3111
3074
|
}
|
|
3112
3075
|
// ============================================
|
|
3113
3076
|
// Connection Lifecycle
|
|
@@ -3129,12 +3092,7 @@ var init_redis = __esm({
|
|
|
3129
3092
|
if (this.options.client) {
|
|
3130
3093
|
client = this.options.client;
|
|
3131
3094
|
} else {
|
|
3132
|
-
|
|
3133
|
-
if (this.options.url) {
|
|
3134
|
-
client = new RedisClass(this.options.url, this.buildRedisOptions());
|
|
3135
|
-
} else {
|
|
3136
|
-
client = new RedisClass(this.buildRedisOptions());
|
|
3137
|
-
}
|
|
3095
|
+
client = this.newClient();
|
|
3138
3096
|
client.on("error", recordSocketError);
|
|
3139
3097
|
}
|
|
3140
3098
|
await client.ping();
|
|
@@ -3367,14 +3325,11 @@ var init_redis = __esm({
|
|
|
3367
3325
|
* Build Redis options from config.
|
|
3368
3326
|
*/
|
|
3369
3327
|
buildRedisOptions() {
|
|
3370
|
-
if (this.
|
|
3371
|
-
return {
|
|
3372
|
-
lazyConnect: false,
|
|
3373
|
-
maxRetriesPerRequest: 3
|
|
3374
|
-
};
|
|
3328
|
+
if (this.connectionUrl) {
|
|
3329
|
+
return { lazyConnect: false, maxRetriesPerRequest: 3, ...this.urlOptions };
|
|
3375
3330
|
}
|
|
3376
3331
|
const config = this.options.config;
|
|
3377
|
-
if (!config) {
|
|
3332
|
+
if (!config || typeof config.url === "string" || config.host === void 0) {
|
|
3378
3333
|
throw new StorageConfigError("redis", "Redis config is required when URL is not provided");
|
|
3379
3334
|
}
|
|
3380
3335
|
return {
|
|
@@ -3387,16 +3342,23 @@ var init_redis = __esm({
|
|
|
3387
3342
|
maxRetriesPerRequest: 3
|
|
3388
3343
|
};
|
|
3389
3344
|
}
|
|
3345
|
+
/**
|
|
3346
|
+
* Create a client this adapter owns. A URL only ioredis reads goes to it as is.
|
|
3347
|
+
*/
|
|
3348
|
+
newClient() {
|
|
3349
|
+
const RedisClass = getRedisClass();
|
|
3350
|
+
if (this.connectionUrl && !this.urlOptions) {
|
|
3351
|
+
return new RedisClass(this.connectionUrl, this.buildRedisOptions());
|
|
3352
|
+
}
|
|
3353
|
+
return new RedisClass(this.buildRedisOptions());
|
|
3354
|
+
}
|
|
3390
3355
|
/**
|
|
3391
3356
|
* Create subscriber connection.
|
|
3392
3357
|
*/
|
|
3393
3358
|
async createSubscriber() {
|
|
3394
|
-
const RedisClass = getRedisClass();
|
|
3395
3359
|
let subscriber;
|
|
3396
|
-
if (this.options.
|
|
3397
|
-
subscriber =
|
|
3398
|
-
} else if (this.options.config) {
|
|
3399
|
-
subscriber = new RedisClass(this.buildRedisOptions());
|
|
3360
|
+
if (this.connectionUrl || this.options.config) {
|
|
3361
|
+
subscriber = this.newClient();
|
|
3400
3362
|
} else if (this.options.client) {
|
|
3401
3363
|
subscriber = this.options.client.duplicate();
|
|
3402
3364
|
} else {
|
|
@@ -3445,7 +3407,8 @@ var init_redis = __esm({
|
|
|
3445
3407
|
// libs/utils/src/storage/adapters/vercel-kv.ts
|
|
3446
3408
|
var vercel_kv_exports = {};
|
|
3447
3409
|
__export(vercel_kv_exports, {
|
|
3448
|
-
VercelKvStorageAdapter: () => VercelKvStorageAdapter
|
|
3410
|
+
VercelKvStorageAdapter: () => VercelKvStorageAdapter,
|
|
3411
|
+
createVercelKvClient: () => createVercelKvClient
|
|
3449
3412
|
});
|
|
3450
3413
|
async function loadVercelKv() {
|
|
3451
3414
|
try {
|
|
@@ -3457,6 +3420,15 @@ async function loadVercelKv() {
|
|
|
3457
3420
|
throw new Error("@vercel/kv is required for Vercel KV storage adapter. Install it with: npm install @vercel/kv");
|
|
3458
3421
|
}
|
|
3459
3422
|
}
|
|
3423
|
+
async function createVercelKvClient(connection = {}) {
|
|
3424
|
+
const url = connection.url ?? process.env["KV_REST_API_URL"];
|
|
3425
|
+
const token = connection.token ?? process.env["KV_REST_API_TOKEN"];
|
|
3426
|
+
if (!url || !token) {
|
|
3427
|
+
throw new StorageConfigError("vercel-kv", "Pass url and token, or set KV_REST_API_URL and KV_REST_API_TOKEN.");
|
|
3428
|
+
}
|
|
3429
|
+
const { createClient } = await loadVercelKv();
|
|
3430
|
+
return createClient({ url, token, cache: void 0, automaticDeserialization: false });
|
|
3431
|
+
}
|
|
3460
3432
|
var VercelKvStorageAdapter;
|
|
3461
3433
|
var init_vercel_kv = __esm({
|
|
3462
3434
|
"libs/utils/src/storage/adapters/vercel-kv.ts"() {
|
|
@@ -3489,13 +3461,7 @@ var init_vercel_kv = __esm({
|
|
|
3489
3461
|
async connect() {
|
|
3490
3462
|
if (this.connected) return;
|
|
3491
3463
|
try {
|
|
3492
|
-
|
|
3493
|
-
const url = this.options.url;
|
|
3494
|
-
const token = this.options.token;
|
|
3495
|
-
if (!url || !token) {
|
|
3496
|
-
throw new StorageConfigError("vercel-kv", "URL and token are required");
|
|
3497
|
-
}
|
|
3498
|
-
this.client = createClient({ url, token, cache: void 0, automaticDeserialization: false });
|
|
3464
|
+
this.client = await createVercelKvClient({ url: this.options.url, token: this.options.token });
|
|
3499
3465
|
await this.client.exists("__healthcheck__");
|
|
3500
3466
|
this.connected = true;
|
|
3501
3467
|
} catch (e) {
|
|
@@ -3668,9 +3634,12 @@ var upstash_exports = {};
|
|
|
3668
3634
|
__export(upstash_exports, {
|
|
3669
3635
|
UpstashStorageAdapter: () => UpstashStorageAdapter
|
|
3670
3636
|
});
|
|
3671
|
-
function
|
|
3637
|
+
async function loadUpstashRedis() {
|
|
3672
3638
|
try {
|
|
3673
|
-
|
|
3639
|
+
const mod = await import("@upstash/redis");
|
|
3640
|
+
const resolved = typeof mod.Redis === "function" ? mod : mod.default;
|
|
3641
|
+
if (!resolved || typeof resolved.Redis !== "function") throw new Error("Redis missing");
|
|
3642
|
+
return resolved;
|
|
3674
3643
|
} catch {
|
|
3675
3644
|
throw new Error(
|
|
3676
3645
|
"@upstash/redis is required for Upstash storage adapter. Install it with: npm install @upstash/redis"
|
|
@@ -3715,7 +3684,7 @@ var init_upstash = __esm({
|
|
|
3715
3684
|
async connect() {
|
|
3716
3685
|
if (this.connected) return;
|
|
3717
3686
|
try {
|
|
3718
|
-
const { Redis } =
|
|
3687
|
+
const { Redis } = await loadUpstashRedis();
|
|
3719
3688
|
const url = this.options.url;
|
|
3720
3689
|
const token = this.options.token;
|
|
3721
3690
|
if (!url || !token) {
|
|
@@ -5243,6 +5212,7 @@ function getDetectedStorageType() {
|
|
|
5243
5212
|
|
|
5244
5213
|
// libs/utils/src/storage/index.ts
|
|
5245
5214
|
init_redis_error_listener();
|
|
5215
|
+
init_redis_url();
|
|
5246
5216
|
init_errors();
|
|
5247
5217
|
|
|
5248
5218
|
// libs/utils/src/storage/typed-storage.ts
|
|
@@ -5956,9 +5926,11 @@ export {
|
|
|
5956
5926
|
createSafeRegExp,
|
|
5957
5927
|
createSecretData,
|
|
5958
5928
|
createStorage,
|
|
5929
|
+
createVercelKvClient,
|
|
5959
5930
|
decryptAesGcm,
|
|
5960
5931
|
decryptValue,
|
|
5961
5932
|
deleteSecret,
|
|
5933
|
+
describeRedisUrlConflicts,
|
|
5962
5934
|
deserializeAndDecrypt,
|
|
5963
5935
|
deserializeBlob,
|
|
5964
5936
|
detectRuntimeContext,
|
|
@@ -5989,7 +5961,7 @@ export {
|
|
|
5989
5961
|
generateCodeChallenge,
|
|
5990
5962
|
generateCodeVerifier,
|
|
5991
5963
|
generatePkcePair,
|
|
5992
|
-
|
|
5964
|
+
generateRsaKeyPair3 as generateRsaKeyPair,
|
|
5993
5965
|
generateSecret,
|
|
5994
5966
|
getAsyncContextMode,
|
|
5995
5967
|
getCookie,
|
|
@@ -6042,6 +6014,7 @@ export {
|
|
|
6042
6014
|
loadSecret,
|
|
6043
6015
|
matchUriTemplate,
|
|
6044
6016
|
matchesPattern,
|
|
6017
|
+
mergeRedisUrlFields,
|
|
6045
6018
|
mkdir,
|
|
6046
6019
|
mkdtemp,
|
|
6047
6020
|
normalizeTTL,
|
|
@@ -6053,7 +6026,7 @@ export {
|
|
|
6053
6026
|
join as pathJoin,
|
|
6054
6027
|
resolve as pathResolve,
|
|
6055
6028
|
pathToFileURL,
|
|
6056
|
-
|
|
6029
|
+
pemToPublicJwk3 as pemToPublicJwk,
|
|
6057
6030
|
processPlatformToolCalls,
|
|
6058
6031
|
randomBytes,
|
|
6059
6032
|
randomUUID,
|
|
@@ -6068,9 +6041,9 @@ export {
|
|
|
6068
6041
|
resetRuntimeContext,
|
|
6069
6042
|
resolveSecretPath,
|
|
6070
6043
|
rm,
|
|
6071
|
-
|
|
6072
|
-
|
|
6073
|
-
|
|
6044
|
+
rsaSignBase64Url3 as rsaSignBase64Url,
|
|
6045
|
+
rsaVerify3 as rsaVerify,
|
|
6046
|
+
rsaVerifySync3 as rsaVerifySync,
|
|
6074
6047
|
runCmd,
|
|
6075
6048
|
runRequestExclusive,
|
|
6076
6049
|
safeExec,
|
package/index.d.ts
CHANGED
|
@@ -26,8 +26,8 @@ export { EventEmitter } from './event-emitter';
|
|
|
26
26
|
export { getEnv, getNodeEnv, getCwd, isProduction, isDevelopment, getEnvFlag, isDebug, setEnv, isEdgeRuntime, isServerless, supportsAnsi, getRuntimeContext, resetRuntimeContext, detectRuntimeContext, isEntryAvailable, checkEntryAvailability, entryAvailabilitySchema, } from './env';
|
|
27
27
|
export type { RuntimeContext, EntryAvailability } from './env';
|
|
28
28
|
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
|
-
export { createStorage, createMemoryStorage, getDetectedStorageType, NamespacedStorageImpl, createRootStorage, createNamespacedStorage, buildPrefix, NAMESPACE_SEPARATOR, StorageError, StorageConnectionError, StorageOperationError, StorageNotSupportedError, StorageConfigError, StorageTTLError, StoragePatternError, StorageNotConnectedError, EncryptedStorageError, BaseStorageAdapter, MemoryStorageAdapter, RedisStorageAdapter, createRedisClient, VercelKvStorageAdapter, 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, } from './storage';
|
|
30
|
-
export type { StorageAdapter, NamespacedStorage, RootStorage, SetOptions, SetEntry, MessageHandler, Unsubscribe, MemoryAdapterOptions, RedisAdapterOptions, VercelKvAdapterOptions, UpstashAdapterOptions, StorageType, StorageConfig, RedisErrorListenerOptions, CreateRedisClientOptions, ErrorEmitterClient, } from './storage';
|
|
29
|
+
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, RedisUrlConnection, RedisUrlMerge, RedisUrlSiblingFields, CreateRedisClientOptions, ErrorEmitterClient, } from './storage';
|
|
31
31
|
export { processPlatformToolCalls } from './llm';
|
|
32
32
|
export type { CallToolFn, OpenAIToolCallItem, OpenAIToolResponse, ClaudeToolUseBlock, ClaudeToolResultBlock, VercelToolCallInfo, PlatformToolCallsInput, PlatformToolCallsOutput, SupportedPlatform, } from './llm';
|
|
33
33
|
export { getMachineId, setMachineIdOverride } from './machine-id';
|