@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/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
- rsaVerifyBrowser: () => rsaVerifyBrowser
2550
+ pemToPublicJwk: () => pemToPublicJwk,
2551
+ rsaSignBase64Url: () => rsaSignBase64Url,
2552
+ rsaVerify: () => rsaVerify,
2553
+ rsaVerifyBrowser: () => rsaVerifyBrowser,
2554
+ rsaVerifySync: () => rsaVerifySync
2716
2555
  });
2717
- import { sha256 as sha256Hash } from "@noble/hashes/sha2.js";
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 { cryptoProvider as cryptoProvider2 } from "#crypto-provider";
2685
+ import * as platformCrypto from "#crypto-provider";
2829
2686
  function getCrypto() {
2830
- return cryptoProvider2;
2687
+ return platformCrypto.cryptoProvider;
2831
2688
  }
2832
- function rsaVerify2(jwtAlg, data, publicJwk, signature) {
2689
+ function rsaVerify3(jwtAlg, data, publicJwk, signature) {
2833
2690
  if (isNode()) {
2834
- return Promise.resolve((init_node(), __toCommonJS(node_exports)).rsaVerify(jwtAlg, data, publicJwk, signature));
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 rsaSignBase64Url2(jwtAlg, data, privateJwk) {
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 (init_node(), __toCommonJS(node_exports)).rsaSignBase64Url(jwtAlg, data, privateJwk);
2700
+ return platformCrypto.rsaSignBase64Url(jwtAlg, data, privateJwk);
2844
2701
  }
2845
- function rsaVerifySync2(jwtAlg, data, publicJwk, signature) {
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 (init_node(), __toCommonJS(node_exports)).rsaVerifySync(jwtAlg, data, publicJwk, signature);
2706
+ return platformCrypto.rsaVerifySync(jwtAlg, data, publicJwk, signature);
2850
2707
  }
2851
- function pemToPublicJwk2(pem) {
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 (init_node(), __toCommonJS(node_exports)).pemToPublicJwk(pem);
2712
+ return platformCrypto.pemToPublicJwk(pem);
2856
2713
  }
2857
- function generateRsaKeyPair2(modulusLength, alg) {
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 (init_node(), __toCommonJS(node_exports)).generateRsaKeyPair(modulusLength, alg);
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
- const client = options.url ? new RedisClass(options.url, baseOptions) : new RedisClass({
3061
- ...baseOptions,
3062
- host: options.host ?? "localhost",
3063
- port: options.port ?? 6379,
3064
- password: options.password,
3065
- db: options.db ?? 0,
3066
- tls: options.tls ? {} : void 0
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
- const RedisClass = getRedisClass();
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.options.url) {
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.url) {
3397
- subscriber = new RedisClass(this.options.url);
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
- const { createClient } = await loadVercelKv();
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 getUpstashRedis() {
3637
+ async function loadUpstashRedis() {
3672
3638
  try {
3673
- return __require("@upstash/redis");
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 } = getUpstashRedis();
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
- generateRsaKeyPair2 as generateRsaKeyPair,
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
- pemToPublicJwk2 as pemToPublicJwk,
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
- rsaSignBase64Url2 as rsaSignBase64Url,
6072
- rsaVerify2 as rsaVerify,
6073
- rsaVerifySync2 as rsaVerifySync,
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';