35 Commits

Author SHA1 Message Date
sarina
527f765b9e chore: update browserslist DB 2026-03-16 00:23:59 +00:00
Jacobo Dominguez
2ac818f4be fix: a11y for screen readers on roles and permissions tabs (#69) 2026-03-03 20:05:52 +11:00
renovate[bot]
f10cbf53a3 chore(deps): update dependency @types/react to v18.3.28 (#78)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-02 03:00:39 -05:00
renovate[bot]
e5e10d7c1f chore(deps): update dependency @edx/browserslist-config to v1.5.1 (#77)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-02 03:00:30 -05:00
edX requirements bot
e8b8d53ec3 chore: update browserslist DB (#75)
Co-authored-by: sarina <1985317+sarina@users.noreply.github.com>
2026-03-01 19:28:33 -05:00
edX requirements bot
e8f5259349 chore: update browserslist DB (#71)
Co-authored-by: sarina <1985317+sarina@users.noreply.github.com>
2026-02-23 09:39:40 -05:00
dependabot[bot]
e7ff71279f build(deps): bump qs and express (#57)
Bumps [qs](https://github.com/ljharb/qs) and [express](https://github.com/expressjs/express). These dependencies needed to be updated together.

Updates `qs` from 6.13.0 to 6.14.1
- [Changelog](https://github.com/ljharb/qs/blob/main/CHANGELOG.md)
- [Commits](https://github.com/ljharb/qs/compare/v6.13.0...v6.14.1)

Updates `express` from 4.21.2 to 4.22.1
- [Release notes](https://github.com/expressjs/express/releases)
- [Changelog](https://github.com/expressjs/express/blob/v4.22.1/History.md)
- [Commits](https://github.com/expressjs/express/compare/4.21.2...v4.22.1)

---
updated-dependencies:
- dependency-name: qs
  dependency-version: 6.14.1
  dependency-type: indirect
- dependency-name: express
  dependency-version: 4.22.1
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-20 11:22:28 -06:00
dependabot[bot]
6be4f86841 build(deps): bump node-forge from 1.3.1 to 1.3.3 (#58)
Bumps [node-forge](https://github.com/digitalbazaar/forge) from 1.3.1 to 1.3.3.
- [Changelog](https://github.com/digitalbazaar/forge/blob/main/CHANGELOG.md)
- [Commits](https://github.com/digitalbazaar/forge/compare/v1.3.1...v1.3.3)

---
updated-dependencies:
- dependency-name: node-forge
  dependency-version: 1.3.3
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-20 11:18:48 -06:00
dependabot[bot]
4817150dcb build(deps): bump js-yaml (#60)
Bumps  and [js-yaml](https://github.com/nodeca/js-yaml). These dependencies needed to be updated together.

Updates `js-yaml` from 3.14.1 to 3.14.2
- [Changelog](https://github.com/nodeca/js-yaml/blob/master/CHANGELOG.md)
- [Commits](https://github.com/nodeca/js-yaml/compare/3.14.1...3.14.2)

Updates `js-yaml` from 4.1.0 to 4.1.1
- [Changelog](https://github.com/nodeca/js-yaml/blob/master/CHANGELOG.md)
- [Commits](https://github.com/nodeca/js-yaml/compare/3.14.1...3.14.2)

---
updated-dependencies:
- dependency-name: js-yaml
  dependency-version: 3.14.2
  dependency-type: indirect
- dependency-name: js-yaml
  dependency-version: 4.1.1
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-20 11:14:11 -06:00
dependabot[bot]
d59cdb22ab build(deps): bump lodash from 4.17.21 to 4.17.23 (#62)
Bumps [lodash](https://github.com/lodash/lodash) from 4.17.21 to 4.17.23.
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.21...4.17.23)

---
updated-dependencies:
- dependency-name: lodash
  dependency-version: 4.17.23
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-20 11:08:26 -06:00
dependabot[bot]
56825a407d build(deps): bump webpack from 5.101.3 to 5.105.0 (#64)
Bumps [webpack](https://github.com/webpack/webpack) from 5.101.3 to 5.105.0.
- [Release notes](https://github.com/webpack/webpack/releases)
- [Changelog](https://github.com/webpack/webpack/blob/main/CHANGELOG.md)
- [Commits](https://github.com/webpack/webpack/compare/v5.101.3...v5.105.0)

---
updated-dependencies:
- dependency-name: webpack
  dependency-version: 5.105.0
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-20 10:59:48 -06:00
dependabot[bot]
a4e999fb51 build(deps): bump axios and @edx/frontend-platform (#70)
Bumps [axios](https://github.com/axios/axios) to 0.30.3 and updates ancestor dependency [@edx/frontend-platform](https://github.com/openedx/frontend-platform). These dependencies need to be updated together.


Updates `axios` from 0.30.2 to 0.30.3
- [Release notes](https://github.com/axios/axios/releases)
- [Changelog](https://github.com/axios/axios/blob/v1.x/CHANGELOG.md)
- [Commits](https://github.com/axios/axios/compare/v0.30.2...v0.30.3)

Updates `@edx/frontend-platform` from 8.5.1 to 8.5.5
- [Release notes](https://github.com/openedx/frontend-platform/releases)
- [Commits](https://github.com/openedx/frontend-platform/compare/v8.5.1...v8.5.5)

---
updated-dependencies:
- dependency-name: axios
  dependency-version: 0.30.3
  dependency-type: indirect
- dependency-name: "@edx/frontend-platform"
  dependency-version: 8.5.5
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-20 10:51:32 -06:00
dependabot[bot]
9a8e853ef3 build(deps): bump @remix-run/router and react-router-dom (#56)
Bumps [@remix-run/router](https://github.com/remix-run/react-router/tree/HEAD/packages/router) to 1.23.2 and updates ancestor dependency [react-router-dom](https://github.com/remix-run/react-router/tree/HEAD/packages/react-router-dom). These dependencies need to be updated together.


Updates `@remix-run/router` from 1.23.0 to 1.23.2
- [Release notes](https://github.com/remix-run/react-router/releases)
- [Changelog](https://github.com/remix-run/react-router/blob/@remix-run/router@1.23.2/packages/router/CHANGELOG.md)
- [Commits](https://github.com/remix-run/react-router/commits/@remix-run/router@1.23.2/packages/router)

Updates `react-router-dom` from 6.30.1 to 6.30.3
- [Release notes](https://github.com/remix-run/react-router/releases)
- [Changelog](https://github.com/remix-run/react-router/blob/main/CHANGELOG.md)
- [Commits](https://github.com/remix-run/react-router/commits/react-router-dom@6.30.3/packages/react-router-dom)

---
updated-dependencies:
- dependency-name: "@remix-run/router"
  dependency-version: 1.23.2
  dependency-type: indirect
- dependency-name: react-router-dom
  dependency-version: 6.30.3
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-20 10:46:31 -06:00
Jacobo Dominguez
2e5c104430 fix: handling malformed library ids as not found errors (#66) 2026-02-18 15:38:09 -06:00
Jacobo Dominguez
8c4eeb2c09 feat: extending delay time for error toasts with retry fn (#67) 2026-02-18 15:37:28 -06:00
edX requirements bot
98e6d808dc chore: update browserslist DB (#68)
Co-authored-by: sarina <1985317+sarina@users.noreply.github.com>
2026-02-15 19:23:11 -05:00
edX requirements bot
59c1c85939 chore: update browserslist DB (#65)
Co-authored-by: sarina <1985317+sarina@users.noreply.github.com>
2026-02-09 00:21:56 +00:00
edX requirements bot
a63df787f7 chore: update browserslist DB (#63)
Co-authored-by: sarina <1985317+sarina@users.noreply.github.com>
2026-02-05 18:56:19 +11:00
edX requirements bot
66e40eccee chore: update browserslist DB (#55)
Co-authored-by: sarina <1985317+sarina@users.noreply.github.com>
2026-01-19 00:17:42 +00:00
edX requirements bot
3213354623 chore: update browserslist DB (#54)
Co-authored-by: sarina <1985317+sarina@users.noreply.github.com>
2026-01-12 00:17:29 +00:00
edX requirements bot
a00e29ec5a chore: update browserslist DB (#53)
Co-authored-by: sarina <1985317+sarina@users.noreply.github.com>
2026-01-05 00:18:04 +00:00
Ty Hob / Brian Mesick
47fdb66ae4 Merge pull request #52 from openedx/update-browserslist-db
Update browserslist DB
2026-01-02 09:32:50 -05:00
Tony Busa
442a27d720 fix: replace FC components with arrow func declaration (#33) 2025-12-31 07:55:10 +11:00
sarina
9f296ec1c6 chore: update browserslist DB 2025-12-29 00:17:46 +00:00
Jacobo Dominguez
c700ce5ca4 fix: changing how the feedback message is displayed for adding team members (#42)
* fix: changing how the feedback message is displayed for adding team members

* fix: updating feedback to consider existing roles a successful messages

* fix: already has role message update

* feat: update not found message
2025-12-29 09:18:05 +11:00
edX requirements bot
8b9a57ace9 chore: update browserslist DB (#51)
Co-authored-by: sarina <1985317+sarina@users.noreply.github.com>
2025-12-08 00:16:25 +00:00
jacobo-dominguez-wgu
19034282fc fix: table cells refactor to get rid of eslint nested components ignore 2025-12-01 10:46:51 -03:00
edX requirements bot
56edd458c3 chore: update browserslist DB (#47)
Co-authored-by: sarina <1985317+sarina@users.noreply.github.com>
2025-11-30 19:18:53 -05:00
edX requirements bot
ea5141830a chore: update browserslist DB (#43)
Co-authored-by: sarina <1985317+sarina@users.noreply.github.com>
2025-11-24 00:16:44 +00:00
Diana Olarte
3df4fef7e1 fix: invalidate PermissionsByRole to update number of user in a role 2025-11-19 12:53:24 -03:00
Jacobo Dominguez
a37491b0a5 refactor: adding namespace to permissions (#37)
Updating namespaces to permissions to use name spaced identifiers by adding the content_libraries prefix.
2025-11-18 15:05:32 -03:00
edX requirements bot
72dc951d36 chore: update browserslist DB (#39)
Co-authored-by: sarina <1985317+sarina@users.noreply.github.com>
2025-11-17 00:15:33 +00:00
jacobo-dominguez-wgu
0572a73fb4 test: replacing queries by test id 2025-11-14 13:43:43 -03:00
edX requirements bot
eb224b9f71 chore: update browserslist DB (#36)
Co-authored-by: sarina <1985317+sarina@users.noreply.github.com>
2025-11-13 19:32:04 +00:00
Jacobo Dominguez
b760584566 fix: base bradcrumb item with no link set (#32) 2025-11-05 14:55:02 -05:00
42 changed files with 2435 additions and 1900 deletions

2692
package-lock.json generated
View File

@@ -11,7 +11,7 @@
"dependencies": {
"@edx/brand": "npm:@openedx/brand-openedx@^1.2.2",
"@edx/frontend-component-header": "^6.4.0",
"@edx/frontend-platform": "^8.3.0",
"@edx/frontend-platform": "^8.5.5",
"@edx/openedx-atlas": "^0.7.0",
"@openedx/frontend-plugin-framework": "^1.7.0",
"@openedx/paragon": "^23.15.1",
@@ -20,7 +20,7 @@
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-error-boundary": "^4.1.2",
"react-router-dom": "^6.0.0"
"react-router-dom": "^6.30.3"
},
"devDependencies": {
"@edx/browserslist-config": "^1.1.1",
@@ -31,7 +31,8 @@
"@testing-library/react": "^16.3.0",
"@testing-library/user-event": "^14.6.1",
"@types/react": "^18",
"@types/react-dom": "^18"
"@types/react-dom": "^18",
"ts-jest": "^29.4.5"
}
},
"node_modules/@adobe/css-tools": {
@@ -161,14 +162,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==",
"devOptional": true,
"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"
@@ -404,9 +405,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==",
"devOptional": true,
"license": "MIT",
"engines": {
@@ -453,13 +454,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==",
"devOptional": true,
"license": "MIT",
"dependencies": {
"@babel/types": "^7.28.4"
"@babel/types": "^7.28.5"
},
"bin": {
"parser": "bin/babel-parser.js"
@@ -1985,18 +1986,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==",
"devOptional": true,
"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.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": {
@@ -2004,14 +2005,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==",
"devOptional": true,
"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"
@@ -2340,9 +2341,9 @@
"license": "GPL-3.0-or-later"
},
"node_modules/@edx/browserslist-config": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/@edx/browserslist-config/-/browserslist-config-1.5.0.tgz",
"integrity": "sha512-d2ggwi5j4DOBJOwhWZxBWQSDR0DhT4ke/1PbzRauICdFkuOyax+PsFjK8GUh443K2OaQpy9PGfiCzZ1Yg37AUA==",
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/@edx/browserslist-config/-/browserslist-config-1.5.1.tgz",
"integrity": "sha512-r2zinEBFUqmh3iLkAb1RYwKDA0sQXjkP8OSl8dkE3Y+DnJwFIb1Yr1diY34vSwSQO5bB15OeLplFqQkbbPNpbA==",
"dev": true,
"license": "AGPL-3.0"
},
@@ -2390,16 +2391,16 @@
}
},
"node_modules/@edx/frontend-platform": {
"version": "8.5.1",
"resolved": "https://registry.npmjs.org/@edx/frontend-platform/-/frontend-platform-8.5.1.tgz",
"integrity": "sha512-8u3EdO0o7xX4vqorjOx3k2wbs2bu3DXlIA3bnD+Y56vSB5QYw6k5GzYqo9pPaTMGeq9TuLRvPLE/QFFlc3xvPg==",
"version": "8.5.5",
"resolved": "https://registry.npmjs.org/@edx/frontend-platform/-/frontend-platform-8.5.5.tgz",
"integrity": "sha512-imExY37cxE7qzKYg3gaqcdfhc0rzpV1DEFmy6PPCJg4m+cycQNiXtAKl3nITkcQkzhV0JYh3qttEgq6d4a1QXw==",
"license": "AGPL-3.0",
"dependencies": {
"@cospired/i18n-iso-languages": "4.2.0",
"@formatjs/intl-pluralrules": "4.3.3",
"@formatjs/intl-relativetimeformat": "10.0.1",
"axios": "1.12.0",
"axios-cache-interceptor": "1.8.0",
"axios": "1.13.5",
"axios-cache-interceptor": "1.11.4",
"form-urlencoded": "4.1.4",
"glob": "7.2.3",
"history": "4.10.1",
@@ -2469,7 +2470,6 @@
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.5.0.tgz",
"integrity": "sha512-sbP8GzB1WDzacS8fgNPpHlp6C9VZe+SJP3F90W9rLemaQj2PzIuTEl1qDOYQf58YIpyjViI24y9aPWCjEzY2cg==",
"dev": true,
"license": "MIT",
"optional": true,
"dependencies": {
@@ -2481,7 +2481,6 @@
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.5.0.tgz",
"integrity": "sha512-97/BJ3iXHww3djw6hYIfErCZFee7qCtrneuLa20UXFCOTCfBM2cvQHjWJ2EG0s0MtdNwInarqCTz35i4wWXHsQ==",
"dev": true,
"license": "MIT",
"optional": true,
"dependencies": {
@@ -2492,7 +2491,6 @@
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.1.0.tgz",
"integrity": "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==",
"dev": true,
"license": "MIT",
"optional": true,
"dependencies": {
@@ -2573,9 +2571,9 @@
"license": "Python-2.0"
},
"node_modules/@eslint/eslintrc/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==",
"devOptional": true,
"license": "MIT",
"dependencies": {
@@ -3089,7 +3087,6 @@
"cpu": [
"arm64"
],
"dev": true,
"license": "Apache-2.0",
"optional": true,
"os": [
@@ -3112,7 +3109,6 @@
"cpu": [
"x64"
],
"dev": true,
"license": "Apache-2.0",
"optional": true,
"os": [
@@ -3135,7 +3131,6 @@
"cpu": [
"arm64"
],
"dev": true,
"license": "LGPL-3.0-or-later",
"optional": true,
"os": [
@@ -3152,7 +3147,6 @@
"cpu": [
"x64"
],
"dev": true,
"license": "LGPL-3.0-or-later",
"optional": true,
"os": [
@@ -3169,7 +3163,6 @@
"cpu": [
"arm"
],
"dev": true,
"license": "LGPL-3.0-or-later",
"optional": true,
"os": [
@@ -3186,7 +3179,6 @@
"cpu": [
"arm64"
],
"dev": true,
"license": "LGPL-3.0-or-later",
"optional": true,
"os": [
@@ -3203,7 +3195,6 @@
"cpu": [
"ppc64"
],
"dev": true,
"license": "LGPL-3.0-or-later",
"optional": true,
"os": [
@@ -3220,7 +3211,6 @@
"cpu": [
"s390x"
],
"dev": true,
"license": "LGPL-3.0-or-later",
"optional": true,
"os": [
@@ -3237,7 +3227,6 @@
"cpu": [
"x64"
],
"dev": true,
"license": "LGPL-3.0-or-later",
"optional": true,
"os": [
@@ -3254,7 +3243,6 @@
"cpu": [
"arm64"
],
"dev": true,
"license": "LGPL-3.0-or-later",
"optional": true,
"os": [
@@ -3271,7 +3259,6 @@
"cpu": [
"x64"
],
"dev": true,
"license": "LGPL-3.0-or-later",
"optional": true,
"os": [
@@ -3288,7 +3275,6 @@
"cpu": [
"arm"
],
"dev": true,
"license": "Apache-2.0",
"optional": true,
"os": [
@@ -3311,7 +3297,6 @@
"cpu": [
"arm64"
],
"dev": true,
"license": "Apache-2.0",
"optional": true,
"os": [
@@ -3334,7 +3319,6 @@
"cpu": [
"ppc64"
],
"dev": true,
"license": "Apache-2.0",
"optional": true,
"os": [
@@ -3357,7 +3341,6 @@
"cpu": [
"s390x"
],
"dev": true,
"license": "Apache-2.0",
"optional": true,
"os": [
@@ -3380,7 +3363,6 @@
"cpu": [
"x64"
],
"dev": true,
"license": "Apache-2.0",
"optional": true,
"os": [
@@ -3403,7 +3385,6 @@
"cpu": [
"arm64"
],
"dev": true,
"license": "Apache-2.0",
"optional": true,
"os": [
@@ -3426,7 +3407,6 @@
"cpu": [
"x64"
],
"dev": true,
"license": "Apache-2.0",
"optional": true,
"os": [
@@ -3449,7 +3429,6 @@
"cpu": [
"wasm32"
],
"dev": true,
"license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT",
"optional": true,
"dependencies": {
@@ -3469,7 +3448,6 @@
"cpu": [
"arm64"
],
"dev": true,
"license": "Apache-2.0 AND LGPL-3.0-or-later",
"optional": true,
"os": [
@@ -3489,7 +3467,6 @@
"cpu": [
"ia32"
],
"dev": true,
"license": "Apache-2.0 AND LGPL-3.0-or-later",
"optional": true,
"os": [
@@ -3509,7 +3486,6 @@
"cpu": [
"x64"
],
"dev": true,
"license": "Apache-2.0 AND LGPL-3.0-or-later",
"optional": true,
"os": [
@@ -3693,19 +3669,18 @@
}
},
"node_modules/@jest/console": {
"version": "30.1.2",
"resolved": "https://registry.npmjs.org/@jest/console/-/console-30.1.2.tgz",
"integrity": "sha512-BGMAxj8VRmoD0MoA/jo9alMXSRoqW8KPeqOfEo1ncxnRLatTBCpRoOwlwlEMdudp68Q6WSGwYrrLtTGOh8fLzw==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/@jest/console/-/console-30.2.0.tgz",
"integrity": "sha512-+O1ifRjkvYIkBqASKWgLxrpEhQAAE7hY77ALLUufSk5717KfOShg6IbqLmdsLMPdUiFvA2kTs0R7YZy+l0IzZQ==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@jest/types": "30.0.5",
"@jest/types": "30.2.0",
"@types/node": "*",
"chalk": "^4.1.2",
"jest-message-util": "30.1.0",
"jest-util": "30.0.5",
"jest-message-util": "30.2.0",
"jest-util": "30.2.0",
"slash": "^3.0.0"
},
"engines": {
@@ -3716,9 +3691,8 @@
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz",
"integrity": "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@sinclair/typebox": "^0.34.0"
@@ -3728,12 +3702,11 @@
}
},
"node_modules/@jest/console/node_modules/@jest/types": {
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-30.0.5.tgz",
"integrity": "sha512-aREYa3aku9SSnea4aX6bhKn4bgv3AXkgijoQgbYV3yvbiGt6z+MQ85+6mIhx9DsKW2BuB/cLR/A+tcMThx+KLQ==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-30.2.0.tgz",
"integrity": "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@jest/pattern": "30.0.1",
@@ -3752,18 +3725,16 @@
"version": "0.34.41",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.41.tgz",
"integrity": "sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true
},
"node_modules/@jest/console/node_modules/ansi-styles": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
"integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"engines": {
"node": ">=10"
@@ -3773,21 +3744,20 @@
}
},
"node_modules/@jest/console/node_modules/jest-message-util": {
"version": "30.1.0",
"resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.1.0.tgz",
"integrity": "sha512-HizKDGG98cYkWmaLUHChq4iN+oCENohQLb7Z5guBPumYs+/etonmNFlg1Ps6yN9LTPyZn+M+b/9BbnHx3WTMDg==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.2.0.tgz",
"integrity": "sha512-y4DKFLZ2y6DxTWD4cDe07RglV88ZiNEdlRfGtqahfbIjfsw1nMCPx49Uev4IA/hWn3sDKyAnSPwoYSsAEdcimw==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@babel/code-frame": "^7.27.1",
"@jest/types": "30.0.5",
"@jest/types": "30.2.0",
"@types/stack-utils": "^2.0.3",
"chalk": "^4.1.2",
"graceful-fs": "^4.2.11",
"micromatch": "^4.0.8",
"pretty-format": "30.0.5",
"pretty-format": "30.2.0",
"slash": "^3.0.0",
"stack-utils": "^2.0.6"
},
@@ -3796,15 +3766,14 @@
}
},
"node_modules/@jest/console/node_modules/jest-util": {
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.0.5.tgz",
"integrity": "sha512-pvyPWssDZR0FlfMxCBoc0tvM8iUEskaRFALUtGQYzVEAqisAztmy+R8LnU14KT4XA0H/a5HMVTXat1jLne010g==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.2.0.tgz",
"integrity": "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@jest/types": "30.0.5",
"@jest/types": "30.2.0",
"@types/node": "*",
"chalk": "^4.1.2",
"ci-info": "^4.2.0",
@@ -3819,9 +3788,8 @@
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"engines": {
"node": ">=12"
@@ -3831,12 +3799,11 @@
}
},
"node_modules/@jest/console/node_modules/pretty-format": {
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.0.5.tgz",
"integrity": "sha512-D1tKtYvByrBkFLe2wHJl2bwMJIiT8rW+XA+TiataH79/FszLQMrpGEvzUVkzPau7OCO0Qnrhpe87PqtOAIB8Yw==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.2.0.tgz",
"integrity": "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@jest/schemas": "30.0.5",
@@ -3851,50 +3818,48 @@
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
"integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"engines": {
"node": ">=8"
}
},
"node_modules/@jest/core": {
"version": "30.1.3",
"resolved": "https://registry.npmjs.org/@jest/core/-/core-30.1.3.tgz",
"integrity": "sha512-LIQz7NEDDO1+eyOA2ZmkiAyYvZuo6s1UxD/e2IHldR6D7UYogVq3arTmli07MkENLq6/3JEQjp0mA8rrHHJ8KQ==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/@jest/core/-/core-30.2.0.tgz",
"integrity": "sha512-03W6IhuhjqTlpzh/ojut/pDB2LPRygyWX8ExpgHtQA8H/3K7+1vKmcINx5UzeOX1se6YEsBsOHQ1CRzf3fOwTQ==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@jest/console": "30.1.2",
"@jest/console": "30.2.0",
"@jest/pattern": "30.0.1",
"@jest/reporters": "30.1.3",
"@jest/test-result": "30.1.3",
"@jest/transform": "30.1.2",
"@jest/types": "30.0.5",
"@jest/reporters": "30.2.0",
"@jest/test-result": "30.2.0",
"@jest/transform": "30.2.0",
"@jest/types": "30.2.0",
"@types/node": "*",
"ansi-escapes": "^4.3.2",
"chalk": "^4.1.2",
"ci-info": "^4.2.0",
"exit-x": "^0.2.2",
"graceful-fs": "^4.2.11",
"jest-changed-files": "30.0.5",
"jest-config": "30.1.3",
"jest-haste-map": "30.1.0",
"jest-message-util": "30.1.0",
"jest-changed-files": "30.2.0",
"jest-config": "30.2.0",
"jest-haste-map": "30.2.0",
"jest-message-util": "30.2.0",
"jest-regex-util": "30.0.1",
"jest-resolve": "30.1.3",
"jest-resolve-dependencies": "30.1.3",
"jest-runner": "30.1.3",
"jest-runtime": "30.1.3",
"jest-snapshot": "30.1.2",
"jest-util": "30.0.5",
"jest-validate": "30.1.0",
"jest-watcher": "30.1.3",
"jest-resolve": "30.2.0",
"jest-resolve-dependencies": "30.2.0",
"jest-runner": "30.2.0",
"jest-runtime": "30.2.0",
"jest-snapshot": "30.2.0",
"jest-util": "30.2.0",
"jest-validate": "30.2.0",
"jest-watcher": "30.2.0",
"micromatch": "^4.0.8",
"pretty-format": "30.0.5",
"pretty-format": "30.2.0",
"slash": "^3.0.0"
},
"engines": {
@@ -3910,23 +3875,22 @@
}
},
"node_modules/@jest/core/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==",
"dev": true,
"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==",
"devOptional": true,
"license": "MIT",
"optional": true,
"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",
@@ -3946,9 +3910,8 @@
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz",
"integrity": "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@sinclair/typebox": "^0.34.0"
@@ -3958,25 +3921,24 @@
}
},
"node_modules/@jest/core/node_modules/@jest/transform": {
"version": "30.1.2",
"resolved": "https://registry.npmjs.org/@jest/transform/-/transform-30.1.2.tgz",
"integrity": "sha512-UYYFGifSgfjujf1Cbd3iU/IQoSd6uwsj8XHj5DSDf5ERDcWMdJOPTkHWXj4U+Z/uMagyOQZ6Vne8C4nRIrCxqA==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/@jest/transform/-/transform-30.2.0.tgz",
"integrity": "sha512-XsauDV82o5qXbhalKxD7p4TZYYdwcaEXC77PPD2HixEFF+6YGppjrAAQurTl2ECWcEomHBMMNS9AH3kcCFx8jA==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@babel/core": "^7.27.4",
"@jest/types": "30.0.5",
"@jest/types": "30.2.0",
"@jridgewell/trace-mapping": "^0.3.25",
"babel-plugin-istanbul": "^7.0.0",
"babel-plugin-istanbul": "^7.0.1",
"chalk": "^4.1.2",
"convert-source-map": "^2.0.0",
"fast-json-stable-stringify": "^2.1.0",
"graceful-fs": "^4.2.11",
"jest-haste-map": "30.1.0",
"jest-haste-map": "30.2.0",
"jest-regex-util": "30.0.1",
"jest-util": "30.0.5",
"jest-util": "30.2.0",
"micromatch": "^4.0.8",
"pirates": "^4.0.7",
"slash": "^3.0.0",
@@ -3987,12 +3949,11 @@
}
},
"node_modules/@jest/core/node_modules/@jest/types": {
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-30.0.5.tgz",
"integrity": "sha512-aREYa3aku9SSnea4aX6bhKn4bgv3AXkgijoQgbYV3yvbiGt6z+MQ85+6mIhx9DsKW2BuB/cLR/A+tcMThx+KLQ==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-30.2.0.tgz",
"integrity": "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@jest/pattern": "30.0.1",
@@ -4011,18 +3972,16 @@
"version": "0.34.41",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.41.tgz",
"integrity": "sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true
},
"node_modules/@jest/core/node_modules/ansi-styles": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
"integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"engines": {
"node": ">=10"
@@ -4035,9 +3994,8 @@
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-7.0.1.tgz",
"integrity": "sha512-D8Z6Qm8jCvVXtIRkBnqNHX0zJ37rQcFJ9u8WOS6tkYOsRdHBzypCstaxWiu5ZIlqQtviRYbgnRLSoCEvjqcqbA==",
"dev": true,
"devOptional": true,
"license": "BSD-3-Clause",
"optional": true,
"peer": true,
"workspaces": [
"test/babel-8"
@@ -4057,9 +4015,8 @@
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz",
"integrity": "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==",
"dev": true,
"devOptional": true,
"license": "BSD-3-Clause",
"optional": true,
"peer": true,
"dependencies": {
"@babel/core": "^7.23.9",
@@ -4073,12 +4030,11 @@
}
},
"node_modules/@jest/core/node_modules/istanbul-lib-instrument/node_modules/semver": {
"version": "7.7.2",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz",
"integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==",
"dev": true,
"version": "7.7.3",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz",
"integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==",
"devOptional": true,
"license": "ISC",
"optional": true,
"peer": true,
"bin": {
"semver": "bin/semver.js"
@@ -4088,22 +4044,21 @@
}
},
"node_modules/@jest/core/node_modules/jest-haste-map": {
"version": "30.1.0",
"resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-30.1.0.tgz",
"integrity": "sha512-JLeM84kNjpRkggcGpQLsV7B8W4LNUWz7oDNVnY1Vjj22b5/fAb3kk3htiD+4Na8bmJmjJR7rBtS2Rmq/NEcADg==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-30.2.0.tgz",
"integrity": "sha512-sQA/jCb9kNt+neM0anSj6eZhLZUIhQgwDt7cPGjumgLM4rXsfb9kpnlacmvZz3Q5tb80nS+oG/if+NBKrHC+Xw==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@jest/types": "30.0.5",
"@jest/types": "30.2.0",
"@types/node": "*",
"anymatch": "^3.1.3",
"fb-watchman": "^2.0.2",
"graceful-fs": "^4.2.11",
"jest-regex-util": "30.0.1",
"jest-util": "30.0.5",
"jest-worker": "30.1.0",
"jest-util": "30.2.0",
"jest-worker": "30.2.0",
"micromatch": "^4.0.8",
"walker": "^1.0.8"
},
@@ -4115,21 +4070,20 @@
}
},
"node_modules/@jest/core/node_modules/jest-message-util": {
"version": "30.1.0",
"resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.1.0.tgz",
"integrity": "sha512-HizKDGG98cYkWmaLUHChq4iN+oCENohQLb7Z5guBPumYs+/etonmNFlg1Ps6yN9LTPyZn+M+b/9BbnHx3WTMDg==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.2.0.tgz",
"integrity": "sha512-y4DKFLZ2y6DxTWD4cDe07RglV88ZiNEdlRfGtqahfbIjfsw1nMCPx49Uev4IA/hWn3sDKyAnSPwoYSsAEdcimw==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@babel/code-frame": "^7.27.1",
"@jest/types": "30.0.5",
"@jest/types": "30.2.0",
"@types/stack-utils": "^2.0.3",
"chalk": "^4.1.2",
"graceful-fs": "^4.2.11",
"micromatch": "^4.0.8",
"pretty-format": "30.0.5",
"pretty-format": "30.2.0",
"slash": "^3.0.0",
"stack-utils": "^2.0.6"
},
@@ -4141,24 +4095,22 @@
"version": "30.0.1",
"resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-30.0.1.tgz",
"integrity": "sha512-jHEQgBXAgc+Gh4g0p3bCevgRCVRkB4VB70zhoAE48gxeSr1hfUOsM/C2WoJgVL7Eyg//hudYENbm3Ne+/dRVVA==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"engines": {
"node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
}
},
"node_modules/@jest/core/node_modules/jest-util": {
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.0.5.tgz",
"integrity": "sha512-pvyPWssDZR0FlfMxCBoc0tvM8iUEskaRFALUtGQYzVEAqisAztmy+R8LnU14KT4XA0H/a5HMVTXat1jLne010g==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.2.0.tgz",
"integrity": "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@jest/types": "30.0.5",
"@jest/types": "30.2.0",
"@types/node": "*",
"chalk": "^4.1.2",
"ci-info": "^4.2.0",
@@ -4173,9 +4125,8 @@
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"engines": {
"node": ">=12"
@@ -4185,12 +4136,11 @@
}
},
"node_modules/@jest/core/node_modules/pretty-format": {
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.0.5.tgz",
"integrity": "sha512-D1tKtYvByrBkFLe2wHJl2bwMJIiT8rW+XA+TiataH79/FszLQMrpGEvzUVkzPau7OCO0Qnrhpe87PqtOAIB8Yw==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.2.0.tgz",
"integrity": "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@jest/schemas": "30.0.5",
@@ -4205,9 +4155,8 @@
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
"integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==",
"dev": true,
"devOptional": true,
"license": "ISC",
"optional": true,
"peer": true,
"engines": {
"node": ">=14"
@@ -4220,9 +4169,8 @@
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
"integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"engines": {
"node": ">=8"
@@ -4232,9 +4180,8 @@
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-5.0.1.tgz",
"integrity": "sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==",
"dev": true,
"devOptional": true,
"license": "ISC",
"optional": true,
"peer": true,
"dependencies": {
"imurmurhash": "^0.1.4",
@@ -4248,27 +4195,25 @@
"version": "30.0.1",
"resolved": "https://registry.npmjs.org/@jest/diff-sequences/-/diff-sequences-30.0.1.tgz",
"integrity": "sha512-n5H8QLDJ47QqbCNn5SuFjCRDrOLEZ0h8vAHCK5RL9Ls7Xa8AQLa/YxAc9UjFqoEDM48muwtBGjtMY5cr0PLDCw==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"engines": {
"node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
}
},
"node_modules/@jest/environment": {
"version": "30.1.2",
"resolved": "https://registry.npmjs.org/@jest/environment/-/environment-30.1.2.tgz",
"integrity": "sha512-N8t1Ytw4/mr9uN28OnVf0SYE2dGhaIxOVYcwsf9IInBKjvofAjbFRvedvBBlyTYk2knbJTiEjEJ2PyyDIBnd9w==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/@jest/environment/-/environment-30.2.0.tgz",
"integrity": "sha512-/QPTL7OBJQ5ac09UDRa3EQes4gt1FTEG/8jZ/4v5IVzx+Cv7dLxlVIvfvSVRiiX2drWyXeBjkMSR8hvOWSog5g==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@jest/fake-timers": "30.1.2",
"@jest/types": "30.0.5",
"@jest/fake-timers": "30.2.0",
"@jest/types": "30.2.0",
"@types/node": "*",
"jest-mock": "30.0.5"
"jest-mock": "30.2.0"
},
"engines": {
"node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
@@ -4278,9 +4223,8 @@
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz",
"integrity": "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@sinclair/typebox": "^0.34.0"
@@ -4290,12 +4234,11 @@
}
},
"node_modules/@jest/environment/node_modules/@jest/types": {
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-30.0.5.tgz",
"integrity": "sha512-aREYa3aku9SSnea4aX6bhKn4bgv3AXkgijoQgbYV3yvbiGt6z+MQ85+6mIhx9DsKW2BuB/cLR/A+tcMThx+KLQ==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-30.2.0.tgz",
"integrity": "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@jest/pattern": "30.0.1",
@@ -4314,22 +4257,20 @@
"version": "0.34.41",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.41.tgz",
"integrity": "sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true
},
"node_modules/@jest/expect": {
"version": "30.1.2",
"resolved": "https://registry.npmjs.org/@jest/expect/-/expect-30.1.2.tgz",
"integrity": "sha512-tyaIExOwQRCxPCGNC05lIjWJztDwk2gPDNSDGg1zitXJJ8dC3++G/CRjE5mb2wQsf89+lsgAgqxxNpDLiCViTA==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/@jest/expect/-/expect-30.2.0.tgz",
"integrity": "sha512-V9yxQK5erfzx99Sf+7LbhBwNWEZ9eZay8qQ9+JSC0TrMR1pMDHLMY+BnVPacWU6Jamrh252/IKo4F1Xn/zfiqA==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"expect": "30.1.2",
"jest-snapshot": "30.1.2"
"expect": "30.2.0",
"jest-snapshot": "30.2.0"
},
"engines": {
"node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
@@ -4349,12 +4290,11 @@
}
},
"node_modules/@jest/expect/node_modules/@jest/expect-utils": {
"version": "30.1.2",
"resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-30.1.2.tgz",
"integrity": "sha512-HXy1qT/bfdjCv7iC336ExbqqYtZvljrV8odNdso7dWK9bSeHtLlvwWWC3YSybSPL03Gg5rug6WLCZAZFH72m0A==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-30.2.0.tgz",
"integrity": "sha512-1JnRfhqpD8HGpOmQp180Fo9Zt69zNtC+9lR+kT7NVL05tNXIi+QC8Csz7lfidMoVLPD3FnOtcmp0CEFnxExGEA==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@jest/get-type": "30.1.0"
@@ -4367,9 +4307,8 @@
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz",
"integrity": "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@sinclair/typebox": "^0.34.0"
@@ -4379,12 +4318,11 @@
}
},
"node_modules/@jest/expect/node_modules/@jest/types": {
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-30.0.5.tgz",
"integrity": "sha512-aREYa3aku9SSnea4aX6bhKn4bgv3AXkgijoQgbYV3yvbiGt6z+MQ85+6mIhx9DsKW2BuB/cLR/A+tcMThx+KLQ==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-30.2.0.tgz",
"integrity": "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@jest/pattern": "30.0.1",
@@ -4403,18 +4341,16 @@
"version": "0.34.41",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.41.tgz",
"integrity": "sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true
},
"node_modules/@jest/expect/node_modules/ansi-styles": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
"integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"engines": {
"node": ">=10"
@@ -4424,77 +4360,73 @@
}
},
"node_modules/@jest/expect/node_modules/expect": {
"version": "30.1.2",
"resolved": "https://registry.npmjs.org/expect/-/expect-30.1.2.tgz",
"integrity": "sha512-xvHszRavo28ejws8FpemjhwswGj4w/BetHIL8cU49u4sGyXDw2+p3YbeDbj6xzlxi6kWTjIRSTJ+9sNXPnF0Zg==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/expect/-/expect-30.2.0.tgz",
"integrity": "sha512-u/feCi0GPsI+988gU2FLcsHyAHTU0MX1Wg68NhAnN7z/+C5wqG+CY8J53N9ioe8RXgaoz0nBR/TYMf3AycUuPw==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@jest/expect-utils": "30.1.2",
"@jest/expect-utils": "30.2.0",
"@jest/get-type": "30.1.0",
"jest-matcher-utils": "30.1.2",
"jest-message-util": "30.1.0",
"jest-mock": "30.0.5",
"jest-util": "30.0.5"
"jest-matcher-utils": "30.2.0",
"jest-message-util": "30.2.0",
"jest-mock": "30.2.0",
"jest-util": "30.2.0"
},
"engines": {
"node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
}
},
"node_modules/@jest/expect/node_modules/jest-diff": {
"version": "30.1.2",
"resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-30.1.2.tgz",
"integrity": "sha512-4+prq+9J61mOVXCa4Qp8ZjavdxzrWQXrI80GNxP8f4tkI2syPuPrJgdRPZRrfUTRvIoUwcmNLbqEJy9W800+NQ==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-30.2.0.tgz",
"integrity": "sha512-dQHFo3Pt4/NLlG5z4PxZ/3yZTZ1C7s9hveiOj+GCN+uT109NC2QgsoVZsVOAvbJ3RgKkvyLGXZV9+piDpWbm6A==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@jest/diff-sequences": "30.0.1",
"@jest/get-type": "30.1.0",
"chalk": "^4.1.2",
"pretty-format": "30.0.5"
"pretty-format": "30.2.0"
},
"engines": {
"node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
}
},
"node_modules/@jest/expect/node_modules/jest-matcher-utils": {
"version": "30.1.2",
"resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-30.1.2.tgz",
"integrity": "sha512-7ai16hy4rSbDjvPTuUhuV8nyPBd6EX34HkBsBcBX2lENCuAQ0qKCPb/+lt8OSWUa9WWmGYLy41PrEzkwRwoGZQ==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-30.2.0.tgz",
"integrity": "sha512-dQ94Nq4dbzmUWkQ0ANAWS9tBRfqCrn0bV9AMYdOi/MHW726xn7eQmMeRTpX2ViC00bpNaWXq+7o4lIQ3AX13Hg==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@jest/get-type": "30.1.0",
"chalk": "^4.1.2",
"jest-diff": "30.1.2",
"pretty-format": "30.0.5"
"jest-diff": "30.2.0",
"pretty-format": "30.2.0"
},
"engines": {
"node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
}
},
"node_modules/@jest/expect/node_modules/jest-message-util": {
"version": "30.1.0",
"resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.1.0.tgz",
"integrity": "sha512-HizKDGG98cYkWmaLUHChq4iN+oCENohQLb7Z5guBPumYs+/etonmNFlg1Ps6yN9LTPyZn+M+b/9BbnHx3WTMDg==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.2.0.tgz",
"integrity": "sha512-y4DKFLZ2y6DxTWD4cDe07RglV88ZiNEdlRfGtqahfbIjfsw1nMCPx49Uev4IA/hWn3sDKyAnSPwoYSsAEdcimw==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@babel/code-frame": "^7.27.1",
"@jest/types": "30.0.5",
"@jest/types": "30.2.0",
"@types/stack-utils": "^2.0.3",
"chalk": "^4.1.2",
"graceful-fs": "^4.2.11",
"micromatch": "^4.0.8",
"pretty-format": "30.0.5",
"pretty-format": "30.2.0",
"slash": "^3.0.0",
"stack-utils": "^2.0.6"
},
@@ -4503,15 +4435,14 @@
}
},
"node_modules/@jest/expect/node_modules/jest-util": {
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.0.5.tgz",
"integrity": "sha512-pvyPWssDZR0FlfMxCBoc0tvM8iUEskaRFALUtGQYzVEAqisAztmy+R8LnU14KT4XA0H/a5HMVTXat1jLne010g==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.2.0.tgz",
"integrity": "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@jest/types": "30.0.5",
"@jest/types": "30.2.0",
"@types/node": "*",
"chalk": "^4.1.2",
"ci-info": "^4.2.0",
@@ -4526,9 +4457,8 @@
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"engines": {
"node": ">=12"
@@ -4538,12 +4468,11 @@
}
},
"node_modules/@jest/expect/node_modules/pretty-format": {
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.0.5.tgz",
"integrity": "sha512-D1tKtYvByrBkFLe2wHJl2bwMJIiT8rW+XA+TiataH79/FszLQMrpGEvzUVkzPau7OCO0Qnrhpe87PqtOAIB8Yw==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.2.0.tgz",
"integrity": "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@jest/schemas": "30.0.5",
@@ -4558,29 +4487,27 @@
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
"integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"engines": {
"node": ">=8"
}
},
"node_modules/@jest/fake-timers": {
"version": "30.1.2",
"resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-30.1.2.tgz",
"integrity": "sha512-Beljfv9AYkr9K+ETX9tvV61rJTY706BhBUtiaepQHeEGfe0DbpvUA5Z3fomwc5Xkhns6NWrcFDZn+72fLieUnA==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-30.2.0.tgz",
"integrity": "sha512-HI3tRLjRxAbBy0VO8dqqm7Hb2mIa8d5bg/NJkyQcOk7V118ObQML8RC5luTF/Zsg4474a+gDvhce7eTnP4GhYw==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@jest/types": "30.0.5",
"@jest/types": "30.2.0",
"@sinonjs/fake-timers": "^13.0.0",
"@types/node": "*",
"jest-message-util": "30.1.0",
"jest-mock": "30.0.5",
"jest-util": "30.0.5"
"jest-message-util": "30.2.0",
"jest-mock": "30.2.0",
"jest-util": "30.2.0"
},
"engines": {
"node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
@@ -4590,9 +4517,8 @@
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz",
"integrity": "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@sinclair/typebox": "^0.34.0"
@@ -4602,12 +4528,11 @@
}
},
"node_modules/@jest/fake-timers/node_modules/@jest/types": {
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-30.0.5.tgz",
"integrity": "sha512-aREYa3aku9SSnea4aX6bhKn4bgv3AXkgijoQgbYV3yvbiGt6z+MQ85+6mIhx9DsKW2BuB/cLR/A+tcMThx+KLQ==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-30.2.0.tgz",
"integrity": "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@jest/pattern": "30.0.1",
@@ -4626,18 +4551,16 @@
"version": "0.34.41",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.41.tgz",
"integrity": "sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true
},
"node_modules/@jest/fake-timers/node_modules/ansi-styles": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
"integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"engines": {
"node": ">=10"
@@ -4647,21 +4570,20 @@
}
},
"node_modules/@jest/fake-timers/node_modules/jest-message-util": {
"version": "30.1.0",
"resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.1.0.tgz",
"integrity": "sha512-HizKDGG98cYkWmaLUHChq4iN+oCENohQLb7Z5guBPumYs+/etonmNFlg1Ps6yN9LTPyZn+M+b/9BbnHx3WTMDg==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.2.0.tgz",
"integrity": "sha512-y4DKFLZ2y6DxTWD4cDe07RglV88ZiNEdlRfGtqahfbIjfsw1nMCPx49Uev4IA/hWn3sDKyAnSPwoYSsAEdcimw==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@babel/code-frame": "^7.27.1",
"@jest/types": "30.0.5",
"@jest/types": "30.2.0",
"@types/stack-utils": "^2.0.3",
"chalk": "^4.1.2",
"graceful-fs": "^4.2.11",
"micromatch": "^4.0.8",
"pretty-format": "30.0.5",
"pretty-format": "30.2.0",
"slash": "^3.0.0",
"stack-utils": "^2.0.6"
},
@@ -4670,15 +4592,14 @@
}
},
"node_modules/@jest/fake-timers/node_modules/jest-util": {
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.0.5.tgz",
"integrity": "sha512-pvyPWssDZR0FlfMxCBoc0tvM8iUEskaRFALUtGQYzVEAqisAztmy+R8LnU14KT4XA0H/a5HMVTXat1jLne010g==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.2.0.tgz",
"integrity": "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@jest/types": "30.0.5",
"@jest/types": "30.2.0",
"@types/node": "*",
"chalk": "^4.1.2",
"ci-info": "^4.2.0",
@@ -4693,9 +4614,8 @@
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"engines": {
"node": ">=12"
@@ -4705,12 +4625,11 @@
}
},
"node_modules/@jest/fake-timers/node_modules/pretty-format": {
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.0.5.tgz",
"integrity": "sha512-D1tKtYvByrBkFLe2wHJl2bwMJIiT8rW+XA+TiataH79/FszLQMrpGEvzUVkzPau7OCO0Qnrhpe87PqtOAIB8Yw==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.2.0.tgz",
"integrity": "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@jest/schemas": "30.0.5",
@@ -4725,9 +4644,8 @@
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
"integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"engines": {
"node": ">=8"
@@ -4737,27 +4655,25 @@
"version": "30.1.0",
"resolved": "https://registry.npmjs.org/@jest/get-type/-/get-type-30.1.0.tgz",
"integrity": "sha512-eMbZE2hUnx1WV0pmURZY9XoXPkUYjpc55mb0CrhtdWLtzMQPFvu/rZkTLZFTsdaVQa+Tr4eWAteqcUzoawq/uA==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"engines": {
"node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
}
},
"node_modules/@jest/globals": {
"version": "30.1.2",
"resolved": "https://registry.npmjs.org/@jest/globals/-/globals-30.1.2.tgz",
"integrity": "sha512-teNTPZ8yZe3ahbYnvnVRDeOjr+3pu2uiAtNtrEsiMjVPPj+cXd5E/fr8BL7v/T7F31vYdEHrI5cC/2OoO/vM9A==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/@jest/globals/-/globals-30.2.0.tgz",
"integrity": "sha512-b63wmnKPaK+6ZZfpYhz9K61oybvbI1aMcIs80++JI1O1rR1vaxHUCNqo3ITu6NU0d4V34yZFoHMn/uoKr/Rwfw==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@jest/environment": "30.1.2",
"@jest/expect": "30.1.2",
"@jest/types": "30.0.5",
"jest-mock": "30.0.5"
"@jest/environment": "30.2.0",
"@jest/expect": "30.2.0",
"@jest/types": "30.2.0",
"jest-mock": "30.2.0"
},
"engines": {
"node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
@@ -4767,9 +4683,8 @@
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz",
"integrity": "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@sinclair/typebox": "^0.34.0"
@@ -4779,12 +4694,11 @@
}
},
"node_modules/@jest/globals/node_modules/@jest/types": {
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-30.0.5.tgz",
"integrity": "sha512-aREYa3aku9SSnea4aX6bhKn4bgv3AXkgijoQgbYV3yvbiGt6z+MQ85+6mIhx9DsKW2BuB/cLR/A+tcMThx+KLQ==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-30.2.0.tgz",
"integrity": "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@jest/pattern": "30.0.1",
@@ -4803,18 +4717,16 @@
"version": "0.34.41",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.41.tgz",
"integrity": "sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true
},
"node_modules/@jest/pattern": {
"version": "30.0.1",
"resolved": "https://registry.npmjs.org/@jest/pattern/-/pattern-30.0.1.tgz",
"integrity": "sha512-gWp7NfQW27LaBQz3TITS8L7ZCQ0TLvtmI//4OwlQRx4rnWxcPNIYjxZpDcN4+UlGxgm3jS5QPz8IPTCkb59wZA==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@types/node": "*",
@@ -4828,28 +4740,26 @@
"version": "30.0.1",
"resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-30.0.1.tgz",
"integrity": "sha512-jHEQgBXAgc+Gh4g0p3bCevgRCVRkB4VB70zhoAE48gxeSr1hfUOsM/C2WoJgVL7Eyg//hudYENbm3Ne+/dRVVA==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"engines": {
"node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
}
},
"node_modules/@jest/reporters": {
"version": "30.1.3",
"resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-30.1.3.tgz",
"integrity": "sha512-VWEQmJWfXMOrzdFEOyGjUEOuVXllgZsoPtEHZzfdNz18RmzJ5nlR6kp8hDdY8dDS1yGOXAY7DHT+AOHIPSBV0w==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-30.2.0.tgz",
"integrity": "sha512-DRyW6baWPqKMa9CzeiBjHwjd8XeAyco2Vt8XbcLFjiwCOEKOvy82GJ8QQnJE9ofsxCMPjH4MfH8fCWIHHDKpAQ==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@bcoe/v8-coverage": "^0.2.3",
"@jest/console": "30.1.2",
"@jest/test-result": "30.1.3",
"@jest/transform": "30.1.2",
"@jest/types": "30.0.5",
"@jest/console": "30.2.0",
"@jest/test-result": "30.2.0",
"@jest/transform": "30.2.0",
"@jest/types": "30.2.0",
"@jridgewell/trace-mapping": "^0.3.25",
"@types/node": "*",
"chalk": "^4.1.2",
@@ -4862,9 +4772,9 @@
"istanbul-lib-report": "^3.0.0",
"istanbul-lib-source-maps": "^5.0.0",
"istanbul-reports": "^3.1.3",
"jest-message-util": "30.1.0",
"jest-util": "30.0.5",
"jest-worker": "30.1.0",
"jest-message-util": "30.2.0",
"jest-util": "30.2.0",
"jest-worker": "30.2.0",
"slash": "^3.0.0",
"string-length": "^4.0.2",
"v8-to-istanbul": "^9.0.1"
@@ -4882,23 +4792,22 @@
}
},
"node_modules/@jest/reporters/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==",
"dev": true,
"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==",
"devOptional": true,
"license": "MIT",
"optional": true,
"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",
@@ -4918,9 +4827,8 @@
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz",
"integrity": "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@sinclair/typebox": "^0.34.0"
@@ -4930,25 +4838,24 @@
}
},
"node_modules/@jest/reporters/node_modules/@jest/transform": {
"version": "30.1.2",
"resolved": "https://registry.npmjs.org/@jest/transform/-/transform-30.1.2.tgz",
"integrity": "sha512-UYYFGifSgfjujf1Cbd3iU/IQoSd6uwsj8XHj5DSDf5ERDcWMdJOPTkHWXj4U+Z/uMagyOQZ6Vne8C4nRIrCxqA==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/@jest/transform/-/transform-30.2.0.tgz",
"integrity": "sha512-XsauDV82o5qXbhalKxD7p4TZYYdwcaEXC77PPD2HixEFF+6YGppjrAAQurTl2ECWcEomHBMMNS9AH3kcCFx8jA==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@babel/core": "^7.27.4",
"@jest/types": "30.0.5",
"@jest/types": "30.2.0",
"@jridgewell/trace-mapping": "^0.3.25",
"babel-plugin-istanbul": "^7.0.0",
"babel-plugin-istanbul": "^7.0.1",
"chalk": "^4.1.2",
"convert-source-map": "^2.0.0",
"fast-json-stable-stringify": "^2.1.0",
"graceful-fs": "^4.2.11",
"jest-haste-map": "30.1.0",
"jest-haste-map": "30.2.0",
"jest-regex-util": "30.0.1",
"jest-util": "30.0.5",
"jest-util": "30.2.0",
"micromatch": "^4.0.8",
"pirates": "^4.0.7",
"slash": "^3.0.0",
@@ -4959,12 +4866,11 @@
}
},
"node_modules/@jest/reporters/node_modules/@jest/types": {
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-30.0.5.tgz",
"integrity": "sha512-aREYa3aku9SSnea4aX6bhKn4bgv3AXkgijoQgbYV3yvbiGt6z+MQ85+6mIhx9DsKW2BuB/cLR/A+tcMThx+KLQ==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-30.2.0.tgz",
"integrity": "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@jest/pattern": "30.0.1",
@@ -4983,18 +4889,16 @@
"version": "0.34.41",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.41.tgz",
"integrity": "sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true
},
"node_modules/@jest/reporters/node_modules/ansi-styles": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
"integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"engines": {
"node": ">=10"
@@ -5007,9 +4911,8 @@
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-7.0.1.tgz",
"integrity": "sha512-D8Z6Qm8jCvVXtIRkBnqNHX0zJ37rQcFJ9u8WOS6tkYOsRdHBzypCstaxWiu5ZIlqQtviRYbgnRLSoCEvjqcqbA==",
"dev": true,
"devOptional": true,
"license": "BSD-3-Clause",
"optional": true,
"peer": true,
"workspaces": [
"test/babel-8"
@@ -5029,9 +4932,8 @@
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
"integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"balanced-match": "^1.0.0"
@@ -5041,9 +4943,8 @@
"version": "10.4.5",
"resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz",
"integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==",
"dev": true,
"devOptional": true,
"license": "ISC",
"optional": true,
"peer": true,
"dependencies": {
"foreground-child": "^3.1.0",
@@ -5064,9 +4965,8 @@
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz",
"integrity": "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==",
"dev": true,
"devOptional": true,
"license": "BSD-3-Clause",
"optional": true,
"peer": true,
"dependencies": {
"@babel/core": "^7.23.9",
@@ -5080,12 +4980,11 @@
}
},
"node_modules/@jest/reporters/node_modules/istanbul-lib-instrument/node_modules/semver": {
"version": "7.7.2",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz",
"integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==",
"dev": true,
"version": "7.7.3",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz",
"integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==",
"devOptional": true,
"license": "ISC",
"optional": true,
"peer": true,
"bin": {
"semver": "bin/semver.js"
@@ -5095,22 +4994,21 @@
}
},
"node_modules/@jest/reporters/node_modules/jest-haste-map": {
"version": "30.1.0",
"resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-30.1.0.tgz",
"integrity": "sha512-JLeM84kNjpRkggcGpQLsV7B8W4LNUWz7oDNVnY1Vjj22b5/fAb3kk3htiD+4Na8bmJmjJR7rBtS2Rmq/NEcADg==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-30.2.0.tgz",
"integrity": "sha512-sQA/jCb9kNt+neM0anSj6eZhLZUIhQgwDt7cPGjumgLM4rXsfb9kpnlacmvZz3Q5tb80nS+oG/if+NBKrHC+Xw==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@jest/types": "30.0.5",
"@jest/types": "30.2.0",
"@types/node": "*",
"anymatch": "^3.1.3",
"fb-watchman": "^2.0.2",
"graceful-fs": "^4.2.11",
"jest-regex-util": "30.0.1",
"jest-util": "30.0.5",
"jest-worker": "30.1.0",
"jest-util": "30.2.0",
"jest-worker": "30.2.0",
"micromatch": "^4.0.8",
"walker": "^1.0.8"
},
@@ -5122,21 +5020,20 @@
}
},
"node_modules/@jest/reporters/node_modules/jest-message-util": {
"version": "30.1.0",
"resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.1.0.tgz",
"integrity": "sha512-HizKDGG98cYkWmaLUHChq4iN+oCENohQLb7Z5guBPumYs+/etonmNFlg1Ps6yN9LTPyZn+M+b/9BbnHx3WTMDg==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.2.0.tgz",
"integrity": "sha512-y4DKFLZ2y6DxTWD4cDe07RglV88ZiNEdlRfGtqahfbIjfsw1nMCPx49Uev4IA/hWn3sDKyAnSPwoYSsAEdcimw==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@babel/code-frame": "^7.27.1",
"@jest/types": "30.0.5",
"@jest/types": "30.2.0",
"@types/stack-utils": "^2.0.3",
"chalk": "^4.1.2",
"graceful-fs": "^4.2.11",
"micromatch": "^4.0.8",
"pretty-format": "30.0.5",
"pretty-format": "30.2.0",
"slash": "^3.0.0",
"stack-utils": "^2.0.6"
},
@@ -5148,24 +5045,22 @@
"version": "30.0.1",
"resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-30.0.1.tgz",
"integrity": "sha512-jHEQgBXAgc+Gh4g0p3bCevgRCVRkB4VB70zhoAE48gxeSr1hfUOsM/C2WoJgVL7Eyg//hudYENbm3Ne+/dRVVA==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"engines": {
"node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
}
},
"node_modules/@jest/reporters/node_modules/jest-util": {
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.0.5.tgz",
"integrity": "sha512-pvyPWssDZR0FlfMxCBoc0tvM8iUEskaRFALUtGQYzVEAqisAztmy+R8LnU14KT4XA0H/a5HMVTXat1jLne010g==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.2.0.tgz",
"integrity": "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@jest/types": "30.0.5",
"@jest/types": "30.2.0",
"@types/node": "*",
"chalk": "^4.1.2",
"ci-info": "^4.2.0",
@@ -5180,9 +5075,8 @@
"version": "9.0.5",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
"integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
"dev": true,
"devOptional": true,
"license": "ISC",
"optional": true,
"peer": true,
"dependencies": {
"brace-expansion": "^2.0.1"
@@ -5198,9 +5092,8 @@
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"engines": {
"node": ">=12"
@@ -5210,12 +5103,11 @@
}
},
"node_modules/@jest/reporters/node_modules/pretty-format": {
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.0.5.tgz",
"integrity": "sha512-D1tKtYvByrBkFLe2wHJl2bwMJIiT8rW+XA+TiataH79/FszLQMrpGEvzUVkzPau7OCO0Qnrhpe87PqtOAIB8Yw==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.2.0.tgz",
"integrity": "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@jest/schemas": "30.0.5",
@@ -5230,9 +5122,8 @@
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
"integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==",
"dev": true,
"devOptional": true,
"license": "ISC",
"optional": true,
"peer": true,
"engines": {
"node": ">=14"
@@ -5245,9 +5136,8 @@
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
"integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"engines": {
"node": ">=8"
@@ -5257,9 +5147,8 @@
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-5.0.1.tgz",
"integrity": "sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==",
"dev": true,
"devOptional": true,
"license": "ISC",
"optional": true,
"peer": true,
"dependencies": {
"imurmurhash": "^0.1.4",
@@ -5283,15 +5172,14 @@
}
},
"node_modules/@jest/snapshot-utils": {
"version": "30.1.2",
"resolved": "https://registry.npmjs.org/@jest/snapshot-utils/-/snapshot-utils-30.1.2.tgz",
"integrity": "sha512-vHoMTpimcPSR7OxS2S0V1Cpg8eKDRxucHjoWl5u4RQcnxqQrV3avETiFpl8etn4dqxEGarBeHbIBety/f8mLXw==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/@jest/snapshot-utils/-/snapshot-utils-30.2.0.tgz",
"integrity": "sha512-0aVxM3RH6DaiLcjj/b0KrIBZhSX1373Xci4l3cW5xiUWPctZ59zQ7jj4rqcJQ/Z8JuN/4wX3FpJSa3RssVvCug==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@jest/types": "30.0.5",
"@jest/types": "30.2.0",
"chalk": "^4.1.2",
"graceful-fs": "^4.2.11",
"natural-compare": "^1.4.0"
@@ -5304,9 +5192,8 @@
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz",
"integrity": "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@sinclair/typebox": "^0.34.0"
@@ -5316,12 +5203,11 @@
}
},
"node_modules/@jest/snapshot-utils/node_modules/@jest/types": {
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-30.0.5.tgz",
"integrity": "sha512-aREYa3aku9SSnea4aX6bhKn4bgv3AXkgijoQgbYV3yvbiGt6z+MQ85+6mIhx9DsKW2BuB/cLR/A+tcMThx+KLQ==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-30.2.0.tgz",
"integrity": "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@jest/pattern": "30.0.1",
@@ -5340,18 +5226,16 @@
"version": "0.34.41",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.41.tgz",
"integrity": "sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true
},
"node_modules/@jest/source-map": {
"version": "30.0.1",
"resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-30.0.1.tgz",
"integrity": "sha512-MIRWMUUR3sdbP36oyNyhbThLHyJ2eEDClPCiHVbrYAe5g3CHRArIVpBw7cdSB5fr+ofSfIb2Tnsw8iEHL0PYQg==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@jridgewell/trace-mapping": "^0.3.25",
@@ -5363,16 +5247,15 @@
}
},
"node_modules/@jest/test-result": {
"version": "30.1.3",
"resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-30.1.3.tgz",
"integrity": "sha512-P9IV8T24D43cNRANPPokn7tZh0FAFnYS2HIfi5vK18CjRkTDR9Y3e1BoEcAJnl4ghZZF4Ecda4M/k41QkvurEQ==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-30.2.0.tgz",
"integrity": "sha512-RF+Z+0CCHkARz5HT9mcQCBulb1wgCP3FBvl9VFokMX27acKphwyQsNuWH3c+ojd1LeWBLoTYoxF0zm6S/66mjg==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@jest/console": "30.1.2",
"@jest/types": "30.0.5",
"@jest/console": "30.2.0",
"@jest/types": "30.2.0",
"@types/istanbul-lib-coverage": "^2.0.6",
"collect-v8-coverage": "^1.0.2"
},
@@ -5384,9 +5267,8 @@
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz",
"integrity": "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@sinclair/typebox": "^0.34.0"
@@ -5396,12 +5278,11 @@
}
},
"node_modules/@jest/test-result/node_modules/@jest/types": {
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-30.0.5.tgz",
"integrity": "sha512-aREYa3aku9SSnea4aX6bhKn4bgv3AXkgijoQgbYV3yvbiGt6z+MQ85+6mIhx9DsKW2BuB/cLR/A+tcMThx+KLQ==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-30.2.0.tgz",
"integrity": "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@jest/pattern": "30.0.1",
@@ -5420,23 +5301,21 @@
"version": "0.34.41",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.41.tgz",
"integrity": "sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true
},
"node_modules/@jest/test-sequencer": {
"version": "30.1.3",
"resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-30.1.3.tgz",
"integrity": "sha512-82J+hzC0qeQIiiZDThh+YUadvshdBswi5nuyXlEmXzrhw5ZQSRHeQ5LpVMD/xc8B3wPePvs6VMzHnntxL+4E3w==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-30.2.0.tgz",
"integrity": "sha512-wXKgU/lk8fKXMu/l5Hog1R61bL4q5GCdT6OJvdAFz1P+QrpoFuLU68eoKuVc4RbrTtNnTL5FByhWdLgOPSph+Q==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@jest/test-result": "30.1.3",
"@jest/test-result": "30.2.0",
"graceful-fs": "^4.2.11",
"jest-haste-map": "30.1.0",
"jest-haste-map": "30.2.0",
"slash": "^3.0.0"
},
"engines": {
@@ -5447,9 +5326,8 @@
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz",
"integrity": "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@sinclair/typebox": "^0.34.0"
@@ -5459,12 +5337,11 @@
}
},
"node_modules/@jest/test-sequencer/node_modules/@jest/types": {
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-30.0.5.tgz",
"integrity": "sha512-aREYa3aku9SSnea4aX6bhKn4bgv3AXkgijoQgbYV3yvbiGt6z+MQ85+6mIhx9DsKW2BuB/cLR/A+tcMThx+KLQ==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-30.2.0.tgz",
"integrity": "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@jest/pattern": "30.0.1",
@@ -5483,28 +5360,26 @@
"version": "0.34.41",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.41.tgz",
"integrity": "sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true
},
"node_modules/@jest/test-sequencer/node_modules/jest-haste-map": {
"version": "30.1.0",
"resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-30.1.0.tgz",
"integrity": "sha512-JLeM84kNjpRkggcGpQLsV7B8W4LNUWz7oDNVnY1Vjj22b5/fAb3kk3htiD+4Na8bmJmjJR7rBtS2Rmq/NEcADg==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-30.2.0.tgz",
"integrity": "sha512-sQA/jCb9kNt+neM0anSj6eZhLZUIhQgwDt7cPGjumgLM4rXsfb9kpnlacmvZz3Q5tb80nS+oG/if+NBKrHC+Xw==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@jest/types": "30.0.5",
"@jest/types": "30.2.0",
"@types/node": "*",
"anymatch": "^3.1.3",
"fb-watchman": "^2.0.2",
"graceful-fs": "^4.2.11",
"jest-regex-util": "30.0.1",
"jest-util": "30.0.5",
"jest-worker": "30.1.0",
"jest-util": "30.2.0",
"jest-worker": "30.2.0",
"micromatch": "^4.0.8",
"walker": "^1.0.8"
},
@@ -5519,24 +5394,22 @@
"version": "30.0.1",
"resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-30.0.1.tgz",
"integrity": "sha512-jHEQgBXAgc+Gh4g0p3bCevgRCVRkB4VB70zhoAE48gxeSr1hfUOsM/C2WoJgVL7Eyg//hudYENbm3Ne+/dRVVA==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"engines": {
"node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
}
},
"node_modules/@jest/test-sequencer/node_modules/jest-util": {
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.0.5.tgz",
"integrity": "sha512-pvyPWssDZR0FlfMxCBoc0tvM8iUEskaRFALUtGQYzVEAqisAztmy+R8LnU14KT4XA0H/a5HMVTXat1jLne010g==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.2.0.tgz",
"integrity": "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@jest/types": "30.0.5",
"@jest/types": "30.2.0",
"@types/node": "*",
"chalk": "^4.1.2",
"ci-info": "^4.2.0",
@@ -5551,9 +5424,8 @@
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"engines": {
"node": ">=12"
@@ -5566,9 +5438,8 @@
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
"integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"engines": {
"node": ">=8"
@@ -5814,7 +5685,6 @@
"version": "0.2.12",
"resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.12.tgz",
"integrity": "sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==",
"dev": true,
"license": "MIT",
"optional": true,
"dependencies": {
@@ -5843,7 +5713,6 @@
"version": "2.1.8-no-fsevents.3",
"resolved": "https://registry.npmjs.org/@nicolo-ribaudo/chokidar-2/-/chokidar-2-2.1.8-no-fsevents.3.tgz",
"integrity": "sha512-s88O1aVtXftvp5bCPB7WnmXc5IwOZZ7YPuwNPt+GtOOXpPvad1LfbmjYv+qII7zP6RU2QGnqve27dnLycEnyEQ==",
"dev": true,
"license": "MIT",
"optional": true
},
@@ -7038,9 +6907,9 @@
}
},
"node_modules/@openedx/paragon/node_modules/axios": {
"version": "0.30.2",
"resolved": "https://registry.npmjs.org/axios/-/axios-0.30.2.tgz",
"integrity": "sha512-0pE4RQ4UQi1jKY6p7u6i1Tkzqmu+d+/tHS7Q7rKunWLB9WyilBTpHHpXzPNMDj5hTbK0B0PTLSz07yqMBiF6xg==",
"version": "0.30.3",
"resolved": "https://registry.npmjs.org/axios/-/axios-0.30.3.tgz",
"integrity": "sha512-5/tmEb6TmE/ax3mdXBc/Mi6YdPGxQsv+0p5YlciXWt3PHIn0VamqCXhRMtScnwY3lbgSXLneOuXAKUhgmSRpwg==",
"license": "MIT",
"dependencies": {
"follow-redirects": "^1.15.4",
@@ -7479,9 +7348,8 @@
"version": "0.2.9",
"resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.9.tgz",
"integrity": "sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"engines": {
"node": "^12.20.0 || ^14.18.0 || >=16.0.0"
@@ -7557,9 +7425,9 @@
}
},
"node_modules/@remix-run/router": {
"version": "1.23.0",
"resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.23.0.tgz",
"integrity": "sha512-O3rHJzAQKamUz1fvE0Qaw0xSFqsA/yafi2iqeE0pvdFtCO1viYx8QL6f3Ln/aCCTLxs68SLf0KPM9eSeM8yBnA==",
"version": "1.23.2",
"resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.23.2.tgz",
"integrity": "sha512-Ic6m2U/rMjTkhERIa/0ZtXJP17QUi2CbWE7cqx4J58M8aA3QTfW+2UlQ4psvTX9IO1RfNVhK3pcpdjej7L+t2w==",
"license": "MIT",
"engines": {
"node": ">=14.0.0"
@@ -7614,9 +7482,8 @@
"version": "13.0.5",
"resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-13.0.5.tgz",
"integrity": "sha512-36/hTbH2uaWuGVERyC6da9YwGWnzUZXuPro/F2LfsdOsLnCojz/iSH8MxUt/FD2S5XBSVPhmArFUXcpCQ2Hkiw==",
"dev": true,
"devOptional": true,
"license": "BSD-3-Clause",
"optional": true,
"peer": true,
"dependencies": {
"@sinonjs/commons": "^3.0.1"
@@ -8103,7 +7970,6 @@
"version": "0.10.1",
"resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz",
"integrity": "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==",
"dev": true,
"license": "MIT",
"optional": true,
"dependencies": {
@@ -8491,13 +8357,13 @@
"license": "MIT"
},
"node_modules/@types/react": {
"version": "18.3.24",
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.24.tgz",
"integrity": "sha512-0dLEBsA1kI3OezMBF8nSsb7Nk19ZnsyE1LLhB8r27KbgU5H4pvuqZLdtE+aUkJVoXgTVuA+iLIwmZ0TuK4tx6A==",
"version": "18.3.28",
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.28.tgz",
"integrity": "sha512-z9VXpC7MWrhfWipitjNdgCauoMLRdIILQsAEV+ZesIzBq/oUlxk0m3ApZuMFCXdnS4U7KrI+l3WRUEGQ8K1QKw==",
"license": "MIT",
"dependencies": {
"@types/prop-types": "*",
"csstype": "^3.0.2"
"csstype": "^3.2.2"
}
},
"node_modules/@types/react-dom": {
@@ -8881,9 +8747,8 @@
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz",
"integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==",
"dev": true,
"devOptional": true,
"license": "ISC",
"optional": true,
"peer": true
},
"node_modules/@unrs/resolver-binding-android-arm-eabi": {
@@ -8893,7 +8758,6 @@
"cpu": [
"arm"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -8907,7 +8771,6 @@
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -8921,7 +8784,6 @@
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -8935,7 +8797,6 @@
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -8949,7 +8810,6 @@
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -8963,7 +8823,6 @@
"cpu": [
"arm"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -8977,7 +8836,6 @@
"cpu": [
"arm"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -8991,7 +8849,6 @@
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -9005,7 +8862,6 @@
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -9019,7 +8875,6 @@
"cpu": [
"ppc64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -9033,7 +8888,6 @@
"cpu": [
"riscv64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -9047,7 +8901,6 @@
"cpu": [
"riscv64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -9061,7 +8914,6 @@
"cpu": [
"s390x"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -9075,7 +8927,6 @@
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -9089,7 +8940,6 @@
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -9103,7 +8953,6 @@
"cpu": [
"wasm32"
],
"dev": true,
"license": "MIT",
"optional": true,
"dependencies": {
@@ -9120,7 +8969,6 @@
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -9134,7 +8982,6 @@
"cpu": [
"ia32"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -9148,7 +8995,6 @@
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -10024,25 +9870,27 @@
}
},
"node_modules/axios": {
"version": "1.12.0",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.12.0.tgz",
"integrity": "sha512-oXTDccv8PcfjZmPGlWsPSwtOJCZ/b6W5jAMCNcfwJbCzDckwG0jrYJFaWH1yvivfCXjVzV/SPDEhMB3Q+DSurg==",
"version": "1.13.5",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.13.5.tgz",
"integrity": "sha512-cz4ur7Vb0xS4/KUN0tPWe44eqxrIu31me+fbang3ijiNscE129POzipJJA6zniq2C/Z6sJCjMimjS8Lc/GAs8Q==",
"license": "MIT",
"dependencies": {
"follow-redirects": "^1.15.6",
"form-data": "^4.0.4",
"follow-redirects": "^1.15.11",
"form-data": "^4.0.5",
"proxy-from-env": "^1.1.0"
}
},
"node_modules/axios-cache-interceptor": {
"version": "1.8.0",
"resolved": "https://registry.npmjs.org/axios-cache-interceptor/-/axios-cache-interceptor-1.8.0.tgz",
"integrity": "sha512-cTNnPGJyQkxnWp0EWvE3NRvgURU5cWw/Qx3dIhXyHSM4Ip0c7EEe0I3an0Jwa549m1CAOg57ibj27YRNLmQCcg==",
"version": "1.11.4",
"resolved": "https://registry.npmjs.org/axios-cache-interceptor/-/axios-cache-interceptor-1.11.4.tgz",
"integrity": "sha512-xZ4OZUxdpcFUpZjrqfYlGK0VglpPRKKSoE3vMHrstxolixQNs/MrbMezOAO5uS454hIEcWpnk75RZK26WkPW/g==",
"license": "MIT",
"dependencies": {
"cache-parser": "1.2.5",
"fast-defer": "1.1.8",
"object-code": "1.3.3"
"cache-parser": "^1.2.6",
"fast-defer": "^1.1.9",
"http-vary": "^1.0.3",
"object-code": "^2.0.0",
"try": "^1.0.3"
},
"engines": {
"node": ">=12"
@@ -10370,13 +10218,16 @@
"license": "MIT"
},
"node_modules/baseline-browser-mapping": {
"version": "2.8.6",
"resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.6.tgz",
"integrity": "sha512-wrH5NNqren/QMtKUEEJf7z86YjfqW/2uw3IL3/xpqZUC95SSVIFXYQeeGjL6FT/X68IROu6RMehZQS5foy2BXw==",
"version": "2.10.8",
"resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.8.tgz",
"integrity": "sha512-PCLz/LXGBsNTErbtB6i5u4eLpHeMfi93aUv5duMmj6caNu6IphS4q6UevDnL36sZQv9lrP11dbPKGMaXPwMKfQ==",
"devOptional": true,
"license": "Apache-2.0",
"bin": {
"baseline-browser-mapping": "dist/cli.js"
"baseline-browser-mapping": "dist/cli.cjs"
},
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/batch": {
@@ -10523,9 +10374,9 @@
}
},
"node_modules/browserslist": {
"version": "4.26.2",
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.26.2.tgz",
"integrity": "sha512-ECFzp6uFOSB+dcZ5BK/IBaGWssbSYBHvuMeMt3MMFyhI0Z8SqGgEkBLARgpRH3hutIgPVsALcMwbDrJqPxQ65A==",
"version": "4.28.1",
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz",
"integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==",
"devOptional": true,
"funding": [
{
@@ -10543,11 +10394,11 @@
],
"license": "MIT",
"dependencies": {
"baseline-browser-mapping": "^2.8.3",
"caniuse-lite": "^1.0.30001741",
"electron-to-chromium": "^1.5.218",
"node-releases": "^2.0.21",
"update-browserslist-db": "^1.1.3"
"baseline-browser-mapping": "^2.9.0",
"caniuse-lite": "^1.0.30001759",
"electron-to-chromium": "^1.5.263",
"node-releases": "^2.0.27",
"update-browserslist-db": "^1.2.0"
},
"bin": {
"browserslist": "cli.js"
@@ -10621,9 +10472,9 @@
}
},
"node_modules/cache-parser": {
"version": "1.2.5",
"resolved": "https://registry.npmjs.org/cache-parser/-/cache-parser-1.2.5.tgz",
"integrity": "sha512-Md/4VhAHByQ9frQ15WD6LrMNiVw9AEl/J7vWIXw+sxT6fSOpbtt6LHTp76vy8+bOESPBO94117Hm2bIjlI7XjA==",
"version": "1.2.6",
"resolved": "https://registry.npmjs.org/cache-parser/-/cache-parser-1.2.6.tgz",
"integrity": "sha512-SjjnKlWgrhDrAWKUxAvmZLRGDa6JExMfjSu59/pvpNoI6mEHYSLcLKUw2RtECEOINvf6dxJo35fY+T/scA0SUA==",
"license": "MIT"
},
"node_modules/call-bind": {
@@ -10721,9 +10572,9 @@
}
},
"node_modules/caniuse-lite": {
"version": "1.0.30001743",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001743.tgz",
"integrity": "sha512-e6Ojr7RV14Un7dz6ASD0aZDmQPT/A+eZU+nuTNfjqmRrmkmQlnTNWH0SKmqagx9PeW87UVqapSurtAXifmtdmw==",
"version": "1.0.30001779",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001779.tgz",
"integrity": "sha512-U5og2PN7V4DMgF50YPNtnZJGWVLFjjsN3zb6uMT5VGYIewieDj1upwfuVNXf4Kor+89c3iCRJnSzMD5LmTvsfA==",
"devOptional": true,
"funding": [
{
@@ -10859,7 +10710,7 @@
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.3.0.tgz",
"integrity": "sha512-l+2bNRMiQgcfILUi33labAZYIWlH1kWDp+ecNo5iisRKrbm0xcRyCww71/YU0Fkw0mAFpz9bJayXPjey6vkmaQ==",
"dev": true,
"devOptional": true,
"funding": [
{
"type": "github",
@@ -10867,19 +10718,17 @@
}
],
"license": "MIT",
"optional": true,
"peer": true,
"engines": {
"node": ">=8"
}
},
"node_modules/cjs-module-lexer": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-2.1.0.tgz",
"integrity": "sha512-UX0OwmYRYQQetfrLEZeewIFFI+wSTofC+pMBLNuH3RUuu/xzG1oz84UCEDOSoQlN3fZ4+AzmV50ZYvGqkMh9yA==",
"dev": true,
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-2.1.1.tgz",
"integrity": "sha512-+CmxIZ/L2vNcEfvNtLdU0ZQ6mbq3FZnwAP2PPTiKP+1QOoKwlKlPgb8UKV0Dds7QVaMnHm+FwSft2VB0s/SLjQ==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true
},
"node_modules/classnames": {
@@ -11362,9 +11211,9 @@
"license": "Python-2.0"
},
"node_modules/cosmiconfig/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==",
"devOptional": true,
"license": "MIT",
"dependencies": {
@@ -12243,9 +12092,9 @@
"license": "MIT"
},
"node_modules/csstype": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==",
"version": "3.2.3",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz",
"integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==",
"license": "MIT"
},
"node_modules/damerau-levenshtein": {
@@ -12892,9 +12741,9 @@
"license": "MIT"
},
"node_modules/electron-to-chromium": {
"version": "1.5.222",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.222.tgz",
"integrity": "sha512-gA7psSwSwQRE60CEoLz6JBCQPIxNeuzB2nL8vE03GK/OHxlvykbLyeiumQy1iH5C2f3YbRAZpGCMT12a/9ih9w==",
"version": "1.5.286",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.286.tgz",
"integrity": "sha512-9tfDXhJ4RKFNerfjdCcZfufu49vg620741MNs26a9+bhLThdB+plgMeou98CAaHu/WATj2iHOOHTp1hWtABj2A==",
"devOptional": true,
"license": "ISC"
},
@@ -12966,14 +12815,14 @@
}
},
"node_modules/enhanced-resolve": {
"version": "5.18.3",
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.3.tgz",
"integrity": "sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==",
"version": "5.19.0",
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.19.0.tgz",
"integrity": "sha512-phv3E1Xl4tQOShqSte26C7Fl84EwUdZsyOuSSk9qtAGyyQs2s3jJzComh+Abf4g187lUUAvH+H26omrqia2aGg==",
"devOptional": true,
"license": "MIT",
"dependencies": {
"graceful-fs": "^4.2.4",
"tapable": "^2.2.0"
"tapable": "^2.3.0"
},
"engines": {
"node": ">=10.13.0"
@@ -13141,9 +12990,9 @@
}
},
"node_modules/es-module-lexer": {
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz",
"integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==",
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.0.0.tgz",
"integrity": "sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==",
"devOptional": true,
"license": "MIT"
},
@@ -13261,7 +13110,6 @@
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
"dev": true,
"license": "BSD-3-Clause",
"optional": true,
"engines": {
@@ -14042,9 +13890,9 @@
}
},
"node_modules/eslint/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==",
"devOptional": true,
"license": "MIT",
"dependencies": {
@@ -14239,9 +14087,8 @@
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/exit-x/-/exit-x-0.2.2.tgz",
"integrity": "sha512-+I6B/IkJc1o/2tiURyz/ivu/O0nKNEArIUB5O7zBrlDVJr22SCLH3xTeEry428LvFhRzIA1g8izguxJ/gbNcVQ==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"engines": {
"node": ">= 0.8.0"
@@ -14271,40 +14118,40 @@
"license": "MIT"
},
"node_modules/express": {
"version": "4.21.2",
"resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz",
"integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==",
"version": "4.22.1",
"resolved": "https://registry.npmjs.org/express/-/express-4.22.1.tgz",
"integrity": "sha512-F2X8g9P1X7uCPZMA3MVf9wcTqlyNp7IhH5qPCI0izhaOIYXaW9L535tGA3qmjRzpH+bZczqq7hVKxTR4NWnu+g==",
"devOptional": true,
"license": "MIT",
"dependencies": {
"accepts": "~1.3.8",
"array-flatten": "1.1.1",
"body-parser": "1.20.3",
"content-disposition": "0.5.4",
"body-parser": "~1.20.3",
"content-disposition": "~0.5.4",
"content-type": "~1.0.4",
"cookie": "0.7.1",
"cookie-signature": "1.0.6",
"cookie": "~0.7.1",
"cookie-signature": "~1.0.6",
"debug": "2.6.9",
"depd": "2.0.0",
"encodeurl": "~2.0.0",
"escape-html": "~1.0.3",
"etag": "~1.8.1",
"finalhandler": "1.3.1",
"fresh": "0.5.2",
"http-errors": "2.0.0",
"finalhandler": "~1.3.1",
"fresh": "~0.5.2",
"http-errors": "~2.0.0",
"merge-descriptors": "1.0.3",
"methods": "~1.1.2",
"on-finished": "2.4.1",
"on-finished": "~2.4.1",
"parseurl": "~1.3.3",
"path-to-regexp": "0.1.12",
"path-to-regexp": "~0.1.12",
"proxy-addr": "~2.0.7",
"qs": "6.13.0",
"qs": "~6.14.0",
"range-parser": "~1.2.1",
"safe-buffer": "5.2.1",
"send": "0.19.0",
"serve-static": "1.16.2",
"send": "~0.19.0",
"serve-static": "~1.16.2",
"setprototypeof": "1.2.0",
"statuses": "2.0.1",
"statuses": "~2.0.1",
"type-is": "~1.6.18",
"utils-merge": "1.0.1",
"vary": "~1.1.2"
@@ -14334,6 +14181,22 @@
"devOptional": true,
"license": "MIT"
},
"node_modules/express/node_modules/qs": {
"version": "6.14.1",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.14.1.tgz",
"integrity": "sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ==",
"devOptional": true,
"license": "BSD-3-Clause",
"dependencies": {
"side-channel": "^1.1.0"
},
"engines": {
"node": ">=0.6"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/fast-deep-equal": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
@@ -14342,9 +14205,9 @@
"license": "MIT"
},
"node_modules/fast-defer": {
"version": "1.1.8",
"resolved": "https://registry.npmjs.org/fast-defer/-/fast-defer-1.1.8.tgz",
"integrity": "sha512-lEJeOH5VL5R09j6AA0D4Uvq7AgsHw0dAImQQ+F3iSyHZuAxyQfWobsagGpTcOPvJr3urmKRHrs+Gs9hV+/Qm/Q==",
"version": "1.1.9",
"resolved": "https://registry.npmjs.org/fast-defer/-/fast-defer-1.1.9.tgz",
"integrity": "sha512-JP7Xm9HuePSeTT1DI78NeE9eAQvgNb9qNP2jlyQrcx4jiWM189omV6oyd0xaUPWHPlKmvDzz6H1FfPWIDU+xfg==",
"license": "MIT"
},
"node_modules/fast-glob": {
@@ -14875,9 +14738,9 @@
}
},
"node_modules/form-data": {
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz",
"integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==",
"version": "4.0.5",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz",
"integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==",
"license": "MIT",
"dependencies": {
"asynckit": "^0.4.0",
@@ -14987,7 +14850,6 @@
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
"dev": true,
"hasInstallScript": true,
"license": "MIT",
"optional": true,
@@ -15372,10 +15234,8 @@
"version": "4.7.8",
"resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz",
"integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"minimist": "^1.2.5",
"neo-async": "^2.6.2",
@@ -15396,10 +15256,8 @@
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
"dev": true,
"devOptional": true,
"license": "BSD-3-Clause",
"optional": true,
"peer": true,
"engines": {
"node": ">=0.10.0"
}
@@ -15833,6 +15691,12 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/http-vary": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/http-vary/-/http-vary-1.0.3.tgz",
"integrity": "sha512-sx7Y8YTqF3o0mFJJvF66n8dbaE8v3liV1RgCz46XP5xK7dnzyZHvwMWRA115q5kjbCPBV65/nOMlgW54WLyiag==",
"license": "MIT"
},
"node_modules/https-proxy-agent": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz",
@@ -17030,9 +16894,8 @@
"version": "5.0.6",
"resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-5.0.6.tgz",
"integrity": "sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==",
"dev": true,
"devOptional": true,
"license": "BSD-3-Clause",
"optional": true,
"peer": true,
"dependencies": {
"@jridgewell/trace-mapping": "^0.3.23",
@@ -17091,18 +16954,17 @@
}
},
"node_modules/jest": {
"version": "30.1.3",
"resolved": "https://registry.npmjs.org/jest/-/jest-30.1.3.tgz",
"integrity": "sha512-Ry+p2+NLk6u8Agh5yVqELfUJvRfV51hhVBRIB5yZPY7mU0DGBmOuFG5GebZbMbm86cdQNK0fhJuDX8/1YorISQ==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/jest/-/jest-30.2.0.tgz",
"integrity": "sha512-F26gjC0yWN8uAA5m5Ss8ZQf5nDHWGlN/xWZIh8S5SRbsEKBovwZhxGd6LJlbZYxBgCYOtreSUyb8hpXyGC5O4A==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@jest/core": "30.1.3",
"@jest/types": "30.0.5",
"@jest/core": "30.2.0",
"@jest/types": "30.2.0",
"import-local": "^3.2.0",
"jest-cli": "30.1.3"
"jest-cli": "30.2.0"
},
"bin": {
"jest": "bin/jest.js"
@@ -17120,16 +16982,15 @@
}
},
"node_modules/jest-changed-files": {
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-30.0.5.tgz",
"integrity": "sha512-bGl2Ntdx0eAwXuGpdLdVYVr5YQHnSZlQ0y9HVDu565lCUAe9sj6JOtBbMmBBikGIegne9piDDIOeiLVoqTkz4A==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-30.2.0.tgz",
"integrity": "sha512-L8lR1ChrRnSdfeOvTrwZMlnWV8G/LLjQ0nG9MBclwWZidA2N5FviRki0Bvh20WRMOX31/JYvzdqTJrk5oBdydQ==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"execa": "^5.1.1",
"jest-util": "30.0.5",
"jest-util": "30.2.0",
"p-limit": "^3.1.0"
},
"engines": {
@@ -17140,9 +17001,8 @@
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz",
"integrity": "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@sinclair/typebox": "^0.34.0"
@@ -17152,12 +17012,11 @@
}
},
"node_modules/jest-changed-files/node_modules/@jest/types": {
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-30.0.5.tgz",
"integrity": "sha512-aREYa3aku9SSnea4aX6bhKn4bgv3AXkgijoQgbYV3yvbiGt6z+MQ85+6mIhx9DsKW2BuB/cLR/A+tcMThx+KLQ==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-30.2.0.tgz",
"integrity": "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@jest/pattern": "30.0.1",
@@ -17176,21 +17035,19 @@
"version": "0.34.41",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.41.tgz",
"integrity": "sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true
},
"node_modules/jest-changed-files/node_modules/jest-util": {
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.0.5.tgz",
"integrity": "sha512-pvyPWssDZR0FlfMxCBoc0tvM8iUEskaRFALUtGQYzVEAqisAztmy+R8LnU14KT4XA0H/a5HMVTXat1jLne010g==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.2.0.tgz",
"integrity": "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@jest/types": "30.0.5",
"@jest/types": "30.2.0",
"@types/node": "*",
"chalk": "^4.1.2",
"ci-info": "^4.2.0",
@@ -17205,9 +17062,8 @@
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"engines": {
"node": ">=12"
@@ -17217,31 +17073,30 @@
}
},
"node_modules/jest-circus": {
"version": "30.1.3",
"resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-30.1.3.tgz",
"integrity": "sha512-Yf3dnhRON2GJT4RYzM89t/EXIWNxKTpWTL9BfF3+geFetWP4XSvJjiU1vrWplOiUkmq8cHLiwuhz+XuUp9DscA==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-30.2.0.tgz",
"integrity": "sha512-Fh0096NC3ZkFx05EP2OXCxJAREVxj1BcW/i6EWqqymcgYKWjyyDpral3fMxVcHXg6oZM7iULer9wGRFvfpl+Tg==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@jest/environment": "30.1.2",
"@jest/expect": "30.1.2",
"@jest/test-result": "30.1.3",
"@jest/types": "30.0.5",
"@jest/environment": "30.2.0",
"@jest/expect": "30.2.0",
"@jest/test-result": "30.2.0",
"@jest/types": "30.2.0",
"@types/node": "*",
"chalk": "^4.1.2",
"co": "^4.6.0",
"dedent": "^1.6.0",
"is-generator-fn": "^2.1.0",
"jest-each": "30.1.0",
"jest-matcher-utils": "30.1.2",
"jest-message-util": "30.1.0",
"jest-runtime": "30.1.3",
"jest-snapshot": "30.1.2",
"jest-util": "30.0.5",
"jest-each": "30.2.0",
"jest-matcher-utils": "30.2.0",
"jest-message-util": "30.2.0",
"jest-runtime": "30.2.0",
"jest-snapshot": "30.2.0",
"jest-util": "30.2.0",
"p-limit": "^3.1.0",
"pretty-format": "30.0.5",
"pretty-format": "30.2.0",
"pure-rand": "^7.0.0",
"slash": "^3.0.0",
"stack-utils": "^2.0.6"
@@ -17254,9 +17109,8 @@
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz",
"integrity": "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@sinclair/typebox": "^0.34.0"
@@ -17266,12 +17120,11 @@
}
},
"node_modules/jest-circus/node_modules/@jest/types": {
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-30.0.5.tgz",
"integrity": "sha512-aREYa3aku9SSnea4aX6bhKn4bgv3AXkgijoQgbYV3yvbiGt6z+MQ85+6mIhx9DsKW2BuB/cLR/A+tcMThx+KLQ==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-30.2.0.tgz",
"integrity": "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@jest/pattern": "30.0.1",
@@ -17290,18 +17143,16 @@
"version": "0.34.41",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.41.tgz",
"integrity": "sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true
},
"node_modules/jest-circus/node_modules/ansi-styles": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
"integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"engines": {
"node": ">=10"
@@ -17311,57 +17162,54 @@
}
},
"node_modules/jest-circus/node_modules/jest-diff": {
"version": "30.1.2",
"resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-30.1.2.tgz",
"integrity": "sha512-4+prq+9J61mOVXCa4Qp8ZjavdxzrWQXrI80GNxP8f4tkI2syPuPrJgdRPZRrfUTRvIoUwcmNLbqEJy9W800+NQ==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-30.2.0.tgz",
"integrity": "sha512-dQHFo3Pt4/NLlG5z4PxZ/3yZTZ1C7s9hveiOj+GCN+uT109NC2QgsoVZsVOAvbJ3RgKkvyLGXZV9+piDpWbm6A==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@jest/diff-sequences": "30.0.1",
"@jest/get-type": "30.1.0",
"chalk": "^4.1.2",
"pretty-format": "30.0.5"
"pretty-format": "30.2.0"
},
"engines": {
"node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
}
},
"node_modules/jest-circus/node_modules/jest-matcher-utils": {
"version": "30.1.2",
"resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-30.1.2.tgz",
"integrity": "sha512-7ai16hy4rSbDjvPTuUhuV8nyPBd6EX34HkBsBcBX2lENCuAQ0qKCPb/+lt8OSWUa9WWmGYLy41PrEzkwRwoGZQ==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-30.2.0.tgz",
"integrity": "sha512-dQ94Nq4dbzmUWkQ0ANAWS9tBRfqCrn0bV9AMYdOi/MHW726xn7eQmMeRTpX2ViC00bpNaWXq+7o4lIQ3AX13Hg==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@jest/get-type": "30.1.0",
"chalk": "^4.1.2",
"jest-diff": "30.1.2",
"pretty-format": "30.0.5"
"jest-diff": "30.2.0",
"pretty-format": "30.2.0"
},
"engines": {
"node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
}
},
"node_modules/jest-circus/node_modules/jest-message-util": {
"version": "30.1.0",
"resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.1.0.tgz",
"integrity": "sha512-HizKDGG98cYkWmaLUHChq4iN+oCENohQLb7Z5guBPumYs+/etonmNFlg1Ps6yN9LTPyZn+M+b/9BbnHx3WTMDg==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.2.0.tgz",
"integrity": "sha512-y4DKFLZ2y6DxTWD4cDe07RglV88ZiNEdlRfGtqahfbIjfsw1nMCPx49Uev4IA/hWn3sDKyAnSPwoYSsAEdcimw==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@babel/code-frame": "^7.27.1",
"@jest/types": "30.0.5",
"@jest/types": "30.2.0",
"@types/stack-utils": "^2.0.3",
"chalk": "^4.1.2",
"graceful-fs": "^4.2.11",
"micromatch": "^4.0.8",
"pretty-format": "30.0.5",
"pretty-format": "30.2.0",
"slash": "^3.0.0",
"stack-utils": "^2.0.6"
},
@@ -17370,15 +17218,14 @@
}
},
"node_modules/jest-circus/node_modules/jest-util": {
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.0.5.tgz",
"integrity": "sha512-pvyPWssDZR0FlfMxCBoc0tvM8iUEskaRFALUtGQYzVEAqisAztmy+R8LnU14KT4XA0H/a5HMVTXat1jLne010g==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.2.0.tgz",
"integrity": "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@jest/types": "30.0.5",
"@jest/types": "30.2.0",
"@types/node": "*",
"chalk": "^4.1.2",
"ci-info": "^4.2.0",
@@ -17393,9 +17240,8 @@
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"engines": {
"node": ">=12"
@@ -17405,12 +17251,11 @@
}
},
"node_modules/jest-circus/node_modules/pretty-format": {
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.0.5.tgz",
"integrity": "sha512-D1tKtYvByrBkFLe2wHJl2bwMJIiT8rW+XA+TiataH79/FszLQMrpGEvzUVkzPau7OCO0Qnrhpe87PqtOAIB8Yw==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.2.0.tgz",
"integrity": "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@jest/schemas": "30.0.5",
@@ -17425,32 +17270,30 @@
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
"integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"engines": {
"node": ">=8"
}
},
"node_modules/jest-cli": {
"version": "30.1.3",
"resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-30.1.3.tgz",
"integrity": "sha512-G8E2Ol3OKch1DEeIBl41NP7OiC6LBhfg25Btv+idcusmoUSpqUkbrneMqbW9lVpI/rCKb/uETidb7DNteheuAQ==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-30.2.0.tgz",
"integrity": "sha512-Os9ukIvADX/A9sLt6Zse3+nmHtHaE6hqOsjQtNiugFTbKRHYIYtZXNGNK9NChseXy7djFPjndX1tL0sCTlfpAA==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@jest/core": "30.1.3",
"@jest/test-result": "30.1.3",
"@jest/types": "30.0.5",
"@jest/core": "30.2.0",
"@jest/test-result": "30.2.0",
"@jest/types": "30.2.0",
"chalk": "^4.1.2",
"exit-x": "^0.2.2",
"import-local": "^3.2.0",
"jest-config": "30.1.3",
"jest-util": "30.0.5",
"jest-validate": "30.1.0",
"jest-config": "30.2.0",
"jest-util": "30.2.0",
"jest-validate": "30.2.0",
"yargs": "^17.7.2"
},
"bin": {
@@ -17472,9 +17315,8 @@
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz",
"integrity": "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@sinclair/typebox": "^0.34.0"
@@ -17484,12 +17326,11 @@
}
},
"node_modules/jest-cli/node_modules/@jest/types": {
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-30.0.5.tgz",
"integrity": "sha512-aREYa3aku9SSnea4aX6bhKn4bgv3AXkgijoQgbYV3yvbiGt6z+MQ85+6mIhx9DsKW2BuB/cLR/A+tcMThx+KLQ==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-30.2.0.tgz",
"integrity": "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@jest/pattern": "30.0.1",
@@ -17508,18 +17349,16 @@
"version": "0.34.41",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.41.tgz",
"integrity": "sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true
},
"node_modules/jest-cli/node_modules/cliui": {
"version": "8.0.1",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
"integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
"dev": true,
"devOptional": true,
"license": "ISC",
"optional": true,
"peer": true,
"dependencies": {
"string-width": "^4.2.0",
@@ -17531,15 +17370,14 @@
}
},
"node_modules/jest-cli/node_modules/jest-util": {
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.0.5.tgz",
"integrity": "sha512-pvyPWssDZR0FlfMxCBoc0tvM8iUEskaRFALUtGQYzVEAqisAztmy+R8LnU14KT4XA0H/a5HMVTXat1jLne010g==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.2.0.tgz",
"integrity": "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@jest/types": "30.0.5",
"@jest/types": "30.2.0",
"@types/node": "*",
"chalk": "^4.1.2",
"ci-info": "^4.2.0",
@@ -17554,9 +17392,8 @@
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"engines": {
"node": ">=12"
@@ -17569,9 +17406,8 @@
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
"integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"ansi-styles": "^4.0.0",
@@ -17589,9 +17425,8 @@
"version": "17.7.2",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
"integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"cliui": "^8.0.1",
@@ -17607,36 +17442,35 @@
}
},
"node_modules/jest-config": {
"version": "30.1.3",
"resolved": "https://registry.npmjs.org/jest-config/-/jest-config-30.1.3.tgz",
"integrity": "sha512-M/f7gqdQEPgZNA181Myz+GXCe8jXcJsGjCMXUzRj22FIXsZOyHNte84e0exntOvdPaeh9tA0w+B8qlP2fAezfw==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/jest-config/-/jest-config-30.2.0.tgz",
"integrity": "sha512-g4WkyzFQVWHtu6uqGmQR4CQxz/CH3yDSlhzXMWzNjDx843gYjReZnMRanjRCq5XZFuQrGDxgUaiYWE8BRfVckA==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@babel/core": "^7.27.4",
"@jest/get-type": "30.1.0",
"@jest/pattern": "30.0.1",
"@jest/test-sequencer": "30.1.3",
"@jest/types": "30.0.5",
"babel-jest": "30.1.2",
"@jest/test-sequencer": "30.2.0",
"@jest/types": "30.2.0",
"babel-jest": "30.2.0",
"chalk": "^4.1.2",
"ci-info": "^4.2.0",
"deepmerge": "^4.3.1",
"glob": "^10.3.10",
"graceful-fs": "^4.2.11",
"jest-circus": "30.1.3",
"jest-docblock": "30.0.1",
"jest-environment-node": "30.1.2",
"jest-circus": "30.2.0",
"jest-docblock": "30.2.0",
"jest-environment-node": "30.2.0",
"jest-regex-util": "30.0.1",
"jest-resolve": "30.1.3",
"jest-runner": "30.1.3",
"jest-util": "30.0.5",
"jest-validate": "30.1.0",
"jest-resolve": "30.2.0",
"jest-runner": "30.2.0",
"jest-util": "30.2.0",
"jest-validate": "30.2.0",
"micromatch": "^4.0.8",
"parse-json": "^5.2.0",
"pretty-format": "30.0.5",
"pretty-format": "30.2.0",
"slash": "^3.0.0",
"strip-json-comments": "^3.1.1"
},
@@ -17661,23 +17495,22 @@
}
},
"node_modules/jest-config/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==",
"dev": true,
"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==",
"devOptional": true,
"license": "MIT",
"optional": true,
"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",
@@ -17697,9 +17530,8 @@
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz",
"integrity": "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@sinclair/typebox": "^0.34.0"
@@ -17709,25 +17541,24 @@
}
},
"node_modules/jest-config/node_modules/@jest/transform": {
"version": "30.1.2",
"resolved": "https://registry.npmjs.org/@jest/transform/-/transform-30.1.2.tgz",
"integrity": "sha512-UYYFGifSgfjujf1Cbd3iU/IQoSd6uwsj8XHj5DSDf5ERDcWMdJOPTkHWXj4U+Z/uMagyOQZ6Vne8C4nRIrCxqA==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/@jest/transform/-/transform-30.2.0.tgz",
"integrity": "sha512-XsauDV82o5qXbhalKxD7p4TZYYdwcaEXC77PPD2HixEFF+6YGppjrAAQurTl2ECWcEomHBMMNS9AH3kcCFx8jA==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@babel/core": "^7.27.4",
"@jest/types": "30.0.5",
"@jest/types": "30.2.0",
"@jridgewell/trace-mapping": "^0.3.25",
"babel-plugin-istanbul": "^7.0.0",
"babel-plugin-istanbul": "^7.0.1",
"chalk": "^4.1.2",
"convert-source-map": "^2.0.0",
"fast-json-stable-stringify": "^2.1.0",
"graceful-fs": "^4.2.11",
"jest-haste-map": "30.1.0",
"jest-haste-map": "30.2.0",
"jest-regex-util": "30.0.1",
"jest-util": "30.0.5",
"jest-util": "30.2.0",
"micromatch": "^4.0.8",
"pirates": "^4.0.7",
"slash": "^3.0.0",
@@ -17738,12 +17569,11 @@
}
},
"node_modules/jest-config/node_modules/@jest/types": {
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-30.0.5.tgz",
"integrity": "sha512-aREYa3aku9SSnea4aX6bhKn4bgv3AXkgijoQgbYV3yvbiGt6z+MQ85+6mIhx9DsKW2BuB/cLR/A+tcMThx+KLQ==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-30.2.0.tgz",
"integrity": "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@jest/pattern": "30.0.1",
@@ -17762,18 +17592,16 @@
"version": "0.34.41",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.41.tgz",
"integrity": "sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true
},
"node_modules/jest-config/node_modules/ansi-styles": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
"integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"engines": {
"node": ">=10"
@@ -17783,18 +17611,17 @@
}
},
"node_modules/jest-config/node_modules/babel-jest": {
"version": "30.1.2",
"resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-30.1.2.tgz",
"integrity": "sha512-IQCus1rt9kaSh7PQxLYRY5NmkNrNlU2TpabzwV7T2jljnpdHOcmnYYv8QmE04Li4S3a2Lj8/yXyET5pBarPr6g==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-30.2.0.tgz",
"integrity": "sha512-0YiBEOxWqKkSQWL9nNGGEgndoeL0ZpWrbLMNL5u/Kaxrli3Eaxlt3ZtIDktEvXt4L/R9r3ODr2zKwGM/2BjxVw==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@jest/transform": "30.1.2",
"@jest/transform": "30.2.0",
"@types/babel__core": "^7.20.5",
"babel-plugin-istanbul": "^7.0.0",
"babel-preset-jest": "30.0.1",
"babel-plugin-istanbul": "^7.0.1",
"babel-preset-jest": "30.2.0",
"chalk": "^4.1.2",
"graceful-fs": "^4.2.11",
"slash": "^3.0.0"
@@ -17803,16 +17630,15 @@
"node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
},
"peerDependencies": {
"@babel/core": "^7.11.0"
"@babel/core": "^7.11.0 || ^8.0.0-0"
}
},
"node_modules/jest-config/node_modules/babel-plugin-istanbul": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-7.0.1.tgz",
"integrity": "sha512-D8Z6Qm8jCvVXtIRkBnqNHX0zJ37rQcFJ9u8WOS6tkYOsRdHBzypCstaxWiu5ZIlqQtviRYbgnRLSoCEvjqcqbA==",
"dev": true,
"devOptional": true,
"license": "BSD-3-Clause",
"optional": true,
"peer": true,
"workspaces": [
"test/babel-8"
@@ -17829,16 +17655,13 @@
}
},
"node_modules/jest-config/node_modules/babel-plugin-jest-hoist": {
"version": "30.0.1",
"resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-30.0.1.tgz",
"integrity": "sha512-zTPME3pI50NsFW8ZBaVIOeAxzEY7XHlmWeXXu9srI+9kNfzCUTy8MFan46xOGZY8NZThMqq+e3qZUKsvXbasnQ==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-30.2.0.tgz",
"integrity": "sha512-ftzhzSGMUnOzcCXd6WHdBGMyuwy15Wnn0iyyWGKgBDLxf9/s5ABuraCSpBX2uG0jUg4rqJnxsLc5+oYBqoxVaA==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@babel/template": "^7.27.2",
"@babel/types": "^7.27.3",
"@types/babel__core": "^7.20.5"
},
"engines": {
@@ -17846,31 +17669,29 @@
}
},
"node_modules/jest-config/node_modules/babel-preset-jest": {
"version": "30.0.1",
"resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-30.0.1.tgz",
"integrity": "sha512-+YHejD5iTWI46cZmcc/YtX4gaKBtdqCHCVfuVinizVpbmyjO3zYmeuyFdfA8duRqQZfgCAMlsfmkVbJ+e2MAJw==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-30.2.0.tgz",
"integrity": "sha512-US4Z3NOieAQumwFnYdUWKvUKh8+YSnS/gB3t6YBiz0bskpu7Pine8pPCheNxlPEW4wnUkma2a94YuW2q3guvCQ==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"babel-plugin-jest-hoist": "30.0.1",
"babel-preset-current-node-syntax": "^1.1.0"
"babel-plugin-jest-hoist": "30.2.0",
"babel-preset-current-node-syntax": "^1.2.0"
},
"engines": {
"node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
},
"peerDependencies": {
"@babel/core": "^7.11.0"
"@babel/core": "^7.11.0 || ^8.0.0-beta.1"
}
},
"node_modules/jest-config/node_modules/brace-expansion": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
"integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"balanced-match": "^1.0.0"
@@ -17880,9 +17701,8 @@
"version": "10.4.5",
"resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz",
"integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==",
"dev": true,
"devOptional": true,
"license": "ISC",
"optional": true,
"peer": true,
"dependencies": {
"foreground-child": "^3.1.0",
@@ -17903,9 +17723,8 @@
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz",
"integrity": "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==",
"dev": true,
"devOptional": true,
"license": "BSD-3-Clause",
"optional": true,
"peer": true,
"dependencies": {
"@babel/core": "^7.23.9",
@@ -17919,12 +17738,11 @@
}
},
"node_modules/jest-config/node_modules/istanbul-lib-instrument/node_modules/semver": {
"version": "7.7.2",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz",
"integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==",
"dev": true,
"version": "7.7.3",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz",
"integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==",
"devOptional": true,
"license": "ISC",
"optional": true,
"peer": true,
"bin": {
"semver": "bin/semver.js"
@@ -17934,22 +17752,21 @@
}
},
"node_modules/jest-config/node_modules/jest-haste-map": {
"version": "30.1.0",
"resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-30.1.0.tgz",
"integrity": "sha512-JLeM84kNjpRkggcGpQLsV7B8W4LNUWz7oDNVnY1Vjj22b5/fAb3kk3htiD+4Na8bmJmjJR7rBtS2Rmq/NEcADg==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-30.2.0.tgz",
"integrity": "sha512-sQA/jCb9kNt+neM0anSj6eZhLZUIhQgwDt7cPGjumgLM4rXsfb9kpnlacmvZz3Q5tb80nS+oG/if+NBKrHC+Xw==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@jest/types": "30.0.5",
"@jest/types": "30.2.0",
"@types/node": "*",
"anymatch": "^3.1.3",
"fb-watchman": "^2.0.2",
"graceful-fs": "^4.2.11",
"jest-regex-util": "30.0.1",
"jest-util": "30.0.5",
"jest-worker": "30.1.0",
"jest-util": "30.2.0",
"jest-worker": "30.2.0",
"micromatch": "^4.0.8",
"walker": "^1.0.8"
},
@@ -17964,24 +17781,22 @@
"version": "30.0.1",
"resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-30.0.1.tgz",
"integrity": "sha512-jHEQgBXAgc+Gh4g0p3bCevgRCVRkB4VB70zhoAE48gxeSr1hfUOsM/C2WoJgVL7Eyg//hudYENbm3Ne+/dRVVA==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"engines": {
"node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
}
},
"node_modules/jest-config/node_modules/jest-util": {
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.0.5.tgz",
"integrity": "sha512-pvyPWssDZR0FlfMxCBoc0tvM8iUEskaRFALUtGQYzVEAqisAztmy+R8LnU14KT4XA0H/a5HMVTXat1jLne010g==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.2.0.tgz",
"integrity": "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@jest/types": "30.0.5",
"@jest/types": "30.2.0",
"@types/node": "*",
"chalk": "^4.1.2",
"ci-info": "^4.2.0",
@@ -17996,9 +17811,8 @@
"version": "9.0.5",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
"integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
"dev": true,
"devOptional": true,
"license": "ISC",
"optional": true,
"peer": true,
"dependencies": {
"brace-expansion": "^2.0.1"
@@ -18014,9 +17828,8 @@
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"engines": {
"node": ">=12"
@@ -18026,12 +17839,11 @@
}
},
"node_modules/jest-config/node_modules/pretty-format": {
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.0.5.tgz",
"integrity": "sha512-D1tKtYvByrBkFLe2wHJl2bwMJIiT8rW+XA+TiataH79/FszLQMrpGEvzUVkzPau7OCO0Qnrhpe87PqtOAIB8Yw==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.2.0.tgz",
"integrity": "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@jest/schemas": "30.0.5",
@@ -18046,9 +17858,8 @@
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
"integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==",
"dev": true,
"devOptional": true,
"license": "ISC",
"optional": true,
"peer": true,
"engines": {
"node": ">=14"
@@ -18061,9 +17872,8 @@
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
"integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"engines": {
"node": ">=8"
@@ -18073,9 +17883,8 @@
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-5.0.1.tgz",
"integrity": "sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==",
"dev": true,
"devOptional": true,
"license": "ISC",
"optional": true,
"peer": true,
"dependencies": {
"imurmurhash": "^0.1.4",
@@ -18102,12 +17911,11 @@
}
},
"node_modules/jest-docblock": {
"version": "30.0.1",
"resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-30.0.1.tgz",
"integrity": "sha512-/vF78qn3DYphAaIc3jy4gA7XSAz167n9Bm/wn/1XhTLW7tTBIzXtCJpb/vcmc73NIIeeohCbdL94JasyXUZsGA==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-30.2.0.tgz",
"integrity": "sha512-tR/FFgZKS1CXluOQzZvNH3+0z9jXr3ldGSD8bhyuxvlVUwbeLOGynkunvlTMxchC5urrKndYiwCFC0DLVjpOCA==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"detect-newline": "^3.1.0"
@@ -18117,19 +17925,18 @@
}
},
"node_modules/jest-each": {
"version": "30.1.0",
"resolved": "https://registry.npmjs.org/jest-each/-/jest-each-30.1.0.tgz",
"integrity": "sha512-A+9FKzxPluqogNahpCv04UJvcZ9B3HamqpDNWNKDjtxVRYB8xbZLFuCr8JAJFpNp83CA0anGQFlpQna9Me+/tQ==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/jest-each/-/jest-each-30.2.0.tgz",
"integrity": "sha512-lpWlJlM7bCUf1mfmuqTA8+j2lNURW9eNafOy99knBM01i5CQeY5UH1vZjgT9071nDJac1M4XsbyI44oNOdhlDQ==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@jest/get-type": "30.1.0",
"@jest/types": "30.0.5",
"@jest/types": "30.2.0",
"chalk": "^4.1.2",
"jest-util": "30.0.5",
"pretty-format": "30.0.5"
"jest-util": "30.2.0",
"pretty-format": "30.2.0"
},
"engines": {
"node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
@@ -18139,9 +17946,8 @@
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz",
"integrity": "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@sinclair/typebox": "^0.34.0"
@@ -18151,12 +17957,11 @@
}
},
"node_modules/jest-each/node_modules/@jest/types": {
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-30.0.5.tgz",
"integrity": "sha512-aREYa3aku9SSnea4aX6bhKn4bgv3AXkgijoQgbYV3yvbiGt6z+MQ85+6mIhx9DsKW2BuB/cLR/A+tcMThx+KLQ==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-30.2.0.tgz",
"integrity": "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@jest/pattern": "30.0.1",
@@ -18175,18 +17980,16 @@
"version": "0.34.41",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.41.tgz",
"integrity": "sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true
},
"node_modules/jest-each/node_modules/ansi-styles": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
"integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"engines": {
"node": ">=10"
@@ -18196,15 +17999,14 @@
}
},
"node_modules/jest-each/node_modules/jest-util": {
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.0.5.tgz",
"integrity": "sha512-pvyPWssDZR0FlfMxCBoc0tvM8iUEskaRFALUtGQYzVEAqisAztmy+R8LnU14KT4XA0H/a5HMVTXat1jLne010g==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.2.0.tgz",
"integrity": "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@jest/types": "30.0.5",
"@jest/types": "30.2.0",
"@types/node": "*",
"chalk": "^4.1.2",
"ci-info": "^4.2.0",
@@ -18219,9 +18021,8 @@
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"engines": {
"node": ">=12"
@@ -18231,12 +18032,11 @@
}
},
"node_modules/jest-each/node_modules/pretty-format": {
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.0.5.tgz",
"integrity": "sha512-D1tKtYvByrBkFLe2wHJl2bwMJIiT8rW+XA+TiataH79/FszLQMrpGEvzUVkzPau7OCO0Qnrhpe87PqtOAIB8Yw==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.2.0.tgz",
"integrity": "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@jest/schemas": "30.0.5",
@@ -18335,21 +18135,20 @@
}
},
"node_modules/jest-environment-node": {
"version": "30.1.2",
"resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-30.1.2.tgz",
"integrity": "sha512-w8qBiXtqGWJ9xpJIA98M0EIoq079GOQRQUyse5qg1plShUCQ0Ek1VTTcczqKrn3f24TFAgFtT+4q3aOXvjbsuA==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-30.2.0.tgz",
"integrity": "sha512-ElU8v92QJ9UrYsKrxDIKCxu6PfNj4Hdcktcn0JX12zqNdqWHB0N+hwOnnBBXvjLd2vApZtuLUGs1QSY+MsXoNA==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@jest/environment": "30.1.2",
"@jest/fake-timers": "30.1.2",
"@jest/types": "30.0.5",
"@jest/environment": "30.2.0",
"@jest/fake-timers": "30.2.0",
"@jest/types": "30.2.0",
"@types/node": "*",
"jest-mock": "30.0.5",
"jest-util": "30.0.5",
"jest-validate": "30.1.0"
"jest-mock": "30.2.0",
"jest-util": "30.2.0",
"jest-validate": "30.2.0"
},
"engines": {
"node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
@@ -18359,9 +18158,8 @@
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz",
"integrity": "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@sinclair/typebox": "^0.34.0"
@@ -18371,12 +18169,11 @@
}
},
"node_modules/jest-environment-node/node_modules/@jest/types": {
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-30.0.5.tgz",
"integrity": "sha512-aREYa3aku9SSnea4aX6bhKn4bgv3AXkgijoQgbYV3yvbiGt6z+MQ85+6mIhx9DsKW2BuB/cLR/A+tcMThx+KLQ==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-30.2.0.tgz",
"integrity": "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@jest/pattern": "30.0.1",
@@ -18395,21 +18192,19 @@
"version": "0.34.41",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.41.tgz",
"integrity": "sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true
},
"node_modules/jest-environment-node/node_modules/jest-util": {
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.0.5.tgz",
"integrity": "sha512-pvyPWssDZR0FlfMxCBoc0tvM8iUEskaRFALUtGQYzVEAqisAztmy+R8LnU14KT4XA0H/a5HMVTXat1jLne010g==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.2.0.tgz",
"integrity": "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@jest/types": "30.0.5",
"@jest/types": "30.2.0",
"@types/node": "*",
"chalk": "^4.1.2",
"ci-info": "^4.2.0",
@@ -18424,9 +18219,8 @@
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"engines": {
"node": ">=12"
@@ -18504,16 +18298,15 @@
}
},
"node_modules/jest-leak-detector": {
"version": "30.1.0",
"resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-30.1.0.tgz",
"integrity": "sha512-AoFvJzwxK+4KohH60vRuHaqXfWmeBATFZpzpmzNmYTtmRMiyGPVhkXpBqxUQunw+dQB48bDf4NpUs6ivVbRv1g==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-30.2.0.tgz",
"integrity": "sha512-M6jKAjyzjHG0SrQgwhgZGy9hFazcudwCNovY/9HPIicmNSBuockPSedAP9vlPK6ONFJ1zfyH/M2/YYJxOz5cdQ==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@jest/get-type": "30.1.0",
"pretty-format": "30.0.5"
"pretty-format": "30.2.0"
},
"engines": {
"node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
@@ -18523,9 +18316,8 @@
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz",
"integrity": "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@sinclair/typebox": "^0.34.0"
@@ -18538,18 +18330,16 @@
"version": "0.34.41",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.41.tgz",
"integrity": "sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true
},
"node_modules/jest-leak-detector/node_modules/ansi-styles": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
"integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"engines": {
"node": ">=10"
@@ -18559,12 +18349,11 @@
}
},
"node_modules/jest-leak-detector/node_modules/pretty-format": {
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.0.5.tgz",
"integrity": "sha512-D1tKtYvByrBkFLe2wHJl2bwMJIiT8rW+XA+TiataH79/FszLQMrpGEvzUVkzPau7OCO0Qnrhpe87PqtOAIB8Yw==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.2.0.tgz",
"integrity": "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@jest/schemas": "30.0.5",
@@ -18623,17 +18412,16 @@
}
},
"node_modules/jest-mock": {
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-30.0.5.tgz",
"integrity": "sha512-Od7TyasAAQX/6S+QCbN6vZoWOMwlTtzzGuxJku1GhGanAjz9y+QsQkpScDmETvdc9aSXyJ/Op4rhpMYBWW91wQ==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-30.2.0.tgz",
"integrity": "sha512-JNNNl2rj4b5ICpmAcq+WbLH83XswjPbjH4T7yvGzfAGCPh1rw+xVNbtk+FnRslvt9lkCcdn9i1oAoKUuFsOxRw==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@jest/types": "30.0.5",
"@jest/types": "30.2.0",
"@types/node": "*",
"jest-util": "30.0.5"
"jest-util": "30.2.0"
},
"engines": {
"node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
@@ -18643,9 +18431,8 @@
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz",
"integrity": "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@sinclair/typebox": "^0.34.0"
@@ -18655,12 +18442,11 @@
}
},
"node_modules/jest-mock/node_modules/@jest/types": {
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-30.0.5.tgz",
"integrity": "sha512-aREYa3aku9SSnea4aX6bhKn4bgv3AXkgijoQgbYV3yvbiGt6z+MQ85+6mIhx9DsKW2BuB/cLR/A+tcMThx+KLQ==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-30.2.0.tgz",
"integrity": "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@jest/pattern": "30.0.1",
@@ -18679,21 +18465,19 @@
"version": "0.34.41",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.41.tgz",
"integrity": "sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true
},
"node_modules/jest-mock/node_modules/jest-util": {
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.0.5.tgz",
"integrity": "sha512-pvyPWssDZR0FlfMxCBoc0tvM8iUEskaRFALUtGQYzVEAqisAztmy+R8LnU14KT4XA0H/a5HMVTXat1jLne010g==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.2.0.tgz",
"integrity": "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@jest/types": "30.0.5",
"@jest/types": "30.2.0",
"@types/node": "*",
"chalk": "^4.1.2",
"ci-info": "^4.2.0",
@@ -18708,9 +18492,8 @@
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"engines": {
"node": ">=12"
@@ -18748,20 +18531,19 @@
}
},
"node_modules/jest-resolve": {
"version": "30.1.3",
"resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-30.1.3.tgz",
"integrity": "sha512-DI4PtTqzw9GwELFS41sdMK32Ajp3XZQ8iygeDMWkxlRhm7uUTOFSZFVZABFuxr0jvspn8MAYy54NxZCsuCTSOw==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-30.2.0.tgz",
"integrity": "sha512-TCrHSxPlx3tBY3hWNtRQKbtgLhsXa1WmbJEqBlTBrGafd5fiQFByy2GNCEoGR+Tns8d15GaL9cxEzKOO3GEb2A==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"chalk": "^4.1.2",
"graceful-fs": "^4.2.11",
"jest-haste-map": "30.1.0",
"jest-haste-map": "30.2.0",
"jest-pnp-resolver": "^1.2.3",
"jest-util": "30.0.5",
"jest-validate": "30.1.0",
"jest-util": "30.2.0",
"jest-validate": "30.2.0",
"slash": "^3.0.0",
"unrs-resolver": "^1.7.11"
},
@@ -18770,16 +18552,15 @@
}
},
"node_modules/jest-resolve-dependencies": {
"version": "30.1.3",
"resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-30.1.3.tgz",
"integrity": "sha512-DNfq3WGmuRyHRHfEet+Zm3QOmVFtIarUOQHHryKPc0YL9ROfgWZxl4+aZq/VAzok2SS3gZdniP+dO4zgo59hBg==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-30.2.0.tgz",
"integrity": "sha512-xTOIGug/0RmIe3mmCqCT95yO0vj6JURrn1TKWlNbhiAefJRWINNPgwVkrVgt/YaerPzY3iItufd80v3lOrFJ2w==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"jest-regex-util": "30.0.1",
"jest-snapshot": "30.1.2"
"jest-snapshot": "30.2.0"
},
"engines": {
"node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
@@ -18789,9 +18570,8 @@
"version": "30.0.1",
"resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-30.0.1.tgz",
"integrity": "sha512-jHEQgBXAgc+Gh4g0p3bCevgRCVRkB4VB70zhoAE48gxeSr1hfUOsM/C2WoJgVL7Eyg//hudYENbm3Ne+/dRVVA==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"engines": {
"node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
@@ -18801,9 +18581,8 @@
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz",
"integrity": "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@sinclair/typebox": "^0.34.0"
@@ -18813,12 +18592,11 @@
}
},
"node_modules/jest-resolve/node_modules/@jest/types": {
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-30.0.5.tgz",
"integrity": "sha512-aREYa3aku9SSnea4aX6bhKn4bgv3AXkgijoQgbYV3yvbiGt6z+MQ85+6mIhx9DsKW2BuB/cLR/A+tcMThx+KLQ==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-30.2.0.tgz",
"integrity": "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@jest/pattern": "30.0.1",
@@ -18837,28 +18615,26 @@
"version": "0.34.41",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.41.tgz",
"integrity": "sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true
},
"node_modules/jest-resolve/node_modules/jest-haste-map": {
"version": "30.1.0",
"resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-30.1.0.tgz",
"integrity": "sha512-JLeM84kNjpRkggcGpQLsV7B8W4LNUWz7oDNVnY1Vjj22b5/fAb3kk3htiD+4Na8bmJmjJR7rBtS2Rmq/NEcADg==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-30.2.0.tgz",
"integrity": "sha512-sQA/jCb9kNt+neM0anSj6eZhLZUIhQgwDt7cPGjumgLM4rXsfb9kpnlacmvZz3Q5tb80nS+oG/if+NBKrHC+Xw==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@jest/types": "30.0.5",
"@jest/types": "30.2.0",
"@types/node": "*",
"anymatch": "^3.1.3",
"fb-watchman": "^2.0.2",
"graceful-fs": "^4.2.11",
"jest-regex-util": "30.0.1",
"jest-util": "30.0.5",
"jest-worker": "30.1.0",
"jest-util": "30.2.0",
"jest-worker": "30.2.0",
"micromatch": "^4.0.8",
"walker": "^1.0.8"
},
@@ -18873,24 +18649,22 @@
"version": "30.0.1",
"resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-30.0.1.tgz",
"integrity": "sha512-jHEQgBXAgc+Gh4g0p3bCevgRCVRkB4VB70zhoAE48gxeSr1hfUOsM/C2WoJgVL7Eyg//hudYENbm3Ne+/dRVVA==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"engines": {
"node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
}
},
"node_modules/jest-resolve/node_modules/jest-util": {
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.0.5.tgz",
"integrity": "sha512-pvyPWssDZR0FlfMxCBoc0tvM8iUEskaRFALUtGQYzVEAqisAztmy+R8LnU14KT4XA0H/a5HMVTXat1jLne010g==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.2.0.tgz",
"integrity": "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@jest/types": "30.0.5",
"@jest/types": "30.2.0",
"@types/node": "*",
"chalk": "^4.1.2",
"ci-info": "^4.2.0",
@@ -18905,9 +18679,8 @@
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"engines": {
"node": ">=12"
@@ -18920,43 +18693,41 @@
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
"integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"engines": {
"node": ">=8"
}
},
"node_modules/jest-runner": {
"version": "30.1.3",
"resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-30.1.3.tgz",
"integrity": "sha512-dd1ORcxQraW44Uz029TtXj85W11yvLpDuIzNOlofrC8GN+SgDlgY4BvyxJiVeuabA1t6idjNbX59jLd2oplOGQ==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-30.2.0.tgz",
"integrity": "sha512-PqvZ2B2XEyPEbclp+gV6KO/F1FIFSbIwewRgmROCMBo/aZ6J1w8Qypoj2pEOcg3G2HzLlaP6VUtvwCI8dM3oqQ==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@jest/console": "30.1.2",
"@jest/environment": "30.1.2",
"@jest/test-result": "30.1.3",
"@jest/transform": "30.1.2",
"@jest/types": "30.0.5",
"@jest/console": "30.2.0",
"@jest/environment": "30.2.0",
"@jest/test-result": "30.2.0",
"@jest/transform": "30.2.0",
"@jest/types": "30.2.0",
"@types/node": "*",
"chalk": "^4.1.2",
"emittery": "^0.13.1",
"exit-x": "^0.2.2",
"graceful-fs": "^4.2.11",
"jest-docblock": "30.0.1",
"jest-environment-node": "30.1.2",
"jest-haste-map": "30.1.0",
"jest-leak-detector": "30.1.0",
"jest-message-util": "30.1.0",
"jest-resolve": "30.1.3",
"jest-runtime": "30.1.3",
"jest-util": "30.0.5",
"jest-watcher": "30.1.3",
"jest-worker": "30.1.0",
"jest-docblock": "30.2.0",
"jest-environment-node": "30.2.0",
"jest-haste-map": "30.2.0",
"jest-leak-detector": "30.2.0",
"jest-message-util": "30.2.0",
"jest-resolve": "30.2.0",
"jest-runtime": "30.2.0",
"jest-util": "30.2.0",
"jest-watcher": "30.2.0",
"jest-worker": "30.2.0",
"p-limit": "^3.1.0",
"source-map-support": "0.5.13"
},
@@ -18965,23 +18736,22 @@
}
},
"node_modules/jest-runner/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==",
"dev": true,
"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==",
"devOptional": true,
"license": "MIT",
"optional": true,
"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",
@@ -19001,9 +18771,8 @@
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz",
"integrity": "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@sinclair/typebox": "^0.34.0"
@@ -19013,25 +18782,24 @@
}
},
"node_modules/jest-runner/node_modules/@jest/transform": {
"version": "30.1.2",
"resolved": "https://registry.npmjs.org/@jest/transform/-/transform-30.1.2.tgz",
"integrity": "sha512-UYYFGifSgfjujf1Cbd3iU/IQoSd6uwsj8XHj5DSDf5ERDcWMdJOPTkHWXj4U+Z/uMagyOQZ6Vne8C4nRIrCxqA==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/@jest/transform/-/transform-30.2.0.tgz",
"integrity": "sha512-XsauDV82o5qXbhalKxD7p4TZYYdwcaEXC77PPD2HixEFF+6YGppjrAAQurTl2ECWcEomHBMMNS9AH3kcCFx8jA==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@babel/core": "^7.27.4",
"@jest/types": "30.0.5",
"@jest/types": "30.2.0",
"@jridgewell/trace-mapping": "^0.3.25",
"babel-plugin-istanbul": "^7.0.0",
"babel-plugin-istanbul": "^7.0.1",
"chalk": "^4.1.2",
"convert-source-map": "^2.0.0",
"fast-json-stable-stringify": "^2.1.0",
"graceful-fs": "^4.2.11",
"jest-haste-map": "30.1.0",
"jest-haste-map": "30.2.0",
"jest-regex-util": "30.0.1",
"jest-util": "30.0.5",
"jest-util": "30.2.0",
"micromatch": "^4.0.8",
"pirates": "^4.0.7",
"slash": "^3.0.0",
@@ -19042,12 +18810,11 @@
}
},
"node_modules/jest-runner/node_modules/@jest/types": {
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-30.0.5.tgz",
"integrity": "sha512-aREYa3aku9SSnea4aX6bhKn4bgv3AXkgijoQgbYV3yvbiGt6z+MQ85+6mIhx9DsKW2BuB/cLR/A+tcMThx+KLQ==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-30.2.0.tgz",
"integrity": "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@jest/pattern": "30.0.1",
@@ -19066,18 +18833,16 @@
"version": "0.34.41",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.41.tgz",
"integrity": "sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true
},
"node_modules/jest-runner/node_modules/ansi-styles": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
"integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"engines": {
"node": ">=10"
@@ -19090,9 +18855,8 @@
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-7.0.1.tgz",
"integrity": "sha512-D8Z6Qm8jCvVXtIRkBnqNHX0zJ37rQcFJ9u8WOS6tkYOsRdHBzypCstaxWiu5ZIlqQtviRYbgnRLSoCEvjqcqbA==",
"dev": true,
"devOptional": true,
"license": "BSD-3-Clause",
"optional": true,
"peer": true,
"workspaces": [
"test/babel-8"
@@ -19112,9 +18876,8 @@
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz",
"integrity": "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==",
"dev": true,
"devOptional": true,
"license": "BSD-3-Clause",
"optional": true,
"peer": true,
"dependencies": {
"@babel/core": "^7.23.9",
@@ -19128,12 +18891,11 @@
}
},
"node_modules/jest-runner/node_modules/istanbul-lib-instrument/node_modules/semver": {
"version": "7.7.2",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz",
"integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==",
"dev": true,
"version": "7.7.3",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz",
"integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==",
"devOptional": true,
"license": "ISC",
"optional": true,
"peer": true,
"bin": {
"semver": "bin/semver.js"
@@ -19143,22 +18905,21 @@
}
},
"node_modules/jest-runner/node_modules/jest-haste-map": {
"version": "30.1.0",
"resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-30.1.0.tgz",
"integrity": "sha512-JLeM84kNjpRkggcGpQLsV7B8W4LNUWz7oDNVnY1Vjj22b5/fAb3kk3htiD+4Na8bmJmjJR7rBtS2Rmq/NEcADg==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-30.2.0.tgz",
"integrity": "sha512-sQA/jCb9kNt+neM0anSj6eZhLZUIhQgwDt7cPGjumgLM4rXsfb9kpnlacmvZz3Q5tb80nS+oG/if+NBKrHC+Xw==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@jest/types": "30.0.5",
"@jest/types": "30.2.0",
"@types/node": "*",
"anymatch": "^3.1.3",
"fb-watchman": "^2.0.2",
"graceful-fs": "^4.2.11",
"jest-regex-util": "30.0.1",
"jest-util": "30.0.5",
"jest-worker": "30.1.0",
"jest-util": "30.2.0",
"jest-worker": "30.2.0",
"micromatch": "^4.0.8",
"walker": "^1.0.8"
},
@@ -19170,21 +18931,20 @@
}
},
"node_modules/jest-runner/node_modules/jest-message-util": {
"version": "30.1.0",
"resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.1.0.tgz",
"integrity": "sha512-HizKDGG98cYkWmaLUHChq4iN+oCENohQLb7Z5guBPumYs+/etonmNFlg1Ps6yN9LTPyZn+M+b/9BbnHx3WTMDg==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.2.0.tgz",
"integrity": "sha512-y4DKFLZ2y6DxTWD4cDe07RglV88ZiNEdlRfGtqahfbIjfsw1nMCPx49Uev4IA/hWn3sDKyAnSPwoYSsAEdcimw==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@babel/code-frame": "^7.27.1",
"@jest/types": "30.0.5",
"@jest/types": "30.2.0",
"@types/stack-utils": "^2.0.3",
"chalk": "^4.1.2",
"graceful-fs": "^4.2.11",
"micromatch": "^4.0.8",
"pretty-format": "30.0.5",
"pretty-format": "30.2.0",
"slash": "^3.0.0",
"stack-utils": "^2.0.6"
},
@@ -19196,24 +18956,22 @@
"version": "30.0.1",
"resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-30.0.1.tgz",
"integrity": "sha512-jHEQgBXAgc+Gh4g0p3bCevgRCVRkB4VB70zhoAE48gxeSr1hfUOsM/C2WoJgVL7Eyg//hudYENbm3Ne+/dRVVA==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"engines": {
"node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
}
},
"node_modules/jest-runner/node_modules/jest-util": {
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.0.5.tgz",
"integrity": "sha512-pvyPWssDZR0FlfMxCBoc0tvM8iUEskaRFALUtGQYzVEAqisAztmy+R8LnU14KT4XA0H/a5HMVTXat1jLne010g==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.2.0.tgz",
"integrity": "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@jest/types": "30.0.5",
"@jest/types": "30.2.0",
"@types/node": "*",
"chalk": "^4.1.2",
"ci-info": "^4.2.0",
@@ -19228,9 +18986,8 @@
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"engines": {
"node": ">=12"
@@ -19240,12 +18997,11 @@
}
},
"node_modules/jest-runner/node_modules/pretty-format": {
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.0.5.tgz",
"integrity": "sha512-D1tKtYvByrBkFLe2wHJl2bwMJIiT8rW+XA+TiataH79/FszLQMrpGEvzUVkzPau7OCO0Qnrhpe87PqtOAIB8Yw==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.2.0.tgz",
"integrity": "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@jest/schemas": "30.0.5",
@@ -19260,9 +19016,8 @@
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
"integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==",
"dev": true,
"devOptional": true,
"license": "ISC",
"optional": true,
"peer": true,
"engines": {
"node": ">=14"
@@ -19275,9 +19030,8 @@
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
"integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"engines": {
"node": ">=8"
@@ -19287,9 +19041,8 @@
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-5.0.1.tgz",
"integrity": "sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==",
"dev": true,
"devOptional": true,
"license": "ISC",
"optional": true,
"peer": true,
"dependencies": {
"imurmurhash": "^0.1.4",
@@ -19300,34 +19053,33 @@
}
},
"node_modules/jest-runtime": {
"version": "30.1.3",
"resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-30.1.3.tgz",
"integrity": "sha512-WS8xgjuNSphdIGnleQcJ3AKE4tBKOVP+tKhCD0u+Tb2sBmsU8DxfbBpZX7//+XOz81zVs4eFpJQwBNji2Y07DA==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-30.2.0.tgz",
"integrity": "sha512-p1+GVX/PJqTucvsmERPMgCPvQJpFt4hFbM+VN3n8TMo47decMUcJbt+rgzwrEme0MQUA/R+1de2axftTHkKckg==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@jest/environment": "30.1.2",
"@jest/fake-timers": "30.1.2",
"@jest/globals": "30.1.2",
"@jest/environment": "30.2.0",
"@jest/fake-timers": "30.2.0",
"@jest/globals": "30.2.0",
"@jest/source-map": "30.0.1",
"@jest/test-result": "30.1.3",
"@jest/transform": "30.1.2",
"@jest/types": "30.0.5",
"@jest/test-result": "30.2.0",
"@jest/transform": "30.2.0",
"@jest/types": "30.2.0",
"@types/node": "*",
"chalk": "^4.1.2",
"cjs-module-lexer": "^2.1.0",
"collect-v8-coverage": "^1.0.2",
"glob": "^10.3.10",
"graceful-fs": "^4.2.11",
"jest-haste-map": "30.1.0",
"jest-message-util": "30.1.0",
"jest-mock": "30.0.5",
"jest-haste-map": "30.2.0",
"jest-message-util": "30.2.0",
"jest-mock": "30.2.0",
"jest-regex-util": "30.0.1",
"jest-resolve": "30.1.3",
"jest-snapshot": "30.1.2",
"jest-util": "30.0.5",
"jest-resolve": "30.2.0",
"jest-snapshot": "30.2.0",
"jest-util": "30.2.0",
"slash": "^3.0.0",
"strip-bom": "^4.0.0"
},
@@ -19336,23 +19088,22 @@
}
},
"node_modules/jest-runtime/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==",
"dev": true,
"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==",
"devOptional": true,
"license": "MIT",
"optional": true,
"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",
@@ -19372,9 +19123,8 @@
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz",
"integrity": "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@sinclair/typebox": "^0.34.0"
@@ -19384,25 +19134,24 @@
}
},
"node_modules/jest-runtime/node_modules/@jest/transform": {
"version": "30.1.2",
"resolved": "https://registry.npmjs.org/@jest/transform/-/transform-30.1.2.tgz",
"integrity": "sha512-UYYFGifSgfjujf1Cbd3iU/IQoSd6uwsj8XHj5DSDf5ERDcWMdJOPTkHWXj4U+Z/uMagyOQZ6Vne8C4nRIrCxqA==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/@jest/transform/-/transform-30.2.0.tgz",
"integrity": "sha512-XsauDV82o5qXbhalKxD7p4TZYYdwcaEXC77PPD2HixEFF+6YGppjrAAQurTl2ECWcEomHBMMNS9AH3kcCFx8jA==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@babel/core": "^7.27.4",
"@jest/types": "30.0.5",
"@jest/types": "30.2.0",
"@jridgewell/trace-mapping": "^0.3.25",
"babel-plugin-istanbul": "^7.0.0",
"babel-plugin-istanbul": "^7.0.1",
"chalk": "^4.1.2",
"convert-source-map": "^2.0.0",
"fast-json-stable-stringify": "^2.1.0",
"graceful-fs": "^4.2.11",
"jest-haste-map": "30.1.0",
"jest-haste-map": "30.2.0",
"jest-regex-util": "30.0.1",
"jest-util": "30.0.5",
"jest-util": "30.2.0",
"micromatch": "^4.0.8",
"pirates": "^4.0.7",
"slash": "^3.0.0",
@@ -19413,12 +19162,11 @@
}
},
"node_modules/jest-runtime/node_modules/@jest/types": {
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-30.0.5.tgz",
"integrity": "sha512-aREYa3aku9SSnea4aX6bhKn4bgv3AXkgijoQgbYV3yvbiGt6z+MQ85+6mIhx9DsKW2BuB/cLR/A+tcMThx+KLQ==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-30.2.0.tgz",
"integrity": "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@jest/pattern": "30.0.1",
@@ -19437,18 +19185,16 @@
"version": "0.34.41",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.41.tgz",
"integrity": "sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true
},
"node_modules/jest-runtime/node_modules/ansi-styles": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
"integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"engines": {
"node": ">=10"
@@ -19461,9 +19207,8 @@
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-7.0.1.tgz",
"integrity": "sha512-D8Z6Qm8jCvVXtIRkBnqNHX0zJ37rQcFJ9u8WOS6tkYOsRdHBzypCstaxWiu5ZIlqQtviRYbgnRLSoCEvjqcqbA==",
"dev": true,
"devOptional": true,
"license": "BSD-3-Clause",
"optional": true,
"peer": true,
"workspaces": [
"test/babel-8"
@@ -19483,9 +19228,8 @@
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
"integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"balanced-match": "^1.0.0"
@@ -19495,9 +19239,8 @@
"version": "10.4.5",
"resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz",
"integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==",
"dev": true,
"devOptional": true,
"license": "ISC",
"optional": true,
"peer": true,
"dependencies": {
"foreground-child": "^3.1.0",
@@ -19518,9 +19261,8 @@
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz",
"integrity": "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==",
"dev": true,
"devOptional": true,
"license": "BSD-3-Clause",
"optional": true,
"peer": true,
"dependencies": {
"@babel/core": "^7.23.9",
@@ -19534,12 +19276,11 @@
}
},
"node_modules/jest-runtime/node_modules/istanbul-lib-instrument/node_modules/semver": {
"version": "7.7.2",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz",
"integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==",
"dev": true,
"version": "7.7.3",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz",
"integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==",
"devOptional": true,
"license": "ISC",
"optional": true,
"peer": true,
"bin": {
"semver": "bin/semver.js"
@@ -19549,22 +19290,21 @@
}
},
"node_modules/jest-runtime/node_modules/jest-haste-map": {
"version": "30.1.0",
"resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-30.1.0.tgz",
"integrity": "sha512-JLeM84kNjpRkggcGpQLsV7B8W4LNUWz7oDNVnY1Vjj22b5/fAb3kk3htiD+4Na8bmJmjJR7rBtS2Rmq/NEcADg==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-30.2.0.tgz",
"integrity": "sha512-sQA/jCb9kNt+neM0anSj6eZhLZUIhQgwDt7cPGjumgLM4rXsfb9kpnlacmvZz3Q5tb80nS+oG/if+NBKrHC+Xw==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@jest/types": "30.0.5",
"@jest/types": "30.2.0",
"@types/node": "*",
"anymatch": "^3.1.3",
"fb-watchman": "^2.0.2",
"graceful-fs": "^4.2.11",
"jest-regex-util": "30.0.1",
"jest-util": "30.0.5",
"jest-worker": "30.1.0",
"jest-util": "30.2.0",
"jest-worker": "30.2.0",
"micromatch": "^4.0.8",
"walker": "^1.0.8"
},
@@ -19576,21 +19316,20 @@
}
},
"node_modules/jest-runtime/node_modules/jest-message-util": {
"version": "30.1.0",
"resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.1.0.tgz",
"integrity": "sha512-HizKDGG98cYkWmaLUHChq4iN+oCENohQLb7Z5guBPumYs+/etonmNFlg1Ps6yN9LTPyZn+M+b/9BbnHx3WTMDg==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.2.0.tgz",
"integrity": "sha512-y4DKFLZ2y6DxTWD4cDe07RglV88ZiNEdlRfGtqahfbIjfsw1nMCPx49Uev4IA/hWn3sDKyAnSPwoYSsAEdcimw==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@babel/code-frame": "^7.27.1",
"@jest/types": "30.0.5",
"@jest/types": "30.2.0",
"@types/stack-utils": "^2.0.3",
"chalk": "^4.1.2",
"graceful-fs": "^4.2.11",
"micromatch": "^4.0.8",
"pretty-format": "30.0.5",
"pretty-format": "30.2.0",
"slash": "^3.0.0",
"stack-utils": "^2.0.6"
},
@@ -19602,24 +19341,22 @@
"version": "30.0.1",
"resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-30.0.1.tgz",
"integrity": "sha512-jHEQgBXAgc+Gh4g0p3bCevgRCVRkB4VB70zhoAE48gxeSr1hfUOsM/C2WoJgVL7Eyg//hudYENbm3Ne+/dRVVA==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"engines": {
"node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
}
},
"node_modules/jest-runtime/node_modules/jest-util": {
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.0.5.tgz",
"integrity": "sha512-pvyPWssDZR0FlfMxCBoc0tvM8iUEskaRFALUtGQYzVEAqisAztmy+R8LnU14KT4XA0H/a5HMVTXat1jLne010g==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.2.0.tgz",
"integrity": "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@jest/types": "30.0.5",
"@jest/types": "30.2.0",
"@types/node": "*",
"chalk": "^4.1.2",
"ci-info": "^4.2.0",
@@ -19634,9 +19371,8 @@
"version": "9.0.5",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
"integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
"dev": true,
"devOptional": true,
"license": "ISC",
"optional": true,
"peer": true,
"dependencies": {
"brace-expansion": "^2.0.1"
@@ -19652,9 +19388,8 @@
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"engines": {
"node": ">=12"
@@ -19664,12 +19399,11 @@
}
},
"node_modules/jest-runtime/node_modules/pretty-format": {
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.0.5.tgz",
"integrity": "sha512-D1tKtYvByrBkFLe2wHJl2bwMJIiT8rW+XA+TiataH79/FszLQMrpGEvzUVkzPau7OCO0Qnrhpe87PqtOAIB8Yw==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.2.0.tgz",
"integrity": "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@jest/schemas": "30.0.5",
@@ -19684,9 +19418,8 @@
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
"integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==",
"dev": true,
"devOptional": true,
"license": "ISC",
"optional": true,
"peer": true,
"engines": {
"node": ">=14"
@@ -19699,9 +19432,8 @@
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
"integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"engines": {
"node": ">=8"
@@ -19711,9 +19443,8 @@
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-5.0.1.tgz",
"integrity": "sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==",
"dev": true,
"devOptional": true,
"license": "ISC",
"optional": true,
"peer": true,
"dependencies": {
"imurmurhash": "^0.1.4",
@@ -19724,12 +19455,11 @@
}
},
"node_modules/jest-snapshot": {
"version": "30.1.2",
"resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-30.1.2.tgz",
"integrity": "sha512-4q4+6+1c8B6Cy5pGgFvjDy/Pa6VYRiGu0yQafKkJ9u6wQx4G5PqI2QR6nxTl43yy7IWsINwz6oT4o6tD12a8Dg==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-30.2.0.tgz",
"integrity": "sha512-5WEtTy2jXPFypadKNpbNkZ72puZCa6UjSr/7djeecHWOu7iYhSXSnHScT8wBz3Rn8Ena5d5RYRcsyKIeqG1IyA==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@babel/core": "^7.27.4",
@@ -19737,20 +19467,20 @@
"@babel/plugin-syntax-jsx": "^7.27.1",
"@babel/plugin-syntax-typescript": "^7.27.1",
"@babel/types": "^7.27.3",
"@jest/expect-utils": "30.1.2",
"@jest/expect-utils": "30.2.0",
"@jest/get-type": "30.1.0",
"@jest/snapshot-utils": "30.1.2",
"@jest/transform": "30.1.2",
"@jest/types": "30.0.5",
"babel-preset-current-node-syntax": "^1.1.0",
"@jest/snapshot-utils": "30.2.0",
"@jest/transform": "30.2.0",
"@jest/types": "30.2.0",
"babel-preset-current-node-syntax": "^1.2.0",
"chalk": "^4.1.2",
"expect": "30.1.2",
"expect": "30.2.0",
"graceful-fs": "^4.2.11",
"jest-diff": "30.1.2",
"jest-matcher-utils": "30.1.2",
"jest-message-util": "30.1.0",
"jest-util": "30.0.5",
"pretty-format": "30.0.5",
"jest-diff": "30.2.0",
"jest-matcher-utils": "30.2.0",
"jest-message-util": "30.2.0",
"jest-util": "30.2.0",
"pretty-format": "30.2.0",
"semver": "^7.7.2",
"synckit": "^0.11.8"
},
@@ -19759,23 +19489,22 @@
}
},
"node_modules/jest-snapshot/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==",
"dev": true,
"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==",
"devOptional": true,
"license": "MIT",
"optional": true,
"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",
@@ -19795,21 +19524,19 @@
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"dev": true,
"devOptional": true,
"license": "ISC",
"optional": true,
"peer": true,
"bin": {
"semver": "bin/semver.js"
}
},
"node_modules/jest-snapshot/node_modules/@jest/expect-utils": {
"version": "30.1.2",
"resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-30.1.2.tgz",
"integrity": "sha512-HXy1qT/bfdjCv7iC336ExbqqYtZvljrV8odNdso7dWK9bSeHtLlvwWWC3YSybSPL03Gg5rug6WLCZAZFH72m0A==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-30.2.0.tgz",
"integrity": "sha512-1JnRfhqpD8HGpOmQp180Fo9Zt69zNtC+9lR+kT7NVL05tNXIi+QC8Csz7lfidMoVLPD3FnOtcmp0CEFnxExGEA==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@jest/get-type": "30.1.0"
@@ -19822,9 +19549,8 @@
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz",
"integrity": "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@sinclair/typebox": "^0.34.0"
@@ -19834,25 +19560,24 @@
}
},
"node_modules/jest-snapshot/node_modules/@jest/transform": {
"version": "30.1.2",
"resolved": "https://registry.npmjs.org/@jest/transform/-/transform-30.1.2.tgz",
"integrity": "sha512-UYYFGifSgfjujf1Cbd3iU/IQoSd6uwsj8XHj5DSDf5ERDcWMdJOPTkHWXj4U+Z/uMagyOQZ6Vne8C4nRIrCxqA==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/@jest/transform/-/transform-30.2.0.tgz",
"integrity": "sha512-XsauDV82o5qXbhalKxD7p4TZYYdwcaEXC77PPD2HixEFF+6YGppjrAAQurTl2ECWcEomHBMMNS9AH3kcCFx8jA==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@babel/core": "^7.27.4",
"@jest/types": "30.0.5",
"@jest/types": "30.2.0",
"@jridgewell/trace-mapping": "^0.3.25",
"babel-plugin-istanbul": "^7.0.0",
"babel-plugin-istanbul": "^7.0.1",
"chalk": "^4.1.2",
"convert-source-map": "^2.0.0",
"fast-json-stable-stringify": "^2.1.0",
"graceful-fs": "^4.2.11",
"jest-haste-map": "30.1.0",
"jest-haste-map": "30.2.0",
"jest-regex-util": "30.0.1",
"jest-util": "30.0.5",
"jest-util": "30.2.0",
"micromatch": "^4.0.8",
"pirates": "^4.0.7",
"slash": "^3.0.0",
@@ -19863,12 +19588,11 @@
}
},
"node_modules/jest-snapshot/node_modules/@jest/types": {
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-30.0.5.tgz",
"integrity": "sha512-aREYa3aku9SSnea4aX6bhKn4bgv3AXkgijoQgbYV3yvbiGt6z+MQ85+6mIhx9DsKW2BuB/cLR/A+tcMThx+KLQ==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-30.2.0.tgz",
"integrity": "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@jest/pattern": "30.0.1",
@@ -19887,18 +19611,16 @@
"version": "0.34.41",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.41.tgz",
"integrity": "sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true
},
"node_modules/jest-snapshot/node_modules/ansi-styles": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
"integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"engines": {
"node": ">=10"
@@ -19911,9 +19633,8 @@
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-7.0.1.tgz",
"integrity": "sha512-D8Z6Qm8jCvVXtIRkBnqNHX0zJ37rQcFJ9u8WOS6tkYOsRdHBzypCstaxWiu5ZIlqQtviRYbgnRLSoCEvjqcqbA==",
"dev": true,
"devOptional": true,
"license": "BSD-3-Clause",
"optional": true,
"peer": true,
"workspaces": [
"test/babel-8"
@@ -19930,20 +19651,19 @@
}
},
"node_modules/jest-snapshot/node_modules/expect": {
"version": "30.1.2",
"resolved": "https://registry.npmjs.org/expect/-/expect-30.1.2.tgz",
"integrity": "sha512-xvHszRavo28ejws8FpemjhwswGj4w/BetHIL8cU49u4sGyXDw2+p3YbeDbj6xzlxi6kWTjIRSTJ+9sNXPnF0Zg==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/expect/-/expect-30.2.0.tgz",
"integrity": "sha512-u/feCi0GPsI+988gU2FLcsHyAHTU0MX1Wg68NhAnN7z/+C5wqG+CY8J53N9ioe8RXgaoz0nBR/TYMf3AycUuPw==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@jest/expect-utils": "30.1.2",
"@jest/expect-utils": "30.2.0",
"@jest/get-type": "30.1.0",
"jest-matcher-utils": "30.1.2",
"jest-message-util": "30.1.0",
"jest-mock": "30.0.5",
"jest-util": "30.0.5"
"jest-matcher-utils": "30.2.0",
"jest-message-util": "30.2.0",
"jest-mock": "30.2.0",
"jest-util": "30.2.0"
},
"engines": {
"node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
@@ -19953,9 +19673,8 @@
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz",
"integrity": "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==",
"dev": true,
"devOptional": true,
"license": "BSD-3-Clause",
"optional": true,
"peer": true,
"dependencies": {
"@babel/core": "^7.23.9",
@@ -19969,40 +19688,38 @@
}
},
"node_modules/jest-snapshot/node_modules/jest-diff": {
"version": "30.1.2",
"resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-30.1.2.tgz",
"integrity": "sha512-4+prq+9J61mOVXCa4Qp8ZjavdxzrWQXrI80GNxP8f4tkI2syPuPrJgdRPZRrfUTRvIoUwcmNLbqEJy9W800+NQ==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-30.2.0.tgz",
"integrity": "sha512-dQHFo3Pt4/NLlG5z4PxZ/3yZTZ1C7s9hveiOj+GCN+uT109NC2QgsoVZsVOAvbJ3RgKkvyLGXZV9+piDpWbm6A==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@jest/diff-sequences": "30.0.1",
"@jest/get-type": "30.1.0",
"chalk": "^4.1.2",
"pretty-format": "30.0.5"
"pretty-format": "30.2.0"
},
"engines": {
"node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
}
},
"node_modules/jest-snapshot/node_modules/jest-haste-map": {
"version": "30.1.0",
"resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-30.1.0.tgz",
"integrity": "sha512-JLeM84kNjpRkggcGpQLsV7B8W4LNUWz7oDNVnY1Vjj22b5/fAb3kk3htiD+4Na8bmJmjJR7rBtS2Rmq/NEcADg==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-30.2.0.tgz",
"integrity": "sha512-sQA/jCb9kNt+neM0anSj6eZhLZUIhQgwDt7cPGjumgLM4rXsfb9kpnlacmvZz3Q5tb80nS+oG/if+NBKrHC+Xw==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@jest/types": "30.0.5",
"@jest/types": "30.2.0",
"@types/node": "*",
"anymatch": "^3.1.3",
"fb-watchman": "^2.0.2",
"graceful-fs": "^4.2.11",
"jest-regex-util": "30.0.1",
"jest-util": "30.0.5",
"jest-worker": "30.1.0",
"jest-util": "30.2.0",
"jest-worker": "30.2.0",
"micromatch": "^4.0.8",
"walker": "^1.0.8"
},
@@ -20014,39 +19731,37 @@
}
},
"node_modules/jest-snapshot/node_modules/jest-matcher-utils": {
"version": "30.1.2",
"resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-30.1.2.tgz",
"integrity": "sha512-7ai16hy4rSbDjvPTuUhuV8nyPBd6EX34HkBsBcBX2lENCuAQ0qKCPb/+lt8OSWUa9WWmGYLy41PrEzkwRwoGZQ==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-30.2.0.tgz",
"integrity": "sha512-dQ94Nq4dbzmUWkQ0ANAWS9tBRfqCrn0bV9AMYdOi/MHW726xn7eQmMeRTpX2ViC00bpNaWXq+7o4lIQ3AX13Hg==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@jest/get-type": "30.1.0",
"chalk": "^4.1.2",
"jest-diff": "30.1.2",
"pretty-format": "30.0.5"
"jest-diff": "30.2.0",
"pretty-format": "30.2.0"
},
"engines": {
"node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
}
},
"node_modules/jest-snapshot/node_modules/jest-message-util": {
"version": "30.1.0",
"resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.1.0.tgz",
"integrity": "sha512-HizKDGG98cYkWmaLUHChq4iN+oCENohQLb7Z5guBPumYs+/etonmNFlg1Ps6yN9LTPyZn+M+b/9BbnHx3WTMDg==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.2.0.tgz",
"integrity": "sha512-y4DKFLZ2y6DxTWD4cDe07RglV88ZiNEdlRfGtqahfbIjfsw1nMCPx49Uev4IA/hWn3sDKyAnSPwoYSsAEdcimw==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@babel/code-frame": "^7.27.1",
"@jest/types": "30.0.5",
"@jest/types": "30.2.0",
"@types/stack-utils": "^2.0.3",
"chalk": "^4.1.2",
"graceful-fs": "^4.2.11",
"micromatch": "^4.0.8",
"pretty-format": "30.0.5",
"pretty-format": "30.2.0",
"slash": "^3.0.0",
"stack-utils": "^2.0.6"
},
@@ -20058,24 +19773,22 @@
"version": "30.0.1",
"resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-30.0.1.tgz",
"integrity": "sha512-jHEQgBXAgc+Gh4g0p3bCevgRCVRkB4VB70zhoAE48gxeSr1hfUOsM/C2WoJgVL7Eyg//hudYENbm3Ne+/dRVVA==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"engines": {
"node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
}
},
"node_modules/jest-snapshot/node_modules/jest-util": {
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.0.5.tgz",
"integrity": "sha512-pvyPWssDZR0FlfMxCBoc0tvM8iUEskaRFALUtGQYzVEAqisAztmy+R8LnU14KT4XA0H/a5HMVTXat1jLne010g==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.2.0.tgz",
"integrity": "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@jest/types": "30.0.5",
"@jest/types": "30.2.0",
"@types/node": "*",
"chalk": "^4.1.2",
"ci-info": "^4.2.0",
@@ -20090,9 +19803,8 @@
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"engines": {
"node": ">=12"
@@ -20102,12 +19814,11 @@
}
},
"node_modules/jest-snapshot/node_modules/pretty-format": {
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.0.5.tgz",
"integrity": "sha512-D1tKtYvByrBkFLe2wHJl2bwMJIiT8rW+XA+TiataH79/FszLQMrpGEvzUVkzPau7OCO0Qnrhpe87PqtOAIB8Yw==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.2.0.tgz",
"integrity": "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@jest/schemas": "30.0.5",
@@ -20119,12 +19830,11 @@
}
},
"node_modules/jest-snapshot/node_modules/semver": {
"version": "7.7.2",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz",
"integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==",
"dev": true,
"version": "7.7.3",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz",
"integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==",
"devOptional": true,
"license": "ISC",
"optional": true,
"peer": true,
"bin": {
"semver": "bin/semver.js"
@@ -20137,9 +19847,8 @@
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
"integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==",
"dev": true,
"devOptional": true,
"license": "ISC",
"optional": true,
"peer": true,
"engines": {
"node": ">=14"
@@ -20152,9 +19861,8 @@
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
"integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"engines": {
"node": ">=8"
@@ -20164,9 +19872,8 @@
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-5.0.1.tgz",
"integrity": "sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==",
"dev": true,
"devOptional": true,
"license": "ISC",
"optional": true,
"peer": true,
"dependencies": {
"imurmurhash": "^0.1.4",
@@ -20211,20 +19918,19 @@
}
},
"node_modules/jest-validate": {
"version": "30.1.0",
"resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-30.1.0.tgz",
"integrity": "sha512-7P3ZlCFW/vhfQ8pE7zW6Oi4EzvuB4sgR72Q1INfW9m0FGo0GADYlPwIkf4CyPq7wq85g+kPMtPOHNAdWHeBOaA==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-30.2.0.tgz",
"integrity": "sha512-FBGWi7dP2hpdi8nBoWxSsLvBFewKAg0+uSQwBaof4Y4DPgBabXgpSYC5/lR7VmnIlSpASmCi/ntRWPbv7089Pw==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@jest/get-type": "30.1.0",
"@jest/types": "30.0.5",
"@jest/types": "30.2.0",
"camelcase": "^6.3.0",
"chalk": "^4.1.2",
"leven": "^3.1.0",
"pretty-format": "30.0.5"
"pretty-format": "30.2.0"
},
"engines": {
"node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
@@ -20234,9 +19940,8 @@
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz",
"integrity": "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@sinclair/typebox": "^0.34.0"
@@ -20246,12 +19951,11 @@
}
},
"node_modules/jest-validate/node_modules/@jest/types": {
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-30.0.5.tgz",
"integrity": "sha512-aREYa3aku9SSnea4aX6bhKn4bgv3AXkgijoQgbYV3yvbiGt6z+MQ85+6mIhx9DsKW2BuB/cLR/A+tcMThx+KLQ==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-30.2.0.tgz",
"integrity": "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@jest/pattern": "30.0.1",
@@ -20270,18 +19974,16 @@
"version": "0.34.41",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.41.tgz",
"integrity": "sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true
},
"node_modules/jest-validate/node_modules/ansi-styles": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
"integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"engines": {
"node": ">=10"
@@ -20291,12 +19993,11 @@
}
},
"node_modules/jest-validate/node_modules/pretty-format": {
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.0.5.tgz",
"integrity": "sha512-D1tKtYvByrBkFLe2wHJl2bwMJIiT8rW+XA+TiataH79/FszLQMrpGEvzUVkzPau7OCO0Qnrhpe87PqtOAIB8Yw==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.2.0.tgz",
"integrity": "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@jest/schemas": "30.0.5",
@@ -20308,21 +20009,20 @@
}
},
"node_modules/jest-watcher": {
"version": "30.1.3",
"resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-30.1.3.tgz",
"integrity": "sha512-6jQUZCP1BTL2gvG9E4YF06Ytq4yMb4If6YoQGRR6PpjtqOXSP3sKe2kqwB6SQ+H9DezOfZaSLnmka1NtGm3fCQ==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-30.2.0.tgz",
"integrity": "sha512-PYxa28dxJ9g777pGm/7PrbnMeA0Jr7osHP9bS7eJy9DuAjMgdGtxgf0uKMyoIsTWAkIbUW5hSDdJ3urmgXBqxg==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@jest/test-result": "30.1.3",
"@jest/types": "30.0.5",
"@jest/test-result": "30.2.0",
"@jest/types": "30.2.0",
"@types/node": "*",
"ansi-escapes": "^4.3.2",
"chalk": "^4.1.2",
"emittery": "^0.13.1",
"jest-util": "30.0.5",
"jest-util": "30.2.0",
"string-length": "^4.0.2"
},
"engines": {
@@ -20333,9 +20033,8 @@
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz",
"integrity": "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@sinclair/typebox": "^0.34.0"
@@ -20345,12 +20044,11 @@
}
},
"node_modules/jest-watcher/node_modules/@jest/types": {
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-30.0.5.tgz",
"integrity": "sha512-aREYa3aku9SSnea4aX6bhKn4bgv3AXkgijoQgbYV3yvbiGt6z+MQ85+6mIhx9DsKW2BuB/cLR/A+tcMThx+KLQ==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-30.2.0.tgz",
"integrity": "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@jest/pattern": "30.0.1",
@@ -20369,21 +20067,19 @@
"version": "0.34.41",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.41.tgz",
"integrity": "sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true
},
"node_modules/jest-watcher/node_modules/jest-util": {
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.0.5.tgz",
"integrity": "sha512-pvyPWssDZR0FlfMxCBoc0tvM8iUEskaRFALUtGQYzVEAqisAztmy+R8LnU14KT4XA0H/a5HMVTXat1jLne010g==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.2.0.tgz",
"integrity": "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@jest/types": "30.0.5",
"@jest/types": "30.2.0",
"@types/node": "*",
"chalk": "^4.1.2",
"ci-info": "^4.2.0",
@@ -20398,9 +20094,8 @@
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"engines": {
"node": ">=12"
@@ -20410,17 +20105,16 @@
}
},
"node_modules/jest-worker": {
"version": "30.1.0",
"resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-30.1.0.tgz",
"integrity": "sha512-uvWcSjlwAAgIu133Tt77A05H7RIk3Ho8tZL50bQM2AkvLdluw9NG48lRCl3Dt+MOH719n/0nnb5YxUwcuJiKRA==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-30.2.0.tgz",
"integrity": "sha512-0Q4Uk8WF7BUwqXHuAjc23vmopWJw5WH7w2tqBoUOZpOjW/ZnR44GXXd1r82RvnmI2GZge3ivrYXk/BE2+VtW2g==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@types/node": "*",
"@ungap/structured-clone": "^1.3.0",
"jest-util": "30.0.5",
"jest-util": "30.2.0",
"merge-stream": "^2.0.0",
"supports-color": "^8.1.1"
},
@@ -20432,9 +20126,8 @@
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz",
"integrity": "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@sinclair/typebox": "^0.34.0"
@@ -20444,12 +20137,11 @@
}
},
"node_modules/jest-worker/node_modules/@jest/types": {
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-30.0.5.tgz",
"integrity": "sha512-aREYa3aku9SSnea4aX6bhKn4bgv3AXkgijoQgbYV3yvbiGt6z+MQ85+6mIhx9DsKW2BuB/cLR/A+tcMThx+KLQ==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-30.2.0.tgz",
"integrity": "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@jest/pattern": "30.0.1",
@@ -20468,21 +20160,19 @@
"version": "0.34.41",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.41.tgz",
"integrity": "sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true
},
"node_modules/jest-worker/node_modules/jest-util": {
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.0.5.tgz",
"integrity": "sha512-pvyPWssDZR0FlfMxCBoc0tvM8iUEskaRFALUtGQYzVEAqisAztmy+R8LnU14KT4XA0H/a5HMVTXat1jLne010g==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.2.0.tgz",
"integrity": "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@jest/types": "30.0.5",
"@jest/types": "30.2.0",
"@types/node": "*",
"chalk": "^4.1.2",
"ci-info": "^4.2.0",
@@ -20497,9 +20187,8 @@
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"engines": {
"node": ">=12"
@@ -20512,9 +20201,8 @@
"version": "8.1.1",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
"integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"has-flag": "^4.0.0"
@@ -20530,9 +20218,8 @@
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz",
"integrity": "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@sinclair/typebox": "^0.34.0"
@@ -20542,12 +20229,11 @@
}
},
"node_modules/jest/node_modules/@jest/types": {
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-30.0.5.tgz",
"integrity": "sha512-aREYa3aku9SSnea4aX6bhKn4bgv3AXkgijoQgbYV3yvbiGt6z+MQ85+6mIhx9DsKW2BuB/cLR/A+tcMThx+KLQ==",
"dev": true,
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-30.2.0.tgz",
"integrity": "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@jest/pattern": "30.0.1",
@@ -20566,9 +20252,8 @@
"version": "0.34.41",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.41.tgz",
"integrity": "sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true
},
"node_modules/jiti": {
@@ -20605,9 +20290,9 @@
}
},
"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==",
"license": "MIT",
"dependencies": {
"argparse": "^1.0.7",
@@ -20899,13 +20584,17 @@
"license": "MIT"
},
"node_modules/loader-runner": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz",
"integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==",
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.1.tgz",
"integrity": "sha512-IWqP2SCPhyVFTBtRcgMHdzlf9ul25NwaFx4wCEH/KjAXuuHY4yNjvPXsBokp8jCB936PyWRaPKUNh8NvylLp2Q==",
"devOptional": true,
"license": "MIT",
"engines": {
"node": ">=6.11.5"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/webpack"
}
},
"node_modules/loader-utils": {
@@ -20954,9 +20643,9 @@
}
},
"node_modules/lodash": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
"version": "4.17.23",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz",
"integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==",
"license": "MIT"
},
"node_modules/lodash-es": {
@@ -21499,9 +21188,9 @@
"optional": true
},
"node_modules/node-forge": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz",
"integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==",
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.3.tgz",
"integrity": "sha512-rLvcdSyRCyouf6jcOIPe/BgwG/d7hKjzMKOas33/pHEr6gbq18IK9zV7DiPvzsz0oBJPme6qr6H6kGZuI9/DZg==",
"devOptional": true,
"license": "(BSD-3-Clause OR GPL-2.0)",
"engines": {
@@ -21516,9 +21205,9 @@
"license": "MIT"
},
"node_modules/node-releases": {
"version": "2.0.21",
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.21.tgz",
"integrity": "sha512-5b0pgg78U3hwXkCM8Z9b2FJdPZlr9Psr9V2gQPESdGHqbntyFJKFW4r5TeWGFzafGY3hzs1JC62VEQMbl1JFkw==",
"version": "2.0.27",
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz",
"integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==",
"devOptional": true,
"license": "MIT"
},
@@ -21585,9 +21274,9 @@
}
},
"node_modules/object-code": {
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/object-code/-/object-code-1.3.3.tgz",
"integrity": "sha512-/Ds4Xd5xzrtUOJ+xJQ57iAy0BZsZltOHssnDgcZ8DOhgh41q1YJCnTPnWdWSLkNGNnxYzhYChjc5dgC9mEERCA==",
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/object-code/-/object-code-2.0.0.tgz",
"integrity": "sha512-qOwMF43O/VAD51nJAB7MKsf1yWksql6O1i0DHRo1yaOQM6xJQH0NAE9UKJzYB7lyKw1jnpeb2BmB8qakjxiYZA==",
"license": "MIT"
},
"node_modules/object-filter": {
@@ -23446,7 +23135,7 @@
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-7.0.1.tgz",
"integrity": "sha512-oTUZM/NAZS8p7ANR3SHh30kXB+zK2r2BPcEn/awJIbOvq82WoMN4p62AWWp3Hhw50G0xMsw1mhIBLqHw64EcNQ==",
"dev": true,
"devOptional": true,
"funding": [
{
"type": "individual",
@@ -23458,7 +23147,6 @@
}
],
"license": "MIT",
"optional": true,
"peer": true
},
"node_modules/purgecss": {
@@ -24164,12 +23852,12 @@
}
},
"node_modules/react-router": {
"version": "6.30.1",
"resolved": "https://registry.npmjs.org/react-router/-/react-router-6.30.1.tgz",
"integrity": "sha512-X1m21aEmxGXqENEPG3T6u0Th7g0aS4ZmoNynhbs+Cn+q+QGTLt+d5IQ2bHAXKzKcxGJjxACpVbnYQSCRcfxHlQ==",
"version": "6.30.3",
"resolved": "https://registry.npmjs.org/react-router/-/react-router-6.30.3.tgz",
"integrity": "sha512-XRnlbKMTmktBkjCLE8/XcZFlnHvr2Ltdr1eJX4idL55/9BbORzyZEaIkBFDhFGCEWBBItsVrDxwx3gnisMitdw==",
"license": "MIT",
"dependencies": {
"@remix-run/router": "1.23.0"
"@remix-run/router": "1.23.2"
},
"engines": {
"node": ">=14.0.0"
@@ -24179,13 +23867,13 @@
}
},
"node_modules/react-router-dom": {
"version": "6.30.1",
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.30.1.tgz",
"integrity": "sha512-llKsgOkZdbPU1Eg3zK8lCn+sjD9wMRZZPuzmdWWX5SUs8OFkN5HnFVC0u5KMeMaC9aoancFI/KoLuKPqN+hxHw==",
"version": "6.30.3",
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.30.3.tgz",
"integrity": "sha512-pxPcv1AczD4vso7G4Z3TKcvlxK7g7TNt3/FNGMhfqyntocvYKj+GCatfigGDjbLozC4baguJ0ReCigoDJXb0ag==",
"license": "MIT",
"dependencies": {
"@remix-run/router": "1.23.0",
"react-router": "6.30.1"
"@remix-run/router": "1.23.2",
"react-router": "6.30.3"
},
"engines": {
"node": ">=14.0.0"
@@ -24916,9 +24604,9 @@
}
},
"node_modules/schema-utils": {
"version": "4.3.2",
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.2.tgz",
"integrity": "sha512-Gn/JaSk/Mt9gYubxTtSn/QCV4em9mpAPiR1rqy/Ocu19u/G9J5WWdNoUT4SiV6mFC3y6cxyFcFwdzPM3FgxGAQ==",
"version": "4.3.3",
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.3.tgz",
"integrity": "sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==",
"devOptional": true,
"license": "MIT",
"dependencies": {
@@ -26217,9 +25905,8 @@
"version": "0.11.11",
"resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.11.tgz",
"integrity": "sha512-MeQTA1r0litLUf0Rp/iisCaL8761lKAZHaimlbGK4j0HysC4PLfqygQj9srcs0m2RdtDYnF8UuYyKpbjHYp7Jw==",
"dev": true,
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@pkgr/core": "^0.2.9"
@@ -26238,9 +25925,9 @@
"license": "MIT"
},
"node_modules/tapable": {
"version": "2.2.3",
"resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.3.tgz",
"integrity": "sha512-ZL6DDuAlRlLGghwcfmSn9sK3Hr6ArtyudlSAiCqQ6IfE+b+HHbydbYDIG15IfS5do+7XQQBdBiubF/cV2dnDzg==",
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz",
"integrity": "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==",
"devOptional": true,
"license": "MIT",
"engines": {
@@ -26271,9 +25958,9 @@
}
},
"node_modules/terser-webpack-plugin": {
"version": "5.3.14",
"resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.14.tgz",
"integrity": "sha512-vkZjpUjb6OMS7dhV+tILUW6BhpDR7P2L/aQSAv+Uwk+m8KATX9EccViHTJR2qDtACKPIYndLGCyl3FMo+r2LMw==",
"version": "5.3.16",
"resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.16.tgz",
"integrity": "sha512-h9oBFCWrq78NyWWVcSwZarJkZ01c2AyGrzs1crmHZO3QUg9D61Wu4NPjBy69n7JqylFF5y+CsUZYmYEIZ3mR+Q==",
"devOptional": true,
"license": "MIT",
"dependencies": {
@@ -26587,6 +26274,15 @@
"tslib": "2"
}
},
"node_modules/try": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/try/-/try-1.0.3.tgz",
"integrity": "sha512-AHA8khVCII6zKyRkyPo6pRwoR9v5jb7QFw6e5avtaVSkxVfaEucYIo06xnwB+pJaEarfYNbs7W3Vq+LZLZiWyA==",
"license": "MIT",
"funding": {
"url": "https://github.com/arthurfiorette/try?sponsor=1"
}
},
"node_modules/ts-api-utils": {
"version": "1.4.3",
"resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.4.3.tgz",
@@ -26601,13 +26297,11 @@
}
},
"node_modules/ts-jest": {
"version": "29.4.4",
"resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.4.4.tgz",
"integrity": "sha512-ccVcRABct5ZELCT5U0+DZwkXMCcOCLi2doHRrKy1nK/s7J7bch6TzJMsrY09WxgUUIP/ITfmcDS8D2yl63rnXw==",
"dev": true,
"version": "29.4.5",
"resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.4.5.tgz",
"integrity": "sha512-HO3GyiWn2qvTQA4kTgjDcXiMwYQt68a1Y8+JuLRVpdIzm+UOLSHgl/XqR4c6nzJkq5rOkjc02O2I7P7l/Yof0Q==",
"devOptional": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"bs-logger": "^0.2.6",
"fast-json-stable-stringify": "^2.1.0",
@@ -26615,7 +26309,7 @@
"json5": "^2.2.3",
"lodash.memoize": "^4.1.2",
"make-error": "^1.3.6",
"semver": "^7.7.2",
"semver": "^7.7.3",
"type-fest": "^4.41.0",
"yargs-parser": "^21.1.1"
},
@@ -26656,13 +26350,11 @@
}
},
"node_modules/ts-jest/node_modules/semver": {
"version": "7.7.2",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz",
"integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==",
"dev": true,
"version": "7.7.3",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz",
"integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==",
"devOptional": true,
"license": "ISC",
"optional": true,
"peer": true,
"bin": {
"semver": "bin/semver.js"
},
@@ -26674,10 +26366,8 @@
"version": "4.41.0",
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz",
"integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==",
"dev": true,
"devOptional": true,
"license": "(MIT OR CC0-1.0)",
"optional": true,
"peer": true,
"engines": {
"node": ">=16"
},
@@ -26937,10 +26627,8 @@
"version": "3.19.3",
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz",
"integrity": "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==",
"dev": true,
"license": "BSD-2-Clause",
"optional": true,
"peer": true,
"bin": {
"uglifyjs": "bin/uglifyjs"
},
@@ -27117,9 +26805,9 @@
}
},
"node_modules/update-browserslist-db": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz",
"integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==",
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz",
"integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==",
"devOptional": true,
"funding": [
{
@@ -27399,9 +27087,9 @@
}
},
"node_modules/watchpack": {
"version": "2.4.4",
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.4.tgz",
"integrity": "sha512-c5EGNOiyxxV5qmTtAB7rbiXxi1ooX1pQKMLX/MIabJjRA0SJBQOjKF+KSVfHkr9U1cADPon0mRiVe/riyaiDUA==",
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.5.1.tgz",
"integrity": "sha512-Zn5uXdcFNIA1+1Ei5McRd+iRzfhENPCe7LeABkJtNulSxjma+l7ltNx55BWZkRlwRnpOgHqxnjyaDgJnNXnqzg==",
"devOptional": true,
"license": "MIT",
"dependencies": {
@@ -27442,9 +27130,9 @@
}
},
"node_modules/webpack": {
"version": "5.101.3",
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.101.3.tgz",
"integrity": "sha512-7b0dTKR3Ed//AD/6kkx/o7duS8H3f1a4w3BYpIriX4BzIhjkn4teo05cptsxvLesHFKK5KObnadmCHBwGc+51A==",
"version": "5.105.0",
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.105.0.tgz",
"integrity": "sha512-gX/dMkRQc7QOMzgTe6KsYFM7DxeIONQSui1s0n/0xht36HvrgbxtM1xBlgx596NbpHuQU8P7QpKwrZYwUX48nw==",
"devOptional": true,
"license": "MIT",
"dependencies": {
@@ -27456,22 +27144,22 @@
"@webassemblyjs/wasm-parser": "^1.14.1",
"acorn": "^8.15.0",
"acorn-import-phases": "^1.0.3",
"browserslist": "^4.24.0",
"browserslist": "^4.28.1",
"chrome-trace-event": "^1.0.2",
"enhanced-resolve": "^5.17.3",
"es-module-lexer": "^1.2.1",
"enhanced-resolve": "^5.19.0",
"es-module-lexer": "^2.0.0",
"eslint-scope": "5.1.1",
"events": "^3.2.0",
"glob-to-regexp": "^0.4.1",
"graceful-fs": "^4.2.11",
"json-parse-even-better-errors": "^2.3.1",
"loader-runner": "^4.2.0",
"loader-runner": "^4.3.1",
"mime-types": "^2.1.27",
"neo-async": "^2.6.2",
"schema-utils": "^4.3.2",
"tapable": "^2.1.1",
"terser-webpack-plugin": "^5.3.11",
"watchpack": "^2.4.1",
"schema-utils": "^4.3.3",
"tapable": "^2.3.0",
"terser-webpack-plugin": "^5.3.16",
"watchpack": "^2.5.1",
"webpack-sources": "^3.3.3"
},
"bin": {
@@ -27981,10 +27669,8 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz",
"integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==",
"dev": true,
"license": "MIT",
"optional": true,
"peer": true
"devOptional": true,
"license": "MIT"
},
"node_modules/wrap-ansi": {
"version": "6.2.0",

View File

@@ -38,7 +38,7 @@
"dependencies": {
"@edx/brand": "npm:@openedx/brand-openedx@^1.2.2",
"@edx/frontend-component-header": "^6.4.0",
"@edx/frontend-platform": "^8.3.0",
"@edx/frontend-platform": "^8.5.5",
"@edx/openedx-atlas": "^0.7.0",
"@openedx/frontend-plugin-framework": "^1.7.0",
"@openedx/paragon": "^23.15.1",
@@ -47,7 +47,7 @@
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-error-boundary": "^4.1.2",
"react-router-dom": "^6.0.0"
"react-router-dom": "^6.30.3"
},
"devDependencies": {
"@edx/browserslist-config": "^1.1.1",
@@ -58,6 +58,7 @@
"@testing-library/react": "^16.3.0",
"@testing-library/user-event": "^14.6.1",
"@types/react": "^18",
"@types/react-dom": "^18"
"@types/react-dom": "^18",
"ts-jest": "^29.4.5"
}
}

View File

@@ -44,9 +44,9 @@ describe('AuthZTitle', () => {
});
it('renders page subtitle as ReactNode', () => {
const subtitleNode = <div data-testid="custom-subtitle">Custom Subtitle</div>;
const subtitleNode = <div>Custom Subtitle</div>;
render(<AuthZTitle {...defaultProps} pageSubtitle={subtitleNode} />);
expect(screen.getByTestId('custom-subtitle')).toBeInTheDocument();
expect(screen.getByText('Custom Subtitle')).toBeInTheDocument();
});
it('renders action buttons and triggers onClick', () => {
@@ -69,7 +69,7 @@ describe('AuthZTitle', () => {
});
it('renders action buttons with icons', () => {
const mockIcon = () => <span data-testid="mock-icon">Icon</span>;
const mockIcon = () => <span role="img" aria-label="save icon">Icon</span>;
const onClick = jest.fn();
const actions = [
{ label: 'Save', icon: mockIcon, onClick },
@@ -77,14 +77,14 @@ describe('AuthZTitle', () => {
render(<AuthZTitle {...defaultProps} actions={actions} />);
const button = screen.getByRole('button', { name: 'Icon Save' });
const button = screen.getByRole('button', { name: 'save icon Save' });
expect(button).toBeInTheDocument();
expect(screen.getByTestId('mock-icon')).toBeInTheDocument();
expect(screen.getByRole('img', { name: 'save icon' })).toBeInTheDocument();
});
it('renders ReactNode actions alongside button actions', () => {
const onClick = jest.fn();
const customAction = <div data-testid="custom-action">Custom Action</div>;
const customAction = <div role="region" aria-label="custom action area">Custom Action</div>;
const actions = [
{ label: 'Save', onClick },
customAction,
@@ -93,6 +93,6 @@ describe('AuthZTitle', () => {
render(<AuthZTitle {...defaultProps} actions={actions} />);
expect(screen.getByRole('button', { name: 'Save' })).toBeInTheDocument();
expect(screen.getByTestId('custom-action')).toBeInTheDocument();
expect(screen.getByRole('region', { name: 'custom action area' })).toBeInTheDocument();
});
});

View File

@@ -0,0 +1,239 @@
import { screen } from '@testing-library/react';
import { Role, PermissionsResourceGrouped } from '@src/types';
import { renderWrapper } from '@src/setupTest';
import PermissionTable from './PermissionTable';
const mockRoles: Role[] = [
{
name: 'Admin',
description: 'Administrator role',
userCount: 0,
permissions: [],
role: '',
},
{
name: 'Editor',
description: 'Editor role',
userCount: 0,
permissions: [],
role: '',
},
{
name: 'Viewer',
description: 'Viewer role',
userCount: 0,
permissions: [],
role: '',
},
];
const mockPermissionsTable: PermissionsResourceGrouped[] = [
{
key: 'users',
label: 'User Management',
description: 'Manage user accounts',
permissions: [
{
key: 'users.read',
resource: 'users',
label: 'View Users',
actionKey: 'read',
roles: {
Admin: true,
Editor: true,
Viewer: true,
},
},
{
key: 'users.write',
resource: 'users',
label: 'Edit Users',
actionKey: 'write',
roles: {
Admin: true,
Editor: true,
Viewer: false,
},
},
],
},
{
key: 'courses',
label: 'Course Management',
description: 'Manage courses',
permissions: [
{
key: 'courses.delete',
resource: 'courses',
label: 'Delete Courses',
actionKey: 'delete',
roles: {
Admin: true,
Editor: false,
Viewer: false,
},
},
],
},
];
describe('PermissionTable', () => {
it('renders within a Card component', () => {
renderWrapper(<PermissionTable roles={mockRoles} permissionsTable={mockPermissionsTable} />);
expect(document.querySelector('.card')).toBeInTheDocument();
});
it('renders table with correct class', () => {
renderWrapper(<PermissionTable roles={mockRoles} permissionsTable={mockPermissionsTable} />);
const table = screen.getByRole('table');
expect(table).toHaveClass('permission-table', 'w-100');
});
it('renders table headers for all roles', () => {
renderWrapper(<PermissionTable roles={mockRoles} permissionsTable={mockPermissionsTable} />);
mockRoles.forEach(role => {
expect(screen.getByRole('columnheader', { name: role.name })).toBeInTheDocument();
});
});
it('applies correct classes to role headers', () => {
renderWrapper(<PermissionTable roles={mockRoles} permissionsTable={mockPermissionsTable} />);
mockRoles.forEach(role => {
const header = screen.getByRole('columnheader', { name: role.name });
expect(header).toHaveClass('text-center', 'py-3');
});
});
it('renders resource group headers', () => {
renderWrapper(<PermissionTable roles={mockRoles} permissionsTable={mockPermissionsTable} />);
expect(screen.getByText('User Management')).toBeInTheDocument();
expect(screen.getByText('Course Management')).toBeInTheDocument();
});
it('applies correct classes to resource group headers', () => {
const { container } = renderWrapper(<PermissionTable roles={mockRoles} permissionsTable={mockPermissionsTable} />);
const resourceRows = container.querySelectorAll('.bg-info-100.text-primary');
expect(resourceRows).toHaveLength(2);
});
it('renders resource group headers with correct colspan', () => {
const { container } = renderWrapper(<PermissionTable roles={mockRoles} permissionsTable={mockPermissionsTable} />);
const resourceCells = container.querySelectorAll('td[colspan]');
resourceCells.forEach(cell => {
expect(cell).toHaveAttribute('colspan', '4');
});
});
it('renders permission labels with icons', () => {
renderWrapper(<PermissionTable roles={mockRoles} permissionsTable={mockPermissionsTable} />);
expect(screen.getByText('View Users')).toBeInTheDocument();
expect(screen.getByText('Edit Users')).toBeInTheDocument();
expect(screen.getByText('Delete Courses')).toBeInTheDocument();
});
it('applies correct classes to permission label cells', () => {
const { container } = renderWrapper(<PermissionTable roles={mockRoles} permissionsTable={mockPermissionsTable} />);
const labelCells = container.querySelectorAll('td.text-start.d-flex');
labelCells.forEach(cell => {
expect(cell).toHaveClass('align-items-center', 'small', 'px-4', 'py-3');
});
});
it('renders permission row borders', () => {
const { container } = renderWrapper(<PermissionTable roles={mockRoles} permissionsTable={mockPermissionsTable} />);
const borderRows = container.querySelectorAll('tr.border-top');
expect(borderRows).toHaveLength(3);
});
it('renders Check icons for granted permissions', () => {
renderWrapper(<PermissionTable roles={mockRoles} permissionsTable={mockPermissionsTable} />);
const grantedIcons = screen.getAllByLabelText(/Permission granted in/);
expect(grantedIcons.length).toBeGreaterThan(0);
});
it('renders Close icons for denied permissions', () => {
renderWrapper(<PermissionTable roles={mockRoles} permissionsTable={mockPermissionsTable} />);
const deniedIcons = screen.getAllByLabelText(/Permission denied in/);
expect(deniedIcons.length).toBeGreaterThan(0);
});
it('applies text-danger class to denied permission icons', () => {
renderWrapper(<PermissionTable roles={mockRoles} permissionsTable={mockPermissionsTable} />);
const deniedIcons = screen.getAllByLabelText(/Permission denied in/);
deniedIcons.forEach(icon => {
expect(icon).toHaveClass('text-danger');
});
});
it('applies correct classes to granted permission icons', () => {
renderWrapper(<PermissionTable roles={mockRoles} permissionsTable={mockPermissionsTable} />);
const grantedIcons = screen.getAllByLabelText(/Permission granted in/);
grantedIcons.forEach(icon => {
expect(icon).toHaveClass('d-inline-block');
expect(icon).not.toHaveClass('text-danger');
});
});
it('centers permission status cells', () => {
const { container } = renderWrapper(<PermissionTable roles={mockRoles} permissionsTable={mockPermissionsTable} />);
const statusCells = container.querySelectorAll('tbody td.text-center');
expect(statusCells.length).toBeGreaterThan(0);
});
it('renders correct aria-labels for granted permissions', () => {
renderWrapper(<PermissionTable roles={mockRoles} permissionsTable={mockPermissionsTable} />);
mockRoles.forEach(role => {
const grantedLabel = `Permission granted in ${role.name} role`;
const icons = screen.queryAllByLabelText(grantedLabel);
expect(icons.length).toBeGreaterThan(0);
});
});
it('renders correct aria-labels for denied permissions', () => {
renderWrapper(<PermissionTable roles={mockRoles} permissionsTable={mockPermissionsTable} />);
const deniedLabel = 'Permission denied in Viewer role';
expect(screen.getAllByLabelText(deniedLabel)).toHaveLength(2);
});
it('handles empty roles array', () => {
renderWrapper(<PermissionTable roles={[]} permissionsTable={mockPermissionsTable} />);
expect(screen.getByRole('table')).toBeInTheDocument();
expect(screen.getByText('User Management')).toBeInTheDocument();
});
it('handles empty permissions table', () => {
renderWrapper(<PermissionTable roles={mockRoles} permissionsTable={[]} />);
expect(screen.getByRole('table')).toBeInTheDocument();
mockRoles.forEach(role => {
expect(screen.getByText(role.name)).toBeInTheDocument();
});
});
it('applies correct margin to permission icons', () => {
const { container } = renderWrapper(<PermissionTable roles={mockRoles} permissionsTable={mockPermissionsTable} />);
const permissionIcons = container.querySelectorAll('td.text-start .paragon-icon');
permissionIcons.forEach(icon => {
expect(icon).toHaveClass('d-inline-block', 'mr-2');
});
});
});

View File

@@ -1,52 +1,83 @@
import { useIntl } from '@edx/frontend-platform/i18n';
import { Check, Close } from '@openedx/paragon/icons';
import { Card, Icon } from '@openedx/paragon';
import { PermissionsResourceGrouped, Role } from '@src/types';
import { actionsDictionary } from './RoleCard/constants';
import ResourceTooltip from './ResourceTooltip';
import messages from './messages';
type PermissionTableProps = {
roles: Role[];
permissionsTable: PermissionsResourceGrouped[];
};
const PermissionTable = ({ permissionsTable, roles }: PermissionTableProps) => (
<Card>
<table className="permission-table w-100">
<thead>
<tr>
<th className="" aria-hidden="true" />
{roles.map(role => (
<th key={role.name} className="text-center py-3">{role.name}</th>
))}
</tr>
</thead>
<tbody>
{permissionsTable.map(resourceGroup => (
<>
<tr className="bg-info-100 text-primary">
<td colSpan={roles.length + 1} className="text-start py-3 px-4">
<strong>{resourceGroup.label}</strong>
<ResourceTooltip resourceGroup={resourceGroup} />
</td>
</tr>
{resourceGroup.permissions.map(permission => (
<tr key={permission.key} className="border-top">
<td className="text-start d-flex align-items-center small px-4 py-3">
<Icon className="d-inline-block mr-2" size="sm" src={actionsDictionary[permission.actionKey]} />
{permission.label}
</td>
{roles.map(role => (
<td key={role.name} className="text-center">
{permission.roles[role.name] ? <Icon className="d-inline-block" src={Check} /> : <Icon className="text-danger d-inline-block" src={Close} />}
</td>
))}
</tr>
const PermissionTable = ({ permissionsTable, roles }: PermissionTableProps) => {
const { formatMessage } = useIntl();
return (
<Card>
<table className="permission-table w-100">
<thead>
<tr>
<th className="" aria-hidden="true" />
{roles.map(role => (
<th key={role.name} className="text-center py-3">{role.name}</th>
))}
</>
))}
</tbody>
</table>
</Card>
);
</tr>
</thead>
<tbody>
{permissionsTable.map(resourceGroup => (
<>
<tr className="bg-info-100 text-primary">
<td colSpan={roles.length + 1} className="text-start py-3 px-4">
<strong>{resourceGroup.label}</strong>
<ResourceTooltip resourceGroup={resourceGroup} />
</td>
</tr>
{resourceGroup.permissions.map(permission => (
<tr key={permission.key} className="border-top">
<td className="text-start d-flex align-items-center small px-4 py-3">
<Icon className="d-inline-block mr-2" size="sm" src={actionsDictionary[permission.actionKey]} />
{permission.label}
</td>
{roles.map(role => (
<td key={role.name} className="text-center">
{
permission.roles[role.name]
? (
<Icon
className="d-inline-block"
src={Check}
aria-label={formatMessage(messages['authz.role.card.permission.for.role.status.granted'], {
roleName: role.name,
})}
screenReaderText={formatMessage(messages['authz.role.card.permission.for.role.status.granted'], {
roleName: role.name,
})}
/>
)
: (
<Icon
className="text-danger d-inline-block"
src={Close}
aria-label={formatMessage(messages['authz.role.card.permission.for.role.status.denied'], {
roleName: role.name,
})}
screenReaderText={formatMessage(messages['authz.role.card.permission.for.role.status.denied'], {
roleName: role.name,
})}
/>
)
}
</td>
))}
</tr>
))}
</>
))}
</tbody>
</table>
</Card>
);
};
export default PermissionTable;

View File

@@ -1,41 +1,50 @@
import { ComponentType } from 'react';
import { useIntl } from '@edx/frontend-platform/i18n';
import {
Chip, Col, Row,
} from '@openedx/paragon';
import { RoleResourceGroup } from '@src/types';
import { actionsDictionary, ActionKey } from './constants';
import ResourceTooltip from '../ResourceTooltip';
import messages from './messages';
type PermissionRowProps = {
resource: RoleResourceGroup;
};
const PermissionRow = ({ resource }: PermissionRowProps) => (
<Row className="row align-items-center border px-2 py-2">
<Col md={2}>
<span className="small font-weight-bold">{resource.label}</span>
<ResourceTooltip resourceGroup={resource} />
</Col>
<Col>
<div className="w-100 d-flex flex-wrap align-items-center">
{resource.permissions.map((action, index) => (
<>
<Chip
key={action.key}
iconBefore={actionsDictionary[action.actionKey as ActionKey] as ComponentType}
disabled={action.disabled}
className="mx-3 my-2 px-3 bg-primary-100 border-0 permission-chip"
variant="light"
>
{action.label}
</Chip>
{(index === resource.permissions.length - 1) ? null
: (<hr className="border-right mx-2" style={{ height: '24px' }} />)}
</>
))}
</div>
</Col>
</Row>
);
const PermissionRow = ({ resource }: PermissionRowProps) => {
const { formatMessage } = useIntl();
return (
<Row className="row align-items-center border px-2 py-2">
<Col md={2}>
<span className="small font-weight-bold">{resource.label}</span>
<ResourceTooltip resourceGroup={resource} />
</Col>
<Col>
<div className="w-100 d-flex flex-wrap align-items-center">
{resource.permissions.map((action, index) => (
<>
<Chip
key={action.key}
iconBefore={actionsDictionary[action.actionKey as ActionKey] as ComponentType}
disabled={action.disabled}
className="mx-3 my-2 px-3 bg-primary-100 border-0 permission-chip"
variant="light"
aria-label={formatMessage(messages['authz.role.card.permissions.ariaLabel'], {
permissionName: action.label,
permissionStatus: formatMessage(messages[`authz.role.card.permissions.status.${action.disabled ? 'denied' : 'granted'}`]),
})}
>
{action.label}
</Chip>
{(index === resource.permissions.length - 1) ? null
: (<hr className="border-right mx-2" style={{ height: '24px' }} />)}
</>
))}
</div>
</Col>
</Row>
);
};
export default PermissionRow;

View File

@@ -4,14 +4,14 @@ import userEvent from '@testing-library/user-event';
import RoleCard from '.';
jest.mock('@openedx/paragon/icons', () => ({
Delete: () => <svg data-testid="delete-icon" />,
Person: () => <svg data-testid="person-icon" />,
Delete: () => <svg role="img" aria-label="delete icon" />,
Person: () => <svg role="img" aria-label="person icon" />,
}));
jest.mock('./constants', () => ({
actionsDictionary: {
view: () => <svg data-testid="view-icon" />,
manage: () => <svg data-testid="manage-icon" />,
view: () => <svg role="img" aria-label="view action icon" />,
manage: () => <svg role="img" aria-label="manage action icon" />,
},
}));
@@ -47,7 +47,7 @@ describe('RoleCard', () => {
// User counter with icon
expect(screen.getByText('2')).toBeInTheDocument();
expect(screen.getByTestId('person-icon')).toBeInTheDocument();
expect(screen.getByRole('img', { name: 'person icon' })).toBeInTheDocument();
// Subtitle (object name)
expect(screen.getByText('Test Library')).toBeInTheDocument();
@@ -71,8 +71,8 @@ describe('RoleCard', () => {
expect(screen.getByText('Manage')).toBeInTheDocument();
// Action icons
expect(screen.getByTestId('view-icon')).toBeInTheDocument();
expect(screen.getByTestId('manage-icon')).toBeInTheDocument();
expect(screen.getByRole('img', { name: 'view action icon' })).toBeInTheDocument();
expect(screen.getByRole('img', { name: 'manage action icon' })).toBeInTheDocument();
});
it('does not show delete button when handleDelete is not passed', () => {
@@ -82,7 +82,7 @@ describe('RoleCard', () => {
it('handles no userCounter gracefully', () => {
renderWrapper(<RoleCard {...defaultProps} userCounter={null} />);
expect(screen.queryByTestId('person-icon')).not.toBeInTheDocument();
expect(screen.queryByRole('img', { name: 'person icon' })).not.toBeInTheDocument();
expect(screen.queryByText('2')).not.toBeInTheDocument();
});

View File

@@ -18,17 +18,26 @@ interface RoleCardProps extends CardTitleProps {
permissionsByResource: any[];
}
const CardTitle = ({ title, userCounter = null }: CardTitleProps) => (
<div className="d-flex align-items-center">
<span className="mr-4 text-primary">{title}</span>
{userCounter !== null && (
<span className="d-flex align-items-center font-weight-normal">
<Icon src={Person} className="mr-1" />
{userCounter}
</span>
)}
</div>
);
const CardTitle = ({ title, userCounter = null }: CardTitleProps) => {
const { formatMessage } = useIntl();
return (
<div className="d-flex align-items-center">
<span className="mr-4 text-primary">{title}</span>
{userCounter !== null && (
<span className="d-flex align-items-center font-weight-normal">
<Icon
src={Person}
className="mr-1"
aria-label={formatMessage(messages['authz.role.card.userCounter'])}
screenReaderText={formatMessage(messages['authz.role.card.userCounter'])}
/>
{userCounter}
</span>
)}
</div>
);
};
const RoleCard = ({
title, objectName, description, handleDelete, permissionsByResource, userCounter,

View File

@@ -51,6 +51,26 @@ const messages = defineMessages({
defaultMessage: 'Delete role action',
description: 'Alt description for delete button',
},
'authz.role.card.userCounter': {
id: 'authz.role.card.userCounter',
defaultMessage: 'Number of users with this role',
description: 'Screen reader text for the user counter icon in the role card header',
},
'authz.role.card.permissions.ariaLabel': {
id: 'authz.role.card.permissions.ariaLabel',
defaultMessage: '{permissionName} permission is {permissionStatus}',
description: 'Aria label for permission chips in the role card',
},
'authz.role.card.permissions.status.denied': {
id: 'authz.role.card.permissions.status.denied',
defaultMessage: 'denied',
description: 'Label for denied status of a permission in the role card',
},
'authz.role.card.permissions.status.granted': {
id: 'authz.role.card.permissions.status.granted',
defaultMessage: 'granted',
description: 'Label for granted status of a permission in the role card',
},
});
export default messages;

View File

@@ -0,0 +1,16 @@
import { defineMessages } from '@edx/frontend-platform/i18n';
const messages = defineMessages({
'authz.role.card.permission.for.role.status.granted': {
id: 'authz.role.card.permission.for.role.status.granted',
defaultMessage: 'Permission granted in {roleName} role',
description: 'Label for granted status of a permission in the permissions table',
},
'authz.role.card.permission.for.role.status.denied': {
id: 'authz.role.card.permission.for.role.status.denied',
defaultMessage: 'Permission denied in {roleName} role',
description: 'Label for denied status of a permission in the permissions table',
},
});
export default messages;

View File

@@ -40,7 +40,7 @@ export type PermissionsByRole = {
userCount: number;
};
export interface PutAssignTeamMembersRoleResponse {
completed: { user: string; status: string }[];
completed: { userIdentifier: string; status: string }[];
errors: { userIdentifier: string; error: string }[];
}

View File

@@ -83,8 +83,11 @@ export const useAssignTeamMembersRole = () => {
mutationFn: async ({ data }: {
data: AssignTeamMembersRoleRequest
}) => assignTeamMembersRole(data),
onSettled: (_data, _error, { data: { scope } }) => {
queryClient.invalidateQueries({ queryKey: authzQueryKeys.teamMembersAll(scope) });
onSettled: (_data, error, { data: { scope } }) => {
if (!error) {
queryClient.invalidateQueries({ queryKey: authzQueryKeys.teamMembersAll(scope) });
queryClient.invalidateQueries({ queryKey: authzQueryKeys.permissionsByRole(scope) });
}
},
});
};
@@ -104,6 +107,7 @@ export const useRevokeUserRoles = () => {
}) => revokeUserRoles(data),
onSettled: (_data, _error, { data: { scope } }) => {
queryClient.invalidateQueries({ queryKey: authzQueryKeys.teamMembersAll(scope) });
queryClient.invalidateQueries({ queryKey: authzQueryKeys.permissionsByRole(scope) });
},
});
};

View File

@@ -3,11 +3,6 @@
.authz-libraries {
--height-action-divider: 30px;
.pgn__breadcrumb li:first-child a {
color: var(--pgn-color-breadcrumb-active);
text-decoration: none;
}
hr {
border-top: var(--pgn-size-border-width) solid var(--pgn-color-border);
width: 100%;

View File

@@ -8,9 +8,12 @@ import AuthZModule from './index';
jest.mock('./libraries-manager', () => ({
// eslint-disable-next-line no-promise-executor-return
LibrariesLayout: lazy(() => new Promise<{ default: ComponentType<any> }>(resolve => setTimeout(() => resolve({ default: () => <div data-testid="layout"><Outlet /></div> }), 100))),
LibrariesTeamManager: () => <div data-testid="libraries-manager">Libraries Team Page</div>,
LibrariesUserManager: () => <div data-testid="libraries-user-manager">Libraries User Page</div>,
LibrariesLayout: lazy(() => new Promise<{ default: ComponentType<any> }>(resolve => setTimeout(
() => resolve({ default: () => <div><Outlet /></div> }),
100,
))),
LibrariesTeamManager: () => <div>Libraries Team Page</div>,
LibrariesUserManager: () => <div>Libraries User Page</div>,
}));
const createTestQueryClient = () => new QueryClient({
@@ -42,10 +45,10 @@ describe('AuthZModule', () => {
</IntlProvider>,
);
expect(screen.getByTestId('loading-page')).toBeInTheDocument();
expect(document.querySelector('.spinner-border')).toBeInTheDocument();
await waitFor(() => {
expect(screen.getByTestId('libraries-manager')).toBeInTheDocument();
expect(screen.getByText('Libraries Team Page')).toBeInTheDocument();
});
});
@@ -63,7 +66,7 @@ describe('AuthZModule', () => {
</IntlProvider>,
);
await waitFor(() => {
expect(screen.getByTestId('libraries-user-manager')).toBeInTheDocument();
expect(screen.getByText('Libraries User Page')).toBeInTheDocument();
});
});
});

View File

@@ -11,7 +11,7 @@ const ThrowError = ({ error }: { error:Error }) => {
describe('LibrariesErrorFallback', () => {
it('renders Access Denied for 401', () => {
const error = { name: '', message: 'NO_ACCESS', customAtributtes: { httpErrorStatus: 401 } };
const error = { name: '', message: 'NO_ACCESS', customAttributes: { httpErrorStatus: 401 } };
renderWrapper(
<ErrorBoundary FallbackComponent={LibrariesErrorFallback}>
<ThrowError error={error} />
@@ -21,8 +21,19 @@ describe('LibrariesErrorFallback', () => {
expect(screen.getByText(/Back to Libraries/i)).toBeInTheDocument();
});
it('renders Not Found for 400 error', () => {
const error = { name: '', message: 'Axios Error (Response): 400', customAttributes: { httpErrorStatus: 400 } };
renderWrapper(
<ErrorBoundary FallbackComponent={LibrariesErrorFallback}>
<ThrowError error={error} />
</ErrorBoundary>,
);
expect(screen.getByText(/Page Not Found/i)).toBeInTheDocument();
expect(screen.getByText(/Back to Libraries/i)).toBeInTheDocument();
});
it('renders Not Found for 404', () => {
const error = { name: '', message: 'NOT_FOUND', customAtributtes: { httpErrorStatus: 404 } };
const error = { name: '', message: 'NOT_FOUND', customAttributes: { httpErrorStatus: 404 } };
renderWrapper(
<ErrorBoundary FallbackComponent={LibrariesErrorFallback}>
<ThrowError error={error} />
@@ -33,7 +44,7 @@ describe('LibrariesErrorFallback', () => {
});
it('renders Server Error for 500 and shows reload', async () => {
const error = { name: '', message: 'SERVER_ERROR', customAtributtes: { httpErrorStatus: 500 } };
const error = { name: '', message: 'SERVER_ERROR', customAttributes: { httpErrorStatus: 500 } };
renderWrapper(
<ErrorBoundary FallbackComponent={LibrariesErrorFallback}>
<ThrowError error={error} />
@@ -45,7 +56,7 @@ describe('LibrariesErrorFallback', () => {
});
it('renders generic error for other error error', () => {
const error = { name: '', message: 'SOMETHING_ELSE', customAtributtes: { httpErrorStatus: 418 } };
const error = { name: '', message: 'SOMETHING_ELSE', customAttributes: { httpErrorStatus: 418 } };
renderWrapper(
<ErrorBoundary FallbackComponent={LibrariesErrorFallback}>
<ThrowError error={error} />
@@ -59,7 +70,7 @@ describe('LibrariesErrorFallback', () => {
// Simulate error with a refetch function
const refetch = jest.fn();
const error = {
name: '', message: 'SERVER_ERROR', customAtributtes: { httpErrorStatus: 500 }, refetch,
name: '', message: 'SERVER_ERROR', customAttributes: { httpErrorStatus: 500 }, refetch,
};
renderWrapper(
<ErrorBoundary FallbackComponent={LibrariesErrorFallback} onReset={refetch}>

View File

@@ -5,7 +5,9 @@ import { useIntl } from '@edx/frontend-platform/i18n';
import {
Button, Container, Hyperlink, Row,
} from '@openedx/paragon';
import { CustomErrors, ERROR_STATUS } from '@src/constants';
import {
CustomErrors, ERROR_STATUS, STATUS_400, STATUS_404,
} from '@src/constants';
import messages from './messages';
@@ -18,11 +20,14 @@ const getErrorConfig = ({ errorMessage, errorStatus }) => {
showBackButton: true,
});
}
// 400 errors are handled as 404 Not Found to avoid exposing potential sensitive information
// about the existence of resources and handling malformed library ids in the URL
if (errorMessage === CustomErrors.NOT_FOUND || ERROR_STATUS.NOT_FOUND.includes(errorStatus)) {
const statusCode = errorStatus === STATUS_400 ? STATUS_404 : errorStatus;
return ({
title: messages['error.page.title.notFound'],
description: messages['error.page.message.notFound'],
statusCode: errorStatus || ERROR_STATUS.NOT_FOUND[0],
statusCode: statusCode || STATUS_404,
showBackButton: true,
});
}

View File

@@ -6,6 +6,7 @@ import { useLibrary, useUpdateLibrary } from '@src/authz-module/data/hooks';
import { useLibraryAuthZ } from './context';
import LibrariesTeamManager from './LibrariesTeamManager';
import { ToastManagerProvider } from './ToastManagerContext';
import { CONTENT_LIBRARY_PERMISSIONS } from './constants';
jest.mock('./context', () => {
const actual = jest.requireActual('./context');
@@ -25,12 +26,12 @@ jest.mock('@src/authz-module/data/hooks', () => ({
jest.mock('./components/TeamTable', () => ({
__esModule: true,
default: () => <div data-testid="team-table">MockTeamTable</div>,
default: () => <div role="table" aria-label="Team Members Table">Team member list</div>,
}));
jest.mock('./components/AddNewTeamMemberModal', () => ({
__esModule: true,
AddNewTeamMemberTrigger: () => <div data-testid="add-team-member-trigger">MockAddNewTeamMemberTrigger</div>,
AddNewTeamMemberTrigger: () => <button type="button">Add Team Member</button>,
}));
jest.mock('../components/RoleCard', () => ({
@@ -40,10 +41,10 @@ jest.mock('../components/RoleCard', () => ({
description: string,
permissionsByResource: any[]
}) => (
<div data-testid="role-card">
<div>{title}</div>
<div>{description}</div>
<div>{permissionsByResource.length} permissions</div>
<div role="article" aria-label={`Role: ${title}`}>
<h3>{title}</h3>
<p>{description}</p>
<span>{permissionsByResource.length} permissions</span>
</div>
),
}));
@@ -71,8 +72,8 @@ describe('LibrariesTeamManager', () => {
},
],
permissions: [
{ key: 'view_library', label: 'view', resource: 'library' },
{ key: 'edit_library', label: 'edit', resource: 'library' },
{ key: CONTENT_LIBRARY_PERMISSIONS.VIEW_LIBRARY, label: 'view', resource: 'library' },
{ key: CONTENT_LIBRARY_PERMISSIONS.EDIT_LIBRARY_COLLECTION, label: 'edit', resource: 'library' },
],
resources: [{ key: 'library', label: 'Library' }],
canManageTeam: true,
@@ -108,10 +109,10 @@ describe('LibrariesTeamManager', () => {
expect(screen.getByText('lib-001')).toBeInTheDocument(); // subtitle
// TeamTable is rendered
expect(screen.getByTestId('team-table')).toBeInTheDocument();
expect(screen.getByRole('table', { name: 'Team Members Table' })).toBeInTheDocument();
// AddNewTeamMemberTrigger is rendered
expect(screen.getByTestId('add-team-member-trigger')).toBeInTheDocument();
expect(screen.getByRole('button', { name: 'Add Team Member' })).toBeInTheDocument();
});
it('renders role cards when "Roles" tab is selected', async () => {
@@ -123,10 +124,10 @@ describe('LibrariesTeamManager', () => {
const rolesTab = await screen.findByRole('tab', { name: /roles/i });
await user.click(rolesTab);
const roleCards = await screen.findAllByTestId('role-card');
const roleCards = await screen.findAllByRole('article', { name: /Role:/ });
const rolesScope = within(roleCards[0]);
expect(roleCards.length).toBe(1);
expect(rolesScope.getByText('Instructor')).toBeInTheDocument();
expect(rolesScope.getByRole('heading', { name: 'Instructor' })).toBeInTheDocument();
expect(screen.getByText(/Can manage content/i)).toBeInTheDocument();
expect(screen.getByText(/1 permissions/i)).toBeInTheDocument();
});
@@ -191,4 +192,12 @@ describe('LibrariesTeamManager', () => {
expect(readPublicToggle).toBeInTheDocument();
expect(readPublicToggle).toBeDisabled();
});
it('renders correct navigation link label and URL on breadcrumb', () => {
renderTeamManager();
const navLink = screen.getByRole('link', { name: 'Manage Access' });
expect(navLink).toBeInTheDocument();
// TODO: Update expected URL when dedicated Manage Access page is created
expect(navLink).toHaveAttribute('href', '/authz/libraries/lib-001');
});
});

View File

@@ -5,6 +5,7 @@ import {
} from '@openedx/paragon';
import { useLibrary } from '@src/authz-module/data/hooks';
import { useLocation } from 'react-router-dom';
import { ROUTES } from '@src/authz-module/constants';
import TeamTable from './components/TeamTable';
import AuthZLayout from '../components/AuthZLayout';
import RoleCard from '../components/RoleCard';
@@ -23,8 +24,9 @@ const LibrariesTeamManager = () => {
libraryId, canManageTeam, roles, permissions, resources,
} = useLibraryAuthZ();
const { data: library } = useLibrary(libraryId);
const rootBradecrumb = intl.formatMessage(messages['library.authz.breadcrumb.root']) || '';
const rootBreadcrumb = intl.formatMessage(messages['library.authz.breadcrumb.root']) || '';
const pageTitle = intl.formatMessage(messages['library.authz.manage.page.title']);
const teamMembersPath = `/authz${ROUTES.LIBRARIES_TEAM_PATH.replace(':libraryId', libraryId)}`;
const [libraryPermissionsByRole, libraryPermissionsByResource] = useMemo(() => {
if (!roles && !permissions && !resources) { return [null, null]; }
@@ -42,7 +44,9 @@ const LibrariesTeamManager = () => {
<div className="authz-libraries">
<AuthZLayout
context={{ id: libraryId, title: library.title, org: library.org }}
navLinks={[{ label: rootBradecrumb }]}
// Temporarily setting '/authz/libraries/:libraryId' as the URL for Manage Access breadcrumb for now as
// currently we do not have a dedicated page. TODO: Update when such page is created.
navLinks={[{ label: rootBreadcrumb, to: teamMembersPath }]}
activeLabel={pageTitle}
pageTitle={pageTitle}
pageSubtitle={libraryId}

View File

@@ -151,6 +151,17 @@ describe('LibrariesUserManager', () => {
expect(screen.getByText('Assign Role')).toBeInTheDocument();
});
it('renders correct navigation link label and URL on breadcrumb', () => {
renderComponent();
const navLinkManageAccess = screen.getByRole('link', { name: 'Manage Access' });
expect(navLinkManageAccess).toBeInTheDocument();
// TODO: Update expected URL when dedicated Manage Access page is created
expect(navLinkManageAccess).toHaveAttribute('href', '/authz/libraries/lib:123');
const navLinkLibraryTeamManagement = screen.getByRole('link', { name: 'Library Team Management' });
expect(navLinkLibraryTeamManagement).toBeInTheDocument();
expect(navLinkLibraryTeamManagement).toHaveAttribute('href', '/authz/libraries/lib:123');
});
describe('Revoking User Role Flow', () => {
it('opens confirmation modal when delete role button is clicked', async () => {
const user = userEvent.setup();

View File

@@ -22,7 +22,7 @@ const LibrariesUserManager = () => {
const {
libraryId, permissions, roles, resources, canManageTeam,
} = useLibraryAuthZ();
const teamMembersPath = `/authz/${ROUTES.LIBRARIES_TEAM_PATH.replace(':libraryId', libraryId)}`;
const teamMembersPath = `/authz${ROUTES.LIBRARIES_TEAM_PATH.replace(':libraryId', libraryId)}`;
useEffect(() => {
if (!canManageTeam) {
@@ -147,7 +147,9 @@ const LibrariesUserManager = () => {
<AuthZLayout
context={{ id: libraryId, title: library.title, org: library.org }}
navLinks={[{ label: rootBreadcrumb }, { label: pageManageTitle, to: teamMembersPath }]}
// Temporarily setting '/authz/libraries/:libraryId' as the URL for Manage Access breadcrumb for now as
// currently we do not have a dedicated page. TODO: Update when such page is created.
navLinks={[{ label: rootBreadcrumb, to: teamMembersPath }, { label: pageManageTitle, to: teamMembersPath }]}
activeLabel={user?.username || ''}
pageTitle={user?.username || ''}
pageSubtitle={<p>{user?.email}</p>}

View File

@@ -137,4 +137,120 @@ describe('ToastManagerContext', () => {
expect(logError).toHaveBeenCalled();
expect(retryFn).toHaveBeenCalled();
});
it('respects custom delay when provided', async () => {
const user = userEvent.setup();
const DelayTestComponent = () => {
const { showToast } = useToastManager();
const handleShowToastWithDelay = () => showToast({
message: 'Custom delay toast',
type: 'success',
delay: 1000, // Custom 1 second delay
});
return (
<button type="button" onClick={handleShowToastWithDelay}>Show Toast With Custom Delay</button>
);
};
renderWrapper(
<ToastManagerProvider>
<DelayTestComponent />
</ToastManagerProvider>,
);
const showButton = screen.getByText('Show Toast With Custom Delay');
await user.click(showButton);
await waitFor(() => {
expect(screen.getByText('Custom delay toast')).toBeInTheDocument();
});
await waitFor(() => {
expect(screen.getByText('Custom delay toast')).toBeInTheDocument();
}, { timeout: 600 });
// Toast should disappear after the custom delay (1000ms)
await waitFor(() => {
expect(screen.queryByText('Custom delay toast')).not.toBeInTheDocument();
}, { timeout: 1200 });
});
it('uses default delay when delay prop is not provided', async () => {
const user = userEvent.setup();
const DefaultDelayTestComponent = () => {
const { showToast } = useToastManager();
const handleShowToastWithoutDelay = () => showToast({
message: 'Default delay toast',
type: 'success',
// No delay prop provided
});
return (
<button type="button" onClick={handleShowToastWithoutDelay}>Show Toast With Default Delay</button>
);
};
renderWrapper(
<ToastManagerProvider>
<DefaultDelayTestComponent />
</ToastManagerProvider>,
);
const showButton = screen.getByText('Show Toast With Default Delay');
await user.click(showButton);
await waitFor(() => {
expect(screen.getByText('Default delay toast')).toBeInTheDocument();
});
// DEFAULT_TOAST_DELAY is 5000ms
await waitFor(() => {
expect(screen.queryByText('Default delay toast')).not.toBeInTheDocument();
}, { timeout: 5050 });
}, 5100);
it('uses longer delay for error toasts with retry functionality', async () => {
const user = userEvent.setup();
const retryFn = jest.fn();
const RetryErrorDelayTestComponent = () => {
const { showErrorToast } = useToastManager();
const handleShowRetryErrorToast = () => showErrorToast(
{ customAttributes: { httpErrorStatus: 500 } },
retryFn,
);
return (
<button type="button" onClick={handleShowRetryErrorToast}>
Show Retry Error Toast
</button>
);
};
renderWrapper(
<ToastManagerProvider>
<RetryErrorDelayTestComponent />
</ToastManagerProvider>,
);
const showButton = screen.getByText('Show Retry Error Toast');
await user.click(showButton);
await waitFor(() => {
expect(screen.getByRole('alert')).toBeInTheDocument();
expect(screen.getByText('Retry')).toBeInTheDocument();
});
await waitFor(() => {
expect(screen.getByRole('alert')).toBeInTheDocument();
}, { timeout: 5050 });
expect(logError).toHaveBeenCalled();
});
});

View File

@@ -5,6 +5,7 @@ import { logError } from '@edx/frontend-platform/logging';
import { useIntl } from '@edx/frontend-platform/i18n';
import { Toast } from '@openedx/paragon';
import messages from './messages';
import { DEFAULT_TOAST_DELAY, RETRY_TOAST_DELAY } from './constants';
type ToastType = 'success' | 'error' | 'error-retry';
@@ -19,11 +20,12 @@ export const ERROR_TOAST_MAP: Record<number | string, { type: ToastType; message
DEFAULT: { type: 'error-retry', messageId: 'library.authz.team.toast.default.error.message' },
};
interface AppToast {
export interface AppToast {
id: string;
message: string;
type: ToastType;
onRetry?: () => void;
delay?: number;
}
const Bold = (chunk: string) => <b>{chunk}</b>;
@@ -47,7 +49,7 @@ export const ToastManagerProvider = ({ children }: ToastManagerProviderProps) =>
const [toasts, setToasts] = useState<(AppToast & { visible: boolean })[]>([]);
const showToast = (toast: Omit<AppToast, 'id'>) => {
const id = `toast-notification-${Date.now()}`;
const id = `toast-notification-${Date.now()}-${Math.floor(Math.random() * 1000000)}`;
const newToast = { ...toast, id, visible: true };
setToasts(prev => [...prev, newToast]);
};
@@ -66,11 +68,19 @@ export const ToastManagerProvider = ({ children }: ToastManagerProviderProps) =>
const errorStatus = error?.customAttributes?.httpErrorStatus;
const toastConfig = ERROR_TOAST_MAP[errorStatus] || ERROR_TOAST_MAP.DEFAULT;
const message = intl.formatMessage(messages[toastConfig.messageId], { Bold, Br });
/**
* For retryable errors, we set a longer delay to give users more time to read the message
* and decide to retry, while for non-retryable errors we use the default delay.
* Since current toast implementation does not allow disabling the autohide prop,
* we use a longer delay for retryable errors to give users more time to read the message.
*/
const delay = toastConfig.type === 'error-retry' && retryFn ? RETRY_TOAST_DELAY : DEFAULT_TOAST_DELAY;
showToast({
message,
type: toastConfig.type,
onRetry: toastConfig.type === 'error-retry' && retryFn ? retryFn : undefined,
delay,
});
};
@@ -92,6 +102,7 @@ export const ToastManagerProvider = ({ children }: ToastManagerProviderProps) =>
key={toast.id}
show={toast.visible}
onClose={() => discardToast(toast.id)}
delay={toast.delay ?? DEFAULT_TOAST_DELAY}
action={toast.onRetry ? {
onClick: () => {
discardToast(toast.id);

View File

@@ -1,4 +1,4 @@
import { FC, useRef } from 'react';
import { useRef } from 'react';
import { useIntl } from '@edx/frontend-platform/i18n';
import {
ActionRow, Form, Hyperlink, Icon, IconButton, ModalDialog,
@@ -24,9 +24,9 @@ interface AddNewTeamMemberModalProps {
handleChangeForm: (e: React.ChangeEvent<HTMLTextAreaElement | HTMLSelectElement>) => void;
}
const AddNewTeamMemberModal: FC<AddNewTeamMemberModalProps> = ({
const AddNewTeamMemberModal = ({
isOpen, isError, isLoading, formValues, close, onSave, handleChangeForm,
}) => {
}: AddNewTeamMemberModalProps) => {
const intl = useIntl();
const { roles } = useLibraryAuthZ();
const [isOpenRolesPopUp, openRolesPopUp, closeRolesPopUp] = useToggle(false);

View File

@@ -1,4 +1,4 @@
import React from 'react';
import React, { act } from 'react';
import { screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { renderWrapper } from '@src/setupTest';
@@ -21,26 +21,27 @@ jest.mock('./AddNewTeamMemberModal', () => {
isOpen, close, onSave, isLoading, formValues, handleChangeForm,
}) => (
isOpen ? (
<div data-testid="add-team-member-modal">
<button type="button" onClick={close} data-testid="close-modal">Close</button>
<button type="button" onClick={onSave} data-testid="save-modal">Save</button>
<div role="dialog" aria-label="Add New Team Member">
<button type="button" onClick={close} aria-label="Close modal">Close</button>
<button type="button" onClick={onSave} aria-label="Save team member">Save</button>
<textarea
name="users"
value={formValues?.users || ''}
onChange={handleChangeForm}
data-testid="users-input"
aria-label="Enter user emails or usernames"
placeholder="Enter emails or usernames"
/>
<select
name="role"
value={formValues?.role || ''}
onChange={handleChangeForm}
data-testid="role-select"
aria-label="Select role"
>
<option value="">Select role</option>
<option value="admin">Admin</option>
<option value="editor">Editor</option>
</select>
{isLoading && <div data-testid="loading-indicator">Loading...</div>}
{isLoading && <div role="status" aria-label="Adding team member loader">Loading...</div>}
</div>
) : null
);
@@ -75,7 +76,7 @@ describe('AddNewTeamMemberTrigger', () => {
const triggerButton = screen.getByRole('button', { name: /add new team member/i });
await user.click(triggerButton);
expect(screen.getByTestId('add-team-member-modal')).toBeInTheDocument();
expect(screen.getByRole('dialog', { name: 'Add New Team Member' })).toBeInTheDocument();
});
it('closes modal when close button is clicked', async () => {
@@ -85,12 +86,12 @@ describe('AddNewTeamMemberTrigger', () => {
const triggerButton = screen.getByRole('button', { name: /add new team member/i });
await user.click(triggerButton);
expect(screen.getByTestId('add-team-member-modal')).toBeInTheDocument();
expect(screen.getByRole('dialog', { name: 'Add New Team Member' })).toBeInTheDocument();
const closeButton = screen.getByTestId('close-modal');
const closeButton = screen.getByRole('button', { name: 'Close modal' });
await user.click(closeButton);
expect(screen.queryByTestId('add-team-member-modal')).not.toBeInTheDocument();
expect(screen.queryByRole('dialog', { name: 'Add New Team Member' })).not.toBeInTheDocument();
});
it('calls addTeamMember with correct data when save is clicked', async () => {
@@ -100,9 +101,9 @@ describe('AddNewTeamMemberTrigger', () => {
const triggerButton = screen.getByRole('button', { name: /add new team member/i });
await user.click(triggerButton);
const usersInput = screen.getByTestId('users-input');
const roleSelect = screen.getByTestId('role-select');
const saveButton = screen.getByTestId('save-modal');
const usersInput = screen.getByRole('textbox', { name: 'Enter user emails or usernames' });
const roleSelect = screen.getByRole('combobox', { name: 'Select role' });
const saveButton = screen.getByRole('button', { name: 'Save team member' });
await user.type(usersInput, 'alice@example.com, bob@example.com');
await user.selectOptions(roleSelect, 'editor');
@@ -129,7 +130,7 @@ describe('AddNewTeamMemberTrigger', () => {
const triggerButton = screen.getByRole('button', { name: /add new team member/i });
await user.click(triggerButton);
const saveButton = screen.getByTestId('save-modal');
const saveButton = screen.getByRole('button', { name: 'Save team member' });
await user.click(saveButton);
// Simulate successful response with no errors
@@ -143,10 +144,10 @@ describe('AddNewTeamMemberTrigger', () => {
});
await waitFor(() => {
expect(screen.queryByTestId('add-team-member-modal')).not.toBeInTheDocument();
expect(screen.queryByRole('dialog', { name: 'Add New Team Member' })).not.toBeInTheDocument();
});
expect(screen.getByText('2 team members added successfully.')).toBeInTheDocument();
expect(screen.getByText(/2 team members added successfully/)).toBeInTheDocument();
});
it('displays mixed success and error toast on partial success', async () => {
@@ -156,7 +157,7 @@ describe('AddNewTeamMemberTrigger', () => {
const triggerButton = screen.getByRole('button', { name: /add new team member/i });
await user.click(triggerButton);
const saveButton = screen.getByTestId('save-modal');
const saveButton = screen.getByRole('button', { name: 'Save team member' });
await user.click(saveButton);
// Simulate partial success response
@@ -176,7 +177,51 @@ describe('AddNewTeamMemberTrigger', () => {
});
// Modal should remain open when there are errors
expect(screen.getByTestId('add-team-member-modal')).toBeInTheDocument();
expect(screen.getByRole('dialog', { name: 'Add New Team Member' })).toBeInTheDocument();
});
it('filters out successfully added users from error users list', async () => {
const user = userEvent.setup();
const mockPartialResponse = {
completed: [
{ userIdentifier: 'alice@example.com' },
],
errors: [
{ userIdentifier: 'bob@example.com', error: 'USER_NOT_FOUND' },
{ userIdentifier: 'charlie@example.com', error: 'USER_NOT_FOUND' },
],
};
(useAssignTeamMembersRole as jest.Mock).mockReturnValue({
mutate: jest.fn((_variables, { onSuccess }) => {
onSuccess(mockPartialResponse);
}),
isPending: false,
});
renderWrapper(<ToastManagerProvider><AddNewTeamMemberTrigger libraryId={mockLibraryId} /></ToastManagerProvider>);
const triggerButton = screen.getByRole('button', { name: /add new team member/i });
await user.click(triggerButton);
const usersInput = screen.getByRole('textbox', { name: /Enter user emails or usernames/i });
const roleSelect = screen.getByRole('combobox', { name: /Select role/i });
const saveButton = screen.getByRole('button', { name: 'Save team member' });
await user.type(usersInput, 'alice@example.com, bob@example.com, charlie@example.com');
await user.selectOptions(roleSelect, 'editor');
await user.click(saveButton);
await waitFor(() => {
expect(usersInput).toHaveValue('bob@example.com, charlie@example.com');
});
await user.type(usersInput, ', new@example.com');
await waitFor(() => {
expect(usersInput).toHaveValue('bob@example.com, charlie@example.com, new@example.com');
});
});
it('displays only error toast when all additions fail', async () => {
@@ -186,7 +231,7 @@ describe('AddNewTeamMemberTrigger', () => {
const triggerButton = screen.getByRole('button', { name: /add new team member/i });
await user.click(triggerButton);
const saveButton = screen.getByTestId('save-modal');
const saveButton = screen.getByRole('button', { name: 'Save team member' });
await user.click(saveButton);
// Simulate all failed response
@@ -204,7 +249,34 @@ describe('AddNewTeamMemberTrigger', () => {
});
// Modal should remain open when there are errors
expect(screen.getByTestId('add-team-member-modal')).toBeInTheDocument();
expect(screen.getByRole('dialog', { name: 'Add New Team Member' })).toBeInTheDocument();
});
it('displays different error toast when different errors happen', async () => {
const user = userEvent.setup();
renderWrapper(<ToastManagerProvider><AddNewTeamMemberTrigger libraryId={mockLibraryId} /></ToastManagerProvider>);
const triggerButton = screen.getByRole('button', { name: /add new team member/i });
await user.click(triggerButton);
const saveButton = screen.getByRole('button', { name: 'Save team member' });
await user.click(saveButton);
const [, { onSuccess }] = mockMutate.mock.calls[0];
onSuccess({
completed: [],
errors: [
{ userIdentifier: 'unknown@example.com', error: 'user_not_found' },
{ userIdentifier: 'already@example.com', error: 'user_already_has_role' },
],
});
await waitFor(() => {
expect(screen.getByText(/We couldn't find a user for 1 email address or username/)).toBeInTheDocument();
expect(screen.getByText(/The user already has the role/)).toBeInTheDocument();
});
expect(screen.getByRole('dialog', { name: 'Add New Team Member' })).toBeInTheDocument();
});
it('resets form values after successful addition with no errors', async () => {
@@ -214,9 +286,9 @@ describe('AddNewTeamMemberTrigger', () => {
const triggerButton = screen.getByRole('button', { name: /add new team member/i });
await user.click(triggerButton);
const usersInput = screen.getByTestId('users-input');
const roleSelect = screen.getByTestId('role-select');
const saveButton = screen.getByTestId('save-modal');
const usersInput = screen.getByRole('textbox', { name: 'Enter user emails or usernames' });
const roleSelect = screen.getByRole('combobox', { name: 'Select role' });
const saveButton = screen.getByRole('button', { name: 'Save team member' });
await user.type(usersInput, 'alice@example.com');
await user.selectOptions(roleSelect, 'editor');
@@ -232,8 +304,8 @@ describe('AddNewTeamMemberTrigger', () => {
// Open modal again to check if form is reset
await user.click(triggerButton);
const newUsersInput = screen.getByTestId('users-input');
const newRoleSelect = screen.getByTestId('role-select');
const newUsersInput = screen.getByRole('textbox', { name: 'Enter user emails or usernames' });
const newRoleSelect = screen.getByRole('combobox', { name: 'Select role' });
expect(newUsersInput).toHaveValue('');
expect(newRoleSelect).toHaveValue('');
@@ -246,7 +318,7 @@ describe('AddNewTeamMemberTrigger', () => {
const triggerButton = screen.getByRole('button', { name: /add new team member/i });
await user.click(triggerButton);
const saveButton = screen.getByTestId('save-modal');
const saveButton = screen.getByRole('button', { name: 'Save team member' });
await user.click(saveButton);
// Simulate successful response
@@ -258,7 +330,7 @@ describe('AddNewTeamMemberTrigger', () => {
// Toast should be visible
await waitFor(() => {
expect(screen.getByText('1 team member added successfully.')).toBeInTheDocument();
expect(screen.getByText(/1 team member added successfully/)).toBeInTheDocument();
});
// Find and close the toast
@@ -289,7 +361,7 @@ describe('AddNewTeamMemberTrigger', () => {
const triggerButton = screen.getByRole('button', { name: /add new team member/i });
await user.click(triggerButton);
const saveButton = screen.getByTestId('save-modal');
const saveButton = screen.getByRole('button', { name: 'Save team member' });
await user.click(saveButton);
await waitFor(() => {
@@ -351,18 +423,20 @@ describe('AddNewTeamMemberTrigger', () => {
const triggerButton = screen.getByRole('button', { name: /add new team member/i });
await user.click(triggerButton);
const userInput = screen.getByTestId('users-input');
const roleSelect = screen.getByTestId('role-select');
const userInput = screen.getByRole('textbox', { name: 'Enter user emails or usernames' });
const roleSelect = screen.getByRole('combobox', { name: 'Select role' });
await user.type(userInput, 'alice@example.com');
await user.selectOptions(roleSelect, 'editor');
const saveButton = screen.getByTestId('save-modal');
const saveButton = screen.getByRole('button', { name: 'Save team member' });
await user.click(saveButton);
// should now reflect isPending = true
const loadingIndicator = await screen.findByTestId('loading-indicator');
expect(loadingIndicator).toBeInTheDocument();
expect(loadingIndicator).toHaveTextContent('Loading...');
act(async () => {
const loadingIndicator = await screen.findByRole('status', { name: 'Adding team member loader' });
expect(loadingIndicator).toBeInTheDocument();
expect(loadingIndicator).toHaveTextContent('Loading...');
});
expect(mutateMock).toHaveBeenCalledWith(
{

View File

@@ -1,4 +1,4 @@
import React, { FC, useState } from 'react';
import React, { useState } from 'react';
import { useIntl } from '@edx/frontend-platform/i18n';
import { Button, useToggle } from '@openedx/paragon';
import { Plus } from '@openedx/paragon/icons';
@@ -6,10 +6,12 @@ import { Plus } from '@openedx/paragon/icons';
import { PutAssignTeamMembersRoleResponse } from 'authz-module/data/api';
import { useAssignTeamMembersRole } from '@src/authz-module/data/hooks';
import { RoleOperationErrorStatus } from '@src/authz-module/constants';
import { useToastManager } from '@src/authz-module/libraries-manager/ToastManagerContext';
import { AppToast, useToastManager } from '@src/authz-module/libraries-manager/ToastManagerContext';
import { DEFAULT_TOAST_DELAY } from '@src/authz-module/libraries-manager/constants';
import AddNewTeamMemberModal from './AddNewTeamMemberModal';
import messages from './messages';
type AppToastOmitIdType = Omit<AppToast, 'id'>;
interface AddNewTeamMemberTriggerProps {
libraryId: string;
}
@@ -19,7 +21,7 @@ const DEFAULT_FORM_VALUES = {
role: '',
};
const AddNewTeamMemberTrigger: FC<AddNewTeamMemberTriggerProps> = ({ libraryId }) => {
const AddNewTeamMemberTrigger = ({ libraryId }: AddNewTeamMemberTriggerProps) => {
const intl = useIntl();
const [isOpen, open, close] = useToggle(false);
const [formValues, setFormValues] = useState(DEFAULT_FORM_VALUES);
@@ -58,53 +60,72 @@ const AddNewTeamMemberTrigger: FC<AddNewTeamMemberTriggerProps> = ({ libraryId }
setFormValues((prev) => ({ ...prev, [name]: value }));
};
const handleErrors = (
const buildErrorMessages = (
errors: PutAssignTeamMembersRoleResponse['errors'],
successfulCount: number,
) => {
): Array<AppToastOmitIdType> => {
const notFoundUsers = errors
.filter((err) => err.error === RoleOperationErrorStatus.USER_NOT_FOUND)
.map((err) => err.userIdentifier.trim());
const alreadyHasRole = errors.some(
(err) => err.error === RoleOperationErrorStatus.USER_ALREADY_HAS_ROLE,
const otherErrors = errors.filter(
(err) => err.error !== RoleOperationErrorStatus.USER_NOT_FOUND
&& err.error !== RoleOperationErrorStatus.USER_ALREADY_HAS_ROLE,
);
if (alreadyHasRole && errors.length === 1 && !successfulCount) {
showToast({
message: intl.formatMessage(messages['libraries.authz.manage.assign.role.existing']),
type: 'error',
const result: Array<AppToastOmitIdType> = [];
const errorTypes = [
{
errorMessageId: 'libraries.authz.manage.add.member.failure.not.found',
users: notFoundUsers,
},
{
errorMessageId: 'libraries.authz.manage.add.member.failure.generic',
users: otherErrors,
},
];
errorTypes.forEach(({ errorMessageId, users }) => {
if (users.length === 0) { return; }
const errorMessage = intl.formatMessage(messages[errorMessageId], {
count: users.length,
userIds: users.join(', '),
Bold,
Br,
});
handleClose();
return;
}
result.push({ message: errorMessage, type: 'error' });
});
if (notFoundUsers.length) {
setErrorUsers(notFoundUsers);
setIsError(true);
setFormValues((prev) => ({
...prev,
users: notFoundUsers.join(', '),
}));
return result;
};
const toastMessage = successfulCount
? intl.formatMessage(messages['libraries.authz.manage.add.member.partial'], {
countSuccess: successfulCount,
countFailure: notFoundUsers.length,
Bold,
Br,
})
: intl.formatMessage(messages['libraries.authz.manage.add.member.failure'], {
count: notFoundUsers.length,
Bold,
Br,
});
const buildSuccessMessage = (completed: PutAssignTeamMembersRoleResponse['completed']): AppToastOmitIdType => {
const userIds = completed.map((user) => user.userIdentifier).join(', ');
const successMessage = intl.formatMessage(messages['libraries.authz.manage.add.member.success'], {
count: completed.length,
userIds,
});
showToast({
message: toastMessage,
type: 'error',
});
}
return {
message: successMessage,
type: 'success',
};
};
const buildRoleAlreadyAssignedMessage = (
roleAlreadyAsignedUsers: PutAssignTeamMembersRoleResponse['errors'],
): AppToastOmitIdType => {
const roleAlreadyAssignedUserIds = roleAlreadyAsignedUsers.map((err) => err.userIdentifier.trim());
const roleAlreadyAssignedMessage = intl.formatMessage(messages['libraries.authz.manage.assign.role.existing'], {
count: roleAlreadyAssignedUserIds.length,
userIds: roleAlreadyAssignedUserIds.join(', '),
Bold,
Br,
});
return {
message: roleAlreadyAssignedMessage,
type: 'success',
};
};
const handleAddTeamMember = () => {
@@ -125,20 +146,44 @@ const AddNewTeamMemberTrigger: FC<AddNewTeamMemberTriggerProps> = ({ libraryId }
assignTeamMembersRole(variables, {
onSuccess: (response) => {
const { completed, errors } = response;
const feedbackMessages: Array<AppToastOmitIdType> = [];
const { USER_ALREADY_HAS_ROLE } = RoleOperationErrorStatus;
// Users who already have the role assigned are not considered errors
const roleAlreadyAssignedUsers = errors.filter((error) => error.error === USER_ALREADY_HAS_ROLE);
const cleanErrors = errors.filter((error) => error.error !== USER_ALREADY_HAS_ROLE);
if (completed.length && !errors.length) {
showToast({
message: intl.formatMessage(messages['libraries.authz.manage.add.member.success'], {
count: completed.length,
}),
type: 'success',
});
handleClose();
return;
if (completed.length) {
feedbackMessages.push(buildSuccessMessage(completed));
}
if (roleAlreadyAssignedUsers.length) {
feedbackMessages.push(buildRoleAlreadyAssignedMessage(roleAlreadyAssignedUsers));
}
if (cleanErrors.length) {
const errorMessages = buildErrorMessages(cleanErrors);
feedbackMessages.push(...errorMessages);
const successUserIds = [
...completed.map(c => c.userIdentifier),
...roleAlreadyAssignedUsers.map(r => r.userIdentifier),
];
const errorUserIds = normalizedUsers.filter((user) => !successUserIds.includes(user));
setErrorUsers(errorUserIds);
setIsError(true);
setFormValues((prev) => ({
...prev,
users: errorUserIds.join(', '),
}));
}
if (errors.length) {
handleErrors(errors, completed.length);
// Calculate delay based on the number of feedback messages, 5 seconds per message
const delay = DEFAULT_TOAST_DELAY * feedbackMessages.length;
feedbackMessages.forEach(({ message, type }) => {
showToast({ message, type, delay });
});
if (!cleanErrors.length) {
handleClose();
}
},
onError: (error, retryVariables) => {

View File

@@ -53,22 +53,22 @@ const messages = defineMessages({
},
'libraries.authz.manage.add.member.success': {
id: 'libraries.authz.manage.add.member.success',
defaultMessage: '{count, plural, one {# team member added successfully.} other {# team members added successfully.}}',
defaultMessage: '{count, plural, one {# team member added successfully} other {# team members added successfully}} ({userIds})',
description: 'Success message when adding new team members',
},
'libraries.authz.manage.add.member.failure': {
id: 'libraries.authz.manage.add.member.failure',
defaultMessage: '<Bold>We couldn\'t find a user for {count, plural, one {# email address or username.} other {# email addresses or usernames.}}</Bold><Br></Br> Please check the values and try again, or invite them to join your organization first.',
description: 'Error message when adding new team members',
'libraries.authz.manage.add.member.failure.not.found': {
id: 'libraries.authz.manage.add.member.failure.not.found',
defaultMessage: '<Bold>We couldn\'t find a user for {count, plural, one {# email address or username} other {# email addresses or usernames}}.</Bold><Br></Br> Please check the values ({userIds}) and try again, or invite them to join your organization first.',
description: 'Error message in case of user not found when adding new team members',
},
'libraries.authz.manage.add.member.partial': {
id: 'libraries.authz.manage.add.member.failure',
defaultMessage: '<Bold>{countSuccess, plural, one {# team member added successfully.} other {# team members added successfully.}}. We couldn\'t find a user for {countFailure, plural, one {# email address or username.} other {# email addresses or usernames.}}</Bold><Br></Br> Please check the values and try again, or invite them to join your organization first.',
description: 'Error message when adding new team members',
'libraries.authz.manage.add.member.failure.generic': {
id: 'libraries.authz.manage.add.member.failure.generic',
defaultMessage: '<Bold>We couldn\'t assign the role to {count, plural, one {team member} other {team members}} ({userIds})}.</Bold><Br></Br> Please check the values and try again.',
description: 'Generic error message when adding new team members',
},
'libraries.authz.manage.assign.role.existing': {
id: 'libraries.authz.manage.assign.existing',
defaultMessage: 'The user already has the role.',
defaultMessage: 'The {count, plural, one {user already has} other {users already have}} the role ({userIds}).',
description: 'Libraries AuthZ assign existing role',
},
'libraries.authz.manage.tooltip.roles.extra.info': {

View File

@@ -1,4 +1,3 @@
import { FC } from 'react';
import { useIntl } from '@edx/frontend-platform/i18n';
import {
ActionRow, Button, Form, ModalDialog,
@@ -16,9 +15,9 @@ interface AssignNewRoleModalProps {
handleChangeSelectedRole: (e: React.ChangeEvent<HTMLTextAreaElement | HTMLSelectElement>) => void;
}
const AssignNewRoleModal: FC<AssignNewRoleModalProps> = ({
const AssignNewRoleModal = ({
isOpen, isLoading, selectedRole, roleOptions, close, onSave, handleChangeSelectedRole,
}) => {
}: AssignNewRoleModalProps) => {
const intl = useIntl();
return (
<ModalDialog

View File

@@ -26,9 +26,9 @@ jest.mock('./AssignNewRoleModal', () => {
selectedRole,
handleChangeSelectedRole,
}: any) => (isOpen ? (
<div data-testid="assign-new-role-modal">
<div role="dialog" aria-label="Assign New Role">
<h2>Add New Role</h2>
<select data-testid="role-select" value={selectedRole} onChange={handleChangeSelectedRole}>
<select value={selectedRole} onChange={handleChangeSelectedRole} aria-label="Select role">
<option value="">Select a role</option>
{roleOptions.map((role: any) => (
<option key={role.role} value={role.role}>
@@ -36,10 +36,10 @@ jest.mock('./AssignNewRoleModal', () => {
</option>
))}
</select>
<button type="button" onClick={onSave} disabled={isLoading} data-testid="save-button">
<button type="button" onClick={onSave} disabled={isLoading} aria-label="Save role assignment">
{isLoading ? 'Saving...' : 'Save'}
</button>
<button type="button" onClick={close} data-testid="cancel-button">
<button type="button" onClick={close} aria-label="Cancel role assignment">
Cancel
</button>
</div>
@@ -106,7 +106,7 @@ describe('AssignNewRoleTrigger', () => {
it('does not show modal initially', () => {
renderComponent();
expect(screen.queryByTestId('assign-new-role-modal')).not.toBeInTheDocument();
expect(screen.queryByRole('dialog', { name: 'Assign New Role' })).not.toBeInTheDocument();
});
it('does not show toast initially', () => {
@@ -124,7 +124,7 @@ describe('AssignNewRoleTrigger', () => {
const triggerButton = screen.getByRole('button', { name: /add new role/i });
await user.click(triggerButton);
expect(screen.getByTestId('assign-new-role-modal')).toBeInTheDocument();
expect(screen.getByRole('dialog', { name: 'Assign New Role' })).toBeInTheDocument();
expect(screen.getByRole('heading', { name: /add new role/i })).toBeInTheDocument();
});
@@ -134,11 +134,11 @@ describe('AssignNewRoleTrigger', () => {
// Open modal
await user.click(screen.getByRole('button', { name: /add new role/i }));
expect(screen.getByTestId('assign-new-role-modal')).toBeInTheDocument();
expect(screen.getByRole('dialog', { name: 'Assign New Role' })).toBeInTheDocument();
// Close modal
await user.click(screen.getByTestId('cancel-button'));
expect(screen.queryByTestId('assign-new-role-modal')).not.toBeInTheDocument();
await user.click(screen.getByRole('button', { name: 'Cancel role assignment' }));
expect(screen.queryByRole('dialog', { name: 'Assign New Role' })).not.toBeInTheDocument();
});
});
@@ -149,7 +149,7 @@ describe('AssignNewRoleTrigger', () => {
await user.click(screen.getByRole('button', { name: /add new role/i }));
const roleSelect = screen.getByTestId('role-select');
const roleSelect = screen.getByRole('combobox', { name: 'Select role' });
await user.selectOptions(roleSelect, 'admin');
expect(roleSelect).toHaveValue('admin');
@@ -163,11 +163,11 @@ describe('AssignNewRoleTrigger', () => {
await user.click(screen.getByRole('button', { name: /add new role/i }));
// Select a role
const roleSelect = screen.getByTestId('role-select');
const roleSelect = screen.getByRole('combobox', { name: 'Select role' });
await user.selectOptions(roleSelect, choosenRole);
// Click save
await user.click(screen.getByTestId('save-button'));
await user.click(screen.getByRole('button', { name: 'Save role assignment' }));
expect(mockMutate).toHaveBeenCalledWith(
{
@@ -191,15 +191,15 @@ describe('AssignNewRoleTrigger', () => {
await user.click(screen.getByRole('button', { name: /add new role/i }));
// Select a role that user already has
const roleSelect = screen.getByTestId('role-select');
const roleSelect = screen.getByRole('combobox', { name: 'Select role' });
await user.selectOptions(roleSelect, choosenRole);
await user.click(screen.getByTestId('save-button'));
await user.click(screen.getByRole('button', { name: 'Save role assignment' }));
// Should not call assignTeamMembersRole
expect(mockMutate).not.toHaveBeenCalled();
// Modal should be closed
expect(screen.queryByTestId('assign-new-role-modal')).not.toBeInTheDocument();
expect(screen.queryByRole('dialog', { name: 'Assign New Role' })).not.toBeInTheDocument();
});
});
@@ -215,7 +215,7 @@ describe('AssignNewRoleTrigger', () => {
await user.click(screen.getByRole('button', { name: /add new role/i }));
expect(screen.getByTestId('save-button')).toBeDisabled();
expect(screen.getByRole('button', { name: 'Save role assignment' })).toBeDisabled();
expect(screen.getByText('Saving...')).toBeInTheDocument();
});
});
@@ -227,10 +227,10 @@ describe('AssignNewRoleTrigger', () => {
await user.click(screen.getByRole('button', { name: /add new role/i }));
const roleSelect = screen.getByTestId('role-select');
const roleSelect = screen.getByRole('combobox', { name: 'Select role' });
await user.selectOptions(roleSelect, 'admin');
await user.click(screen.getByTestId('save-button'));
await user.click(screen.getByRole('button', { name: 'Save role assignment' }));
// Simulate successful API call
const onSuccessCallback = mockMutate.mock.calls[0][1].onSuccess;
@@ -247,22 +247,22 @@ describe('AssignNewRoleTrigger', () => {
await user.click(screen.getByRole('button', { name: /add new role/i }));
const roleSelect = screen.getByTestId('role-select');
const roleSelect = screen.getByRole('combobox', { name: 'Select role' });
await user.selectOptions(roleSelect, 'admin');
await user.click(screen.getByTestId('save-button'));
await user.click(screen.getByRole('button', { name: 'Save role assignment' }));
// Simulate successful API call
const onSuccessCallback = mockMutate.mock.calls[0][1].onSuccess;
onSuccessCallback({ errors: [] });
await waitFor(() => {
expect(screen.queryByTestId('assign-new-role-modal')).not.toBeInTheDocument();
expect(screen.queryByRole('dialog', { name: 'Assign New Role' })).not.toBeInTheDocument();
});
// Open modal again to check if role is reset
await user.click(screen.getByRole('button', { name: /add new role/i }));
expect(screen.getByTestId('role-select')).toHaveValue('');
expect(screen.getByRole('combobox', { name: 'Select role' })).toHaveValue('');
});
});
@@ -273,15 +273,15 @@ describe('AssignNewRoleTrigger', () => {
renderComponent();
await user.click(screen.getByRole('button', { name: /add new role/i }));
await user.selectOptions(screen.getByTestId('role-select'), 'admin');
await user.click(screen.getByTestId('save-button'));
await user.selectOptions(screen.getByRole('combobox', { name: 'Select role' }), 'admin');
await user.click(screen.getByRole('button', { name: 'Save role assignment' }));
const { onSuccess } = mockMutate.mock.calls[0][1];
onSuccess({ errors: [{ error: 'role_assignment_error' }] });
await waitFor(() => {
expect(screen.getByText(/Something went wrong/i)).toBeInTheDocument();
expect(screen.getByTestId('role-select')).toHaveValue(''); // role reset
expect(screen.getByRole('combobox', { name: 'Select role' })).toHaveValue(''); // role reset
});
});
@@ -306,8 +306,8 @@ describe('AssignNewRoleTrigger', () => {
// Open modal and select a role
await user.click(screen.getByRole('button', { name: /add new role/i }));
await user.selectOptions(screen.getByTestId('role-select'), 'admin');
await user.click(screen.getByTestId('save-button'));
await user.selectOptions(screen.getByRole('combobox', { name: 'Select role' }), 'admin');
await user.click(screen.getByRole('button', { name: 'Save role assignment' }));
// Wait for the error toast to appear with a retry button
await waitFor(() => {

View File

@@ -1,4 +1,4 @@
import { FC, useState } from 'react';
import { useState } from 'react';
import { useIntl } from '@edx/frontend-platform/i18n';
import { Button, useToggle } from '@openedx/paragon';
import { Plus } from '@openedx/paragon/icons';
@@ -17,11 +17,11 @@ interface AssignNewRoleTriggerProps {
currentUserRoles: string[];
}
const AssignNewRoleTrigger: FC<AssignNewRoleTriggerProps> = ({
const AssignNewRoleTrigger = ({
username,
libraryId,
currentUserRoles,
}) => {
}: AssignNewRoleTriggerProps) => {
const intl = useIntl();
const [isOpen, open, close] = useToggle(false);
const { roles } = useLibraryAuthZ();

View File

@@ -1,4 +1,3 @@
import { FC } from 'react';
import {
ActionRow, AlertModal, Icon, ModalDialog, Stack,
StatefulButton,
@@ -21,9 +20,9 @@ interface ConfirmDeletionModalProps {
}
}
const ConfirmDeletionModal: FC<ConfirmDeletionModalProps> = ({
const ConfirmDeletionModal = ({
isOpen, close, onSave, isDeleting, context,
}) => {
}: ConfirmDeletionModalProps) => {
const intl = useIntl();
return (
<AlertModal

View File

@@ -0,0 +1,183 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { IntlProvider } from '@edx/frontend-platform/i18n';
import { useNavigate } from 'react-router-dom';
import { useLibraryAuthZ } from '@src/authz-module/libraries-manager/context';
import { useTeamMembers } from '@src/authz-module/data/hooks';
import {
EmailCell,
NameCell,
ActionCell,
RolesCell,
} from './Cells';
jest.mock('react-router-dom', () => ({
useNavigate: jest.fn(),
}));
jest.mock('@src/authz-module/libraries-manager/context', () => ({
useLibraryAuthZ: jest.fn(),
}));
jest.mock('@src/authz-module/data/hooks', () => ({
useTeamMembers: jest.fn(),
}));
jest.mock('../hooks/useQuerySettings', () => ({
useQuerySettings: jest.fn(() => ({
querySettings: { page: 1, limit: 10 },
})),
}));
const mockNavigate = useNavigate as jest.Mock;
const mockUseLibraryAuthZ = useLibraryAuthZ as jest.Mock;
const mockUseTeamMembers = useTeamMembers as jest.Mock;
const renderWithIntl = (component: React.ReactElement) => render(
<IntlProvider locale="en" messages={{}}>
{component}
</IntlProvider>,
);
const mockTeamMember = {
username: 'john.doe',
fullName: 'John Doe',
email: 'john.doe@example.com',
roles: ['instructor', 'author'],
createdAt: '2023-01-01T00:00:00Z',
};
const mockSkeletonMember = {
username: 'skeleton',
fullName: '',
email: '',
roles: [],
createdAt: '',
};
const mockCellProps = {
row: { original: mockTeamMember },
};
const mockSkeletonCellProps = {
row: { original: mockSkeletonMember },
};
describe('Table Cells', () => {
beforeEach(() => {
jest.clearAllMocks();
mockUseLibraryAuthZ.mockReturnValue({
username: 'current.user',
libraryId: 'lib123',
canManageTeam: true,
roles: [
{ role: 'instructor', name: 'Instructor' },
{ role: 'author', name: 'Author' },
],
});
mockUseTeamMembers.mockReturnValue({ isLoading: false });
mockNavigate.mockReturnValue(jest.fn());
});
describe('EmailCell', () => {
it('displays user email', () => {
renderWithIntl(<EmailCell {...mockCellProps} />);
expect(screen.getByText('john.doe@example.com')).toBeInTheDocument();
});
it('shows loading skeleton for loading state', () => {
renderWithIntl(<EmailCell {...mockSkeletonCellProps} />);
expect(document.querySelector('.react-loading-skeleton')).toBeInTheDocument();
});
});
describe('NameCell', () => {
it('displays username for regular user', () => {
renderWithIntl(<NameCell {...mockCellProps} />);
expect(screen.getByText('john.doe')).toBeInTheDocument();
});
it('displays current user indicator for logged in user', () => {
const currentUserProps = {
...mockCellProps,
row: { original: { ...mockTeamMember, username: 'current.user' } },
};
renderWithIntl(<NameCell {...currentUserProps} />);
expect(screen.getByText('current.user')).toBeInTheDocument();
expect(screen.getByText('current.user').parentElement).toBeInTheDocument();
});
it('shows loading skeleton for loading state', () => {
renderWithIntl(<NameCell {...mockSkeletonCellProps} />);
expect(document.querySelector('.react-loading-skeleton')).toBeInTheDocument();
});
});
describe('ActionCell', () => {
it('renders edit button for manageable team member', () => {
renderWithIntl(<ActionCell {...mockCellProps} />);
const editButton = screen.getByRole('button');
expect(editButton).toBeInTheDocument();
expect(document.querySelector('.pgn__icon')).toBeInTheDocument();
expect(document.querySelector('svg')).toBeInTheDocument();
});
it('navigates to user page when edit button is clicked', async () => {
const user = userEvent.setup();
const navigateMock = jest.fn();
mockNavigate.mockReturnValue(navigateMock);
renderWithIntl(<ActionCell {...mockCellProps} />);
const editButton = screen.getByRole('button');
await user.click(editButton);
expect(navigateMock).toHaveBeenCalledWith('/authz/libraries/lib123/john.doe');
});
it('does not render edit button for current user', () => {
const currentUserProps = {
...mockCellProps,
row: { original: { ...mockTeamMember, username: 'current.user' } },
};
renderWithIntl(<ActionCell {...currentUserProps} />);
expect(screen.queryByRole('button')).not.toBeInTheDocument();
});
it('does not render edit button when user cannot manage team', () => {
mockUseLibraryAuthZ.mockReturnValue({
username: 'current.user',
libraryId: 'lib123',
canManageTeam: false,
roles: [],
});
renderWithIntl(<ActionCell {...mockCellProps} />);
expect(screen.queryByRole('button')).not.toBeInTheDocument();
});
it('does not render edit button during loading', () => {
mockUseTeamMembers.mockReturnValue({ isLoading: true });
renderWithIntl(<ActionCell {...mockCellProps} />);
expect(screen.queryByRole('button')).not.toBeInTheDocument();
});
});
describe('RolesCell', () => {
it('displays role chips for user roles', () => {
renderWithIntl(<RolesCell {...mockCellProps} />);
expect(screen.getByText('Instructor')).toBeInTheDocument();
expect(screen.getByText('Author')).toBeInTheDocument();
});
it('shows loading skeleton for loading state', () => {
renderWithIntl(<RolesCell {...mockSkeletonCellProps} />);
expect(document.querySelector('.react-loading-skeleton')).toBeInTheDocument();
});
it('handles user with no roles', () => {
const noRolesProps = {
...mockCellProps,
row: { original: { ...mockTeamMember, roles: [] } },
};
renderWithIntl(<RolesCell {...noRolesProps} />);
expect(screen.queryByText('Instructor')).not.toBeInTheDocument();
expect(screen.queryByText('Author')).not.toBeInTheDocument();
});
});
});

View File

@@ -0,0 +1,74 @@
import { useIntl } from '@edx/frontend-platform/i18n';
import { Button, Chip, Skeleton } from '@openedx/paragon';
import { Edit } from '@openedx/paragon/icons';
import { TableCellValue, TeamMember } from '@src/types';
import { useLibraryAuthZ } from '@src/authz-module/libraries-manager/context';
import { useNavigate } from 'react-router-dom';
import { useTeamMembers } from '@src/authz-module/data/hooks';
import { SKELETON_ROWS } from '@src/authz-module/libraries-manager/constants';
import { useQuerySettings } from '../hooks/useQuerySettings';
import messages from '../messages';
type CellProps = TableCellValue<TeamMember>;
const EmailCell = ({ row }: CellProps) => (row.original?.username === SKELETON_ROWS[0].username ? (
<Skeleton width="180px" />
) : (
row.original.email
));
const NameCell = ({ row }: CellProps) => {
const intl = useIntl();
const { username } = useLibraryAuthZ();
if (row.original.username === SKELETON_ROWS[0].username) {
return <Skeleton width="180px" />;
}
if (row.original.username === username) {
return (
<span>
{username}
<span className="text-gray-500">{intl.formatMessage(messages['library.authz.team.table.username.current'])}</span>
</span>
);
}
return row.original.username;
};
const ActionCell = ({ row }: CellProps) => {
const intl = useIntl();
const {
libraryId, canManageTeam, username,
} = useLibraryAuthZ();
const navigate = useNavigate();
const { querySettings } = useQuerySettings();
const { isLoading } = useTeamMembers(libraryId, querySettings);
return (
canManageTeam && row.original.username !== username && !isLoading ? (
<Button
iconBefore={Edit}
variant="link"
size="sm"
onClick={() => navigate(`/authz/libraries/${libraryId}/${row.original.username}`)}
>
{intl.formatMessage(messages['authz.libraries.team.table.edit.action'])}
</Button>
) : null);
};
const RolesCell = ({ row }: CellProps) => {
const { roles } = useLibraryAuthZ();
const roleLabels = roles.reduce((acc, role) => ({ ...acc, [role.role]: role.name }), {} as Record<string, string>);
return (row.original.username === SKELETON_ROWS[0].username ? (
<Skeleton width="80px" />
) : (
row.original.roles.map((role) => (
<Chip key={`${row.original.username}-role-${role}`}>{roleLabels[role]}</Chip>
))
));
};
export {
EmailCell, NameCell, ActionCell, RolesCell,
};

View File

@@ -1,4 +1,3 @@
import { FC } from 'react';
import {
Dropdown, Form, Icon, Stack,
} from '@openedx/paragon';
@@ -11,9 +10,9 @@ interface MultipleChoiceFilterProps {
setFilter: (value: string[]) => void;
}
const MultipleChoiceFilter: FC<MultipleChoiceFilterProps> = ({
const MultipleChoiceFilter = ({
Header, filterChoices, filterValue, setFilter,
}) => {
}: MultipleChoiceFilterProps) => {
const checkedBoxes = filterValue || [];
const changeCheckbox = (value) => {

View File

@@ -1,4 +1,3 @@
import { FC } from 'react';
import {
Form,
Icon,
@@ -11,9 +10,9 @@ interface SearchFilterProps {
placeholder: string;
}
const SearchFilter: FC<SearchFilterProps> = ({
const SearchFilter = ({
filterValue, setFilter, placeholder,
}) => (
}: SearchFilterProps) => (
<Form.Control
className="mw-xs mr-0"
trailingElement={<Icon src={Search} />}

View File

@@ -7,10 +7,8 @@ import userEvent from '@testing-library/user-event';
import TableControlBar from './TableControlBar';
jest.mock('./MultipleChoiceFilter', () => {
// eslint-disable-next-line react/prop-types
const MockMultipleChoiceFilter = (props) => (
// eslint-disable-next-line react/prop-types
<div data-testid="multiple-choice-filter" data-column-id={props.id || props.accessor}>
const MockMultipleChoiceFilter = (props: { id?: string; accessor?: string }) => (
<div role="group" aria-label={`Filter by ${props.id || props.accessor}`}>
Multiple Choice Filter
</div>
);
@@ -20,7 +18,7 @@ jest.mock('./MultipleChoiceFilter', () => {
jest.mock('./SortDropdown', () => {
const MockSortDropdown = () => (
<div data-testid="sort-dropdown">
<div role="group" aria-label="Sort options">
Sort Dropdown
</div>
);
@@ -31,7 +29,7 @@ jest.mock('./SortDropdown', () => {
jest.mock('./SearchFilter', () => {
// eslint-disable-next-line react/prop-types
const MockSearchFilter = (props) => (
<div data-testid="search-filter">
<div role="search" aria-label="Search filter">
<input
// eslint-disable-next-line react/prop-types
placeholder={props.placeholder}
@@ -39,7 +37,7 @@ jest.mock('./SearchFilter', () => {
value={props.filterValue || ''}
// eslint-disable-next-line react/prop-types
onChange={(e) => props.setFilter(e.target.value)}
data-testid="search-input"
aria-label="Search input"
/>
</div>
);
@@ -74,7 +72,7 @@ describe('TableControlBar', () => {
it('should render basic structure with SortDropdown and RowStatus', () => {
renderWithContext();
expect(screen.getByTestId('sort-dropdown')).toBeInTheDocument();
expect(screen.getByRole('group', { name: 'Sort options' })).toBeInTheDocument();
const container = screen.getByText('Sort Dropdown').closest('.pgn__data-table-status-bar');
expect(container).toHaveClass('pgn__data-table-status-bar', 'mb-3', 'flex-wrap');
});
@@ -131,9 +129,9 @@ describe('TableControlBar', () => {
renderWithContext(contextWithCheckboxColumn);
const multipleChoiceFilter = screen.getByTestId('multiple-choice-filter');
const multipleChoiceFilter = screen.getByRole('group', { name: 'Filter by roles' });
expect(multipleChoiceFilter).toBeInTheDocument();
expect(multipleChoiceFilter).toHaveAttribute('data-column-id', 'roles');
expect(screen.getByText('Multiple Choice Filter')).toBeInTheDocument();
});
it('should render SearchFilter for columns with TextFilter', () => {
@@ -154,8 +152,8 @@ describe('TableControlBar', () => {
renderWithContext(contextWithTextColumn);
expect(screen.getByTestId('search-filter')).toBeInTheDocument();
expect(screen.getByTestId('search-input')).toBeInTheDocument();
expect(screen.getByRole('search', { name: 'Search filter' })).toBeInTheDocument();
expect(screen.getByRole('textbox', { name: 'Search input' })).toBeInTheDocument();
});
it('should not render any filter for unsupported Filter types', () => {
@@ -176,8 +174,8 @@ describe('TableControlBar', () => {
renderWithContext(contextWithCustomFilter);
// Only SortDropdown should be present, no filter components
expect(screen.getByTestId('sort-dropdown')).toBeInTheDocument();
expect(screen.queryByTestId('search-filter')).not.toBeInTheDocument();
expect(screen.queryByTestId('multiple-choice-filter')).not.toBeInTheDocument();
expect(screen.getByRole('group', { name: 'Sort options' })).toBeInTheDocument();
expect(screen.queryByRole('search', { name: 'Search filter' })).not.toBeInTheDocument();
expect(screen.queryByRole('group', { name: /Filter by/ })).not.toBeInTheDocument();
});
});

View File

@@ -4,6 +4,7 @@ import { renderWrapper } from '@src/setupTest';
import { useTeamMembers } from '@src/authz-module/data/hooks';
import { useLibraryAuthZ } from '@src/authz-module/libraries-manager/context';
import { ToastManagerProvider } from '@src/authz-module/libraries-manager/ToastManagerContext';
import { CONTENT_LIBRARY_PERMISSIONS } from '@src/authz-module/libraries-manager/constants';
import TeamTable from './index';
const mockNavigate = jest.fn();
@@ -45,9 +46,9 @@ describe('TeamTable', () => {
{
role: 'admin',
permissions: [
'delete_library',
'publish_library',
'manage_library_team',
CONTENT_LIBRARY_PERMISSIONS.DELETE_LIBRARY,
CONTENT_LIBRARY_PERMISSIONS.PUBLISH_LIBRARY_CONTENT,
CONTENT_LIBRARY_PERMISSIONS.MANAGE_LIBRARY_TEAM,
],
userCount: 3,
name: 'Admin',
@@ -56,8 +57,8 @@ describe('TeamTable', () => {
{
role: 'editor',
permissions: [
'edit_library',
'publish_library',
CONTENT_LIBRARY_PERMISSIONS.EDIT_LIBRARY_CONTENT,
CONTENT_LIBRARY_PERMISSIONS.PUBLISH_LIBRARY_CONTENT,
],
userCount: 3,
name: 'Editor',
@@ -66,7 +67,7 @@ describe('TeamTable', () => {
{
role: 'viewer',
permissions: [
'view_library',
CONTENT_LIBRARY_PERMISSIONS.VIEW_LIBRARY,
],
userCount: 3,
name: 'Viewer',

View File

@@ -1,70 +1,37 @@
import { useEffect, useMemo } from 'react';
import { useNavigate } from 'react-router-dom';
import debounce from 'lodash.debounce';
import { useIntl } from '@edx/frontend-platform/i18n';
import {
DataTable, Button, Chip, Skeleton,
DataTable,
TextFilter,
CheckboxFilter,
TableFooter,
} from '@openedx/paragon';
import { Edit } from '@openedx/paragon/icons';
import { TableCellValue, TeamMember } from '@src/types';
import { useTeamMembers } from '@src/authz-module/data/hooks';
import { useLibraryAuthZ } from '@src/authz-module/libraries-manager/context';
import { useToastManager } from '@src/authz-module/libraries-manager/ToastManagerContext';
import { SKELETON_ROWS } from '@src/authz-module/libraries-manager/constants';
import { useQuerySettings } from './hooks/useQuerySettings';
import TableControlBar from './components/TableControlBar';
import messages from './messages';
const SKELETON_ROWS = Array.from({ length: 10 }).map(() => ({
username: 'skeleton',
name: '',
email: '',
roles: [],
}));
import {
ActionCell, EmailCell, NameCell, RolesCell,
} from './components/Cells';
const DEFAULT_PAGE_SIZE = 10;
type CellProps = TableCellValue<TeamMember>;
const EmailCell = ({ row }: CellProps) => (row.original?.username === SKELETON_ROWS[0].username ? (
<Skeleton width="180px" />
) : (
row.original.email
));
const NameCell = ({ row }: CellProps) => {
const intl = useIntl();
const { username } = useLibraryAuthZ();
if (row.original.username === SKELETON_ROWS[0].username) {
return <Skeleton width="180px" />;
}
if (row.original.username === username) {
return (
<span>
{username}
<span className="text-gray-500">{intl.formatMessage(messages['library.authz.team.table.username.current'])}</span>
</span>
);
}
return row.original.username;
};
const TeamTable = () => {
const intl = useIntl();
const {
libraryId, canManageTeam, username, roles,
libraryId, roles,
} = useLibraryAuthZ();
const roleLabels = roles.reduce((acc, role) => ({ ...acc, [role.role]: role.name }), {} as Record<string, string>);
const { showErrorToast } = useToastManager();
const { querySettings, handleTableFetch } = useQuerySettings();
const {
data: teamMembers, isLoading, isError, error, refetch,
data: teamMembers, isError, error, refetch,
} = useTeamMembers(libraryId, querySettings);
if (error) {
@@ -74,8 +41,6 @@ const TeamTable = () => {
const rows = isError ? [] : (teamMembers?.results || SKELETON_ROWS);
const pageCount = teamMembers?.count ? Math.ceil(teamMembers.count / DEFAULT_PAGE_SIZE) : 1;
const navigate = useNavigate();
const adaptedFilterChoices = useMemo(
() => roles.map((role) => ({
name: role.name,
@@ -108,18 +73,7 @@ const TeamTable = () => {
{
id: 'action',
Header: intl.formatMessage(messages['library.authz.team.table.action']),
// eslint-disable-next-line react/no-unstable-nested-components
Cell: ({ row }: CellProps) => (
canManageTeam && row.original.username !== username && !isLoading ? (
<Button
iconBefore={Edit}
variant="link"
size="sm"
onClick={() => navigate(`/authz/libraries/${libraryId}/${row.original.username}`)}
>
{intl.formatMessage(messages['authz.libraries.team.table.edit.action'])}
</Button>
) : null),
Cell: ActionCell,
},
]}
columns={
@@ -140,14 +94,7 @@ const TeamTable = () => {
{
Header: intl.formatMessage(messages['library.authz.team.table.roles']),
accessor: 'roles',
// eslint-disable-next-line react/no-unstable-nested-components
Cell: ({ row }: CellProps) => (row.original.username === SKELETON_ROWS[0].username ? (
<Skeleton width="80px" />
) : (
row.original.roles.map((role) => (
<Chip key={`${row.original.username}-role-${role}`}>{roleLabels[role]}</Chip>
))
)),
Cell: RolesCell,
Filter: CheckboxFilter,
filter: 'includesValue',
filterChoices: Object.values(adaptedFilterChoices),

View File

@@ -1,5 +1,22 @@
import { PermissionMetadata, ResourceMetadata, RoleMetadata } from 'types';
export const CONTENT_LIBRARY_PERMISSIONS = {
DELETE_LIBRARY: 'content_libraries.delete_library',
MANAGE_LIBRARY_TAGS: 'content_libraries.manage_library_tags',
VIEW_LIBRARY: 'content_libraries.view_library',
EDIT_LIBRARY_CONTENT: 'content_libraries.edit_library_content',
PUBLISH_LIBRARY_CONTENT: 'content_libraries.publish_library_content',
REUSE_LIBRARY_CONTENT: 'content_libraries.reuse_library_content',
CREATE_LIBRARY_COLLECTION: 'content_libraries.create_library_collection',
EDIT_LIBRARY_COLLECTION: 'content_libraries.edit_library_collection',
DELETE_LIBRARY_COLLECTION: 'content_libraries.delete_library_collection',
MANAGE_LIBRARY_TEAM: 'content_libraries.manage_library_team',
VIEW_LIBRARY_TEAM: 'content_libraries.view_library_team',
};
// Note: this information will eventually come from the backend API
// but for the MVP we decided to manage it in the frontend
export const libraryRolesMetadata: RoleMetadata[] = [
@@ -17,18 +34,27 @@ export const libraryResourceTypes: ResourceMetadata[] = [
];
export const libraryPermissions: PermissionMetadata[] = [
{ key: 'delete_library', resource: 'library', description: 'Allows the user to delete the library and all its contents.' },
{ key: 'manage_library_tags', resource: 'library', description: 'Add or remove tags from content.' },
{ key: 'view_library', resource: 'library', description: 'View content, search, filter, and sort within the library.' },
{ key: CONTENT_LIBRARY_PERMISSIONS.DELETE_LIBRARY, resource: 'library', description: 'Allows the user to delete the library and all its contents.' },
{ key: CONTENT_LIBRARY_PERMISSIONS.MANAGE_LIBRARY_TAGS, resource: 'library', description: 'Add or remove tags from content.' },
{ key: CONTENT_LIBRARY_PERMISSIONS.VIEW_LIBRARY, resource: 'library', description: 'View content, search, filter, and sort within the library.' },
{ key: 'edit_library_content', resource: 'library_content', description: 'Edit content in draft mode' },
{ key: 'publish_library_content', resource: 'library_content', description: 'Publish content, making it available for reuse' },
{ key: 'reuse_library_content', resource: 'library_content', description: 'Reuse published content within a course.' },
{ key: CONTENT_LIBRARY_PERMISSIONS.EDIT_LIBRARY_CONTENT, resource: 'library_content', description: 'Edit content in draft mode' },
{ key: CONTENT_LIBRARY_PERMISSIONS.PUBLISH_LIBRARY_CONTENT, resource: 'library_content', description: 'Publish content, making it available for reuse' },
{ key: CONTENT_LIBRARY_PERMISSIONS.REUSE_LIBRARY_CONTENT, resource: 'library_content', description: 'Reuse published content within a course.' },
{ key: 'create_library_collection', resource: 'library_collection', description: 'Create new collections within a library.' },
{ key: 'edit_library_collection', resource: 'library_collection', description: 'Add or remove content from existing collections.' },
{ key: 'delete_library_collection', resource: 'library_collection', description: 'Delete entire collections from the library.' },
{ key: CONTENT_LIBRARY_PERMISSIONS.CREATE_LIBRARY_COLLECTION, resource: 'library_collection', description: 'Create new collections within a library.' },
{ key: CONTENT_LIBRARY_PERMISSIONS.EDIT_LIBRARY_COLLECTION, resource: 'library_collection', description: 'Add or remove content from existing collections.' },
{ key: CONTENT_LIBRARY_PERMISSIONS.DELETE_LIBRARY_COLLECTION, resource: 'library_collection', description: 'Delete entire collections from the library.' },
{ key: 'manage_library_team', resource: 'library_team', description: 'View the list of users who have access to the library.' },
{ key: 'view_library_team', resource: 'library_team', description: 'Add, remove, and assign roles to users within the library.' },
{ key: CONTENT_LIBRARY_PERMISSIONS.MANAGE_LIBRARY_TEAM, resource: 'library_team', description: 'View the list of users who have access to the library.' },
{ key: CONTENT_LIBRARY_PERMISSIONS.VIEW_LIBRARY_TEAM, resource: 'library_team', description: 'Add, remove, and assign roles to users within the library.' },
];
export const DEFAULT_TOAST_DELAY = 5000;
export const RETRY_TOAST_DELAY = 120_000; // 2 minutes
export const SKELETON_ROWS = Array.from({ length: 10 }).map(() => ({
username: 'skeleton',
name: '',
email: '',
roles: [],
}));

View File

@@ -5,6 +5,7 @@ import { useValidateUserPermissions } from '@src/data/hooks';
import { renderWrapper } from '@src/setupTest';
import { usePermissionsByRole } from '@src/authz-module/data/hooks';
import { CustomErrors } from '@src/constants';
import { CONTENT_LIBRARY_PERMISSIONS } from './constants';
import { LibraryAuthZProvider, useLibraryAuthZ } from './context';
jest.mock('react-router-dom', () => ({
@@ -15,16 +16,10 @@ jest.mock('react-router-dom', () => ({
jest.mock('@src/data/hooks', () => ({
useValidateUserPermissions: jest.fn(),
}));
// Move the mock after imports and use actual values
jest.mock('@src/authz-module/data/hooks', () => ({
usePermissionsByRole: jest.fn().mockReturnValue({
data: [
{
role: 'library_author',
permissions: ['view_library_team', 'edit_library'],
user_count: 12,
},
],
}),
usePermissionsByRole: jest.fn(),
}));
class ErrorBoundary extends Component<{ children: ReactNode }, { hasError: boolean; error?: Error }> {
@@ -49,14 +44,12 @@ const TestComponent = () => {
const context = useLibraryAuthZ();
return (
<div>
<div data-testid="username">{context.username}</div>
<div data-testid="libraryId">{context.libraryId}</div>
<div data-testid="canManageTeam">{context.canManageTeam ? 'true' : 'false'}</div>
<div data-testid="roles">{Array.isArray(context.roles) ? context.roles.length : 'undefined'}</div>
<div data-testid="permissions">
{Array.isArray(context.permissions) ? context.permissions.length : 'undefined'}
</div>
<div data-testid="resources">{Array.isArray(context.resources) ? context.resources.length : 'undefined'}</div>
<div>Username: {context.username}</div>
<div>Library ID: {context.libraryId}</div>
<div>Can manage team: {context.canManageTeam ? 'Yes' : 'No'}</div>
<div>Roles count: {Array.isArray(context.roles) ? context.roles.length : 'undefined'}</div>
<div>Permissions count: {Array.isArray(context.permissions) ? context.permissions.length : 'undefined'}</div>
<div>Resources count: {Array.isArray(context.resources) ? context.resources.length : 'undefined'}</div>
</div>
);
};
@@ -67,6 +60,14 @@ describe('LibraryAuthZProvider', () => {
(useParams as jest.Mock).mockReturnValue({ libraryId: 'lib123' });
(usePermissionsByRole as jest.Mock).mockReturnValue({
data: [
{
role: 'library_author',
permissions: [
CONTENT_LIBRARY_PERMISSIONS.VIEW_LIBRARY_TEAM,
CONTENT_LIBRARY_PERMISSIONS.EDIT_LIBRARY_CONTENT,
],
user_count: 12,
},
{
role: 'instructor',
description: 'Can create and edit content',
@@ -109,12 +110,12 @@ describe('LibraryAuthZProvider', () => {
</LibraryAuthZProvider>,
);
expect(screen.getByTestId('username')).toHaveTextContent('testuser');
expect(screen.getByTestId('libraryId')).toHaveTextContent('lib123');
expect(screen.getByTestId('canManageTeam')).toHaveTextContent('true');
expect(Number(screen.getByTestId('roles').textContent)).not.toBeNaN();
expect(Number(screen.getByTestId('permissions').textContent)).not.toBeNaN();
expect(Number(screen.getByTestId('resources').textContent)).not.toBeNaN();
expect(screen.getByText(/Username: testuser/)).toBeInTheDocument();
expect(screen.getByText(/Library ID: lib123/)).toBeInTheDocument();
expect(screen.getByText(/Can manage team: Yes/)).toBeInTheDocument();
expect(screen.getByText(/Roles count: \d+/)).toBeInTheDocument();
expect(screen.getByText(/Permissions count: \d+/)).toBeInTheDocument();
expect(screen.getByText(/Resources count: \d+/)).toBeInTheDocument();
});
it('throws error when user lacks both view and manage permissions', () => {
@@ -148,7 +149,7 @@ describe('LibraryAuthZProvider', () => {
</LibraryAuthZProvider>,
);
expect(screen.getByTestId('canManageTeam')).toHaveTextContent('false');
expect(screen.getByText(/Can manage team: No/)).toBeInTheDocument();
});
it('throws error when libraryId is missing', () => {

View File

@@ -7,9 +7,14 @@ import { useValidateUserPermissions } from '@src/data/hooks';
import { usePermissionsByRole } from '@src/authz-module/data/hooks';
import { PermissionMetadata, ResourceMetadata, Role } from 'types';
import { CustomErrors } from '@src/constants';
import { libraryPermissions, libraryResourceTypes, libraryRolesMetadata } from './constants';
import {
CONTENT_LIBRARY_PERMISSIONS, libraryPermissions, libraryResourceTypes, libraryRolesMetadata,
} from './constants';
const LIBRARY_TEAM_PERMISSIONS = ['view_library_team', 'manage_library_team'];
const LIBRARY_TEAM_PERMISSIONS = [
CONTENT_LIBRARY_PERMISSIONS.VIEW_LIBRARY_TEAM,
CONTENT_LIBRARY_PERMISSIONS.MANAGE_LIBRARY_TEAM,
];
export type AppContextType = {
authenticatedUser: {
@@ -33,7 +38,7 @@ type AuthZProviderProps = {
children: ReactNode;
};
export const LibraryAuthZProvider: React.FC<AuthZProviderProps> = ({ children }:AuthZProviderProps) => {
export const LibraryAuthZProvider = ({ children }: AuthZProviderProps) => {
const { libraryId } = useParams<{ libraryId: string }>();
const { authenticatedUser } = useContext(AppContext) as AppContextType;

View File

@@ -1,7 +1,7 @@
import { Spinner, Container } from '@openedx/paragon';
const LoadingPage = () => (
<Container className="d-flex vh-100" data-testid="loading-page">
<Container className="d-flex vh-100">
<Spinner
variant="primary"
animation="border"

View File

@@ -10,8 +10,11 @@ type ErrorStatusCode = {
[key in CustomErrors]: number[];
};
export const STATUS_400 = 400;
export const STATUS_404 = 404;
export const ERROR_STATUS: ErrorStatusCode = {
[CustomErrors.NO_ACCESS]: [403, 401],
[CustomErrors.NOT_FOUND]: [404],
[CustomErrors.NOT_FOUND]: [400, 404],
[CustomErrors.SERVER_ERROR]: [500, 501, 502, 503, 504, 505, 506, 507, 508, 510, 511],
};