From e6126fbc39b5b72fe180f87e1a740461891a6eb7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 27 Nov 2025 17:31:44 +0200 Subject: [PATCH 01/12] build(deps): bump golang.org/x/crypto from 0.36.0 to 0.45.0 in /tools/golang-example (#4637) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- tools/golang-example/go.mod | 4 ++-- tools/golang-example/go.sum | 16 ++++++++-------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/tools/golang-example/go.mod b/tools/golang-example/go.mod index 2354f2dc2b..3583b12505 100644 --- a/tools/golang-example/go.mod +++ b/tools/golang-example/go.mod @@ -30,9 +30,9 @@ require ( github.com/supranational/blst v0.3.16-0.20250831170142-f48500c1fdbe // indirect github.com/tklauser/go-sysconf v0.3.12 // indirect github.com/tklauser/numcpus v0.6.1 // indirect - golang.org/x/crypto v0.36.0 // indirect + golang.org/x/crypto v0.45.0 // indirect golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa // indirect golang.org/x/sync v0.12.0 // indirect - golang.org/x/sys v0.36.0 // indirect + golang.org/x/sys v0.38.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/tools/golang-example/go.sum b/tools/golang-example/go.sum index cf3df08a9f..57d032dbee 100644 --- a/tools/golang-example/go.sum +++ b/tools/golang-example/go.sum @@ -183,12 +183,12 @@ github.com/urfave/cli/v2 v2.27.5 h1:WoHEJLdsXr6dDWoJgMq/CboDmyY/8HMMH1fTECbih+w= github.com/urfave/cli/v2 v2.27.5/go.mod h1:3Sevf16NykTbInEnD0yKkjDAeZDS0A6bzhBH5hrMvTQ= github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGCjxCBTO/36wtF6j2nSip77qHd4x4= github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM= -golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34= -golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc= +golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q= +golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4= golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa h1:FRnLl4eNAQl8hwxVVC17teOw8kdjVDVAiFMtgUdTSRQ= golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa/go.mod h1:zk2irFbV9DP96SEBUUAy67IdHUaZuSnrz1n472HUCLE= -golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8= -golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= +golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY= +golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw= golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -196,10 +196,10 @@ golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k= -golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY= -golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= +golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= +golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= +golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= golang.org/x/time v0.9.0 h1:EsRrnYcQiGH+5FfbgvV4AP7qEZstoyrHB0DzarOQ4ZY= golang.org/x/time v0.9.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= From e62bc669cb19703956e33ffdd9d5abc847cceacd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 27 Nov 2025 17:31:56 +0200 Subject: [PATCH 02/12] build(deps): bump golang.org/x/crypto from 0.36.0 to 0.45.0 in /tools/golang-json-rpc-tests (#4636) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- tools/golang-json-rpc-tests/go.mod | 4 ++-- tools/golang-json-rpc-tests/go.sum | 16 ++++++++-------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/tools/golang-json-rpc-tests/go.mod b/tools/golang-json-rpc-tests/go.mod index 58b41c2137..7153446bc9 100644 --- a/tools/golang-json-rpc-tests/go.mod +++ b/tools/golang-json-rpc-tests/go.mod @@ -29,8 +29,8 @@ require ( github.com/supranational/blst v0.3.16-0.20250831170142-f48500c1fdbe // indirect github.com/tklauser/go-sysconf v0.3.12 // indirect github.com/tklauser/numcpus v0.6.1 // indirect - golang.org/x/crypto v0.36.0 // indirect + golang.org/x/crypto v0.45.0 // indirect golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa // indirect golang.org/x/sync v0.12.0 // indirect - golang.org/x/sys v0.36.0 // indirect + golang.org/x/sys v0.38.0 // indirect ) diff --git a/tools/golang-json-rpc-tests/go.sum b/tools/golang-json-rpc-tests/go.sum index 9e649e1859..b83372c5b8 100644 --- a/tools/golang-json-rpc-tests/go.sum +++ b/tools/golang-json-rpc-tests/go.sum @@ -183,12 +183,12 @@ github.com/urfave/cli/v2 v2.27.5 h1:WoHEJLdsXr6dDWoJgMq/CboDmyY/8HMMH1fTECbih+w= github.com/urfave/cli/v2 v2.27.5/go.mod h1:3Sevf16NykTbInEnD0yKkjDAeZDS0A6bzhBH5hrMvTQ= github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGCjxCBTO/36wtF6j2nSip77qHd4x4= github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM= -golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34= -golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc= +golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q= +golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4= golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa h1:FRnLl4eNAQl8hwxVVC17teOw8kdjVDVAiFMtgUdTSRQ= golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa/go.mod h1:zk2irFbV9DP96SEBUUAy67IdHUaZuSnrz1n472HUCLE= -golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8= -golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= +golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY= +golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw= golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -196,10 +196,10 @@ golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k= -golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY= -golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= +golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= +golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= +golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= golang.org/x/time v0.9.0 h1:EsRrnYcQiGH+5FfbgvV4AP7qEZstoyrHB0DzarOQ4ZY= golang.org/x/time v0.9.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= From eedb638f567cece60152cb36f3c91492ee2b1adf Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 27 Nov 2025 17:32:07 +0200 Subject: [PATCH 03/12] build(deps-dev): bump js-yaml from 3.14.1 to 3.14.2 in /tools/hedera-crosschain-bridge (#4626) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .../hedera-crosschain-bridge/package-lock.json | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/tools/hedera-crosschain-bridge/package-lock.json b/tools/hedera-crosschain-bridge/package-lock.json index 3b7010adf5..9564d6ee66 100644 --- a/tools/hedera-crosschain-bridge/package-lock.json +++ b/tools/hedera-crosschain-bridge/package-lock.json @@ -2025,9 +2025,9 @@ } }, "node_modules/@istanbuljs/load-nyc-config/node_modules/js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "version": "3.14.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz", + "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==", "dev": true, "license": "MIT", "peer": true, @@ -8296,9 +8296,9 @@ "peer": true }, "node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", "dev": true, "license": "MIT", "dependencies": { @@ -11115,9 +11115,9 @@ } }, "node_modules/sc-istanbul/node_modules/js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "version": "3.14.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz", + "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==", "dev": true, "license": "MIT", "peer": true, From 46820d671145693e84967f9741b5884c6c04840b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 27 Nov 2025 17:32:16 +0200 Subject: [PATCH 04/12] build(deps): bump js-yaml in /tools/layer-zero-example (#4621) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- tools/layer-zero-example/package-lock.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tools/layer-zero-example/package-lock.json b/tools/layer-zero-example/package-lock.json index 6ea00abb66..4b97bfe005 100644 --- a/tools/layer-zero-example/package-lock.json +++ b/tools/layer-zero-example/package-lock.json @@ -5013,9 +5013,9 @@ "license": "MIT" }, "node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", "dev": true, "license": "MIT", "dependencies": { @@ -6344,9 +6344,9 @@ } }, "node_modules/sc-istanbul/node_modules/js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "version": "3.14.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz", + "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==", "dev": true, "license": "MIT", "peer": true, From 1515b87dae3f8871a7d124b4f9182f3cbaad3f4e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 27 Nov 2025 17:32:29 +0200 Subject: [PATCH 05/12] build(deps-dev): bump js-yaml from 4.1.0 to 4.1.1 in /tools/waffle-example (#4614) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- tools/waffle-example/package-lock.json | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tools/waffle-example/package-lock.json b/tools/waffle-example/package-lock.json index e72e80569f..f55d143b7c 100644 --- a/tools/waffle-example/package-lock.json +++ b/tools/waffle-example/package-lock.json @@ -4125,10 +4125,11 @@ "dev": true }, "node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", "dev": true, + "license": "MIT", "dependencies": { "argparse": "^2.0.1" }, From c34aad0b1fdc264ae9911cf1e1dfcacf807d8bdc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 27 Nov 2025 17:32:46 +0200 Subject: [PATCH 06/12] build(deps): bump the minor-and-patch-npm-weekly group across 8 directories with 8 updates (#4609) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- dapp-example/package-lock.json | 563 +++++++++--------- dapp-example/package.json | 8 +- tools/hardhat-example/package-lock.json | 14 +- tools/hardhat-example/package.json | 2 +- tools/hardhat-viem-example/package-lock.json | 22 +- tools/hardhat-viem-example/package.json | 4 +- .../package-lock.json | 110 ++-- tools/hedera-crosschain-bridge/package.json | 6 +- .../package-lock.json | 6 +- tools/subgraph-example/package-lock.json | 8 +- tools/subgraph-example/package.json | 2 +- tools/waffle-example/package-lock.json | 8 +- tools/waffle-example/package.json | 2 +- tools/web3js-example/package-lock.json | 8 +- tools/web3js-example/package.json | 2 +- tools/whbar-hardhat-example/package-lock.json | 66 +- tools/whbar-hardhat-example/package.json | 2 +- 17 files changed, 416 insertions(+), 417 deletions(-) diff --git a/dapp-example/package-lock.json b/dapp-example/package-lock.json index ce5574f6f9..1f79f4ede8 100644 --- a/dapp-example/package-lock.json +++ b/dapp-example/package-lock.json @@ -11,7 +11,7 @@ "@emotion/react": "^11.14.0", "@emotion/styled": "^11.14.1", "@hashgraph/sdk": "^2.75.0", - "@mui/material": "^7.3.4", + "@mui/material": "^7.3.5", "ethers": "^6.15.0", "react": "^19.1.1", "react-dom": "^19.2.0", @@ -19,9 +19,9 @@ "typescript": "^5.5.4" }, "devDependencies": { - "@babel/core": "^7.28.3", - "@babel/preset-env": "^7.28.3", - "@cypress/webpack-batteries-included-preprocessor": "^4.0.2", + "@babel/core": "^7.28.5", + "@babel/preset-env": "^7.28.5", + "@cypress/webpack-batteries-included-preprocessor": "^4.0.4", "@cypress/webpack-preprocessor": "^6.0.4", "@synthetixio/synpress": "^3.7.3", "babel-loader": "^10.0.0", @@ -51,18 +51,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@ampproject/remapping": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", - "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.24" - }, - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/@babel/code-frame": { "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", @@ -78,30 +66,30 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.0.tgz", - "integrity": "sha512-60X7qkglvrap8mn1lh2ebxXdZYtUcpd7gsmy9kLaBJ4i/WdY8PqTSdxyA8qraikqKQK5C1KRBKXqznrVapyNaw==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.5.tgz", + "integrity": "sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA==", "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.3.tgz", - "integrity": "sha512-yDBHV9kQNcr2/sUr9jghVyz9C3Y5G2zUM2H2lo+9mKv4sFgbA8s8Z9t8D1jiTkGoO/NoIfKMyKWr4s6CN23ZwQ==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.5.tgz", + "integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==", "license": "MIT", "dependencies": { - "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.28.3", + "@babel/generator": "^7.28.5", "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-module-transforms": "^7.28.3", - "@babel/helpers": "^7.28.3", - "@babel/parser": "^7.28.3", + "@babel/helpers": "^7.28.4", + "@babel/parser": "^7.28.5", "@babel/template": "^7.27.2", - "@babel/traverse": "^7.28.3", - "@babel/types": "^7.28.2", + "@babel/traverse": "^7.28.5", + "@babel/types": "^7.28.5", + "@jridgewell/remapping": "^2.3.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -142,13 +130,13 @@ } }, "node_modules/@babel/generator": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.3.tgz", - "integrity": "sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.5.tgz", + "integrity": "sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==", "license": "MIT", "dependencies": { - "@babel/parser": "^7.28.3", - "@babel/types": "^7.28.2", + "@babel/parser": "^7.28.5", + "@babel/types": "^7.28.5", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" @@ -386,9 +374,9 @@ } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", - "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", "license": "MIT", "engines": { "node": ">=6.9.0" @@ -418,25 +406,25 @@ } }, "node_modules/@babel/helpers": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.3.tgz", - "integrity": "sha512-PTNtvUQihsAsDHMOP5pfobP8C6CM4JWXmP8DrEIt46c3r2bf87Ua1zoqevsMo9g+tWDwgWrFP5EIxuBx5RudAw==", + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.4.tgz", + "integrity": "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==", "license": "MIT", "dependencies": { "@babel/template": "^7.27.2", - "@babel/types": "^7.28.2" + "@babel/types": "^7.28.4" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/parser": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.4.tgz", - "integrity": "sha512-yZbBqeM6TkpP9du/I2pUZnJsRMGGvOuIrhjzC1AwHwW+6he4mni6Bp/m8ijn0iOuZuPI2BfkCoSRunpyjnrQKg==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.5.tgz", + "integrity": "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==", "license": "MIT", "dependencies": { - "@babel/types": "^7.28.4" + "@babel/types": "^7.28.5" }, "bin": { "parser": "bin/babel-parser.js" @@ -446,13 +434,13 @@ } }, "node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.27.1.tgz", - "integrity": "sha512-QPG3C9cCVRQLxAVwmefEmwdTanECuUBMQZ/ym5kiw3XKCGA7qkuQLcjWWHcrD/GKbn/WmJwaezfuuAOcyKlRPA==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.28.5.tgz", + "integrity": "sha512-87GDMS3tsmMSi/3bWOte1UblL+YUTFMV8SZPZ2eSEL17s74Cw/l63rR6NmGVKMYW2GYi85nE+/d6Hw5N0bEk2Q==", "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", - "@babel/traverse": "^7.27.1" + "@babel/traverse": "^7.28.5" }, "engines": { "node": ">=6.9.0" @@ -936,9 +924,9 @@ } }, "node_modules/@babel/plugin-transform-block-scoping": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.28.0.tgz", - "integrity": "sha512-gKKnwjpdx5sER/wl0WN0efUBFzF/56YZO0RJrSYP4CljXnP31ByY7fol89AzomdlLNzI36AvOTmYHsnZTCkq8Q==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.28.5.tgz", + "integrity": "sha512-45DmULpySVvmq9Pj3X9B+62Xe+DJGov27QravQJU1LLcapR6/10i+gYVAucGGJpHBp5mYxIMK4nDAT/QDLr47g==", "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -983,9 +971,9 @@ } }, "node_modules/@babel/plugin-transform-classes": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.28.3.tgz", - "integrity": "sha512-DoEWC5SuxuARF2KdKmGUq3ghfPMO6ZzR12Dnp5gubwbeWJo4dbNWXJPVlwvh4Zlq6Z7YVvL8VFxeSOJgjsx4Sg==", + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.28.4.tgz", + "integrity": "sha512-cFOlhIYPBv/iBoc+KS3M6et2XPtbT2HiCRfBXWtfpc9OAyostldxIf9YAYB6ypURBBbx+Qv6nyrLzASfJe+hBA==", "license": "MIT", "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", @@ -993,7 +981,7 @@ "@babel/helper-globals": "^7.28.0", "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-replace-supers": "^7.27.1", - "@babel/traverse": "^7.28.3" + "@babel/traverse": "^7.28.4" }, "engines": { "node": ">=6.9.0" @@ -1019,13 +1007,13 @@ } }, "node_modules/@babel/plugin-transform-destructuring": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.28.0.tgz", - "integrity": "sha512-v1nrSMBiKcodhsyJ4Gf+Z0U/yawmJDBOTpEB3mcQY52r9RIyPneGyAS/yM6seP/8I+mWI3elOMtT5dB8GJVs+A==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.28.5.tgz", + "integrity": "sha512-Kl9Bc6D0zTUcFUvkNuQh4eGXPKKNDOJQXVyyM4ZAQPMveniJdxi8XMJwLo+xSoW3MIq81bD33lcUe9kZpl0MCw==", "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", - "@babel/traverse": "^7.28.0" + "@babel/traverse": "^7.28.5" }, "engines": { "node": ">=6.9.0" @@ -1113,9 +1101,9 @@ } }, "node_modules/@babel/plugin-transform-exponentiation-operator": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.27.1.tgz", - "integrity": "sha512-uspvXnhHvGKf2r4VVtBpeFnuDWsJLQ6MF6lGJLC89jBR1uoVeqM416AZtTuhTezOfgHicpJQmoD5YUakO/YmXQ==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.28.5.tgz", + "integrity": "sha512-D4WIMaFtwa2NizOp+dnoFjRez/ClKiC2BqqImwKd1X28nqBtZEyCYJ2ozQrrzlxAFrcrjxo39S6khe9RNDlGzw==", "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -1222,9 +1210,9 @@ } }, "node_modules/@babel/plugin-transform-logical-assignment-operators": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.27.1.tgz", - "integrity": "sha512-SJvDs5dXxiae4FbSL1aBJlG4wvl594N6YEVVn9e3JGulwioy6z3oPjx/sQBO3Y4NwUu5HNix6KJ3wBZoewcdbw==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.28.5.tgz", + "integrity": "sha512-axUuqnUTBuXyHGcJEVVh9pORaN6wC5bYfE7FGzPiaWa3syib9m7g+/IT/4VgCOe2Upef43PHzeAvcrVek6QuuA==", "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -1284,15 +1272,15 @@ } }, "node_modules/@babel/plugin-transform-modules-systemjs": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.27.1.tgz", - "integrity": "sha512-w5N1XzsRbc0PQStASMksmUeqECuzKuTJer7kFagK8AXgpCMkeDMO5S+aaFb7A51ZYDF7XI34qsTX+fkHiIm5yA==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.28.5.tgz", + "integrity": "sha512-vn5Jma98LCOeBy/KpeQhXcV2WZgaRUtjwQmjoBuLNlOmkg0fB5pdvYVeWRYI69wWKwK2cD1QbMiUQnoujWvrew==", "license": "MIT", "dependencies": { - "@babel/helper-module-transforms": "^7.27.1", + "@babel/helper-module-transforms": "^7.28.3", "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-validator-identifier": "^7.27.1", - "@babel/traverse": "^7.27.1" + "@babel/helper-validator-identifier": "^7.28.5", + "@babel/traverse": "^7.28.5" }, "engines": { "node": ">=6.9.0" @@ -1379,16 +1367,16 @@ } }, "node_modules/@babel/plugin-transform-object-rest-spread": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.28.0.tgz", - "integrity": "sha512-9VNGikXxzu5eCiQjdE4IZn8sb9q7Xsk5EXLDBKUYg1e/Tve8/05+KJEtcxGxAgCY5t/BpKQM+JEL/yT4tvgiUA==", + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.28.4.tgz", + "integrity": "sha512-373KA2HQzKhQCYiRVIRr+3MjpCObqzDlyrM6u4I201wL8Mp2wHf7uB8GhDwis03k2ti8Zr65Zyyqs1xOxUF/Ew==", "license": "MIT", "dependencies": { "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-plugin-utils": "^7.27.1", "@babel/plugin-transform-destructuring": "^7.28.0", "@babel/plugin-transform-parameters": "^7.27.7", - "@babel/traverse": "^7.28.0" + "@babel/traverse": "^7.28.4" }, "engines": { "node": ">=6.9.0" @@ -1429,9 +1417,9 @@ } }, "node_modules/@babel/plugin-transform-optional-chaining": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.27.1.tgz", - "integrity": "sha512-BQmKPPIuc8EkZgNKsv0X4bPmOoayeu4F1YCwx2/CfmDSXDbp7GnzlUH+/ul5VGfRg1AoFPsrIThlEBj2xb4CAg==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.28.5.tgz", + "integrity": "sha512-N6fut9IZlPnjPwgiQkXNhb+cT8wQKFlJNqcZkWlcTqkcqx6/kU4ynGmLFoa4LViBSirn05YAwk+sQBbPfxtYzQ==", "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", @@ -1587,9 +1575,9 @@ } }, "node_modules/@babel/plugin-transform-regenerator": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.28.3.tgz", - "integrity": "sha512-K3/M/a4+ESb5LEldjQb+XSrpY0nF+ZBFlTCbSnKaYAMfD8v33O6PMs4uYnOk19HlcsI8WMu3McdFPTiQHF/1/A==", + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.28.4.tgz", + "integrity": "sha512-+ZEdQlBoRg9m2NnzvEeLgtvBMO4tkFBw5SQIUgLICgTrumLoU7lr+Oghi6km2PFj+dbUt2u1oby2w3BDO9YQnA==", "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -1811,16 +1799,16 @@ } }, "node_modules/@babel/preset-env": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.28.3.tgz", - "integrity": "sha512-ROiDcM+GbYVPYBOeCR6uBXKkQpBExLl8k9HO1ygXEyds39j+vCCsjmj7S8GOniZQlEs81QlkdJZe76IpLSiqpg==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.28.5.tgz", + "integrity": "sha512-S36mOoi1Sb6Fz98fBfE+UZSpYw5mJm0NUHtIKrOuNcqeFauy1J6dIvXm2KRVKobOSaGq4t/hBXdN4HGU3wL9Wg==", "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.28.0", + "@babel/compat-data": "^7.28.5", "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-validator-option": "^7.27.1", - "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.27.1", + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.28.5", "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.27.1", "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.27.1", "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.27.1", @@ -1833,42 +1821,42 @@ "@babel/plugin-transform-async-generator-functions": "^7.28.0", "@babel/plugin-transform-async-to-generator": "^7.27.1", "@babel/plugin-transform-block-scoped-functions": "^7.27.1", - "@babel/plugin-transform-block-scoping": "^7.28.0", + "@babel/plugin-transform-block-scoping": "^7.28.5", "@babel/plugin-transform-class-properties": "^7.27.1", "@babel/plugin-transform-class-static-block": "^7.28.3", - "@babel/plugin-transform-classes": "^7.28.3", + "@babel/plugin-transform-classes": "^7.28.4", "@babel/plugin-transform-computed-properties": "^7.27.1", - "@babel/plugin-transform-destructuring": "^7.28.0", + "@babel/plugin-transform-destructuring": "^7.28.5", "@babel/plugin-transform-dotall-regex": "^7.27.1", "@babel/plugin-transform-duplicate-keys": "^7.27.1", "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.27.1", "@babel/plugin-transform-dynamic-import": "^7.27.1", "@babel/plugin-transform-explicit-resource-management": "^7.28.0", - "@babel/plugin-transform-exponentiation-operator": "^7.27.1", + "@babel/plugin-transform-exponentiation-operator": "^7.28.5", "@babel/plugin-transform-export-namespace-from": "^7.27.1", "@babel/plugin-transform-for-of": "^7.27.1", "@babel/plugin-transform-function-name": "^7.27.1", "@babel/plugin-transform-json-strings": "^7.27.1", "@babel/plugin-transform-literals": "^7.27.1", - "@babel/plugin-transform-logical-assignment-operators": "^7.27.1", + "@babel/plugin-transform-logical-assignment-operators": "^7.28.5", "@babel/plugin-transform-member-expression-literals": "^7.27.1", "@babel/plugin-transform-modules-amd": "^7.27.1", "@babel/plugin-transform-modules-commonjs": "^7.27.1", - "@babel/plugin-transform-modules-systemjs": "^7.27.1", + "@babel/plugin-transform-modules-systemjs": "^7.28.5", "@babel/plugin-transform-modules-umd": "^7.27.1", "@babel/plugin-transform-named-capturing-groups-regex": "^7.27.1", "@babel/plugin-transform-new-target": "^7.27.1", "@babel/plugin-transform-nullish-coalescing-operator": "^7.27.1", "@babel/plugin-transform-numeric-separator": "^7.27.1", - "@babel/plugin-transform-object-rest-spread": "^7.28.0", + "@babel/plugin-transform-object-rest-spread": "^7.28.4", "@babel/plugin-transform-object-super": "^7.27.1", "@babel/plugin-transform-optional-catch-binding": "^7.27.1", - "@babel/plugin-transform-optional-chaining": "^7.27.1", + "@babel/plugin-transform-optional-chaining": "^7.28.5", "@babel/plugin-transform-parameters": "^7.27.7", "@babel/plugin-transform-private-methods": "^7.27.1", "@babel/plugin-transform-private-property-in-object": "^7.27.1", "@babel/plugin-transform-property-literals": "^7.27.1", - "@babel/plugin-transform-regenerator": "^7.28.3", + "@babel/plugin-transform-regenerator": "^7.28.4", "@babel/plugin-transform-regexp-modifiers": "^7.27.1", "@babel/plugin-transform-reserved-words": "^7.27.1", "@babel/plugin-transform-shorthand-properties": "^7.27.1", @@ -1983,17 +1971,17 @@ } }, "node_modules/@babel/traverse": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.3.tgz", - "integrity": "sha512-7w4kZYHneL3A6NP2nxzHvT3HCZ7puDZZjFMqDpBPECub79sTtSO5CGXDkKrTQq8ksAwfD/XI2MRFX23njdDaIQ==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.5.tgz", + "integrity": "sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==", "license": "MIT", "dependencies": { "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.28.3", + "@babel/generator": "^7.28.5", "@babel/helper-globals": "^7.28.0", - "@babel/parser": "^7.28.3", + "@babel/parser": "^7.28.5", "@babel/template": "^7.27.2", - "@babel/types": "^7.28.2", + "@babel/types": "^7.28.5", "debug": "^4.3.1" }, "engines": { @@ -2021,13 +2009,13 @@ } }, "node_modules/@babel/types": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.4.tgz", - "integrity": "sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.5.tgz", + "integrity": "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==", "license": "MIT", "dependencies": { "@babel/helper-string-parser": "^7.27.1", - "@babel/helper-validator-identifier": "^7.27.1" + "@babel/helper-validator-identifier": "^7.28.5" }, "engines": { "node": ">=6.9.0" @@ -2461,9 +2449,9 @@ } }, "node_modules/@cypress/webpack-batteries-included-preprocessor": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@cypress/webpack-batteries-included-preprocessor/-/webpack-batteries-included-preprocessor-4.0.2.tgz", - "integrity": "sha512-e8PbMERspCBTk0yBiZfsdoTdeA1amhCtETgw3iY2m8GqEA5ZBFUcWhLC1s/Ags2x5SwlkJO54xa2COoft8Oq2w==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@cypress/webpack-batteries-included-preprocessor/-/webpack-batteries-included-preprocessor-4.0.4.tgz", + "integrity": "sha512-aQ8aRvkbAjXVHzfC5U3Xpfwk0s1bVHR3Ze8GruEZflWhIQLfLD3I/ozAe1h92da/E9YeWheM51gI6R0C8cLNbg==", "dev": true, "license": "MIT", "dependencies": { @@ -4557,6 +4545,16 @@ "@jridgewell/trace-mapping": "^0.3.24" } }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, "node_modules/@jridgewell/resolve-uri": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", @@ -4606,9 +4604,9 @@ "integrity": "sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==" }, "node_modules/@mui/core-downloads-tracker": { - "version": "7.3.4", - "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-7.3.4.tgz", - "integrity": "sha512-BIktMapG3r4iXwIhYNpvk97ZfYWTreBBQTWjQKbNbzI64+ULHfYavQEX2w99aSWHS58DvXESWIgbD9adKcUOBw==", + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-7.3.5.tgz", + "integrity": "sha512-kOLwlcDPnVz2QMhiBv0OQ8le8hTCqKM9cRXlfVPL91l3RGeOsxrIhNRsUt3Xb8wb+pTVUolW+JXKym93vRKxCw==", "license": "MIT", "funding": { "type": "opencollective", @@ -4616,22 +4614,22 @@ } }, "node_modules/@mui/material": { - "version": "7.3.4", - "resolved": "https://registry.npmjs.org/@mui/material/-/material-7.3.4.tgz", - "integrity": "sha512-gEQL9pbJZZHT7lYJBKQCS723v1MGys2IFc94COXbUIyCTWa+qC77a7hUax4Yjd5ggEm35dk4AyYABpKKWC4MLw==", + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/@mui/material/-/material-7.3.5.tgz", + "integrity": "sha512-8VVxFmp1GIm9PpmnQoCoYo0UWHoOrdA57tDL62vkpzEgvb/d71Wsbv4FRg7r1Gyx7PuSo0tflH34cdl/NvfHNQ==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.28.4", - "@mui/core-downloads-tracker": "^7.3.4", - "@mui/system": "^7.3.3", - "@mui/types": "^7.4.7", - "@mui/utils": "^7.3.3", + "@mui/core-downloads-tracker": "^7.3.5", + "@mui/system": "^7.3.5", + "@mui/types": "^7.4.8", + "@mui/utils": "^7.3.5", "@popperjs/core": "^2.11.8", "@types/react-transition-group": "^4.4.12", "clsx": "^2.1.1", "csstype": "^3.1.3", "prop-types": "^15.8.1", - "react-is": "^19.1.1", + "react-is": "^19.2.0", "react-transition-group": "^4.4.5" }, "engines": { @@ -4644,7 +4642,7 @@ "peerDependencies": { "@emotion/react": "^11.5.0", "@emotion/styled": "^11.3.0", - "@mui/material-pigment-css": "^7.3.3", + "@mui/material-pigment-css": "^7.3.5", "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", "react": "^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0" @@ -4665,18 +4663,19 @@ } }, "node_modules/@mui/material/node_modules/react-is": { - "version": "19.1.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.1.1.tgz", - "integrity": "sha512-tr41fA15Vn8p4X9ntI+yCyeGSf1TlYaY5vlTZfQmeLBrFo3psOPX6HhTDnFNL9uj3EhP0KAQ80cugCl4b4BERA==" + "version": "19.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.2.0.tgz", + "integrity": "sha512-x3Ax3kNSMIIkyVYhWPyO09bu0uttcAIoecO/um/rKGQ4EltYWVYtyiGkS/3xMynrbVQdS69Jhlv8FXUEZehlzA==", + "license": "MIT" }, "node_modules/@mui/private-theming": { - "version": "7.3.3", - "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-7.3.3.tgz", - "integrity": "sha512-OJM+9nj5JIyPUvsZ5ZjaeC9PfktmK+W5YaVLToLR8L0lB/DGmv1gcKE43ssNLSvpoW71Hct0necfade6+kW3zQ==", + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-7.3.5.tgz", + "integrity": "sha512-cTx584W2qrLonwhZLbEN7P5pAUu0nZblg8cLBlTrZQ4sIiw8Fbvg7GvuphQaSHxPxrCpa7FDwJKtXdbl2TSmrA==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.28.4", - "@mui/utils": "^7.3.3", + "@mui/utils": "^7.3.5", "prop-types": "^15.8.1" }, "engines": { @@ -4697,9 +4696,9 @@ } }, "node_modules/@mui/styled-engine": { - "version": "7.3.3", - "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-7.3.3.tgz", - "integrity": "sha512-CmFxvRJIBCEaWdilhXMw/5wFJ1+FT9f3xt+m2pPXhHPeVIbBg9MnMvNSJjdALvnQJMPw8jLhrUtXmN7QAZV2fw==", + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-7.3.5.tgz", + "integrity": "sha512-zbsZ0uYYPndFCCPp2+V3RLcAN6+fv4C8pdwRx6OS3BwDkRCN8WBehqks7hWyF3vj1kdQLIWrpdv/5Y0jHRxYXQ==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.28.4", @@ -4731,16 +4730,16 @@ } }, "node_modules/@mui/system": { - "version": "7.3.3", - "resolved": "https://registry.npmjs.org/@mui/system/-/system-7.3.3.tgz", - "integrity": "sha512-Lqq3emZr5IzRLKaHPuMaLBDVaGvxoh6z7HMWd1RPKawBM5uMRaQ4ImsmmgXWtwJdfZux5eugfDhXJUo2mliS8Q==", + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/@mui/system/-/system-7.3.5.tgz", + "integrity": "sha512-yPaf5+gY3v80HNkJcPi6WT+r9ebeM4eJzrREXPxMt7pNTV/1eahyODO4fbH3Qvd8irNxDFYn5RQ3idHW55rA6g==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.28.4", - "@mui/private-theming": "^7.3.3", - "@mui/styled-engine": "^7.3.3", - "@mui/types": "^7.4.7", - "@mui/utils": "^7.3.3", + "@mui/private-theming": "^7.3.5", + "@mui/styled-engine": "^7.3.5", + "@mui/types": "^7.4.8", + "@mui/utils": "^7.3.5", "clsx": "^2.1.1", "csstype": "^3.1.3", "prop-types": "^15.8.1" @@ -4771,9 +4770,9 @@ } }, "node_modules/@mui/types": { - "version": "7.4.7", - "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.4.7.tgz", - "integrity": "sha512-8vVje9rdEr1rY8oIkYgP+Su5Kwl6ik7O3jQ0wl78JGSmiZhRHV+vkjooGdKD8pbtZbutXFVTWQYshu2b3sG9zw==", + "version": "7.4.8", + "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.4.8.tgz", + "integrity": "sha512-ZNXLBjkPV6ftLCmmRCafak3XmSn8YV0tKE/ZOhzKys7TZXUiE0mZxlH8zKDo6j6TTUaDnuij68gIG+0Ucm7Xhw==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.28.4" @@ -4788,17 +4787,17 @@ } }, "node_modules/@mui/utils": { - "version": "7.3.3", - "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-7.3.3.tgz", - "integrity": "sha512-kwNAUh7bLZ7mRz9JZ+6qfRnnxbE4Zuc+RzXnhSpRSxjTlSTj7b4JxRLXpG+MVtPVtqks5k/XC8No1Vs3x4Z2gg==", + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-7.3.5.tgz", + "integrity": "sha512-jisvFsEC3sgjUjcPnR4mYfhzjCDIudttSGSbe1o/IXFNu0kZuR+7vqQI0jg8qtcVZBHWrwTfvAZj9MNMumcq1g==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.28.4", - "@mui/types": "^7.4.7", + "@mui/types": "^7.4.8", "@types/prop-types": "^15.7.15", "clsx": "^2.1.1", "prop-types": "^15.8.1", - "react-is": "^19.1.1" + "react-is": "^19.2.0" }, "engines": { "node": ">=14.0.0" @@ -29390,15 +29389,6 @@ "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==" }, - "@ampproject/remapping": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", - "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", - "requires": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.24" - } - }, "@babel/code-frame": { "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", @@ -29410,25 +29400,25 @@ } }, "@babel/compat-data": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.0.tgz", - "integrity": "sha512-60X7qkglvrap8mn1lh2ebxXdZYtUcpd7gsmy9kLaBJ4i/WdY8PqTSdxyA8qraikqKQK5C1KRBKXqznrVapyNaw==" + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.5.tgz", + "integrity": "sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA==" }, "@babel/core": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.3.tgz", - "integrity": "sha512-yDBHV9kQNcr2/sUr9jghVyz9C3Y5G2zUM2H2lo+9mKv4sFgbA8s8Z9t8D1jiTkGoO/NoIfKMyKWr4s6CN23ZwQ==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.5.tgz", + "integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==", "requires": { - "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.28.3", + "@babel/generator": "^7.28.5", "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-module-transforms": "^7.28.3", - "@babel/helpers": "^7.28.3", - "@babel/parser": "^7.28.3", + "@babel/helpers": "^7.28.4", + "@babel/parser": "^7.28.5", "@babel/template": "^7.27.2", - "@babel/traverse": "^7.28.3", - "@babel/types": "^7.28.2", + "@babel/traverse": "^7.28.5", + "@babel/types": "^7.28.5", + "@jridgewell/remapping": "^2.3.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -29454,12 +29444,12 @@ } }, "@babel/generator": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.3.tgz", - "integrity": "sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.5.tgz", + "integrity": "sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==", "requires": { - "@babel/parser": "^7.28.3", - "@babel/types": "^7.28.2", + "@babel/parser": "^7.28.5", + "@babel/types": "^7.28.5", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" @@ -29612,9 +29602,9 @@ "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==" }, "@babel/helper-validator-identifier": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", - "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==" + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==" }, "@babel/helper-validator-option": { "version": "7.27.1", @@ -29632,29 +29622,29 @@ } }, "@babel/helpers": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.3.tgz", - "integrity": "sha512-PTNtvUQihsAsDHMOP5pfobP8C6CM4JWXmP8DrEIt46c3r2bf87Ua1zoqevsMo9g+tWDwgWrFP5EIxuBx5RudAw==", + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.4.tgz", + "integrity": "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==", "requires": { "@babel/template": "^7.27.2", - "@babel/types": "^7.28.2" + "@babel/types": "^7.28.4" } }, "@babel/parser": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.4.tgz", - "integrity": "sha512-yZbBqeM6TkpP9du/I2pUZnJsRMGGvOuIrhjzC1AwHwW+6he4mni6Bp/m8ijn0iOuZuPI2BfkCoSRunpyjnrQKg==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.5.tgz", + "integrity": "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==", "requires": { - "@babel/types": "^7.28.4" + "@babel/types": "^7.28.5" } }, "@babel/plugin-bugfix-firefox-class-in-computed-class-key": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.27.1.tgz", - "integrity": "sha512-QPG3C9cCVRQLxAVwmefEmwdTanECuUBMQZ/ym5kiw3XKCGA7qkuQLcjWWHcrD/GKbn/WmJwaezfuuAOcyKlRPA==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.28.5.tgz", + "integrity": "sha512-87GDMS3tsmMSi/3bWOte1UblL+YUTFMV8SZPZ2eSEL17s74Cw/l63rR6NmGVKMYW2GYi85nE+/d6Hw5N0bEk2Q==", "requires": { "@babel/helper-plugin-utils": "^7.27.1", - "@babel/traverse": "^7.27.1" + "@babel/traverse": "^7.28.5" } }, "@babel/plugin-bugfix-safari-class-field-initializer-scope": { @@ -29944,9 +29934,9 @@ } }, "@babel/plugin-transform-block-scoping": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.28.0.tgz", - "integrity": "sha512-gKKnwjpdx5sER/wl0WN0efUBFzF/56YZO0RJrSYP4CljXnP31ByY7fol89AzomdlLNzI36AvOTmYHsnZTCkq8Q==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.28.5.tgz", + "integrity": "sha512-45DmULpySVvmq9Pj3X9B+62Xe+DJGov27QravQJU1LLcapR6/10i+gYVAucGGJpHBp5mYxIMK4nDAT/QDLr47g==", "requires": { "@babel/helper-plugin-utils": "^7.27.1" } @@ -29970,16 +29960,16 @@ } }, "@babel/plugin-transform-classes": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.28.3.tgz", - "integrity": "sha512-DoEWC5SuxuARF2KdKmGUq3ghfPMO6ZzR12Dnp5gubwbeWJo4dbNWXJPVlwvh4Zlq6Z7YVvL8VFxeSOJgjsx4Sg==", + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.28.4.tgz", + "integrity": "sha512-cFOlhIYPBv/iBoc+KS3M6et2XPtbT2HiCRfBXWtfpc9OAyostldxIf9YAYB6ypURBBbx+Qv6nyrLzASfJe+hBA==", "requires": { "@babel/helper-annotate-as-pure": "^7.27.3", "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-globals": "^7.28.0", "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-replace-supers": "^7.27.1", - "@babel/traverse": "^7.28.3" + "@babel/traverse": "^7.28.4" } }, "@babel/plugin-transform-computed-properties": { @@ -29992,12 +29982,12 @@ } }, "@babel/plugin-transform-destructuring": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.28.0.tgz", - "integrity": "sha512-v1nrSMBiKcodhsyJ4Gf+Z0U/yawmJDBOTpEB3mcQY52r9RIyPneGyAS/yM6seP/8I+mWI3elOMtT5dB8GJVs+A==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.28.5.tgz", + "integrity": "sha512-Kl9Bc6D0zTUcFUvkNuQh4eGXPKKNDOJQXVyyM4ZAQPMveniJdxi8XMJwLo+xSoW3MIq81bD33lcUe9kZpl0MCw==", "requires": { "@babel/helper-plugin-utils": "^7.27.1", - "@babel/traverse": "^7.28.0" + "@babel/traverse": "^7.28.5" } }, "@babel/plugin-transform-dotall-regex": { @@ -30044,9 +30034,9 @@ } }, "@babel/plugin-transform-exponentiation-operator": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.27.1.tgz", - "integrity": "sha512-uspvXnhHvGKf2r4VVtBpeFnuDWsJLQ6MF6lGJLC89jBR1uoVeqM416AZtTuhTezOfgHicpJQmoD5YUakO/YmXQ==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.28.5.tgz", + "integrity": "sha512-D4WIMaFtwa2NizOp+dnoFjRez/ClKiC2BqqImwKd1X28nqBtZEyCYJ2ozQrrzlxAFrcrjxo39S6khe9RNDlGzw==", "requires": { "@babel/helper-plugin-utils": "^7.27.1" } @@ -30104,9 +30094,9 @@ } }, "@babel/plugin-transform-logical-assignment-operators": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.27.1.tgz", - "integrity": "sha512-SJvDs5dXxiae4FbSL1aBJlG4wvl594N6YEVVn9e3JGulwioy6z3oPjx/sQBO3Y4NwUu5HNix6KJ3wBZoewcdbw==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.28.5.tgz", + "integrity": "sha512-axUuqnUTBuXyHGcJEVVh9pORaN6wC5bYfE7FGzPiaWa3syib9m7g+/IT/4VgCOe2Upef43PHzeAvcrVek6QuuA==", "requires": { "@babel/helper-plugin-utils": "^7.27.1" } @@ -30138,14 +30128,14 @@ } }, "@babel/plugin-transform-modules-systemjs": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.27.1.tgz", - "integrity": "sha512-w5N1XzsRbc0PQStASMksmUeqECuzKuTJer7kFagK8AXgpCMkeDMO5S+aaFb7A51ZYDF7XI34qsTX+fkHiIm5yA==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.28.5.tgz", + "integrity": "sha512-vn5Jma98LCOeBy/KpeQhXcV2WZgaRUtjwQmjoBuLNlOmkg0fB5pdvYVeWRYI69wWKwK2cD1QbMiUQnoujWvrew==", "requires": { - "@babel/helper-module-transforms": "^7.27.1", + "@babel/helper-module-transforms": "^7.28.3", "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-validator-identifier": "^7.27.1", - "@babel/traverse": "^7.27.1" + "@babel/helper-validator-identifier": "^7.28.5", + "@babel/traverse": "^7.28.5" } }, "@babel/plugin-transform-modules-umd": { @@ -30191,15 +30181,15 @@ } }, "@babel/plugin-transform-object-rest-spread": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.28.0.tgz", - "integrity": "sha512-9VNGikXxzu5eCiQjdE4IZn8sb9q7Xsk5EXLDBKUYg1e/Tve8/05+KJEtcxGxAgCY5t/BpKQM+JEL/yT4tvgiUA==", + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.28.4.tgz", + "integrity": "sha512-373KA2HQzKhQCYiRVIRr+3MjpCObqzDlyrM6u4I201wL8Mp2wHf7uB8GhDwis03k2ti8Zr65Zyyqs1xOxUF/Ew==", "requires": { "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-plugin-utils": "^7.27.1", "@babel/plugin-transform-destructuring": "^7.28.0", "@babel/plugin-transform-parameters": "^7.27.7", - "@babel/traverse": "^7.28.0" + "@babel/traverse": "^7.28.4" } }, "@babel/plugin-transform-object-super": { @@ -30220,9 +30210,9 @@ } }, "@babel/plugin-transform-optional-chaining": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.27.1.tgz", - "integrity": "sha512-BQmKPPIuc8EkZgNKsv0X4bPmOoayeu4F1YCwx2/CfmDSXDbp7GnzlUH+/ul5VGfRg1AoFPsrIThlEBj2xb4CAg==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.28.5.tgz", + "integrity": "sha512-N6fut9IZlPnjPwgiQkXNhb+cT8wQKFlJNqcZkWlcTqkcqx6/kU4ynGmLFoa4LViBSirn05YAwk+sQBbPfxtYzQ==", "requires": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" @@ -30309,9 +30299,9 @@ } }, "@babel/plugin-transform-regenerator": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.28.3.tgz", - "integrity": "sha512-K3/M/a4+ESb5LEldjQb+XSrpY0nF+ZBFlTCbSnKaYAMfD8v33O6PMs4uYnOk19HlcsI8WMu3McdFPTiQHF/1/A==", + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.28.4.tgz", + "integrity": "sha512-+ZEdQlBoRg9m2NnzvEeLgtvBMO4tkFBw5SQIUgLICgTrumLoU7lr+Oghi6km2PFj+dbUt2u1oby2w3BDO9YQnA==", "requires": { "@babel/helper-plugin-utils": "^7.27.1" } @@ -30435,15 +30425,15 @@ } }, "@babel/preset-env": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.28.3.tgz", - "integrity": "sha512-ROiDcM+GbYVPYBOeCR6uBXKkQpBExLl8k9HO1ygXEyds39j+vCCsjmj7S8GOniZQlEs81QlkdJZe76IpLSiqpg==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.28.5.tgz", + "integrity": "sha512-S36mOoi1Sb6Fz98fBfE+UZSpYw5mJm0NUHtIKrOuNcqeFauy1J6dIvXm2KRVKobOSaGq4t/hBXdN4HGU3wL9Wg==", "requires": { - "@babel/compat-data": "^7.28.0", + "@babel/compat-data": "^7.28.5", "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-validator-option": "^7.27.1", - "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.27.1", + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.28.5", "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.27.1", "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.27.1", "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.27.1", @@ -30456,42 +30446,42 @@ "@babel/plugin-transform-async-generator-functions": "^7.28.0", "@babel/plugin-transform-async-to-generator": "^7.27.1", "@babel/plugin-transform-block-scoped-functions": "^7.27.1", - "@babel/plugin-transform-block-scoping": "^7.28.0", + "@babel/plugin-transform-block-scoping": "^7.28.5", "@babel/plugin-transform-class-properties": "^7.27.1", "@babel/plugin-transform-class-static-block": "^7.28.3", - "@babel/plugin-transform-classes": "^7.28.3", + "@babel/plugin-transform-classes": "^7.28.4", "@babel/plugin-transform-computed-properties": "^7.27.1", - "@babel/plugin-transform-destructuring": "^7.28.0", + "@babel/plugin-transform-destructuring": "^7.28.5", "@babel/plugin-transform-dotall-regex": "^7.27.1", "@babel/plugin-transform-duplicate-keys": "^7.27.1", "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.27.1", "@babel/plugin-transform-dynamic-import": "^7.27.1", "@babel/plugin-transform-explicit-resource-management": "^7.28.0", - "@babel/plugin-transform-exponentiation-operator": "^7.27.1", + "@babel/plugin-transform-exponentiation-operator": "^7.28.5", "@babel/plugin-transform-export-namespace-from": "^7.27.1", "@babel/plugin-transform-for-of": "^7.27.1", "@babel/plugin-transform-function-name": "^7.27.1", "@babel/plugin-transform-json-strings": "^7.27.1", "@babel/plugin-transform-literals": "^7.27.1", - "@babel/plugin-transform-logical-assignment-operators": "^7.27.1", + "@babel/plugin-transform-logical-assignment-operators": "^7.28.5", "@babel/plugin-transform-member-expression-literals": "^7.27.1", "@babel/plugin-transform-modules-amd": "^7.27.1", "@babel/plugin-transform-modules-commonjs": "^7.27.1", - "@babel/plugin-transform-modules-systemjs": "^7.27.1", + "@babel/plugin-transform-modules-systemjs": "^7.28.5", "@babel/plugin-transform-modules-umd": "^7.27.1", "@babel/plugin-transform-named-capturing-groups-regex": "^7.27.1", "@babel/plugin-transform-new-target": "^7.27.1", "@babel/plugin-transform-nullish-coalescing-operator": "^7.27.1", "@babel/plugin-transform-numeric-separator": "^7.27.1", - "@babel/plugin-transform-object-rest-spread": "^7.28.0", + "@babel/plugin-transform-object-rest-spread": "^7.28.4", "@babel/plugin-transform-object-super": "^7.27.1", "@babel/plugin-transform-optional-catch-binding": "^7.27.1", - "@babel/plugin-transform-optional-chaining": "^7.27.1", + "@babel/plugin-transform-optional-chaining": "^7.28.5", "@babel/plugin-transform-parameters": "^7.27.7", "@babel/plugin-transform-private-methods": "^7.27.1", "@babel/plugin-transform-private-property-in-object": "^7.27.1", "@babel/plugin-transform-property-literals": "^7.27.1", - "@babel/plugin-transform-regenerator": "^7.28.3", + "@babel/plugin-transform-regenerator": "^7.28.4", "@babel/plugin-transform-regexp-modifiers": "^7.27.1", "@babel/plugin-transform-reserved-words": "^7.27.1", "@babel/plugin-transform-shorthand-properties": "^7.27.1", @@ -30572,16 +30562,16 @@ } }, "@babel/traverse": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.3.tgz", - "integrity": "sha512-7w4kZYHneL3A6NP2nxzHvT3HCZ7puDZZjFMqDpBPECub79sTtSO5CGXDkKrTQq8ksAwfD/XI2MRFX23njdDaIQ==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.5.tgz", + "integrity": "sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==", "requires": { "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.28.3", + "@babel/generator": "^7.28.5", "@babel/helper-globals": "^7.28.0", - "@babel/parser": "^7.28.3", + "@babel/parser": "^7.28.5", "@babel/template": "^7.27.2", - "@babel/types": "^7.28.2", + "@babel/types": "^7.28.5", "debug": "^4.3.1" } }, @@ -30601,12 +30591,12 @@ } }, "@babel/types": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.4.tgz", - "integrity": "sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.5.tgz", + "integrity": "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==", "requires": { "@babel/helper-string-parser": "^7.27.1", - "@babel/helper-validator-identifier": "^7.27.1" + "@babel/helper-validator-identifier": "^7.28.5" } }, "@bcoe/v8-coverage": { @@ -30853,9 +30843,9 @@ } }, "@cypress/webpack-batteries-included-preprocessor": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@cypress/webpack-batteries-included-preprocessor/-/webpack-batteries-included-preprocessor-4.0.2.tgz", - "integrity": "sha512-e8PbMERspCBTk0yBiZfsdoTdeA1amhCtETgw3iY2m8GqEA5ZBFUcWhLC1s/Ags2x5SwlkJO54xa2COoft8Oq2w==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@cypress/webpack-batteries-included-preprocessor/-/webpack-batteries-included-preprocessor-4.0.4.tgz", + "integrity": "sha512-aQ8aRvkbAjXVHzfC5U3Xpfwk0s1bVHR3Ze8GruEZflWhIQLfLD3I/ozAe1h92da/E9YeWheM51gI6R0C8cLNbg==", "dev": true, "requires": { "@babel/core": "^7.28.0", @@ -32273,6 +32263,15 @@ "@jridgewell/trace-mapping": "^0.3.24" } }, + "@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "requires": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, "@jridgewell/resolve-uri": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", @@ -32312,50 +32311,50 @@ "integrity": "sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==" }, "@mui/core-downloads-tracker": { - "version": "7.3.4", - "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-7.3.4.tgz", - "integrity": "sha512-BIktMapG3r4iXwIhYNpvk97ZfYWTreBBQTWjQKbNbzI64+ULHfYavQEX2w99aSWHS58DvXESWIgbD9adKcUOBw==" + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-7.3.5.tgz", + "integrity": "sha512-kOLwlcDPnVz2QMhiBv0OQ8le8hTCqKM9cRXlfVPL91l3RGeOsxrIhNRsUt3Xb8wb+pTVUolW+JXKym93vRKxCw==" }, "@mui/material": { - "version": "7.3.4", - "resolved": "https://registry.npmjs.org/@mui/material/-/material-7.3.4.tgz", - "integrity": "sha512-gEQL9pbJZZHT7lYJBKQCS723v1MGys2IFc94COXbUIyCTWa+qC77a7hUax4Yjd5ggEm35dk4AyYABpKKWC4MLw==", + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/@mui/material/-/material-7.3.5.tgz", + "integrity": "sha512-8VVxFmp1GIm9PpmnQoCoYo0UWHoOrdA57tDL62vkpzEgvb/d71Wsbv4FRg7r1Gyx7PuSo0tflH34cdl/NvfHNQ==", "requires": { "@babel/runtime": "^7.28.4", - "@mui/core-downloads-tracker": "^7.3.4", - "@mui/system": "^7.3.3", - "@mui/types": "^7.4.7", - "@mui/utils": "^7.3.3", + "@mui/core-downloads-tracker": "^7.3.5", + "@mui/system": "^7.3.5", + "@mui/types": "^7.4.8", + "@mui/utils": "^7.3.5", "@popperjs/core": "^2.11.8", "@types/react-transition-group": "^4.4.12", "clsx": "^2.1.1", "csstype": "^3.1.3", "prop-types": "^15.8.1", - "react-is": "^19.1.1", + "react-is": "^19.2.0", "react-transition-group": "^4.4.5" }, "dependencies": { "react-is": { - "version": "19.1.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.1.1.tgz", - "integrity": "sha512-tr41fA15Vn8p4X9ntI+yCyeGSf1TlYaY5vlTZfQmeLBrFo3psOPX6HhTDnFNL9uj3EhP0KAQ80cugCl4b4BERA==" + "version": "19.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.2.0.tgz", + "integrity": "sha512-x3Ax3kNSMIIkyVYhWPyO09bu0uttcAIoecO/um/rKGQ4EltYWVYtyiGkS/3xMynrbVQdS69Jhlv8FXUEZehlzA==" } } }, "@mui/private-theming": { - "version": "7.3.3", - "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-7.3.3.tgz", - "integrity": "sha512-OJM+9nj5JIyPUvsZ5ZjaeC9PfktmK+W5YaVLToLR8L0lB/DGmv1gcKE43ssNLSvpoW71Hct0necfade6+kW3zQ==", + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-7.3.5.tgz", + "integrity": "sha512-cTx584W2qrLonwhZLbEN7P5pAUu0nZblg8cLBlTrZQ4sIiw8Fbvg7GvuphQaSHxPxrCpa7FDwJKtXdbl2TSmrA==", "requires": { "@babel/runtime": "^7.28.4", - "@mui/utils": "^7.3.3", + "@mui/utils": "^7.3.5", "prop-types": "^15.8.1" } }, "@mui/styled-engine": { - "version": "7.3.3", - "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-7.3.3.tgz", - "integrity": "sha512-CmFxvRJIBCEaWdilhXMw/5wFJ1+FT9f3xt+m2pPXhHPeVIbBg9MnMvNSJjdALvnQJMPw8jLhrUtXmN7QAZV2fw==", + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-7.3.5.tgz", + "integrity": "sha512-zbsZ0uYYPndFCCPp2+V3RLcAN6+fv4C8pdwRx6OS3BwDkRCN8WBehqks7hWyF3vj1kdQLIWrpdv/5Y0jHRxYXQ==", "requires": { "@babel/runtime": "^7.28.4", "@emotion/cache": "^11.14.0", @@ -32366,39 +32365,39 @@ } }, "@mui/system": { - "version": "7.3.3", - "resolved": "https://registry.npmjs.org/@mui/system/-/system-7.3.3.tgz", - "integrity": "sha512-Lqq3emZr5IzRLKaHPuMaLBDVaGvxoh6z7HMWd1RPKawBM5uMRaQ4ImsmmgXWtwJdfZux5eugfDhXJUo2mliS8Q==", + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/@mui/system/-/system-7.3.5.tgz", + "integrity": "sha512-yPaf5+gY3v80HNkJcPi6WT+r9ebeM4eJzrREXPxMt7pNTV/1eahyODO4fbH3Qvd8irNxDFYn5RQ3idHW55rA6g==", "requires": { "@babel/runtime": "^7.28.4", - "@mui/private-theming": "^7.3.3", - "@mui/styled-engine": "^7.3.3", - "@mui/types": "^7.4.7", - "@mui/utils": "^7.3.3", + "@mui/private-theming": "^7.3.5", + "@mui/styled-engine": "^7.3.5", + "@mui/types": "^7.4.8", + "@mui/utils": "^7.3.5", "clsx": "^2.1.1", "csstype": "^3.1.3", "prop-types": "^15.8.1" } }, "@mui/types": { - "version": "7.4.7", - "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.4.7.tgz", - "integrity": "sha512-8vVje9rdEr1rY8oIkYgP+Su5Kwl6ik7O3jQ0wl78JGSmiZhRHV+vkjooGdKD8pbtZbutXFVTWQYshu2b3sG9zw==", + "version": "7.4.8", + "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.4.8.tgz", + "integrity": "sha512-ZNXLBjkPV6ftLCmmRCafak3XmSn8YV0tKE/ZOhzKys7TZXUiE0mZxlH8zKDo6j6TTUaDnuij68gIG+0Ucm7Xhw==", "requires": { "@babel/runtime": "^7.28.4" } }, "@mui/utils": { - "version": "7.3.3", - "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-7.3.3.tgz", - "integrity": "sha512-kwNAUh7bLZ7mRz9JZ+6qfRnnxbE4Zuc+RzXnhSpRSxjTlSTj7b4JxRLXpG+MVtPVtqks5k/XC8No1Vs3x4Z2gg==", + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-7.3.5.tgz", + "integrity": "sha512-jisvFsEC3sgjUjcPnR4mYfhzjCDIudttSGSbe1o/IXFNu0kZuR+7vqQI0jg8qtcVZBHWrwTfvAZj9MNMumcq1g==", "requires": { "@babel/runtime": "^7.28.4", - "@mui/types": "^7.4.7", + "@mui/types": "^7.4.8", "@types/prop-types": "^15.7.15", "clsx": "^2.1.1", "prop-types": "^15.8.1", - "react-is": "^19.1.1" + "react-is": "^19.2.0" }, "dependencies": { "react-is": { diff --git a/dapp-example/package.json b/dapp-example/package.json index 9543516cc8..be787024b1 100644 --- a/dapp-example/package.json +++ b/dapp-example/package.json @@ -6,7 +6,7 @@ "@emotion/react": "^11.14.0", "@emotion/styled": "^11.14.1", "@hashgraph/sdk": "^2.75.0", - "@mui/material": "^7.3.4", + "@mui/material": "^7.3.5", "ethers": "^6.15.0", "react": "^19.1.1", "react-dom": "^19.2.0", @@ -27,9 +27,9 @@ "mocha": "10.8.2" }, "devDependencies": { - "@babel/core": "^7.28.3", - "@babel/preset-env": "^7.28.3", - "@cypress/webpack-batteries-included-preprocessor": "^4.0.2", + "@babel/core": "^7.28.5", + "@babel/preset-env": "^7.28.5", + "@cypress/webpack-batteries-included-preprocessor": "^4.0.4", "@cypress/webpack-preprocessor": "^6.0.4", "@synthetixio/synpress": "^3.7.3", "babel-loader": "^10.0.0", diff --git a/tools/hardhat-example/package-lock.json b/tools/hardhat-example/package-lock.json index fa189c29ba..ae93a3be9d 100644 --- a/tools/hardhat-example/package-lock.json +++ b/tools/hardhat-example/package-lock.json @@ -12,7 +12,7 @@ "devDependencies": { "@hashgraph/hedera-local": "^2.39.0", "@nomicfoundation/hardhat-toolbox": "^6.1.0", - "dotenv": "^17.2.1", + "dotenv": "^17.2.3", "hardhat": "^2.26.1" } }, @@ -5440,9 +5440,9 @@ } }, "node_modules/dotenv": { - "version": "17.2.1", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.1.tgz", - "integrity": "sha512-kQhDYKZecqnM0fCnzI5eIv5L4cAe/iRI+HqMbO/hbRdTAeXDG+M9FjipUxNfbARuEg4iHIbhnhs78BCHNbSxEQ==", + "version": "17.2.3", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.3.tgz", + "integrity": "sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w==", "dev": true, "license": "BSD-2-Clause", "engines": { @@ -12230,9 +12230,9 @@ } }, "node_modules/typescript": { - "version": "5.9.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.2.tgz", - "integrity": "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==", + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "dev": true, "license": "Apache-2.0", "peer": true, diff --git a/tools/hardhat-example/package.json b/tools/hardhat-example/package.json index 96204210ec..8f5ad2d7b4 100644 --- a/tools/hardhat-example/package.json +++ b/tools/hardhat-example/package.json @@ -7,7 +7,7 @@ "devDependencies": { "@hashgraph/hedera-local": "^2.39.0", "@nomicfoundation/hardhat-toolbox": "^6.1.0", - "dotenv": "^17.2.1", + "dotenv": "^17.2.3", "hardhat": "^2.26.1" }, "dependencies": { diff --git a/tools/hardhat-viem-example/package-lock.json b/tools/hardhat-viem-example/package-lock.json index 7aedbc8243..73254d1501 100644 --- a/tools/hardhat-viem-example/package-lock.json +++ b/tools/hardhat-viem-example/package-lock.json @@ -9,8 +9,8 @@ "version": "1.0.0", "dependencies": { "@hashgraph/hedera-local": "^2.29.2", - "@nomicfoundation/hardhat-toolbox-viem": "^5.0.0", - "dotenv": "^17.2.1" + "@nomicfoundation/hardhat-toolbox-viem": "^5.0.1", + "dotenv": "^17.2.3" }, "devDependencies": { "@nomicfoundation/hardhat-chai-matchers": "^2.0.6", @@ -5508,9 +5508,9 @@ } }, "node_modules/@nomicfoundation/hardhat-toolbox-viem": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-toolbox-viem/-/hardhat-toolbox-viem-5.0.0.tgz", - "integrity": "sha512-pls++zTi+NcYPV6lWpyEFJqblfvaQ9oMXDOFfob1u1GT3PilXOcl3pRC9gHOCPnujOrU8xdiWfuZ/4X/26Ve5A==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-toolbox-viem/-/hardhat-toolbox-viem-5.0.1.tgz", + "integrity": "sha512-NhPQjHwTk356k6WS7tPeEWS5ymtlZe2lzcZzvgd2AD7wrMXE/zUu5qacXgwPq/M6HVEczSpuFeu+/koQgA2pbA==", "license": "MIT", "peerDependencies": { "@nomicfoundation/hardhat-ignition": "^3.0.0", @@ -8610,9 +8610,9 @@ } }, "node_modules/dotenv": { - "version": "17.2.1", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.1.tgz", - "integrity": "sha512-kQhDYKZecqnM0fCnzI5eIv5L4cAe/iRI+HqMbO/hbRdTAeXDG+M9FjipUxNfbARuEg4iHIbhnhs78BCHNbSxEQ==", + "version": "17.2.3", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.3.tgz", + "integrity": "sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w==", "license": "BSD-2-Clause", "engines": { "node": ">=12" @@ -15692,9 +15692,9 @@ } }, "node_modules/typescript": { - "version": "5.9.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.2.tgz", - "integrity": "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==", + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "license": "Apache-2.0", "peer": true, "bin": { diff --git a/tools/hardhat-viem-example/package.json b/tools/hardhat-viem-example/package.json index 6e6a481256..4e353ec1d2 100644 --- a/tools/hardhat-viem-example/package.json +++ b/tools/hardhat-viem-example/package.json @@ -9,8 +9,8 @@ }, "dependencies": { "@hashgraph/hedera-local": "^2.29.2", - "@nomicfoundation/hardhat-toolbox-viem": "^5.0.0", - "dotenv": "^17.2.1" + "@nomicfoundation/hardhat-toolbox-viem": "^5.0.1", + "dotenv": "^17.2.3" }, "devDependencies": { "@nomicfoundation/hardhat-chai-matchers": "^2.0.6", diff --git a/tools/hedera-crosschain-bridge/package-lock.json b/tools/hedera-crosschain-bridge/package-lock.json index 9564d6ee66..d0be777315 100644 --- a/tools/hedera-crosschain-bridge/package-lock.json +++ b/tools/hedera-crosschain-bridge/package-lock.json @@ -8,12 +8,12 @@ "license": "Apache-2.0", "devDependencies": { "@hashgraph/sdk": "^2.75.0", - "@layerzerolabs/lz-evm-oapp-v2": "^3.0.126", - "@layerzerolabs/lz-v2-utilities": "^3.0.126", + "@layerzerolabs/lz-evm-oapp-v2": "^3.0.146", + "@layerzerolabs/lz-v2-utilities": "^3.0.146", "@layerzerolabs/oapp-evm": "^0.3.2", "@layerzerolabs/onft-evm": "^0.2.3", "@nomicfoundation/hardhat-toolbox": "^6.1.0", - "dotenv": "^17.2.1", + "dotenv": "^17.2.3", "hardhat": "^2.24.1" } }, @@ -64,22 +64,22 @@ } }, "node_modules/@babel/core": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.4.tgz", - "integrity": "sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.5.tgz", + "integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==", "dev": true, "license": "MIT", "peer": true, "dependencies": { "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.28.3", + "@babel/generator": "^7.28.5", "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-module-transforms": "^7.28.3", "@babel/helpers": "^7.28.4", - "@babel/parser": "^7.28.4", + "@babel/parser": "^7.28.5", "@babel/template": "^7.27.2", - "@babel/traverse": "^7.28.4", - "@babel/types": "^7.28.4", + "@babel/traverse": "^7.28.5", + "@babel/types": "^7.28.5", "@jridgewell/remapping": "^2.3.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", @@ -96,15 +96,15 @@ } }, "node_modules/@babel/generator": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.3.tgz", - "integrity": "sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.5.tgz", + "integrity": "sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==", "dev": true, "license": "MIT", "peer": true, "dependencies": { - "@babel/parser": "^7.28.3", - "@babel/types": "^7.28.2", + "@babel/parser": "^7.28.5", + "@babel/types": "^7.28.5", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" @@ -211,9 +211,9 @@ } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", - "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", "dev": true, "license": "MIT", "peer": true, @@ -248,14 +248,14 @@ } }, "node_modules/@babel/parser": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.4.tgz", - "integrity": "sha512-yZbBqeM6TkpP9du/I2pUZnJsRMGGvOuIrhjzC1AwHwW+6he4mni6Bp/m8ijn0iOuZuPI2BfkCoSRunpyjnrQKg==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.5.tgz", + "integrity": "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==", "dev": true, "license": "MIT", "peer": true, "dependencies": { - "@babel/types": "^7.28.4" + "@babel/types": "^7.28.5" }, "bin": { "parser": "bin/babel-parser.js" @@ -514,19 +514,19 @@ } }, "node_modules/@babel/traverse": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.4.tgz", - "integrity": "sha512-YEzuboP2qvQavAcjgQNVgsvHIDv6ZpwXvcvjmyySP2DIMuByS/6ioU5G9pYrWHM6T2YDfc7xga9iNzYOs12CFQ==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.5.tgz", + "integrity": "sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==", "dev": true, "license": "MIT", "peer": true, "dependencies": { "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.28.3", + "@babel/generator": "^7.28.5", "@babel/helper-globals": "^7.28.0", - "@babel/parser": "^7.28.4", + "@babel/parser": "^7.28.5", "@babel/template": "^7.27.2", - "@babel/types": "^7.28.4", + "@babel/types": "^7.28.5", "debug": "^4.3.1" }, "engines": { @@ -555,15 +555,15 @@ } }, "node_modules/@babel/types": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.4.tgz", - "integrity": "sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.5.tgz", + "integrity": "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==", "dev": true, "license": "MIT", "peer": true, "dependencies": { "@babel/helper-string-parser": "^7.27.1", - "@babel/helper-validator-identifier": "^7.27.1" + "@babel/helper-validator-identifier": "^7.28.5" }, "engines": { "node": ">=6.9.0" @@ -2333,9 +2333,9 @@ } }, "node_modules/@layerzerolabs/lz-evm-messagelib-v2": { - "version": "3.0.126", - "resolved": "https://registry.npmjs.org/@layerzerolabs/lz-evm-messagelib-v2/-/lz-evm-messagelib-v2-3.0.126.tgz", - "integrity": "sha512-Yp53HY6mkqaRu/4w5wt50CoL7rfQhcfmuIVABY60Lnb2wma2jDY7rAYH/W1tpJebxjdVhaP1BUGj8CaZdAK0Qw==", + "version": "3.0.146", + "resolved": "https://registry.npmjs.org/@layerzerolabs/lz-evm-messagelib-v2/-/lz-evm-messagelib-v2-3.0.146.tgz", + "integrity": "sha512-XF8IRIVbW9YwAL6VwVJwDcEGGcOY7ruvmNl4dHAZJSSCWdb0ceMpf15zEAQj9s6aB4SIbAdgChkS5v+5gvgRBg==", "dev": true, "license": "LZBL-1.2", "peer": true, @@ -2344,8 +2344,8 @@ "@axelar-network/axelar-gmp-sdk-solidity": "^5.6.4", "@chainlink/contracts-ccip": "^0.7.6", "@eth-optimism/contracts": "^0.6.0", - "@layerzerolabs/lz-evm-protocol-v2": "^3.0.126", - "@layerzerolabs/lz-evm-v1-0.7": "^3.0.126", + "@layerzerolabs/lz-evm-protocol-v2": "^3.0.146", + "@layerzerolabs/lz-evm-v1-0.7": "^3.0.146", "@openzeppelin/contracts": "^4.8.1 || ^5.0.0", "@openzeppelin/contracts-upgradeable": "^4.8.1 || ^5.0.0", "hardhat-deploy": "^0.12.4", @@ -2358,15 +2358,15 @@ } }, "node_modules/@layerzerolabs/lz-evm-oapp-v2": { - "version": "3.0.126", - "resolved": "https://registry.npmjs.org/@layerzerolabs/lz-evm-oapp-v2/-/lz-evm-oapp-v2-3.0.126.tgz", - "integrity": "sha512-ueHX+4D3Y89Y+wwfaz0F8x7vPulpyHBl1J80XRRehopacJwEtK68PYy7rtWtBHDeNKD4IbhE9HHO+j/WH4hljQ==", + "version": "3.0.146", + "resolved": "https://registry.npmjs.org/@layerzerolabs/lz-evm-oapp-v2/-/lz-evm-oapp-v2-3.0.146.tgz", + "integrity": "sha512-2PwP7ExMQMqKscpDK/83A1hk0I4MaFKSgHxEI1jGH/10nkJJ6wIL4SMkalxP9yFpWC7MAYrejLYqDejc6peDsQ==", "dev": true, "license": "MIT", "peerDependencies": { - "@layerzerolabs/lz-evm-messagelib-v2": "^3.0.126", - "@layerzerolabs/lz-evm-protocol-v2": "^3.0.126", - "@layerzerolabs/lz-evm-v1-0.7": "^3.0.126", + "@layerzerolabs/lz-evm-messagelib-v2": "^3.0.146", + "@layerzerolabs/lz-evm-protocol-v2": "^3.0.146", + "@layerzerolabs/lz-evm-v1-0.7": "^3.0.146", "@openzeppelin/contracts": "^4.8.1 || ^5.0.0", "@openzeppelin/contracts-upgradeable": "^4.8.1 || ^5.0.0", "hardhat-deploy": "^0.12.4", @@ -2374,9 +2374,9 @@ } }, "node_modules/@layerzerolabs/lz-evm-protocol-v2": { - "version": "3.0.126", - "resolved": "https://registry.npmjs.org/@layerzerolabs/lz-evm-protocol-v2/-/lz-evm-protocol-v2-3.0.126.tgz", - "integrity": "sha512-lj3bPEbihrAzsiEYuF6E4+jcwN1rbL3kX8xNAegtMEnD221/oQGqSfFG235BT8gs2wk4bdY/BE6r5CENOmajlQ==", + "version": "3.0.146", + "resolved": "https://registry.npmjs.org/@layerzerolabs/lz-evm-protocol-v2/-/lz-evm-protocol-v2-3.0.146.tgz", + "integrity": "sha512-Lw+drVpXuyk3PFSCmFmgzaxl2I7bYFt/lyqqGPJYMzwXb9wifoWLpIIM9yWz3hFSgHpJI+jMviG5H+no6iomtw==", "dev": true, "license": "LZBL-1.2", "peer": true, @@ -2388,9 +2388,9 @@ } }, "node_modules/@layerzerolabs/lz-evm-v1-0.7": { - "version": "3.0.126", - "resolved": "https://registry.npmjs.org/@layerzerolabs/lz-evm-v1-0.7/-/lz-evm-v1-0.7-3.0.126.tgz", - "integrity": "sha512-Tzx7oK/6nDUqjE7TBPeJdIp9+F6YkRGvmW1B5Tg2oLOCign509LT7ch6g0OFMmLd8qQKvE+w5cmUTkzA/rrNew==", + "version": "3.0.146", + "resolved": "https://registry.npmjs.org/@layerzerolabs/lz-evm-v1-0.7/-/lz-evm-v1-0.7-3.0.146.tgz", + "integrity": "sha512-tZb6eLLbBvdW8NfLdxWGKxRVFpu06xVooD4XUsNJxzbuomotVcZvCOe8AWgW+dmAZxlgm6KPiBk8Pn5qe17+ww==", "dev": true, "license": "BUSL-1.1", "peer": true, @@ -2401,9 +2401,9 @@ } }, "node_modules/@layerzerolabs/lz-v2-utilities": { - "version": "3.0.126", - "resolved": "https://registry.npmjs.org/@layerzerolabs/lz-v2-utilities/-/lz-v2-utilities-3.0.126.tgz", - "integrity": "sha512-YyzYFRYtIVAPAywSG6ogVfU7eQvEh2H4H6ooqeb0Tx/WpTZS+gnGcVdILZPlPO9KPe6uU7CGKIqUXx2Ahn5v/g==", + "version": "3.0.146", + "resolved": "https://registry.npmjs.org/@layerzerolabs/lz-v2-utilities/-/lz-v2-utilities-3.0.146.tgz", + "integrity": "sha512-KLPQ81c98JrbAUbtvEpXTeWubArWKXztabBpf7svdP7x4fGeQf+tyPLEENbo0O2TNczl0D7qB17o0UZ4n9v73A==", "dev": true, "license": "BUSL-1.1", "dependencies": { @@ -5817,9 +5817,9 @@ } }, "node_modules/dotenv": { - "version": "17.2.1", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.1.tgz", - "integrity": "sha512-kQhDYKZecqnM0fCnzI5eIv5L4cAe/iRI+HqMbO/hbRdTAeXDG+M9FjipUxNfbARuEg4iHIbhnhs78BCHNbSxEQ==", + "version": "17.2.3", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.3.tgz", + "integrity": "sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w==", "dev": true, "license": "BSD-2-Clause", "engines": { diff --git a/tools/hedera-crosschain-bridge/package.json b/tools/hedera-crosschain-bridge/package.json index 12f10e630f..e57378d779 100644 --- a/tools/hedera-crosschain-bridge/package.json +++ b/tools/hedera-crosschain-bridge/package.json @@ -13,12 +13,12 @@ "license": "Apache-2.0", "devDependencies": { "@hashgraph/sdk": "^2.75.0", - "@layerzerolabs/lz-evm-oapp-v2": "^3.0.126", - "@layerzerolabs/lz-v2-utilities": "^3.0.126", + "@layerzerolabs/lz-evm-oapp-v2": "^3.0.146", + "@layerzerolabs/lz-v2-utilities": "^3.0.146", "@layerzerolabs/oapp-evm": "^0.3.2", "@layerzerolabs/onft-evm": "^0.2.3", "@nomicfoundation/hardhat-toolbox": "^6.1.0", - "dotenv": "^17.2.1", + "dotenv": "^17.2.3", "hardhat": "^2.24.1" } } diff --git a/tools/solidity-coverage-example/package-lock.json b/tools/solidity-coverage-example/package-lock.json index adf6417843..cc0915ca70 100644 --- a/tools/solidity-coverage-example/package-lock.json +++ b/tools/solidity-coverage-example/package-lock.json @@ -7336,9 +7336,9 @@ } }, "node_modules/typescript": { - "version": "5.9.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.2.tgz", - "integrity": "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==", + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "dev": true, "license": "Apache-2.0", "peer": true, diff --git a/tools/subgraph-example/package-lock.json b/tools/subgraph-example/package-lock.json index 371fed18ba..e0563a4219 100644 --- a/tools/subgraph-example/package-lock.json +++ b/tools/subgraph-example/package-lock.json @@ -19,7 +19,7 @@ "@typescript-eslint/eslint-plugin": "^4.33.0", "@typescript-eslint/parser": "^4.33.0", "chai": "^4.3.7", - "dotenv": "^17.2.1", + "dotenv": "^17.2.3", "eslint": "^7.32.0", "eslint-config-prettier": "^8.5.0", "eslint-config-standard": "^16.0.3", @@ -13042,9 +13042,9 @@ } }, "node_modules/dotenv": { - "version": "17.2.1", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.1.tgz", - "integrity": "sha512-kQhDYKZecqnM0fCnzI5eIv5L4cAe/iRI+HqMbO/hbRdTAeXDG+M9FjipUxNfbARuEg4iHIbhnhs78BCHNbSxEQ==", + "version": "17.2.3", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.3.tgz", + "integrity": "sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w==", "dev": true, "license": "BSD-2-Clause", "engines": { diff --git a/tools/subgraph-example/package.json b/tools/subgraph-example/package.json index 9c64f80c3b..2b96ff91d5 100644 --- a/tools/subgraph-example/package.json +++ b/tools/subgraph-example/package.json @@ -14,7 +14,7 @@ "@typescript-eslint/eslint-plugin": "^4.33.0", "@typescript-eslint/parser": "^4.33.0", "chai": "^4.3.7", - "dotenv": "^17.2.1", + "dotenv": "^17.2.3", "eslint": "^7.32.0", "eslint-config-prettier": "^8.5.0", "eslint-config-standard": "^16.0.3", diff --git a/tools/waffle-example/package-lock.json b/tools/waffle-example/package-lock.json index f55d143b7c..181cd31105 100644 --- a/tools/waffle-example/package-lock.json +++ b/tools/waffle-example/package-lock.json @@ -7,7 +7,7 @@ "name": "waffle-project", "devDependencies": { "chai": "^5.1.1", - "dotenv": "^17.2.1", + "dotenv": "^17.2.3", "ethereum-waffle": "^4.0.10", "mocha": "^10.8.2" } @@ -2509,9 +2509,9 @@ } }, "node_modules/dotenv": { - "version": "17.2.1", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.1.tgz", - "integrity": "sha512-kQhDYKZecqnM0fCnzI5eIv5L4cAe/iRI+HqMbO/hbRdTAeXDG+M9FjipUxNfbARuEg4iHIbhnhs78BCHNbSxEQ==", + "version": "17.2.3", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.3.tgz", + "integrity": "sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w==", "dev": true, "license": "BSD-2-Clause", "engines": { diff --git a/tools/waffle-example/package.json b/tools/waffle-example/package.json index f486387db9..177cb018ae 100644 --- a/tools/waffle-example/package.json +++ b/tools/waffle-example/package.json @@ -7,7 +7,7 @@ "type": "commonjs", "devDependencies": { "chai": "^5.1.1", - "dotenv": "^17.2.1", + "dotenv": "^17.2.3", "ethereum-waffle": "^4.0.10", "mocha": "^10.8.2" }, diff --git a/tools/web3js-example/package-lock.json b/tools/web3js-example/package-lock.json index 62d26971f3..8769268901 100644 --- a/tools/web3js-example/package-lock.json +++ b/tools/web3js-example/package-lock.json @@ -9,7 +9,7 @@ "version": "1.0.0", "license": "Apache-2.0", "dependencies": { - "dotenv": "^17.2.1", + "dotenv": "^17.2.3", "web3": "^4.16.0" }, "devDependencies": { @@ -479,9 +479,9 @@ } }, "node_modules/dotenv": { - "version": "17.2.1", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.1.tgz", - "integrity": "sha512-kQhDYKZecqnM0fCnzI5eIv5L4cAe/iRI+HqMbO/hbRdTAeXDG+M9FjipUxNfbARuEg4iHIbhnhs78BCHNbSxEQ==", + "version": "17.2.3", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.3.tgz", + "integrity": "sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w==", "license": "BSD-2-Clause", "engines": { "node": ">=12" diff --git a/tools/web3js-example/package.json b/tools/web3js-example/package.json index 2cb5197498..8653ee95da 100644 --- a/tools/web3js-example/package.json +++ b/tools/web3js-example/package.json @@ -9,7 +9,7 @@ "author": "", "license": "Apache-2.0", "dependencies": { - "dotenv": "^17.2.1", + "dotenv": "^17.2.3", "web3": "^4.16.0" }, "devDependencies": { diff --git a/tools/whbar-hardhat-example/package-lock.json b/tools/whbar-hardhat-example/package-lock.json index ee73cd3a57..030736996e 100644 --- a/tools/whbar-hardhat-example/package-lock.json +++ b/tools/whbar-hardhat-example/package-lock.json @@ -9,7 +9,7 @@ "version": "0.0.1", "dependencies": { "@hashgraph/sdk": "^2.75.0", - "dotenv": "^17.2.1" + "dotenv": "^17.2.3" }, "devDependencies": { "@nomicfoundation/hardhat-toolbox": "^6.1.0", @@ -50,21 +50,21 @@ } }, "node_modules/@babel/core": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.4.tgz", - "integrity": "sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.5.tgz", + "integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==", "license": "MIT", "peer": true, "dependencies": { "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.28.3", + "@babel/generator": "^7.28.5", "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-module-transforms": "^7.28.3", "@babel/helpers": "^7.28.4", - "@babel/parser": "^7.28.4", + "@babel/parser": "^7.28.5", "@babel/template": "^7.27.2", - "@babel/traverse": "^7.28.4", - "@babel/types": "^7.28.4", + "@babel/traverse": "^7.28.5", + "@babel/types": "^7.28.5", "@jridgewell/remapping": "^2.3.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", @@ -81,14 +81,14 @@ } }, "node_modules/@babel/generator": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.3.tgz", - "integrity": "sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.5.tgz", + "integrity": "sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==", "license": "MIT", "peer": true, "dependencies": { - "@babel/parser": "^7.28.3", - "@babel/types": "^7.28.2", + "@babel/parser": "^7.28.5", + "@babel/types": "^7.28.5", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" @@ -188,9 +188,9 @@ } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", - "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", "license": "MIT", "peer": true, "engines": { @@ -222,13 +222,13 @@ } }, "node_modules/@babel/parser": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.4.tgz", - "integrity": "sha512-yZbBqeM6TkpP9du/I2pUZnJsRMGGvOuIrhjzC1AwHwW+6he4mni6Bp/m8ijn0iOuZuPI2BfkCoSRunpyjnrQKg==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.5.tgz", + "integrity": "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==", "license": "MIT", "peer": true, "dependencies": { - "@babel/types": "^7.28.4" + "@babel/types": "^7.28.5" }, "bin": { "parser": "bin/babel-parser.js" @@ -470,18 +470,18 @@ } }, "node_modules/@babel/traverse": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.4.tgz", - "integrity": "sha512-YEzuboP2qvQavAcjgQNVgsvHIDv6ZpwXvcvjmyySP2DIMuByS/6ioU5G9pYrWHM6T2YDfc7xga9iNzYOs12CFQ==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.5.tgz", + "integrity": "sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==", "license": "MIT", "peer": true, "dependencies": { "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.28.3", + "@babel/generator": "^7.28.5", "@babel/helper-globals": "^7.28.0", - "@babel/parser": "^7.28.4", + "@babel/parser": "^7.28.5", "@babel/template": "^7.27.2", - "@babel/types": "^7.28.4", + "@babel/types": "^7.28.5", "debug": "^4.3.1" }, "engines": { @@ -509,14 +509,14 @@ } }, "node_modules/@babel/types": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.4.tgz", - "integrity": "sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.5.tgz", + "integrity": "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==", "license": "MIT", "peer": true, "dependencies": { "@babel/helper-string-parser": "^7.27.1", - "@babel/helper-validator-identifier": "^7.27.1" + "@babel/helper-validator-identifier": "^7.28.5" }, "engines": { "node": ">=6.9.0" @@ -4808,9 +4808,9 @@ } }, "node_modules/dotenv": { - "version": "17.2.1", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.1.tgz", - "integrity": "sha512-kQhDYKZecqnM0fCnzI5eIv5L4cAe/iRI+HqMbO/hbRdTAeXDG+M9FjipUxNfbARuEg4iHIbhnhs78BCHNbSxEQ==", + "version": "17.2.3", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.3.tgz", + "integrity": "sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w==", "license": "BSD-2-Clause", "engines": { "node": ">=12" diff --git a/tools/whbar-hardhat-example/package.json b/tools/whbar-hardhat-example/package.json index e1ea35502a..a09a5d5baa 100644 --- a/tools/whbar-hardhat-example/package.json +++ b/tools/whbar-hardhat-example/package.json @@ -8,7 +8,7 @@ }, "dependencies": { "@hashgraph/sdk": "^2.75.0", - "dotenv": "^17.2.1" + "dotenv": "^17.2.3" }, "overrides": { "cookie": "^0.7.0" From 2e9648a3334d774576558601b1d58c151d84cc3f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 27 Nov 2025 17:33:02 +0200 Subject: [PATCH 07/12] build(deps): bump github.com/consensys/gnark-crypto from 0.18.0 to 0.18.1 in /tools/golang-json-rpc-tests (#4562) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- tools/golang-json-rpc-tests/go.mod | 2 +- tools/golang-json-rpc-tests/go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/golang-json-rpc-tests/go.mod b/tools/golang-json-rpc-tests/go.mod index 7153446bc9..2f657e24e4 100644 --- a/tools/golang-json-rpc-tests/go.mod +++ b/tools/golang-json-rpc-tests/go.mod @@ -13,7 +13,7 @@ require ( github.com/Microsoft/go-winio v0.6.2 // indirect github.com/StackExchange/wmi v1.2.1 // indirect github.com/bits-and-blooms/bitset v1.20.0 // indirect - github.com/consensys/gnark-crypto v0.18.0 // indirect + github.com/consensys/gnark-crypto v0.18.1 // indirect github.com/crate-crypto/go-eth-kzg v1.4.0 // indirect github.com/crate-crypto/go-ipa v0.0.0-20240724233137-53bbb0ceb27a // indirect github.com/deckarep/golang-set/v2 v2.6.0 // indirect diff --git a/tools/golang-json-rpc-tests/go.sum b/tools/golang-json-rpc-tests/go.sum index b83372c5b8..5826838f50 100644 --- a/tools/golang-json-rpc-tests/go.sum +++ b/tools/golang-json-rpc-tests/go.sum @@ -26,8 +26,8 @@ github.com/cockroachdb/redact v1.1.5 h1:u1PMllDkdFfPWaNGMyLD1+so+aq3uUItthCFqzwP github.com/cockroachdb/redact v1.1.5/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg= github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 h1:zuQyyAKVxetITBuuhv3BI9cMrmStnpT18zmgmTxunpo= github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06/go.mod h1:7nc4anLGjupUW/PeY5qiNYsdNXj7zopG+eqsS7To5IQ= -github.com/consensys/gnark-crypto v0.18.0 h1:vIye/FqI50VeAr0B3dx+YjeIvmc3LWz4yEfbWBpTUf0= -github.com/consensys/gnark-crypto v0.18.0/go.mod h1:L3mXGFTe1ZN+RSJ+CLjUt9x7PNdx8ubaYfDROyp2Z8c= +github.com/consensys/gnark-crypto v0.18.1 h1:RyLV6UhPRoYYzaFnPQA4qK3DyuDgkTgskDdoGqFt3fI= +github.com/consensys/gnark-crypto v0.18.1/go.mod h1:L3mXGFTe1ZN+RSJ+CLjUt9x7PNdx8ubaYfDROyp2Z8c= github.com/cpuguy83/go-md2man/v2 v2.0.5 h1:ZtcqGrnekaHpVLArFSe4HK5DoKx1T0rq2DwVB0alcyc= github.com/cpuguy83/go-md2man/v2 v2.0.5/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/crate-crypto/go-eth-kzg v1.4.0 h1:WzDGjHk4gFg6YzV0rJOAsTK4z3Qkz5jd4RE3DAvPFkg= From 2b977344788a473f53d6627578b9997015ea42ec Mon Sep 17 00:00:00 2001 From: jasuwienas Date: Fri, 5 Dec 2025 17:17:20 +0100 Subject: [PATCH 08/12] feat: add cache factory, unify client interface, remove fallback (#4558) (#4623) Signed-off-by: Mariusz Jasuwienas Signed-off-by: jasuwienas --- .../src/lib/clients/cache/ICacheClient.ts | 5 +- .../lib/clients/cache/IRedisCacheClient.ts | 16 -- .../src/lib/clients/cache/localLRUCache.ts | 68 ++++- .../src/lib/clients/cache/redisCache/index.ts | 3 + .../cache/{ => redisCache}/redisCache.ts | 25 +- .../cache/redisCache/safeRedisCache.ts | 172 ++++++++++++ packages/relay/src/lib/clients/index.ts | 2 +- .../src/lib/factories/cacheClientFactory.ts | 22 ++ packages/relay/src/lib/relay.ts | 10 +- .../lib/services/cacheService/cacheService.ts | 252 ++++-------------- .../tests/lib/clients/localLRUCache.spec.ts | 102 ++++++- .../tests/lib/clients/redisCache.spec.ts | 30 ++- .../hbarSpendingPlanConfigService.spec.ts | 5 +- packages/relay/tests/lib/eth/eth-helpers.ts | 3 +- .../relay/tests/lib/ethGetBlockBy.spec.ts | 6 +- packages/relay/tests/lib/hapiService.spec.ts | 3 +- .../relay/tests/lib/mirrorNodeClient.spec.ts | 5 +- packages/relay/tests/lib/openrpc.spec.ts | 3 +- packages/relay/tests/lib/precheck.spec.ts | 3 +- ...mAddressHbarSpendingPlanRepository.spec.ts | 3 +- .../hbarSpendingPlanRepository.spec.ts | 3 +- ...pAddressHbarSpendingPlanRepository.spec.ts | 3 +- packages/relay/tests/lib/sdkClient.spec.ts | 3 +- .../cacheService/cacheService.spec.ts | 56 ++-- .../tests/lib/services/eth/filter.spec.ts | 42 +-- .../hbarLimitService/hbarLimitService.spec.ts | 4 +- .../metricService/metricService.spec.ts | 5 +- .../tests/acceptance/cacheService.spec.ts | 32 ++- .../tests/acceptance/hbarLimiter.spec.ts | 6 +- 29 files changed, 548 insertions(+), 344 deletions(-) delete mode 100644 packages/relay/src/lib/clients/cache/IRedisCacheClient.ts create mode 100644 packages/relay/src/lib/clients/cache/redisCache/index.ts rename packages/relay/src/lib/clients/cache/{ => redisCache}/redisCache.ts (94%) create mode 100644 packages/relay/src/lib/clients/cache/redisCache/safeRedisCache.ts create mode 100644 packages/relay/src/lib/factories/cacheClientFactory.ts diff --git a/packages/relay/src/lib/clients/cache/ICacheClient.ts b/packages/relay/src/lib/clients/cache/ICacheClient.ts index 4590c3877b..a8028bc41b 100644 --- a/packages/relay/src/lib/clients/cache/ICacheClient.ts +++ b/packages/relay/src/lib/clients/cache/ICacheClient.ts @@ -4,8 +4,11 @@ export interface ICacheClient { keys(pattern: string, callingMethod: string): Promise; get(key: string, callingMethod: string): Promise; set(key: string, value: any, callingMethod: string, ttl?: number): Promise; - multiSet(keyValuePairs: Record, callingMethod: string): Promise; + multiSet(keyValuePairs: Record, callingMethod: string, ttl?: number | undefined): Promise; pipelineSet(keyValuePairs: Record, callingMethod: string, ttl?: number | undefined): Promise; delete(key: string, callingMethod: string): Promise; clear(): Promise; + incrBy(key: string, amount: number, callingMethod: string): Promise; + rPush(key: string, value: any, callingMethod: string): Promise; + lRange(key: string, start: number, end: number, callingMethod: string): Promise; } diff --git a/packages/relay/src/lib/clients/cache/IRedisCacheClient.ts b/packages/relay/src/lib/clients/cache/IRedisCacheClient.ts deleted file mode 100644 index 59a1ae3176..0000000000 --- a/packages/relay/src/lib/clients/cache/IRedisCacheClient.ts +++ /dev/null @@ -1,16 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 - -import { RequestDetails } from '../../types'; -import type { ICacheClient } from './ICacheClient'; - -export interface IRedisCacheClient extends ICacheClient { - incrBy(key: string, amount: number, callingMethod: string, requestDetails: RequestDetails): Promise; - rPush(key: string, value: any, callingMethod: string, requestDetails: RequestDetails): Promise; - lRange( - key: string, - start: number, - end: number, - callingMethod: string, - requestDetails: RequestDetails, - ): Promise; -} diff --git a/packages/relay/src/lib/clients/cache/localLRUCache.ts b/packages/relay/src/lib/clients/cache/localLRUCache.ts index 63cf309b49..b58f6917af 100644 --- a/packages/relay/src/lib/clients/cache/localLRUCache.ts +++ b/packages/relay/src/lib/clients/cache/localLRUCache.ts @@ -72,6 +72,7 @@ export class LocalLRUCache implements ICacheClient { * @constructor * @param {Logger} logger - The logger instance to be used for logging. * @param {Registry} register - The registry instance used for metrics tracking. + * @param {Set} reservedKeys - These are the cache keys delegated to the reserved cache. */ public constructor(logger: Logger, register: Registry, reservedKeys: Set = new Set()) { this.cache = new LRUCache(this.options); @@ -137,8 +138,9 @@ export class LocalLRUCache implements ICacheClient { * @param key - The key to check the remaining TTL for. * @param callingMethod - The name of the method calling the cache. * @returns The remaining TTL in milliseconds. + * @private */ - public async getRemainingTtl(key: string, callingMethod: string): Promise { + private async getRemainingTtl(key: string, callingMethod: string): Promise { const prefixedKey = this.prefixKey(key); const cache = this.getCacheInstance(key); const remainingTtl = cache.getRemainingTTL(prefixedKey); // in milliseconds @@ -280,6 +282,70 @@ export class LocalLRUCache implements ICacheClient { return matchingKeys.map((key) => key.substring(LocalLRUCache.CACHE_KEY_PREFIX.length)); } + /** + * Increments a value in the cache. + * + * @param key The key to increment + * @param amount The amount to increment by + * @param callingMethod The name of the calling method + * @returns The value of the key after incrementing + */ + public async incrBy(key: string, amount: number, callingMethod: string): Promise { + const value = await this.get(key, callingMethod); + const newValue = value + amount; + const remainingTtl = await this.getRemainingTtl(key, callingMethod); + await this.set(key, newValue, callingMethod, remainingTtl); + return newValue; + } + + /** + * Retrieves a range of elements from a list in the cache. + * + * @param key The key of the list + * @param start The start index + * @param end The end index + * @param callingMethod The name of the calling method + * @returns The list of elements in the range + */ + public async lRange(key: string, start: number, end: number, callingMethod: string): Promise { + const values = (await this.get(key, callingMethod)) ?? []; + if (!Array.isArray(values)) { + throw new Error(`Value at key ${key} is not an array`); + } + if (end < 0) { + end = values.length + end; + } + return values.slice(start, end + 1); + } + + /** + * Pushes a value to the end of a list in the cache. + * + * @param key The key of the list + * @param value The value to push + * @param callingMethod The name of the calling method + * @returns The length of the list after pushing + */ + public async rPush(key: string, value: any, callingMethod: string): Promise { + const values = (await this.get(key, callingMethod)) ?? []; + if (!Array.isArray(values)) { + throw new Error(`Value at key ${key} is not an array`); + } + values.push(value); + const remainingTtl = await this.getRemainingTtl(key, callingMethod); + await this.set(key, values, callingMethod, remainingTtl); + return values.length; + } + + /** + * Returns the appropriate cache instance for the given key. + * If a reserved cache exists and the key is marked as reserved, + * the reserved cache is returned; otherwise the default cache is used. + * + * @param key - The cache key being accessed. + * @returns The selected cache instance + * @private + */ private getCacheInstance(key: string): LRUCache { return this.reservedCache && this.reservedKeys.has(key) ? this.reservedCache : this.cache; } diff --git a/packages/relay/src/lib/clients/cache/redisCache/index.ts b/packages/relay/src/lib/clients/cache/redisCache/index.ts new file mode 100644 index 0000000000..9b154f4462 --- /dev/null +++ b/packages/relay/src/lib/clients/cache/redisCache/index.ts @@ -0,0 +1,3 @@ +// SPDX-License-Identifier: Apache-2.0 + +export { SafeRedisCache as RedisCache } from './safeRedisCache'; diff --git a/packages/relay/src/lib/clients/cache/redisCache.ts b/packages/relay/src/lib/clients/cache/redisCache/redisCache.ts similarity index 94% rename from packages/relay/src/lib/clients/cache/redisCache.ts rename to packages/relay/src/lib/clients/cache/redisCache/redisCache.ts index 7238343cb0..1f88a97774 100644 --- a/packages/relay/src/lib/clients/cache/redisCache.ts +++ b/packages/relay/src/lib/clients/cache/redisCache/redisCache.ts @@ -2,16 +2,15 @@ import { ConfigService } from '@hashgraph/json-rpc-config-service/dist/services'; import { Logger } from 'pino'; -import { Registry } from 'prom-client'; import { RedisClientType } from 'redis'; -import { Utils } from '../../../utils'; -import { IRedisCacheClient } from './IRedisCacheClient'; +import { Utils } from '../../../../utils'; +import { ICacheClient } from '../ICacheClient'; /** * A class that provides caching functionality using Redis. */ -export class RedisCache implements IRedisCacheClient { +export class RedisCache implements ICacheClient { /** * Prefix used to namespace all keys managed by this cache. * @@ -29,19 +28,14 @@ export class RedisCache implements IRedisCacheClient { private readonly options = { // Max time to live in ms, for items before they are considered stale. ttl: ConfigService.get('CACHE_TTL'), + multiSetEnabled: ConfigService.get('MULTI_SET'), }; /** * The logger used for logging all output from this class. * @private */ - private readonly logger: Logger; - - /** - * The metrics register used for metrics tracking. - * @private - */ - private readonly register: Registry; + protected readonly logger: Logger; /** * The Redis client. @@ -53,11 +47,10 @@ export class RedisCache implements IRedisCacheClient { * Creates an instance of `RedisCache`. * * @param {Logger} logger - The logger instance. - * @param {Registry} register - The metrics registry. + * @param {RedisClientType} client */ - public constructor(logger: Logger, register: Registry, client: RedisClientType) { + public constructor(logger: Logger, client: RedisClientType) { this.logger = logger; - this.register = register; this.client = client; } @@ -129,9 +122,11 @@ export class RedisCache implements IRedisCacheClient { * * @param keyValuePairs - An object where each property is a key and its value is the value to be cached. * @param callingMethod - The name of the calling method. + * @param [ttl] - The time-to-live (expiration) of the cache item in milliseconds. Used in fallback to pipelineSet. * @returns A Promise that resolves when the values are cached. */ - async multiSet(keyValuePairs: Record, callingMethod: string): Promise { + async multiSet(keyValuePairs: Record, callingMethod: string, ttl?: number): Promise { + if (!this.options.multiSetEnabled) return this.pipelineSet(keyValuePairs, callingMethod, ttl); // Serialize values and add prefix const serializedKeyValuePairs: Record = {}; for (const [key, value] of Object.entries(keyValuePairs)) { diff --git a/packages/relay/src/lib/clients/cache/redisCache/safeRedisCache.ts b/packages/relay/src/lib/clients/cache/redisCache/safeRedisCache.ts new file mode 100644 index 0000000000..db948af7be --- /dev/null +++ b/packages/relay/src/lib/clients/cache/redisCache/safeRedisCache.ts @@ -0,0 +1,172 @@ +// SPDX-License-Identifier: Apache-2.0 + +import { RedisCacheError } from '../../../errors/RedisCacheError'; +import { RedisCache } from './redisCache'; + +/** + * A safer wrapper around {@link RedisCache} which is responsible for: + * - ignoring all Redis command errors. + * - logging all errors, + * - returning default values in cases of failures. + * + * Thanks to that our application will be able to continue functioning even with Redis being down... + */ +export class SafeRedisCache extends RedisCache { + /** + * Retrieves a value from the cache. + * + * This method wraps {@link RedisCache.get} and ensures `null` is returned instead of throwing error. + * + * @param key - The cache key. + * @param callingMethod - Name of the method making the request (for logging). + * @returns The cached value, or `null` if Redis fails or the value does not exist. + */ + async get(key: string, callingMethod: string): Promise { + return await this.safeCall(() => super.get(key, callingMethod), null); + } + + /** + /** + * Stores a value in the cache safely. + * + * Wraps {@link RedisCache.set} and suppresses Redis errors. + * On failure, nothing is thrown and the error is logged. + * + * @param key - The cache key. + * @param value - The value to store. + * @param callingMethod - Name of the calling method. + * @param ttl - Optional TTL in milliseconds. + */ + async set(key: string, value: any, callingMethod: string, ttl?: number): Promise { + await this.safeCall(() => super.set(key, value, callingMethod, ttl), undefined); + } + + /** + * Stores multiple key-value pairs safely. + * + * Wraps {@link RedisCache.multiSet} with error suppression. + * + * @param keyValuePairs - Object of key-value pairs to set. + * @param callingMethod - Name of the calling method. + * @param ttl - Optional TTL used in fallback pipeline mode. + */ + async multiSet(keyValuePairs: Record, callingMethod: string, ttl?: number): Promise { + await this.safeCall(() => super.multiSet(keyValuePairs, callingMethod, ttl), undefined); + } + + /** + * Performs a pipelined multi-set operation safely. + * + * Wraps {@link RedisCache.pipelineSet} with error suppression. + * + * @param keyValuePairs - Key-value pairs to write. + * @param callingMethod - Name of the calling method. + * @param ttl - Optional TTL. + */ + async pipelineSet(keyValuePairs: Record, callingMethod: string, ttl?: number): Promise { + await this.safeCall(() => super.pipelineSet(keyValuePairs, callingMethod, ttl), undefined); + } + + /** + * Deletes a value from the cache safely. + * + * Wraps {@link RedisCache.delete} with error suppression. + * + * @param key - Key to delete. + * @param callingMethod - Name of the calling method. + */ + async delete(key: string, callingMethod: string): Promise { + await this.safeCall(() => super.delete(key, callingMethod), undefined); + } + + /** + * Increments a numeric value safely. + * + * Wraps {@link RedisCache.incrBy}. + * On failure, returns the `amount` argument as fallback. + * + * @param key - Key to increment. + * @param amount - Increment amount. + * @param callingMethod - Name of the calling method. + * @returns The incremented value or the fallback (amount) if Redis fails. + */ + async incrBy(key: string, amount: number, callingMethod: string): Promise { + return await this.safeCall(() => super.incrBy(key, amount, callingMethod), amount); + } + + /** + * Retrieves a list slice safely. + * + * Wraps {@link RedisCache.lRange}. + * On error, returns an empty array. + * + * @param key - List key. + * @param start - Start index. + * @param end - End index. + * @param callingMethod - Name of the calling method. + * @returns List of elements, or an empty array on failure. + */ + async lRange(key: string, start: number, end: number, callingMethod: string): Promise { + return await this.safeCall(() => super.lRange(key, start, end, callingMethod), []); + } + + /** + * Pushes a value to a list safely. + * + * Wraps {@link RedisCache.rPush}. + * Returns `0` on failure. + * + * @param key - List key. + * @param value - Value to push. + * @param callingMethod - Name of the calling method. + * @returns The new list length, or `0` if Redis fails. + */ + async rPush(key: string, value: any, callingMethod: string): Promise { + return await this.safeCall(() => super.rPush(key, value, callingMethod), 0); + } + + /** + * Retrieves keys matching a pattern safely. + * + * Wraps {@link RedisCache.keys}. + * Returns an empty array on error. + * + * @param pattern - Match pattern. + * @param callingMethod - Name of the calling method. + * @returns Array of matched keys (prefix removed), or empty array on error. + */ + async keys(pattern: string, callingMethod: string): Promise { + return await this.safeCall(() => super.keys(pattern, callingMethod), []); + } + + /** + * Clears all cache keys safely. + * + * Wraps {@link RedisCache.clear}. + * Any Redis failure is logged and ignored. + */ + + async clear(): Promise { + await this.safeCall(() => super.clear(), null); + } + + /** + * Executes a Redis call safely. + * + * This is the core safety mechanism of {@link SafeRedisCache}. + * + * @template T The expected return type. + * @param fn - Function containing the Redis call. + * @param fallback - Value to return if an error occurs. + * @returns The result of `fn()` or the fallback. + */ + async safeCall(fn: () => Promise, fallback: T): Promise { + try { + return await fn(); + } catch (error) { + const redisError = new RedisCacheError(error); + this.logger.error(redisError, 'Error occurred while getting the cache from Redis.'); + return fallback; + } + } +} diff --git a/packages/relay/src/lib/clients/index.ts b/packages/relay/src/lib/clients/index.ts index 5a9efcc138..8c398c4c7e 100644 --- a/packages/relay/src/lib/clients/index.ts +++ b/packages/relay/src/lib/clients/index.ts @@ -1,6 +1,6 @@ // SPDX-License-Identifier: Apache-2.0 export * from './cache/localLRUCache'; -export * from './cache/redisCache'; +export * from './cache/redisCache/index'; export * from './mirrorNodeClient'; export * from './sdkClient'; diff --git a/packages/relay/src/lib/factories/cacheClientFactory.ts b/packages/relay/src/lib/factories/cacheClientFactory.ts new file mode 100644 index 0000000000..8cf93ea4b2 --- /dev/null +++ b/packages/relay/src/lib/factories/cacheClientFactory.ts @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: Apache-2.0 + +import { ConfigService } from '@hashgraph/json-rpc-config-service/dist/services'; +import type { Logger } from 'pino'; +import { Registry } from 'prom-client'; +import type { RedisClientType } from 'redis'; + +import { LocalLRUCache, RedisCache } from '../clients'; +import type { ICacheClient } from '../clients/cache/ICacheClient'; + +export class CacheClientFactory { + static create( + logger: Logger, + register: Registry = new Registry(), + reservedKeys: Set = new Set(), + redisClient?: RedisClientType, + ): ICacheClient { + return !ConfigService.get('TEST') && redisClient !== undefined + ? new RedisCache(logger.child({ name: 'redisCache' }), redisClient) + : new LocalLRUCache(logger.child({ name: 'localLRUCache' }), register, reservedKeys); + } +} diff --git a/packages/relay/src/lib/relay.ts b/packages/relay/src/lib/relay.ts index edc61ddd09..b48d9f72ab 100644 --- a/packages/relay/src/lib/relay.ts +++ b/packages/relay/src/lib/relay.ts @@ -19,6 +19,7 @@ import { IPAddressHbarSpendingPlanRepository } from './db/repositories/hbarLimit import { DebugImpl } from './debug'; import { RpcMethodDispatcher } from './dispatcher'; import { EthImpl } from './eth'; +import { CacheClientFactory } from './factories/cacheClientFactory'; import { NetImpl } from './net'; import { CacheService } from './services/cacheService/cacheService'; import HAPIService from './services/hapiService/hapiService'; @@ -284,10 +285,13 @@ export class Relay { // Create CacheService with the connected Redis client (or undefined for LRU-only) this.cacheService = new CacheService( - this.logger.child({ name: 'cache-service' }), + CacheClientFactory.create( + this.logger.child({ name: 'cache-service' }), + this.register, + reservedKeys, + this.redisClient, + ), this.register, - reservedKeys, - this.redisClient, ); // Create spending plan repositories diff --git a/packages/relay/src/lib/services/cacheService/cacheService.ts b/packages/relay/src/lib/services/cacheService/cacheService.ts index 26dcd155a9..56ccce8b4d 100644 --- a/packages/relay/src/lib/services/cacheService/cacheService.ts +++ b/packages/relay/src/lib/services/cacheService/cacheService.ts @@ -1,48 +1,21 @@ // SPDX-License-Identifier: Apache-2.0 import { ConfigService } from '@hashgraph/json-rpc-config-service/dist/services'; -import type { Logger } from 'pino'; import { Counter, Registry } from 'prom-client'; -import { RedisClientType } from 'redis'; -import { LocalLRUCache, RedisCache } from '../../clients'; +import { RedisCache } from '../../clients'; import { ICacheClient } from '../../clients/cache/ICacheClient'; -import { RedisCacheError } from '../../errors/RedisCacheError'; - -export enum CACHE_LEVEL { - L1 = 'L1_CACHE', - L2 = 'L2_CACHE', -} /** * A service that manages caching using different cache implementations based on configuration. */ export class CacheService { /** - * The LRU cache used for caching items from requests. - * - * @private - */ - private readonly internalCache: ICacheClient; - - /** - * The Redis cache used for caching items from requests. + * The cache used for caching items from requests. * * @private */ - private readonly sharedCache: ICacheClient; - - /** - * The logger used for logging all output from this class. - * @private - */ - private readonly logger: Logger; - - /** - * The metrics register used for metrics tracking. - * @private - */ - private readonly register: Registry; + private readonly client: ICacheClient; /** * Used for reference to the state of REDIS_ENABLED and REDIS_URL env. variables. @@ -79,24 +52,10 @@ export class CacheService { private readonly cacheMethodsCounter: Counter; - public constructor( - logger: Logger, - register: Registry = new Registry(), - reservedKeys: Set = new Set(), - redisClient?: RedisClientType, - ) { - this.logger = logger; - this.register = register; - - this.internalCache = new LocalLRUCache(logger.child({ name: 'localLRUCache' }), register, reservedKeys); - this.sharedCache = this.internalCache; - this.isSharedCacheEnabled = !ConfigService.get('TEST') && redisClient !== undefined; - this.shouldMultiSet = ConfigService.get('MULTI_SET'); - - if (this.isSharedCacheEnabled) { - this.sharedCache = new RedisCache(logger.child({ name: 'redisCache' }), register, redisClient!); - } - + public constructor(client: ICacheClient, register: Registry = new Registry()) { + this.client = client; + this.isSharedCacheEnabled = client instanceof RedisCache; // TODO measurements will be moved out of here in the next PR. + this.shouldMultiSet = ConfigService.get('MULTI_SET'); // TODO measurements will be moved out of here in the next PR. /** * Labels: * callingMethod - The method initiating the cache operation @@ -104,7 +63,7 @@ export class CacheService { * method - The CacheService method being called */ const metricName = 'rpc_cache_service_methods_counter'; - this.register.removeSingleMetric(metricName); + register.removeSingleMetric(metricName); this.cacheMethodsCounter = new Counter({ name: metricName, help: 'Counter for calls to methods of CacheService separated by CallingMethod and CacheType', @@ -121,19 +80,11 @@ export class CacheService { * @returns A Promise that resolves with the cached value or null if not found. */ private async getFromSharedCache(key: string, callingMethod: string): Promise { - try { - this.cacheMethodsCounter - .labels(callingMethod, CacheService.cacheTypes.REDIS, CacheService.methods.GET_ASYNC) - .inc(1); - - return await this.sharedCache.get(key, callingMethod); - } catch (error) { - const redisError = new RedisCacheError(error); - this.logger.error(redisError, 'Error occurred while getting the cache from Redis. Fallback to internal cache.'); + this.cacheMethodsCounter + .labels(callingMethod, CacheService.cacheTypes.REDIS, CacheService.methods.GET_ASYNC) + .inc(1); - // fallback to internal cache in case of Redis error - return await this.getFromInternalCache(key, callingMethod); - } + return await this.client.get(key, callingMethod); } /** @@ -161,13 +112,12 @@ export class CacheService { private async getFromInternalCache(key: string, callingMethod: string): Promise { this.cacheMethodsCounter.labels(callingMethod, CacheService.cacheTypes.LRU, CacheService.methods.GET).inc(1); - return await this.internalCache.get(key, callingMethod); + return await this.client.get(key, callingMethod); } /** * Sets a value in the cache associated with the given key. - * If the shared cache is enabled and an error occurs while setting in it, - * the internal cache is used as a fallback. + * * @param key - The key to associate with the value. * @param value - The value to cache. * @param callingMethod - The name of the method calling the cache. @@ -175,52 +125,27 @@ export class CacheService { */ public async set(key: string, value: any, callingMethod: string, ttl?: number): Promise { if (this.isSharedCacheEnabled) { - try { - this.cacheMethodsCounter.labels(callingMethod, CacheService.cacheTypes.REDIS, CacheService.methods.SET).inc(1); - - await this.sharedCache.set(key, value, callingMethod, ttl); - return; - } catch (error) { - const redisError = new RedisCacheError(error); - this.logger.error(redisError, 'Error occurred while setting the cache to Redis. Fallback to internal cache.'); - } + this.cacheMethodsCounter.labels(callingMethod, CacheService.cacheTypes.REDIS, CacheService.methods.SET).inc(1); + } else { + this.cacheMethodsCounter.labels(callingMethod, CacheService.cacheTypes.LRU, CacheService.methods.SET).inc(1); } - - // fallback to internal cache in case of Redis error - this.cacheMethodsCounter.labels(callingMethod, CacheService.cacheTypes.LRU, CacheService.methods.SET).inc(1); - await this.internalCache.set(key, value, callingMethod, ttl); + await this.client.set(key, value, callingMethod, ttl); } /** * Sets multiple values in the cache, each associated with its respective key. - * Depends on env. variable, whether we will be using pipelining method or multiSet - * If the shared cache is enabled and an error occurs while setting in it, - * the internal cache is used as a fallback. * @param entries - An object containing key-value pairs to cache. * @param callingMethod - The name of the method calling the cache. * @param ttl - Time to live for the cached value in milliseconds (optional). */ public async multiSet(entries: Record, callingMethod: string, ttl?: number): Promise { + await this.client.multiSet(entries, callingMethod, ttl); if (this.isSharedCacheEnabled) { const metricsMethod = this.shouldMultiSet ? CacheService.methods.MSET : CacheService.methods.PIPELINE; - try { - if (this.shouldMultiSet) { - await this.sharedCache.multiSet(entries, callingMethod); - } else { - await this.sharedCache.pipelineSet(entries, callingMethod, ttl); - } - - this.cacheMethodsCounter.labels(callingMethod, CacheService.cacheTypes.REDIS, metricsMethod).inc(1); - return; - } catch (error) { - const redisError = new RedisCacheError(error); - this.logger.error(redisError, 'Error occurred while setting the cache to Redis. Fallback to internal cache.'); - } + this.cacheMethodsCounter.labels(callingMethod, CacheService.cacheTypes.REDIS, metricsMethod).inc(1); + } else { + this.cacheMethodsCounter.labels(callingMethod, CacheService.cacheTypes.LRU, CacheService.methods.SET).inc(1); } - - // fallback to internal cache, but use pipeline, because of it's TTL support - await this.internalCache.pipelineSet(entries, callingMethod, ttl); - this.cacheMethodsCounter.labels(callingMethod, CacheService.cacheTypes.LRU, CacheService.methods.SET).inc(1); } /** @@ -232,22 +157,11 @@ export class CacheService { */ public async delete(key: string, callingMethod: string): Promise { if (this.isSharedCacheEnabled) { - try { - this.cacheMethodsCounter - .labels(callingMethod, CacheService.cacheTypes.REDIS, CacheService.methods.DELETE) - .inc(1); - - await this.sharedCache.delete(key, callingMethod); - return; - } catch (error) { - const redisError = new RedisCacheError(error); - this.logger.error(redisError, `Error occurred while deleting cache from Redis.`); - } + this.cacheMethodsCounter.labels(callingMethod, CacheService.cacheTypes.REDIS, CacheService.methods.DELETE).inc(1); + } else { + this.cacheMethodsCounter.labels(callingMethod, CacheService.cacheTypes.LRU, CacheService.methods.DELETE).inc(1); } - - // fallback to internal cache in case of Redis error - this.cacheMethodsCounter.labels(callingMethod, CacheService.cacheTypes.LRU, CacheService.methods.DELETE).inc(1); - await this.internalCache.delete(key, callingMethod); + await this.client.delete(key, callingMethod); } /** @@ -256,18 +170,7 @@ export class CacheService { * Else the internal cache clearing is attempted. */ public async clear(): Promise { - if (this.isSharedCacheEnabled) { - try { - await this.sharedCache.clear(); - return; - } catch (error) { - const redisError = new RedisCacheError(error); - this.logger.error(redisError, `Error occurred while clearing Redis cache.`); - } - } - - // fallback to internal cache in case of Redis error - await this.internalCache.clear(); + await this.client.clear(); } /** @@ -278,31 +181,16 @@ export class CacheService { * @returns A Promise that resolves with the new value of the key after incrementing. */ public async incrBy(key: string, amount: number, callingMethod: string): Promise { - if (this.isSharedCacheEnabled && this.sharedCache instanceof RedisCache) { - try { - this.cacheMethodsCounter - .labels(callingMethod, CacheService.cacheTypes.REDIS, CacheService.methods.INCR_BY) - .inc(1); - - return await this.sharedCache.incrBy(key, amount, callingMethod); - } catch (error) { - const redisError = new RedisCacheError(error); - this.logger.error(redisError, `Error occurred while incrementing cache in Redis.`); - } + if (this.isSharedCacheEnabled) { + this.cacheMethodsCounter + .labels(callingMethod, CacheService.cacheTypes.REDIS, CacheService.methods.INCR_BY) + .inc(1); + } else { + this.cacheMethodsCounter.labels(callingMethod, CacheService.cacheTypes.LRU, CacheService.methods.GET).inc(1); + this.cacheMethodsCounter.labels(callingMethod, CacheService.cacheTypes.LRU, CacheService.methods.SET).inc(1); } - // Fallback to internal cache - const value = await this.getFromInternalCache(key, callingMethod); - const newValue = value + amount; - const remainingTtl = - this.internalCache instanceof LocalLRUCache - ? await this.internalCache.getRemainingTtl(key, callingMethod) - : undefined; - - this.cacheMethodsCounter.labels(callingMethod, CacheService.cacheTypes.LRU, CacheService.methods.SET).inc(1); - await this.internalCache.set(key, newValue, callingMethod, remainingTtl); - - return newValue; + return await this.client.incrBy(key, amount, callingMethod); } /** @@ -313,34 +201,14 @@ export class CacheService { * @returns A Promise that resolves with the new length of the list after pushing. */ public async rPush(key: string, value: any, callingMethod: string): Promise { - if (this.isSharedCacheEnabled && this.sharedCache instanceof RedisCache) { - try { - this.cacheMethodsCounter - .labels(callingMethod, CacheService.cacheTypes.REDIS, CacheService.methods.RPUSH) - .inc(1); - - return await this.sharedCache.rPush(key, value, callingMethod); - } catch (error) { - const redisError = new RedisCacheError(error); - this.logger.error(redisError, `Error occurred while pushing cache in Redis.`); - } - } - - // Fallback to internal cache - const values = (await this.getFromInternalCache(key, callingMethod)) ?? []; - if (!Array.isArray(values)) { - throw new Error(`Value at key ${key} is not an array`); + if (this.isSharedCacheEnabled) { + this.cacheMethodsCounter.labels(callingMethod, CacheService.cacheTypes.REDIS, CacheService.methods.RPUSH).inc(1); + } else { + this.cacheMethodsCounter.labels(callingMethod, CacheService.cacheTypes.LRU, CacheService.methods.GET).inc(1); + this.cacheMethodsCounter.labels(callingMethod, CacheService.cacheTypes.LRU, CacheService.methods.SET).inc(1); } - values.push(value); - const remainingTtl = - this.internalCache instanceof LocalLRUCache - ? await this.internalCache.getRemainingTtl(key, callingMethod) - : undefined; - - this.cacheMethodsCounter.labels(callingMethod, CacheService.cacheTypes.LRU, CacheService.methods.SET).inc(1); - await this.internalCache.set(key, values, callingMethod, remainingTtl); - return values.length; + return await this.client.rPush(key, value, callingMethod); } /** @@ -353,28 +221,12 @@ export class CacheService { * @template T - The type of the values in the list. */ public async lRange(key: string, start: number, end: number, callingMethod: string): Promise { - if (this.isSharedCacheEnabled && this.sharedCache instanceof RedisCache) { - try { - this.cacheMethodsCounter - .labels(callingMethod, CacheService.cacheTypes.REDIS, CacheService.methods.LRANGE) - .inc(1); - - return await this.sharedCache.lRange(key, start, end, callingMethod); - } catch (error) { - const redisError = new RedisCacheError(error); - this.logger.error(redisError, `Error occurred while getting cache in Redis.`); - } - } - - // Fallback to internal cache - const values = (await this.getFromInternalCache(key, callingMethod)) ?? []; - if (!Array.isArray(values)) { - throw new Error(`Value at key ${key} is not an array`); - } - if (end < 0) { - end = values.length + end; + if (this.isSharedCacheEnabled) { + this.cacheMethodsCounter.labels(callingMethod, CacheService.cacheTypes.REDIS, CacheService.methods.LRANGE).inc(1); + } else { + this.cacheMethodsCounter.labels(callingMethod, CacheService.cacheTypes.LRU, CacheService.methods.GET).inc(1); } - return values.slice(start, end + 1); + return await this.client.lRange(key, start, end, callingMethod); } /** @@ -384,16 +236,6 @@ export class CacheService { * @returns A Promise that resolves with an array of keys that match the pattern. */ async keys(pattern: string, callingMethod: string): Promise { - if (this.isSharedCacheEnabled && this.sharedCache instanceof RedisCache) { - try { - return await this.sharedCache.keys(pattern, callingMethod); - } catch (error) { - const redisError = new RedisCacheError(error); - this.logger.error(redisError, `Error occurred while getting keys from Redis.`); - } - } - - // Fallback to internal cache - return this.internalCache.keys(pattern, callingMethod); + return await this.client.keys(pattern, callingMethod); } } diff --git a/packages/relay/tests/lib/clients/localLRUCache.spec.ts b/packages/relay/tests/lib/clients/localLRUCache.spec.ts index 6bc5f7da9f..6ff0aa61cb 100644 --- a/packages/relay/tests/lib/clients/localLRUCache.spec.ts +++ b/packages/relay/tests/lib/clients/localLRUCache.spec.ts @@ -2,7 +2,6 @@ import chai, { expect } from 'chai'; import chaiAsPromised from 'chai-as-promised'; -import pino from 'pino'; import { Registry } from 'prom-client'; import sinon from 'sinon'; @@ -13,8 +12,11 @@ chai.use(chaiAsPromised); describe('LocalLRUCache Test Suite', async function () { this.timeout(10000); - - const logger = pino({ level: 'silent' }); + const logger = { + child: sinon.stub().returnsThis(), + trace: sinon.stub(), + isLevelEnabled: sinon.stub().returns(true), + }; const registry = new Registry(); const callingMethod = 'localLRUCacheTest'; @@ -284,4 +286,98 @@ describe('LocalLRUCache Test Suite', async function () { expect(await localLRUCache.get('number', callingMethod)).to.equal(5644); }); }); + + describe('incrBy', function () { + it('increments an existing integer value', async function () { + const key = 'counter'; + await localLRUCache.set(key, 5, callingMethod); + const newValue = await localLRUCache.incrBy(key, 3, callingMethod); + expect(newValue).to.equal(8); + + const stored = await localLRUCache.get(key, callingMethod); + expect(stored).to.equal(8); + }); + + it('increments when value is zero', async function () { + const key = 'counter'; + await localLRUCache.set(key, 0, callingMethod); + const newValue = await localLRUCache.incrBy(key, 10, callingMethod); + expect(newValue).to.equal(10); + }); + + it('increments when key does not exist', async function () { + await localLRUCache.clear(); + const key = 'missing'; + const newValue = await localLRUCache.incrBy(key, 5, callingMethod); + expect(newValue).to.equal(5); + }); + }); + + describe('lRange', function () { + it('returns the correct range for a valid array', async function () { + const key = 'list'; + const value = [10, 20, 30, 40]; + await localLRUCache.set(key, value, callingMethod); + + const result = await localLRUCache.lRange(key, 1, 2, callingMethod); + expect(result).to.deep.equal([20, 30]); + }); + + it('supports negative end index', async function () { + const key = 'list'; + const value = [10, 20, 30, 40]; + await localLRUCache.set(key, value, callingMethod); + + const result = await localLRUCache.lRange(key, 1, -1, callingMethod); + expect(result).to.deep.equal([20, 30, 40]); + }); + + it('returns empty array when key does not exist', async function () { + const key = 'missing'; + const result = await localLRUCache.lRange(key, 0, 10, callingMethod); + expect(result).to.deep.equal([]); + }); + + it('throws when the value is not an array', async function () { + const key = 'notList'; + await localLRUCache.set(key, 123, callingMethod); + + await expect(localLRUCache.lRange(key, 0, 1, callingMethod)).to.be.rejectedWith( + `Value at key ${key} is not an array`, + ); + }); + }); + + describe('rPush', function () { + it('pushes value to end of an existing list', async function () { + const key = 'list'; + const initial = [1, 2]; + await localLRUCache.set(key, initial, callingMethod); + + const length = await localLRUCache.rPush(key, 3, callingMethod); + expect(length).to.equal(3); + + const stored = await localLRUCache.get(key, callingMethod); + expect(stored).to.deep.equal([1, 2, 3]); + }); + + it('initializes a new list when key does not exist', async function () { + const key = 'missing'; + + const length = await localLRUCache.rPush(key, 'a', callingMethod); + expect(length).to.equal(1); + + const stored = await localLRUCache.get(key, callingMethod); + expect(stored).to.deep.equal(['a']); + }); + + it('throws when existing value is not an array', async function () { + const key = 'wrongType'; + await localLRUCache.set(key, 999, callingMethod); + + await expect(localLRUCache.rPush(key, 'x', callingMethod)).to.be.rejectedWith( + `Value at key ${key} is not an array`, + ); + }); + }); }); diff --git a/packages/relay/tests/lib/clients/redisCache.spec.ts b/packages/relay/tests/lib/clients/redisCache.spec.ts index 882cf7c624..d6794a4f52 100644 --- a/packages/relay/tests/lib/clients/redisCache.spec.ts +++ b/packages/relay/tests/lib/clients/redisCache.spec.ts @@ -3,7 +3,6 @@ import chai, { expect } from 'chai'; import chaiAsPromised from 'chai-as-promised'; import { pino } from 'pino'; -import { Registry } from 'prom-client'; import { RedisClientType } from 'redis'; import sinon from 'sinon'; @@ -16,18 +15,24 @@ chai.use(chaiAsPromised); describe('RedisCache Test Suite', async function () { this.timeout(10000); - const logger = pino({ level: 'silent' }); - const registry = new Registry(); + const mockLogger = { + child: sinon.stub().returnsThis(), + trace: sinon.stub(), + info: sinon.stub(), + isLevelEnabled: sinon.stub().returns(true), + }; const callingMethod = 'RedisCacheTest'; let redisCache: RedisCache; let redisClient: RedisClientType; + const logger = mockLogger.child({ name: 'mock' }); + useInMemoryRedisServer(logger, 6379); this.beforeAll(async () => { redisClient = await RedisClientManager.getClient(logger); - redisCache = new RedisCache(logger.child({ name: `cache` }), registry, redisClient); + redisCache = new RedisCache(logger.child({ name: `cache` }), redisClient); redisCache['options'].ttl = 100; sinon.spy(redisClient, 'set'); }); @@ -163,6 +168,23 @@ describe('RedisCache Test Suite', async function () { expect(cachedValue).deep.equal(keyValuePairs[key]); } }); + + it('should fallback to pipeline set when multiset disabled', async function () { + const keyValuePairs = { + int: 1, + string: 'test', + boolean: false, + array: ['false'], + object: { result: true }, + }; + redisCache['options'].multiSetEnabled = false; + await redisCache.multiSet(keyValuePairs, callingMethod); + + for (const key in keyValuePairs) { + const cachedValue = await redisCache.get(key, callingMethod); + expect(cachedValue).deep.equal(keyValuePairs[key]); + } + }); }); describe('PipelineSet Test Suite', async function () { diff --git a/packages/relay/tests/lib/config/hbarSpendingPlanConfigService.spec.ts b/packages/relay/tests/lib/config/hbarSpendingPlanConfigService.spec.ts index 440db1610e..30763607c2 100644 --- a/packages/relay/tests/lib/config/hbarSpendingPlanConfigService.spec.ts +++ b/packages/relay/tests/lib/config/hbarSpendingPlanConfigService.spec.ts @@ -23,6 +23,7 @@ import { IPAddressHbarSpendingPlanNotFoundError, } from '../../../src/lib/db/types/hbarLimiter/errors'; import { SubscriptionTier } from '../../../src/lib/db/types/hbarLimiter/subscriptionTier'; +import { CacheClientFactory } from '../../../src/lib/factories/cacheClientFactory'; import { CacheService } from '../../../src/lib/services/cacheService/cacheService'; import { SpendingPlanConfig } from '../../../src/lib/types/spendingPlanConfig'; import { @@ -168,10 +169,8 @@ describe('HbarSpendingPlanConfigService', function () { redisClient = undefined; } cacheService = new CacheService( - logger.child({ name: 'cache-service' }), + CacheClientFactory.create(logger.child({ name: 'cache-service' }), registry, reservedKeys, redisClient as any), registry, - reservedKeys, - redisClient as any, ); hbarSpendingPlanRepository = new HbarSpendingPlanRepository( cacheService, diff --git a/packages/relay/tests/lib/eth/eth-helpers.ts b/packages/relay/tests/lib/eth/eth-helpers.ts index d106fdff79..0f12d4fe56 100644 --- a/packages/relay/tests/lib/eth/eth-helpers.ts +++ b/packages/relay/tests/lib/eth/eth-helpers.ts @@ -12,6 +12,7 @@ import { EvmAddressHbarSpendingPlanRepository } from '../../../src/lib/db/reposi import { HbarSpendingPlanRepository } from '../../../src/lib/db/repositories/hbarLimiter/hbarSpendingPlanRepository'; import { IPAddressHbarSpendingPlanRepository } from '../../../src/lib/db/repositories/hbarLimiter/ipAddressHbarSpendingPlanRepository'; import { EthImpl } from '../../../src/lib/eth'; +import { CacheClientFactory } from '../../../src/lib/factories/cacheClientFactory'; import { CommonService } from '../../../src/lib/services'; import { CacheService } from '../../../src/lib/services/cacheService/cacheService'; import HAPIService from '../../../src/lib/services/hapiService/hapiService'; @@ -34,7 +35,7 @@ export function generateEthTestEnv(fixedFeeHistory = false) { ConfigServiceTestHelper.dynamicOverride('ETH_FEE_HISTORY_FIXED', fixedFeeHistory); const logger = pino({ level: 'silent' }); const registry = new Registry(); - const cacheService = new CacheService(logger, registry); + const cacheService = new CacheService(CacheClientFactory.create(logger, registry), registry); const mirrorNodeInstance = new MirrorNodeClient( ConfigService.get('MIRROR_NODE_URL'), logger.child({ name: `mirror-node` }), diff --git a/packages/relay/tests/lib/ethGetBlockBy.spec.ts b/packages/relay/tests/lib/ethGetBlockBy.spec.ts index 1deee3c89f..42d942643e 100644 --- a/packages/relay/tests/lib/ethGetBlockBy.spec.ts +++ b/packages/relay/tests/lib/ethGetBlockBy.spec.ts @@ -12,6 +12,7 @@ import { nanOrNumberTo0x, nullableNumberTo0x, numberTo0x, toHash32 } from '../.. import { MirrorNodeClient } from '../../src/lib/clients'; import constants from '../../src/lib/constants'; import { EthImpl } from '../../src/lib/eth'; +import { CacheClientFactory } from '../../src/lib/factories/cacheClientFactory'; import { Log, Transaction } from '../../src/lib/model'; import { BlockService, CommonService } from '../../src/lib/services'; import { CacheService } from '../../src/lib/services/cacheService/cacheService'; @@ -108,7 +109,10 @@ describe('eth_getBlockBy', async function () { eval: sinon.stub(), quit: sinon.stub().resolves(true), } as any; - cacheService = new CacheService(logger, registry, new Set(), redisClientMock as any); + cacheService = new CacheService( + CacheClientFactory.create(logger, registry, new Set(), redisClientMock as any), + registry, + ); // @ts-ignore mirrorNodeInstance = new MirrorNodeClient( diff --git a/packages/relay/tests/lib/hapiService.spec.ts b/packages/relay/tests/lib/hapiService.spec.ts index 4a5e523bc3..354d95100c 100644 --- a/packages/relay/tests/lib/hapiService.spec.ts +++ b/packages/relay/tests/lib/hapiService.spec.ts @@ -10,6 +10,7 @@ import constants from '../../src/lib/constants'; import { EvmAddressHbarSpendingPlanRepository } from '../../src/lib/db/repositories/hbarLimiter/evmAddressHbarSpendingPlanRepository'; import { HbarSpendingPlanRepository } from '../../src/lib/db/repositories/hbarLimiter/hbarSpendingPlanRepository'; import { IPAddressHbarSpendingPlanRepository } from '../../src/lib/db/repositories/hbarLimiter/ipAddressHbarSpendingPlanRepository'; +import { CacheClientFactory } from '../../src/lib/factories/cacheClientFactory'; import { CacheService } from '../../src/lib/services/cacheService/cacheService'; import HAPIService from '../../src/lib/services/hapiService/hapiService'; import { HbarLimitService } from '../../src/lib/services/hbarLimitService'; @@ -38,7 +39,7 @@ describe('HAPI Service', async function () { this.beforeAll(() => { const duration = constants.HBAR_RATE_LIMIT_DURATION; - cacheService = new CacheService(logger, registry); + cacheService = new CacheService(CacheClientFactory.create(logger, registry), registry); const hbarSpendingPlanRepository = new HbarSpendingPlanRepository(cacheService, logger); const evmAddressHbarSpendingPlanRepository = new EvmAddressHbarSpendingPlanRepository(cacheService, logger); diff --git a/packages/relay/tests/lib/mirrorNodeClient.spec.ts b/packages/relay/tests/lib/mirrorNodeClient.spec.ts index 834e53349b..4498fdef7f 100644 --- a/packages/relay/tests/lib/mirrorNodeClient.spec.ts +++ b/packages/relay/tests/lib/mirrorNodeClient.spec.ts @@ -14,6 +14,7 @@ import { MirrorNodeClientError, predefined } from '../../src'; import { MirrorNodeClient } from '../../src/lib/clients'; import constants from '../../src/lib/constants'; import { SDKClientError } from '../../src/lib/errors/SDKClientError'; +import { CacheClientFactory } from '../../src/lib/factories/cacheClientFactory'; import { CacheService } from '../../src/lib/services/cacheService/cacheService'; import { MirrorNodeTransactionRecord, RequestDetails } from '../../src/lib/types'; import { mockData, random20BytesAddress, withOverriddenEnvsInMochaTest } from '../helpers'; @@ -39,7 +40,7 @@ describe('MirrorNodeClient', async function () { }, timeout: 20 * 1000, }); - cacheService = new CacheService(logger, registry); + cacheService = new CacheService(CacheClientFactory.create(logger, registry), registry); mirrorNodeInstance = new MirrorNodeClient( ConfigService.get('MIRROR_NODE_URL'), logger.child({ name: `mirror-node` }), @@ -51,7 +52,7 @@ describe('MirrorNodeClient', async function () { beforeEach(async () => { mock = new MockAdapter(instance); - await cacheService.clear(requestDetails); + await cacheService.clear(); }); describe('Forwarded Header', () => { diff --git a/packages/relay/tests/lib/openrpc.spec.ts b/packages/relay/tests/lib/openrpc.spec.ts index 0ce03609b2..8d4577d64e 100644 --- a/packages/relay/tests/lib/openrpc.spec.ts +++ b/packages/relay/tests/lib/openrpc.spec.ts @@ -24,6 +24,7 @@ import { EvmAddressHbarSpendingPlanRepository } from '../../src/lib/db/repositor import { HbarSpendingPlanRepository } from '../../src/lib/db/repositories/hbarLimiter/hbarSpendingPlanRepository'; import { IPAddressHbarSpendingPlanRepository } from '../../src/lib/db/repositories/hbarLimiter/ipAddressHbarSpendingPlanRepository'; import { EthImpl } from '../../src/lib/eth'; +import { CacheClientFactory } from '../../src/lib/factories/cacheClientFactory'; import { NetImpl } from '../../src/lib/net'; import { CacheService } from '../../src/lib/services/cacheService/cacheService'; import ClientService from '../../src/lib/services/hapiService/hapiService'; @@ -106,7 +107,7 @@ describe('Open RPC Specification', function () { }); mock = new MockAdapter(instance, { onNoMatch: 'throwException' }); - const cacheService = new CacheService(logger, registry); + const cacheService = new CacheService(CacheClientFactory.create(logger, registry), registry); mirrorNodeInstance = new MirrorNodeClient( ConfigService.get('MIRROR_NODE_URL'), logger.child({ name: `mirror-node` }), diff --git a/packages/relay/tests/lib/precheck.spec.ts b/packages/relay/tests/lib/precheck.spec.ts index 5e1d4ddf00..ef54333ff2 100644 --- a/packages/relay/tests/lib/precheck.spec.ts +++ b/packages/relay/tests/lib/precheck.spec.ts @@ -28,6 +28,7 @@ import { ONE_TINYBAR_IN_WEI_HEX } from './eth/eth-config'; const registry = new Registry(); import sinon from 'sinon'; +import { CacheClientFactory } from '../../src/lib/factories/cacheClientFactory'; import { TransactionPoolService } from '../../src/lib/services/transactionPoolService/transactionPoolService'; import { RequestDetails } from '../../src/lib/types'; @@ -94,7 +95,7 @@ describe('Precheck', async function () { ConfigService.get('MIRROR_NODE_URL')!, logger.child({ name: `mirror-node` }), registry, - new CacheService(logger, registry), + new CacheService(CacheClientFactory.create(logger, registry), registry), instance, ); const transactionPoolService = sinon.createStubInstance(TransactionPoolService); diff --git a/packages/relay/tests/lib/repositories/hbarLimiter/evmAddressHbarSpendingPlanRepository.spec.ts b/packages/relay/tests/lib/repositories/hbarLimiter/evmAddressHbarSpendingPlanRepository.spec.ts index 6137e70300..85c89d75e9 100644 --- a/packages/relay/tests/lib/repositories/hbarLimiter/evmAddressHbarSpendingPlanRepository.spec.ts +++ b/packages/relay/tests/lib/repositories/hbarLimiter/evmAddressHbarSpendingPlanRepository.spec.ts @@ -13,6 +13,7 @@ import { EvmAddressHbarSpendingPlan } from '../../../../src/lib/db/entities/hbar import { EvmAddressHbarSpendingPlanRepository } from '../../../../src/lib/db/repositories/hbarLimiter/evmAddressHbarSpendingPlanRepository'; import { EvmAddressHbarSpendingPlanNotFoundError } from '../../../../src/lib/db/types/hbarLimiter/errors'; import { IEvmAddressHbarSpendingPlan } from '../../../../src/lib/db/types/hbarLimiter/evmAddressHbarSpendingPlan'; +import { CacheClientFactory } from '../../../../src/lib/factories/cacheClientFactory'; import { CacheService } from '../../../../src/lib/services/cacheService/cacheService'; import { overrideEnvsInMochaDescribe, useInMemoryRedisServer } from '../../../helpers'; @@ -41,7 +42,7 @@ describe('@evmAddressHbarSpendingPlanRepository EvmAddressHbarSpendingPlanReposi } else { redisClient = undefined; } - cacheService = new CacheService(logger, registry, new Set(), redisClient); + cacheService = new CacheService(CacheClientFactory.create(logger, registry, new Set(), redisClient), registry); cacheServiceSpy = sinon.spy(cacheService); repository = new EvmAddressHbarSpendingPlanRepository( cacheService, diff --git a/packages/relay/tests/lib/repositories/hbarLimiter/hbarSpendingPlanRepository.spec.ts b/packages/relay/tests/lib/repositories/hbarLimiter/hbarSpendingPlanRepository.spec.ts index d0cdf93d12..9c4f470162 100644 --- a/packages/relay/tests/lib/repositories/hbarLimiter/hbarSpendingPlanRepository.spec.ts +++ b/packages/relay/tests/lib/repositories/hbarLimiter/hbarSpendingPlanRepository.spec.ts @@ -16,6 +16,7 @@ import { import { IDetailedHbarSpendingPlan } from '../../../../src/lib/db/types/hbarLimiter/hbarSpendingPlan'; import { IHbarSpendingRecord } from '../../../../src/lib/db/types/hbarLimiter/hbarSpendingRecord'; import { SubscriptionTier } from '../../../../src/lib/db/types/hbarLimiter/subscriptionTier'; +import { CacheClientFactory } from '../../../../src/lib/factories/cacheClientFactory'; import { CacheService } from '../../../../src/lib/services/cacheService/cacheService'; import { overrideEnvsInMochaDescribe, useInMemoryRedisServer } from '../../../helpers'; @@ -44,7 +45,7 @@ describe('HbarSpendingPlanRepository', function () { } else { redisClient = undefined; } - cacheService = new CacheService(logger, registry, new Set(), redisClient); + cacheService = new CacheService(CacheClientFactory.create(logger, registry, new Set(), redisClient), registry); cacheServiceSpy = sinon.spy(cacheService); repository = new HbarSpendingPlanRepository(cacheService, logger.child({ name: `HbarSpendingPlanRepository` })); }); diff --git a/packages/relay/tests/lib/repositories/hbarLimiter/ipAddressHbarSpendingPlanRepository.spec.ts b/packages/relay/tests/lib/repositories/hbarLimiter/ipAddressHbarSpendingPlanRepository.spec.ts index 89041072c3..49e9d05b28 100644 --- a/packages/relay/tests/lib/repositories/hbarLimiter/ipAddressHbarSpendingPlanRepository.spec.ts +++ b/packages/relay/tests/lib/repositories/hbarLimiter/ipAddressHbarSpendingPlanRepository.spec.ts @@ -12,6 +12,7 @@ import { IPAddressHbarSpendingPlan } from '../../../../src/lib/db/entities/hbarL import { IPAddressHbarSpendingPlanRepository } from '../../../../src/lib/db/repositories/hbarLimiter/ipAddressHbarSpendingPlanRepository'; import { IPAddressHbarSpendingPlanNotFoundError } from '../../../../src/lib/db/types/hbarLimiter/errors'; import { IIPAddressHbarSpendingPlan } from '../../../../src/lib/db/types/hbarLimiter/ipAddressHbarSpendingPlan'; +import { CacheClientFactory } from '../../../../src/lib/factories/cacheClientFactory'; import { CacheService } from '../../../../src/lib/services/cacheService/cacheService'; import { overrideEnvsInMochaDescribe, useInMemoryRedisServer } from '../../../helpers'; @@ -38,7 +39,7 @@ describe('IPAddressHbarSpendingPlanRepository', function () { if (isSharedCacheEnabled) { await RedisClientManager.getClient(logger); } - cacheService = new CacheService(logger, registry); + cacheService = new CacheService(CacheClientFactory.create(logger, registry), registry); cacheServiceSpy = sinon.spy(cacheService); repository = new IPAddressHbarSpendingPlanRepository( cacheService, diff --git a/packages/relay/tests/lib/sdkClient.spec.ts b/packages/relay/tests/lib/sdkClient.spec.ts index b82781391c..673001cce3 100644 --- a/packages/relay/tests/lib/sdkClient.spec.ts +++ b/packages/relay/tests/lib/sdkClient.spec.ts @@ -39,6 +39,7 @@ import { EvmAddressHbarSpendingPlanRepository } from '../../src/lib/db/repositor import { HbarSpendingPlanRepository } from '../../src/lib/db/repositories/hbarLimiter/hbarSpendingPlanRepository'; import { IPAddressHbarSpendingPlanRepository } from '../../src/lib/db/repositories/hbarLimiter/ipAddressHbarSpendingPlanRepository'; import { SDKClientError } from '../../src/lib/errors/SDKClientError'; +import { CacheClientFactory } from '../../src/lib/factories/cacheClientFactory'; import { CacheService } from '../../src/lib/services/cacheService/cacheService'; import HAPIService from '../../src/lib/services/hapiService/hapiService'; import { HbarLimitService } from '../../src/lib/services/hbarLimitService'; @@ -86,7 +87,7 @@ describe('SdkClient', async function () { const hederaNetwork = ConfigService.get('HEDERA_NETWORK')!; const duration = constants.HBAR_RATE_LIMIT_DURATION; - cacheService = new CacheService(logger, registry); + cacheService = new CacheService(CacheClientFactory.create(logger, registry), registry); const hbarSpendingPlanRepository = new HbarSpendingPlanRepository(cacheService, logger); const evmAddressHbarSpendingPlanRepository = new EvmAddressHbarSpendingPlanRepository(cacheService, logger); const ipAddressHbarSpendingPlanRepository = new IPAddressHbarSpendingPlanRepository(cacheService, logger); diff --git a/packages/relay/tests/lib/services/cacheService/cacheService.spec.ts b/packages/relay/tests/lib/services/cacheService/cacheService.spec.ts index af0d656c43..5ac375ebc2 100644 --- a/packages/relay/tests/lib/services/cacheService/cacheService.spec.ts +++ b/packages/relay/tests/lib/services/cacheService/cacheService.spec.ts @@ -9,6 +9,7 @@ import * as sinon from 'sinon'; import { ICacheClient } from '../../../../src/lib/clients/cache/ICacheClient'; import { LocalLRUCache } from '../../../../src/lib/clients/cache/localLRUCache'; import { RedisClientManager } from '../../../../src/lib/clients/redisClientManager'; +import { CacheClientFactory } from '../../../../src/lib/factories/cacheClientFactory'; import { CacheService } from '../../../../src/lib/services/cacheService/cacheService'; import { overrideEnvsInMochaDescribe, useInMemoryRedisServer } from '../../../helpers'; @@ -26,7 +27,7 @@ describe('CacheService Test Suite', async function () { describe('keys', async function () { let internalCacheSpy: sinon.SinonSpiedInstance; before(async () => { - internalCacheSpy = sinon.spy(cacheService['internalCache']); + internalCacheSpy = sinon.spy(cacheService['client']); }); it('should retrieve all keys', async function () { @@ -133,7 +134,7 @@ describe('CacheService Test Suite', async function () { overrideEnvsInMochaDescribe({ REDIS_ENABLED: false }); this.beforeAll(() => { - cacheService = new CacheService(logger, registry); + cacheService = new CacheService(CacheClientFactory.create(logger, registry), registry); }); this.afterEach(async () => { @@ -235,7 +236,7 @@ describe('CacheService Test Suite', async function () { describe('should not initialize redis cache if shared cache is not enabled', async function () { it('should not initialize redis cache if shared cache is not enabled', async function () { - expect(cacheService['sharedCache']).to.be.an.instanceOf(LocalLRUCache); + expect(cacheService['client']).to.be.an.instanceOf(LocalLRUCache); }); }); }); @@ -251,7 +252,10 @@ describe('CacheService Test Suite', async function () { overrideEnvsInMochaDescribe({ MULTI_SET: true }); before(async () => { - cacheService = new CacheService(logger, registry, new Set(), await RedisClientManager.getClient(logger)); + cacheService = new CacheService( + CacheClientFactory.create(logger, registry, new Set(), await RedisClientManager.getClient(logger)), + registry, + ); }); this.beforeEach(async () => { @@ -317,7 +321,7 @@ describe('CacheService Test Suite', async function () { } }); - it('should be able to getAsync from internal cache in case of Redis error', async function () { + it('should be able to ignore getAsync failure in case of Redis error', async function () { const key = 'string'; await RedisClientManager.disconnect(); @@ -325,50 +329,38 @@ describe('CacheService Test Suite', async function () { expect(cachedValue).eq(null); }); - it('should be able to set to internal cache in case of Redis error', async function () { + it('should be able to ignore set failure in case of Redis error', async function () { const key = 'string'; const value = 'value'; await RedisClientManager.disconnect(); await expect(cacheService.set(key, value, callingMethod)).to.eventually.not.be.rejected; - - const internalCacheRes = await cacheService.getAsync(key, callingMethod); - expect(internalCacheRes).to.eq(value); }); - it('should be able to multiSet to internal cache in case of Redis error', async function () { + it('should be able to ignore multiSet failure in case of Redis error', async function () { await RedisClientManager.disconnect(); await expect(cacheService.multiSet(multiSetEntries, callingMethod)).to.eventually.not.be.rejected; - - for (const [key, value] of Object.entries(multiSetEntries)) { - const internalCacheRes = await cacheService.getAsync(key, callingMethod); - expect(internalCacheRes).to.eq(value); - } }); - it('should be able to pipelineSet to internal cache in case of Redis error', async function () { + it('should be able to ignore pipelineSet failure in case of Redis error', async function () { // @ts-ignore cacheService['shouldMultiSet'] = false; await RedisClientManager.disconnect(); await expect(cacheService.multiSet(multiSetEntries, callingMethod)).to.eventually.not.be.rejected; - - for (const [key, value] of Object.entries(multiSetEntries)) { - const internalCacheRes = await cacheService.getAsync(key, callingMethod); - expect(internalCacheRes).to.eq(value); - } }); - it('should be able to clear from internal cache in case of Redis error', async function () { + it('should be able to ignore clear failure in case of Redis error', async function () { await RedisClientManager.disconnect(); + await expect(cacheService.clear()).to.eventually.not.be.rejected; }); - it('should be able to delete from internal cache in case of Redis error', async function () { + it('should be able to ignore delete failure in case of Redis error', async function () { const key = 'string'; await RedisClientManager.disconnect(); @@ -407,16 +399,12 @@ describe('CacheService Test Suite', async function () { expect(newValue).to.equal(15); }); - it('should increment value in internal cache in case of Redis error', async function () { + it('should be able to ignore increment failure in case of Redis error', async function () { const key = 'counter'; const amount = 5; - - await RedisClientManager.disconnect(); - await cacheService.set(key, 10, callingMethod); - const newValue = await cacheService.incrBy(key, amount, callingMethod); - - expect(newValue).to.equal(15); + await RedisClientManager.disconnect(); + await expect(cacheService.incrBy(key, 5, callingMethod)).to.eventually.not.be.rejected; }); }); @@ -431,7 +419,7 @@ describe('CacheService Test Suite', async function () { expect(cachedValue).to.deep.equal([value]); }); - it('should push value to internal cache in case of Redis error', async function () { + it('should not push value in case of Redis error', async function () { const key = 'list'; const value = 'item'; @@ -440,7 +428,7 @@ describe('CacheService Test Suite', async function () { await cacheService.rPush(key, value, callingMethod); const cachedValue = await cacheService.lRange(key, 0, -1, callingMethod); - expect(cachedValue).to.deep.equal([value]); + expect(cachedValue).to.deep.equal([]); }); }); @@ -469,7 +457,7 @@ describe('CacheService Test Suite', async function () { expect(range).to.deep.equal(['item2', 'item3']); }); - it('should retrieve range from internal cache in case of Redis error', async function () { + it('should not retrieve range in case of Redis error', async function () { await RedisClientManager.disconnect(); const key = 'list'; @@ -480,7 +468,7 @@ describe('CacheService Test Suite', async function () { const range = await cacheService.lRange(key, 0, 1, callingMethod); - expect(range).to.deep.equal(['item1', 'item2']); + expect(range).to.deep.equal([]); }); }); diff --git a/packages/relay/tests/lib/services/eth/filter.spec.ts b/packages/relay/tests/lib/services/eth/filter.spec.ts index 6387f649f4..09b418de3a 100644 --- a/packages/relay/tests/lib/services/eth/filter.spec.ts +++ b/packages/relay/tests/lib/services/eth/filter.spec.ts @@ -10,6 +10,7 @@ import { v4 as uuid } from 'uuid'; import { predefined } from '../../../../src'; import { MirrorNodeClient } from '../../../../src/lib/clients'; import constants from '../../../../src/lib/constants'; +import { CacheClientFactory } from '../../../../src/lib/factories/cacheClientFactory'; import { CommonService, FilterService } from '../../../../src/lib/services'; import { CacheService } from '../../../../src/lib/services/cacheService/cacheService'; import { RequestDetails } from '../../../../src/lib/types'; @@ -52,7 +53,7 @@ describe('Filter API Test Suite', async function () { const validateFilterCache = async (filterId: string, expectedFilterType: string, expectedParams = {}) => { const cacheKey = `${constants.CACHE_KEY.FILTERID}_${filterId}`; - const cachedFilter = await cacheService.getAsync(cacheKey, 'validateFilterCache', requestDetails); + const cachedFilter = await cacheService.getAsync(cacheKey, 'validateFilterCache'); expect(cachedFilter).to.exist; expect(cachedFilter.type).to.exist; expect(cachedFilter.type).to.eq(expectedFilterType); @@ -62,7 +63,7 @@ describe('Filter API Test Suite', async function () { }; this.beforeAll(() => { - cacheService = new CacheService(logger, registry); + cacheService = new CacheService(CacheClientFactory.create(logger, registry)); mirrorNodeInstance = new MirrorNodeClient( ConfigService.get('MIRROR_NODE_URL'), logger.child({ name: `mirror-node` }), @@ -83,7 +84,7 @@ describe('Filter API Test Suite', async function () { this.beforeEach(async () => { // reset cache and restMock - await cacheService.clear(requestDetails); + await cacheService.clear(); restMock.reset(); }); @@ -334,17 +335,11 @@ describe('Filter API Test Suite', async function () { describe('eth_uninstallFilter', async function () { it('should return true if filter is deleted', async function () { const cacheKey = `${constants.CACHE_KEY.FILTERID}_${existingFilterId}`; - await cacheService.set( - cacheKey, - filterObject, - filterService.ethUninstallFilter, - requestDetails, - constants.FILTER.TTL, - ); + await cacheService.set(cacheKey, filterObject, filterService.ethUninstallFilter, constants.FILTER.TTL); const result = await filterService.uninstallFilter(existingFilterId, requestDetails); - const isDeleted = !(await cacheService.getAsync(cacheKey, filterService.ethUninstallFilter, requestDetails)); + const isDeleted = !(await cacheService.getAsync(cacheKey, filterService.ethUninstallFilter)); expect(result).to.eq(true); expect(isDeleted).to.eq(true); }); @@ -564,13 +559,7 @@ describe('Filter API Test Suite', async function () { .reply(200, JSON.stringify({ blocks: [] })); const cacheKey = `${constants.CACHE_KEY.FILTERID}_${existingFilterId}`; - await cacheService.set( - cacheKey, - blockFilterObject, - filterService.ethGetFilterChanges, - requestDetails, - constants.FILTER.TTL, - ); + await cacheService.set(cacheKey, blockFilterObject, filterService.ethGetFilterChanges, constants.FILTER.TTL); const result = await filterService.getFilterChanges(existingFilterId, requestDetails); expect(result).to.exist; @@ -603,13 +592,7 @@ describe('Filter API Test Suite', async function () { .reply(200, JSON.stringify({ blocks: [] })); const cacheKey = `${constants.CACHE_KEY.FILTERID}_${existingFilterId}`; - await cacheService.set( - cacheKey, - blockFilterObject, - filterService.ethGetFilterChanges, - requestDetails, - constants.FILTER.TTL, - ); + await cacheService.set(cacheKey, blockFilterObject, filterService.ethGetFilterChanges, constants.FILTER.TTL); const resultCurrentBlock = await filterService.getFilterChanges(existingFilterId, requestDetails); expect(resultCurrentBlock).to.not.be.empty; @@ -673,13 +656,7 @@ describe('Filter API Test Suite', async function () { ); const cacheKey = `${constants.CACHE_KEY.FILTERID}_${existingFilterId}`; - await cacheService.set( - cacheKey, - blockFilterObject, - filterService.ethGetFilterChanges, - requestDetails, - constants.FILTER.TTL, - ); + await cacheService.set(cacheKey, blockFilterObject, filterService.ethGetFilterChanges, constants.FILTER.TTL); const blocks = await filterService.getFilterChanges(existingFilterId, requestDetails); expect(blocks).to.be.empty; @@ -697,7 +674,6 @@ describe('Filter API Test Suite', async function () { lastQueried: null, }, filterService.ethGetFilterChanges, - requestDetails, constants.FILTER.TTL, ); diff --git a/packages/relay/tests/lib/services/hbarLimitService/hbarLimitService.spec.ts b/packages/relay/tests/lib/services/hbarLimitService/hbarLimitService.spec.ts index 25356cf364..9855260839 100644 --- a/packages/relay/tests/lib/services/hbarLimitService/hbarLimitService.spec.ts +++ b/packages/relay/tests/lib/services/hbarLimitService/hbarLimitService.spec.ts @@ -6,6 +6,7 @@ import { AccountId, Hbar } from '@hashgraph/sdk'; import chai, { expect } from 'chai'; import chaiAsPromised from 'chai-as-promised'; import { randomBytes, uuidV4 } from 'ethers'; +import Long from 'long'; import pino, { Logger } from 'pino'; import { Counter, Gauge, Registry } from 'prom-client'; import sinon from 'sinon'; @@ -23,6 +24,7 @@ import { } from '../../../../src/lib/db/types/hbarLimiter/errors'; import { IDetailedHbarSpendingPlan } from '../../../../src/lib/db/types/hbarLimiter/hbarSpendingPlan'; import { SubscriptionTier } from '../../../../src/lib/db/types/hbarLimiter/subscriptionTier'; +import { CacheClientFactory } from '../../../../src/lib/factories/cacheClientFactory'; import { CacheService } from '../../../../src/lib/services/cacheService/cacheService'; import { HbarLimitService } from '../../../../src/lib/services/hbarLimitService'; import { RequestDetails } from '../../../../src/lib/types'; @@ -57,7 +59,7 @@ describe('HBAR Rate Limit Service', function () { let loggerSpy: sinon.SinonSpiedInstance; beforeEach(async function () { - cacheService = new CacheService(logger, register); + cacheService = new CacheService(CacheClientFactory.create(logger, register)); loggerSpy = sinon.spy(logger); hbarSpendingPlanRepository = new HbarSpendingPlanRepository( cacheService, diff --git a/packages/relay/tests/lib/services/metricService/metricService.spec.ts b/packages/relay/tests/lib/services/metricService/metricService.spec.ts index 7450dd27c7..bedadd9cb5 100644 --- a/packages/relay/tests/lib/services/metricService/metricService.spec.ts +++ b/packages/relay/tests/lib/services/metricService/metricService.spec.ts @@ -17,6 +17,7 @@ import constants from '../../../../src/lib/constants'; import { EvmAddressHbarSpendingPlanRepository } from '../../../../src/lib/db/repositories/hbarLimiter/evmAddressHbarSpendingPlanRepository'; import { HbarSpendingPlanRepository } from '../../../../src/lib/db/repositories/hbarLimiter/hbarSpendingPlanRepository'; import { IPAddressHbarSpendingPlanRepository } from '../../../../src/lib/db/repositories/hbarLimiter/ipAddressHbarSpendingPlanRepository'; +import { CacheClientFactory } from '../../../../src/lib/factories/cacheClientFactory'; import { CacheService } from '../../../../src/lib/services/cacheService/cacheService'; import { HbarLimitService } from '../../../../src/lib/services/hbarLimitService'; import MetricService from '../../../../src/lib/services/metricService/metricService'; @@ -135,7 +136,7 @@ describe('Metric Service', function () { ConfigService.get('MIRROR_NODE_URL'), logger.child({ name: `mirror-node` }), registry, - new CacheService(logger, registry), + new CacheService(CacheClientFactory.create(logger, registry)), instance, ); }); @@ -147,7 +148,7 @@ describe('Metric Service', function () { eventEmitter = new EventEmitter(); - const cacheService = new CacheService(logger, registry); + const cacheService = new CacheService(CacheClientFactory.create(logger, registry)); const hbarSpendingPlanRepository = new HbarSpendingPlanRepository(cacheService, logger); const evmAddressHbarSpendingPlanRepository = new EvmAddressHbarSpendingPlanRepository(cacheService, logger); const ipAddressHbarSpendingPlanRepository = new IPAddressHbarSpendingPlanRepository(cacheService, logger); diff --git a/packages/server/tests/acceptance/cacheService.spec.ts b/packages/server/tests/acceptance/cacheService.spec.ts index 6ea4240f12..5acd6d5fce 100644 --- a/packages/server/tests/acceptance/cacheService.spec.ts +++ b/packages/server/tests/acceptance/cacheService.spec.ts @@ -2,6 +2,7 @@ import { ConfigService } from '@hashgraph/json-rpc-config-service/dist/services'; import { RedisCache } from '@hashgraph/json-rpc-relay/dist/lib/clients/cache/redisCache'; +import { CacheClientFactory } from '@hashgraph/json-rpc-relay/dist/lib/factories/cacheClientFactory'; import { CacheService } from '@hashgraph/json-rpc-relay/dist/lib/services/cacheService/cacheService'; import { RedisClientManager } from '@hashgraph/json-rpc-relay/src/lib/clients/redisClientManager'; import { expect } from 'chai'; @@ -24,16 +25,18 @@ describe('@cache-service Acceptance Tests for shared cache', function () { before(async () => { logger = pino({ level: 'silent' }); + redisClient = await RedisClientManager.getClient(logger); - cacheService = new CacheService(logger, undefined, undefined, redisClient); + cacheService = new CacheService(CacheClientFactory.create(logger, undefined, undefined, redisClient)); + await new Promise((r) => setTimeout(r, 1000)); }); it('Correctly performs set, get and delete operations', async () => { const dataLabel = `${DATA_LABEL_PREFIX}1`; - const setSharedCacheSpy = sinon.spy(cacheService['sharedCache'], 'set'); - const getSharedCacheSpy = sinon.spy(cacheService['sharedCache'], 'get'); - const deleteSharedCacheSpy = sinon.spy(cacheService['sharedCache'], 'delete'); + const setSharedCacheSpy = sinon.spy(cacheService['client'], 'set'); + const getSharedCacheSpy = sinon.spy(cacheService['client'], 'get'); + const deleteSharedCacheSpy = sinon.spy(cacheService['client'], 'delete'); await cacheService.set(dataLabel, DATA, CALLING_METHOD); await new Promise((r) => setTimeout(r, 200)); @@ -41,7 +44,7 @@ describe('@cache-service Acceptance Tests for shared cache', function () { expect(cache).to.deep.eq(DATA, 'set method saves to shared cache'); expect(cacheService['isSharedCacheEnabled']).to.be.true; - expect(cacheService['sharedCache']).to.be.instanceOf(RedisCache); + expect(cacheService['client']).to.be.instanceOf(RedisCache); const cacheFromService = await cacheService.getAsync(dataLabel, CALLING_METHOD); expect(cacheFromService).to.deep.eq(DATA, 'getAsync method reads correctly from shared cache'); @@ -83,7 +86,7 @@ describe('@cache-service Acceptance Tests for shared cache', function () { it('Falls back to local cache for REDIS_ENABLED !== true', async () => { const dataLabel = `${DATA_LABEL_PREFIX}3`; - const serviceWithDisabledRedis = new CacheService(logger); + const serviceWithDisabledRedis = new CacheService(CacheClientFactory.create(logger)); const isRedisEnabled = ConfigService.get('REDIS_ENABLED') && !!ConfigService.get('REDIS_URL'); await new Promise((r) => setTimeout(r, 1000)); expect(isRedisEnabled).to.eq(false); @@ -97,7 +100,7 @@ describe('@cache-service Acceptance Tests for shared cache', function () { it('Cache set by one instance can be accessed by another', async () => { const dataLabel = `${DATA_LABEL_PREFIX}4`; - const otherServiceInstance = new CacheService(logger, undefined, undefined, redisClient); + const otherServiceInstance = new CacheService(CacheClientFactory.create(logger, undefined, undefined, redisClient)); await cacheService.set(dataLabel, DATA, CALLING_METHOD); await new Promise((r) => setTimeout(r, 200)); @@ -116,12 +119,12 @@ describe('@cache-service Acceptance Tests for shared cache', function () { await new Promise((r) => setTimeout(r, 1000)); }); - it('tests fallback of getAsync operation', async () => { + it('tests missing fallback of getAsync operation', async () => { await cacheService.set(dataLabel, DATA, CALLING_METHOD); await new Promise((r) => setTimeout(r, 200)); const dataInLRU = await cacheService.getAsync(dataLabel, CALLING_METHOD); - expect(dataInLRU).to.deep.eq(DATA, 'data is stored in local cache'); + expect(dataInLRU).to.be.null; }); it('test multiSet operation', async () => { @@ -136,7 +139,7 @@ describe('@cache-service Acceptance Tests for shared cache', function () { for (const key in pairs) { const cachedValue = await cacheService.getAsync(key, CALLING_METHOD); - expect(cachedValue).deep.equal(pairs[key]); + expect(cachedValue).to.be.null; } }); @@ -148,5 +151,14 @@ describe('@cache-service Acceptance Tests for shared cache', function () { const dataInLRU = await cacheService.getAsync(dataLabel, CALLING_METHOD); expect(dataInLRU).to.be.null; }); + + it('test clear operation', async () => { + await cacheService.set(dataLabel, DATA, CALLING_METHOD); + await new Promise((r) => setTimeout(r, 200)); + + await cacheService.clear(); + const dataInLRU = await cacheService.getAsync(dataLabel, CALLING_METHOD); + expect(dataInLRU).to.be.null; + }); }); }); diff --git a/packages/server/tests/acceptance/hbarLimiter.spec.ts b/packages/server/tests/acceptance/hbarLimiter.spec.ts index 1450e29d2b..be70bc1252 100644 --- a/packages/server/tests/acceptance/hbarLimiter.spec.ts +++ b/packages/server/tests/acceptance/hbarLimiter.spec.ts @@ -24,6 +24,7 @@ import { Logger } from 'pino'; import { Registry } from 'prom-client'; import { RedisClientType } from 'redis'; +import { CacheClientFactory } from '../../../relay/src/lib/factories/cacheClientFactory'; import MetricsClient from '../clients/metricsClient'; import MirrorClient from '../clients/mirrorClient'; import RelayClient from '../clients/relayClient'; @@ -86,7 +87,10 @@ describe('@hbarlimiter HBAR Limiter Acceptance Tests', function () { const register = new Registry(); const reservedKeys = HbarSpendingPlanConfigService.getPreconfiguredSpendingPlanKeys(logger); - cacheService = new CacheService(logger.child({ name: 'cache-service' }), register, reservedKeys, redisClient); + cacheService = new CacheService( + CacheClientFactory.create(logger.child({ name: 'cache-service' }), register, reservedKeys, redisClient), + register, + ); evmAddressSpendingPlanRepository = new EvmAddressHbarSpendingPlanRepository(cacheService, logger); ipSpendingPlanRepository = new IPAddressHbarSpendingPlanRepository(cacheService, logger); From aaa082dd25596f1e541134232d8d3f216c846f51 Mon Sep 17 00:00:00 2001 From: jasuwienas Date: Fri, 5 Dec 2025 17:35:20 +0100 Subject: [PATCH 09/12] test: migrate koa version from v2 to v3 (#4505) (#4613) Signed-off-by: Mariusz Jasuwienas --- package-lock.json | 707 +++++++++++------- package.json | 2 - packages/server/package.json | 6 +- packages/server/src/server.ts | 2 +- .../server/tests/integration/server.spec.ts | 21 +- packages/ws-server/package.json | 5 +- 6 files changed, 442 insertions(+), 301 deletions(-) diff --git a/package-lock.json b/package-lock.json index cb5ddad3c8..08248fd63a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,7 +11,6 @@ "@ethereumjs/rlp": "^10.0.0", "@ethereumjs/trie": "^6.2.1", "@ethereumjs/util": "^9.1.0", - "koa-cors": "^0.0.16", "koa-websocket": "^7.0.0", "lerna": "^9.0.0", "pino": "^10.1.0", @@ -27,7 +26,6 @@ "@types/chai-as-promised": "^8.0.2", "@types/co-body": "6.1.3", "@types/find-config": "^1.0.4", - "@types/koa-cors": "^0.0.6", "@types/lodash": "^4.17.7", "@types/sinon": "^17.0.4", "@typescript-eslint/eslint-plugin": "^8.44.1", @@ -2991,7 +2989,6 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/@koa/cors/-/cors-5.0.0.tgz", "integrity": "sha512-x/iUDjcS90W69PryLDIMgFyV21YLTnG9zOpPXS7Bkt2b8AsY3zZsIpOLBkYr9fBcF3HbkKaER5hOBZLfpLgYNw==", - "dev": true, "license": "MIT", "dependencies": { "vary": "^1.1.2" @@ -5424,19 +5421,20 @@ "@types/node": "*" } }, - "node_modules/@types/koa-compose": { - "version": "3.2.8", - "resolved": "https://registry.npmjs.org/@types/koa-compose/-/koa-compose-3.2.8.tgz", - "integrity": "sha512-4Olc63RY+MKvxMwVknCUDhRQX1pFQoBZ/lXcRLP69PQkEpze/0cr8LNqJQe5NFb/b19DWi2a5bTi2VAlQzhJuA==", + "node_modules/@types/koa__cors": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@types/koa__cors/-/koa__cors-5.0.1.tgz", + "integrity": "sha512-xZckuh3B6ycSBAIYnBImG1VDHyBNZsltGAuGb4THuZllccdLgD5DUs4RA7TAUjB58THg00SSZ1e//duQef7WRw==", "dev": true, + "license": "MIT", "dependencies": { "@types/koa": "*" } }, - "node_modules/@types/koa-cors": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/@types/koa-cors/-/koa-cors-0.0.6.tgz", - "integrity": "sha512-JGT9/jtFahFfmZ9YmzM/TTpkc+Bw7ZLQUCvn2sFyZXi7DI4nd4noAmyha6i2nThHvVVBfh+V9OhVwPTpVAls6A==", + "node_modules/@types/koa-compose": { + "version": "3.2.8", + "resolved": "https://registry.npmjs.org/@types/koa-compose/-/koa-compose-3.2.8.tgz", + "integrity": "sha512-4Olc63RY+MKvxMwVknCUDhRQX1pFQoBZ/lXcRLP69PQkEpze/0cr8LNqJQe5NFb/b19DWi2a5bTi2VAlQzhJuA==", "dev": true, "dependencies": { "@types/koa": "*" @@ -7009,19 +7007,6 @@ "node": ">=18" } }, - "node_modules/cache-content-type": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/cache-content-type/-/cache-content-type-1.0.1.tgz", - "integrity": "sha512-IKufZ1o4Ut42YUrZSo8+qnMTrFuKkvyoLXUywKz9GJ5BrhOFGhLdkx9sG4KAnVvbY6kEcSFjLQul+DVmBm2bgA==", - "license": "MIT", - "dependencies": { - "mime-types": "^2.1.18", - "ylru": "^1.2.0" - }, - "engines": { - "node": ">= 6.0.0" - } - }, "node_modules/call-bind": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", @@ -7047,22 +7032,6 @@ "node": ">= 0.4" } }, - "node_modules/call-bound": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.3.tgz", - "integrity": "sha512-YTd+6wGlNlPxSuri7Y6X8tY2dmm12UMH66RpKMhiX6rsk5wXXnYgbUcOt8kiS31/AjfoTOvCsE+w8nZQLQnzHA==", - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.1", - "get-intrinsic": "^1.2.6" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/caller-callsite": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz", @@ -8353,6 +8322,7 @@ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", "license": "MIT", + "peer": true, "engines": { "node": ">= 0.8" } @@ -10536,24 +10506,6 @@ "node": ">=8" } }, - "node_modules/is-generator-function": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.0.tgz", - "integrity": "sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ==", - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "get-proto": "^1.0.0", - "has-tostringtag": "^1.0.2", - "safe-regex-test": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-glob": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", @@ -10597,24 +10549,6 @@ "node": ">=0.10.0" } }, - "node_modules/is-regex": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", - "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "gopd": "^1.2.0", - "has-tostringtag": "^1.0.2", - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-retry-allowed": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-2.2.0.tgz", @@ -11554,63 +11488,11 @@ "node": ">=0.10.0" } }, - "node_modules/koa": { - "version": "2.16.1", - "resolved": "https://registry.npmjs.org/koa/-/koa-2.16.1.tgz", - "integrity": "sha512-umfX9d3iuSxTQP4pnzLOz0HKnPg0FaUUIKcye2lOiz3KPu1Y3M3xlz76dISdFPQs37P9eJz1wUpcTS6KDPn9fA==", - "license": "MIT", - "dependencies": { - "accepts": "^1.3.5", - "cache-content-type": "^1.0.0", - "content-disposition": "~0.5.2", - "content-type": "^1.0.4", - "cookies": "~0.9.0", - "debug": "^4.3.2", - "delegates": "^1.0.0", - "depd": "^2.0.0", - "destroy": "^1.0.4", - "encodeurl": "^1.0.2", - "escape-html": "^1.0.3", - "fresh": "~0.5.2", - "http-assert": "^1.3.0", - "http-errors": "^1.6.3", - "is-generator-function": "^1.0.7", - "koa-compose": "^4.1.0", - "koa-convert": "^2.0.0", - "on-finished": "^2.3.0", - "only": "~0.0.2", - "parseurl": "^1.3.2", - "statuses": "^1.5.0", - "type-is": "^1.6.16", - "vary": "^1.1.2" - }, - "engines": { - "node": "^4.8.4 || ^6.10.1 || ^7.10.1 || >= 8.1.4" - } - }, "node_modules/koa-compose": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/koa-compose/-/koa-compose-4.1.0.tgz", "integrity": "sha512-8ODW8TrDuMYvXRwra/Kh7/rJo9BtOfPc6qO8eAfC80CnCvSjSl0bkRM24X6/XBBEyj0v1nRUQ1LyOy3dbqOWXw==" }, - "node_modules/koa-convert": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/koa-convert/-/koa-convert-2.0.0.tgz", - "integrity": "sha512-asOvN6bFlSnxewce2e/DK3p4tltyfC4VM7ZwuTuepI7dEQVcvpyFuBcEARu1+Hxg8DIwytce2n7jrZtRlPrARA==", - "license": "MIT", - "dependencies": { - "co": "^4.6.0", - "koa-compose": "^4.1.0" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/koa-cors": { - "version": "0.0.16", - "resolved": "https://registry.npmjs.org/koa-cors/-/koa-cors-0.0.16.tgz", - "integrity": "sha512-s15knPxe3AJBi2I/ZMPL0pSqU+PLYLO6k5tI0AqClkzavowvocPlSdFUwaHNqtjHMhsGmiq2tiX/25iILJx9YA==" - }, "node_modules/koa-websocket": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/koa-websocket/-/koa-websocket-7.0.0.tgz", @@ -14906,11 +14788,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/only": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/only/-/only-0.0.2.tgz", - "integrity": "sha512-Fvw+Jemq5fjjyWz6CpKx6w9s7xxqo3+JCyM0WXWeCSOboZ8ABkyvP8ID4CZuChA/wxSx+XSJmdOm8rGVyJ1hdQ==" - }, "node_modules/open": { "version": "8.4.2", "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", @@ -17180,23 +17057,6 @@ } ] }, - "node_modules/safe-regex-test": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", - "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "is-regex": "^1.2.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/safe-stable-stringify": { "version": "2.4.3", "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.3.tgz", @@ -19140,15 +19000,6 @@ "fd-slicer": "~1.1.0" } }, - "node_modules/ylru": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/ylru/-/ylru-1.4.0.tgz", - "integrity": "sha512-2OQsPNEmBCvXuFlIni/a+Rn+R2pHW9INm0BxXJ4hVDA8TirqMj+J/Rp9ItLatT/5pZqWwefVrTQcHpixsxnVlA==", - "license": "MIT", - "engines": { - "node": ">= 4.0.0" - } - }, "node_modules/yn": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", @@ -19554,19 +19405,19 @@ "dependencies": { "@hashgraph/json-rpc-config-service": "file:../config-service", "@hashgraph/json-rpc-relay": "file:../relay", + "@koa/cors": "^5.0.0", "co-body": "6.2.0", "dotenv": "^17.2.1", - "koa": "^2.13.4", - "koa-cors": "^0.0.16", + "koa": "^3.0.1", "pino": "^10.1.0", "pino-pretty": "^7.6.1", "uuid": "^13.0.0" }, "devDependencies": { "@hashgraph/sdk": "^2.63.0", - "@koa/cors": "^5.0.0", "@types/chai": "^4.3.0", "@types/cors": "^2.8.12", + "@types/koa__cors": "^5.0.1", "@types/mocha": "^10.0.10", "@types/node": "^24.9.1", "@types/uuid": "^10.0.0", @@ -19779,6 +19630,99 @@ "node": "*" } }, + "packages/server/node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "packages/server/node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "license": "MIT", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "packages/server/node_modules/http-errors/node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "packages/server/node_modules/koa": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/koa/-/koa-3.1.1.tgz", + "integrity": "sha512-KDDuvpfqSK0ZKEO2gCPedNjl5wYpfj+HNiuVRlbhd1A88S3M0ySkdf2V/EJ4NWt5dwh5PXCdcenrKK2IQJAxsg==", + "license": "MIT", + "dependencies": { + "accepts": "^1.3.8", + "content-disposition": "~0.5.4", + "content-type": "^1.0.5", + "cookies": "~0.9.1", + "delegates": "^1.0.0", + "destroy": "^1.2.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "fresh": "~0.5.2", + "http-assert": "^1.5.0", + "http-errors": "^2.0.0", + "koa-compose": "^4.1.0", + "mime-types": "^3.0.1", + "on-finished": "^2.4.1", + "parseurl": "^1.3.3", + "statuses": "^2.0.1", + "type-is": "^2.0.1", + "vary": "^1.1.2" + }, + "engines": { + "node": ">= 18" + } + }, + "packages/server/node_modules/media-typer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", + "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "packages/server/node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "packages/server/node_modules/mime-types": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz", + "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==", + "license": "MIT", + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">= 0.6" + } + }, "packages/server/node_modules/on-exit-leak-free": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/on-exit-leak-free/-/on-exit-leak-free-2.1.2.tgz", @@ -19861,6 +19805,29 @@ "node": ">= 10.x" } }, + "packages/server/node_modules/statuses": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "packages/server/node_modules/type-is": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz", + "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==", + "license": "MIT", + "dependencies": { + "content-type": "^1.0.5", + "media-typer": "^1.1.0", + "mime-types": "^3.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, "packages/ws-server": { "name": "@hashgraph/json-rpc-ws-server", "version": "0.74.0-SNAPSHOT", @@ -19868,10 +19835,10 @@ "@hashgraph/json-rpc-config-service": "file:../config-service", "@hashgraph/json-rpc-relay": "file:../relay", "@hashgraph/json-rpc-server": "file:../server", + "@koa/cors": "^5.0.0", "co-body": "6.2.0", "dotenv": "^17.2.1", - "koa": "^2.13.4", - "koa-cors": "^0.0.16", + "koa": "^3.0.1", "koa-websocket": "^7.0.0", "lru-cache": "^11.1.0", "pino": "^10.1.0", @@ -19879,7 +19846,6 @@ }, "devDependencies": { "@hashgraph/sdk": "^2.63.0", - "@koa/cors": "^5.0.0", "@types/chai": "^4.3.0", "@types/cors": "^2.8.12", "@types/mocha": "^10.0.10", @@ -20092,6 +20058,99 @@ "node": "*" } }, + "packages/ws-server/node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "packages/ws-server/node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "license": "MIT", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "packages/ws-server/node_modules/http-errors/node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "packages/ws-server/node_modules/koa": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/koa/-/koa-3.1.1.tgz", + "integrity": "sha512-KDDuvpfqSK0ZKEO2gCPedNjl5wYpfj+HNiuVRlbhd1A88S3M0ySkdf2V/EJ4NWt5dwh5PXCdcenrKK2IQJAxsg==", + "license": "MIT", + "dependencies": { + "accepts": "^1.3.8", + "content-disposition": "~0.5.4", + "content-type": "^1.0.5", + "cookies": "~0.9.1", + "delegates": "^1.0.0", + "destroy": "^1.2.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "fresh": "~0.5.2", + "http-assert": "^1.5.0", + "http-errors": "^2.0.0", + "koa-compose": "^4.1.0", + "mime-types": "^3.0.1", + "on-finished": "^2.4.1", + "parseurl": "^1.3.3", + "statuses": "^2.0.1", + "type-is": "^2.0.1", + "vary": "^1.1.2" + }, + "engines": { + "node": ">= 18" + } + }, + "packages/ws-server/node_modules/media-typer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", + "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "packages/ws-server/node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "packages/ws-server/node_modules/mime-types": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz", + "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==", + "license": "MIT", + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">= 0.6" + } + }, "packages/ws-server/node_modules/on-exit-leak-free": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/on-exit-leak-free/-/on-exit-leak-free-2.1.2.tgz", @@ -20173,6 +20232,29 @@ "engines": { "node": ">= 10.x" } + }, + "packages/ws-server/node_modules/statuses": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "packages/ws-server/node_modules/type-is": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz", + "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==", + "license": "MIT", + "dependencies": { + "content-type": "^1.0.5", + "media-typer": "^1.1.0", + "mime-types": "^3.0.0" + }, + "engines": { + "node": ">= 0.6" + } } }, "dependencies": { @@ -21543,6 +21625,7 @@ "@koa/cors": "^5.0.0", "@types/chai": "^4.3.0", "@types/cors": "^2.8.12", + "@types/koa__cors": "^5.0.1", "@types/mocha": "^10.0.10", "@types/node": "^24.9.1", "@types/uuid": "^10.0.0", @@ -21553,8 +21636,7 @@ "dotenv": "^17.2.1", "ethers": "^6.15.0", "execution-apis": "git://github.com/ethereum/execution-apis.git#7907424db935b93c2fe6a3c0faab943adebe8557", - "koa": "^2.13.4", - "koa-cors": "^0.0.16", + "koa": "^3.0.1", "mocha": "^11.7.1", "pino": "^10.1.0", "pino-pretty": "^7.6.1", @@ -21709,6 +21791,73 @@ "integrity": "sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==", "dev": true }, + "encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==" + }, + "http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "requires": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "dependencies": { + "statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==" + } + } + }, + "koa": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/koa/-/koa-3.1.1.tgz", + "integrity": "sha512-KDDuvpfqSK0ZKEO2gCPedNjl5wYpfj+HNiuVRlbhd1A88S3M0ySkdf2V/EJ4NWt5dwh5PXCdcenrKK2IQJAxsg==", + "requires": { + "accepts": "^1.3.8", + "content-disposition": "~0.5.4", + "content-type": "^1.0.5", + "cookies": "~0.9.1", + "delegates": "^1.0.0", + "destroy": "^1.2.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "fresh": "~0.5.2", + "http-assert": "^1.5.0", + "http-errors": "^2.0.0", + "koa-compose": "^4.1.0", + "mime-types": "^3.0.1", + "on-finished": "^2.4.1", + "parseurl": "^1.3.3", + "statuses": "^2.0.1", + "type-is": "^2.0.1", + "vary": "^1.1.2" + } + }, + "media-typer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", + "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==" + }, + "mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==" + }, + "mime-types": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz", + "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==", + "requires": { + "mime-db": "^1.54.0" + } + }, "on-exit-leak-free": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/on-exit-leak-free/-/on-exit-leak-free-2.1.2.tgz", @@ -21764,6 +21913,21 @@ "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", "dev": true + }, + "statuses": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==" + }, + "type-is": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz", + "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==", + "requires": { + "content-type": "^1.0.5", + "media-typer": "^1.1.0", + "mime-types": "^3.0.0" + } } } }, @@ -21785,8 +21949,7 @@ "co-body": "6.2.0", "dotenv": "^17.2.1", "ethers": "^6.15.0", - "koa": "^2.13.4", - "koa-cors": "^0.0.16", + "koa": "^3.0.1", "koa-websocket": "^7.0.0", "lru-cache": "^11.1.0", "mocha": "^11.7.1", @@ -21942,6 +22105,73 @@ "integrity": "sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==", "dev": true }, + "encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==" + }, + "http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "requires": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "dependencies": { + "statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==" + } + } + }, + "koa": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/koa/-/koa-3.1.1.tgz", + "integrity": "sha512-KDDuvpfqSK0ZKEO2gCPedNjl5wYpfj+HNiuVRlbhd1A88S3M0ySkdf2V/EJ4NWt5dwh5PXCdcenrKK2IQJAxsg==", + "requires": { + "accepts": "^1.3.8", + "content-disposition": "~0.5.4", + "content-type": "^1.0.5", + "cookies": "~0.9.1", + "delegates": "^1.0.0", + "destroy": "^1.2.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "fresh": "~0.5.2", + "http-assert": "^1.5.0", + "http-errors": "^2.0.0", + "koa-compose": "^4.1.0", + "mime-types": "^3.0.1", + "on-finished": "^2.4.1", + "parseurl": "^1.3.3", + "statuses": "^2.0.1", + "type-is": "^2.0.1", + "vary": "^1.1.2" + } + }, + "media-typer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", + "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==" + }, + "mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==" + }, + "mime-types": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz", + "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==", + "requires": { + "mime-db": "^1.54.0" + } + }, "on-exit-leak-free": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/on-exit-leak-free/-/on-exit-leak-free-2.1.2.tgz", @@ -21997,6 +22227,21 @@ "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", "dev": true + }, + "statuses": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==" + }, + "type-is": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz", + "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==", + "requires": { + "content-type": "^1.0.5", + "media-typer": "^1.1.0", + "mime-types": "^3.0.0" + } } } }, @@ -22829,7 +23074,6 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/@koa/cors/-/cors-5.0.0.tgz", "integrity": "sha512-x/iUDjcS90W69PryLDIMgFyV21YLTnG9zOpPXS7Bkt2b8AsY3zZsIpOLBkYr9fBcF3HbkKaER5hOBZLfpLgYNw==", - "dev": true, "requires": { "vary": "^1.1.2" } @@ -24653,19 +24897,19 @@ "@types/node": "*" } }, - "@types/koa-compose": { - "version": "3.2.8", - "resolved": "https://registry.npmjs.org/@types/koa-compose/-/koa-compose-3.2.8.tgz", - "integrity": "sha512-4Olc63RY+MKvxMwVknCUDhRQX1pFQoBZ/lXcRLP69PQkEpze/0cr8LNqJQe5NFb/b19DWi2a5bTi2VAlQzhJuA==", + "@types/koa__cors": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@types/koa__cors/-/koa__cors-5.0.1.tgz", + "integrity": "sha512-xZckuh3B6ycSBAIYnBImG1VDHyBNZsltGAuGb4THuZllccdLgD5DUs4RA7TAUjB58THg00SSZ1e//duQef7WRw==", "dev": true, "requires": { "@types/koa": "*" } }, - "@types/koa-cors": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/@types/koa-cors/-/koa-cors-0.0.6.tgz", - "integrity": "sha512-JGT9/jtFahFfmZ9YmzM/TTpkc+Bw7ZLQUCvn2sFyZXi7DI4nd4noAmyha6i2nThHvVVBfh+V9OhVwPTpVAls6A==", + "@types/koa-compose": { + "version": "3.2.8", + "resolved": "https://registry.npmjs.org/@types/koa-compose/-/koa-compose-3.2.8.tgz", + "integrity": "sha512-4Olc63RY+MKvxMwVknCUDhRQX1pFQoBZ/lXcRLP69PQkEpze/0cr8LNqJQe5NFb/b19DWi2a5bTi2VAlQzhJuA==", "dev": true, "requires": { "@types/koa": "*" @@ -25791,15 +26035,6 @@ } } }, - "cache-content-type": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/cache-content-type/-/cache-content-type-1.0.1.tgz", - "integrity": "sha512-IKufZ1o4Ut42YUrZSo8+qnMTrFuKkvyoLXUywKz9GJ5BrhOFGhLdkx9sG4KAnVvbY6kEcSFjLQul+DVmBm2bgA==", - "requires": { - "mime-types": "^2.1.18", - "ylru": "^1.2.0" - } - }, "call-bind": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", @@ -25818,15 +26053,6 @@ "function-bind": "^1.1.2" } }, - "call-bound": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.3.tgz", - "integrity": "sha512-YTd+6wGlNlPxSuri7Y6X8tY2dmm12UMH66RpKMhiX6rsk5wXXnYgbUcOt8kiS31/AjfoTOvCsE+w8nZQLQnzHA==", - "requires": { - "call-bind-apply-helpers": "^1.0.1", - "get-intrinsic": "^1.2.6" - } - }, "caller-callsite": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz", @@ -26723,7 +26949,8 @@ "encodeurl": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==" + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "peer": true }, "encoding": { "version": "0.1.13", @@ -28236,17 +28463,6 @@ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" }, - "is-generator-function": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.0.tgz", - "integrity": "sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ==", - "requires": { - "call-bound": "^1.0.3", - "get-proto": "^1.0.0", - "has-tostringtag": "^1.0.2", - "safe-regex-test": "^1.1.0" - } - }, "is-glob": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", @@ -28275,17 +28491,6 @@ "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", "integrity": "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==" }, - "is-regex": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", - "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", - "requires": { - "call-bound": "^1.0.2", - "gopd": "^1.2.0", - "has-tostringtag": "^1.0.2", - "hasown": "^2.0.2" - } - }, "is-retry-allowed": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-2.2.0.tgz", @@ -28955,55 +29160,11 @@ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==" }, - "koa": { - "version": "2.16.1", - "resolved": "https://registry.npmjs.org/koa/-/koa-2.16.1.tgz", - "integrity": "sha512-umfX9d3iuSxTQP4pnzLOz0HKnPg0FaUUIKcye2lOiz3KPu1Y3M3xlz76dISdFPQs37P9eJz1wUpcTS6KDPn9fA==", - "requires": { - "accepts": "^1.3.5", - "cache-content-type": "^1.0.0", - "content-disposition": "~0.5.2", - "content-type": "^1.0.4", - "cookies": "~0.9.0", - "debug": "^4.3.2", - "delegates": "^1.0.0", - "depd": "^2.0.0", - "destroy": "^1.0.4", - "encodeurl": "^1.0.2", - "escape-html": "^1.0.3", - "fresh": "~0.5.2", - "http-assert": "^1.3.0", - "http-errors": "^1.6.3", - "is-generator-function": "^1.0.7", - "koa-compose": "^4.1.0", - "koa-convert": "^2.0.0", - "on-finished": "^2.3.0", - "only": "~0.0.2", - "parseurl": "^1.3.2", - "statuses": "^1.5.0", - "type-is": "^1.6.16", - "vary": "^1.1.2" - } - }, "koa-compose": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/koa-compose/-/koa-compose-4.1.0.tgz", "integrity": "sha512-8ODW8TrDuMYvXRwra/Kh7/rJo9BtOfPc6qO8eAfC80CnCvSjSl0bkRM24X6/XBBEyj0v1nRUQ1LyOy3dbqOWXw==" }, - "koa-convert": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/koa-convert/-/koa-convert-2.0.0.tgz", - "integrity": "sha512-asOvN6bFlSnxewce2e/DK3p4tltyfC4VM7ZwuTuepI7dEQVcvpyFuBcEARu1+Hxg8DIwytce2n7jrZtRlPrARA==", - "requires": { - "co": "^4.6.0", - "koa-compose": "^4.1.0" - } - }, - "koa-cors": { - "version": "0.0.16", - "resolved": "https://registry.npmjs.org/koa-cors/-/koa-cors-0.0.16.tgz", - "integrity": "sha512-s15knPxe3AJBi2I/ZMPL0pSqU+PLYLO6k5tI0AqClkzavowvocPlSdFUwaHNqtjHMhsGmiq2tiX/25iILJx9YA==" - }, "koa-websocket": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/koa-websocket/-/koa-websocket-7.0.0.tgz", @@ -31419,11 +31580,6 @@ "mimic-fn": "^2.1.0" } }, - "only": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/only/-/only-0.0.2.tgz", - "integrity": "sha512-Fvw+Jemq5fjjyWz6CpKx6w9s7xxqo3+JCyM0WXWeCSOboZ8ABkyvP8ID4CZuChA/wxSx+XSJmdOm8rGVyJ1hdQ==" - }, "open": { "version": "8.4.2", "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", @@ -33028,16 +33184,6 @@ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" }, - "safe-regex-test": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", - "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", - "requires": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "is-regex": "^1.2.1" - } - }, "safe-stable-stringify": { "version": "2.4.3", "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.3.tgz", @@ -34452,11 +34598,6 @@ "fd-slicer": "~1.1.0" } }, - "ylru": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/ylru/-/ylru-1.4.0.tgz", - "integrity": "sha512-2OQsPNEmBCvXuFlIni/a+Rn+R2pHW9INm0BxXJ4hVDA8TirqMj+J/Rp9ItLatT/5pZqWwefVrTQcHpixsxnVlA==" - }, "yn": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", diff --git a/package.json b/package.json index fec4c97981..99a8618f60 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,6 @@ "@types/chai-as-promised": "^8.0.2", "@types/co-body": "6.1.3", "@types/find-config": "^1.0.4", - "@types/koa-cors": "^0.0.6", "@types/lodash": "^4.17.7", "@types/sinon": "^17.0.4", "@typescript-eslint/eslint-plugin": "^8.44.1", @@ -91,7 +90,6 @@ "@ethereumjs/rlp": "^10.0.0", "@ethereumjs/trie": "^6.2.1", "@ethereumjs/util": "^9.1.0", - "koa-cors": "^0.0.16", "koa-websocket": "^7.0.0", "lerna": "^9.0.0", "pino": "^10.1.0", diff --git a/packages/server/package.json b/packages/server/package.json index 927e2de132..111bac1127 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -8,19 +8,19 @@ "dependencies": { "@hashgraph/json-rpc-config-service": "file:../config-service", "@hashgraph/json-rpc-relay": "file:../relay", + "@koa/cors": "^5.0.0", "co-body": "6.2.0", "dotenv": "^17.2.1", - "koa": "^2.13.4", - "koa-cors": "^0.0.16", + "koa": "^3.0.1", "pino": "^10.1.0", "pino-pretty": "^7.6.1", "uuid": "^13.0.0" }, "devDependencies": { "@hashgraph/sdk": "^2.63.0", - "@koa/cors": "^5.0.0", "@types/chai": "^4.3.0", "@types/cors": "^2.8.12", + "@types/koa__cors": "^5.0.1", "@types/mocha": "^10.0.10", "@types/node": "^24.9.1", "@types/uuid": "^10.0.0", diff --git a/packages/server/src/server.ts b/packages/server/src/server.ts index 570880b3ff..cbb02249d8 100644 --- a/packages/server/src/server.ts +++ b/packages/server/src/server.ts @@ -5,8 +5,8 @@ import { AsyncLocalStorage } from 'node:async_hooks'; import { ConfigService } from '@hashgraph/json-rpc-config-service/dist/services'; import { Relay } from '@hashgraph/json-rpc-relay/dist'; import { RedisClientManager } from '@hashgraph/json-rpc-relay/dist/lib/clients/redisClientManager'; +import cors from '@koa/cors'; import fs from 'fs'; -import cors from 'koa-cors'; import path from 'path'; import pino from 'pino'; import { collectDefaultMetrics, Histogram, Registry } from 'prom-client'; diff --git a/packages/server/tests/integration/server.spec.ts b/packages/server/tests/integration/server.spec.ts index 7db403a096..66840c5fc1 100644 --- a/packages/server/tests/integration/server.spec.ts +++ b/packages/server/tests/integration/server.spec.ts @@ -91,9 +91,20 @@ describe('RPC Server', function () { describe('HTTP Endpoints', function () { it('should execute HTTP OPTIONS cors preflight check', async function () { - const response = await testClient.options('/'); + const config = { headers: { 'Access-Control-Request-Method': 'POST' } }; + const response = await testClient.options('/', config); BaseTest.validResponseCheck(response, { status: 204, statusText: 'No Content' }); + + expect( + response.headers, + "Preflight response: headers should have 'access-control-allow-methods' property", + ).to.have.property('access-control-allow-methods'); + expect( + response.headers['access-control-allow-methods'], + "Preflight response: 'headers[access-control-allow-methods]' should equal 'GET,HEAD,PUT,POST,DELETE,PATCH'", + ).to.be.equal('GET,HEAD,PUT,POST,DELETE,PATCH'); + BaseTest.validCorsCheck(response); }); @@ -3339,14 +3350,6 @@ class BaseTest { response.headers['access-control-allow-origin'], "Default response: 'headers[access-control-allow-origin]' should equal '*'", ).to.be.equal('*'); - expect( - response.headers, - "Default response: headers should have 'access-control-allow-methods' property", - ).to.have.property('access-control-allow-methods'); - expect( - response.headers['access-control-allow-methods'], - "Default response: 'headers[access-control-allow-methods]' should equal 'GET,HEAD,PUT,POST,DELETE'", - ).to.be.equal('GET,HEAD,PUT,POST,DELETE'); } static defaultResponseChecks(response) { diff --git a/packages/ws-server/package.json b/packages/ws-server/package.json index 10b2e81350..21ab0c4ec0 100644 --- a/packages/ws-server/package.json +++ b/packages/ws-server/package.json @@ -9,10 +9,10 @@ "@hashgraph/json-rpc-config-service": "file:../config-service", "@hashgraph/json-rpc-relay": "file:../relay", "@hashgraph/json-rpc-server": "file:../server", + "@koa/cors": "^5.0.0", "co-body": "6.2.0", "dotenv": "^17.2.1", - "koa": "^2.13.4", - "koa-cors": "^0.0.16", + "koa": "^3.0.1", "koa-websocket": "^7.0.0", "lru-cache": "^11.1.0", "pino": "^10.1.0", @@ -20,7 +20,6 @@ }, "devDependencies": { "@hashgraph/sdk": "^2.63.0", - "@koa/cors": "^5.0.0", "@types/chai": "^4.3.0", "@types/cors": "^2.8.12", "@types/mocha": "^10.0.10", From 11129b03372873ba36761313d5547b4bab008b35 Mon Sep 17 00:00:00 2001 From: jasuwienas Date: Fri, 5 Dec 2025 17:35:39 +0100 Subject: [PATCH 10/12] test: stabilize tests by adjusting time waiting for mine and price tolerance (#4658) (#4661) Signed-off-by: Mariusz Jasuwienas --- packages/server/tests/acceptance/hbarLimiter.spec.ts | 1 + packages/server/tests/acceptance/rpc_batch1.spec.ts | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/server/tests/acceptance/hbarLimiter.spec.ts b/packages/server/tests/acceptance/hbarLimiter.spec.ts index be70bc1252..c643605571 100644 --- a/packages/server/tests/acceptance/hbarLimiter.spec.ts +++ b/packages/server/tests/acceptance/hbarLimiter.spec.ts @@ -334,6 +334,7 @@ describe('@hbarlimiter HBAR Limiter Acceptance Tests', function () { }); it('should deploy a large contract and decrease remaining HBAR in limiter when transaction data is large', async function () { + overrideEnvsInMochaDescribe({ TEST_TRANSACTION_RECORD_COST_TOLERANCE: 0.25 }); const initialRemainingHbars = Number(await metrics.get(testConstants.METRICS.REMAINING_HBAR_LIMIT)); expect(initialRemainingHbars).to.be.gt(0); diff --git a/packages/server/tests/acceptance/rpc_batch1.spec.ts b/packages/server/tests/acceptance/rpc_batch1.spec.ts index b3f18bc55c..86d3af8504 100644 --- a/packages/server/tests/acceptance/rpc_batch1.spec.ts +++ b/packages/server/tests/acceptance/rpc_batch1.spec.ts @@ -688,7 +688,7 @@ describe('@api-batch-1 RPC Server Acceptance Tests', function () { it('should not cache "latest" block in "eth_getBlockByNumber" ', async function () { const blockResult = await relay.call(RelayCalls.ETH_ENDPOINTS.ETH_GET_BLOCK_BY_NUMBER, ['latest', false]); - await Utils.wait(1000); + await Utils.wait(2000); const blockResult2 = await relay.call(RelayCalls.ETH_ENDPOINTS.ETH_GET_BLOCK_BY_NUMBER, ['latest', false]); expect(blockResult).to.not.deep.equal(blockResult2); @@ -696,7 +696,7 @@ describe('@api-batch-1 RPC Server Acceptance Tests', function () { it('should not cache "finalized" block in "eth_getBlockByNumber" ', async function () { const blockResult = await relay.call(RelayCalls.ETH_ENDPOINTS.ETH_GET_BLOCK_BY_NUMBER, ['finalized', false]); - await Utils.wait(1000); + await Utils.wait(2000); const blockResult2 = await relay.call(RelayCalls.ETH_ENDPOINTS.ETH_GET_BLOCK_BY_NUMBER, ['finalized', false]); expect(blockResult).to.not.deep.equal(blockResult2); @@ -704,7 +704,7 @@ describe('@api-batch-1 RPC Server Acceptance Tests', function () { it('should not cache "safe" block in "eth_getBlockByNumber" ', async function () { const blockResult = await relay.call(RelayCalls.ETH_ENDPOINTS.ETH_GET_BLOCK_BY_NUMBER, ['safe', false]); - await Utils.wait(1000); + await Utils.wait(2000); const blockResult2 = await relay.call(RelayCalls.ETH_ENDPOINTS.ETH_GET_BLOCK_BY_NUMBER, ['safe', false]); expect(blockResult).to.not.deep.equal(blockResult2); @@ -712,7 +712,7 @@ describe('@api-batch-1 RPC Server Acceptance Tests', function () { it('should not cache "pending" block in "eth_getBlockByNumber" ', async function () { const blockResult = await relay.call(RelayCalls.ETH_ENDPOINTS.ETH_GET_BLOCK_BY_NUMBER, ['pending', false]); - await Utils.wait(1000); + await Utils.wait(2000); const blockResult2 = await relay.call(RelayCalls.ETH_ENDPOINTS.ETH_GET_BLOCK_BY_NUMBER, ['pending', false]); expect(blockResult).to.not.deep.equal(blockResult2); From 75f8196a6c6e9b1675ac4d54a09dd2517d1bf1dc Mon Sep 17 00:00:00 2001 From: jasuwienas Date: Fri, 5 Dec 2025 17:36:42 +0100 Subject: [PATCH 11/12] feat: fail when sending a transaction with non empty acess list (#4651) Signed-off-by: Mariusz Jasuwienas --- packages/relay/src/lib/precheck.ts | 9 ++++ packages/relay/tests/lib/precheck.spec.ts | 18 ++++++++ .../sendRawTransactionExtension.spec.ts | 44 +++++++++++++++++++ 3 files changed, 71 insertions(+) diff --git a/packages/relay/src/lib/precheck.ts b/packages/relay/src/lib/precheck.ts index bc63166833..aabcaa99cb 100644 --- a/packages/relay/src/lib/precheck.ts +++ b/packages/relay/src/lib/precheck.ts @@ -77,6 +77,7 @@ export class Precheck { mirrorAccountInfo.ethereum_nonce + (await this.transactionPoolService.getPendingCount(parsedTx.from!)); this.nonce(parsedTx, signerNonce); this.balance(parsedTx, mirrorAccountInfo.balance); + this.accessList(parsedTx); await this.receiverAccount(parsedTx, requestDetails); } @@ -214,6 +215,14 @@ export class Precheck { } } + /** + * Checks if the value of the access was not set. + * @param tx - The transaction. + */ + accessList(tx: Transaction): void { + if (tx.accessList?.length) throw predefined.NOT_YET_IMPLEMENTED; + } + /** * Calculates the intrinsic gas cost based on the number of bytes in the data field. * Using a loop that goes through every two characters in the string it counts the zero and non-zero bytes. diff --git a/packages/relay/tests/lib/precheck.spec.ts b/packages/relay/tests/lib/precheck.spec.ts index ef54333ff2..53fddd40f3 100644 --- a/packages/relay/tests/lib/precheck.spec.ts +++ b/packages/relay/tests/lib/precheck.spec.ts @@ -926,4 +926,22 @@ describe('Precheck', async function () { ); }); }); + + describe('accessList', async function () { + it('should successfully parse a valid transaction string with empty access list', function () { + parsedTxWithMatchingChainId.accessList = []; + precheck.accessList(parsedTxWithMatchingChainId); + expect(parsedTxWithMatchingChainId.accessList).to.be.empty; + }); + + it('should throw NOT_YET_IMPLEMENTED for non-empty access list', function () { + parsedTxWithMatchingChainId.accessList = [ + { + address: '0x67D8d32E9Bf1a9968a5ff53B87d777Aa8EBBEe69', + storageKeys: [], + }, + ]; + expect(() => precheck.accessList(parsedTxWithMatchingChainId)).to.throw('Not yet implemented'); + }); + }); }); diff --git a/packages/server/tests/acceptance/sendRawTransactionExtension.spec.ts b/packages/server/tests/acceptance/sendRawTransactionExtension.spec.ts index bca01434c0..f5200c8a43 100644 --- a/packages/server/tests/acceptance/sendRawTransactionExtension.spec.ts +++ b/packages/server/tests/acceptance/sendRawTransactionExtension.spec.ts @@ -97,6 +97,50 @@ describe('@sendRawTransactionExtension Acceptance Tests', function () { }); }); + describe('accessList', function () { + it('should fail when calling "eth_sendRawTransaction" with non-empty access list', async function () { + const gasPrice = await relay.gasPrice(); + const transaction = { + type: 2, + chainId: Number(CHAIN_ID), + nonce: await relay.getAccountNonce(accounts[1].address), + maxPriorityFeePerGas: gasPrice, + maxFeePerGas: gasPrice, + gasLimit: defaultGasLimit, + accessList: [ + { + address: '0x67D8d32E9Bf1a9968a5ff53B87d777Aa8EBBEe69', + storageKeys: [], + }, + ], + to: accounts[0].address, + }; + + const signedTx = await accounts[1].wallet.signTransaction(transaction); + await expect(relay.sendRawTransaction(signedTx)).to.eventually.be.rejected; + }); + + it('should succeed when calling "eth_sendRawTransaction" with an empty access list', async function () { + const gasPrice = await relay.gasPrice(); + const transaction = { + type: 2, + chainId: Number(CHAIN_ID), + nonce: await relay.getAccountNonce(accounts[1].address), + maxPriorityFeePerGas: gasPrice, + maxFeePerGas: gasPrice, + gasLimit: defaultGasLimit, + accessList: [], + to: accounts[0].address, + }; + const signedTx = await accounts[1].wallet.signTransaction(transaction); + const transactionHash = await relay.sendRawTransaction(signedTx); + await relay.pollForValidTransactionReceipt(transactionHash); + + const info = await mirrorNode.get(`/contracts/results/${transactionHash}`); + expect(info).to.exist; + }); + }); + describe('callDataSize', function () { it('@release should execute "eth_sendRawTransaction" with regular transaction size within the CALL_DATA_SIZE_LIMIT - 128kb limit', async function () { const gasPrice = await relay.gasPrice(); From 8336fbec6acdf8d4017c4bec11756aee34f877e4 Mon Sep 17 00:00:00 2001 From: Mariusz Jasuwienas Date: Fri, 5 Dec 2025 18:31:57 +0100 Subject: [PATCH 12/12] feat: move cache measurements to dedicated decorator (#4558) Signed-off-by: Mariusz Jasuwienas --- docs/testing-guide.md | 10 +- .../src/lib/clients/cache/ICacheClient.ts | 5 + .../src/lib/clients/cache/localLRUCache.ts | 13 + .../src/lib/clients/cache/measurableCache.ts | 174 +++++++++++++ .../clients/cache/redisCache/redisCache.ts | 13 + .../cache/redisCache/safeRedisCache.ts | 13 + packages/relay/src/lib/clients/index.ts | 1 + .../src/lib/factories/cacheClientFactory.ts | 27 +- packages/relay/src/lib/relay.ts | 11 +- .../lib/services/cacheService/cacheService.ts | 239 +----------------- .../hbarSpendingPlanConfigService.spec.ts | 6 +- packages/relay/tests/lib/eth/eth-helpers.ts | 3 +- .../relay/tests/lib/ethGetBlockBy.spec.ts | 5 +- packages/relay/tests/lib/hapiService.spec.ts | 2 +- .../relay/tests/lib/mirrorNodeClient.spec.ts | 2 +- packages/relay/tests/lib/openrpc.spec.ts | 3 +- packages/relay/tests/lib/precheck.spec.ts | 3 +- packages/relay/tests/lib/relay.spec.ts | 3 - ...mAddressHbarSpendingPlanRepository.spec.ts | 2 +- .../hbarSpendingPlanRepository.spec.ts | 2 +- ...pAddressHbarSpendingPlanRepository.spec.ts | 2 +- packages/relay/tests/lib/sdkClient.spec.ts | 2 +- .../cacheService/cacheService.spec.ts | 13 +- .../tests/lib/services/eth/filter.spec.ts | 2 +- .../hbarLimitService/hbarLimitService.spec.ts | 2 +- .../metricService/metricService.spec.ts | 5 +- .../tests/acceptance/cacheService.spec.ts | 15 +- .../tests/acceptance/hbarLimiter.spec.ts | 6 +- .../server/tests/integration/server.spec.ts | 7 +- 29 files changed, 293 insertions(+), 298 deletions(-) create mode 100644 packages/relay/src/lib/clients/cache/measurableCache.ts diff --git a/docs/testing-guide.md b/docs/testing-guide.md index c88efe845a..35bf564771 100644 --- a/docs/testing-guide.md +++ b/docs/testing-guide.md @@ -156,6 +156,7 @@ import chaiAsPromised from 'chai-as-promised'; import sinon from 'sinon'; import { MyClass } from './my-class'; import { CacheService } from './cache-service'; +import { CacheClientFactory } from './cacheClientFactory'; chai.use(chaiAsPromised); @@ -165,7 +166,7 @@ describe('MyClass', function() { beforeEach(function() { // Common setup for all tests - cacheService = new CacheService(); + cacheService = CacheClientFactory.create(); myClass = new MyClass(cacheService); }); @@ -229,7 +230,7 @@ describe('MyClass', function() { }); }); }); - + describe('anotherMethod', () => { // Tests for anotherMethod // Use analogous formatting to the tests for myMethod @@ -268,6 +269,9 @@ import sinon from 'sinon'; import pino from 'pino'; import { overrideEnvsInMochaDescribe, useInMemoryRedisServer, withOverriddenEnvsInMochaTest } from './helpers'; +import { CacheService } from './cache-service'; +import { CacheClientFactory } from './cacheClientFactory'; + chai.use(chaiAsPromised); describe('MyClass', function() { @@ -289,7 +293,7 @@ describe('MyClass', function() { beforeEach(function() { // Common setup for all tests serviceThatDependsOnEnv = new ServiceThatDependsOnEnv(); - cacheService = new CacheService(); + cacheService = CacheClientFactory.create(); myClass = new MyClass(serviceThatDependsOnEnv, cacheService); }); diff --git a/packages/relay/src/lib/clients/cache/ICacheClient.ts b/packages/relay/src/lib/clients/cache/ICacheClient.ts index a8028bc41b..505071b980 100644 --- a/packages/relay/src/lib/clients/cache/ICacheClient.ts +++ b/packages/relay/src/lib/clients/cache/ICacheClient.ts @@ -11,4 +11,9 @@ export interface ICacheClient { incrBy(key: string, amount: number, callingMethod: string): Promise; rPush(key: string, value: any, callingMethod: string): Promise; lRange(key: string, start: number, end: number, callingMethod: string): Promise; + + /** + * @deprecated Alias of `get`; consider removing. Left in place to avoid modifying the CacheService interface. + */ + getAsync(key: string, callingMethod: string): Promise; } diff --git a/packages/relay/src/lib/clients/cache/localLRUCache.ts b/packages/relay/src/lib/clients/cache/localLRUCache.ts index b58f6917af..6bb6787d9c 100644 --- a/packages/relay/src/lib/clients/cache/localLRUCache.ts +++ b/packages/relay/src/lib/clients/cache/localLRUCache.ts @@ -110,6 +110,19 @@ export class LocalLRUCache implements ICacheClient { return `${LocalLRUCache.CACHE_KEY_PREFIX}${key}`; } + /** + * Alias for the `get` method. + * + * @param key - The key associated with the cached value. + * @param callingMethod - The name of the method calling the cache. + * @returns The cached value if found, otherwise null. + * + * @deprecated use `get` instead. + */ + public getAsync(key: string, callingMethod: string): Promise { + return this.get(key, callingMethod); + } + /** * Retrieves a cached value associated with the given key. * If the value exists in the cache, updates metrics and logs the retrieval. diff --git a/packages/relay/src/lib/clients/cache/measurableCache.ts b/packages/relay/src/lib/clients/cache/measurableCache.ts new file mode 100644 index 0000000000..364f0586e3 --- /dev/null +++ b/packages/relay/src/lib/clients/cache/measurableCache.ts @@ -0,0 +1,174 @@ +// SPDX-License-Identifier: Apache-2.0 + +import { Counter } from 'prom-client'; + +import { ICacheClient } from './ICacheClient'; + +/** + * Represents a cache client that performs the caching operations and tracks and counts all processed events. + * + * @implements {ICacheClient} + */ +export class MeasurableCache implements ICacheClient { + private decorated: ICacheClient; + private readonly cacheMethodsCounter: Counter; + + public static readonly methods = { + GET: 'get', + SET: 'set', + DELETE: 'delete', + MSET: 'mSet', + PIPELINE: 'pipeline', + INCR_BY: 'incrBy', + RPUSH: 'rpush', + LRANGE: 'lrange', + }; + + private cacheType: string; + + public constructor(decorated: ICacheClient, cacheMethodsCounter: Counter, cacheType: string) { + this.decorated = decorated; + this.cacheMethodsCounter = cacheMethodsCounter; + this.cacheType = cacheType; + } + + /** + * Alias for the `get` method. + * + * @param key - The key associated with the cached value. + * @param callingMethod - The name of the method calling the cache. + * @returns The cached value if found, otherwise null. + * + * @deprecated use `get` instead. + */ + public getAsync(key: string, callingMethod: string): Promise { + return this.decorated.get(key, callingMethod); + } + + /** + * Calls the method that retrieves a cached value associated with the given key + * and tracks how many times this event occurs. + * + * @param key - The key associated with the cached value. + * @param callingMethod - The name of the method calling the cache. + * @returns The cached value if found, otherwise null. + */ + public async get(key: string, callingMethod: string): Promise { + this.cacheMethodsCounter.labels(callingMethod, this.cacheType, MeasurableCache.methods.GET).inc(1); + return await this.decorated.get(key, callingMethod); + } + + /** + * Calls the method that sets a value in the cache for the given key + * and tracks how many times this event occurs. + * + * @param key - The key to associate with the value. + * @param value - The value to cache. + * @param callingMethod - The name of the method calling the cache. + * @param ttl - Time to live for the cached value in milliseconds (optional). + */ + public async set(key: string, value: any, callingMethod: string, ttl?: number): Promise { + this.cacheMethodsCounter.labels(callingMethod, this.cacheType, MeasurableCache.methods.SET).inc(1); + return await this.decorated.set(key, value, callingMethod, ttl); + } + + /** + * Calls the method that stores multiple key–value pairs in the cache + * and tracks how many times this event occurs. + * + * @param keyValuePairs - An object where each property is a key and its value is the value to be cached. + * @param callingMethod - The name of the calling method. + * @param ttl - Time to live on the set values + * @returns A Promise that resolves when the values are cached. + */ + public async multiSet(keyValuePairs: Record, callingMethod: string, ttl?: number): Promise { + this.cacheMethodsCounter.labels(callingMethod, this.cacheType, MeasurableCache.methods.MSET).inc(1); + await this.decorated.multiSet(keyValuePairs, callingMethod, ttl); + } + + /** + * Calls the pipelineSet method that stores multiple key–value pairs in the cache + * and tracks how many times this event occurs. + * + * @param keyValuePairs - An object where each property is a key and its value is the value to be cached. + * @param callingMethod - The name of the calling method. + * @param ttl - Time to live on the set values + * @returns A Promise that resolves when the values are cached. + */ + public async pipelineSet(keyValuePairs: Record, callingMethod: string, ttl?: number): Promise { + this.cacheMethodsCounter.labels(callingMethod, this.cacheType, MeasurableCache.methods.PIPELINE).inc(1); + await this.decorated.pipelineSet(keyValuePairs, callingMethod, ttl); + } + + /** + * Calls the method that deletes the cached value associated with the given key + * and tracks how many times this event occurs. + * + * @param key - The key associated with the cached value to delete. + * @param callingMethod - The name of the method calling the cache. + */ + public async delete(key: string, callingMethod: string): Promise { + this.cacheMethodsCounter.labels(callingMethod, this.cacheType, MeasurableCache.methods.DELETE).inc(1); + await this.decorated.delete(key, callingMethod); + } + + /** + * Calls the method that clears the entire cache, removing all entries. + */ + public async clear(): Promise { + await this.decorated.clear(); + } + + /** + * Call the method that retrieves all keys in the cache that match the given pattern. + * + * @param pattern - The pattern to match keys against. + * @param callingMethod - The name of the method calling the cache. + * @returns An array of keys that match the pattern (without the cache prefix). + */ + public async keys(pattern: string, callingMethod: string): Promise { + return await this.decorated.keys(pattern, callingMethod); + } + + /** + * Calls the method that increments a cached value and tracks how many times this event occurs. + * + * @param key The key to increment + * @param amount The amount to increment by + * @param callingMethod The name of the calling method + * @returns The value of the key after incrementing + */ + public async incrBy(key: string, amount: number, callingMethod: string): Promise { + this.cacheMethodsCounter.labels(callingMethod, this.cacheType, MeasurableCache.methods.INCR_BY).inc(1); + return await this.decorated.incrBy(key, amount, callingMethod); + } + + /** + * Calls the method that retrieves a range of elements from a list in the cache + * and tracks how many times this event occurs. + * + * @param key The key of the list + * @param start The start index + * @param end The end index + * @param callingMethod The name of the calling method + * @returns The list of elements in the range + */ + public async lRange(key: string, start: number, end: number, callingMethod: string): Promise { + this.cacheMethodsCounter.labels(callingMethod, this.cacheType, MeasurableCache.methods.LRANGE).inc(1); + return await this.decorated.lRange(key, start, end, callingMethod); + } + + /** + * Calls the method that pushes a value to the end of a list in the cache + * and tracks how many times this event occurs. + * + * @param key The key of the list + * @param value The value to push + * @param callingMethod The name of the calling method + * @returns The length of the list after pushing + */ + public async rPush(key: string, value: any, callingMethod: string): Promise { + this.cacheMethodsCounter.labels(callingMethod, this.cacheType, MeasurableCache.methods.RPUSH).inc(1); + return await this.decorated.rPush(key, value, callingMethod); + } +} diff --git a/packages/relay/src/lib/clients/cache/redisCache/redisCache.ts b/packages/relay/src/lib/clients/cache/redisCache/redisCache.ts index 1f88a97774..fb25a6c297 100644 --- a/packages/relay/src/lib/clients/cache/redisCache/redisCache.ts +++ b/packages/relay/src/lib/clients/cache/redisCache/redisCache.ts @@ -65,6 +65,19 @@ export class RedisCache implements ICacheClient { return `${RedisCache.CACHE_KEY_PREFIX}${key}`; } + /** + * Alias for the `get` method. + * + * @param key - The key associated with the cached value. + * @param callingMethod - The name of the method calling the cache. + * @returns The cached value if found, otherwise null. + * + * @deprecated use `get` instead. + */ + public getAsync(key: string, callingMethod: string): Promise { + return this.get(key, callingMethod); + } + /** * Retrieves a value from the cache. * diff --git a/packages/relay/src/lib/clients/cache/redisCache/safeRedisCache.ts b/packages/relay/src/lib/clients/cache/redisCache/safeRedisCache.ts index db948af7be..aa08e8d32c 100644 --- a/packages/relay/src/lib/clients/cache/redisCache/safeRedisCache.ts +++ b/packages/relay/src/lib/clients/cache/redisCache/safeRedisCache.ts @@ -12,6 +12,19 @@ import { RedisCache } from './redisCache'; * Thanks to that our application will be able to continue functioning even with Redis being down... */ export class SafeRedisCache extends RedisCache { + /** + * Alias for the `get` method. + * + * @param key - The key associated with the cached value. + * @param callingMethod - The name of the method calling the cache. + * @returns The cached value if found, otherwise null. + * + * @deprecated use `get` instead. + */ + public getAsync(key: string, callingMethod: string): Promise { + return this.get(key, callingMethod); + } + /** * Retrieves a value from the cache. * diff --git a/packages/relay/src/lib/clients/index.ts b/packages/relay/src/lib/clients/index.ts index 8c398c4c7e..2b1b25c400 100644 --- a/packages/relay/src/lib/clients/index.ts +++ b/packages/relay/src/lib/clients/index.ts @@ -1,6 +1,7 @@ // SPDX-License-Identifier: Apache-2.0 export * from './cache/localLRUCache'; +export * from './cache/measurableCache'; export * from './cache/redisCache/index'; export * from './mirrorNodeClient'; export * from './sdkClient'; diff --git a/packages/relay/src/lib/factories/cacheClientFactory.ts b/packages/relay/src/lib/factories/cacheClientFactory.ts index 8cf93ea4b2..10887daf9c 100644 --- a/packages/relay/src/lib/factories/cacheClientFactory.ts +++ b/packages/relay/src/lib/factories/cacheClientFactory.ts @@ -2,12 +2,31 @@ import { ConfigService } from '@hashgraph/json-rpc-config-service/dist/services'; import type { Logger } from 'pino'; -import { Registry } from 'prom-client'; +import { Counter, Registry } from 'prom-client'; import type { RedisClientType } from 'redis'; -import { LocalLRUCache, RedisCache } from '../clients'; +import { LocalLRUCache, MeasurableCache, RedisCache } from '../clients'; import type { ICacheClient } from '../clients/cache/ICacheClient'; +const measurable = (client: ICacheClient, register: Registry, configType: 'lru' | 'redis') => { + /** + * Labels: + * callingMethod - The method initiating the cache operation + * cacheType - redis/lru + * method - The CacheService method being called + */ + const metricName = 'rpc_cache_service_methods_counter'; + register.removeSingleMetric(metricName); + const methodsCounter = new Counter({ + name: metricName, + help: 'Counter for calls to methods of CacheService separated by CallingMethod and CacheType', + registers: [register], + labelNames: ['callingMethod', 'cacheType', 'method'], + }); + + return new MeasurableCache(client, methodsCounter, configType); +}; + export class CacheClientFactory { static create( logger: Logger, @@ -16,7 +35,7 @@ export class CacheClientFactory { redisClient?: RedisClientType, ): ICacheClient { return !ConfigService.get('TEST') && redisClient !== undefined - ? new RedisCache(logger.child({ name: 'redisCache' }), redisClient) - : new LocalLRUCache(logger.child({ name: 'localLRUCache' }), register, reservedKeys); + ? measurable(new RedisCache(logger.child({ name: 'redisCache' }), redisClient), register, 'redis') + : measurable(new LocalLRUCache(logger.child({ name: 'localLRUCache' }), register, reservedKeys), register, 'lru'); } } diff --git a/packages/relay/src/lib/relay.ts b/packages/relay/src/lib/relay.ts index b48d9f72ab..de06da335c 100644 --- a/packages/relay/src/lib/relay.ts +++ b/packages/relay/src/lib/relay.ts @@ -284,14 +284,11 @@ export class Relay { const reservedKeys = HbarSpendingPlanConfigService.getPreconfiguredSpendingPlanKeys(this.logger); // Create CacheService with the connected Redis client (or undefined for LRU-only) - this.cacheService = new CacheService( - CacheClientFactory.create( - this.logger.child({ name: 'cache-service' }), - this.register, - reservedKeys, - this.redisClient, - ), + this.cacheService = CacheClientFactory.create( + this.logger.child({ name: 'cache-service' }), this.register, + reservedKeys, + this.redisClient, ); // Create spending plan repositories diff --git a/packages/relay/src/lib/services/cacheService/cacheService.ts b/packages/relay/src/lib/services/cacheService/cacheService.ts index 56ccce8b4d..265fa0372c 100644 --- a/packages/relay/src/lib/services/cacheService/cacheService.ts +++ b/packages/relay/src/lib/services/cacheService/cacheService.ts @@ -1,241 +1,8 @@ // SPDX-License-Identifier: Apache-2.0 -import { ConfigService } from '@hashgraph/json-rpc-config-service/dist/services'; -import { Counter, Registry } from 'prom-client'; - -import { RedisCache } from '../../clients'; -import { ICacheClient } from '../../clients/cache/ICacheClient'; - /** * A service that manages caching using different cache implementations based on configuration. + * Client can be used directly, instead of this service, but it is left as an alias + * (and entrypoint for potential rewrites). */ -export class CacheService { - /** - * The cache used for caching items from requests. - * - * @private - */ - private readonly client: ICacheClient; - - /** - * Used for reference to the state of REDIS_ENABLED and REDIS_URL env. variables. - */ - private readonly isSharedCacheEnabled: boolean; - - /** - * Used for setting what type of multiSet method should be used to save new values. - */ - private readonly shouldMultiSet: boolean; - - /** - * Represents a caching manager that utilizes various cache implementations based on configuration. - * @param {Logger} logger - The logger used for logging all output from this class. - * @param {Registry} register - The metrics register used for metrics tracking. - */ - - private static readonly cacheTypes = { - REDIS: 'redis', - LRU: 'lru', - }; - - private static readonly methods = { - GET: 'get', - GET_ASYNC: 'getAsync', - SET: 'set', - DELETE: 'delete', - MSET: 'mSet', - PIPELINE: 'pipeline', - INCR_BY: 'incrBy', - RPUSH: 'rpush', - LRANGE: 'lrange', - }; - - private readonly cacheMethodsCounter: Counter; - - public constructor(client: ICacheClient, register: Registry = new Registry()) { - this.client = client; - this.isSharedCacheEnabled = client instanceof RedisCache; // TODO measurements will be moved out of here in the next PR. - this.shouldMultiSet = ConfigService.get('MULTI_SET'); // TODO measurements will be moved out of here in the next PR. - /** - * Labels: - * callingMethod - The method initiating the cache operation - * cacheType - redis/lru - * method - The CacheService method being called - */ - const metricName = 'rpc_cache_service_methods_counter'; - register.removeSingleMetric(metricName); - this.cacheMethodsCounter = new Counter({ - name: metricName, - help: 'Counter for calls to methods of CacheService separated by CallingMethod and CacheType', - registers: [register], - labelNames: ['callingMethod', 'cacheType', 'method'], - }); - } - - /** - * Retrieves a value from the cache asynchronously. - * - * @param key - The cache key. - * @param callingMethod - The name of the calling method. - * @returns A Promise that resolves with the cached value or null if not found. - */ - private async getFromSharedCache(key: string, callingMethod: string): Promise { - this.cacheMethodsCounter - .labels(callingMethod, CacheService.cacheTypes.REDIS, CacheService.methods.GET_ASYNC) - .inc(1); - - return await this.client.get(key, callingMethod); - } - - /** - * If SharedCacheEnabled will use shared, otherwise will fallback to internal cache. - * @param key - The cache key. - * @param callingMethod - The name of the calling method. - * @returns A Promise that resolves with the cached value or null if not found. - * @template T - The type of the cached value. - */ - public async getAsync(key: string, callingMethod: string): Promise { - if (this.isSharedCacheEnabled) { - return await this.getFromSharedCache(key, callingMethod); - } else { - return await this.getFromInternalCache(key, callingMethod); - } - } - - /** - * Retrieves a value from the internal cache. - * - * @param key - The cache key. - * @param callingMethod - The name of the calling method. - * @returns A Promise that resolves with the cached value or null if not found. - */ - private async getFromInternalCache(key: string, callingMethod: string): Promise { - this.cacheMethodsCounter.labels(callingMethod, CacheService.cacheTypes.LRU, CacheService.methods.GET).inc(1); - - return await this.client.get(key, callingMethod); - } - - /** - * Sets a value in the cache associated with the given key. - * - * @param key - The key to associate with the value. - * @param value - The value to cache. - * @param callingMethod - The name of the method calling the cache. - * @param ttl - Time to live for the cached value in milliseconds (optional). - */ - public async set(key: string, value: any, callingMethod: string, ttl?: number): Promise { - if (this.isSharedCacheEnabled) { - this.cacheMethodsCounter.labels(callingMethod, CacheService.cacheTypes.REDIS, CacheService.methods.SET).inc(1); - } else { - this.cacheMethodsCounter.labels(callingMethod, CacheService.cacheTypes.LRU, CacheService.methods.SET).inc(1); - } - await this.client.set(key, value, callingMethod, ttl); - } - - /** - * Sets multiple values in the cache, each associated with its respective key. - * @param entries - An object containing key-value pairs to cache. - * @param callingMethod - The name of the method calling the cache. - * @param ttl - Time to live for the cached value in milliseconds (optional). - */ - public async multiSet(entries: Record, callingMethod: string, ttl?: number): Promise { - await this.client.multiSet(entries, callingMethod, ttl); - if (this.isSharedCacheEnabled) { - const metricsMethod = this.shouldMultiSet ? CacheService.methods.MSET : CacheService.methods.PIPELINE; - this.cacheMethodsCounter.labels(callingMethod, CacheService.cacheTypes.REDIS, metricsMethod).inc(1); - } else { - this.cacheMethodsCounter.labels(callingMethod, CacheService.cacheTypes.LRU, CacheService.methods.SET).inc(1); - } - } - - /** - * Deletes a cached value associated with the given key. - * If the shared cache is enabled and an error occurs while deleting from it, just logs the error. - * Else the internal cache deletion is attempted. - * @param key - The key associated with the cached value to delete. - * @param callingMethod - The name of the method calling the cache. - */ - public async delete(key: string, callingMethod: string): Promise { - if (this.isSharedCacheEnabled) { - this.cacheMethodsCounter.labels(callingMethod, CacheService.cacheTypes.REDIS, CacheService.methods.DELETE).inc(1); - } else { - this.cacheMethodsCounter.labels(callingMethod, CacheService.cacheTypes.LRU, CacheService.methods.DELETE).inc(1); - } - await this.client.delete(key, callingMethod); - } - - /** - * Clears the cache. - * If the shared cache is enabled and an error occurs while clearing it, just logs the error. - * Else the internal cache clearing is attempted. - */ - public async clear(): Promise { - await this.client.clear(); - } - - /** - * Increments the value of a key in the cache by the specified amount. - * @param key - The key to increment. - * @param amount - The amount to increment by. - * @param callingMethod - The name of the calling method. - * @returns A Promise that resolves with the new value of the key after incrementing. - */ - public async incrBy(key: string, amount: number, callingMethod: string): Promise { - if (this.isSharedCacheEnabled) { - this.cacheMethodsCounter - .labels(callingMethod, CacheService.cacheTypes.REDIS, CacheService.methods.INCR_BY) - .inc(1); - } else { - this.cacheMethodsCounter.labels(callingMethod, CacheService.cacheTypes.LRU, CacheService.methods.GET).inc(1); - this.cacheMethodsCounter.labels(callingMethod, CacheService.cacheTypes.LRU, CacheService.methods.SET).inc(1); - } - - return await this.client.incrBy(key, amount, callingMethod); - } - - /** - * Pushes a value to the end of a list in the cache. - * @param key - The key of the list. - * @param value - The value to push. - * @param callingMethod - The name of the calling method. - * @returns A Promise that resolves with the new length of the list after pushing. - */ - public async rPush(key: string, value: any, callingMethod: string): Promise { - if (this.isSharedCacheEnabled) { - this.cacheMethodsCounter.labels(callingMethod, CacheService.cacheTypes.REDIS, CacheService.methods.RPUSH).inc(1); - } else { - this.cacheMethodsCounter.labels(callingMethod, CacheService.cacheTypes.LRU, CacheService.methods.GET).inc(1); - this.cacheMethodsCounter.labels(callingMethod, CacheService.cacheTypes.LRU, CacheService.methods.SET).inc(1); - } - - return await this.client.rPush(key, value, callingMethod); - } - - /** - * Retrieves a range of values from a list in the cache. - * @param key - The key of the list. - * @param start - The start index of the range. - * @param end - The end index of the range. - * @param callingMethod - The name of the calling method. - * @returns A Promise that resolves with the values in the range. - * @template T - The type of the values in the list. - */ - public async lRange(key: string, start: number, end: number, callingMethod: string): Promise { - if (this.isSharedCacheEnabled) { - this.cacheMethodsCounter.labels(callingMethod, CacheService.cacheTypes.REDIS, CacheService.methods.LRANGE).inc(1); - } else { - this.cacheMethodsCounter.labels(callingMethod, CacheService.cacheTypes.LRU, CacheService.methods.GET).inc(1); - } - return await this.client.lRange(key, start, end, callingMethod); - } - - /** - * Retrieves all keys matching the given pattern. - * @param pattern - The pattern to match keys against. - * @param callingMethod - The name of the calling method. - * @returns A Promise that resolves with an array of keys that match the pattern. - */ - async keys(pattern: string, callingMethod: string): Promise { - return await this.client.keys(pattern, callingMethod); - } -} +export { ICacheClient as CacheService } from '../../clients/cache/ICacheClient'; diff --git a/packages/relay/tests/lib/config/hbarSpendingPlanConfigService.spec.ts b/packages/relay/tests/lib/config/hbarSpendingPlanConfigService.spec.ts index 30763607c2..e560225be5 100644 --- a/packages/relay/tests/lib/config/hbarSpendingPlanConfigService.spec.ts +++ b/packages/relay/tests/lib/config/hbarSpendingPlanConfigService.spec.ts @@ -168,9 +168,11 @@ describe('HbarSpendingPlanConfigService', function () { } else { redisClient = undefined; } - cacheService = new CacheService( - CacheClientFactory.create(logger.child({ name: 'cache-service' }), registry, reservedKeys, redisClient as any), + cacheService = CacheClientFactory.create( + logger.child({ name: 'cache-service' }), registry, + reservedKeys, + redisClient as any, ); hbarSpendingPlanRepository = new HbarSpendingPlanRepository( cacheService, diff --git a/packages/relay/tests/lib/eth/eth-helpers.ts b/packages/relay/tests/lib/eth/eth-helpers.ts index 0f12d4fe56..55b26ed3c6 100644 --- a/packages/relay/tests/lib/eth/eth-helpers.ts +++ b/packages/relay/tests/lib/eth/eth-helpers.ts @@ -14,7 +14,6 @@ import { IPAddressHbarSpendingPlanRepository } from '../../../src/lib/db/reposit import { EthImpl } from '../../../src/lib/eth'; import { CacheClientFactory } from '../../../src/lib/factories/cacheClientFactory'; import { CommonService } from '../../../src/lib/services'; -import { CacheService } from '../../../src/lib/services/cacheService/cacheService'; import HAPIService from '../../../src/lib/services/hapiService/hapiService'; import { HbarLimitService } from '../../../src/lib/services/hbarLimitService'; @@ -35,7 +34,7 @@ export function generateEthTestEnv(fixedFeeHistory = false) { ConfigServiceTestHelper.dynamicOverride('ETH_FEE_HISTORY_FIXED', fixedFeeHistory); const logger = pino({ level: 'silent' }); const registry = new Registry(); - const cacheService = new CacheService(CacheClientFactory.create(logger, registry), registry); + const cacheService = CacheClientFactory.create(logger, registry); const mirrorNodeInstance = new MirrorNodeClient( ConfigService.get('MIRROR_NODE_URL'), logger.child({ name: `mirror-node` }), diff --git a/packages/relay/tests/lib/ethGetBlockBy.spec.ts b/packages/relay/tests/lib/ethGetBlockBy.spec.ts index 42d942643e..6536efd0dd 100644 --- a/packages/relay/tests/lib/ethGetBlockBy.spec.ts +++ b/packages/relay/tests/lib/ethGetBlockBy.spec.ts @@ -109,10 +109,7 @@ describe('eth_getBlockBy', async function () { eval: sinon.stub(), quit: sinon.stub().resolves(true), } as any; - cacheService = new CacheService( - CacheClientFactory.create(logger, registry, new Set(), redisClientMock as any), - registry, - ); + cacheService = CacheClientFactory.create(logger, registry, new Set(), redisClientMock as any); // @ts-ignore mirrorNodeInstance = new MirrorNodeClient( diff --git a/packages/relay/tests/lib/hapiService.spec.ts b/packages/relay/tests/lib/hapiService.spec.ts index 354d95100c..14d3321f12 100644 --- a/packages/relay/tests/lib/hapiService.spec.ts +++ b/packages/relay/tests/lib/hapiService.spec.ts @@ -39,7 +39,7 @@ describe('HAPI Service', async function () { this.beforeAll(() => { const duration = constants.HBAR_RATE_LIMIT_DURATION; - cacheService = new CacheService(CacheClientFactory.create(logger, registry), registry); + cacheService = CacheClientFactory.create(logger, registry); const hbarSpendingPlanRepository = new HbarSpendingPlanRepository(cacheService, logger); const evmAddressHbarSpendingPlanRepository = new EvmAddressHbarSpendingPlanRepository(cacheService, logger); diff --git a/packages/relay/tests/lib/mirrorNodeClient.spec.ts b/packages/relay/tests/lib/mirrorNodeClient.spec.ts index 4498fdef7f..80c8b80d44 100644 --- a/packages/relay/tests/lib/mirrorNodeClient.spec.ts +++ b/packages/relay/tests/lib/mirrorNodeClient.spec.ts @@ -40,7 +40,7 @@ describe('MirrorNodeClient', async function () { }, timeout: 20 * 1000, }); - cacheService = new CacheService(CacheClientFactory.create(logger, registry), registry); + cacheService = CacheClientFactory.create(logger, registry); mirrorNodeInstance = new MirrorNodeClient( ConfigService.get('MIRROR_NODE_URL'), logger.child({ name: `mirror-node` }), diff --git a/packages/relay/tests/lib/openrpc.spec.ts b/packages/relay/tests/lib/openrpc.spec.ts index 8d4577d64e..af797d7fec 100644 --- a/packages/relay/tests/lib/openrpc.spec.ts +++ b/packages/relay/tests/lib/openrpc.spec.ts @@ -26,7 +26,6 @@ import { IPAddressHbarSpendingPlanRepository } from '../../src/lib/db/repositori import { EthImpl } from '../../src/lib/eth'; import { CacheClientFactory } from '../../src/lib/factories/cacheClientFactory'; import { NetImpl } from '../../src/lib/net'; -import { CacheService } from '../../src/lib/services/cacheService/cacheService'; import ClientService from '../../src/lib/services/hapiService/hapiService'; import { HbarLimitService } from '../../src/lib/services/hbarLimitService'; import { TxPoolImpl } from '../../src/lib/txpool'; @@ -107,7 +106,7 @@ describe('Open RPC Specification', function () { }); mock = new MockAdapter(instance, { onNoMatch: 'throwException' }); - const cacheService = new CacheService(CacheClientFactory.create(logger, registry), registry); + const cacheService = CacheClientFactory.create(logger, registry); mirrorNodeInstance = new MirrorNodeClient( ConfigService.get('MIRROR_NODE_URL'), logger.child({ name: `mirror-node` }), diff --git a/packages/relay/tests/lib/precheck.spec.ts b/packages/relay/tests/lib/precheck.spec.ts index 53fddd40f3..e3aba892e2 100644 --- a/packages/relay/tests/lib/precheck.spec.ts +++ b/packages/relay/tests/lib/precheck.spec.ts @@ -13,7 +13,6 @@ import { JsonRpcError, predefined } from '../../src'; import { MirrorNodeClient } from '../../src/lib/clients'; import constants from '../../src/lib/constants'; import { Precheck } from '../../src/lib/precheck'; -import { CacheService } from '../../src/lib/services/cacheService/cacheService'; import { blobVersionedHash, contractAddress1, @@ -95,7 +94,7 @@ describe('Precheck', async function () { ConfigService.get('MIRROR_NODE_URL')!, logger.child({ name: `mirror-node` }), registry, - new CacheService(CacheClientFactory.create(logger, registry), registry), + CacheClientFactory.create(logger, registry), instance, ); const transactionPoolService = sinon.createStubInstance(TransactionPoolService); diff --git a/packages/relay/tests/lib/relay.spec.ts b/packages/relay/tests/lib/relay.spec.ts index e4149cf08e..509ae391ce 100644 --- a/packages/relay/tests/lib/relay.spec.ts +++ b/packages/relay/tests/lib/relay.spec.ts @@ -9,7 +9,6 @@ import sinon from 'sinon'; import { Relay } from '../../src'; import { MirrorNodeClient } from '../../src/lib/clients/mirrorNodeClient'; -import { CacheService } from '../../src/lib/services/cacheService/cacheService'; import { overrideEnvsInMochaDescribe, withOverriddenEnvsInMochaTest } from '../helpers'; chai.use(chaiAsPromised); @@ -52,8 +51,6 @@ describe('Relay', () => { let populatePreconfiguredSpendingPlansSpy: sinon.SinonSpy; beforeEach(() => { - // @ts-ignore - CacheService.instances = []; loggerSpy = sinon.spy(logger); populatePreconfiguredSpendingPlansSpy = sinon.spy(Relay.prototype, 'populatePreconfiguredSpendingPlans'); }); diff --git a/packages/relay/tests/lib/repositories/hbarLimiter/evmAddressHbarSpendingPlanRepository.spec.ts b/packages/relay/tests/lib/repositories/hbarLimiter/evmAddressHbarSpendingPlanRepository.spec.ts index 85c89d75e9..35787dc283 100644 --- a/packages/relay/tests/lib/repositories/hbarLimiter/evmAddressHbarSpendingPlanRepository.spec.ts +++ b/packages/relay/tests/lib/repositories/hbarLimiter/evmAddressHbarSpendingPlanRepository.spec.ts @@ -42,7 +42,7 @@ describe('@evmAddressHbarSpendingPlanRepository EvmAddressHbarSpendingPlanReposi } else { redisClient = undefined; } - cacheService = new CacheService(CacheClientFactory.create(logger, registry, new Set(), redisClient), registry); + cacheService = CacheClientFactory.create(logger, registry, new Set(), redisClient); cacheServiceSpy = sinon.spy(cacheService); repository = new EvmAddressHbarSpendingPlanRepository( cacheService, diff --git a/packages/relay/tests/lib/repositories/hbarLimiter/hbarSpendingPlanRepository.spec.ts b/packages/relay/tests/lib/repositories/hbarLimiter/hbarSpendingPlanRepository.spec.ts index 9c4f470162..4f9803df98 100644 --- a/packages/relay/tests/lib/repositories/hbarLimiter/hbarSpendingPlanRepository.spec.ts +++ b/packages/relay/tests/lib/repositories/hbarLimiter/hbarSpendingPlanRepository.spec.ts @@ -45,7 +45,7 @@ describe('HbarSpendingPlanRepository', function () { } else { redisClient = undefined; } - cacheService = new CacheService(CacheClientFactory.create(logger, registry, new Set(), redisClient), registry); + cacheService = CacheClientFactory.create(logger, registry, new Set(), redisClient); cacheServiceSpy = sinon.spy(cacheService); repository = new HbarSpendingPlanRepository(cacheService, logger.child({ name: `HbarSpendingPlanRepository` })); }); diff --git a/packages/relay/tests/lib/repositories/hbarLimiter/ipAddressHbarSpendingPlanRepository.spec.ts b/packages/relay/tests/lib/repositories/hbarLimiter/ipAddressHbarSpendingPlanRepository.spec.ts index 49e9d05b28..c143a18f53 100644 --- a/packages/relay/tests/lib/repositories/hbarLimiter/ipAddressHbarSpendingPlanRepository.spec.ts +++ b/packages/relay/tests/lib/repositories/hbarLimiter/ipAddressHbarSpendingPlanRepository.spec.ts @@ -39,7 +39,7 @@ describe('IPAddressHbarSpendingPlanRepository', function () { if (isSharedCacheEnabled) { await RedisClientManager.getClient(logger); } - cacheService = new CacheService(CacheClientFactory.create(logger, registry), registry); + cacheService = CacheClientFactory.create(logger, registry); cacheServiceSpy = sinon.spy(cacheService); repository = new IPAddressHbarSpendingPlanRepository( cacheService, diff --git a/packages/relay/tests/lib/sdkClient.spec.ts b/packages/relay/tests/lib/sdkClient.spec.ts index 673001cce3..e627bde6d7 100644 --- a/packages/relay/tests/lib/sdkClient.spec.ts +++ b/packages/relay/tests/lib/sdkClient.spec.ts @@ -87,7 +87,7 @@ describe('SdkClient', async function () { const hederaNetwork = ConfigService.get('HEDERA_NETWORK')!; const duration = constants.HBAR_RATE_LIMIT_DURATION; - cacheService = new CacheService(CacheClientFactory.create(logger, registry), registry); + cacheService = CacheClientFactory.create(logger, registry); const hbarSpendingPlanRepository = new HbarSpendingPlanRepository(cacheService, logger); const evmAddressHbarSpendingPlanRepository = new EvmAddressHbarSpendingPlanRepository(cacheService, logger); const ipAddressHbarSpendingPlanRepository = new IPAddressHbarSpendingPlanRepository(cacheService, logger); diff --git a/packages/relay/tests/lib/services/cacheService/cacheService.spec.ts b/packages/relay/tests/lib/services/cacheService/cacheService.spec.ts index 5ac375ebc2..94c97e7940 100644 --- a/packages/relay/tests/lib/services/cacheService/cacheService.spec.ts +++ b/packages/relay/tests/lib/services/cacheService/cacheService.spec.ts @@ -27,7 +27,7 @@ describe('CacheService Test Suite', async function () { describe('keys', async function () { let internalCacheSpy: sinon.SinonSpiedInstance; before(async () => { - internalCacheSpy = sinon.spy(cacheService['client']); + internalCacheSpy = sinon.spy(cacheService); }); it('should retrieve all keys', async function () { @@ -134,7 +134,7 @@ describe('CacheService Test Suite', async function () { overrideEnvsInMochaDescribe({ REDIS_ENABLED: false }); this.beforeAll(() => { - cacheService = new CacheService(CacheClientFactory.create(logger, registry), registry); + cacheService = CacheClientFactory.create(logger, registry); }); this.afterEach(async () => { @@ -236,7 +236,7 @@ describe('CacheService Test Suite', async function () { describe('should not initialize redis cache if shared cache is not enabled', async function () { it('should not initialize redis cache if shared cache is not enabled', async function () { - expect(cacheService['client']).to.be.an.instanceOf(LocalLRUCache); + expect(cacheService['decorated']).to.be.an.instanceOf(LocalLRUCache); }); }); }); @@ -252,10 +252,7 @@ describe('CacheService Test Suite', async function () { overrideEnvsInMochaDescribe({ MULTI_SET: true }); before(async () => { - cacheService = new CacheService( - CacheClientFactory.create(logger, registry, new Set(), await RedisClientManager.getClient(logger)), - registry, - ); + cacheService = CacheClientFactory.create(logger, registry, new Set(), await RedisClientManager.getClient(logger)); }); this.beforeEach(async () => { @@ -356,7 +353,6 @@ describe('CacheService Test Suite', async function () { it('should be able to ignore clear failure in case of Redis error', async function () { await RedisClientManager.disconnect(); - await expect(cacheService.clear()).to.eventually.not.be.rejected; }); @@ -401,7 +397,6 @@ describe('CacheService Test Suite', async function () { it('should be able to ignore increment failure in case of Redis error', async function () { const key = 'counter'; - const amount = 5; await cacheService.set(key, 10, callingMethod); await RedisClientManager.disconnect(); await expect(cacheService.incrBy(key, 5, callingMethod)).to.eventually.not.be.rejected; diff --git a/packages/relay/tests/lib/services/eth/filter.spec.ts b/packages/relay/tests/lib/services/eth/filter.spec.ts index 09b418de3a..3c42b8a68c 100644 --- a/packages/relay/tests/lib/services/eth/filter.spec.ts +++ b/packages/relay/tests/lib/services/eth/filter.spec.ts @@ -63,7 +63,7 @@ describe('Filter API Test Suite', async function () { }; this.beforeAll(() => { - cacheService = new CacheService(CacheClientFactory.create(logger, registry)); + cacheService = CacheClientFactory.create(logger, registry); mirrorNodeInstance = new MirrorNodeClient( ConfigService.get('MIRROR_NODE_URL'), logger.child({ name: `mirror-node` }), diff --git a/packages/relay/tests/lib/services/hbarLimitService/hbarLimitService.spec.ts b/packages/relay/tests/lib/services/hbarLimitService/hbarLimitService.spec.ts index 9855260839..12c50b08e0 100644 --- a/packages/relay/tests/lib/services/hbarLimitService/hbarLimitService.spec.ts +++ b/packages/relay/tests/lib/services/hbarLimitService/hbarLimitService.spec.ts @@ -59,7 +59,7 @@ describe('HBAR Rate Limit Service', function () { let loggerSpy: sinon.SinonSpiedInstance; beforeEach(async function () { - cacheService = new CacheService(CacheClientFactory.create(logger, register)); + cacheService = CacheClientFactory.create(logger, register); loggerSpy = sinon.spy(logger); hbarSpendingPlanRepository = new HbarSpendingPlanRepository( cacheService, diff --git a/packages/relay/tests/lib/services/metricService/metricService.spec.ts b/packages/relay/tests/lib/services/metricService/metricService.spec.ts index bedadd9cb5..819b1a1f5e 100644 --- a/packages/relay/tests/lib/services/metricService/metricService.spec.ts +++ b/packages/relay/tests/lib/services/metricService/metricService.spec.ts @@ -18,7 +18,6 @@ import { EvmAddressHbarSpendingPlanRepository } from '../../../../src/lib/db/rep import { HbarSpendingPlanRepository } from '../../../../src/lib/db/repositories/hbarLimiter/hbarSpendingPlanRepository'; import { IPAddressHbarSpendingPlanRepository } from '../../../../src/lib/db/repositories/hbarLimiter/ipAddressHbarSpendingPlanRepository'; import { CacheClientFactory } from '../../../../src/lib/factories/cacheClientFactory'; -import { CacheService } from '../../../../src/lib/services/cacheService/cacheService'; import { HbarLimitService } from '../../../../src/lib/services/hbarLimitService'; import MetricService from '../../../../src/lib/services/metricService/metricService'; import { @@ -136,7 +135,7 @@ describe('Metric Service', function () { ConfigService.get('MIRROR_NODE_URL'), logger.child({ name: `mirror-node` }), registry, - new CacheService(CacheClientFactory.create(logger, registry)), + CacheClientFactory.create(logger, registry), instance, ); }); @@ -148,7 +147,7 @@ describe('Metric Service', function () { eventEmitter = new EventEmitter(); - const cacheService = new CacheService(CacheClientFactory.create(logger, registry)); + const cacheService = CacheClientFactory.create(logger, registry); const hbarSpendingPlanRepository = new HbarSpendingPlanRepository(cacheService, logger); const evmAddressHbarSpendingPlanRepository = new EvmAddressHbarSpendingPlanRepository(cacheService, logger); const ipAddressHbarSpendingPlanRepository = new IPAddressHbarSpendingPlanRepository(cacheService, logger); diff --git a/packages/server/tests/acceptance/cacheService.spec.ts b/packages/server/tests/acceptance/cacheService.spec.ts index 5acd6d5fce..dcfe20ead0 100644 --- a/packages/server/tests/acceptance/cacheService.spec.ts +++ b/packages/server/tests/acceptance/cacheService.spec.ts @@ -27,24 +27,23 @@ describe('@cache-service Acceptance Tests for shared cache', function () { logger = pino({ level: 'silent' }); redisClient = await RedisClientManager.getClient(logger); - cacheService = new CacheService(CacheClientFactory.create(logger, undefined, undefined, redisClient)); + cacheService = CacheClientFactory.create(logger, undefined, undefined, redisClient); await new Promise((r) => setTimeout(r, 1000)); }); it('Correctly performs set, get and delete operations', async () => { const dataLabel = `${DATA_LABEL_PREFIX}1`; - const setSharedCacheSpy = sinon.spy(cacheService['client'], 'set'); - const getSharedCacheSpy = sinon.spy(cacheService['client'], 'get'); - const deleteSharedCacheSpy = sinon.spy(cacheService['client'], 'delete'); + const setSharedCacheSpy = sinon.spy(cacheService, 'set'); + const getSharedCacheSpy = sinon.spy(cacheService, 'getAsync'); + const deleteSharedCacheSpy = sinon.spy(cacheService, 'delete'); await cacheService.set(dataLabel, DATA, CALLING_METHOD); await new Promise((r) => setTimeout(r, 200)); const cache = await cacheService.getAsync(dataLabel, CALLING_METHOD); expect(cache).to.deep.eq(DATA, 'set method saves to shared cache'); - expect(cacheService['isSharedCacheEnabled']).to.be.true; - expect(cacheService['client']).to.be.instanceOf(RedisCache); + expect(cacheService['decorated']).to.be.instanceOf(RedisCache); const cacheFromService = await cacheService.getAsync(dataLabel, CALLING_METHOD); expect(cacheFromService).to.deep.eq(DATA, 'getAsync method reads correctly from shared cache'); @@ -86,7 +85,7 @@ describe('@cache-service Acceptance Tests for shared cache', function () { it('Falls back to local cache for REDIS_ENABLED !== true', async () => { const dataLabel = `${DATA_LABEL_PREFIX}3`; - const serviceWithDisabledRedis = new CacheService(CacheClientFactory.create(logger)); + const serviceWithDisabledRedis = CacheClientFactory.create(logger); const isRedisEnabled = ConfigService.get('REDIS_ENABLED') && !!ConfigService.get('REDIS_URL'); await new Promise((r) => setTimeout(r, 1000)); expect(isRedisEnabled).to.eq(false); @@ -100,7 +99,7 @@ describe('@cache-service Acceptance Tests for shared cache', function () { it('Cache set by one instance can be accessed by another', async () => { const dataLabel = `${DATA_LABEL_PREFIX}4`; - const otherServiceInstance = new CacheService(CacheClientFactory.create(logger, undefined, undefined, redisClient)); + const otherServiceInstance = CacheClientFactory.create(logger, undefined, undefined, redisClient); await cacheService.set(dataLabel, DATA, CALLING_METHOD); await new Promise((r) => setTimeout(r, 200)); diff --git a/packages/server/tests/acceptance/hbarLimiter.spec.ts b/packages/server/tests/acceptance/hbarLimiter.spec.ts index c643605571..25d8dc3c2e 100644 --- a/packages/server/tests/acceptance/hbarLimiter.spec.ts +++ b/packages/server/tests/acceptance/hbarLimiter.spec.ts @@ -87,9 +87,11 @@ describe('@hbarlimiter HBAR Limiter Acceptance Tests', function () { const register = new Registry(); const reservedKeys = HbarSpendingPlanConfigService.getPreconfiguredSpendingPlanKeys(logger); - cacheService = new CacheService( - CacheClientFactory.create(logger.child({ name: 'cache-service' }), register, reservedKeys, redisClient), + cacheService = CacheClientFactory.create( + logger.child({ name: 'cache-service' }), register, + reservedKeys, + redisClient, ); evmAddressSpendingPlanRepository = new EvmAddressHbarSpendingPlanRepository(cacheService, logger); diff --git a/packages/server/tests/integration/server.spec.ts b/packages/server/tests/integration/server.spec.ts index 66840c5fc1..1d3df028d8 100644 --- a/packages/server/tests/integration/server.spec.ts +++ b/packages/server/tests/integration/server.spec.ts @@ -8,7 +8,6 @@ import { predefined, Relay } from '@hashgraph/json-rpc-relay'; import { MirrorNodeClient } from '@hashgraph/json-rpc-relay/dist/lib/clients'; import { TracerType } from '@hashgraph/json-rpc-relay/dist/lib/constants'; import { DebugImpl } from '@hashgraph/json-rpc-relay/dist/lib/debug'; -import { CacheService } from '@hashgraph/json-rpc-relay/dist/lib/services/cacheService/cacheService'; import { Constants, TYPES } from '@hashgraph/json-rpc-relay/dist/lib/validators'; import serverTestConstants from '../helpers/constants'; @@ -24,6 +23,8 @@ import { GCProfiler } from 'v8'; chai.use(chaiAsPromised); +import { MeasurableCache } from '@hashgraph/json-rpc-relay/dist/lib/clients/cache/measurableCache'; + import { contractAddress1, contractAddress2, @@ -3048,8 +3049,8 @@ describe('RPC Server', function () { }); callTracer = sinon.stub(DebugImpl.prototype, 'callTracer').resolves(callTracerResult); prestateTracer = sinon.stub(DebugImpl.prototype, 'prestateTracer').resolves(prestateTracerResult); - cacheGetAsync = sinon.stub(CacheService.prototype, 'getAsync').resolves(null); - cacheSet = sinon.stub(CacheService.prototype, 'set').resolves(); + cacheGetAsync = sinon.stub(MeasurableCache.prototype, 'getAsync').resolves(null); + cacheSet = sinon.stub(MeasurableCache.prototype, 'set').resolves(); requireDebugAPIEnabled = sinon.stub(DebugImpl, 'requireDebugAPIEnabled').returns(); });