@frontmcp/utils 1.9.2 → 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/esm/crypto/browser.mjs +27 -4
- package/esm/index.mjs +129 -238
- package/index.d.ts +1 -1
- package/index.js +131 -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/crypto/browser.d.ts
CHANGED
|
@@ -11,6 +11,11 @@ import type { CryptoProvider } from './types';
|
|
|
11
11
|
export declare const browserCrypto: CryptoProvider;
|
|
12
12
|
/** Alias for conditional import resolution via `#crypto-provider`. */
|
|
13
13
|
export { browserCrypto as cryptoProvider };
|
|
14
|
+
export declare function rsaVerify(): boolean;
|
|
15
|
+
export declare function rsaSignBase64Url(): string;
|
|
16
|
+
export declare function rsaVerifySync(): boolean;
|
|
17
|
+
export declare function pemToPublicJwk(): JsonWebKey;
|
|
18
|
+
export declare function generateRsaKeyPair(): never;
|
|
14
19
|
export { isRsaPssAlg, jwtAlgToWebCryptoAlg } from './jwt-alg';
|
|
15
20
|
/**
|
|
16
21
|
* Verify an RSA signature using WebCrypto.
|
package/crypto/browser.js
CHANGED
|
@@ -22,16 +22,21 @@ var browser_exports = {};
|
|
|
22
22
|
__export(browser_exports, {
|
|
23
23
|
browserCrypto: () => browserCrypto,
|
|
24
24
|
cryptoProvider: () => browserCrypto,
|
|
25
|
+
generateRsaKeyPair: () => generateRsaKeyPair,
|
|
25
26
|
isRsaPssAlg: () => isRsaPssAlg,
|
|
26
27
|
jwtAlgToWebCryptoAlg: () => jwtAlgToWebCryptoAlg,
|
|
27
|
-
|
|
28
|
+
pemToPublicJwk: () => pemToPublicJwk,
|
|
29
|
+
rsaSignBase64Url: () => rsaSignBase64Url,
|
|
30
|
+
rsaVerify: () => rsaVerify,
|
|
31
|
+
rsaVerifyBrowser: () => rsaVerifyBrowser,
|
|
32
|
+
rsaVerifySync: () => rsaVerifySync
|
|
28
33
|
});
|
|
29
34
|
module.exports = __toCommonJS(browser_exports);
|
|
30
|
-
var
|
|
31
|
-
var import_hmac = require("@noble/hashes/hmac.js");
|
|
35
|
+
var import_aes = require("@noble/ciphers/aes.js");
|
|
32
36
|
var import_hkdf = require("@noble/hashes/hkdf.js");
|
|
37
|
+
var import_hmac = require("@noble/hashes/hmac.js");
|
|
38
|
+
var import_sha2 = require("@noble/hashes/sha2.js");
|
|
33
39
|
var import_utils = require("@noble/hashes/utils.js");
|
|
34
|
-
var import_aes = require("@noble/ciphers/aes.js");
|
|
35
40
|
|
|
36
41
|
// libs/utils/src/crypto/jwt-alg.ts
|
|
37
42
|
function isRsaPssAlg(jwtAlg) {
|
|
@@ -119,6 +124,24 @@ var browserCrypto = {
|
|
|
119
124
|
return constantTimeEqual(a, b);
|
|
120
125
|
}
|
|
121
126
|
};
|
|
127
|
+
function nodeOnly(name) {
|
|
128
|
+
throw new Error(`${name} is only available in Node.js runtimes`);
|
|
129
|
+
}
|
|
130
|
+
function rsaVerify() {
|
|
131
|
+
return nodeOnly("rsaVerify");
|
|
132
|
+
}
|
|
133
|
+
function rsaSignBase64Url() {
|
|
134
|
+
return nodeOnly("rsaSignBase64Url");
|
|
135
|
+
}
|
|
136
|
+
function rsaVerifySync() {
|
|
137
|
+
return nodeOnly("rsaVerifySync");
|
|
138
|
+
}
|
|
139
|
+
function pemToPublicJwk() {
|
|
140
|
+
return nodeOnly("pemToPublicJwk");
|
|
141
|
+
}
|
|
142
|
+
function generateRsaKeyPair() {
|
|
143
|
+
return nodeOnly("generateRsaKeyPair");
|
|
144
|
+
}
|
|
122
145
|
async function rsaVerifyBrowser(jwtAlg, data, publicJwk, signature) {
|
|
123
146
|
if (typeof globalThis.crypto?.subtle === "undefined") {
|
|
124
147
|
throw new Error("WebCrypto API (crypto.subtle) is not available in this environment");
|
|
@@ -154,7 +177,12 @@ function getSaltLength(jwtAlg) {
|
|
|
154
177
|
0 && (module.exports = {
|
|
155
178
|
browserCrypto,
|
|
156
179
|
cryptoProvider,
|
|
180
|
+
generateRsaKeyPair,
|
|
157
181
|
isRsaPssAlg,
|
|
158
182
|
jwtAlgToWebCryptoAlg,
|
|
159
|
-
|
|
183
|
+
pemToPublicJwk,
|
|
184
|
+
rsaSignBase64Url,
|
|
185
|
+
rsaVerify,
|
|
186
|
+
rsaVerifyBrowser,
|
|
187
|
+
rsaVerifySync
|
|
160
188
|
});
|
package/crypto/node.d.ts
CHANGED
|
@@ -48,7 +48,7 @@ export declare function generateRsaKeyPair(modulusLength?: number, alg?: string)
|
|
|
48
48
|
* For RSA-PSS (PS256/PS384/PS512), callers must pass appropriate padding/saltLength options.
|
|
49
49
|
*/
|
|
50
50
|
export declare function rsaSign(algorithm: string, data: Buffer, privateKey: crypto.KeyObject, options?: Omit<crypto.SignKeyObjectInput, 'key'>): Buffer;
|
|
51
|
-
export declare function rsaVerify(jwtAlg: string, data: Buffer, publicJwk: JsonWebKey, signature: Buffer): boolean;
|
|
51
|
+
export declare function rsaVerify(jwtAlg: string, data: Buffer | Uint8Array, publicJwk: JsonWebKey, signature: Buffer | Uint8Array): boolean;
|
|
52
52
|
/**
|
|
53
53
|
* Sign data with an RSA private JWK and return a base64url-encoded signature.
|
|
54
54
|
*
|
package/esm/crypto/browser.mjs
CHANGED
|
@@ -2,11 +2,11 @@ var __frontmcpModule = typeof process !== "undefined" && typeof process.getBuilt
|
|
|
2
2
|
const require = __frontmcpModule ? __frontmcpModule.createRequire(import.meta.url || 'file:///') : undefined;
|
|
3
3
|
// __frontmcpCreateRequire
|
|
4
4
|
// libs/utils/src/crypto/browser.ts
|
|
5
|
-
import {
|
|
6
|
-
import { hmac } from "@noble/hashes/hmac.js";
|
|
5
|
+
import { gcm } from "@noble/ciphers/aes.js";
|
|
7
6
|
import { hkdf } from "@noble/hashes/hkdf.js";
|
|
7
|
+
import { hmac } from "@noble/hashes/hmac.js";
|
|
8
|
+
import { sha256 as sha256Hash } from "@noble/hashes/sha2.js";
|
|
8
9
|
import { randomBytes as nobleRandomBytes } from "@noble/hashes/utils.js";
|
|
9
|
-
import { gcm } from "@noble/ciphers/aes.js";
|
|
10
10
|
|
|
11
11
|
// libs/utils/src/crypto/jwt-alg.ts
|
|
12
12
|
function isRsaPssAlg(jwtAlg) {
|
|
@@ -94,6 +94,24 @@ var browserCrypto = {
|
|
|
94
94
|
return constantTimeEqual(a, b);
|
|
95
95
|
}
|
|
96
96
|
};
|
|
97
|
+
function nodeOnly(name) {
|
|
98
|
+
throw new Error(`${name} is only available in Node.js runtimes`);
|
|
99
|
+
}
|
|
100
|
+
function rsaVerify() {
|
|
101
|
+
return nodeOnly("rsaVerify");
|
|
102
|
+
}
|
|
103
|
+
function rsaSignBase64Url() {
|
|
104
|
+
return nodeOnly("rsaSignBase64Url");
|
|
105
|
+
}
|
|
106
|
+
function rsaVerifySync() {
|
|
107
|
+
return nodeOnly("rsaVerifySync");
|
|
108
|
+
}
|
|
109
|
+
function pemToPublicJwk() {
|
|
110
|
+
return nodeOnly("pemToPublicJwk");
|
|
111
|
+
}
|
|
112
|
+
function generateRsaKeyPair() {
|
|
113
|
+
return nodeOnly("generateRsaKeyPair");
|
|
114
|
+
}
|
|
97
115
|
async function rsaVerifyBrowser(jwtAlg, data, publicJwk, signature) {
|
|
98
116
|
if (typeof globalThis.crypto?.subtle === "undefined") {
|
|
99
117
|
throw new Error("WebCrypto API (crypto.subtle) is not available in this environment");
|
|
@@ -128,7 +146,12 @@ function getSaltLength(jwtAlg) {
|
|
|
128
146
|
export {
|
|
129
147
|
browserCrypto,
|
|
130
148
|
browserCrypto as cryptoProvider,
|
|
149
|
+
generateRsaKeyPair,
|
|
131
150
|
isRsaPssAlg,
|
|
132
151
|
jwtAlgToWebCryptoAlg,
|
|
133
|
-
|
|
152
|
+
pemToPublicJwk,
|
|
153
|
+
rsaSignBase64Url,
|
|
154
|
+
rsaVerify,
|
|
155
|
+
rsaVerifyBrowser,
|
|
156
|
+
rsaVerifySync
|
|
134
157
|
};
|
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();
|
|
@@ -3023,37 +2880,55 @@ function decodeOrRaw(encoded) {
|
|
|
3023
2880
|
return encoded;
|
|
3024
2881
|
}
|
|
3025
2882
|
}
|
|
3026
|
-
function
|
|
2883
|
+
function integerOrUndefined(text) {
|
|
2884
|
+
const value = Number.parseInt(text ?? "", 10);
|
|
2885
|
+
return Number.isNaN(value) ? void 0 : value;
|
|
2886
|
+
}
|
|
2887
|
+
function readRedisUrl(rawUrl) {
|
|
3027
2888
|
let url;
|
|
3028
2889
|
try {
|
|
3029
2890
|
url = new URL(rawUrl);
|
|
3030
2891
|
} catch {
|
|
3031
2892
|
return void 0;
|
|
3032
2893
|
}
|
|
3033
|
-
|
|
3034
|
-
const
|
|
3035
|
-
const
|
|
3036
|
-
const
|
|
3037
|
-
const
|
|
3038
|
-
|
|
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;
|
|
3039
2914
|
const fillIns = {};
|
|
3040
2915
|
const conflicts = [];
|
|
3041
|
-
if (fields.host !== void 0 && fields.host !==
|
|
2916
|
+
if (fields.host !== void 0 && fields.host !== connection.host) conflicts.push("host");
|
|
3042
2917
|
if (fields.port !== void 0) {
|
|
3043
|
-
if (
|
|
3044
|
-
else if (fields.port !==
|
|
2918
|
+
if (connection.port === void 0) fillIns.port = fields.port;
|
|
2919
|
+
else if (fields.port !== connection.port) conflicts.push("port");
|
|
3045
2920
|
}
|
|
3046
2921
|
if (fields.password !== void 0) {
|
|
3047
|
-
if (
|
|
3048
|
-
else if (fields.password !==
|
|
2922
|
+
if (connection.password === void 0) fillIns.password = fields.password;
|
|
2923
|
+
else if (fields.password !== connection.password) conflicts.push("password");
|
|
3049
2924
|
}
|
|
3050
2925
|
if (fields.db !== void 0) {
|
|
3051
|
-
if (
|
|
3052
|
-
else if (fields.db !==
|
|
2926
|
+
if (connection.db === void 0) fillIns.db = fields.db;
|
|
2927
|
+
else if (fields.db !== connection.db) conflicts.push("db");
|
|
3053
2928
|
}
|
|
3054
|
-
if (fields.tls === true && !
|
|
3055
|
-
if (fields.tls === false &&
|
|
3056
|
-
return { fillIns, conflicts };
|
|
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 };
|
|
3057
2932
|
}
|
|
3058
2933
|
function describeRedisUrlConflicts(conflicts) {
|
|
3059
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.`;
|
|
@@ -3103,28 +2978,49 @@ function getRedisClass() {
|
|
|
3103
2978
|
});
|
|
3104
2979
|
}
|
|
3105
2980
|
}
|
|
3106
|
-
function
|
|
2981
|
+
function resolveUrlOptions(connectionUrl, options) {
|
|
3107
2982
|
const { url: configUrl, ...siblingFields } = { url: void 0, ...options.config };
|
|
3108
2983
|
if (options.url && configUrl && configUrl !== options.url) {
|
|
3109
2984
|
throw new StorageConfigError("redis", "redis.url and redis.config.url name different servers; set one of them.");
|
|
3110
2985
|
}
|
|
3111
|
-
|
|
3112
|
-
|
|
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) {
|
|
3113
2992
|
throw new StorageConfigError("redis", describeRedisUrlConflicts(merge.conflicts));
|
|
3114
2993
|
}
|
|
3115
|
-
|
|
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
|
+
};
|
|
3116
3004
|
}
|
|
3117
3005
|
function createRedisClient(options) {
|
|
3006
|
+
const urlOptions = options.url ? urlConnectionOptions(options.url, options) : void 0;
|
|
3118
3007
|
const RedisClass = getRedisClass();
|
|
3119
3008
|
const baseOptions = { lazyConnect: false, maxRetriesPerRequest: 3 };
|
|
3120
|
-
|
|
3121
|
-
|
|
3122
|
-
|
|
3123
|
-
|
|
3124
|
-
|
|
3125
|
-
|
|
3126
|
-
|
|
3127
|
-
|
|
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
|
+
}
|
|
3128
3024
|
attachRedisErrorListener(client, { label: options.label ?? "redis", logger: options.logger });
|
|
3129
3025
|
return client;
|
|
3130
3026
|
}
|
|
@@ -3149,7 +3045,8 @@ var init_redis = __esm({
|
|
|
3149
3045
|
keyPrefix;
|
|
3150
3046
|
subscriptionHandlers = /* @__PURE__ */ new Map();
|
|
3151
3047
|
connectionUrl;
|
|
3152
|
-
|
|
3048
|
+
/** The connection options of a URL this adapter reads itself; undefined for one only ioredis reads. */
|
|
3049
|
+
urlOptions;
|
|
3153
3050
|
constructor(options = {}) {
|
|
3154
3051
|
super();
|
|
3155
3052
|
const hasClient = options.client !== void 0;
|
|
@@ -3173,7 +3070,7 @@ var init_redis = __esm({
|
|
|
3173
3070
|
this.keyPrefix = options.keyPrefix ?? "";
|
|
3174
3071
|
const configUrl = options.config?.url;
|
|
3175
3072
|
this.connectionUrl = options.url ?? (typeof configUrl === "string" ? configUrl : void 0);
|
|
3176
|
-
this.
|
|
3073
|
+
this.urlOptions = this.connectionUrl ? resolveUrlOptions(this.connectionUrl, options) : void 0;
|
|
3177
3074
|
}
|
|
3178
3075
|
// ============================================
|
|
3179
3076
|
// Connection Lifecycle
|
|
@@ -3195,12 +3092,7 @@ var init_redis = __esm({
|
|
|
3195
3092
|
if (this.options.client) {
|
|
3196
3093
|
client = this.options.client;
|
|
3197
3094
|
} else {
|
|
3198
|
-
|
|
3199
|
-
if (this.connectionUrl) {
|
|
3200
|
-
client = new RedisClass(this.connectionUrl, this.buildRedisOptions());
|
|
3201
|
-
} else {
|
|
3202
|
-
client = new RedisClass(this.buildRedisOptions());
|
|
3203
|
-
}
|
|
3095
|
+
client = this.newClient();
|
|
3204
3096
|
client.on("error", recordSocketError);
|
|
3205
3097
|
}
|
|
3206
3098
|
await client.ping();
|
|
@@ -3434,15 +3326,7 @@ var init_redis = __esm({
|
|
|
3434
3326
|
*/
|
|
3435
3327
|
buildRedisOptions() {
|
|
3436
3328
|
if (this.connectionUrl) {
|
|
3437
|
-
|
|
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
|
-
};
|
|
3329
|
+
return { lazyConnect: false, maxRetriesPerRequest: 3, ...this.urlOptions };
|
|
3446
3330
|
}
|
|
3447
3331
|
const config = this.options.config;
|
|
3448
3332
|
if (!config || typeof config.url === "string" || config.host === void 0) {
|
|
@@ -3458,16 +3342,23 @@ var init_redis = __esm({
|
|
|
3458
3342
|
maxRetriesPerRequest: 3
|
|
3459
3343
|
};
|
|
3460
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
|
+
}
|
|
3461
3355
|
/**
|
|
3462
3356
|
* Create subscriber connection.
|
|
3463
3357
|
*/
|
|
3464
3358
|
async createSubscriber() {
|
|
3465
|
-
const RedisClass = getRedisClass();
|
|
3466
3359
|
let subscriber;
|
|
3467
|
-
if (this.connectionUrl) {
|
|
3468
|
-
subscriber =
|
|
3469
|
-
} else if (this.options.config) {
|
|
3470
|
-
subscriber = new RedisClass(this.buildRedisOptions());
|
|
3360
|
+
if (this.connectionUrl || this.options.config) {
|
|
3361
|
+
subscriber = this.newClient();
|
|
3471
3362
|
} else if (this.options.client) {
|
|
3472
3363
|
subscriber = this.options.client.duplicate();
|
|
3473
3364
|
} else {
|
|
@@ -6070,7 +5961,7 @@ export {
|
|
|
6070
5961
|
generateCodeChallenge,
|
|
6071
5962
|
generateCodeVerifier,
|
|
6072
5963
|
generatePkcePair,
|
|
6073
|
-
|
|
5964
|
+
generateRsaKeyPair3 as generateRsaKeyPair,
|
|
6074
5965
|
generateSecret,
|
|
6075
5966
|
getAsyncContextMode,
|
|
6076
5967
|
getCookie,
|
|
@@ -6135,7 +6026,7 @@ export {
|
|
|
6135
6026
|
join as pathJoin,
|
|
6136
6027
|
resolve as pathResolve,
|
|
6137
6028
|
pathToFileURL,
|
|
6138
|
-
|
|
6029
|
+
pemToPublicJwk3 as pemToPublicJwk,
|
|
6139
6030
|
processPlatformToolCalls,
|
|
6140
6031
|
randomBytes,
|
|
6141
6032
|
randomUUID,
|
|
@@ -6150,9 +6041,9 @@ export {
|
|
|
6150
6041
|
resetRuntimeContext,
|
|
6151
6042
|
resolveSecretPath,
|
|
6152
6043
|
rm,
|
|
6153
|
-
|
|
6154
|
-
|
|
6155
|
-
|
|
6044
|
+
rsaSignBase64Url3 as rsaSignBase64Url,
|
|
6045
|
+
rsaVerify3 as rsaVerify,
|
|
6046
|
+
rsaVerifySync3 as rsaVerifySync,
|
|
6156
6047
|
runCmd,
|
|
6157
6048
|
runRequestExclusive,
|
|
6158
6049
|
safeExec,
|
package/index.d.ts
CHANGED
|
@@ -27,7 +27,7 @@ export { getEnv, getNodeEnv, getCwd, isProduction, isDevelopment, getEnvFlag, is
|
|
|
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
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, RedisUrlMerge, RedisUrlSiblingFields, CreateRedisClientOptions, ErrorEmitterClient, } 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';
|
package/index.js
CHANGED
|
@@ -2541,180 +2541,19 @@ var init_key_persistence2 = __esm({
|
|
|
2541
2541
|
}
|
|
2542
2542
|
});
|
|
2543
2543
|
|
|
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
2544
|
// libs/utils/src/crypto/browser.ts
|
|
2711
2545
|
var browser_exports = {};
|
|
2712
2546
|
__export(browser_exports, {
|
|
2713
2547
|
browserCrypto: () => browserCrypto,
|
|
2714
2548
|
cryptoProvider: () => browserCrypto,
|
|
2549
|
+
generateRsaKeyPair: () => generateRsaKeyPair,
|
|
2715
2550
|
isRsaPssAlg: () => isRsaPssAlg,
|
|
2716
2551
|
jwtAlgToWebCryptoAlg: () => jwtAlgToWebCryptoAlg,
|
|
2717
|
-
|
|
2552
|
+
pemToPublicJwk: () => pemToPublicJwk,
|
|
2553
|
+
rsaSignBase64Url: () => rsaSignBase64Url,
|
|
2554
|
+
rsaVerify: () => rsaVerify,
|
|
2555
|
+
rsaVerifyBrowser: () => rsaVerifyBrowser,
|
|
2556
|
+
rsaVerifySync: () => rsaVerifySync
|
|
2718
2557
|
});
|
|
2719
2558
|
function toBytes(data) {
|
|
2720
2559
|
if (typeof data === "string") {
|
|
@@ -2743,6 +2582,24 @@ function constantTimeEqual(a, b) {
|
|
|
2743
2582
|
}
|
|
2744
2583
|
return result === 0;
|
|
2745
2584
|
}
|
|
2585
|
+
function nodeOnly(name) {
|
|
2586
|
+
throw new Error(`${name} is only available in Node.js runtimes`);
|
|
2587
|
+
}
|
|
2588
|
+
function rsaVerify() {
|
|
2589
|
+
return nodeOnly("rsaVerify");
|
|
2590
|
+
}
|
|
2591
|
+
function rsaSignBase64Url() {
|
|
2592
|
+
return nodeOnly("rsaSignBase64Url");
|
|
2593
|
+
}
|
|
2594
|
+
function rsaVerifySync() {
|
|
2595
|
+
return nodeOnly("rsaVerifySync");
|
|
2596
|
+
}
|
|
2597
|
+
function pemToPublicJwk() {
|
|
2598
|
+
return nodeOnly("pemToPublicJwk");
|
|
2599
|
+
}
|
|
2600
|
+
function generateRsaKeyPair() {
|
|
2601
|
+
return nodeOnly("generateRsaKeyPair");
|
|
2602
|
+
}
|
|
2746
2603
|
async function rsaVerifyBrowser(jwtAlg, data, publicJwk, signature) {
|
|
2747
2604
|
if (typeof globalThis.crypto?.subtle === "undefined") {
|
|
2748
2605
|
throw new Error("WebCrypto API (crypto.subtle) is not available in this environment");
|
|
@@ -2774,15 +2631,15 @@ function getSaltLength(jwtAlg) {
|
|
|
2774
2631
|
return 32;
|
|
2775
2632
|
}
|
|
2776
2633
|
}
|
|
2777
|
-
var
|
|
2634
|
+
var import_aes, import_hkdf, import_hmac, import_sha2, import_utils, browserCrypto;
|
|
2778
2635
|
var init_browser = __esm({
|
|
2779
2636
|
"libs/utils/src/crypto/browser.ts"() {
|
|
2780
2637
|
"use strict";
|
|
2781
|
-
|
|
2782
|
-
import_hmac = require("@noble/hashes/hmac.js");
|
|
2638
|
+
import_aes = require("@noble/ciphers/aes.js");
|
|
2783
2639
|
import_hkdf = require("@noble/hashes/hkdf.js");
|
|
2640
|
+
import_hmac = require("@noble/hashes/hmac.js");
|
|
2641
|
+
import_sha2 = require("@noble/hashes/sha2.js");
|
|
2784
2642
|
import_utils = require("@noble/hashes/utils.js");
|
|
2785
|
-
import_aes = require("@noble/ciphers/aes.js");
|
|
2786
2643
|
init_jwt_alg();
|
|
2787
2644
|
init_jwt_alg();
|
|
2788
2645
|
browserCrypto = {
|
|
@@ -2828,38 +2685,38 @@ var init_browser = __esm({
|
|
|
2828
2685
|
|
|
2829
2686
|
// libs/utils/src/crypto/index.ts
|
|
2830
2687
|
function getCrypto() {
|
|
2831
|
-
return
|
|
2688
|
+
return platformCrypto.cryptoProvider;
|
|
2832
2689
|
}
|
|
2833
|
-
function
|
|
2690
|
+
function rsaVerify3(jwtAlg, data, publicJwk, signature) {
|
|
2834
2691
|
if (isNode()) {
|
|
2835
|
-
return Promise.resolve(
|
|
2692
|
+
return Promise.resolve(platformCrypto.rsaVerify(jwtAlg, data, publicJwk, signature));
|
|
2836
2693
|
}
|
|
2837
2694
|
const { rsaVerifyBrowser: rsaVerifyBrowser2 } = (init_browser(), __toCommonJS(browser_exports));
|
|
2838
2695
|
return rsaVerifyBrowser2(jwtAlg, data, publicJwk, signature);
|
|
2839
2696
|
}
|
|
2840
|
-
function
|
|
2697
|
+
function rsaSignBase64Url3(jwtAlg, data, privateJwk) {
|
|
2841
2698
|
if (!isNode()) {
|
|
2842
2699
|
throw new Error("rsaSignBase64Url is only available in Node.js runtimes");
|
|
2843
2700
|
}
|
|
2844
|
-
return
|
|
2701
|
+
return platformCrypto.rsaSignBase64Url(jwtAlg, data, privateJwk);
|
|
2845
2702
|
}
|
|
2846
|
-
function
|
|
2703
|
+
function rsaVerifySync3(jwtAlg, data, publicJwk, signature) {
|
|
2847
2704
|
if (!isNode()) {
|
|
2848
2705
|
throw new Error("rsaVerifySync is only available in Node.js runtimes; use the async rsaVerify in browsers");
|
|
2849
2706
|
}
|
|
2850
|
-
return
|
|
2707
|
+
return platformCrypto.rsaVerifySync(jwtAlg, data, publicJwk, signature);
|
|
2851
2708
|
}
|
|
2852
|
-
function
|
|
2709
|
+
function pemToPublicJwk3(pem) {
|
|
2853
2710
|
if (!isNode()) {
|
|
2854
2711
|
throw new Error("pemToPublicJwk is only available in Node.js runtimes");
|
|
2855
2712
|
}
|
|
2856
|
-
return
|
|
2713
|
+
return platformCrypto.pemToPublicJwk(pem);
|
|
2857
2714
|
}
|
|
2858
|
-
function
|
|
2715
|
+
function generateRsaKeyPair3(modulusLength, alg) {
|
|
2859
2716
|
if (!isNode()) {
|
|
2860
2717
|
throw new Error("generateRsaKeyPair is only available in Node.js runtimes");
|
|
2861
2718
|
}
|
|
2862
|
-
return
|
|
2719
|
+
return platformCrypto.generateRsaKeyPair(modulusLength, alg);
|
|
2863
2720
|
}
|
|
2864
2721
|
function randomUUID() {
|
|
2865
2722
|
return getCrypto().randomUUID();
|
|
@@ -2965,11 +2822,11 @@ function base64Decode(data) {
|
|
|
2965
2822
|
function sha256Base64url(data) {
|
|
2966
2823
|
return base64urlEncode(sha256(data));
|
|
2967
2824
|
}
|
|
2968
|
-
var
|
|
2825
|
+
var platformCrypto, HKDF_SHA256_MAX_LENGTH;
|
|
2969
2826
|
var init_crypto = __esm({
|
|
2970
2827
|
"libs/utils/src/crypto/index.ts"() {
|
|
2971
2828
|
"use strict";
|
|
2972
|
-
|
|
2829
|
+
platformCrypto = __toESM(require("#crypto-provider"));
|
|
2973
2830
|
init_runtime();
|
|
2974
2831
|
init_jwt_alg();
|
|
2975
2832
|
init_runtime();
|
|
@@ -3025,37 +2882,55 @@ function decodeOrRaw(encoded) {
|
|
|
3025
2882
|
return encoded;
|
|
3026
2883
|
}
|
|
3027
2884
|
}
|
|
3028
|
-
function
|
|
2885
|
+
function integerOrUndefined(text) {
|
|
2886
|
+
const value = Number.parseInt(text ?? "", 10);
|
|
2887
|
+
return Number.isNaN(value) ? void 0 : value;
|
|
2888
|
+
}
|
|
2889
|
+
function readRedisUrl(rawUrl) {
|
|
3029
2890
|
let url;
|
|
3030
2891
|
try {
|
|
3031
2892
|
url = new URL(rawUrl);
|
|
3032
2893
|
} catch {
|
|
3033
2894
|
return void 0;
|
|
3034
2895
|
}
|
|
3035
|
-
|
|
3036
|
-
const
|
|
3037
|
-
const
|
|
3038
|
-
const
|
|
3039
|
-
const
|
|
3040
|
-
|
|
2896
|
+
if (url.protocol !== "redis:" && url.protocol !== "rediss:") return void 0;
|
|
2897
|
+
const query = Object.fromEntries(url.searchParams);
|
|
2898
|
+
const { host, port, username, password, db, ...otherOptions } = query;
|
|
2899
|
+
const queryOptions = {};
|
|
2900
|
+
for (const [name, value = ""] of Object.entries(otherOptions)) {
|
|
2901
|
+
queryOptions[name] = name === "family" ? integerOrUndefined(value) ?? value : value;
|
|
2902
|
+
}
|
|
2903
|
+
return {
|
|
2904
|
+
host: url.hostname.replace(/^\[(.*)\]$/, "$1") || host,
|
|
2905
|
+
port: integerOrUndefined(url.port || port),
|
|
2906
|
+
username: decodeOrRaw(url.username) || username || void 0,
|
|
2907
|
+
password: decodeOrRaw(url.password) || password || void 0,
|
|
2908
|
+
db: integerOrUndefined(url.pathname.replace(/^\/+/, "") || db),
|
|
2909
|
+
tls: url.protocol === "rediss:",
|
|
2910
|
+
queryOptions
|
|
2911
|
+
};
|
|
2912
|
+
}
|
|
2913
|
+
function mergeRedisUrlFields(rawUrl, fields) {
|
|
2914
|
+
const connection = readRedisUrl(rawUrl);
|
|
2915
|
+
if (!connection) return void 0;
|
|
3041
2916
|
const fillIns = {};
|
|
3042
2917
|
const conflicts = [];
|
|
3043
|
-
if (fields.host !== void 0 && fields.host !==
|
|
2918
|
+
if (fields.host !== void 0 && fields.host !== connection.host) conflicts.push("host");
|
|
3044
2919
|
if (fields.port !== void 0) {
|
|
3045
|
-
if (
|
|
3046
|
-
else if (fields.port !==
|
|
2920
|
+
if (connection.port === void 0) fillIns.port = fields.port;
|
|
2921
|
+
else if (fields.port !== connection.port) conflicts.push("port");
|
|
3047
2922
|
}
|
|
3048
2923
|
if (fields.password !== void 0) {
|
|
3049
|
-
if (
|
|
3050
|
-
else if (fields.password !==
|
|
2924
|
+
if (connection.password === void 0) fillIns.password = fields.password;
|
|
2925
|
+
else if (fields.password !== connection.password) conflicts.push("password");
|
|
3051
2926
|
}
|
|
3052
2927
|
if (fields.db !== void 0) {
|
|
3053
|
-
if (
|
|
3054
|
-
else if (fields.db !==
|
|
2928
|
+
if (connection.db === void 0) fillIns.db = fields.db;
|
|
2929
|
+
else if (fields.db !== connection.db) conflicts.push("db");
|
|
3055
2930
|
}
|
|
3056
|
-
if (fields.tls === true && !
|
|
3057
|
-
if (fields.tls === false &&
|
|
3058
|
-
return { fillIns, conflicts };
|
|
2931
|
+
if (fields.tls === true && !connection.tls) fillIns.tls = true;
|
|
2932
|
+
if (fields.tls === false && connection.tls) conflicts.push("tls");
|
|
2933
|
+
return { connection, fillIns, conflicts };
|
|
3059
2934
|
}
|
|
3060
2935
|
function describeRedisUrlConflicts(conflicts) {
|
|
3061
2936
|
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 +2980,49 @@ function getRedisClass() {
|
|
|
3105
2980
|
});
|
|
3106
2981
|
}
|
|
3107
2982
|
}
|
|
3108
|
-
function
|
|
2983
|
+
function resolveUrlOptions(connectionUrl, options) {
|
|
3109
2984
|
const { url: configUrl, ...siblingFields } = { url: void 0, ...options.config };
|
|
3110
2985
|
if (options.url && configUrl && configUrl !== options.url) {
|
|
3111
2986
|
throw new StorageConfigError("redis", "redis.url and redis.config.url name different servers; set one of them.");
|
|
3112
2987
|
}
|
|
3113
|
-
|
|
3114
|
-
|
|
2988
|
+
return urlConnectionOptions(connectionUrl, siblingFields);
|
|
2989
|
+
}
|
|
2990
|
+
function urlConnectionOptions(url, fields) {
|
|
2991
|
+
const merge = mergeRedisUrlFields(url, fields);
|
|
2992
|
+
if (!merge) return void 0;
|
|
2993
|
+
if (merge.conflicts.length > 0) {
|
|
3115
2994
|
throw new StorageConfigError("redis", describeRedisUrlConflicts(merge.conflicts));
|
|
3116
2995
|
}
|
|
3117
|
-
|
|
2996
|
+
const { queryOptions, tls, ...stated } = merge.connection;
|
|
2997
|
+
return { ...queryOptions, ...stated, ...toFillInOptions(merge.fillIns), ...tls ? { tls: {} } : {} };
|
|
2998
|
+
}
|
|
2999
|
+
function toFillInOptions({ port, password, db, tls }) {
|
|
3000
|
+
return {
|
|
3001
|
+
...port !== void 0 ? { port } : {},
|
|
3002
|
+
...password !== void 0 ? { password } : {},
|
|
3003
|
+
...db !== void 0 ? { db } : {},
|
|
3004
|
+
...tls ? { tls: {} } : {}
|
|
3005
|
+
};
|
|
3118
3006
|
}
|
|
3119
3007
|
function createRedisClient(options) {
|
|
3008
|
+
const urlOptions = options.url ? urlConnectionOptions(options.url, options) : void 0;
|
|
3120
3009
|
const RedisClass = getRedisClass();
|
|
3121
3010
|
const baseOptions = { lazyConnect: false, maxRetriesPerRequest: 3 };
|
|
3122
|
-
|
|
3123
|
-
|
|
3124
|
-
|
|
3125
|
-
|
|
3126
|
-
|
|
3127
|
-
|
|
3128
|
-
|
|
3129
|
-
|
|
3011
|
+
let client;
|
|
3012
|
+
if (urlOptions) {
|
|
3013
|
+
client = new RedisClass({ ...baseOptions, ...urlOptions });
|
|
3014
|
+
} else if (options.url) {
|
|
3015
|
+
client = new RedisClass(options.url, baseOptions);
|
|
3016
|
+
} else {
|
|
3017
|
+
client = new RedisClass({
|
|
3018
|
+
...baseOptions,
|
|
3019
|
+
host: options.host ?? "localhost",
|
|
3020
|
+
port: options.port ?? 6379,
|
|
3021
|
+
password: options.password,
|
|
3022
|
+
db: options.db ?? 0,
|
|
3023
|
+
tls: options.tls ? {} : void 0
|
|
3024
|
+
});
|
|
3025
|
+
}
|
|
3130
3026
|
attachRedisErrorListener(client, { label: options.label ?? "redis", logger: options.logger });
|
|
3131
3027
|
return client;
|
|
3132
3028
|
}
|
|
@@ -3151,7 +3047,8 @@ var init_redis = __esm({
|
|
|
3151
3047
|
keyPrefix;
|
|
3152
3048
|
subscriptionHandlers = /* @__PURE__ */ new Map();
|
|
3153
3049
|
connectionUrl;
|
|
3154
|
-
|
|
3050
|
+
/** The connection options of a URL this adapter reads itself; undefined for one only ioredis reads. */
|
|
3051
|
+
urlOptions;
|
|
3155
3052
|
constructor(options = {}) {
|
|
3156
3053
|
super();
|
|
3157
3054
|
const hasClient = options.client !== void 0;
|
|
@@ -3175,7 +3072,7 @@ var init_redis = __esm({
|
|
|
3175
3072
|
this.keyPrefix = options.keyPrefix ?? "";
|
|
3176
3073
|
const configUrl = options.config?.url;
|
|
3177
3074
|
this.connectionUrl = options.url ?? (typeof configUrl === "string" ? configUrl : void 0);
|
|
3178
|
-
this.
|
|
3075
|
+
this.urlOptions = this.connectionUrl ? resolveUrlOptions(this.connectionUrl, options) : void 0;
|
|
3179
3076
|
}
|
|
3180
3077
|
// ============================================
|
|
3181
3078
|
// Connection Lifecycle
|
|
@@ -3197,12 +3094,7 @@ var init_redis = __esm({
|
|
|
3197
3094
|
if (this.options.client) {
|
|
3198
3095
|
client = this.options.client;
|
|
3199
3096
|
} else {
|
|
3200
|
-
|
|
3201
|
-
if (this.connectionUrl) {
|
|
3202
|
-
client = new RedisClass(this.connectionUrl, this.buildRedisOptions());
|
|
3203
|
-
} else {
|
|
3204
|
-
client = new RedisClass(this.buildRedisOptions());
|
|
3205
|
-
}
|
|
3097
|
+
client = this.newClient();
|
|
3206
3098
|
client.on("error", recordSocketError);
|
|
3207
3099
|
}
|
|
3208
3100
|
await client.ping();
|
|
@@ -3436,15 +3328,7 @@ var init_redis = __esm({
|
|
|
3436
3328
|
*/
|
|
3437
3329
|
buildRedisOptions() {
|
|
3438
3330
|
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
|
-
};
|
|
3331
|
+
return { lazyConnect: false, maxRetriesPerRequest: 3, ...this.urlOptions };
|
|
3448
3332
|
}
|
|
3449
3333
|
const config = this.options.config;
|
|
3450
3334
|
if (!config || typeof config.url === "string" || config.host === void 0) {
|
|
@@ -3460,16 +3344,23 @@ var init_redis = __esm({
|
|
|
3460
3344
|
maxRetriesPerRequest: 3
|
|
3461
3345
|
};
|
|
3462
3346
|
}
|
|
3347
|
+
/**
|
|
3348
|
+
* Create a client this adapter owns. A URL only ioredis reads goes to it as is.
|
|
3349
|
+
*/
|
|
3350
|
+
newClient() {
|
|
3351
|
+
const RedisClass = getRedisClass();
|
|
3352
|
+
if (this.connectionUrl && !this.urlOptions) {
|
|
3353
|
+
return new RedisClass(this.connectionUrl, this.buildRedisOptions());
|
|
3354
|
+
}
|
|
3355
|
+
return new RedisClass(this.buildRedisOptions());
|
|
3356
|
+
}
|
|
3463
3357
|
/**
|
|
3464
3358
|
* Create subscriber connection.
|
|
3465
3359
|
*/
|
|
3466
3360
|
async createSubscriber() {
|
|
3467
|
-
const RedisClass = getRedisClass();
|
|
3468
3361
|
let subscriber;
|
|
3469
|
-
if (this.connectionUrl) {
|
|
3470
|
-
subscriber =
|
|
3471
|
-
} else if (this.options.config) {
|
|
3472
|
-
subscriber = new RedisClass(this.buildRedisOptions());
|
|
3362
|
+
if (this.connectionUrl || this.options.config) {
|
|
3363
|
+
subscriber = this.newClient();
|
|
3473
3364
|
} else if (this.options.client) {
|
|
3474
3365
|
subscriber = this.options.client.duplicate();
|
|
3475
3366
|
} else {
|
|
@@ -4297,7 +4188,7 @@ __export(index_exports, {
|
|
|
4297
4188
|
generateCodeChallenge: () => generateCodeChallenge,
|
|
4298
4189
|
generateCodeVerifier: () => generateCodeVerifier,
|
|
4299
4190
|
generatePkcePair: () => generatePkcePair,
|
|
4300
|
-
generateRsaKeyPair: () =>
|
|
4191
|
+
generateRsaKeyPair: () => generateRsaKeyPair3,
|
|
4301
4192
|
generateSecret: () => generateSecret,
|
|
4302
4193
|
getAsyncContextMode: () => import_async_context.getAsyncContextMode,
|
|
4303
4194
|
getCookie: () => getCookie,
|
|
@@ -4362,7 +4253,7 @@ __export(index_exports, {
|
|
|
4362
4253
|
pathJoin: () => import_path2.join,
|
|
4363
4254
|
pathResolve: () => import_path2.resolve,
|
|
4364
4255
|
pathToFileURL: () => import_path2.pathToFileURL,
|
|
4365
|
-
pemToPublicJwk: () =>
|
|
4256
|
+
pemToPublicJwk: () => pemToPublicJwk3,
|
|
4366
4257
|
processPlatformToolCalls: () => processPlatformToolCalls,
|
|
4367
4258
|
randomBytes: () => randomBytes,
|
|
4368
4259
|
randomUUID: () => randomUUID,
|
|
@@ -4377,9 +4268,9 @@ __export(index_exports, {
|
|
|
4377
4268
|
resetRuntimeContext: () => import_runtime_context.resetRuntimeContext,
|
|
4378
4269
|
resolveSecretPath: () => resolveSecretPath,
|
|
4379
4270
|
rm: () => rm,
|
|
4380
|
-
rsaSignBase64Url: () =>
|
|
4381
|
-
rsaVerify: () =>
|
|
4382
|
-
rsaVerifySync: () =>
|
|
4271
|
+
rsaSignBase64Url: () => rsaSignBase64Url3,
|
|
4272
|
+
rsaVerify: () => rsaVerify3,
|
|
4273
|
+
rsaVerifySync: () => rsaVerifySync3,
|
|
4383
4274
|
runCmd: () => runCmd,
|
|
4384
4275
|
runRequestExclusive: () => import_async_context.runRequestExclusive,
|
|
4385
4276
|
safeExec: () => safeExec,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@frontmcp/utils",
|
|
3
|
-
"version": "1.9.
|
|
3
|
+
"version": "1.9.3",
|
|
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.3",
|
|
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 {};
|
package/storage/index.d.ts
CHANGED
|
@@ -9,7 +9,7 @@ export { createStorage, createMemoryStorage, getDetectedStorageType } from './fa
|
|
|
9
9
|
export { attachRedisErrorListener, DEFAULT_REDIS_ERROR_LOG_INTERVAL_MS } from './redis-error-listener';
|
|
10
10
|
export type { RedisErrorListenerOptions, ErrorEmitterClient } from './redis-error-listener';
|
|
11
11
|
export { mergeRedisUrlFields, describeRedisUrlConflicts } from './redis-url';
|
|
12
|
-
export type { RedisUrlMerge, RedisUrlSiblingFields } from './redis-url';
|
|
12
|
+
export type { RedisUrlConnection, RedisUrlMerge, RedisUrlSiblingFields } from './redis-url';
|
|
13
13
|
export { NamespacedStorageImpl, createRootStorage, createNamespacedStorage, buildPrefix, NAMESPACE_SEPARATOR, } from './namespace';
|
|
14
14
|
export { StorageError, StorageConnectionError, StorageOperationError, StorageNotSupportedError, StorageConfigError, StorageTTLError, StoragePatternError, StorageNotConnectedError, EncryptedStorageError, } from './errors';
|
|
15
15
|
export { TypedStorage } from './typed-storage';
|
package/storage/redis-url.d.ts
CHANGED
|
@@ -8,20 +8,42 @@ export interface RedisUrlSiblingFields {
|
|
|
8
8
|
db?: number;
|
|
9
9
|
tls?: boolean;
|
|
10
10
|
}
|
|
11
|
+
/**
|
|
12
|
+
* What a `redis://` or `rediss://` URL states, read as ioredis reads it: the userinfo, port and path
|
|
13
|
+
* first, then the same names in its query. An empty username or password counts as left out.
|
|
14
|
+
*/
|
|
15
|
+
export interface RedisUrlConnection {
|
|
16
|
+
host?: string;
|
|
17
|
+
port?: number;
|
|
18
|
+
username?: string;
|
|
19
|
+
password?: string;
|
|
20
|
+
db?: number;
|
|
21
|
+
tls: boolean;
|
|
22
|
+
/** The query's other options, which ioredis takes as they are (`family` as a number). */
|
|
23
|
+
queryOptions: Record<string, string | number>;
|
|
24
|
+
}
|
|
11
25
|
/**
|
|
12
26
|
* Outcome of combining a Redis URL with the fields written beside it.
|
|
13
27
|
*/
|
|
14
28
|
export interface RedisUrlMerge {
|
|
29
|
+
/** What the URL states. */
|
|
30
|
+
connection: RedisUrlConnection;
|
|
15
31
|
/** Fields the URL leaves out that the sibling fields supply. */
|
|
16
32
|
fillIns: Pick<RedisUrlSiblingFields, 'port' | 'password' | 'db' | 'tls'>;
|
|
17
33
|
/** Sibling fields whose value contradicts the URL. */
|
|
18
34
|
conflicts: Array<keyof RedisUrlSiblingFields>;
|
|
19
35
|
}
|
|
36
|
+
/**
|
|
37
|
+
* Read a `redis://` or `rediss://` URL. Returns `undefined` for an unparseable URL or another
|
|
38
|
+
* scheme (such as a socket path), which only ioredis reads.
|
|
39
|
+
*/
|
|
40
|
+
export declare function readRedisUrl(rawUrl: string): RedisUrlConnection | undefined;
|
|
20
41
|
/**
|
|
21
42
|
* The URL is the base: fields beside it fill in only what it leaves out (a
|
|
22
|
-
* port, a password, a database, TLS), and a field that contradicts it
|
|
23
|
-
* conflict the caller must reject
|
|
24
|
-
*
|
|
43
|
+
* port, a password, a database, TLS), and a field that contradicts what it
|
|
44
|
+
* states, in its userinfo, path or query, is a conflict the caller must reject
|
|
45
|
+
* (#768). Returns `undefined` for a URL {@link readRedisUrl} cannot read, which
|
|
46
|
+
* the caller reports on its own terms.
|
|
25
47
|
*/
|
|
26
48
|
export declare function mergeRedisUrlFields(rawUrl: string, fields: RedisUrlSiblingFields): RedisUrlMerge | undefined;
|
|
27
49
|
/** Human-readable reason for {@link RedisUrlMerge.conflicts}. */
|