Compare commits

..

102 Commits

Author SHA1 Message Date
sundasnoreen12
f1b3a9006e Merge remote-tracking branch 'origin/2u-main' into INF-rebase-2u-main
-m "fix: fixed conflicts"
2025-07-08 13:27:47 +05:00
sundasnoreen12
ddcd4dbe08 fix: package lock file 2025-07-08 12:50:41 +05:00
eemaanamir
d55ddbeb0f fix: resolved merge conflicts 2025-07-08 12:04:39 +05:00
ayesha waris
f3f14fb3e7 fix: fixed cohesion page url setup (#1476)
Co-authored-by: Ayesha Waris <ayesha.waris@A006-01000.local>
2025-04-23 20:25:22 +05:00
ayesha waris
6c8b3835b6 fix: fixed cohesion pageview (#1475)
Co-authored-by: Ayesha Waris <ayesha.waris@192.168.10.17>
2025-04-23 13:17:14 +05:00
sundasnoreen12
8cbe6ce02e Merge pull request #1472 from openedx/sundas/upgrade-frontend-build
fix: properly set background color for floating labels
2025-04-03 17:05:24 +05:00
sundasnoreen12
a53334d3bf fix: properly set background color for floating labels 2025-04-03 16:48:53 +05:00
sundasnoreen12
0172c79dd9 Merge pull request #1465 from openedx/sundas/paragon-upgrade
feat: upgraded package for paragon
2025-03-28 14:17:25 +05:00
sundasnoreen12
5d4abcbab3 feat: upgraded package for paragon 2025-03-28 13:16:34 +05:00
sundasnoreen12
c9987eb2f4 Merge pull request #1425 from openedx/sundas-new/INF-1779
feat: implemented restricted country implementation
2025-03-20 12:59:23 +05:00
sundasnoreen12
a2ad9d5248 refactor: optimize code 2025-03-20 12:52:58 +05:00
sundasnoreen12
cca87bd16a fix: fixed issue by removing empty array 2025-03-20 12:52:50 +05:00
sundasnoreen12
206c4c887b test: refactor test file 2025-03-20 12:52:50 +05:00
sundasnoreen12
09dc21eb0e feat: implemented restricted country implementation 2025-03-20 12:52:50 +05:00
ayesha waris
945af2bdfd fix: fixed tagular console error if cohesion script is not loaded (#1452)
Co-authored-by: Ayesha Waris <ayesha.waris@192.168.10.3>
2025-03-19 23:31:59 +05:00
Awais Ansari
0dca6f3fdc Merge pull request #1451 from openedx/aansari/sync-with-master
chore: sync with master
2025-03-18 13:11:41 +05:00
Awais Ansari
189a67c9dc Merge branch 'master' of github.com:openedx/frontend-app-authn into aansari/sync-with-master 2025-03-18 12:58:16 +05:00
sundasnoreen12
3dceb63b9c Merge pull request #1445 from openedx/sundas/INF-1819
fix: blocked web crawlers for auth MFE
2025-03-10 12:25:26 +05:00
ayesha waris
9385174b93 fix: adding defer to cohesion script (#1447)
Co-authored-by: Ayesha Waris <ayesha.waris@192.168.1.11>
2025-03-06 13:43:09 +05:00
sundasnoreen12
86ed8e2361 fix: blocked web crawlers for auth MFE 2025-03-05 15:27:09 +05:00
ayesha waris
f5a6ece6b1 refactor: moved updated script to index.html (#1443)
Co-authored-by: Ayesha Waris <ayesha.waris@192.168.1.11>
2025-03-05 13:44:49 +05:00
ayesha waris
0d71e31ffb feat: update cohesion script (#1441)
Co-authored-by: Ayesha Waris <ayesha.waris@192.168.1.11>
2025-03-04 14:47:29 +05:00
Awais Ansari
38dd2944b8 Revert "feat: updated cohesion snippet (#1433)" (#1437)
This reverts commit 244b9e68e6.
2025-02-28 16:01:29 +05:00
Awais Ansari
f4708ed274 Revert "fix: removed style tag for updated cohesion script (#1434)" (#1438)
This reverts commit cb7300441c.
2025-02-28 16:01:16 +05:00
ayesha waris
cb7300441c fix: removed style tag for updated cohesion script (#1434)
Co-authored-by: Ayesha Waris <ayesha.waris@A006-01000.local>
2025-02-27 18:39:55 +05:00
ayesha waris
244b9e68e6 feat: updated cohesion snippet (#1433)
Co-authored-by: Ayesha Waris <ayesha.waris@192.168.10.37>
2025-02-27 16:34:56 +05:00
Awais Ansari
c04ed9aa43 feat: updated cohesion script (#1400) 2024-12-23 21:18:01 +05:00
ayesha waris
354c73bb2a fix: fixed account activation error message (#1384) 2024-11-29 18:28:23 +05:00
ayesha waris
76a5a5dffa fix: fixed event data (#1383) 2024-11-29 16:30:23 +05:00
Eemaan Amir
5efe9d8344 Merge pull request #1382 from openedx/inf-universal-cookie-update
chore: rebase 2u-main
2024-11-28 12:57:37 +05:00
ayesha waris
cd2003921b fix: fixed duplicate event firing on post SSO login registration (#1381) 2024-11-27 18:56:03 +05:00
Eemaan Amir
7339aec7c2 Merge pull request #1380 from openedx/inf-reselect-update
chore: rebase 2u-main
2024-11-27 14:20:46 +05:00
Eemaan Amir
025870a3b9 Merge pull request #1378 from openedx/inf-checkout-action-update
chore: rebase 2u-main
2024-11-22 13:12:32 +05:00
Eemaan Amir
8dc77d5db6 Merge pull request #1377 from openedx/inf-github-action-update
chore: rebase 2u-main
2024-11-21 15:14:51 +05:00
Eemaan Amir
40a1f4ce6b Merge pull request #1373 from openedx/inf-codecov-action-update
chore: rebase 2u-main
2024-11-19 19:18:40 +05:00
Eemaan Amir
bb9fcd91c0 Merge pull request #1372 from openedx/inf-husky-update
chore: rebase 2u-main
2024-11-19 16:40:26 +05:00
ayesha waris
0fa00290da fix: fixed cohesion snippet loading (#1366) 2024-11-13 17:45:20 +05:00
Eemaan Amir
b18caa2da0 Merge pull request #1363 from openedx/inf-algoliasearch-helper-update
Rebase with 2u-main
2024-11-11 19:02:34 +05:00
ayesha waris
5ca86f9183 perf: updated cohesion id stitching script (#1358) 2024-11-11 17:17:58 +05:00
ayesha waris
2a9dbe9d30 fix: delaying nudge password redirection (#1337)
* fix: delaying  nudge password redirection

* fix: fixed test cases
2024-10-24 14:41:35 +05:00
ayesha waris
62508e3bc7 fix: fixed event aborting in firefox due to page redirect (#1336)
* fix: fixed event aborting in firefox due to page redirect

* fix: fixed test cases

* refactor: created a util for redirect
2024-10-23 20:00:17 +05:00
ayesha waris
ceb489753b feat: added update cohesion script (#1335) 2024-10-22 15:11:11 +05:00
ayesha waris
5035a07e0a fix: fixed nudge password edge case (#1334) 2024-10-19 00:30:40 +05:00
Awais Ansari
f086a165e2 fix: removed duplicate registration events (#1333) 2024-10-18 20:01:26 +05:00
Awais Ansari
9239df3620 fix: cohesion script and SSO issue (#1332)
* fix: userId error on script load

* fix: SSO cohesion event
2024-10-18 19:26:04 +05:00
Awais Ansari
009125c3ef fix: triggered login event on success (#1331)
* fix: triggered login event on success

* fix: fixed failing test cases

---------

Co-authored-by: ayeshoali <ayeshoali@gmail.com>
2024-10-18 18:28:40 +05:00
ayesha waris
b69ed6e422 fix: fixed opt out event text (#1330) 2024-10-18 14:42:28 +05:00
ayesha waris
07ee2392e9 feat: added cohesion events tracking (#1329)
* feat: added cohesion events tracking

* test: fixed failing test cases

* refactor: moved cohesion code into a folder

* refactor: fire event on successful form submission

---------

Co-authored-by: Awais Ansari <awais.ansari63@gmail.com>
2024-10-17 20:28:25 +05:00
Awais Ansari
2bfce01772 Merge pull request #1328 from openedx/aansari/rebase-with-master
chore: rebase 2u main with master
2024-10-11 16:06:10 +05:00
Awais Ansari
1477ed33d7 Merge branch 'master' of github.com:openedx/frontend-app-authn into aansari/rebase-with-master 2024-10-04 18:13:47 +05:00
Awais Ansari
c4f1a97316 build: updated webpack.prod.config.js (#1327)
* build: updated webpack.prod.config.js

* fix: lint error
2024-09-25 17:16:32 +05:00
Awais Ansari
47b0501e1c feat: add MainAppSlot for chatbot plugin (#1320)
* feat: add MainAppSlot for chatbot plugin

* test: added test for MainAppSlot

* chore: add read me for plugin-slot
2024-09-25 13:58:01 +05:00
Muhammad Abdullah Waheed
e496bb62c5 Merge pull request #1318 from openedx/manwar/update-2u-main
refactor: sync 2u-main with master
2024-09-19 16:20:26 +05:00
Awais Ansari
b41fca3605 feat: removed Russian Federation from country list (#1315) 2024-09-12 10:01:48 +05:00
Mubbshar Anwar
ac2548913f fix: password reset redirection (#1300)
fix authenticated user redirects to 404 if token is invalide for password reset
VAN-2052
2024-09-12 10:01:48 +05:00
Blue
cd9b3bd084 fix: covert totalRegistrationTime to snake case (#1302)
Description:
Convert totalRegistrationTime to snake case
VAN-1816

Co-authored-by: Ahtesham Quraish <ahtesham.quraish@192.168.1.4>
2024-09-12 10:01:40 +05:00
Syed Sajjad Hussain Shah
efc07aac67 fix: fix datadog js errors (#1296) 2024-09-12 09:59:52 +05:00
Syed Sajjad Hussain Shah
2d50ed224f fix: retain query params in authenticated user redirection (#1288) 2024-09-12 09:59:52 +05:00
Mubbshar Anwar
d10f9b932b fix: fix marketingEmailsOptIn null value (#1294)
Fix marketingEmailsOptIn null value issue for SSO flow on onboarding component

VAN-2013
2024-09-12 09:59:52 +05:00
Mubbshar Anwar
05aa85a5fb fix: remove cookie (#1286)
-remove marketingEmailsOptIn cookie on successful registration
- fix tests
2024-09-12 09:59:52 +05:00
Syed Sajjad Hussain Shah
56bd6d835e fix: set marketing opt in in cookie for sso (#1285) 2024-09-12 09:59:52 +05:00
Muhammad Abdullah Waheed
afd4d24360 feat: added app name identifier in segment events (#1277)
* feat: added app name identifier in registration call

* feat: added utils for tracking events

* refactor: mapped login events

* refactor: mapped forgot password events

* refactor: mapped reset password events

* refactor: mapped register events

* fix: fixed unit tests

* refactor: mapped progressive prifiling events

* fix: fixed unit tests

* refactor: added app name in logistration events

* refactor: resolved PR reviews and fixed tests
2024-09-12 09:59:47 +05:00
Mubbshar Anwar
4898864416 feat: hard code fields on frontend (#1256)
* feat: hard code fields
hard code configurable fields on frontend which includes country field on register page & level of education & gender field on progressive profiling

VAN-1971

* fix: fix secondary provider null name issue
2024-09-12 09:56:53 +05:00
Mubbshar Anwar
739f94d624 Update 2u-main with master (#1254)
* feat: Hide preloaders for third party auth providers if they are disabled

* feat: remove username from the registration from (#1201) (#1241)

Co-authored-by: Attiya Ishaque <atiya.ishaq@arbisoft.com>

* fix: add new entry for another US label (#1244)

Add new entry for for another US label which is United States

* feat: implement multi step registration experiment

Rebase 2u main with master (#1228)

* chore(deps): update dependency babel-plugin-formatjs to v10.5.14

* fix(deps): update dependency @edx/frontend-platform to v7.1.3

* fix(deps): update font awesome to v6.5.2

* chore(deps): update dependency @openedx/frontend-build to v13.1.4

* fix(deps): update dependency @openedx/paragon to v22.2.1

* fix(deps): update dependency algoliasearch to v4.23.3

* fix(deps): update dependency algoliasearch-helper to v3.17.0

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* feat: add multi step registration eventing (#1226)

* feat: implement multi step registration experiment

* feat: add multi step registration eventing

* fix: fix register button width

* fix: fix register button loader for control

* feat: capture marketing lead in experiment events (#1243)

* revert: multistep registration experiment
revert multistep registration experiment changes

VAN-1930

* feat: implement auto generated username experiment (#1248)

* feat: implement auto generated username registration exp

* feat: add page event for reset password (#1253)

Description: Add page event for reset password page
VAN-1929

---------

Co-authored-by: Stanislav Lunyachek <stanislav.lunyachek@raccoongang.com>
Co-authored-by: Syed Sajjad Hussain Shah <52817156+syedsajjadkazmii@users.noreply.github.com>
Co-authored-by: Attiya Ishaque <atiya.ishaq@arbisoft.com>
Co-authored-by: Blue <ahtesham-quraish@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Syed Sajjad  Hussain Shah <ssajjad@2u.com>
2024-09-12 09:56:53 +05:00
Blue
1819edc9b7 feat: add page event for reset password (#1253)
Description: Add page event for reset password page
VAN-1929
2024-09-12 09:56:53 +05:00
Blue
ad0d75ab0d feat: implement auto generated username experiment (#1248)
* feat: implement auto generated username registration exp
2024-09-12 09:56:53 +05:00
mubbsharanwar
a90ebb7d4d revert: multistep registration experiment
revert multistep registration experiment changes

VAN-1930
2024-09-12 09:52:48 +05:00
Syed Sajjad Hussain Shah
f8290adab5 feat: capture marketing lead in experiment events (#1243) 2024-09-12 09:50:51 +05:00
Syed Sajjad Hussain Shah
788a42b341 fix: fix register button loader for control 2024-09-12 09:49:24 +05:00
Syed Sajjad Hussain Shah
4f48e82959 fix: fix register button width 2024-09-12 09:49:19 +05:00
Syed Sajjad Hussain Shah
99850574fb feat: add multi step registration eventing (#1226)
* feat: implement multi step registration experiment

* feat: add multi step registration eventing
2024-09-12 09:47:16 +05:00
Syed Sajjad Hussain Shah
d66afe98f0 feat: implement multi step registration experiment 2024-09-12 09:44:24 +05:00
Syed Sajjad Hussain Shah
e2cdfce832 Rebase 2u main with master (#1228)
* chore(deps): update dependency babel-plugin-formatjs to v10.5.14

* fix(deps): update dependency @edx/frontend-platform to v7.1.3

* fix(deps): update font awesome to v6.5.2

* chore(deps): update dependency @openedx/frontend-build to v13.1.4

* fix(deps): update dependency @openedx/paragon to v22.2.1

* fix(deps): update dependency algoliasearch to v4.23.3

* fix(deps): update dependency algoliasearch-helper to v3.17.0

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-09-11 18:23:56 +05:00
Awais Ansari
c1e63da778 feat: removed Russian Federation from country list (#1315) 2024-09-10 21:11:44 +05:00
Mubbshar Anwar
ecf4c3ae53 fix: password reset redirection (#1300)
fix authenticated user redirects to 404 if token is invalide for password reset
VAN-2052
2024-08-29 09:48:21 +05:00
Blue
2428b4c389 fix: covert totalRegistrationTime to snake case (#1302)
Description:
Convert totalRegistrationTime to snake case
VAN-1816

Co-authored-by: Ahtesham Quraish <ahtesham.quraish@192.168.1.4>
2024-08-28 14:58:40 +05:00
Syed Sajjad Hussain Shah
099fe8d717 fix: fix datadog js errors (#1296) 2024-08-01 16:06:20 +05:00
Syed Sajjad Hussain Shah
4755540be8 fix: retain query params in authenticated user redirection (#1288) 2024-07-29 11:23:48 +05:00
Mubbshar Anwar
9a30f053c7 fix: fix marketingEmailsOptIn null value (#1294)
Fix marketingEmailsOptIn null value issue for SSO flow on onboarding component

VAN-2013
2024-07-26 15:57:18 +05:00
Mubbshar Anwar
6b983e18d3 fix: remove cookie (#1286)
-remove marketingEmailsOptIn cookie on successful registration
- fix tests
2024-07-12 17:05:50 +05:00
Syed Sajjad Hussain Shah
327210192c fix: set marketing opt in in cookie for sso (#1285) 2024-07-12 13:18:42 +05:00
Muhammad Abdullah Waheed
0d603b5fa1 feat: added app name identifier in segment events (#1277)
* feat: added app name identifier in registration call

* feat: added utils for tracking events

* refactor: mapped login events

* refactor: mapped forgot password events

* refactor: mapped reset password events

* refactor: mapped register events

* fix: fixed unit tests

* refactor: mapped progressive prifiling events

* fix: fixed unit tests

* refactor: added app name in logistration events

* refactor: resolved PR reviews and fixed tests
2024-07-03 17:08:44 +05:00
Mubbshar Anwar
efaa83a1bc feat: hard code fields on frontend (#1256)
* feat: hard code fields
hard code configurable fields on frontend which includes country field on register page & level of education & gender field on progressive profiling

VAN-1971

* fix: fix secondary provider null name issue
2024-06-11 12:01:30 +05:00
Mubbshar Anwar
bd63bb1f15 Update 2u-main with master (#1254)
* feat: Hide preloaders for third party auth providers if they are disabled

* feat: remove username from the registration from (#1201) (#1241)

Co-authored-by: Attiya Ishaque <atiya.ishaq@arbisoft.com>

* fix: add new entry for another US label (#1244)

Add new entry for for another US label which is United States

* feat: implement multi step registration experiment

Rebase 2u main with master (#1228)

* chore(deps): update dependency babel-plugin-formatjs to v10.5.14

* fix(deps): update dependency @edx/frontend-platform to v7.1.3

* fix(deps): update font awesome to v6.5.2

* chore(deps): update dependency @openedx/frontend-build to v13.1.4

* fix(deps): update dependency @openedx/paragon to v22.2.1

* fix(deps): update dependency algoliasearch to v4.23.3

* fix(deps): update dependency algoliasearch-helper to v3.17.0

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* feat: add multi step registration eventing (#1226)

* feat: implement multi step registration experiment

* feat: add multi step registration eventing

* fix: fix register button width

* fix: fix register button loader for control

* feat: capture marketing lead in experiment events (#1243)

* revert: multistep registration experiment
revert multistep registration experiment changes

VAN-1930

* feat: implement auto generated username experiment (#1248)

* feat: implement auto generated username registration exp

* feat: add page event for reset password (#1253)

Description: Add page event for reset password page
VAN-1929

---------

Co-authored-by: Stanislav Lunyachek <stanislav.lunyachek@raccoongang.com>
Co-authored-by: Syed Sajjad Hussain Shah <52817156+syedsajjadkazmii@users.noreply.github.com>
Co-authored-by: Attiya Ishaque <atiya.ishaq@arbisoft.com>
Co-authored-by: Blue <ahtesham-quraish@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Syed Sajjad  Hussain Shah <ssajjad@2u.com>
2024-06-07 07:57:42 +05:00
Blue
5754c2961a feat: add page event for reset password (#1253)
Description: Add page event for reset password page
VAN-1929
2024-06-04 16:27:14 +05:00
Blue
dcbd644a25 feat: implement auto generated username experiment (#1248)
* feat: implement auto generated username registration exp
2024-05-13 14:11:03 +05:00
Blue
52e438652c 2u-main rebase with master (#1246)
Rebase 2u-main with master
2024-05-07 16:44:47 +05:00
mubbsharanwar
d8947a4c0a revert: multistep registration experiment
revert multistep registration experiment changes

VAN-1930
2024-05-07 11:47:28 +05:00
Syed Sajjad Hussain Shah
03d1666c2c feat: capture marketing lead in experiment events (#1243) 2024-04-25 15:28:05 +05:00
Syed Sajjad Hussain Shah
3782503983 fix: fix register button loader for control 2024-04-22 16:53:23 +05:00
Syed Sajjad Hussain Shah
b219fe3683 fix: fix register button width 2024-04-22 14:37:36 +05:00
Syed Sajjad Hussain Shah
90f650ce3e feat: add multi step registration eventing (#1226)
* feat: implement multi step registration experiment

* feat: add multi step registration eventing
2024-04-18 11:09:32 +05:00
Syed Sajjad Hussain Shah
6f325c20c3 feat: implement multi step registration experiment 2024-04-18 11:09:32 +05:00
Syed Sajjad Hussain Shah
de12dfbf9e Merge pull request #1236 from openedx/master
adding master commits to 2u-main
2024-04-18 10:19:28 +05:00
Syed Sajjad Hussain Shah
c663f6fa30 Rebase 2u main with master (#1228)
* chore(deps): update dependency babel-plugin-formatjs to v10.5.14

* fix(deps): update dependency @edx/frontend-platform to v7.1.3

* fix(deps): update font awesome to v6.5.2

* chore(deps): update dependency @openedx/frontend-build to v13.1.4

* fix(deps): update dependency @openedx/paragon to v22.2.1

* fix(deps): update dependency algoliasearch to v4.23.3

* fix(deps): update dependency algoliasearch-helper to v3.17.0

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-04-17 17:00:28 +05:00
renovate[bot]
dba93333fd fix(deps): update dependency algoliasearch-helper to v3.17.0 2024-04-17 16:50:35 +05:00
renovate[bot]
611af07326 fix(deps): update dependency algoliasearch to v4.23.3 2024-04-17 16:50:35 +05:00
renovate[bot]
564ec70d9e fix(deps): update dependency @openedx/paragon to v22.2.1 2024-04-17 16:50:35 +05:00
renovate[bot]
65e95a4d1b chore(deps): update dependency @openedx/frontend-build to v13.1.4 2024-04-17 16:50:35 +05:00
renovate[bot]
cf2b50005b fix(deps): update font awesome to v6.5.2 2024-04-17 16:50:35 +05:00
renovate[bot]
faf4ff8488 fix(deps): update dependency @edx/frontend-platform to v7.1.3 2024-04-17 16:50:35 +05:00
renovate[bot]
7d64220852 chore(deps): update dependency babel-plugin-formatjs to v10.5.14 2024-04-17 16:50:35 +05:00
107 changed files with 4345 additions and 3278 deletions

3
.env
View File

@@ -16,6 +16,9 @@ SITE_NAME=null
INFO_EMAIL=''
# ***** Cookies *****
USER_RETENTION_COOKIE_NAME=null
# ***** Cohesion Keys *****
COHESION_WRITE_KEY=''
COHESION_SOURCE_KEY=''
# ***** Links *****
LOGIN_ISSUE_SUPPORT_LINK=''
AUTHN_PROGRESSIVE_PROFILING_SUPPORT_LINK=null

View File

@@ -25,6 +25,9 @@ ENABLE_PROGRESSIVE_PROFILING_ON_AUTHN='true'
# ***** Cookies *****
SESSION_COOKIE_DOMAIN='localhost'
USER_INFO_COOKIE_NAME='edx-user-info'
# ***** Cohesion Keys *****
COHESION_WRITE_KEY=''
COHESION_SOURCE_KEY=''
# ***** Links *****
LOGIN_ISSUE_SUPPORT_LINK='http://localhost:18000/login-issue-support-url'
TOS_AND_HONOR_CODE='http://localhost:18000/honor'

View File

@@ -18,4 +18,6 @@ SEGMENT_KEY=''
SITE_NAME='Your Platform Name Here'
APP_ID=''
MFE_CONFIG_API_URL=''
COHESION_WRITE_KEY=''
COHESION_SOURCE_KEY=''
PARAGON_THEME_URLS={}

View File

@@ -1,7 +1,7 @@
// eslint-disable-next-line import/no-extraneous-dependencies
const { createConfig } = require('@openedx/frontend-build');
module.exports = createConfig('eslint', {
const config = createConfig('eslint', {
rules: {
// Temporarily update the 'indent', 'template-curly-spacing' and
// 'no-multiple-empty-lines' rules since they are causing eslint
@@ -50,3 +50,14 @@ module.exports = createConfig('eslint', {
'function-paren-newline': 'off',
},
});
config.settings = {
'import/resolver': {
node: {
paths: ['src', 'node_modules'],
extensions: ['.js', '.jsx'],
},
},
};
module.exports = config;

View File

@@ -14,7 +14,7 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v6
uses: actions/checkout@v4
- name: Setup Nodejs
uses: actions/setup-node@v4
with:

2
.nvmrc
View File

@@ -1 +1 @@
24
20

2
CODEOWNERS Normal file
View File

@@ -0,0 +1,2 @@
# The following users are the owners of all frontend-app-authn files
* @openedx/2u-infinity

60
example.env.config.js Normal file
View File

@@ -0,0 +1,60 @@
/*
Authn MFE is now able to handle JS-based configuration!
For the time being, the `.env.*` files are still made available when cloning down this repo or pulling from
the master branch. To switch to using `env.config.js`, make a copy of `example.env.config.js` and configure as needed.
For testing with Jest Snapshot, there is a mock in `/src/setupTest.jsx` for `getConfig` that will need to be
uncommented.
Note: having both .env and env.config.js files will follow a predictable order, in which non-empty values in the
JS-based config will overwrite the .env environment variables.
frontend-platform's getConfig loads configuration in the following sequence:
- .env file config
- optional handlers (commonly used to merge MFE-specific config in via additional process.env variables)
- env.config.js file config
- runtime config
*/
module.exports = {
NODE_ENV: 'development',
NODE_PATH: './src',
PORT: 1999,
ACCESS_TOKEN_COOKIE_NAME: 'edx-jwt-cookie-header-payload',
BASE_URL: 'http://localhost:1999',
CREDENTIALS_BASE_URL: 'http://localhost:18150',
CSRF_TOKEN_API_PATH: '/csrf/api/v1/token',
ECOMMERCE_BASE_URL: 'http://localhost:18130',
LANGUAGE_PREFERENCE_COOKIE_NAME: 'openedx-language-preference',
LMS_BASE_URL: 'http://localhost:18000',
LOGIN_URL: 'http://localhost:1999/login',
LOGOUT_URL: 'http://localhost:18000/logout',
LOGO_URL: 'https://edx-cdn.org/v3/default/logo.svg',
LOGO_TRADEMARK_URL: 'https://edx-cdn.org/v3/default/logo-trademark.svg',
LOGO_WHITE_URL: 'https://edx-cdn.org/v3/default/logo-white.svg',
FAVICON_URL: 'https://edx-cdn.org/v3/default/favicon.ico',
MARKETING_SITE_BASE_URL: 'http://localhost:18000',
ORDER_HISTORY_URL: 'http://localhost:1996/orders',
REFRESH_ACCESS_TOKEN_ENDPOINT: 'http://localhost:18000/login_refresh',
SEGMENT_KEY: '',
SITE_NAME: 'Your Platform Name Here',
INFO_EMAIL: 'info@example.com',
ENABLE_DYNAMIC_REGISTRATION_FIELDS: 'true',
ENABLE_PROGRESSIVE_PROFILING_ON_AUTHN: 'true',
SESSION_COOKIE_DOMAIN: 'localhost',
USER_INFO_COOKIE_NAME: 'edx-user-info',
LOGIN_ISSUE_SUPPORT_LINK: 'http://localhost:18000/login-issue-support-url',
TOS_AND_HONOR_CODE: 'http://localhost:18000/honor',
TOS_LINK: 'http://localhost:18000/tos',
PRIVACY_POLICY: 'http://localhost:18000/privacy',
AUTHN_PROGRESSIVE_PROFILING_SUPPORT_LINK: 'http://localhost:1999/welcome',
BANNER_IMAGE_LARGE: '',
BANNER_IMAGE_MEDIUM: '',
BANNER_IMAGE_SMALL: '',
BANNER_IMAGE_EXTRA_SMALL: '',
APP_ID: '',
MFE_CONFIG_API_URL: '',
ZENDESK_KEY: '',
ZENDESK_LOGO_URL: '',
};

4733
package-lock.json generated
View File

@@ -15,8 +15,8 @@
"@fortawesome/fontawesome-svg-core": "6.7.2",
"@fortawesome/free-brands-svg-icons": "6.7.2",
"@fortawesome/free-solid-svg-icons": "6.7.2",
"@fortawesome/react-fontawesome": "0.2.6",
"@openedx/frontend-plugin-framework": "^1.7.0",
"@fortawesome/react-fontawesome": "0.2.2",
"@openedx/frontend-plugin-framework": "^1.3.0",
"@openedx/paragon": "^23.4.2",
"@optimizely/react-sdk": "^2.9.1",
"@redux-devtools/extension": "3.3.0",
@@ -26,22 +26,23 @@
"classnames": "2.5.1",
"core-js": "3.43.0",
"fastest-levenshtein": "1.0.16",
"form-urlencoded": "6.1.6",
"form-urlencoded": "6.1.5",
"prop-types": "15.8.1",
"query-string": "7.1.3",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-error-boundary": "^4.0.13",
"react-helmet": "6.1.0",
"react-loading-skeleton": "3.5.0",
"react-redux": "7.2.9",
"react-responsive": "8.2.0",
"react-router": "6.30.2",
"react-router-dom": "6.30.2",
"react-router": "6.30.1",
"react-router-dom": "6.30.1",
"react-zendesk": "^0.1.13",
"redux": "4.2.1",
"redux-logger": "3.0.6",
"redux-mock-store": "1.5.5",
"redux-saga": "1.4.2",
"redux-saga": "1.3.0",
"redux-thunk": "2.4.2",
"regenerator-runtime": "0.14.1",
"reselect": "5.1.1",
@@ -49,93 +50,96 @@
},
"devDependencies": {
"@edx/browserslist-config": "^1.1.1",
"@openedx/frontend-build": "^14.6.2",
"babel-plugin-formatjs": "10.5.41",
"@edx/reactifex": "1.1.0",
"@openedx/frontend-build": "^14.6.1",
"babel-plugin-formatjs": "10.5.39",
"copy-webpack-plugin": "^11.0.0",
"eslint-plugin-import": "2.32.0",
"glob": "7.2.3",
"history": "5.3.0",
"jest": "30.2.0",
"husky": "9.1.7",
"jest": "30.0.4",
"react-test-renderer": "^18.3.1",
"ts-jest": "^29.4.0"
}
},
"node_modules/@algolia/cache-browser-local-storage": {
"version": "4.25.3",
"resolved": "https://registry.npmjs.org/@algolia/cache-browser-local-storage/-/cache-browser-local-storage-4.25.3.tgz",
"integrity": "sha512-J0vrnbIYmDIf9d9qQwBXaHn10VoQ/rA+2iBMr/idfsjHhL9I4h2pC9Dj1i0ggDLv9sPajbeVVh0BdC+mDbo7Tw==",
"version": "4.25.2",
"resolved": "https://registry.npmjs.org/@algolia/cache-browser-local-storage/-/cache-browser-local-storage-4.25.2.tgz",
"integrity": "sha512-tA1rqAafI+gUdewjZwyTsZVxesl22MTgLWRKt1+TBiL26NiKx7SjRqTI3pzm8ngx1ftM5LSgXkVIgk2+SRgPTg==",
"license": "MIT",
"dependencies": {
"@algolia/cache-common": "4.25.3"
"@algolia/cache-common": "4.25.2"
}
},
"node_modules/@algolia/cache-common": {
"version": "4.25.3",
"resolved": "https://registry.npmjs.org/@algolia/cache-common/-/cache-common-4.25.3.tgz",
"integrity": "sha512-dDls2jhGFdkGnoKwXADBnjosHKdKiwlY+tzaua5J0q9XJptn6DCBDUt3pg46GhTRz+64x08M+dyp8nNoV+3/Jw==",
"version": "4.25.2",
"resolved": "https://registry.npmjs.org/@algolia/cache-common/-/cache-common-4.25.2.tgz",
"integrity": "sha512-E+aZwwwmhvZXsRA1+8DhH2JJIwugBzHivASTnoq7bmv0nmForLyH7rMG5cOTiDK36DDLnKq1rMGzxWZZ70KZag==",
"license": "MIT"
},
"node_modules/@algolia/cache-in-memory": {
"version": "4.25.3",
"resolved": "https://registry.npmjs.org/@algolia/cache-in-memory/-/cache-in-memory-4.25.3.tgz",
"integrity": "sha512-6u/fVDr3ZIJIgtqdgUDB5kL9KcOdowmxf052bjfI1XhFTpxmIa49HcAEh1y2R0YqmmNDQHaPCT0QzwkINhWbug==",
"version": "4.25.2",
"resolved": "https://registry.npmjs.org/@algolia/cache-in-memory/-/cache-in-memory-4.25.2.tgz",
"integrity": "sha512-KYcenhfPKgR+WJ6IEwKVEFMKKCWLZdnYuw08+3Pn1cxAXbJcTIKjoYgEXzEW6gJmDaau2l55qNrZo6MBbX7+sw==",
"license": "MIT",
"dependencies": {
"@algolia/cache-common": "4.25.3"
"@algolia/cache-common": "4.25.2"
}
},
"node_modules/@algolia/client-account": {
"version": "4.25.3",
"resolved": "https://registry.npmjs.org/@algolia/client-account/-/client-account-4.25.3.tgz",
"integrity": "sha512-TkSVT5+davX4Dzt3gyEJ+SAfaVT5bHrZctAiup/AGPV7sNBigv4kuZv40OEbMMgu1uPJ4zw3tA39Oj/mOjd6gg==",
"version": "4.25.2",
"resolved": "https://registry.npmjs.org/@algolia/client-account/-/client-account-4.25.2.tgz",
"integrity": "sha512-IfRGhBxvjli9mdexrCxX2N4XT9NBN3tvZK5zCaL8zkDcgsthiM9WPvGIZS/pl/FuXB7hA0lE5kqOzsQDP6OmGQ==",
"license": "MIT",
"dependencies": {
"@algolia/client-common": "4.25.3",
"@algolia/client-search": "4.25.3",
"@algolia/transporter": "4.25.3"
"@algolia/client-common": "4.25.2",
"@algolia/client-search": "4.25.2",
"@algolia/transporter": "4.25.2"
}
},
"node_modules/@algolia/client-analytics": {
"version": "4.25.3",
"resolved": "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-4.25.3.tgz",
"integrity": "sha512-vHSU4zBaENbRjzwFYB3OQuDlKXwe+YDRgyGh1kKZhcMRDSsEBH/PGNWn+2ZmtbgrNS52TC+TJ8oUOg5wXIeISw==",
"version": "4.25.2",
"resolved": "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-4.25.2.tgz",
"integrity": "sha512-4Yxxhxh+XjXY8zPyo+h6tQuyoJWDBn8E3YLr8j+YAEy5p+r3/5Tp+ANvQ+hNaQXbwZpyf5d4ViYOBjJ8+bWNEg==",
"license": "MIT",
"dependencies": {
"@algolia/client-common": "4.25.3",
"@algolia/client-search": "4.25.3",
"@algolia/requester-common": "4.25.3",
"@algolia/transporter": "4.25.3"
"@algolia/client-common": "4.25.2",
"@algolia/client-search": "4.25.2",
"@algolia/requester-common": "4.25.2",
"@algolia/transporter": "4.25.2"
}
},
"node_modules/@algolia/client-common": {
"version": "4.25.3",
"resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-4.25.3.tgz",
"integrity": "sha512-ExRdFnJDe7t1/DgJUsqjzZKeI9gkLft4oVttlyTMru8TRNWA6eZ0wHRj4uQ9N3sxmzPiw3C53wigor705n1yQw==",
"version": "4.25.2",
"resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-4.25.2.tgz",
"integrity": "sha512-HXX8vbJPYW29P18GxciiwaDpQid6UhpPP9nW9WE181uGUgFhyP5zaEkYWf9oYBrjMubrGwXi5YEzJOz6Oa4faA==",
"license": "MIT",
"dependencies": {
"@algolia/requester-common": "4.25.3",
"@algolia/transporter": "4.25.3"
"@algolia/requester-common": "4.25.2",
"@algolia/transporter": "4.25.2"
}
},
"node_modules/@algolia/client-personalization": {
"version": "4.25.3",
"resolved": "https://registry.npmjs.org/@algolia/client-personalization/-/client-personalization-4.25.3.tgz",
"integrity": "sha512-ycCkQ0nWoH+sf0Gh20kk4NfJ+iUBc59ailqNCFcVl/0th1dtHF0P61IGetTsSmxVPZedDvnHop2z1ujWpYzNmw==",
"version": "4.25.2",
"resolved": "https://registry.npmjs.org/@algolia/client-personalization/-/client-personalization-4.25.2.tgz",
"integrity": "sha512-K81PRaHF77mHv2u8foWTHnIf5c+QNf/SnKNM7rB8JPi7TMYi4E5o2mFbgdU1ovd8eg9YMOEAuLkl1Nz1vbM3zQ==",
"license": "MIT",
"dependencies": {
"@algolia/client-common": "4.25.3",
"@algolia/requester-common": "4.25.3",
"@algolia/transporter": "4.25.3"
"@algolia/client-common": "4.25.2",
"@algolia/requester-common": "4.25.2",
"@algolia/transporter": "4.25.2"
}
},
"node_modules/@algolia/client-search": {
"version": "4.25.3",
"resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-4.25.3.tgz",
"integrity": "sha512-GFA99zL6cfNSDEDHfEJ0TmVYmXCJofQpForFhCShQLfRQgBYud9UBHOh4LB6ZSzmtVDIfP33joCA9hxQWPIbFw==",
"version": "4.25.2",
"resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-4.25.2.tgz",
"integrity": "sha512-pO/LpVnQlbJpcHRk+AroWyyFnh01eOlO6/uLZRUmYvr/hpKZKxI6n7ufgTawbo0KrAu2CePfiOkStYOmDuRjzQ==",
"license": "MIT",
"dependencies": {
"@algolia/client-common": "4.25.3",
"@algolia/requester-common": "4.25.3",
"@algolia/transporter": "4.25.3"
"@algolia/client-common": "4.25.2",
"@algolia/requester-common": "4.25.2",
"@algolia/transporter": "4.25.2"
}
},
"node_modules/@algolia/events": {
@@ -145,72 +149,72 @@
"license": "MIT"
},
"node_modules/@algolia/logger-common": {
"version": "4.25.3",
"resolved": "https://registry.npmjs.org/@algolia/logger-common/-/logger-common-4.25.3.tgz",
"integrity": "sha512-RrlmuHNTc9CIgykWh37QduDAkpX4745KQ75I+vhgT5ER3BBykaYByDTyWkyFSSlZjpDHXtOymu9epNbI5V6OWQ==",
"version": "4.25.2",
"resolved": "https://registry.npmjs.org/@algolia/logger-common/-/logger-common-4.25.2.tgz",
"integrity": "sha512-aUXpcodoIpLPsnVc2OHgC9E156R7yXWLW2l+Zn24Cyepfq3IvmuVckBvJDpp7nPnXkEzeMuvnVxQfQsk+zP/BA==",
"license": "MIT"
},
"node_modules/@algolia/logger-console": {
"version": "4.25.3",
"resolved": "https://registry.npmjs.org/@algolia/logger-console/-/logger-console-4.25.3.tgz",
"integrity": "sha512-s8AtfF9W+6Pbxfwkmzywd8ThVJ04D4JZlNyBdCuWpC5b3jzx1JAXT9ZL8K2faUsO4rEdHpy9LXMURvF7cQAE0w==",
"version": "4.25.2",
"resolved": "https://registry.npmjs.org/@algolia/logger-console/-/logger-console-4.25.2.tgz",
"integrity": "sha512-H3Y+UB0Ty0htvMJ6zDSufhFTSDlg3Pyj3AXilfDdDRcvfhH4C/cJNVm+CTaGORxL5uKABGsBp+SZjsEMTyAunQ==",
"license": "MIT",
"dependencies": {
"@algolia/logger-common": "4.25.3"
"@algolia/logger-common": "4.25.2"
}
},
"node_modules/@algolia/recommend": {
"version": "4.25.3",
"resolved": "https://registry.npmjs.org/@algolia/recommend/-/recommend-4.25.3.tgz",
"integrity": "sha512-/vpXzDFLmrkcM1UOvZae8i/z8wRs2uaKKlPaHqN24ySADWKyf2zxVsDmtcaGMYzBYqYsKR1XKFvwGA5HQxaZxQ==",
"version": "4.25.2",
"resolved": "https://registry.npmjs.org/@algolia/recommend/-/recommend-4.25.2.tgz",
"integrity": "sha512-puRrGeXwAuVa4mLdvXvmxHRFz9MkcCOLPcjz7MjU4NihlpIa+lZYgikJ7z0SUAaYgd6l5Bh00hXiU/OlX5ffXQ==",
"license": "MIT",
"dependencies": {
"@algolia/cache-browser-local-storage": "4.25.3",
"@algolia/cache-common": "4.25.3",
"@algolia/cache-in-memory": "4.25.3",
"@algolia/client-common": "4.25.3",
"@algolia/client-search": "4.25.3",
"@algolia/logger-common": "4.25.3",
"@algolia/logger-console": "4.25.3",
"@algolia/requester-browser-xhr": "4.25.3",
"@algolia/requester-common": "4.25.3",
"@algolia/requester-node-http": "4.25.3",
"@algolia/transporter": "4.25.3"
"@algolia/cache-browser-local-storage": "4.25.2",
"@algolia/cache-common": "4.25.2",
"@algolia/cache-in-memory": "4.25.2",
"@algolia/client-common": "4.25.2",
"@algolia/client-search": "4.25.2",
"@algolia/logger-common": "4.25.2",
"@algolia/logger-console": "4.25.2",
"@algolia/requester-browser-xhr": "4.25.2",
"@algolia/requester-common": "4.25.2",
"@algolia/requester-node-http": "4.25.2",
"@algolia/transporter": "4.25.2"
}
},
"node_modules/@algolia/requester-browser-xhr": {
"version": "4.25.3",
"resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-4.25.3.tgz",
"integrity": "sha512-5ZXO55IDqXUehQKilVYU6OdUBT2XGI+JIki2UsxUkMykH4ksA9EU8YZJth1ZwEYTDC50bVSH32VCYsOFB0MUTA==",
"version": "4.25.2",
"resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-4.25.2.tgz",
"integrity": "sha512-aAjfsI0AjWgXLh/xr9eoR8/9HekBkIER3bxGoBf9d1XWMMoTo/q92Da2fewkxwLE6mla95QJ9suJGOtMOewXXQ==",
"license": "MIT",
"dependencies": {
"@algolia/requester-common": "4.25.3"
"@algolia/requester-common": "4.25.2"
}
},
"node_modules/@algolia/requester-common": {
"version": "4.25.3",
"resolved": "https://registry.npmjs.org/@algolia/requester-common/-/requester-common-4.25.3.tgz",
"integrity": "sha512-n5dJA5jlIle5IQavlDWBXC46lw/VuwFbbknWJcPiJ6nJ6lRllpLOhV2ZJeUdCvRyg/6zG18h+9+Q/m2d/vLEIw==",
"version": "4.25.2",
"resolved": "https://registry.npmjs.org/@algolia/requester-common/-/requester-common-4.25.2.tgz",
"integrity": "sha512-Q4wC3sgY0UFjV3Rb3icRLTpPB5/M44A8IxzJHM9PNeK1T3iX7X/fmz7ATUYQYZTpwHCYATlsQKWiTpql1hHjVg==",
"license": "MIT"
},
"node_modules/@algolia/requester-node-http": {
"version": "4.25.3",
"resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-4.25.3.tgz",
"integrity": "sha512-7BXWAyVMK1Z3gT+2RPv0I48HfaIlho3nCQaB/tjziw+DdPigHRDq+xjtdzL8y+5O1g7LEdlPI9QHAgDbW/BLXw==",
"version": "4.25.2",
"resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-4.25.2.tgz",
"integrity": "sha512-Ja/FYB7W9ZM+m8UrMIlawNUAKpncvb9Mo+D8Jq5WepGTUyQ9CBYLsjwxv9O8wbj3TSWqTInf4uUBJ2FKR8G7xw==",
"license": "MIT",
"dependencies": {
"@algolia/requester-common": "4.25.3"
"@algolia/requester-common": "4.25.2"
}
},
"node_modules/@algolia/transporter": {
"version": "4.25.3",
"resolved": "https://registry.npmjs.org/@algolia/transporter/-/transporter-4.25.3.tgz",
"integrity": "sha512-2yji+TKjC1uOxhJ9pCdw7lQm6GSiQ+fMvNH4es6oz82DrBpkVHkeU49HmpyTqz8Ai9e+nW/UBz8T9+UyBul3dA==",
"version": "4.25.2",
"resolved": "https://registry.npmjs.org/@algolia/transporter/-/transporter-4.25.2.tgz",
"integrity": "sha512-yw3RLHWc6V+pbdsFtq8b6T5bJqLDqnfKWS7nac1Vzcmgvs/V/Lfy7/6iOF9XRilu5aBDOBHoP1SOeIDghguzWw==",
"license": "MIT",
"dependencies": {
"@algolia/cache-common": "4.25.3",
"@algolia/logger-common": "4.25.3",
"@algolia/requester-common": "4.25.3"
"@algolia/cache-common": "4.25.2",
"@algolia/logger-common": "4.25.2",
"@algolia/requester-common": "4.25.2"
}
},
"node_modules/@ampproject/remapping": {
@@ -272,9 +276,9 @@
}
},
"node_modules/@babel/compat-data": {
"version": "7.28.4",
"resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.4.tgz",
"integrity": "sha512-YsmSKC29MJwf0gF8Rjjrg5LQCmyh+j/nD8/eP7f+BeoQTKYqs9RoWbjGOdy0+1Ekr68RJZMUOPVQaQisnIo4Rw==",
"version": "7.28.0",
"resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.0.tgz",
"integrity": "sha512-60X7qkglvrap8mn1lh2ebxXdZYtUcpd7gsmy9kLaBJ4i/WdY8PqTSdxyA8qraikqKQK5C1KRBKXqznrVapyNaw==",
"devOptional": true,
"license": "MIT",
"engines": {
@@ -287,7 +291,6 @@
"integrity": "sha512-5e3FI4Q3M3Pbr21+5xJwCv6ZT6KmGkI0vw3Tozy5ODAQFTIWe37iT8Cr7Ice2Ntb+M3iSKCEWMB1MBgKrW3whg==",
"devOptional": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@ampproject/remapping": "^2.2.0",
"@babel/code-frame": "^7.24.7",
@@ -333,14 +336,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.0",
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.0.tgz",
"integrity": "sha512-lJjzvrbEeWrhB4P3QBsH7tey117PjLZnDbLiQEKjQ/fNJTjuq4HSqgFA+UNSwZT8D7dxxbnuSBMsa1lrWzKlQg==",
"devOptional": true,
"license": "MIT",
"dependencies": {
"@babel/parser": "^7.28.3",
"@babel/types": "^7.28.2",
"@babel/parser": "^7.28.0",
"@babel/types": "^7.28.0",
"@jridgewell/gen-mapping": "^0.3.12",
"@jridgewell/trace-mapping": "^0.3.28",
"jsesc": "^3.0.2"
@@ -380,18 +383,18 @@
}
},
"node_modules/@babel/helper-create-class-features-plugin": {
"version": "7.28.3",
"resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.28.3.tgz",
"integrity": "sha512-V9f6ZFIYSLNEbuGA/92uOvYsGCJNsuA8ESZ4ldc09bWk/j8H8TKiPw8Mk1eG6olpnO0ALHJmYfZvF4MEE4gajg==",
"version": "7.27.1",
"resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.27.1.tgz",
"integrity": "sha512-QwGAmuvM17btKU5VqXfb+Giw4JcN0hjuufz3DYnpeVDvZLAObloM77bhMXiqry3Iio+Ai4phVRDwl6WU10+r5A==",
"devOptional": true,
"license": "MIT",
"dependencies": {
"@babel/helper-annotate-as-pure": "^7.27.3",
"@babel/helper-annotate-as-pure": "^7.27.1",
"@babel/helper-member-expression-to-functions": "^7.27.1",
"@babel/helper-optimise-call-expression": "^7.27.1",
"@babel/helper-replace-supers": "^7.27.1",
"@babel/helper-skip-transparent-expression-wrappers": "^7.27.1",
"@babel/traverse": "^7.28.3",
"@babel/traverse": "^7.27.1",
"semver": "^6.3.1"
},
"engines": {
@@ -475,15 +478,15 @@
}
},
"node_modules/@babel/helper-module-transforms": {
"version": "7.28.3",
"resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz",
"integrity": "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==",
"version": "7.27.3",
"resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.27.3.tgz",
"integrity": "sha512-dSOvYwvyLsWBeIRyOeHXp5vPj5l1I011r52FM1+r1jCERv+aFXYk4whgQccYEGYxK2H3ZAIA8nuPkQ0HaUo3qg==",
"devOptional": true,
"license": "MIT",
"dependencies": {
"@babel/helper-module-imports": "^7.27.1",
"@babel/helper-validator-identifier": "^7.27.1",
"@babel/traverse": "^7.28.3"
"@babel/traverse": "^7.27.3"
},
"engines": {
"node": ">=6.9.0"
@@ -595,42 +598,42 @@
}
},
"node_modules/@babel/helper-wrap-function": {
"version": "7.28.3",
"resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.28.3.tgz",
"integrity": "sha512-zdf983tNfLZFletc0RRXYrHrucBEg95NIFMkn6K9dbeMYnsgHaSBGcQqdsCSStG2PYwRre0Qc2NNSCXbG+xc6g==",
"version": "7.27.1",
"resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.27.1.tgz",
"integrity": "sha512-NFJK2sHUvrjo8wAU/nQTWU890/zB2jj0qBcCbZbbf+005cAsv6tMjXz31fBign6M5ov1o0Bllu+9nbqkfsjjJQ==",
"devOptional": true,
"license": "MIT",
"dependencies": {
"@babel/template": "^7.27.2",
"@babel/traverse": "^7.28.3",
"@babel/types": "^7.28.2"
"@babel/template": "^7.27.1",
"@babel/traverse": "^7.27.1",
"@babel/types": "^7.27.1"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helpers": {
"version": "7.28.4",
"resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.4.tgz",
"integrity": "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==",
"version": "7.27.6",
"resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.27.6.tgz",
"integrity": "sha512-muE8Tt8M22638HU31A3CgfSUciwz1fhATfoVai05aPXGor//CdWDCbnlY1yvBPo07njuVOCNGCSp/GTt12lIug==",
"devOptional": true,
"license": "MIT",
"dependencies": {
"@babel/template": "^7.27.2",
"@babel/types": "^7.28.4"
"@babel/types": "^7.27.6"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/parser": {
"version": "7.28.4",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.4.tgz",
"integrity": "sha512-yZbBqeM6TkpP9du/I2pUZnJsRMGGvOuIrhjzC1AwHwW+6he4mni6Bp/m8ijn0iOuZuPI2BfkCoSRunpyjnrQKg==",
"version": "7.28.0",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.0.tgz",
"integrity": "sha512-jVZGvOxOuNSsuQuLRTh13nU0AogFlw32w/MT+LV6D3sP5WdbW61E77RnkbaO2dUvmPAYrBDJXGn5gGS6tH4j8g==",
"devOptional": true,
"license": "MIT",
"dependencies": {
"@babel/types": "^7.28.4"
"@babel/types": "^7.28.0"
},
"bin": {
"parser": "bin/babel-parser.js"
@@ -691,14 +694,14 @@
}
},
"node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": {
"version": "7.28.3",
"resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.28.3.tgz",
"integrity": "sha512-b6YTX108evsvE4YgWyQ921ZAFFQm3Bn+CA3+ZXlNVnPhx+UfsVURoPjfGAPCjBgrqo30yX/C2nZGX96DxvR9Iw==",
"version": "7.27.1",
"resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.27.1.tgz",
"integrity": "sha512-6BpaYGDavZqkI6yT+KSPdpZFfpnd68UKXbcjI9pJ13pvHhPrCKWOOLp+ysvMeA+DxnhuPpgIaRpxRxo5A9t5jw==",
"devOptional": true,
"license": "MIT",
"dependencies": {
"@babel/helper-plugin-utils": "^7.27.1",
"@babel/traverse": "^7.28.3"
"@babel/traverse": "^7.27.1"
},
"engines": {
"node": ">=6.9.0"
@@ -1126,9 +1129,9 @@
}
},
"node_modules/@babel/plugin-transform-block-scoping": {
"version": "7.28.4",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.28.4.tgz",
"integrity": "sha512-1yxmvN0MJHOhPVmAsmoW5liWwoILobu/d/ShymZmj867bAdxGbehIrew1DuLpw2Ukv+qDSSPQdYW1dLNE7t11A==",
"version": "7.28.0",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.28.0.tgz",
"integrity": "sha512-gKKnwjpdx5sER/wl0WN0efUBFzF/56YZO0RJrSYP4CljXnP31ByY7fol89AzomdlLNzI36AvOTmYHsnZTCkq8Q==",
"devOptional": true,
"license": "MIT",
"dependencies": {
@@ -1159,13 +1162,13 @@
}
},
"node_modules/@babel/plugin-transform-class-static-block": {
"version": "7.28.3",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.28.3.tgz",
"integrity": "sha512-LtPXlBbRoc4Njl/oh1CeD/3jC+atytbnf/UqLoqTDcEYGUPj022+rvfkbDYieUrSj3CaV4yHDByPE+T2HwfsJg==",
"version": "7.27.1",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.27.1.tgz",
"integrity": "sha512-s734HmYU78MVzZ++joYM+NkJusItbdRcbm+AGRgJCt3iA+yux0QpD9cBVdz3tKyrjVYWRl7j0mHSmv4lhV0aoA==",
"devOptional": true,
"license": "MIT",
"dependencies": {
"@babel/helper-create-class-features-plugin": "^7.28.3",
"@babel/helper-create-class-features-plugin": "^7.27.1",
"@babel/helper-plugin-utils": "^7.27.1"
},
"engines": {
@@ -1176,9 +1179,9 @@
}
},
"node_modules/@babel/plugin-transform-classes": {
"version": "7.28.4",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.28.4.tgz",
"integrity": "sha512-cFOlhIYPBv/iBoc+KS3M6et2XPtbT2HiCRfBXWtfpc9OAyostldxIf9YAYB6ypURBBbx+Qv6nyrLzASfJe+hBA==",
"version": "7.28.0",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.28.0.tgz",
"integrity": "sha512-IjM1IoJNw72AZFlj33Cu8X0q2XK/6AaVC3jQu+cgQ5lThWD5ajnuUAml80dqRmOhmPkTH8uAwnpMu9Rvj0LTRA==",
"devOptional": true,
"license": "MIT",
"dependencies": {
@@ -1187,7 +1190,7 @@
"@babel/helper-globals": "^7.28.0",
"@babel/helper-plugin-utils": "^7.27.1",
"@babel/helper-replace-supers": "^7.27.1",
"@babel/traverse": "^7.28.4"
"@babel/traverse": "^7.28.0"
},
"engines": {
"node": ">=6.9.0"
@@ -1546,9 +1549,9 @@
}
},
"node_modules/@babel/plugin-transform-object-rest-spread": {
"version": "7.28.4",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.28.4.tgz",
"integrity": "sha512-373KA2HQzKhQCYiRVIRr+3MjpCObqzDlyrM6u4I201wL8Mp2wHf7uB8GhDwis03k2ti8Zr65Zyyqs1xOxUF/Ew==",
"version": "7.28.0",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.28.0.tgz",
"integrity": "sha512-9VNGikXxzu5eCiQjdE4IZn8sb9q7Xsk5EXLDBKUYg1e/Tve8/05+KJEtcxGxAgCY5t/BpKQM+JEL/yT4tvgiUA==",
"devOptional": true,
"license": "MIT",
"dependencies": {
@@ -1556,7 +1559,7 @@
"@babel/helper-plugin-utils": "^7.27.1",
"@babel/plugin-transform-destructuring": "^7.28.0",
"@babel/plugin-transform-parameters": "^7.27.7",
"@babel/traverse": "^7.28.4"
"@babel/traverse": "^7.28.0"
},
"engines": {
"node": ">=6.9.0"
@@ -1768,9 +1771,9 @@
}
},
"node_modules/@babel/plugin-transform-regenerator": {
"version": "7.28.4",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.28.4.tgz",
"integrity": "sha512-+ZEdQlBoRg9m2NnzvEeLgtvBMO4tkFBw5SQIUgLICgTrumLoU7lr+Oghi6km2PFj+dbUt2u1oby2w3BDO9YQnA==",
"version": "7.28.0",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.28.0.tgz",
"integrity": "sha512-LOAozRVbqxEVjSKfhGnuLoE4Kz4Oc5UJzuvFUhSsQzdCdaAQu06mG8zDv2GFSerM62nImUZ7K92vxnQcLSDlCQ==",
"devOptional": true,
"license": "MIT",
"dependencies": {
@@ -2120,18 +2123,18 @@
}
},
"node_modules/@babel/runtime": {
"version": "7.28.4",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.4.tgz",
"integrity": "sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==",
"version": "7.27.6",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.6.tgz",
"integrity": "sha512-vbavdySgbTTrmFE+EsiqUTzlOr5bzlnJtUv9PynGCAKvfQqjIXbvFdumPM/GxMDfyuGMJaJAU6TO4zc1Jf1i8Q==",
"license": "MIT",
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/runtime-corejs3": {
"version": "7.28.4",
"resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.28.4.tgz",
"integrity": "sha512-h7iEYiW4HebClDEhtvFObtPmIvrd1SSfpI9EhOeKk4CtIK/ngBWFpuhCzhdmRKtg71ylcue+9I6dv54XYO1epQ==",
"version": "7.28.0",
"resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.28.0.tgz",
"integrity": "sha512-nlIXnSqLcBij8K8TtkxbBJgfzfvi75V1pAKSM7dUXejGw12vJAqez74jZrHTsJ3Z+Aczc5Q/6JgNjKRMsVU44g==",
"license": "MIT",
"dependencies": {
"core-js-pure": "^3.43.0"
@@ -2156,18 +2159,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.0",
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.0.tgz",
"integrity": "sha512-mGe7UK5wWyh0bKRfupsUchrQGqvDbZDbKJw+kcRGSmdHVYrv+ltd0pnpDTVpiTqnaBru9iEvA8pz8W46v0Amwg==",
"devOptional": true,
"license": "MIT",
"dependencies": {
"@babel/code-frame": "^7.27.1",
"@babel/generator": "^7.28.3",
"@babel/generator": "^7.28.0",
"@babel/helper-globals": "^7.28.0",
"@babel/parser": "^7.28.4",
"@babel/parser": "^7.28.0",
"@babel/template": "^7.27.2",
"@babel/types": "^7.28.4",
"@babel/types": "^7.28.0",
"debug": "^4.3.1"
},
"engines": {
@@ -2175,9 +2178,9 @@
}
},
"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.0",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.0.tgz",
"integrity": "sha512-jYnje+JyZG5YThjHiF28oT4SIZLnYOcSBb6+SDaFIyzDVSkXQmQQYclJ2R+YxcdmK0AX6x1E5OQNtuh3jHDrUg==",
"devOptional": true,
"license": "MIT",
"dependencies": {
@@ -2329,16 +2332,14 @@
}
},
"node_modules/@bundled-es-modules/memfs/node_modules/memfs": {
"version": "4.39.0",
"resolved": "https://registry.npmjs.org/memfs/-/memfs-4.39.0.tgz",
"integrity": "sha512-tFRr2IkSXl2B6IAJsxjHIMTOsfLt9W+8+t2uNxCeQcz4tFqgQR8DYk8hlLH2HsucTctLuoHq3U0G08atyBE3yw==",
"version": "4.17.2",
"resolved": "https://registry.npmjs.org/memfs/-/memfs-4.17.2.tgz",
"integrity": "sha512-NgYhCOWgovOXSzvYgUW0LQ7Qy72rWQMGGFJDoWg4G30RHd3z77VbYdtJ4fembJXBy8pMIUA31XNAupobOQlwdg==",
"license": "Apache-2.0",
"dependencies": {
"@jsonjoy.com/json-pack": "^1.11.0",
"@jsonjoy.com/util": "^1.9.0",
"glob-to-regex.js": "^1.0.1",
"thingies": "^2.5.0",
"tree-dump": "^1.0.3",
"@jsonjoy.com/json-pack": "^1.0.3",
"@jsonjoy.com/util": "^1.3.0",
"tree-dump": "^1.0.1",
"tslib": "^2.0.0"
},
"engines": {
@@ -2444,7 +2445,6 @@
}
],
"license": "MIT",
"peer": true,
"engines": {
"node": "^14 || ^16 || >=18"
},
@@ -2467,7 +2467,6 @@
}
],
"license": "MIT",
"peer": true,
"engines": {
"node": "^14 || ^16 || >=18"
}
@@ -2520,9 +2519,9 @@
"license": "AGPL-3.0"
},
"node_modules/@edx/eslint-config": {
"version": "4.4.0",
"resolved": "https://registry.npmjs.org/@edx/eslint-config/-/eslint-config-4.4.0.tgz",
"integrity": "sha512-NoKXNU2F2O5FEnV/DoBIgN8XiiG6FZcIwSBn1GBUgY1tm/+kSpgFMF8UfGK8g5Kk437u5ofpRLx3J+PnEfBf2Q==",
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/@edx/eslint-config/-/eslint-config-4.3.0.tgz",
"integrity": "sha512-4W9wFG4ALr3xocakCsncgJbK67RHfSmDwHDXKHReFtjxl/FRkxhS6qayz189oChqfANieeV3zRCLaq44bLf+/A==",
"devOptional": true,
"license": "MIT",
"peerDependencies": {
@@ -2538,15 +2537,15 @@
}
},
"node_modules/@edx/frontend-platform": {
"version": "8.5.2",
"resolved": "https://registry.npmjs.org/@edx/frontend-platform/-/frontend-platform-8.5.2.tgz",
"integrity": "sha512-YlxNWs8NW/I7F03k/jH6grWIuY/GJrspq7fqWm5K0ocvNEf+B8XKcaLUof+jVUuCItK93SoVRDZewwejnjty5w==",
"version": "8.4.0",
"resolved": "https://registry.npmjs.org/@edx/frontend-platform/-/frontend-platform-8.4.0.tgz",
"integrity": "sha512-toWMU7qVx56f5bLk6/Sl5WWqlKtGp602qDs22JYp5r2VBp5F/nzcrpXXWC925/kH0TP5hI2OMolmLq6n2N8a4Q==",
"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": "1.9.0",
"axios-cache-interceptor": "1.8.0",
"form-urlencoded": "4.1.4",
"glob": "7.2.3",
@@ -2648,6 +2647,30 @@
"atlas": "atlas"
}
},
"node_modules/@edx/reactifex": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@edx/reactifex/-/reactifex-1.1.0.tgz",
"integrity": "sha512-tXIB+lxTKNsWeMrlJ+NXAiBgvuJ7OVLxzdGMPVYPOL8Xh3BJ/S7CC1/foV8iKl0859UwshLPTAUCOn4NhgGDvw==",
"dev": true,
"license": "MIT",
"dependencies": {
"axios": "^0.21.1",
"yargs": "^17.1.1"
},
"bin": {
"edx_reactifex": "main.js"
}
},
"node_modules/@edx/reactifex/node_modules/axios": {
"version": "0.21.4",
"resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz",
"integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==",
"dev": true,
"license": "MIT",
"dependencies": {
"follow-redirects": "^1.14.0"
}
},
"node_modules/@edx/typescript-config": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@edx/typescript-config/-/typescript-config-1.1.0.tgz",
@@ -2659,21 +2682,21 @@
}
},
"node_modules/@emnapi/core": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.5.0.tgz",
"integrity": "sha512-sbP8GzB1WDzacS8fgNPpHlp6C9VZe+SJP3F90W9rLemaQj2PzIuTEl1qDOYQf58YIpyjViI24y9aPWCjEzY2cg==",
"version": "1.4.4",
"resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.4.4.tgz",
"integrity": "sha512-A9CnAbC6ARNMKcIcrQwq6HeHCjpcBZ5wSx4U01WXCqEKlrzB9F9315WDNHkrs2xbx7YjjSxbUYxuN6EQzpcY2g==",
"dev": true,
"license": "MIT",
"optional": true,
"dependencies": {
"@emnapi/wasi-threads": "1.1.0",
"@emnapi/wasi-threads": "1.0.3",
"tslib": "^2.4.0"
}
},
"node_modules/@emnapi/runtime": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.5.0.tgz",
"integrity": "sha512-97/BJ3iXHww3djw6hYIfErCZFee7qCtrneuLa20UXFCOTCfBM2cvQHjWJ2EG0s0MtdNwInarqCTz35i4wWXHsQ==",
"version": "1.4.4",
"resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.4.4.tgz",
"integrity": "sha512-hHyapA4A3gPaDCNfiqyZUStTMqIkKRshqPIuDOXv1hcBnD4U3l8cP0T1HMCfGRxQ6V64TGCcoswChANyOAwbQg==",
"dev": true,
"license": "MIT",
"optional": true,
@@ -2682,9 +2705,9 @@
}
},
"node_modules/@emnapi/wasi-threads": {
"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==",
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.0.3.tgz",
"integrity": "sha512-8K5IFFsQqF9wQNJptGbS6FNKgUTsSRYnTqNCG1vPP8jFdjSv18n2mQfJpkt2Oibo9iBEzcDnDxNwKTzC7svlJw==",
"dev": true,
"license": "MIT",
"optional": true,
@@ -2693,9 +2716,9 @@
}
},
"node_modules/@eslint-community/eslint-utils": {
"version": "4.9.0",
"resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.0.tgz",
"integrity": "sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==",
"version": "4.7.0",
"resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.7.0.tgz",
"integrity": "sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==",
"devOptional": true,
"license": "MIT",
"dependencies": {
@@ -2854,26 +2877,26 @@
}
},
"node_modules/@formatjs/icu-messageformat-parser": {
"version": "2.11.4",
"resolved": "https://registry.npmjs.org/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-2.11.4.tgz",
"integrity": "sha512-7kR78cRrPNB4fjGFZg3Rmj5aah8rQj9KPzuLsmcSn4ipLXQvC04keycTI1F7kJYDwIXtT2+7IDEto842CfZBtw==",
"version": "2.11.2",
"resolved": "https://registry.npmjs.org/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-2.11.2.tgz",
"integrity": "sha512-AfiMi5NOSo2TQImsYAg8UYddsNJ/vUEv/HaNqiFjnI3ZFfWihUtD5QtuX6kHl8+H+d3qvnE/3HZrfzgdWpsLNA==",
"devOptional": true,
"license": "MIT",
"dependencies": {
"@formatjs/ecma402-abstract": "2.3.6",
"@formatjs/icu-skeleton-parser": "1.8.16",
"@formatjs/ecma402-abstract": "2.3.4",
"@formatjs/icu-skeleton-parser": "1.8.14",
"tslib": "^2.8.0"
}
},
"node_modules/@formatjs/icu-messageformat-parser/node_modules/@formatjs/ecma402-abstract": {
"version": "2.3.6",
"resolved": "https://registry.npmjs.org/@formatjs/ecma402-abstract/-/ecma402-abstract-2.3.6.tgz",
"integrity": "sha512-HJnTFeRM2kVFVr5gr5kH1XP6K0JcJtE7Lzvtr3FS/so5f1kpsqqqxy5JF+FRaO6H2qmcMfAUIox7AJteieRtVw==",
"version": "2.3.4",
"resolved": "https://registry.npmjs.org/@formatjs/ecma402-abstract/-/ecma402-abstract-2.3.4.tgz",
"integrity": "sha512-qrycXDeaORzIqNhBOx0btnhpD1c+/qFIHAN9znofuMJX6QBwtbrmlpWfD4oiUUD2vJUOIYFA/gYtg2KAMGG7sA==",
"devOptional": true,
"license": "MIT",
"dependencies": {
"@formatjs/fast-memoize": "2.2.7",
"@formatjs/intl-localematcher": "0.6.2",
"@formatjs/intl-localematcher": "0.6.1",
"decimal.js": "^10.4.3",
"tslib": "^2.8.0"
}
@@ -2889,9 +2912,9 @@
}
},
"node_modules/@formatjs/icu-messageformat-parser/node_modules/@formatjs/intl-localematcher": {
"version": "0.6.2",
"resolved": "https://registry.npmjs.org/@formatjs/intl-localematcher/-/intl-localematcher-0.6.2.tgz",
"integrity": "sha512-XOMO2Hupl0wdd172Y06h6kLpBz6Dv+J4okPLl4LPtzbr8f66WbIoy4ev98EBuZ6ZK4h5ydTN6XneT4QVpD7cdA==",
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/@formatjs/intl-localematcher/-/intl-localematcher-0.6.1.tgz",
"integrity": "sha512-ePEgLgVCqi2BBFnTMWPfIghu6FkbZnnBVhO2sSxvLfrdFw7wCHAHiDoM2h4NRgjbaY7+B7HgOLZGkK187pZTZg==",
"devOptional": true,
"license": "MIT",
"dependencies": {
@@ -2899,25 +2922,25 @@
}
},
"node_modules/@formatjs/icu-skeleton-parser": {
"version": "1.8.16",
"resolved": "https://registry.npmjs.org/@formatjs/icu-skeleton-parser/-/icu-skeleton-parser-1.8.16.tgz",
"integrity": "sha512-H13E9Xl+PxBd8D5/6TVUluSpxGNvFSlN/b3coUp0e0JpuWXXnQDiavIpY3NnvSp4xhEMoXyyBvVfdFX8jglOHQ==",
"version": "1.8.14",
"resolved": "https://registry.npmjs.org/@formatjs/icu-skeleton-parser/-/icu-skeleton-parser-1.8.14.tgz",
"integrity": "sha512-i4q4V4qslThK4Ig8SxyD76cp3+QJ3sAqr7f6q9VVfeGtxG9OhiAk3y9XF6Q41OymsKzsGQ6OQQoJNY4/lI8TcQ==",
"devOptional": true,
"license": "MIT",
"dependencies": {
"@formatjs/ecma402-abstract": "2.3.6",
"@formatjs/ecma402-abstract": "2.3.4",
"tslib": "^2.8.0"
}
},
"node_modules/@formatjs/icu-skeleton-parser/node_modules/@formatjs/ecma402-abstract": {
"version": "2.3.6",
"resolved": "https://registry.npmjs.org/@formatjs/ecma402-abstract/-/ecma402-abstract-2.3.6.tgz",
"integrity": "sha512-HJnTFeRM2kVFVr5gr5kH1XP6K0JcJtE7Lzvtr3FS/so5f1kpsqqqxy5JF+FRaO6H2qmcMfAUIox7AJteieRtVw==",
"version": "2.3.4",
"resolved": "https://registry.npmjs.org/@formatjs/ecma402-abstract/-/ecma402-abstract-2.3.4.tgz",
"integrity": "sha512-qrycXDeaORzIqNhBOx0btnhpD1c+/qFIHAN9znofuMJX6QBwtbrmlpWfD4oiUUD2vJUOIYFA/gYtg2KAMGG7sA==",
"devOptional": true,
"license": "MIT",
"dependencies": {
"@formatjs/fast-memoize": "2.2.7",
"@formatjs/intl-localematcher": "0.6.2",
"@formatjs/intl-localematcher": "0.6.1",
"decimal.js": "^10.4.3",
"tslib": "^2.8.0"
}
@@ -2933,9 +2956,9 @@
}
},
"node_modules/@formatjs/icu-skeleton-parser/node_modules/@formatjs/intl-localematcher": {
"version": "0.6.2",
"resolved": "https://registry.npmjs.org/@formatjs/intl-localematcher/-/intl-localematcher-0.6.2.tgz",
"integrity": "sha512-XOMO2Hupl0wdd172Y06h6kLpBz6Dv+J4okPLl4LPtzbr8f66WbIoy4ev98EBuZ6ZK4h5ydTN6XneT4QVpD7cdA==",
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/@formatjs/intl-localematcher/-/intl-localematcher-0.6.1.tgz",
"integrity": "sha512-ePEgLgVCqi2BBFnTMWPfIghu6FkbZnnBVhO2sSxvLfrdFw7wCHAHiDoM2h4NRgjbaY7+B7HgOLZGkK187pZTZg==",
"devOptional": true,
"license": "MIT",
"dependencies": {
@@ -3100,16 +3123,17 @@
}
},
"node_modules/@formatjs/ts-transformer": {
"version": "3.14.2",
"resolved": "https://registry.npmjs.org/@formatjs/ts-transformer/-/ts-transformer-3.14.2.tgz",
"integrity": "sha512-c47ij+2Xi4jMDO3Hz01BDF3yB4575Gkoq24sFzVw1K1kpHvITsFfdlXQbhxScBwJi2gBhMpuZ++XsTUZ9O0Law==",
"version": "3.14.0",
"resolved": "https://registry.npmjs.org/@formatjs/ts-transformer/-/ts-transformer-3.14.0.tgz",
"integrity": "sha512-sWV+gLu3N/Fqb6Jh4cSbKAOIO/bumATZvyF8+TGFW+sAhmedvgQXpnUwiy4qJpU6buEq3Ap5jFGfmDRf0V6HYQ==",
"devOptional": true,
"license": "MIT",
"dependencies": {
"@formatjs/icu-messageformat-parser": "2.11.4",
"@formatjs/icu-messageformat-parser": "2.11.2",
"@types/json-stable-stringify": "^1.1.0",
"@types/node": "^22.0.0",
"chalk": "^4.1.2",
"json-stable-stringify": "^1.3.0",
"json-stable-stringify": "^1.1.1",
"tslib": "^2.8.0",
"typescript": "^5.6.0"
},
@@ -3123,9 +3147,9 @@
}
},
"node_modules/@formatjs/ts-transformer/node_modules/@types/node": {
"version": "22.18.3",
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.18.3.tgz",
"integrity": "sha512-gTVM8js2twdtqM+AE2PdGEe9zGQY4UvmFjan9rZcVb6FGdStfjWoWejdmy4CfWVO9rh5MiYQGZloKAGkJt8lMw==",
"version": "22.16.0",
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.16.0.tgz",
"integrity": "sha512-B2egV9wALML1JCpv3VQoQ+yesQKAmNMBIAY7OteVrikcOcAkWm+dGL6qpeCktPjAv6N1JLnhbNiqS35UpFyBsQ==",
"devOptional": true,
"license": "MIT",
"dependencies": {
@@ -3167,7 +3191,6 @@
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.7.2.tgz",
"integrity": "sha512-yxtOBWDrdi5DD5o1pmVdq3WMCvnobT0LU6R8RyyVXPvFRd2o79/0NCuQoCjNTeZz9EzA9xS3JxNWfv54RIHFEA==",
"license": "MIT",
"peer": true,
"dependencies": {
"@fortawesome/fontawesome-common-types": "6.7.2"
},
@@ -3200,16 +3223,16 @@
}
},
"node_modules/@fortawesome/react-fontawesome": {
"version": "0.2.6",
"resolved": "https://registry.npmjs.org/@fortawesome/react-fontawesome/-/react-fontawesome-0.2.6.tgz",
"integrity": "sha512-mtBFIi1UsYQo7rYonYFkjgYKGoL8T+fEH6NGUpvuqtY3ytMsAoDaPo5rk25KuMtKDipY4bGYM/CkmCHA1N3FUg==",
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/@fortawesome/react-fontawesome/-/react-fontawesome-0.2.2.tgz",
"integrity": "sha512-EnkrprPNqI6SXJl//m29hpaNzOp1bruISWaOiRtkMi/xSvHJlzc2j2JAYS7egxt/EbjSNV/k6Xy0AQI6vB2+1g==",
"license": "MIT",
"dependencies": {
"prop-types": "^15.8.1"
},
"peerDependencies": {
"@fortawesome/fontawesome-svg-core": "~1 || ~6 || ~7",
"react": "^16.3 || ^17.0.0 || ^18.0.0 || ^19.0.0"
"@fortawesome/fontawesome-svg-core": "~1 || ~6",
"react": ">=16.3"
}
},
"node_modules/@fullhuman/postcss-purgecss": {
@@ -3263,483 +3286,6 @@
"devOptional": true,
"license": "BSD-3-Clause"
},
"node_modules/@img/sharp-darwin-arm64": {
"version": "0.34.3",
"resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.3.tgz",
"integrity": "sha512-ryFMfvxxpQRsgZJqBd4wsttYQbCxsJksrv9Lw/v798JcQ8+w84mBWuXwl+TT0WJ/WrYOLaYpwQXi3sA9nTIaIg==",
"cpu": [
"arm64"
],
"dev": true,
"license": "Apache-2.0",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
},
"optionalDependencies": {
"@img/sharp-libvips-darwin-arm64": "1.2.0"
}
},
"node_modules/@img/sharp-darwin-x64": {
"version": "0.34.3",
"resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.3.tgz",
"integrity": "sha512-yHpJYynROAj12TA6qil58hmPmAwxKKC7reUqtGLzsOHfP7/rniNGTL8tjWX6L3CTV4+5P4ypcS7Pp+7OB+8ihA==",
"cpu": [
"x64"
],
"dev": true,
"license": "Apache-2.0",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
},
"optionalDependencies": {
"@img/sharp-libvips-darwin-x64": "1.2.0"
}
},
"node_modules/@img/sharp-libvips-darwin-arm64": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.0.tgz",
"integrity": "sha512-sBZmpwmxqwlqG9ueWFXtockhsxefaV6O84BMOrhtg/YqbTaRdqDE7hxraVE3y6gVM4eExmfzW4a8el9ArLeEiQ==",
"cpu": [
"arm64"
],
"dev": true,
"license": "LGPL-3.0-or-later",
"optional": true,
"os": [
"darwin"
],
"funding": {
"url": "https://opencollective.com/libvips"
}
},
"node_modules/@img/sharp-libvips-darwin-x64": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.0.tgz",
"integrity": "sha512-M64XVuL94OgiNHa5/m2YvEQI5q2cl9d/wk0qFTDVXcYzi43lxuiFTftMR1tOnFQovVXNZJ5TURSDK2pNe9Yzqg==",
"cpu": [
"x64"
],
"dev": true,
"license": "LGPL-3.0-or-later",
"optional": true,
"os": [
"darwin"
],
"funding": {
"url": "https://opencollective.com/libvips"
}
},
"node_modules/@img/sharp-libvips-linux-arm": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.0.tgz",
"integrity": "sha512-mWd2uWvDtL/nvIzThLq3fr2nnGfyr/XMXlq8ZJ9WMR6PXijHlC3ksp0IpuhK6bougvQrchUAfzRLnbsen0Cqvw==",
"cpu": [
"arm"
],
"dev": true,
"license": "LGPL-3.0-or-later",
"optional": true,
"os": [
"linux"
],
"funding": {
"url": "https://opencollective.com/libvips"
}
},
"node_modules/@img/sharp-libvips-linux-arm64": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.0.tgz",
"integrity": "sha512-RXwd0CgG+uPRX5YYrkzKyalt2OJYRiJQ8ED/fi1tq9WQW2jsQIn0tqrlR5l5dr/rjqq6AHAxURhj2DVjyQWSOA==",
"cpu": [
"arm64"
],
"dev": true,
"license": "LGPL-3.0-or-later",
"optional": true,
"os": [
"linux"
],
"funding": {
"url": "https://opencollective.com/libvips"
}
},
"node_modules/@img/sharp-libvips-linux-ppc64": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.2.0.tgz",
"integrity": "sha512-Xod/7KaDDHkYu2phxxfeEPXfVXFKx70EAFZ0qyUdOjCcxbjqyJOEUpDe6RIyaunGxT34Anf9ue/wuWOqBW2WcQ==",
"cpu": [
"ppc64"
],
"dev": true,
"license": "LGPL-3.0-or-later",
"optional": true,
"os": [
"linux"
],
"funding": {
"url": "https://opencollective.com/libvips"
}
},
"node_modules/@img/sharp-libvips-linux-s390x": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.2.0.tgz",
"integrity": "sha512-eMKfzDxLGT8mnmPJTNMcjfO33fLiTDsrMlUVcp6b96ETbnJmd4uvZxVJSKPQfS+odwfVaGifhsB07J1LynFehw==",
"cpu": [
"s390x"
],
"dev": true,
"license": "LGPL-3.0-or-later",
"optional": true,
"os": [
"linux"
],
"funding": {
"url": "https://opencollective.com/libvips"
}
},
"node_modules/@img/sharp-libvips-linux-x64": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.0.tgz",
"integrity": "sha512-ZW3FPWIc7K1sH9E3nxIGB3y3dZkpJlMnkk7z5tu1nSkBoCgw2nSRTFHI5pB/3CQaJM0pdzMF3paf9ckKMSE9Tg==",
"cpu": [
"x64"
],
"dev": true,
"license": "LGPL-3.0-or-later",
"optional": true,
"os": [
"linux"
],
"funding": {
"url": "https://opencollective.com/libvips"
}
},
"node_modules/@img/sharp-libvips-linuxmusl-arm64": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.0.tgz",
"integrity": "sha512-UG+LqQJbf5VJ8NWJ5Z3tdIe/HXjuIdo4JeVNADXBFuG7z9zjoegpzzGIyV5zQKi4zaJjnAd2+g2nna8TZvuW9Q==",
"cpu": [
"arm64"
],
"dev": true,
"license": "LGPL-3.0-or-later",
"optional": true,
"os": [
"linux"
],
"funding": {
"url": "https://opencollective.com/libvips"
}
},
"node_modules/@img/sharp-libvips-linuxmusl-x64": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.0.tgz",
"integrity": "sha512-SRYOLR7CXPgNze8akZwjoGBoN1ThNZoqpOgfnOxmWsklTGVfJiGJoC/Lod7aNMGA1jSsKWM1+HRX43OP6p9+6Q==",
"cpu": [
"x64"
],
"dev": true,
"license": "LGPL-3.0-or-later",
"optional": true,
"os": [
"linux"
],
"funding": {
"url": "https://opencollective.com/libvips"
}
},
"node_modules/@img/sharp-linux-arm": {
"version": "0.34.3",
"resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.3.tgz",
"integrity": "sha512-oBK9l+h6KBN0i3dC8rYntLiVfW8D8wH+NPNT3O/WBHeW0OQWCjfWksLUaPidsrDKpJgXp3G3/hkmhptAW0I3+A==",
"cpu": [
"arm"
],
"dev": true,
"license": "Apache-2.0",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
},
"optionalDependencies": {
"@img/sharp-libvips-linux-arm": "1.2.0"
}
},
"node_modules/@img/sharp-linux-arm64": {
"version": "0.34.3",
"resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.3.tgz",
"integrity": "sha512-QdrKe3EvQrqwkDrtuTIjI0bu6YEJHTgEeqdzI3uWJOH6G1O8Nl1iEeVYRGdj1h5I21CqxSvQp1Yv7xeU3ZewbA==",
"cpu": [
"arm64"
],
"dev": true,
"license": "Apache-2.0",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
},
"optionalDependencies": {
"@img/sharp-libvips-linux-arm64": "1.2.0"
}
},
"node_modules/@img/sharp-linux-ppc64": {
"version": "0.34.3",
"resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.34.3.tgz",
"integrity": "sha512-GLtbLQMCNC5nxuImPR2+RgrviwKwVql28FWZIW1zWruy6zLgA5/x2ZXk3mxj58X/tszVF69KK0Is83V8YgWhLA==",
"cpu": [
"ppc64"
],
"dev": true,
"license": "Apache-2.0",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
},
"optionalDependencies": {
"@img/sharp-libvips-linux-ppc64": "1.2.0"
}
},
"node_modules/@img/sharp-linux-s390x": {
"version": "0.34.3",
"resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.3.tgz",
"integrity": "sha512-3gahT+A6c4cdc2edhsLHmIOXMb17ltffJlxR0aC2VPZfwKoTGZec6u5GrFgdR7ciJSsHT27BD3TIuGcuRT0KmQ==",
"cpu": [
"s390x"
],
"dev": true,
"license": "Apache-2.0",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
},
"optionalDependencies": {
"@img/sharp-libvips-linux-s390x": "1.2.0"
}
},
"node_modules/@img/sharp-linux-x64": {
"version": "0.34.3",
"resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.3.tgz",
"integrity": "sha512-8kYso8d806ypnSq3/Ly0QEw90V5ZoHh10yH0HnrzOCr6DKAPI6QVHvwleqMkVQ0m+fc7EH8ah0BB0QPuWY6zJQ==",
"cpu": [
"x64"
],
"dev": true,
"license": "Apache-2.0",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
},
"optionalDependencies": {
"@img/sharp-libvips-linux-x64": "1.2.0"
}
},
"node_modules/@img/sharp-linuxmusl-arm64": {
"version": "0.34.3",
"resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.3.tgz",
"integrity": "sha512-vAjbHDlr4izEiXM1OTggpCcPg9tn4YriK5vAjowJsHwdBIdx0fYRsURkxLG2RLm9gyBq66gwtWI8Gx0/ov+JKQ==",
"cpu": [
"arm64"
],
"dev": true,
"license": "Apache-2.0",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
},
"optionalDependencies": {
"@img/sharp-libvips-linuxmusl-arm64": "1.2.0"
}
},
"node_modules/@img/sharp-linuxmusl-x64": {
"version": "0.34.3",
"resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.3.tgz",
"integrity": "sha512-gCWUn9547K5bwvOn9l5XGAEjVTTRji4aPTqLzGXHvIr6bIDZKNTA34seMPgM0WmSf+RYBH411VavCejp3PkOeQ==",
"cpu": [
"x64"
],
"dev": true,
"license": "Apache-2.0",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
},
"optionalDependencies": {
"@img/sharp-libvips-linuxmusl-x64": "1.2.0"
}
},
"node_modules/@img/sharp-wasm32": {
"version": "0.34.3",
"resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.34.3.tgz",
"integrity": "sha512-+CyRcpagHMGteySaWos8IbnXcHgfDn7pO2fiC2slJxvNq9gDipYBN42/RagzctVRKgxATmfqOSulgZv5e1RdMg==",
"cpu": [
"wasm32"
],
"dev": true,
"license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT",
"optional": true,
"dependencies": {
"@emnapi/runtime": "^1.4.4"
},
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
}
},
"node_modules/@img/sharp-win32-arm64": {
"version": "0.34.3",
"resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.3.tgz",
"integrity": "sha512-MjnHPnbqMXNC2UgeLJtX4XqoVHHlZNd+nPt1kRPmj63wURegwBhZlApELdtxM2OIZDRv/DFtLcNhVbd1z8GYXQ==",
"cpu": [
"arm64"
],
"dev": true,
"license": "Apache-2.0 AND LGPL-3.0-or-later",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
}
},
"node_modules/@img/sharp-win32-ia32": {
"version": "0.34.3",
"resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.3.tgz",
"integrity": "sha512-xuCdhH44WxuXgOM714hn4amodJMZl3OEvf0GVTm0BEyMeA2to+8HEdRPShH0SLYptJY1uBw+SCFP9WVQi1Q/cw==",
"cpu": [
"ia32"
],
"dev": true,
"license": "Apache-2.0 AND LGPL-3.0-or-later",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
}
},
"node_modules/@img/sharp-win32-x64": {
"version": "0.34.3",
"resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.3.tgz",
"integrity": "sha512-OWwz05d++TxzLEv4VnsTz5CmZ6mI6S05sfQGEMrNrQcOEERbX46332IvE7pO/EUiw7jUrrS40z/M7kPyjfl04g==",
"cpu": [
"x64"
],
"dev": true,
"license": "Apache-2.0 AND LGPL-3.0-or-later",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
}
},
"node_modules/@inquirer/external-editor": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@inquirer/external-editor/-/external-editor-1.0.2.tgz",
"integrity": "sha512-yy9cOoBnx58TlsPrIxauKIFQTiyH+0MK4e97y4sV9ERbI+zDxw7i2hxHLCIEGIE/8PPvDxGhgzIOTSOWcs6/MQ==",
"license": "MIT",
"dependencies": {
"chardet": "^2.1.0",
"iconv-lite": "^0.7.0"
},
"engines": {
"node": ">=18"
},
"peerDependencies": {
"@types/node": ">=18"
},
"peerDependenciesMeta": {
"@types/node": {
"optional": true
}
}
},
"node_modules/@inquirer/external-editor/node_modules/iconv-lite": {
"version": "0.7.0",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.0.tgz",
"integrity": "sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==",
"license": "MIT",
"dependencies": {
"safer-buffer": ">= 2.1.2 < 3.0.0"
},
"engines": {
"node": ">=0.10.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/express"
}
},
"node_modules/@isaacs/cliui": {
"version": "8.0.2",
"resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz",
@@ -3758,9 +3304,9 @@
}
},
"node_modules/@isaacs/cliui/node_modules/ansi-regex": {
"version": "6.2.2",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz",
"integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==",
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz",
"integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==",
"license": "MIT",
"engines": {
"node": ">=12"
@@ -3770,9 +3316,9 @@
}
},
"node_modules/@isaacs/cliui/node_modules/ansi-styles": {
"version": "6.2.3",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz",
"integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==",
"version": "6.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz",
"integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==",
"license": "MIT",
"engines": {
"node": ">=12"
@@ -3805,9 +3351,9 @@
}
},
"node_modules/@isaacs/cliui/node_modules/strip-ansi": {
"version": "7.1.2",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz",
"integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==",
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz",
"integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==",
"license": "MIT",
"dependencies": {
"ansi-regex": "^6.0.1"
@@ -3874,17 +3420,17 @@
}
},
"node_modules/@jest/console": {
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/@jest/console/-/console-30.2.0.tgz",
"integrity": "sha512-+O1ifRjkvYIkBqASKWgLxrpEhQAAE7hY77ALLUufSk5717KfOShg6IbqLmdsLMPdUiFvA2kTs0R7YZy+l0IzZQ==",
"version": "30.0.4",
"resolved": "https://registry.npmjs.org/@jest/console/-/console-30.0.4.tgz",
"integrity": "sha512-tMLCDvBJBwPqMm4OAiuKm2uF5y5Qe26KgcMn+nrDSWpEW+eeFmqA0iO4zJfL16GP7gE3bUUQ3hIuUJ22AqVRnw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/types": "30.2.0",
"@jest/types": "30.0.1",
"@types/node": "*",
"chalk": "^4.1.2",
"jest-message-util": "30.2.0",
"jest-util": "30.2.0",
"jest-message-util": "30.0.2",
"jest-util": "30.0.2",
"slash": "^3.0.0"
},
"engines": {
@@ -3892,9 +3438,9 @@
}
},
"node_modules/@jest/console/node_modules/@jest/schemas": {
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz",
"integrity": "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==",
"version": "30.0.1",
"resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.1.tgz",
"integrity": "sha512-+g/1TKjFuGrf1Hh0QPCv0gISwBxJ+MQSNXmG9zjHy7BmFhtoJ9fdNhWJp3qUKRi93AOZHXtdxZgJ1vAtz6z65w==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -3905,14 +3451,14 @@
}
},
"node_modules/@jest/console/node_modules/@jest/types": {
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-30.2.0.tgz",
"integrity": "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg==",
"version": "30.0.1",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-30.0.1.tgz",
"integrity": "sha512-HGwoYRVF0QSKJu1ZQX0o5ZrUrrhj0aOOFA8hXrumD7SIzjouevhawbTjmXdwOmURdGluU9DM/XvGm3NyFoiQjw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/pattern": "30.0.1",
"@jest/schemas": "30.0.5",
"@jest/schemas": "30.0.1",
"@types/istanbul-lib-coverage": "^2.0.6",
"@types/istanbul-reports": "^3.0.4",
"@types/node": "*",
@@ -3924,9 +3470,9 @@
}
},
"node_modules/@jest/console/node_modules/@sinclair/typebox": {
"version": "0.34.41",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.41.tgz",
"integrity": "sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g==",
"version": "0.34.37",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.37.tgz",
"integrity": "sha512-2TRuQVgQYfy+EzHRTIvkhv2ADEouJ2xNS/Vq+W5EuuewBdOrvATvljZTxHWZSTYr2sTjTHpGvucaGAt67S2akw==",
"dev": true,
"license": "MIT"
},
@@ -3944,19 +3490,19 @@
}
},
"node_modules/@jest/console/node_modules/jest-message-util": {
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.2.0.tgz",
"integrity": "sha512-y4DKFLZ2y6DxTWD4cDe07RglV88ZiNEdlRfGtqahfbIjfsw1nMCPx49Uev4IA/hWn3sDKyAnSPwoYSsAEdcimw==",
"version": "30.0.2",
"resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.0.2.tgz",
"integrity": "sha512-vXywcxmr0SsKXF/bAD7t7nMamRvPuJkras00gqYeB1V0WllxZrbZ0paRr3XqpFU2sYYjD0qAaG2fRyn/CGZ0aw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/code-frame": "^7.27.1",
"@jest/types": "30.2.0",
"@jest/types": "30.0.1",
"@types/stack-utils": "^2.0.3",
"chalk": "^4.1.2",
"graceful-fs": "^4.2.11",
"micromatch": "^4.0.8",
"pretty-format": "30.2.0",
"pretty-format": "30.0.2",
"slash": "^3.0.0",
"stack-utils": "^2.0.6"
},
@@ -3965,13 +3511,13 @@
}
},
"node_modules/@jest/console/node_modules/jest-util": {
"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==",
"version": "30.0.2",
"resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.0.2.tgz",
"integrity": "sha512-8IyqfKS4MqprBuUpZNlFB5l+WFehc8bfCe1HSZFHzft2mOuND8Cvi9r1musli+u6F3TqanCZ/Ik4H4pXUolZIg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/types": "30.2.0",
"@jest/types": "30.0.1",
"@types/node": "*",
"chalk": "^4.1.2",
"ci-info": "^4.2.0",
@@ -3983,9 +3529,9 @@
}
},
"node_modules/@jest/console/node_modules/picomatch": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz",
"integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
"dev": true,
"license": "MIT",
"engines": {
@@ -3996,13 +3542,13 @@
}
},
"node_modules/@jest/console/node_modules/pretty-format": {
"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==",
"version": "30.0.2",
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.0.2.tgz",
"integrity": "sha512-yC5/EBSOrTtqhCKfLHqoUIAXVRZnukHPwWBJWR7h84Q3Be1DRQZLncwcfLoPA5RPQ65qfiCMqgYwdUuQ//eVpg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/schemas": "30.0.5",
"@jest/schemas": "30.0.1",
"ansi-styles": "^5.2.0",
"react-is": "^18.3.1"
},
@@ -4028,39 +3574,39 @@
}
},
"node_modules/@jest/core": {
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/@jest/core/-/core-30.2.0.tgz",
"integrity": "sha512-03W6IhuhjqTlpzh/ojut/pDB2LPRygyWX8ExpgHtQA8H/3K7+1vKmcINx5UzeOX1se6YEsBsOHQ1CRzf3fOwTQ==",
"version": "30.0.4",
"resolved": "https://registry.npmjs.org/@jest/core/-/core-30.0.4.tgz",
"integrity": "sha512-MWScSO9GuU5/HoWjpXAOBs6F/iobvK1XlioelgOM9St7S0Z5WTI9kjCQLPeo4eQRRYusyLW25/J7J5lbFkrYXw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/console": "30.2.0",
"@jest/console": "30.0.4",
"@jest/pattern": "30.0.1",
"@jest/reporters": "30.2.0",
"@jest/test-result": "30.2.0",
"@jest/transform": "30.2.0",
"@jest/types": "30.2.0",
"@jest/reporters": "30.0.4",
"@jest/test-result": "30.0.4",
"@jest/transform": "30.0.4",
"@jest/types": "30.0.1",
"@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.2.0",
"jest-config": "30.2.0",
"jest-haste-map": "30.2.0",
"jest-message-util": "30.2.0",
"jest-changed-files": "30.0.2",
"jest-config": "30.0.4",
"jest-haste-map": "30.0.2",
"jest-message-util": "30.0.2",
"jest-regex-util": "30.0.1",
"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",
"jest-resolve": "30.0.2",
"jest-resolve-dependencies": "30.0.4",
"jest-runner": "30.0.4",
"jest-runtime": "30.0.4",
"jest-snapshot": "30.0.4",
"jest-util": "30.0.2",
"jest-validate": "30.0.2",
"jest-watcher": "30.0.4",
"micromatch": "^4.0.8",
"pretty-format": "30.2.0",
"pretty-format": "30.0.2",
"slash": "^3.0.0"
},
"engines": {
@@ -4076,22 +3622,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==",
"version": "7.28.0",
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.0.tgz",
"integrity": "sha512-UlLAnTPrFdNGoFtbSXwcGFQBtQZJCNjaN6hQNP3UPvuNXT1i82N26KL3dZeIpNalWywr9IuQuncaAfUaS1g6sQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@ampproject/remapping": "^2.2.0",
"@babel/code-frame": "^7.27.1",
"@babel/generator": "^7.28.3",
"@babel/generator": "^7.28.0",
"@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/helper-module-transforms": "^7.27.3",
"@babel/helpers": "^7.27.6",
"@babel/parser": "^7.28.0",
"@babel/template": "^7.27.2",
"@babel/traverse": "^7.28.4",
"@babel/types": "^7.28.4",
"@jridgewell/remapping": "^2.3.5",
"@babel/traverse": "^7.28.0",
"@babel/types": "^7.28.0",
"convert-source-map": "^2.0.0",
"debug": "^4.1.0",
"gensync": "^1.0.0-beta.2",
@@ -4107,9 +3653,9 @@
}
},
"node_modules/@jest/core/node_modules/@jest/schemas": {
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz",
"integrity": "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==",
"version": "30.0.1",
"resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.1.tgz",
"integrity": "sha512-+g/1TKjFuGrf1Hh0QPCv0gISwBxJ+MQSNXmG9zjHy7BmFhtoJ9fdNhWJp3qUKRi93AOZHXtdxZgJ1vAtz6z65w==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -4120,23 +3666,23 @@
}
},
"node_modules/@jest/core/node_modules/@jest/transform": {
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/@jest/transform/-/transform-30.2.0.tgz",
"integrity": "sha512-XsauDV82o5qXbhalKxD7p4TZYYdwcaEXC77PPD2HixEFF+6YGppjrAAQurTl2ECWcEomHBMMNS9AH3kcCFx8jA==",
"version": "30.0.4",
"resolved": "https://registry.npmjs.org/@jest/transform/-/transform-30.0.4.tgz",
"integrity": "sha512-atvy4hRph/UxdCIBp+UB2jhEA/jJiUeGZ7QPgBi9jUUKNgi3WEoMXGNG7zbbELG2+88PMabUNCDchmqgJy3ELg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/core": "^7.27.4",
"@jest/types": "30.2.0",
"@jest/types": "30.0.1",
"@jridgewell/trace-mapping": "^0.3.25",
"babel-plugin-istanbul": "^7.0.1",
"babel-plugin-istanbul": "^7.0.0",
"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.2.0",
"jest-haste-map": "30.0.2",
"jest-regex-util": "30.0.1",
"jest-util": "30.2.0",
"jest-util": "30.0.2",
"micromatch": "^4.0.8",
"pirates": "^4.0.7",
"slash": "^3.0.0",
@@ -4147,14 +3693,14 @@
}
},
"node_modules/@jest/core/node_modules/@jest/types": {
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-30.2.0.tgz",
"integrity": "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg==",
"version": "30.0.1",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-30.0.1.tgz",
"integrity": "sha512-HGwoYRVF0QSKJu1ZQX0o5ZrUrrhj0aOOFA8hXrumD7SIzjouevhawbTjmXdwOmURdGluU9DM/XvGm3NyFoiQjw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/pattern": "30.0.1",
"@jest/schemas": "30.0.5",
"@jest/schemas": "30.0.1",
"@types/istanbul-lib-coverage": "^2.0.6",
"@types/istanbul-reports": "^3.0.4",
"@types/node": "*",
@@ -4166,9 +3712,9 @@
}
},
"node_modules/@jest/core/node_modules/@sinclair/typebox": {
"version": "0.34.41",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.41.tgz",
"integrity": "sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g==",
"version": "0.34.37",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.37.tgz",
"integrity": "sha512-2TRuQVgQYfy+EzHRTIvkhv2ADEouJ2xNS/Vq+W5EuuewBdOrvATvljZTxHWZSTYr2sTjTHpGvucaGAt67S2akw==",
"dev": true,
"license": "MIT"
},
@@ -4186,14 +3732,11 @@
}
},
"node_modules/@jest/core/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==",
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-7.0.0.tgz",
"integrity": "sha512-C5OzENSx/A+gt7t4VH1I2XsflxyPUmXRFPKBxt33xncdOmq7oROVM3bZv9Ysjjkv8OJYDMa+tKuKMvqU/H3xdw==",
"dev": true,
"license": "BSD-3-Clause",
"workspaces": [
"test/babel-8"
],
"dependencies": {
"@babel/helper-plugin-utils": "^7.0.0",
"@istanbuljs/load-nyc-config": "^1.0.0",
@@ -4236,20 +3779,20 @@
}
},
"node_modules/@jest/core/node_modules/jest-haste-map": {
"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==",
"version": "30.0.2",
"resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-30.0.2.tgz",
"integrity": "sha512-telJBKpNLeCb4MaX+I5k496556Y2FiKR/QLZc0+MGBYl4k3OO0472drlV2LUe7c1Glng5HuAu+5GLYp//GpdOQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/types": "30.2.0",
"@jest/types": "30.0.1",
"@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.2.0",
"jest-worker": "30.2.0",
"jest-util": "30.0.2",
"jest-worker": "30.0.2",
"micromatch": "^4.0.8",
"walker": "^1.0.8"
},
@@ -4261,19 +3804,19 @@
}
},
"node_modules/@jest/core/node_modules/jest-message-util": {
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.2.0.tgz",
"integrity": "sha512-y4DKFLZ2y6DxTWD4cDe07RglV88ZiNEdlRfGtqahfbIjfsw1nMCPx49Uev4IA/hWn3sDKyAnSPwoYSsAEdcimw==",
"version": "30.0.2",
"resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.0.2.tgz",
"integrity": "sha512-vXywcxmr0SsKXF/bAD7t7nMamRvPuJkras00gqYeB1V0WllxZrbZ0paRr3XqpFU2sYYjD0qAaG2fRyn/CGZ0aw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/code-frame": "^7.27.1",
"@jest/types": "30.2.0",
"@jest/types": "30.0.1",
"@types/stack-utils": "^2.0.3",
"chalk": "^4.1.2",
"graceful-fs": "^4.2.11",
"micromatch": "^4.0.8",
"pretty-format": "30.2.0",
"pretty-format": "30.0.2",
"slash": "^3.0.0",
"stack-utils": "^2.0.6"
},
@@ -4292,13 +3835,13 @@
}
},
"node_modules/@jest/core/node_modules/jest-util": {
"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==",
"version": "30.0.2",
"resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.0.2.tgz",
"integrity": "sha512-8IyqfKS4MqprBuUpZNlFB5l+WFehc8bfCe1HSZFHzft2mOuND8Cvi9r1musli+u6F3TqanCZ/Ik4H4pXUolZIg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/types": "30.2.0",
"@jest/types": "30.0.1",
"@types/node": "*",
"chalk": "^4.1.2",
"ci-info": "^4.2.0",
@@ -4310,9 +3853,9 @@
}
},
"node_modules/@jest/core/node_modules/picomatch": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz",
"integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
"dev": true,
"license": "MIT",
"engines": {
@@ -4323,13 +3866,13 @@
}
},
"node_modules/@jest/core/node_modules/pretty-format": {
"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==",
"version": "30.0.2",
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.0.2.tgz",
"integrity": "sha512-yC5/EBSOrTtqhCKfLHqoUIAXVRZnukHPwWBJWR7h84Q3Be1DRQZLncwcfLoPA5RPQ65qfiCMqgYwdUuQ//eVpg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/schemas": "30.0.5",
"@jest/schemas": "30.0.1",
"ansi-styles": "^5.2.0",
"react-is": "^18.3.1"
},
@@ -4392,25 +3935,25 @@
}
},
"node_modules/@jest/environment": {
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/@jest/environment/-/environment-30.2.0.tgz",
"integrity": "sha512-/QPTL7OBJQ5ac09UDRa3EQes4gt1FTEG/8jZ/4v5IVzx+Cv7dLxlVIvfvSVRiiX2drWyXeBjkMSR8hvOWSog5g==",
"version": "30.0.4",
"resolved": "https://registry.npmjs.org/@jest/environment/-/environment-30.0.4.tgz",
"integrity": "sha512-5NT+sr7ZOb8wW7C4r7wOKnRQ8zmRWQT2gW4j73IXAKp5/PX1Z8MCStBLQDYfIG3n1Sw0NRfYGdp0iIPVooBAFQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/fake-timers": "30.2.0",
"@jest/types": "30.2.0",
"@jest/fake-timers": "30.0.4",
"@jest/types": "30.0.1",
"@types/node": "*",
"jest-mock": "30.2.0"
"jest-mock": "30.0.2"
},
"engines": {
"node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
}
},
"node_modules/@jest/environment/node_modules/@jest/schemas": {
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz",
"integrity": "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==",
"version": "30.0.1",
"resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.1.tgz",
"integrity": "sha512-+g/1TKjFuGrf1Hh0QPCv0gISwBxJ+MQSNXmG9zjHy7BmFhtoJ9fdNhWJp3qUKRi93AOZHXtdxZgJ1vAtz6z65w==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -4421,14 +3964,14 @@
}
},
"node_modules/@jest/environment/node_modules/@jest/types": {
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-30.2.0.tgz",
"integrity": "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg==",
"version": "30.0.1",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-30.0.1.tgz",
"integrity": "sha512-HGwoYRVF0QSKJu1ZQX0o5ZrUrrhj0aOOFA8hXrumD7SIzjouevhawbTjmXdwOmURdGluU9DM/XvGm3NyFoiQjw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/pattern": "30.0.1",
"@jest/schemas": "30.0.5",
"@jest/schemas": "30.0.1",
"@types/istanbul-lib-coverage": "^2.0.6",
"@types/istanbul-reports": "^3.0.4",
"@types/node": "*",
@@ -4440,21 +3983,21 @@
}
},
"node_modules/@jest/environment/node_modules/@sinclair/typebox": {
"version": "0.34.41",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.41.tgz",
"integrity": "sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g==",
"version": "0.34.37",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.37.tgz",
"integrity": "sha512-2TRuQVgQYfy+EzHRTIvkhv2ADEouJ2xNS/Vq+W5EuuewBdOrvATvljZTxHWZSTYr2sTjTHpGvucaGAt67S2akw==",
"dev": true,
"license": "MIT"
},
"node_modules/@jest/expect": {
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/@jest/expect/-/expect-30.2.0.tgz",
"integrity": "sha512-V9yxQK5erfzx99Sf+7LbhBwNWEZ9eZay8qQ9+JSC0TrMR1pMDHLMY+BnVPacWU6Jamrh252/IKo4F1Xn/zfiqA==",
"version": "30.0.4",
"resolved": "https://registry.npmjs.org/@jest/expect/-/expect-30.0.4.tgz",
"integrity": "sha512-Z/DL7t67LBHSX4UzDyeYKqOxE/n7lbrrgEwWM3dGiH5Dgn35nk+YtgzKudmfIrBI8DRRrKYY5BCo3317HZV1Fw==",
"dev": true,
"license": "MIT",
"dependencies": {
"expect": "30.2.0",
"jest-snapshot": "30.2.0"
"expect": "30.0.4",
"jest-snapshot": "30.0.4"
},
"engines": {
"node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
@@ -4474,22 +4017,22 @@
}
},
"node_modules/@jest/expect/node_modules/@jest/expect-utils": {
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-30.2.0.tgz",
"integrity": "sha512-1JnRfhqpD8HGpOmQp180Fo9Zt69zNtC+9lR+kT7NVL05tNXIi+QC8Csz7lfidMoVLPD3FnOtcmp0CEFnxExGEA==",
"version": "30.0.4",
"resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-30.0.4.tgz",
"integrity": "sha512-EgXecHDNfANeqOkcak0DxsoVI4qkDUsR7n/Lr2vtmTBjwLPBnnPOF71S11Q8IObWzxm2QgQoY6f9hzrRD3gHRA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/get-type": "30.1.0"
"@jest/get-type": "30.0.1"
},
"engines": {
"node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
}
},
"node_modules/@jest/expect/node_modules/@jest/schemas": {
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz",
"integrity": "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==",
"version": "30.0.1",
"resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.1.tgz",
"integrity": "sha512-+g/1TKjFuGrf1Hh0QPCv0gISwBxJ+MQSNXmG9zjHy7BmFhtoJ9fdNhWJp3qUKRi93AOZHXtdxZgJ1vAtz6z65w==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -4500,14 +4043,14 @@
}
},
"node_modules/@jest/expect/node_modules/@jest/types": {
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-30.2.0.tgz",
"integrity": "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg==",
"version": "30.0.1",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-30.0.1.tgz",
"integrity": "sha512-HGwoYRVF0QSKJu1ZQX0o5ZrUrrhj0aOOFA8hXrumD7SIzjouevhawbTjmXdwOmURdGluU9DM/XvGm3NyFoiQjw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/pattern": "30.0.1",
"@jest/schemas": "30.0.5",
"@jest/schemas": "30.0.1",
"@types/istanbul-lib-coverage": "^2.0.6",
"@types/istanbul-reports": "^3.0.4",
"@types/node": "*",
@@ -4519,9 +4062,9 @@
}
},
"node_modules/@jest/expect/node_modules/@sinclair/typebox": {
"version": "0.34.41",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.41.tgz",
"integrity": "sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g==",
"version": "0.34.37",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.37.tgz",
"integrity": "sha512-2TRuQVgQYfy+EzHRTIvkhv2ADEouJ2xNS/Vq+W5EuuewBdOrvATvljZTxHWZSTYr2sTjTHpGvucaGAt67S2akw==",
"dev": true,
"license": "MIT"
},
@@ -4539,69 +4082,69 @@
}
},
"node_modules/@jest/expect/node_modules/expect": {
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/expect/-/expect-30.2.0.tgz",
"integrity": "sha512-u/feCi0GPsI+988gU2FLcsHyAHTU0MX1Wg68NhAnN7z/+C5wqG+CY8J53N9ioe8RXgaoz0nBR/TYMf3AycUuPw==",
"version": "30.0.4",
"resolved": "https://registry.npmjs.org/expect/-/expect-30.0.4.tgz",
"integrity": "sha512-dDLGjnP2cKbEppxVICxI/Uf4YemmGMPNy0QytCbfafbpYk9AFQsxb8Uyrxii0RPK7FWgLGlSem+07WirwS3cFQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/expect-utils": "30.2.0",
"@jest/get-type": "30.1.0",
"jest-matcher-utils": "30.2.0",
"jest-message-util": "30.2.0",
"jest-mock": "30.2.0",
"jest-util": "30.2.0"
"@jest/expect-utils": "30.0.4",
"@jest/get-type": "30.0.1",
"jest-matcher-utils": "30.0.4",
"jest-message-util": "30.0.2",
"jest-mock": "30.0.2",
"jest-util": "30.0.2"
},
"engines": {
"node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
}
},
"node_modules/@jest/expect/node_modules/jest-diff": {
"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==",
"version": "30.0.4",
"resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-30.0.4.tgz",
"integrity": "sha512-TSjceIf6797jyd+R64NXqicttROD+Qf98fex7CowmlSn7f8+En0da1Dglwr1AXxDtVizoxXYZBlUQwNhoOXkNw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/diff-sequences": "30.0.1",
"@jest/get-type": "30.1.0",
"@jest/get-type": "30.0.1",
"chalk": "^4.1.2",
"pretty-format": "30.2.0"
"pretty-format": "30.0.2"
},
"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.2.0",
"resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-30.2.0.tgz",
"integrity": "sha512-dQ94Nq4dbzmUWkQ0ANAWS9tBRfqCrn0bV9AMYdOi/MHW726xn7eQmMeRTpX2ViC00bpNaWXq+7o4lIQ3AX13Hg==",
"version": "30.0.4",
"resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-30.0.4.tgz",
"integrity": "sha512-ubCewJ54YzeAZ2JeHHGVoU+eDIpQFsfPQs0xURPWoNiO42LGJ+QGgfSf+hFIRplkZDkhH5MOvuxHKXRTUU3dUQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/get-type": "30.1.0",
"@jest/get-type": "30.0.1",
"chalk": "^4.1.2",
"jest-diff": "30.2.0",
"pretty-format": "30.2.0"
"jest-diff": "30.0.4",
"pretty-format": "30.0.2"
},
"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.2.0",
"resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.2.0.tgz",
"integrity": "sha512-y4DKFLZ2y6DxTWD4cDe07RglV88ZiNEdlRfGtqahfbIjfsw1nMCPx49Uev4IA/hWn3sDKyAnSPwoYSsAEdcimw==",
"version": "30.0.2",
"resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.0.2.tgz",
"integrity": "sha512-vXywcxmr0SsKXF/bAD7t7nMamRvPuJkras00gqYeB1V0WllxZrbZ0paRr3XqpFU2sYYjD0qAaG2fRyn/CGZ0aw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/code-frame": "^7.27.1",
"@jest/types": "30.2.0",
"@jest/types": "30.0.1",
"@types/stack-utils": "^2.0.3",
"chalk": "^4.1.2",
"graceful-fs": "^4.2.11",
"micromatch": "^4.0.8",
"pretty-format": "30.2.0",
"pretty-format": "30.0.2",
"slash": "^3.0.0",
"stack-utils": "^2.0.6"
},
@@ -4610,13 +4153,13 @@
}
},
"node_modules/@jest/expect/node_modules/jest-util": {
"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==",
"version": "30.0.2",
"resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.0.2.tgz",
"integrity": "sha512-8IyqfKS4MqprBuUpZNlFB5l+WFehc8bfCe1HSZFHzft2mOuND8Cvi9r1musli+u6F3TqanCZ/Ik4H4pXUolZIg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/types": "30.2.0",
"@jest/types": "30.0.1",
"@types/node": "*",
"chalk": "^4.1.2",
"ci-info": "^4.2.0",
@@ -4628,9 +4171,9 @@
}
},
"node_modules/@jest/expect/node_modules/picomatch": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz",
"integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
"dev": true,
"license": "MIT",
"engines": {
@@ -4641,13 +4184,13 @@
}
},
"node_modules/@jest/expect/node_modules/pretty-format": {
"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==",
"version": "30.0.2",
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.0.2.tgz",
"integrity": "sha512-yC5/EBSOrTtqhCKfLHqoUIAXVRZnukHPwWBJWR7h84Q3Be1DRQZLncwcfLoPA5RPQ65qfiCMqgYwdUuQ//eVpg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/schemas": "30.0.5",
"@jest/schemas": "30.0.1",
"ansi-styles": "^5.2.0",
"react-is": "^18.3.1"
},
@@ -4673,27 +4216,27 @@
}
},
"node_modules/@jest/fake-timers": {
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-30.2.0.tgz",
"integrity": "sha512-HI3tRLjRxAbBy0VO8dqqm7Hb2mIa8d5bg/NJkyQcOk7V118ObQML8RC5luTF/Zsg4474a+gDvhce7eTnP4GhYw==",
"version": "30.0.4",
"resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-30.0.4.tgz",
"integrity": "sha512-qZ7nxOcL5+gwBO6LErvwVy5k06VsX/deqo2XnVUSTV0TNC9lrg8FC3dARbi+5lmrr5VyX5drragK+xLcOjvjYw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/types": "30.2.0",
"@jest/types": "30.0.1",
"@sinonjs/fake-timers": "^13.0.0",
"@types/node": "*",
"jest-message-util": "30.2.0",
"jest-mock": "30.2.0",
"jest-util": "30.2.0"
"jest-message-util": "30.0.2",
"jest-mock": "30.0.2",
"jest-util": "30.0.2"
},
"engines": {
"node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
}
},
"node_modules/@jest/fake-timers/node_modules/@jest/schemas": {
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz",
"integrity": "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==",
"version": "30.0.1",
"resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.1.tgz",
"integrity": "sha512-+g/1TKjFuGrf1Hh0QPCv0gISwBxJ+MQSNXmG9zjHy7BmFhtoJ9fdNhWJp3qUKRi93AOZHXtdxZgJ1vAtz6z65w==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -4704,14 +4247,14 @@
}
},
"node_modules/@jest/fake-timers/node_modules/@jest/types": {
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-30.2.0.tgz",
"integrity": "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg==",
"version": "30.0.1",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-30.0.1.tgz",
"integrity": "sha512-HGwoYRVF0QSKJu1ZQX0o5ZrUrrhj0aOOFA8hXrumD7SIzjouevhawbTjmXdwOmURdGluU9DM/XvGm3NyFoiQjw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/pattern": "30.0.1",
"@jest/schemas": "30.0.5",
"@jest/schemas": "30.0.1",
"@types/istanbul-lib-coverage": "^2.0.6",
"@types/istanbul-reports": "^3.0.4",
"@types/node": "*",
@@ -4723,9 +4266,9 @@
}
},
"node_modules/@jest/fake-timers/node_modules/@sinclair/typebox": {
"version": "0.34.41",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.41.tgz",
"integrity": "sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g==",
"version": "0.34.37",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.37.tgz",
"integrity": "sha512-2TRuQVgQYfy+EzHRTIvkhv2ADEouJ2xNS/Vq+W5EuuewBdOrvATvljZTxHWZSTYr2sTjTHpGvucaGAt67S2akw==",
"dev": true,
"license": "MIT"
},
@@ -4743,19 +4286,19 @@
}
},
"node_modules/@jest/fake-timers/node_modules/jest-message-util": {
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.2.0.tgz",
"integrity": "sha512-y4DKFLZ2y6DxTWD4cDe07RglV88ZiNEdlRfGtqahfbIjfsw1nMCPx49Uev4IA/hWn3sDKyAnSPwoYSsAEdcimw==",
"version": "30.0.2",
"resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.0.2.tgz",
"integrity": "sha512-vXywcxmr0SsKXF/bAD7t7nMamRvPuJkras00gqYeB1V0WllxZrbZ0paRr3XqpFU2sYYjD0qAaG2fRyn/CGZ0aw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/code-frame": "^7.27.1",
"@jest/types": "30.2.0",
"@jest/types": "30.0.1",
"@types/stack-utils": "^2.0.3",
"chalk": "^4.1.2",
"graceful-fs": "^4.2.11",
"micromatch": "^4.0.8",
"pretty-format": "30.2.0",
"pretty-format": "30.0.2",
"slash": "^3.0.0",
"stack-utils": "^2.0.6"
},
@@ -4764,13 +4307,13 @@
}
},
"node_modules/@jest/fake-timers/node_modules/jest-util": {
"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==",
"version": "30.0.2",
"resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.0.2.tgz",
"integrity": "sha512-8IyqfKS4MqprBuUpZNlFB5l+WFehc8bfCe1HSZFHzft2mOuND8Cvi9r1musli+u6F3TqanCZ/Ik4H4pXUolZIg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/types": "30.2.0",
"@jest/types": "30.0.1",
"@types/node": "*",
"chalk": "^4.1.2",
"ci-info": "^4.2.0",
@@ -4782,9 +4325,9 @@
}
},
"node_modules/@jest/fake-timers/node_modules/picomatch": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz",
"integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
"dev": true,
"license": "MIT",
"engines": {
@@ -4795,13 +4338,13 @@
}
},
"node_modules/@jest/fake-timers/node_modules/pretty-format": {
"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==",
"version": "30.0.2",
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.0.2.tgz",
"integrity": "sha512-yC5/EBSOrTtqhCKfLHqoUIAXVRZnukHPwWBJWR7h84Q3Be1DRQZLncwcfLoPA5RPQ65qfiCMqgYwdUuQ//eVpg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/schemas": "30.0.5",
"@jest/schemas": "30.0.1",
"ansi-styles": "^5.2.0",
"react-is": "^18.3.1"
},
@@ -4827,9 +4370,9 @@
}
},
"node_modules/@jest/get-type": {
"version": "30.1.0",
"resolved": "https://registry.npmjs.org/@jest/get-type/-/get-type-30.1.0.tgz",
"integrity": "sha512-eMbZE2hUnx1WV0pmURZY9XoXPkUYjpc55mb0CrhtdWLtzMQPFvu/rZkTLZFTsdaVQa+Tr4eWAteqcUzoawq/uA==",
"version": "30.0.1",
"resolved": "https://registry.npmjs.org/@jest/get-type/-/get-type-30.0.1.tgz",
"integrity": "sha512-AyYdemXCptSRFirI5EPazNxyPwAL0jXt3zceFjaj8NFiKP9pOi0bfXonf6qkf82z2t3QWPeLCWWw4stPBzctLw==",
"dev": true,
"license": "MIT",
"engines": {
@@ -4837,25 +4380,25 @@
}
},
"node_modules/@jest/globals": {
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/@jest/globals/-/globals-30.2.0.tgz",
"integrity": "sha512-b63wmnKPaK+6ZZfpYhz9K61oybvbI1aMcIs80++JI1O1rR1vaxHUCNqo3ITu6NU0d4V34yZFoHMn/uoKr/Rwfw==",
"version": "30.0.4",
"resolved": "https://registry.npmjs.org/@jest/globals/-/globals-30.0.4.tgz",
"integrity": "sha512-avyZuxEHF2EUhFF6NEWVdxkRRV6iXXcIES66DLhuLlU7lXhtFG/ySq/a8SRZmEJSsLkNAFX6z6mm8KWyXe9OEA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/environment": "30.2.0",
"@jest/expect": "30.2.0",
"@jest/types": "30.2.0",
"jest-mock": "30.2.0"
"@jest/environment": "30.0.4",
"@jest/expect": "30.0.4",
"@jest/types": "30.0.1",
"jest-mock": "30.0.2"
},
"engines": {
"node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
}
},
"node_modules/@jest/globals/node_modules/@jest/schemas": {
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz",
"integrity": "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==",
"version": "30.0.1",
"resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.1.tgz",
"integrity": "sha512-+g/1TKjFuGrf1Hh0QPCv0gISwBxJ+MQSNXmG9zjHy7BmFhtoJ9fdNhWJp3qUKRi93AOZHXtdxZgJ1vAtz6z65w==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -4866,14 +4409,14 @@
}
},
"node_modules/@jest/globals/node_modules/@jest/types": {
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-30.2.0.tgz",
"integrity": "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg==",
"version": "30.0.1",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-30.0.1.tgz",
"integrity": "sha512-HGwoYRVF0QSKJu1ZQX0o5ZrUrrhj0aOOFA8hXrumD7SIzjouevhawbTjmXdwOmURdGluU9DM/XvGm3NyFoiQjw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/pattern": "30.0.1",
"@jest/schemas": "30.0.5",
"@jest/schemas": "30.0.1",
"@types/istanbul-lib-coverage": "^2.0.6",
"@types/istanbul-reports": "^3.0.4",
"@types/node": "*",
@@ -4885,9 +4428,9 @@
}
},
"node_modules/@jest/globals/node_modules/@sinclair/typebox": {
"version": "0.34.41",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.41.tgz",
"integrity": "sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g==",
"version": "0.34.37",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.37.tgz",
"integrity": "sha512-2TRuQVgQYfy+EzHRTIvkhv2ADEouJ2xNS/Vq+W5EuuewBdOrvATvljZTxHWZSTYr2sTjTHpGvucaGAt67S2akw==",
"dev": true,
"license": "MIT"
},
@@ -4916,17 +4459,17 @@
}
},
"node_modules/@jest/reporters": {
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-30.2.0.tgz",
"integrity": "sha512-DRyW6baWPqKMa9CzeiBjHwjd8XeAyco2Vt8XbcLFjiwCOEKOvy82GJ8QQnJE9ofsxCMPjH4MfH8fCWIHHDKpAQ==",
"version": "30.0.4",
"resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-30.0.4.tgz",
"integrity": "sha512-6ycNmP0JSJEEys1FbIzHtjl9BP0tOZ/KN6iMeAKrdvGmUsa1qfRdlQRUDKJ4P84hJ3xHw1yTqJt4fvPNHhyE+g==",
"dev": true,
"license": "MIT",
"dependencies": {
"@bcoe/v8-coverage": "^0.2.3",
"@jest/console": "30.2.0",
"@jest/test-result": "30.2.0",
"@jest/transform": "30.2.0",
"@jest/types": "30.2.0",
"@jest/console": "30.0.4",
"@jest/test-result": "30.0.4",
"@jest/transform": "30.0.4",
"@jest/types": "30.0.1",
"@jridgewell/trace-mapping": "^0.3.25",
"@types/node": "*",
"chalk": "^4.1.2",
@@ -4939,9 +4482,9 @@
"istanbul-lib-report": "^3.0.0",
"istanbul-lib-source-maps": "^5.0.0",
"istanbul-reports": "^3.1.3",
"jest-message-util": "30.2.0",
"jest-util": "30.2.0",
"jest-worker": "30.2.0",
"jest-message-util": "30.0.2",
"jest-util": "30.0.2",
"jest-worker": "30.0.2",
"slash": "^3.0.0",
"string-length": "^4.0.2",
"v8-to-istanbul": "^9.0.1"
@@ -4959,22 +4502,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==",
"version": "7.28.0",
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.0.tgz",
"integrity": "sha512-UlLAnTPrFdNGoFtbSXwcGFQBtQZJCNjaN6hQNP3UPvuNXT1i82N26KL3dZeIpNalWywr9IuQuncaAfUaS1g6sQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@ampproject/remapping": "^2.2.0",
"@babel/code-frame": "^7.27.1",
"@babel/generator": "^7.28.3",
"@babel/generator": "^7.28.0",
"@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/helper-module-transforms": "^7.27.3",
"@babel/helpers": "^7.27.6",
"@babel/parser": "^7.28.0",
"@babel/template": "^7.27.2",
"@babel/traverse": "^7.28.4",
"@babel/types": "^7.28.4",
"@jridgewell/remapping": "^2.3.5",
"@babel/traverse": "^7.28.0",
"@babel/types": "^7.28.0",
"convert-source-map": "^2.0.0",
"debug": "^4.1.0",
"gensync": "^1.0.0-beta.2",
@@ -4990,9 +4533,9 @@
}
},
"node_modules/@jest/reporters/node_modules/@jest/schemas": {
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz",
"integrity": "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==",
"version": "30.0.1",
"resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.1.tgz",
"integrity": "sha512-+g/1TKjFuGrf1Hh0QPCv0gISwBxJ+MQSNXmG9zjHy7BmFhtoJ9fdNhWJp3qUKRi93AOZHXtdxZgJ1vAtz6z65w==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -5003,23 +4546,23 @@
}
},
"node_modules/@jest/reporters/node_modules/@jest/transform": {
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/@jest/transform/-/transform-30.2.0.tgz",
"integrity": "sha512-XsauDV82o5qXbhalKxD7p4TZYYdwcaEXC77PPD2HixEFF+6YGppjrAAQurTl2ECWcEomHBMMNS9AH3kcCFx8jA==",
"version": "30.0.4",
"resolved": "https://registry.npmjs.org/@jest/transform/-/transform-30.0.4.tgz",
"integrity": "sha512-atvy4hRph/UxdCIBp+UB2jhEA/jJiUeGZ7QPgBi9jUUKNgi3WEoMXGNG7zbbELG2+88PMabUNCDchmqgJy3ELg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/core": "^7.27.4",
"@jest/types": "30.2.0",
"@jest/types": "30.0.1",
"@jridgewell/trace-mapping": "^0.3.25",
"babel-plugin-istanbul": "^7.0.1",
"babel-plugin-istanbul": "^7.0.0",
"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.2.0",
"jest-haste-map": "30.0.2",
"jest-regex-util": "30.0.1",
"jest-util": "30.2.0",
"jest-util": "30.0.2",
"micromatch": "^4.0.8",
"pirates": "^4.0.7",
"slash": "^3.0.0",
@@ -5030,14 +4573,14 @@
}
},
"node_modules/@jest/reporters/node_modules/@jest/types": {
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-30.2.0.tgz",
"integrity": "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg==",
"version": "30.0.1",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-30.0.1.tgz",
"integrity": "sha512-HGwoYRVF0QSKJu1ZQX0o5ZrUrrhj0aOOFA8hXrumD7SIzjouevhawbTjmXdwOmURdGluU9DM/XvGm3NyFoiQjw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/pattern": "30.0.1",
"@jest/schemas": "30.0.5",
"@jest/schemas": "30.0.1",
"@types/istanbul-lib-coverage": "^2.0.6",
"@types/istanbul-reports": "^3.0.4",
"@types/node": "*",
@@ -5049,9 +4592,9 @@
}
},
"node_modules/@jest/reporters/node_modules/@sinclair/typebox": {
"version": "0.34.41",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.41.tgz",
"integrity": "sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g==",
"version": "0.34.37",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.37.tgz",
"integrity": "sha512-2TRuQVgQYfy+EzHRTIvkhv2ADEouJ2xNS/Vq+W5EuuewBdOrvATvljZTxHWZSTYr2sTjTHpGvucaGAt67S2akw==",
"dev": true,
"license": "MIT"
},
@@ -5069,14 +4612,11 @@
}
},
"node_modules/@jest/reporters/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==",
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-7.0.0.tgz",
"integrity": "sha512-C5OzENSx/A+gt7t4VH1I2XsflxyPUmXRFPKBxt33xncdOmq7oROVM3bZv9Ysjjkv8OJYDMa+tKuKMvqU/H3xdw==",
"dev": true,
"license": "BSD-3-Clause",
"workspaces": [
"test/babel-8"
],
"dependencies": {
"@babel/helper-plugin-utils": "^7.0.0",
"@istanbuljs/load-nyc-config": "^1.0.0",
@@ -5150,20 +4690,20 @@
}
},
"node_modules/@jest/reporters/node_modules/jest-haste-map": {
"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==",
"version": "30.0.2",
"resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-30.0.2.tgz",
"integrity": "sha512-telJBKpNLeCb4MaX+I5k496556Y2FiKR/QLZc0+MGBYl4k3OO0472drlV2LUe7c1Glng5HuAu+5GLYp//GpdOQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/types": "30.2.0",
"@jest/types": "30.0.1",
"@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.2.0",
"jest-worker": "30.2.0",
"jest-util": "30.0.2",
"jest-worker": "30.0.2",
"micromatch": "^4.0.8",
"walker": "^1.0.8"
},
@@ -5175,19 +4715,19 @@
}
},
"node_modules/@jest/reporters/node_modules/jest-message-util": {
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.2.0.tgz",
"integrity": "sha512-y4DKFLZ2y6DxTWD4cDe07RglV88ZiNEdlRfGtqahfbIjfsw1nMCPx49Uev4IA/hWn3sDKyAnSPwoYSsAEdcimw==",
"version": "30.0.2",
"resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.0.2.tgz",
"integrity": "sha512-vXywcxmr0SsKXF/bAD7t7nMamRvPuJkras00gqYeB1V0WllxZrbZ0paRr3XqpFU2sYYjD0qAaG2fRyn/CGZ0aw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/code-frame": "^7.27.1",
"@jest/types": "30.2.0",
"@jest/types": "30.0.1",
"@types/stack-utils": "^2.0.3",
"chalk": "^4.1.2",
"graceful-fs": "^4.2.11",
"micromatch": "^4.0.8",
"pretty-format": "30.2.0",
"pretty-format": "30.0.2",
"slash": "^3.0.0",
"stack-utils": "^2.0.6"
},
@@ -5206,13 +4746,13 @@
}
},
"node_modules/@jest/reporters/node_modules/jest-util": {
"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==",
"version": "30.0.2",
"resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.0.2.tgz",
"integrity": "sha512-8IyqfKS4MqprBuUpZNlFB5l+WFehc8bfCe1HSZFHzft2mOuND8Cvi9r1musli+u6F3TqanCZ/Ik4H4pXUolZIg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/types": "30.2.0",
"@jest/types": "30.0.1",
"@types/node": "*",
"chalk": "^4.1.2",
"ci-info": "^4.2.0",
@@ -5240,9 +4780,9 @@
}
},
"node_modules/@jest/reporters/node_modules/picomatch": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz",
"integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
"dev": true,
"license": "MIT",
"engines": {
@@ -5253,13 +4793,13 @@
}
},
"node_modules/@jest/reporters/node_modules/pretty-format": {
"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==",
"version": "30.0.2",
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.0.2.tgz",
"integrity": "sha512-yC5/EBSOrTtqhCKfLHqoUIAXVRZnukHPwWBJWR7h84Q3Be1DRQZLncwcfLoPA5RPQ65qfiCMqgYwdUuQ//eVpg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/schemas": "30.0.5",
"@jest/schemas": "30.0.1",
"ansi-styles": "^5.2.0",
"react-is": "^18.3.1"
},
@@ -5325,13 +4865,13 @@
}
},
"node_modules/@jest/snapshot-utils": {
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/@jest/snapshot-utils/-/snapshot-utils-30.2.0.tgz",
"integrity": "sha512-0aVxM3RH6DaiLcjj/b0KrIBZhSX1373Xci4l3cW5xiUWPctZ59zQ7jj4rqcJQ/Z8JuN/4wX3FpJSa3RssVvCug==",
"version": "30.0.4",
"resolved": "https://registry.npmjs.org/@jest/snapshot-utils/-/snapshot-utils-30.0.4.tgz",
"integrity": "sha512-BEpX8M/Y5lG7MI3fmiO+xCnacOrVsnbqVrcDZIT8aSGkKV1w2WwvRQxSWw5SIS8ozg7+h8tSj5EO1Riqqxcdag==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/types": "30.2.0",
"@jest/types": "30.0.1",
"chalk": "^4.1.2",
"graceful-fs": "^4.2.11",
"natural-compare": "^1.4.0"
@@ -5341,9 +4881,9 @@
}
},
"node_modules/@jest/snapshot-utils/node_modules/@jest/schemas": {
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz",
"integrity": "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==",
"version": "30.0.1",
"resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.1.tgz",
"integrity": "sha512-+g/1TKjFuGrf1Hh0QPCv0gISwBxJ+MQSNXmG9zjHy7BmFhtoJ9fdNhWJp3qUKRi93AOZHXtdxZgJ1vAtz6z65w==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -5354,14 +4894,14 @@
}
},
"node_modules/@jest/snapshot-utils/node_modules/@jest/types": {
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-30.2.0.tgz",
"integrity": "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg==",
"version": "30.0.1",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-30.0.1.tgz",
"integrity": "sha512-HGwoYRVF0QSKJu1ZQX0o5ZrUrrhj0aOOFA8hXrumD7SIzjouevhawbTjmXdwOmURdGluU9DM/XvGm3NyFoiQjw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/pattern": "30.0.1",
"@jest/schemas": "30.0.5",
"@jest/schemas": "30.0.1",
"@types/istanbul-lib-coverage": "^2.0.6",
"@types/istanbul-reports": "^3.0.4",
"@types/node": "*",
@@ -5373,9 +4913,9 @@
}
},
"node_modules/@jest/snapshot-utils/node_modules/@sinclair/typebox": {
"version": "0.34.41",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.41.tgz",
"integrity": "sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g==",
"version": "0.34.37",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.37.tgz",
"integrity": "sha512-2TRuQVgQYfy+EzHRTIvkhv2ADEouJ2xNS/Vq+W5EuuewBdOrvATvljZTxHWZSTYr2sTjTHpGvucaGAt67S2akw==",
"dev": true,
"license": "MIT"
},
@@ -5395,14 +4935,14 @@
}
},
"node_modules/@jest/test-result": {
"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==",
"version": "30.0.4",
"resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-30.0.4.tgz",
"integrity": "sha512-Mfpv8kjyKTHqsuu9YugB6z1gcdB3TSSOaKlehtVaiNlClMkEHY+5ZqCY2CrEE3ntpBMlstX/ShDAf84HKWsyIw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/console": "30.2.0",
"@jest/types": "30.2.0",
"@jest/console": "30.0.4",
"@jest/types": "30.0.1",
"@types/istanbul-lib-coverage": "^2.0.6",
"collect-v8-coverage": "^1.0.2"
},
@@ -5411,9 +4951,9 @@
}
},
"node_modules/@jest/test-result/node_modules/@jest/schemas": {
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz",
"integrity": "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==",
"version": "30.0.1",
"resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.1.tgz",
"integrity": "sha512-+g/1TKjFuGrf1Hh0QPCv0gISwBxJ+MQSNXmG9zjHy7BmFhtoJ9fdNhWJp3qUKRi93AOZHXtdxZgJ1vAtz6z65w==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -5424,14 +4964,14 @@
}
},
"node_modules/@jest/test-result/node_modules/@jest/types": {
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-30.2.0.tgz",
"integrity": "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg==",
"version": "30.0.1",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-30.0.1.tgz",
"integrity": "sha512-HGwoYRVF0QSKJu1ZQX0o5ZrUrrhj0aOOFA8hXrumD7SIzjouevhawbTjmXdwOmURdGluU9DM/XvGm3NyFoiQjw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/pattern": "30.0.1",
"@jest/schemas": "30.0.5",
"@jest/schemas": "30.0.1",
"@types/istanbul-lib-coverage": "^2.0.6",
"@types/istanbul-reports": "^3.0.4",
"@types/node": "*",
@@ -5443,22 +4983,22 @@
}
},
"node_modules/@jest/test-result/node_modules/@sinclair/typebox": {
"version": "0.34.41",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.41.tgz",
"integrity": "sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g==",
"version": "0.34.37",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.37.tgz",
"integrity": "sha512-2TRuQVgQYfy+EzHRTIvkhv2ADEouJ2xNS/Vq+W5EuuewBdOrvATvljZTxHWZSTYr2sTjTHpGvucaGAt67S2akw==",
"dev": true,
"license": "MIT"
},
"node_modules/@jest/test-sequencer": {
"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==",
"version": "30.0.4",
"resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-30.0.4.tgz",
"integrity": "sha512-bj6ePmqi4uxAE8EHE0Slmk5uBYd9Vd/PcVt06CsBxzH4bbA8nGsI1YbXl/NH+eii4XRtyrRx+Cikub0x8H4vDg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/test-result": "30.2.0",
"@jest/test-result": "30.0.4",
"graceful-fs": "^4.2.11",
"jest-haste-map": "30.2.0",
"jest-haste-map": "30.0.2",
"slash": "^3.0.0"
},
"engines": {
@@ -5466,9 +5006,9 @@
}
},
"node_modules/@jest/test-sequencer/node_modules/@jest/schemas": {
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz",
"integrity": "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==",
"version": "30.0.1",
"resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.1.tgz",
"integrity": "sha512-+g/1TKjFuGrf1Hh0QPCv0gISwBxJ+MQSNXmG9zjHy7BmFhtoJ9fdNhWJp3qUKRi93AOZHXtdxZgJ1vAtz6z65w==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -5479,14 +5019,14 @@
}
},
"node_modules/@jest/test-sequencer/node_modules/@jest/types": {
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-30.2.0.tgz",
"integrity": "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg==",
"version": "30.0.1",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-30.0.1.tgz",
"integrity": "sha512-HGwoYRVF0QSKJu1ZQX0o5ZrUrrhj0aOOFA8hXrumD7SIzjouevhawbTjmXdwOmURdGluU9DM/XvGm3NyFoiQjw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/pattern": "30.0.1",
"@jest/schemas": "30.0.5",
"@jest/schemas": "30.0.1",
"@types/istanbul-lib-coverage": "^2.0.6",
"@types/istanbul-reports": "^3.0.4",
"@types/node": "*",
@@ -5498,27 +5038,27 @@
}
},
"node_modules/@jest/test-sequencer/node_modules/@sinclair/typebox": {
"version": "0.34.41",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.41.tgz",
"integrity": "sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g==",
"version": "0.34.37",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.37.tgz",
"integrity": "sha512-2TRuQVgQYfy+EzHRTIvkhv2ADEouJ2xNS/Vq+W5EuuewBdOrvATvljZTxHWZSTYr2sTjTHpGvucaGAt67S2akw==",
"dev": true,
"license": "MIT"
},
"node_modules/@jest/test-sequencer/node_modules/jest-haste-map": {
"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==",
"version": "30.0.2",
"resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-30.0.2.tgz",
"integrity": "sha512-telJBKpNLeCb4MaX+I5k496556Y2FiKR/QLZc0+MGBYl4k3OO0472drlV2LUe7c1Glng5HuAu+5GLYp//GpdOQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/types": "30.2.0",
"@jest/types": "30.0.1",
"@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.2.0",
"jest-worker": "30.2.0",
"jest-util": "30.0.2",
"jest-worker": "30.0.2",
"micromatch": "^4.0.8",
"walker": "^1.0.8"
},
@@ -5540,13 +5080,13 @@
}
},
"node_modules/@jest/test-sequencer/node_modules/jest-util": {
"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==",
"version": "30.0.2",
"resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.0.2.tgz",
"integrity": "sha512-8IyqfKS4MqprBuUpZNlFB5l+WFehc8bfCe1HSZFHzft2mOuND8Cvi9r1musli+u6F3TqanCZ/Ik4H4pXUolZIg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/types": "30.2.0",
"@jest/types": "30.0.1",
"@types/node": "*",
"chalk": "^4.1.2",
"ci-info": "^4.2.0",
@@ -5558,9 +5098,9 @@
}
},
"node_modules/@jest/test-sequencer/node_modules/picomatch": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz",
"integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
"dev": true,
"license": "MIT",
"engines": {
@@ -5636,9 +5176,9 @@
}
},
"node_modules/@jridgewell/gen-mapping": {
"version": "0.3.13",
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz",
"integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==",
"version": "0.3.12",
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.12.tgz",
"integrity": "sha512-OuLGC46TjB5BbN1dH8JULVVZY4WTdkF7tV9Ys6wLL1rubZnCMstOhNHueU5bLCrnRuDhKPDM4g6sw4Bel5Gzqg==",
"devOptional": true,
"license": "MIT",
"dependencies": {
@@ -5646,17 +5186,6 @@
"@jridgewell/trace-mapping": "^0.3.24"
}
},
"node_modules/@jridgewell/remapping": {
"version": "2.3.5",
"resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz",
"integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==",
"devOptional": true,
"license": "MIT",
"dependencies": {
"@jridgewell/gen-mapping": "^0.3.5",
"@jridgewell/trace-mapping": "^0.3.24"
}
},
"node_modules/@jridgewell/resolve-uri": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
@@ -5668,9 +5197,9 @@
}
},
"node_modules/@jridgewell/source-map": {
"version": "0.3.11",
"resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.11.tgz",
"integrity": "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==",
"version": "0.3.10",
"resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.10.tgz",
"integrity": "sha512-0pPkgz9dY+bijgistcTTJ5mR+ocqRXLuhXHYdzoMmmoJ2C9S46RCm2GMUbatPEUK9Yjy26IrAy8D/M00lLkv+Q==",
"devOptional": true,
"license": "MIT",
"dependencies": {
@@ -5679,16 +5208,16 @@
}
},
"node_modules/@jridgewell/sourcemap-codec": {
"version": "1.5.5",
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
"integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
"version": "1.5.4",
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.4.tgz",
"integrity": "sha512-VT2+G1VQs/9oz078bLrYbecdZKs912zQlkelYpuf+SXF+QvZDYJlbx/LSx+meSAwdDFnF8FVXW92AVjjkVmgFw==",
"devOptional": true,
"license": "MIT"
},
"node_modules/@jridgewell/trace-mapping": {
"version": "0.3.31",
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz",
"integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==",
"version": "0.3.29",
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.29.tgz",
"integrity": "sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ==",
"devOptional": true,
"license": "MIT",
"dependencies": {
@@ -5712,71 +5241,16 @@
"tslib": "2"
}
},
"node_modules/@jsonjoy.com/buffers": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@jsonjoy.com/buffers/-/buffers-1.0.0.tgz",
"integrity": "sha512-NDigYR3PHqCnQLXYyoLbnEdzMMvzeiCWo1KOut7Q0CoIqg9tUAPKJ1iq/2nFhc5kZtexzutNY0LFjdwWL3Dw3Q==",
"license": "Apache-2.0",
"engines": {
"node": ">=10.0"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/streamich"
},
"peerDependencies": {
"tslib": "2"
}
},
"node_modules/@jsonjoy.com/codegen": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@jsonjoy.com/codegen/-/codegen-1.0.0.tgz",
"integrity": "sha512-E8Oy+08cmCf0EK/NMxpaJZmOxPqM+6iSe2S4nlSBrPZOORoDJILxtbSUEDKQyTamm/BVAhIGllOBNU79/dwf0g==",
"license": "Apache-2.0",
"engines": {
"node": ">=10.0"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/streamich"
},
"peerDependencies": {
"tslib": "2"
}
},
"node_modules/@jsonjoy.com/json-pack": {
"version": "1.11.0",
"resolved": "https://registry.npmjs.org/@jsonjoy.com/json-pack/-/json-pack-1.11.0.tgz",
"integrity": "sha512-nLqSTAYwpk+5ZQIoVp7pfd/oSKNWlEdvTq2LzVA4r2wtWZg6v+5u0VgBOaDJuUfNOuw/4Ysq6glN5QKSrOCgrA==",
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@jsonjoy.com/json-pack/-/json-pack-1.2.0.tgz",
"integrity": "sha512-io1zEbbYcElht3tdlqEOFxZ0dMTYrHz9iMf0gqn1pPjZFTCgM5R4R5IMA20Chb2UPYYsxjzs8CgZ7Nb5n2K2rA==",
"license": "Apache-2.0",
"dependencies": {
"@jsonjoy.com/base64": "^1.1.2",
"@jsonjoy.com/buffers": "^1.0.0",
"@jsonjoy.com/codegen": "^1.0.0",
"@jsonjoy.com/json-pointer": "^1.0.1",
"@jsonjoy.com/util": "^1.9.0",
"@jsonjoy.com/base64": "^1.1.1",
"@jsonjoy.com/util": "^1.1.2",
"hyperdyperid": "^1.2.0",
"thingies": "^2.5.0"
},
"engines": {
"node": ">=10.0"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/streamich"
},
"peerDependencies": {
"tslib": "2"
}
},
"node_modules/@jsonjoy.com/json-pointer": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@jsonjoy.com/json-pointer/-/json-pointer-1.0.2.tgz",
"integrity": "sha512-Fsn6wM2zlDzY1U+v4Nc8bo3bVqgfNTGcn6dMgs6FjrEnt4ZCe60o6ByKRjOGlI2gow0aE/Q41QOigdTqkyK5fg==",
"license": "Apache-2.0",
"dependencies": {
"@jsonjoy.com/codegen": "^1.0.0",
"@jsonjoy.com/util": "^1.9.0"
"thingies": "^1.20.0"
},
"engines": {
"node": ">=10.0"
@@ -5790,14 +5264,10 @@
}
},
"node_modules/@jsonjoy.com/util": {
"version": "1.9.0",
"resolved": "https://registry.npmjs.org/@jsonjoy.com/util/-/util-1.9.0.tgz",
"integrity": "sha512-pLuQo+VPRnN8hfPqUTLTHk126wuYdXVxE6aDmjSeV4NCAgyxWbiOIeNJVtID3h1Vzpoi9m4jXezf73I6LgabgQ==",
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/@jsonjoy.com/util/-/util-1.6.0.tgz",
"integrity": "sha512-sw/RMbehRhN68WRtcKCpQOPfnH6lLP4GJfqzi3iYej8tnzpZUDr6UkZYJjcjjC0FWEJOJbyM3PTIwxucUmDG2A==",
"license": "Apache-2.0",
"dependencies": {
"@jsonjoy.com/buffers": "^1.0.0",
"@jsonjoy.com/codegen": "^1.0.0"
},
"engines": {
"node": ">=10.0"
},
@@ -5817,16 +5287,16 @@
"license": "MIT"
},
"node_modules/@napi-rs/wasm-runtime": {
"version": "0.2.12",
"resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.12.tgz",
"integrity": "sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==",
"version": "0.2.11",
"resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.11.tgz",
"integrity": "sha512-9DPkXtvHydrcOsopiYpUgPHpmj0HWZKMUnL2dZqpvC42lsratuBG06V5ipyno0fUek5VlFsNQ+AcFATSrJXgMA==",
"dev": true,
"license": "MIT",
"optional": true,
"dependencies": {
"@emnapi/core": "^1.4.3",
"@emnapi/runtime": "^1.4.3",
"@tybys/wasm-util": "^0.10.0"
"@tybys/wasm-util": "^0.9.0"
}
},
"node_modules/@newrelic/publish-sourcemap": {
@@ -5974,12 +5444,11 @@
}
},
"node_modules/@openedx/frontend-build": {
"version": "14.6.2",
"resolved": "https://registry.npmjs.org/@openedx/frontend-build/-/frontend-build-14.6.2.tgz",
"integrity": "sha512-Iu4/GPq90Xr/MSWnonn2qX8VDhI89HN7KOYBZ0/sxmAQgvXXNc7OYNC7kumvzbYzKueJQTyZoUYS7UjKB/n1WA==",
"version": "14.6.1",
"resolved": "https://registry.npmjs.org/@openedx/frontend-build/-/frontend-build-14.6.1.tgz",
"integrity": "sha512-HPswCfxThP0F92fmKqOetQ+E7HNiXDmOE+vHkfrpdKYNUj6Sn+7jaBICn8pNfif8uq4tF2ZGRnAgfUphry2ORQ==",
"devOptional": true,
"license": "AGPL-3.0",
"peer": true,
"dependencies": {
"@babel/cli": "7.24.8",
"@babel/core": "7.24.9",
@@ -6024,7 +5493,7 @@
"file-loader": "6.2.0",
"html-webpack-plugin": "5.6.3",
"identity-obj-proxy": "3.0.0",
"image-minimizer-webpack-plugin": "4.1.4",
"image-minimizer-webpack-plugin": "3.8.3",
"jest": "29.7.0",
"jest-environment-jsdom": "29.7.0",
"mini-css-extract-plugin": "1.6.2",
@@ -6032,13 +5501,13 @@
"postcss": "8.4.49",
"postcss-custom-media": "10.0.8",
"postcss-loader": "7.3.4",
"postcss-rtlcss": "5.7.1",
"postcss-rtlcss": "5.1.2",
"react-dev-utils": "12.0.1",
"react-refresh": "0.16.0",
"resolve-url-loader": "5.0.0",
"sass": "1.85.1",
"sass-loader": "13.3.3",
"sharp": "0.34.3",
"sharp": "0.32.6",
"source-map-loader": "4.0.2",
"style-loader": "3.3.4",
"ts-jest": "29.1.4",
@@ -6475,9 +5944,9 @@
}
},
"node_modules/@openedx/frontend-build/node_modules/istanbul-lib-source-maps/node_modules/debug": {
"version": "4.4.3",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
"integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
"version": "4.4.1",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz",
"integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==",
"devOptional": true,
"license": "MIT",
"dependencies": {
@@ -6498,7 +5967,6 @@
"integrity": "sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==",
"devOptional": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@jest/core": "^29.7.0",
"@jest/types": "^29.6.3",
@@ -7139,11 +6607,10 @@
}
},
"node_modules/@openedx/paragon": {
"version": "23.18.0",
"resolved": "https://registry.npmjs.org/@openedx/paragon/-/paragon-23.18.0.tgz",
"integrity": "sha512-xrYhTzi6wQW6C9bRMfQl8smRf/u8Cg0MCZiQFKl6rpP9dpKJ4+lpADrVN8EU6wzSDi65dF38kZ6QD5yvBRSRAQ==",
"version": "23.14.0",
"resolved": "https://registry.npmjs.org/@openedx/paragon/-/paragon-23.14.0.tgz",
"integrity": "sha512-+z5PspPI5D+/Xh87KG0ZYt/E+mOlgEMj6/IXeBWSj0vUvawj/pYzKgj+hlGbFGV9lIKkKnQJA8iurQrR++VXZA==",
"license": "Apache-2.0",
"peer": true,
"workspaces": [
"example",
"component-generator",
@@ -7154,7 +6621,7 @@
"dependencies": {
"@popperjs/core": "^2.11.4",
"@tokens-studio/sd-transforms": "^1.2.4",
"axios": "^0.30.2",
"axios": "^0.27.2",
"bootstrap": "^4.6.2",
"chalk": "^4.1.2",
"child_process": "^1.0.2",
@@ -7163,7 +6630,7 @@
"cli-progress": "^3.12.0",
"commander": "^9.4.1",
"email-prop-type": "^3.0.0",
"file-selector": "^0.10.0",
"file-selector": "^0.6.0",
"glob": "^8.0.3",
"inquirer": "^8.2.5",
"js-toml": "^1.0.0",
@@ -7188,11 +6655,11 @@
"react-loading-skeleton": "^3.1.0",
"react-popper": "^2.2.5",
"react-proptype-conditional-require": "^1.0.4",
"react-responsive": "^10.0.0",
"react-responsive": "^8.2.0",
"react-table": "^7.7.0",
"react-transition-group": "^4.4.2",
"sass": "^1.58.3",
"style-dictionary": "^4.4.0",
"style-dictionary": "^4.3.2",
"tabbable": "^5.3.3",
"uncontrollable": "^7.2.1",
"uuid": "^9.0.0"
@@ -7207,14 +6674,13 @@
}
},
"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.27.2",
"resolved": "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz",
"integrity": "sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==",
"license": "MIT",
"dependencies": {
"follow-redirects": "^1.15.4",
"form-data": "^4.0.4",
"proxy-from-env": "^1.1.0"
"follow-redirects": "^1.14.9",
"form-data": "^4.0.0"
}
},
"node_modules/@openedx/paragon/node_modules/brace-expansion": {
@@ -7255,15 +6721,6 @@
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/@openedx/paragon/node_modules/matchmediaquery": {
"version": "0.4.2",
"resolved": "https://registry.npmjs.org/matchmediaquery/-/matchmediaquery-0.4.2.tgz",
"integrity": "sha512-wrZpoT50ehYOudhDjt/YvUJc6eUzcdFPdmbizfgvswCKNHD1/OBOHYJpHie+HXpu6bSkEGieFMYk6VuutaiRfA==",
"license": "MIT",
"dependencies": {
"css-mediaquery": "^0.1.2"
}
},
"node_modules/@openedx/paragon/node_modules/minimatch": {
"version": "5.1.6",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz",
@@ -7304,30 +6761,6 @@
"postcss": "^8.4"
}
},
"node_modules/@openedx/paragon/node_modules/react-responsive": {
"version": "10.0.1",
"resolved": "https://registry.npmjs.org/react-responsive/-/react-responsive-10.0.1.tgz",
"integrity": "sha512-OM5/cRvbtUWEX8le8RCT8scA8y2OPtb0Q/IViEyCEM5FBN8lRrkUOZnu87I88A6njxDldvxG+rLBxWiA7/UM9g==",
"license": "MIT",
"dependencies": {
"hyphenate-style-name": "^1.0.0",
"matchmediaquery": "^0.4.2",
"prop-types": "^15.6.1",
"shallow-equal": "^3.1.0"
},
"engines": {
"node": ">=14"
},
"peerDependencies": {
"react": ">=16.8.0"
}
},
"node_modules/@openedx/paragon/node_modules/shallow-equal": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/shallow-equal/-/shallow-equal-3.1.0.tgz",
"integrity": "sha512-pfVOw8QZIXpMbhBWvzBISicvToTiM5WBF1EeAUZDDSb5Dt29yl4AYbyywbJFSEsRUMr7gJaxqCdr4L3tQf9wVg==",
"license": "MIT"
},
"node_modules/@optimizely/js-sdk-logging": {
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/@optimizely/js-sdk-logging/-/js-sdk-logging-0.3.1.tgz",
@@ -7417,6 +6850,30 @@
}
}
},
"node_modules/@optimizely/optimizely-sdk/node_modules/decompress-response": {
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-4.2.1.tgz",
"integrity": "sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==",
"license": "MIT",
"dependencies": {
"mimic-response": "^2.0.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/@optimizely/optimizely-sdk/node_modules/mimic-response": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz",
"integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==",
"license": "MIT",
"engines": {
"node": ">=8"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/@optimizely/optimizely-sdk/node_modules/uuid": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
@@ -7760,9 +7217,9 @@
}
},
"node_modules/@pkgr/core": {
"version": "0.2.9",
"resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.9.tgz",
"integrity": "sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==",
"version": "0.2.7",
"resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.7.tgz",
"integrity": "sha512-YLT9Zo3oNPJoBjBc4q8G2mjU4tqIbf5CEOORbUUr48dCD9q3umJ3IPlVqOqDakPfd2HuwccBaqlGhN4Gmr5OWg==",
"dev": true,
"license": "MIT",
"engines": {
@@ -7833,7 +7290,6 @@
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz",
"integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==",
"license": "MIT",
"peer": true,
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/popperjs"
@@ -7853,17 +7309,17 @@
}
},
"node_modules/@redux-saga/core": {
"version": "1.4.2",
"resolved": "https://registry.npmjs.org/@redux-saga/core/-/core-1.4.2.tgz",
"integrity": "sha512-nIMLGKo6jV6Wc1sqtVQs1iqbB3Kq20udB/u9XEaZQisT6YZ0NRB8+4L6WqD/E+YziYutd27NJbG8EWUPkb7c6Q==",
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/@redux-saga/core/-/core-1.3.0.tgz",
"integrity": "sha512-L+i+qIGuyWn7CIg7k1MteHGfttKPmxwZR5E7OsGikCL2LzYA0RERlaUY00Y3P3ZV2EYgrsYlBrGs6cJP5OKKqA==",
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.28.4",
"@redux-saga/deferred": "^1.3.1",
"@redux-saga/delay-p": "^1.3.1",
"@redux-saga/is": "^1.2.1",
"@redux-saga/symbols": "^1.2.1",
"@redux-saga/types": "^1.3.1",
"@babel/runtime": "^7.6.3",
"@redux-saga/deferred": "^1.2.1",
"@redux-saga/delay-p": "^1.2.1",
"@redux-saga/is": "^1.1.3",
"@redux-saga/symbols": "^1.1.3",
"@redux-saga/types": "^1.2.1",
"typescript-tuple": "^2.2.1"
},
"funding": {
@@ -7872,46 +7328,46 @@
}
},
"node_modules/@redux-saga/deferred": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/@redux-saga/deferred/-/deferred-1.3.1.tgz",
"integrity": "sha512-0YZ4DUivWojXBqLB/TmuRRpDDz7tyq1I0AuDV7qi01XlLhM5m51W7+xYtIckH5U2cMlv9eAuicsfRAi1XHpXIg==",
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/@redux-saga/deferred/-/deferred-1.2.1.tgz",
"integrity": "sha512-cmin3IuuzMdfQjA0lG4B+jX+9HdTgHZZ+6u3jRAOwGUxy77GSlTi4Qp2d6PM1PUoTmQUR5aijlA39scWWPF31g==",
"license": "MIT"
},
"node_modules/@redux-saga/delay-p": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/@redux-saga/delay-p/-/delay-p-1.3.1.tgz",
"integrity": "sha512-597I7L5MXbD/1i3EmcaOOjL/5suxJD7p5tnbV1PiWnE28c2cYiIHqmSMK2s7us2/UrhOL2KTNBiD0qBg6KnImg==",
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/@redux-saga/delay-p/-/delay-p-1.2.1.tgz",
"integrity": "sha512-MdiDxZdvb1m+Y0s4/hgdcAXntpUytr9g0hpcOO1XFVyyzkrDu3SKPgBFOtHn7lhu7n24ZKIAT1qtKyQjHqRd+w==",
"license": "MIT",
"dependencies": {
"@redux-saga/symbols": "^1.2.1"
"@redux-saga/symbols": "^1.1.3"
}
},
"node_modules/@redux-saga/is": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/@redux-saga/is/-/is-1.2.1.tgz",
"integrity": "sha512-x3aWtX3GmQfEvn8dh0ovPbsXgK9JjpiR24wKztpGbZP8JZUWWvUgKrvnWZ/T/4iphOBftyVc9VrIwhAnsM+OFA==",
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/@redux-saga/is/-/is-1.1.3.tgz",
"integrity": "sha512-naXrkETG1jLRfVfhOx/ZdLj0EyAzHYbgJWkXbB3qFliPcHKiWbv/ULQryOAEKyjrhiclmr6AMdgsXFyx7/yE6Q==",
"license": "MIT",
"dependencies": {
"@redux-saga/symbols": "^1.2.1",
"@redux-saga/types": "^1.3.1"
"@redux-saga/symbols": "^1.1.3",
"@redux-saga/types": "^1.2.1"
}
},
"node_modules/@redux-saga/symbols": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/@redux-saga/symbols/-/symbols-1.2.1.tgz",
"integrity": "sha512-3dh+uDvpBXi7EUp/eO+N7eFM4xKaU4yuGBXc50KnZGzIrR/vlvkTFQsX13zsY8PB6sCFYAgROfPSRUj8331QSA==",
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/@redux-saga/symbols/-/symbols-1.1.3.tgz",
"integrity": "sha512-hCx6ZvU4QAEUojETnX8EVg4ubNLBFl1Lps4j2tX7o45x/2qg37m3c6v+kSp8xjDJY+2tJw4QB3j8o8dsl1FDXg==",
"license": "MIT"
},
"node_modules/@redux-saga/types": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/@redux-saga/types/-/types-1.3.1.tgz",
"integrity": "sha512-YRCrJdhQLobGIQ8Cj1sta3nn6DrZDTSUnrIYhS2e5V590BmfVDleKoAquclAiKSBKWJwmuXTb+b4BL6rSHnahw==",
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/@redux-saga/types/-/types-1.2.1.tgz",
"integrity": "sha512-1dgmkh+3so0+LlBWRhGA33ua4MYr7tUOj+a9Si28vUi0IUFNbff1T3sgpeDJI/LaC75bBYnQ0A3wXjn0OrRNBA==",
"license": "MIT"
},
"node_modules/@remix-run/router": {
"version": "1.23.1",
"resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.23.1.tgz",
"integrity": "sha512-vDbaOzF7yT2Qs4vO6XV1MHcJv+3dgR1sT+l3B8xxOVhUC336prMvqrvsLL/9Dnw2xr6Qhz4J0dmS0llNAbnUmQ==",
"version": "1.23.0",
"resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.23.0.tgz",
"integrity": "sha512-O3rHJzAQKamUz1fvE0Qaw0xSFqsA/yafi2iqeE0pvdFtCO1viYx8QL6f3Ln/aCCTLxs68SLf0KPM9eSeM8yBnA==",
"license": "MIT",
"engines": {
"node": ">=14.0.0"
@@ -8141,7 +7597,6 @@
"integrity": "sha512-8QqtOQT5ACVlmsvKOJNEaWmRPmcojMOzCz4Hs2BGG/toAp/K38LcsMRyLp349glq5AzJbCEeimEoxaX6v/fLrA==",
"devOptional": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@babel/core": "^7.21.3",
"@svgr/babel-preset": "8.1.0",
@@ -8245,9 +7700,9 @@
}
},
"node_modules/@testing-library/dom": {
"version": "10.4.1",
"resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.1.tgz",
"integrity": "sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==",
"version": "10.4.0",
"resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.0.tgz",
"integrity": "sha512-pemlzrSESWbdAloYml3bAJMEfNh1Z7EduzqPKprCH5S341frlpYnUEW0H72dLxa6IsYr+mPno20GiSm+h9dEdQ==",
"license": "MIT",
"peer": true,
"dependencies": {
@@ -8255,9 +7710,9 @@
"@babel/runtime": "^7.12.5",
"@types/aria-query": "^5.0.1",
"aria-query": "5.3.0",
"chalk": "^4.1.0",
"dom-accessibility-api": "^0.5.9",
"lz-string": "^1.5.0",
"picocolors": "1.1.1",
"pretty-format": "^27.0.2"
},
"engines": {
@@ -8338,9 +7793,9 @@
}
},
"node_modules/@tybys/wasm-util": {
"version": "0.10.1",
"resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz",
"integrity": "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==",
"version": "0.9.0",
"resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.9.0.tgz",
"integrity": "sha512-6+7nlbMVX/PVDCwaIQ8nTOPveOcFLSt8GcXdx8hD0bt39uWxYT88uXzqTd4fTvqta7oeUJqudepapKNt2DYJFw==",
"dev": true,
"license": "MIT",
"optional": true,
@@ -8352,7 +7807,8 @@
"version": "5.0.4",
"resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz",
"integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==",
"license": "MIT"
"license": "MIT",
"peer": true
},
"node_modules/@types/babel__core": {
"version": "7.20.5",
@@ -8400,13 +7856,13 @@
}
},
"node_modules/@types/babel__traverse": {
"version": "7.28.0",
"resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz",
"integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==",
"version": "7.20.7",
"resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.7.tgz",
"integrity": "sha512-dkO5fhS7+/oos4ciWxyEyjWe48zmG6wbCheo/G2ZnHx4fs3EU6YC6UM8rk56gAjNJ9P3MTH2jo5jb92/K6wbng==",
"devOptional": true,
"license": "MIT",
"dependencies": {
"@babel/types": "^7.28.2"
"@babel/types": "^7.20.7"
}
},
"node_modules/@types/body-parser": {
@@ -8500,9 +7956,9 @@
}
},
"node_modules/@types/express-serve-static-core": {
"version": "5.0.7",
"resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-5.0.7.tgz",
"integrity": "sha512-R+33OsgWw7rOhD1emjU7dzCDHucJrgJXMA5PYCzJxVil0dsyx5iBEPHqpPfiKNJQb7lZ1vxwoLR4Z87bBUpeGQ==",
"version": "5.0.6",
"resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-5.0.6.tgz",
"integrity": "sha512-3xhRnjJPkULekpSzgtoNYYcTWgEZkp4myc+Saevii5JPnHNvHMRlBSHDbs7Bh1iPPoVTERHEZXyhyLbMEsExsA==",
"devOptional": true,
"license": "MIT",
"dependencies": {
@@ -8547,15 +8003,13 @@
}
},
"node_modules/@types/hoist-non-react-statics": {
"version": "3.3.7",
"resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.7.tgz",
"integrity": "sha512-PQTyIulDkIDro8P+IHbKCsw7U2xxBYflVzW/FgWdCAePD9xGSidgA76/GeJ6lBKoblyhf9pBY763gbrN+1dI8g==",
"version": "3.3.6",
"resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.6.tgz",
"integrity": "sha512-lPByRJUer/iN/xa4qpyL0qmL11DqNW81iU/IG1S3uvRUq4oKagz8VCxZjiWkumgt66YT3vOdDgZ0o32sGKtCEw==",
"license": "MIT",
"dependencies": {
"@types/react": "*",
"hoist-non-react-statics": "^3.3.0"
},
"peerDependencies": {
"@types/react": "*"
}
},
"node_modules/@types/html-minifier-terser": {
@@ -8709,20 +8163,19 @@
"license": "MIT"
},
"node_modules/@types/node": {
"version": "24.4.0",
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.4.0.tgz",
"integrity": "sha512-gUuVEAK4/u6F9wRLznPUU4WGUacSEBDPoC2TrBkw3GAnOLHBL45QdfHOXp1kJ4ypBGLxTOB+t7NJLpKoC3gznQ==",
"version": "24.0.10",
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.0.10.tgz",
"integrity": "sha512-ENHwaH+JIRTDIEEbDK6QSQntAYGtbvdDXnMXnZaZ6k13Du1dPMmprkEHIL7ok2Wl2aZevetwTAb5S+7yIF+enA==",
"devOptional": true,
"license": "MIT",
"peer": true,
"dependencies": {
"undici-types": "~7.11.0"
"undici-types": "~7.8.0"
}
},
"node_modules/@types/node-forge": {
"version": "1.3.14",
"resolved": "https://registry.npmjs.org/@types/node-forge/-/node-forge-1.3.14.tgz",
"integrity": "sha512-mhVF2BnD4BO+jtOp7z1CdzaK4mbuK0LLQYAvdOLqHTavxFNq4zA1EmYkpnFjP8HOUzedfQkRnp0E2ulSAYSzAw==",
"version": "1.3.12",
"resolved": "https://registry.npmjs.org/@types/node-forge/-/node-forge-1.3.12.tgz",
"integrity": "sha512-a0ToKlRVnUw3aXKQq2F+krxZKq7B8LEQijzPn5RdFAMatARD2JX9o8FBpMXOOrjob0uc13aN+V/AXniOXW4d9A==",
"devOptional": true,
"license": "MIT",
"dependencies": {
@@ -8764,11 +8217,10 @@
"license": "MIT"
},
"node_modules/@types/react": {
"version": "18.3.26",
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.26.tgz",
"integrity": "sha512-RFA/bURkcKzx/X9oumPG9Vp3D3JUgus/d0b67KB0t5S/raciymilkOa66olh78MUI92QLbEJevO7rvqU/kjwKA==",
"version": "18.3.23",
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.23.tgz",
"integrity": "sha512-/LDXMQh55EzZQ0uVAZmKKhfENivEvWz6E+EYzh+/MCjMhNsotd+ZHhBGIjFDTi6+fz0OhQQQLbTgdQIxxCsC0w==",
"license": "MIT",
"peer": true,
"dependencies": {
"@types/prop-types": "*",
"csstype": "^3.0.2"
@@ -8803,9 +8255,9 @@
"license": "MIT"
},
"node_modules/@types/semver": {
"version": "7.7.1",
"resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.7.1.tgz",
"integrity": "sha512-FmgJfu+MOcQ370SD0ev7EI8TlCAfKYU+B4m5T3yXc1CiRN94g/SZPtsCkk506aUDtlMnFZvasDwHHUcZUEaYuA==",
"version": "7.7.0",
"resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.7.0.tgz",
"integrity": "sha512-k107IF4+Xr7UHjwDc7Cfd6PRQfbdkiRabXGRjo07b4WyPahFBZCZ1sE+BNxYIJPPg73UkfOsVOLwqVc/6ETrIA==",
"devOptional": true,
"license": "MIT"
},
@@ -8911,7 +8363,6 @@
"integrity": "sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag==",
"devOptional": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@eslint-community/regexpp": "^4.4.0",
"@typescript-eslint/scope-manager": "5.62.0",
@@ -8960,7 +8411,6 @@
"integrity": "sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==",
"devOptional": true,
"license": "BSD-2-Clause",
"peer": true,
"dependencies": {
"@typescript-eslint/scope-manager": "5.62.0",
"@typescript-eslint/types": "5.62.0",
@@ -9163,9 +8613,9 @@
"license": "ISC"
},
"node_modules/@unrs/resolver-binding-android-arm-eabi": {
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm-eabi/-/resolver-binding-android-arm-eabi-1.11.1.tgz",
"integrity": "sha512-ppLRUgHVaGRWUx0R0Ut06Mjo9gBaBkg3v/8AxusGLhsIotbBLuRk51rAzqLC8gq6NyyAojEXglNjzf6R948DNw==",
"version": "1.11.0",
"resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm-eabi/-/resolver-binding-android-arm-eabi-1.11.0.tgz",
"integrity": "sha512-LRw5BW29sYj9NsQC6QoqeLVQhEa+BwVINYyMlcve+6stwdBsSt5UB7zw4UZB4+4PNqIVilHoMaPWCb/KhABHQw==",
"cpu": [
"arm"
],
@@ -9177,9 +8627,9 @@
]
},
"node_modules/@unrs/resolver-binding-android-arm64": {
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm64/-/resolver-binding-android-arm64-1.11.1.tgz",
"integrity": "sha512-lCxkVtb4wp1v+EoN+HjIG9cIIzPkX5OtM03pQYkG+U5O/wL53LC4QbIeazgiKqluGeVEeBlZahHalCaBvU1a2g==",
"version": "1.11.0",
"resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm64/-/resolver-binding-android-arm64-1.11.0.tgz",
"integrity": "sha512-zYX8D2zcWCAHqghA8tPjbp7LwjVXbIZP++mpU/Mrf5jUVlk3BWIxkeB8yYzZi5GpFSlqMcRZQxQqbMI0c2lASQ==",
"cpu": [
"arm64"
],
@@ -9191,9 +8641,9 @@
]
},
"node_modules/@unrs/resolver-binding-darwin-arm64": {
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-arm64/-/resolver-binding-darwin-arm64-1.11.1.tgz",
"integrity": "sha512-gPVA1UjRu1Y/IsB/dQEsp2V1pm44Of6+LWvbLc9SDk1c2KhhDRDBUkQCYVWe6f26uJb3fOK8saWMgtX8IrMk3g==",
"version": "1.11.0",
"resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-arm64/-/resolver-binding-darwin-arm64-1.11.0.tgz",
"integrity": "sha512-YsYOT049hevAY/lTYD77GhRs885EXPeAfExG5KenqMJ417nYLS2N/kpRpYbABhFZBVQn+2uRPasTe4ypmYoo3w==",
"cpu": [
"arm64"
],
@@ -9205,9 +8655,9 @@
]
},
"node_modules/@unrs/resolver-binding-darwin-x64": {
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-x64/-/resolver-binding-darwin-x64-1.11.1.tgz",
"integrity": "sha512-cFzP7rWKd3lZaCsDze07QX1SC24lO8mPty9vdP+YVa3MGdVgPmFc59317b2ioXtgCMKGiCLxJ4HQs62oz6GfRQ==",
"version": "1.11.0",
"resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-x64/-/resolver-binding-darwin-x64-1.11.0.tgz",
"integrity": "sha512-PSjvk3OZf1aZImdGY5xj9ClFG3bC4gnSSYWrt+id0UAv+GwwVldhpMFjAga8SpMo2T1GjV9UKwM+QCsQCQmtdA==",
"cpu": [
"x64"
],
@@ -9219,9 +8669,9 @@
]
},
"node_modules/@unrs/resolver-binding-freebsd-x64": {
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/@unrs/resolver-binding-freebsd-x64/-/resolver-binding-freebsd-x64-1.11.1.tgz",
"integrity": "sha512-fqtGgak3zX4DCB6PFpsH5+Kmt/8CIi4Bry4rb1ho6Av2QHTREM+47y282Uqiu3ZRF5IQioJQ5qWRV6jduA+iGw==",
"version": "1.11.0",
"resolved": "https://registry.npmjs.org/@unrs/resolver-binding-freebsd-x64/-/resolver-binding-freebsd-x64-1.11.0.tgz",
"integrity": "sha512-KC/iFaEN/wsTVYnHClyHh5RSYA9PpuGfqkFua45r4sweXpC0KHZ+BYY7ikfcGPt5w1lMpR1gneFzuqWLQxsRKg==",
"cpu": [
"x64"
],
@@ -9233,9 +8683,9 @@
]
},
"node_modules/@unrs/resolver-binding-linux-arm-gnueabihf": {
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-gnueabihf/-/resolver-binding-linux-arm-gnueabihf-1.11.1.tgz",
"integrity": "sha512-u92mvlcYtp9MRKmP+ZvMmtPN34+/3lMHlyMj7wXJDeXxuM0Vgzz0+PPJNsro1m3IZPYChIkn944wW8TYgGKFHw==",
"version": "1.11.0",
"resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-gnueabihf/-/resolver-binding-linux-arm-gnueabihf-1.11.0.tgz",
"integrity": "sha512-CDh/0v8uot43cB4yKtDL9CVY8pbPnMV0dHyQCE4lFz6PW/+9tS0i9eqP5a91PAqEBVMqH1ycu+k8rP6wQU846w==",
"cpu": [
"arm"
],
@@ -9247,9 +8697,9 @@
]
},
"node_modules/@unrs/resolver-binding-linux-arm-musleabihf": {
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-musleabihf/-/resolver-binding-linux-arm-musleabihf-1.11.1.tgz",
"integrity": "sha512-cINaoY2z7LVCrfHkIcmvj7osTOtm6VVT16b5oQdS4beibX2SYBwgYLmqhBjA1t51CarSaBuX5YNsWLjsqfW5Cw==",
"version": "1.11.0",
"resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-musleabihf/-/resolver-binding-linux-arm-musleabihf-1.11.0.tgz",
"integrity": "sha512-+TE7epATDSnvwr3L/hNHX3wQ8KQYB+jSDTdywycg3qDqvavRP8/HX9qdq/rMcnaRDn4EOtallb3vL/5wCWGCkw==",
"cpu": [
"arm"
],
@@ -9261,9 +8711,9 @@
]
},
"node_modules/@unrs/resolver-binding-linux-arm64-gnu": {
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-gnu/-/resolver-binding-linux-arm64-gnu-1.11.1.tgz",
"integrity": "sha512-34gw7PjDGB9JgePJEmhEqBhWvCiiWCuXsL9hYphDF7crW7UgI05gyBAi6MF58uGcMOiOqSJ2ybEeCvHcq0BCmQ==",
"version": "1.11.0",
"resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-gnu/-/resolver-binding-linux-arm64-gnu-1.11.0.tgz",
"integrity": "sha512-VBAYGg3VahofpQ+L4k/ZO8TSICIbUKKTaMYOWHWfuYBFqPbSkArZZLezw3xd27fQkxX4BaLGb/RKnW0dH9Y/UA==",
"cpu": [
"arm64"
],
@@ -9275,9 +8725,9 @@
]
},
"node_modules/@unrs/resolver-binding-linux-arm64-musl": {
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-musl/-/resolver-binding-linux-arm64-musl-1.11.1.tgz",
"integrity": "sha512-RyMIx6Uf53hhOtJDIamSbTskA99sPHS96wxVE/bJtePJJtpdKGXO1wY90oRdXuYOGOTuqjT8ACccMc4K6QmT3w==",
"version": "1.11.0",
"resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-musl/-/resolver-binding-linux-arm64-musl-1.11.0.tgz",
"integrity": "sha512-9IgGFUUb02J1hqdRAHXpZHIeUHRrbnGo6vrRbz0fREH7g+rzQy53/IBSyadZ/LG5iqMxukriNPu4hEMUn+uWEg==",
"cpu": [
"arm64"
],
@@ -9289,9 +8739,9 @@
]
},
"node_modules/@unrs/resolver-binding-linux-ppc64-gnu": {
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-ppc64-gnu/-/resolver-binding-linux-ppc64-gnu-1.11.1.tgz",
"integrity": "sha512-D8Vae74A4/a+mZH0FbOkFJL9DSK2R6TFPC9M+jCWYia/q2einCubX10pecpDiTmkJVUH+y8K3BZClycD8nCShA==",
"version": "1.11.0",
"resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-ppc64-gnu/-/resolver-binding-linux-ppc64-gnu-1.11.0.tgz",
"integrity": "sha512-LR4iQ/LPjMfivpL2bQ9kmm3UnTas3U+umcCnq/CV7HAkukVdHxrDD1wwx74MIWbbgzQTLPYY7Ur2MnnvkYJCBQ==",
"cpu": [
"ppc64"
],
@@ -9303,9 +8753,9 @@
]
},
"node_modules/@unrs/resolver-binding-linux-riscv64-gnu": {
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-gnu/-/resolver-binding-linux-riscv64-gnu-1.11.1.tgz",
"integrity": "sha512-frxL4OrzOWVVsOc96+V3aqTIQl1O2TjgExV4EKgRY09AJ9leZpEg8Ak9phadbuX0BA4k8U5qtvMSQQGGmaJqcQ==",
"version": "1.11.0",
"resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-gnu/-/resolver-binding-linux-riscv64-gnu-1.11.0.tgz",
"integrity": "sha512-HCupFQwMrRhrOg7YHrobbB5ADg0Q8RNiuefqMHVsdhEy9lLyXm/CxsCXeLJdrg27NAPsCaMDtdlm8Z2X8x91Tg==",
"cpu": [
"riscv64"
],
@@ -9317,9 +8767,9 @@
]
},
"node_modules/@unrs/resolver-binding-linux-riscv64-musl": {
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-musl/-/resolver-binding-linux-riscv64-musl-1.11.1.tgz",
"integrity": "sha512-mJ5vuDaIZ+l/acv01sHoXfpnyrNKOk/3aDoEdLO/Xtn9HuZlDD6jKxHlkN8ZhWyLJsRBxfv9GYM2utQ1SChKew==",
"version": "1.11.0",
"resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-musl/-/resolver-binding-linux-riscv64-musl-1.11.0.tgz",
"integrity": "sha512-Ckxy76A5xgjWa4FNrzcKul5qFMWgP5JSQ5YKd0XakmWOddPLSkQT+uAvUpQNnFGNbgKzv90DyQlxPDYPQ4nd6A==",
"cpu": [
"riscv64"
],
@@ -9331,9 +8781,9 @@
]
},
"node_modules/@unrs/resolver-binding-linux-s390x-gnu": {
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-s390x-gnu/-/resolver-binding-linux-s390x-gnu-1.11.1.tgz",
"integrity": "sha512-kELo8ebBVtb9sA7rMe1Cph4QHreByhaZ2QEADd9NzIQsYNQpt9UkM9iqr2lhGr5afh885d/cB5QeTXSbZHTYPg==",
"version": "1.11.0",
"resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-s390x-gnu/-/resolver-binding-linux-s390x-gnu-1.11.0.tgz",
"integrity": "sha512-HfO0PUCCRte2pMJmVyxPI+eqT7KuV3Fnvn2RPvMe5mOzb2BJKf4/Vth8sSt9cerQboMaTVpbxyYjjLBWIuI5BQ==",
"cpu": [
"s390x"
],
@@ -9345,9 +8795,9 @@
]
},
"node_modules/@unrs/resolver-binding-linux-x64-gnu": {
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-gnu/-/resolver-binding-linux-x64-gnu-1.11.1.tgz",
"integrity": "sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w==",
"version": "1.11.0",
"resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-gnu/-/resolver-binding-linux-x64-gnu-1.11.0.tgz",
"integrity": "sha512-9PZdjP7tLOEjpXHS6+B/RNqtfVUyDEmaViPOuSqcbomLdkJnalt5RKQ1tr2m16+qAufV0aDkfhXtoO7DQos/jg==",
"cpu": [
"x64"
],
@@ -9359,9 +8809,9 @@
]
},
"node_modules/@unrs/resolver-binding-linux-x64-musl": {
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-musl/-/resolver-binding-linux-x64-musl-1.11.1.tgz",
"integrity": "sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA==",
"version": "1.11.0",
"resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-musl/-/resolver-binding-linux-x64-musl-1.11.0.tgz",
"integrity": "sha512-qkE99ieiSKMnFJY/EfyGKVtNra52/k+lVF/PbO4EL5nU6AdvG4XhtJ+WHojAJP7ID9BNIra/yd75EHndewNRfA==",
"cpu": [
"x64"
],
@@ -9373,9 +8823,9 @@
]
},
"node_modules/@unrs/resolver-binding-wasm32-wasi": {
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/@unrs/resolver-binding-wasm32-wasi/-/resolver-binding-wasm32-wasi-1.11.1.tgz",
"integrity": "sha512-5u4RkfxJm+Ng7IWgkzi3qrFOvLvQYnPBmjmZQ8+szTK/b31fQCnleNl1GgEt7nIsZRIf5PLhPwT0WM+q45x/UQ==",
"version": "1.11.0",
"resolved": "https://registry.npmjs.org/@unrs/resolver-binding-wasm32-wasi/-/resolver-binding-wasm32-wasi-1.11.0.tgz",
"integrity": "sha512-MjXek8UL9tIX34gymvQLecz2hMaQzOlaqYJJBomwm1gsvK2F7hF+YqJJ2tRyBDTv9EZJGMt4KlKkSD/gZWCOiw==",
"cpu": [
"wasm32"
],
@@ -9390,9 +8840,9 @@
}
},
"node_modules/@unrs/resolver-binding-win32-arm64-msvc": {
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-arm64-msvc/-/resolver-binding-win32-arm64-msvc-1.11.1.tgz",
"integrity": "sha512-nRcz5Il4ln0kMhfL8S3hLkxI85BXs3o8EYoattsJNdsX4YUU89iOkVn7g0VHSRxFuVMdM4Q1jEpIId1Ihim/Uw==",
"version": "1.11.0",
"resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-arm64-msvc/-/resolver-binding-win32-arm64-msvc-1.11.0.tgz",
"integrity": "sha512-9LT6zIGO7CHybiQSh7DnQGwFMZvVr0kUjah6qQfkH2ghucxPV6e71sUXJdSM4Ba0MaGE6DC/NwWf7mJmc3DAng==",
"cpu": [
"arm64"
],
@@ -9404,9 +8854,9 @@
]
},
"node_modules/@unrs/resolver-binding-win32-ia32-msvc": {
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-ia32-msvc/-/resolver-binding-win32-ia32-msvc-1.11.1.tgz",
"integrity": "sha512-DCEI6t5i1NmAZp6pFonpD5m7i6aFrpofcp4LA2i8IIq60Jyo28hamKBxNrZcyOwVOZkgsRp9O2sXWBWP8MnvIQ==",
"version": "1.11.0",
"resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-ia32-msvc/-/resolver-binding-win32-ia32-msvc-1.11.0.tgz",
"integrity": "sha512-HYchBYOZ7WN266VjoGm20xFv5EonG/ODURRgwl9EZT7Bq1nLEs6VKJddzfFdXEAho0wfFlt8L/xIiE29Pmy1RA==",
"cpu": [
"ia32"
],
@@ -9418,9 +8868,9 @@
]
},
"node_modules/@unrs/resolver-binding-win32-x64-msvc": {
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-x64-msvc/-/resolver-binding-win32-x64-msvc-1.11.1.tgz",
"integrity": "sha512-lrW200hZdbfRtztbygyaq/6jP6AKE8qQN2KvPcJ+x7wiD038YtnYtZ82IMNJ69GJibV7bwL3y9FgK+5w/pYt6g==",
"version": "1.11.0",
"resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-x64-msvc/-/resolver-binding-win32-x64-msvc-1.11.0.tgz",
"integrity": "sha512-+oLKLHw3I1UQo4MeHfoLYF+e6YBa8p5vYUw3Rgt7IDzCs+57vIZqQlIo62NDpYM0VG6BjWOwnzBczMvbtH8hag==",
"cpu": [
"x64"
],
@@ -9660,9 +9110,9 @@
"license": "BSD-2-Clause"
},
"node_modules/@zip.js/zip.js": {
"version": "2.8.2",
"resolved": "https://registry.npmjs.org/@zip.js/zip.js/-/zip.js-2.8.2.tgz",
"integrity": "sha512-PI6UdgpSeVoGvzguKHmy2bwOqI3UYkntLZOCpyJSKIi7234c5aJmQYkJB/P4P2YUJkqhbqvu7iM2/0eJZ178nA==",
"version": "2.7.63",
"resolved": "https://registry.npmjs.org/@zip.js/zip.js/-/zip.js-2.7.63.tgz",
"integrity": "sha512-B02i6QDMUQ4c+5F9LmliBGA+jFsiEHIlF0eLQ6rWLaQOD3YwI6vyWwGkVCNJnVVguE2xYyr9fAwSD/3valm1/Q==",
"license": "BSD-3-Clause",
"engines": {
"bun": ">=0.7.0",
@@ -9698,7 +9148,6 @@
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
"devOptional": true,
"license": "MIT",
"peer": true,
"bin": {
"acorn": "bin/acorn"
},
@@ -9717,19 +9166,6 @@
"acorn-walk": "^8.0.2"
}
},
"node_modules/acorn-import-phases": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/acorn-import-phases/-/acorn-import-phases-1.0.4.tgz",
"integrity": "sha512-wKmbr/DDiIXzEOiWrTTUcDm24kQ2vGfZQvM2fwg2vXqR5uW6aapr7ObPtj1th32b9u90/Pf4AItvdTh42fBmVQ==",
"devOptional": true,
"license": "MIT",
"engines": {
"node": ">=10.13.0"
},
"peerDependencies": {
"acorn": "^8.14.0"
}
},
"node_modules/acorn-jsx": {
"version": "5.3.2",
"resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
@@ -9796,7 +9232,6 @@
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
"devOptional": true,
"license": "MIT",
"peer": true,
"dependencies": {
"fast-deep-equal": "^3.1.1",
"fast-json-stable-stringify": "^2.0.0",
@@ -9861,33 +9296,32 @@
}
},
"node_modules/algoliasearch": {
"version": "4.25.3",
"resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-4.25.3.tgz",
"integrity": "sha512-kgeIixgDiB+FbH1cHDFUtTNkxdJadHryF8lSPIHHQkEeUrzZA1Hi3PLL+EgNubO0dch4ALNb5G4rw+FDCv3Vbw==",
"version": "4.25.2",
"resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-4.25.2.tgz",
"integrity": "sha512-lYx98L6kb1VvXypbPI7Z54C4BJB2VT5QvOYthvPq6/POufZj+YdyeZSKjoLBKHJgGmYWQTHOKtcCTdKf98WOCA==",
"license": "MIT",
"peer": true,
"dependencies": {
"@algolia/cache-browser-local-storage": "4.25.3",
"@algolia/cache-common": "4.25.3",
"@algolia/cache-in-memory": "4.25.3",
"@algolia/client-account": "4.25.3",
"@algolia/client-analytics": "4.25.3",
"@algolia/client-common": "4.25.3",
"@algolia/client-personalization": "4.25.3",
"@algolia/client-search": "4.25.3",
"@algolia/logger-common": "4.25.3",
"@algolia/logger-console": "4.25.3",
"@algolia/recommend": "4.25.3",
"@algolia/requester-browser-xhr": "4.25.3",
"@algolia/requester-common": "4.25.3",
"@algolia/requester-node-http": "4.25.3",
"@algolia/transporter": "4.25.3"
"@algolia/cache-browser-local-storage": "4.25.2",
"@algolia/cache-common": "4.25.2",
"@algolia/cache-in-memory": "4.25.2",
"@algolia/client-account": "4.25.2",
"@algolia/client-analytics": "4.25.2",
"@algolia/client-common": "4.25.2",
"@algolia/client-personalization": "4.25.2",
"@algolia/client-search": "4.25.2",
"@algolia/logger-common": "4.25.2",
"@algolia/logger-console": "4.25.2",
"@algolia/recommend": "4.25.2",
"@algolia/requester-browser-xhr": "4.25.2",
"@algolia/requester-common": "4.25.2",
"@algolia/requester-node-http": "4.25.2",
"@algolia/transporter": "4.25.2"
}
},
"node_modules/algoliasearch-helper": {
"version": "3.26.1",
"resolved": "https://registry.npmjs.org/algoliasearch-helper/-/algoliasearch-helper-3.26.1.tgz",
"integrity": "sha512-CAlCxm4fYBXtvc5MamDzP6Svu8rW4z9me4DCBY1rQ2UDJ0u0flWmusQ8M3nOExZsLLRcUwUPoRAPMrhzOG3erw==",
"version": "3.26.0",
"resolved": "https://registry.npmjs.org/algoliasearch-helper/-/algoliasearch-helper-3.26.0.tgz",
"integrity": "sha512-Rv2x3GXleQ3ygwhkhJubhhYGsICmShLAiqtUuJTUkr9uOCOXyF2E71LVT4XDnVffbknv8XgScP4U0Oxtgm+hIw==",
"license": "MIT",
"dependencies": {
"@algolia/events": "^4.0.1"
@@ -10239,6 +9673,13 @@
"node": ">=8"
}
},
"node_modules/async": {
"version": "3.2.6",
"resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz",
"integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==",
"dev": true,
"license": "MIT"
},
"node_modules/async-function": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz",
@@ -10337,14 +9778,13 @@
}
},
"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.9.0",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.9.0.tgz",
"integrity": "sha512-re4CqKTJaURpzbLHtIi6XpDv20/CnpXOtjRY5/CU32L8gU8ek9UIivcfvSWvmKEngmVbrUtPpdDwWDWL7DNHvg==",
"license": "MIT",
"peer": true,
"dependencies": {
"follow-redirects": "^1.15.6",
"form-data": "^4.0.4",
"form-data": "^4.0.0",
"proxy-from-env": "^1.1.0"
}
},
@@ -10378,6 +9818,13 @@
"node": ">= 0.4"
}
},
"node_modules/b4a": {
"version": "1.6.7",
"resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.7.tgz",
"integrity": "sha512-OnAYlL5b7LEkALw87fUVafQw5rVR9RjwGd4KUwNQ6DrrNmaVaUCgLipfVlzrPQ4tWOR9P0IXGNOx50jYCCdSJg==",
"devOptional": true,
"license": "Apache-2.0"
},
"node_modules/babel-jest": {
"version": "29.7.0",
"resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz",
@@ -10429,9 +9876,9 @@
}
},
"node_modules/babel-plugin-formatjs": {
"version": "10.5.41",
"resolved": "https://registry.npmjs.org/babel-plugin-formatjs/-/babel-plugin-formatjs-10.5.41.tgz",
"integrity": "sha512-ZpozYGek+Bdyl52LgzW1MhPYBRKbROdbHBuBz7KAO88Ht7GcyCBiwJxpAjVDb0YBA9LGKUemGQOLdEDkRCe2hg==",
"version": "10.5.39",
"resolved": "https://registry.npmjs.org/babel-plugin-formatjs/-/babel-plugin-formatjs-10.5.39.tgz",
"integrity": "sha512-GnQGhQZLFYB0dqWUb07sl0h31tCEwU0HblS+rIAYNP84Fj5zQCyCldcYFm9gsEGYvialuYpxEt9+7+d/zqG7lQ==",
"devOptional": true,
"license": "MIT",
"dependencies": {
@@ -10440,8 +9887,8 @@
"@babel/plugin-syntax-jsx": "^7.25.9",
"@babel/traverse": "^7.26.10",
"@babel/types": "^7.26.10",
"@formatjs/icu-messageformat-parser": "2.11.4",
"@formatjs/ts-transformer": "3.14.2",
"@formatjs/icu-messageformat-parser": "2.11.2",
"@formatjs/ts-transformer": "3.14.0",
"@types/babel__core": "^7.20.5",
"@types/babel__helper-plugin-utils": "^7.10.3",
"@types/babel__traverse": "^7.20.6",
@@ -10449,22 +9896,22 @@
}
},
"node_modules/babel-plugin-formatjs/node_modules/@babel/core": {
"version": "7.28.4",
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.4.tgz",
"integrity": "sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA==",
"version": "7.28.0",
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.0.tgz",
"integrity": "sha512-UlLAnTPrFdNGoFtbSXwcGFQBtQZJCNjaN6hQNP3UPvuNXT1i82N26KL3dZeIpNalWywr9IuQuncaAfUaS1g6sQ==",
"devOptional": true,
"license": "MIT",
"dependencies": {
"@ampproject/remapping": "^2.2.0",
"@babel/code-frame": "^7.27.1",
"@babel/generator": "^7.28.3",
"@babel/generator": "^7.28.0",
"@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/helper-module-transforms": "^7.27.3",
"@babel/helpers": "^7.27.6",
"@babel/parser": "^7.28.0",
"@babel/template": "^7.27.2",
"@babel/traverse": "^7.28.4",
"@babel/types": "^7.28.4",
"@jridgewell/remapping": "^2.3.5",
"@babel/traverse": "^7.28.0",
"@babel/types": "^7.28.0",
"convert-source-map": "^2.0.0",
"debug": "^4.1.0",
"gensync": "^1.0.0-beta.2",
@@ -10594,9 +10041,9 @@
"license": "MIT"
},
"node_modules/babel-preset-current-node-syntax": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.2.0.tgz",
"integrity": "sha512-E/VlAEzRrsLEb2+dv8yp3bo4scof3l9nR4lrld+Iy5NyVqgVYUJnDAmunkhPMisRI32Qc4iRiz425d8vM++2fg==",
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.1.0.tgz",
"integrity": "sha512-ldYss8SbBlWva1bs28q78Ju5Zq1F+8BrqBZZ0VFhLBvhh6lCpC2o3gDJi/5DRLs9FgYZCnmPYIVFU4lRXCkyUw==",
"devOptional": true,
"license": "MIT",
"dependencies": {
@@ -10617,7 +10064,7 @@
"@babel/plugin-syntax-top-level-await": "^7.14.5"
},
"peerDependencies": {
"@babel/core": "^7.0.0 || ^8.0.0-0"
"@babel/core": "^7.0.0"
}
},
"node_modules/babel-preset-jest": {
@@ -10670,6 +10117,83 @@
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
"license": "MIT"
},
"node_modules/bare-events": {
"version": "2.5.4",
"resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.5.4.tgz",
"integrity": "sha512-+gFfDkR8pj4/TrWCGUGWmJIkBwuxPS5F+a5yWjOHQt2hHvNZd5YLzadjmDUtFmMM4y429bnKLa8bYBMHcYdnQA==",
"dev": true,
"license": "Apache-2.0",
"optional": true
},
"node_modules/bare-fs": {
"version": "4.1.6",
"resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-4.1.6.tgz",
"integrity": "sha512-25RsLF33BqooOEFNdMcEhMpJy8EoR88zSMrnOQOaM3USnOK2VmaJ1uaQEwPA6AQjrv1lXChScosN6CzbwbO9OQ==",
"dev": true,
"license": "Apache-2.0",
"optional": true,
"dependencies": {
"bare-events": "^2.5.4",
"bare-path": "^3.0.0",
"bare-stream": "^2.6.4"
},
"engines": {
"bare": ">=1.16.0"
},
"peerDependencies": {
"bare-buffer": "*"
},
"peerDependenciesMeta": {
"bare-buffer": {
"optional": true
}
}
},
"node_modules/bare-os": {
"version": "3.6.1",
"resolved": "https://registry.npmjs.org/bare-os/-/bare-os-3.6.1.tgz",
"integrity": "sha512-uaIjxokhFidJP+bmmvKSgiMzj2sV5GPHaZVAIktcxcpCyBFFWO+YlikVAdhmUo2vYFvFhOXIAlldqV29L8126g==",
"dev": true,
"license": "Apache-2.0",
"optional": true,
"engines": {
"bare": ">=1.14.0"
}
},
"node_modules/bare-path": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/bare-path/-/bare-path-3.0.0.tgz",
"integrity": "sha512-tyfW2cQcB5NN8Saijrhqn0Zh7AnFNsnczRcuWODH0eYAXBsJ5gVxAUuNr7tsHSC6IZ77cA0SitzT+s47kot8Mw==",
"dev": true,
"license": "Apache-2.0",
"optional": true,
"dependencies": {
"bare-os": "^3.0.1"
}
},
"node_modules/bare-stream": {
"version": "2.6.5",
"resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-2.6.5.tgz",
"integrity": "sha512-jSmxKJNJmHySi6hC42zlZnq00rga4jjxcgNZjY9N5WlOe/iOoGRtdwGsHzQv2RlH2KOYMwGUXhf2zXd32BA9RA==",
"dev": true,
"license": "Apache-2.0",
"optional": true,
"dependencies": {
"streamx": "^2.21.0"
},
"peerDependencies": {
"bare-buffer": "*",
"bare-events": "*"
},
"peerDependenciesMeta": {
"bare-buffer": {
"optional": true
},
"bare-events": {
"optional": true
}
}
},
"node_modules/base64-js": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
@@ -10690,16 +10214,6 @@
],
"license": "MIT"
},
"node_modules/baseline-browser-mapping": {
"version": "2.8.4",
"resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.4.tgz",
"integrity": "sha512-L+YvJwGAgwJBV1p6ffpSTa2KRc69EeeYGYjRVWKs0GKrK+LON0GC0gV+rKSNtALEDvMDqkvCFq9r1r94/Gjwxw==",
"devOptional": true,
"license": "Apache-2.0",
"bin": {
"baseline-browser-mapping": "dist/cli.js"
}
},
"node_modules/batch": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz",
@@ -10844,9 +10358,9 @@
}
},
"node_modules/browserslist": {
"version": "4.26.0",
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.26.0.tgz",
"integrity": "sha512-P9go2WrP9FiPwLv3zqRD/Uoxo0RSHjzFCiQz7d4vbmwNqQFo9T9WCeP/Qn5EbcKQY6DBbkxEXNcpJOmncNrb7A==",
"version": "4.25.1",
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.25.1.tgz",
"integrity": "sha512-KGj0KoOMXLpSNkkEI6Z6mShmQy0bc1I+T7K9N81k4WWMrfz+6fQ6es80B/YLAeRoKvjYE1YSHHOW1qe9xIVzHw==",
"devOptional": true,
"funding": [
{
@@ -10863,12 +10377,10 @@
}
],
"license": "MIT",
"peer": true,
"dependencies": {
"baseline-browser-mapping": "^2.8.2",
"caniuse-lite": "^1.0.30001741",
"electron-to-chromium": "^1.5.218",
"node-releases": "^2.0.21",
"caniuse-lite": "^1.0.30001726",
"electron-to-chromium": "^1.5.173",
"node-releases": "^2.0.19",
"update-browserslist-db": "^1.1.3"
},
"bin": {
@@ -11043,9 +10555,9 @@
}
},
"node_modules/caniuse-lite": {
"version": "1.0.30001741",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001741.tgz",
"integrity": "sha512-QGUGitqsc8ARjLdgAfxETDhRbJ0REsP6O3I96TAth/mVjh2cYzN2u+3AzPP3aVSm2FehEItaJw1xd+IGBXWeSw==",
"version": "1.0.30001727",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001727.tgz",
"integrity": "sha512-pB68nIHmbN6L/4C6MH1DokyR3bYqFwjaSs/sWDHGj4CTcFtQUQMuJftVwWkXq7mNWOybD3KhUv3oWHoGxgP14Q==",
"devOptional": true,
"funding": [
{
@@ -11111,9 +10623,9 @@
}
},
"node_modules/chardet": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/chardet/-/chardet-2.1.0.tgz",
"integrity": "sha512-bNFETTG/pM5ryzQ9Ad0lJOTa6HWD/YsScAR3EnCPZRPlQh77JocYktSHOUHelyhm8IARL+o4c4F1bP5KVOjiRA==",
"version": "0.7.0",
"resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz",
"integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==",
"license": "MIT"
},
"node_modules/chevrotain": {
@@ -11161,6 +10673,13 @@
"fsevents": "~2.3.2"
}
},
"node_modules/chownr": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz",
"integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==",
"devOptional": true,
"license": "ISC"
},
"node_modules/chroma-js": {
"version": "2.6.0",
"resolved": "https://registry.npmjs.org/chroma-js/-/chroma-js-2.6.0.tgz",
@@ -11483,9 +11002,9 @@
}
},
"node_modules/compression": {
"version": "1.8.1",
"resolved": "https://registry.npmjs.org/compression/-/compression-1.8.1.tgz",
"integrity": "sha512-9mAqGPHLakhCLeNyxPkK4xVo746zQ/czLH1Ky+vkitMnWfWZps8r0qXuwhwizagCRttsL4lfG4pIOvaWLpAP0w==",
"version": "1.8.0",
"resolved": "https://registry.npmjs.org/compression/-/compression-1.8.0.tgz",
"integrity": "sha512-k6WLKfunuqCYD3t6AsuPGvQWaKwuLLh2/xHNcX4qE+vIfDNXpSqnrhwA7O53R7WVQUnt8dVAIW+YHr7xTgOgGA==",
"devOptional": true,
"license": "MIT",
"dependencies": {
@@ -11493,7 +11012,7 @@
"compressible": "~2.0.18",
"debug": "2.6.9",
"negotiator": "~0.6.4",
"on-headers": "~1.1.0",
"on-headers": "~1.0.2",
"safe-buffer": "5.2.1",
"vary": "~1.1.2"
},
@@ -11605,6 +11124,77 @@
"devOptional": true,
"license": "MIT"
},
"node_modules/copy-webpack-plugin": {
"version": "11.0.0",
"resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-11.0.0.tgz",
"integrity": "sha512-fX2MWpamkW0hZxMEg0+mYnA40LTosOSa5TqZ9GYIBzyJa9C3QUaMPSE2xAi/buNr8u89SfD9wHSQVBzrRa/SOQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"fast-glob": "^3.2.11",
"glob-parent": "^6.0.1",
"globby": "^13.1.1",
"normalize-path": "^3.0.0",
"schema-utils": "^4.0.0",
"serialize-javascript": "^6.0.0"
},
"engines": {
"node": ">= 14.15.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/webpack"
},
"peerDependencies": {
"webpack": "^5.1.0"
}
},
"node_modules/copy-webpack-plugin/node_modules/glob-parent": {
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
"integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
"dev": true,
"license": "ISC",
"dependencies": {
"is-glob": "^4.0.3"
},
"engines": {
"node": ">=10.13.0"
}
},
"node_modules/copy-webpack-plugin/node_modules/globby": {
"version": "13.2.2",
"resolved": "https://registry.npmjs.org/globby/-/globby-13.2.2.tgz",
"integrity": "sha512-Y1zNGV+pzQdh7H39l9zgB4PJqjRNqydvdYCDG4HFXM4XuvSaQQlEc91IU1yALL8gUTDomgBAfz3XJdmUS+oo0w==",
"dev": true,
"license": "MIT",
"dependencies": {
"dir-glob": "^3.0.1",
"fast-glob": "^3.3.0",
"ignore": "^5.2.4",
"merge2": "^1.4.1",
"slash": "^4.0.0"
},
"engines": {
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/copy-webpack-plugin/node_modules/slash": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz",
"integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/core-js": {
"version": "3.43.0",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.43.0.tgz",
@@ -11617,13 +11207,13 @@
}
},
"node_modules/core-js-compat": {
"version": "3.45.1",
"resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.45.1.tgz",
"integrity": "sha512-tqTt5T4PzsMIZ430XGviK4vzYSoeNJ6CXODi6c/voxOT6IZqBht5/EKaSNnYiEjjRYxjVz7DQIsOsY0XNi8PIA==",
"version": "3.44.0",
"resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.44.0.tgz",
"integrity": "sha512-JepmAj2zfl6ogy34qfWtcE7nHKAJnKsQFRn++scjVS2bZFllwptzw61BZcZFYBPpUznLfAvh0LGhxKppk04ClA==",
"devOptional": true,
"license": "MIT",
"dependencies": {
"browserslist": "^4.25.3"
"browserslist": "^4.25.1"
},
"funding": {
"type": "opencollective",
@@ -11631,9 +11221,9 @@
}
},
"node_modules/core-js-pure": {
"version": "3.45.1",
"resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.45.1.tgz",
"integrity": "sha512-OHnWFKgTUshEU8MK+lOs1H8kC8GkTi9Z1tvNkxrCcw9wl3MJIO7q2ld77wjWn4/xuGrVu2X+nME1iIIPBSdyEQ==",
"version": "3.44.0",
"resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.44.0.tgz",
"integrity": "sha512-gvMQAGB4dfVUxpYD0k3Fq8J+n5bB6Ytl15lqlZrOIXFzxOhtPaObfkQGHtMRdyjIf7z2IeNULwi1jEwyS+ltKQ==",
"hasInstallScript": true,
"license": "MIT",
"funding": {
@@ -12681,9 +12271,9 @@
"license": "MIT"
},
"node_modules/debug": {
"version": "4.4.3",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
"integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
"version": "4.4.1",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz",
"integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==",
"devOptional": true,
"license": "MIT",
"dependencies": {
@@ -12715,21 +12305,25 @@
}
},
"node_modules/decompress-response": {
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-4.2.1.tgz",
"integrity": "sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==",
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz",
"integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==",
"devOptional": true,
"license": "MIT",
"dependencies": {
"mimic-response": "^2.0.0"
"mimic-response": "^3.1.0"
},
"engines": {
"node": ">=8"
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/dedent": {
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/dedent/-/dedent-1.7.0.tgz",
"integrity": "sha512-HGFtf8yhuhGhqO07SV79tRp+br4MnbdjeVxotpn1QBl30pcLLCQjX5b2295ll0fv8RKDKsmWYrl05usHM9CewQ==",
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/dedent/-/dedent-1.6.0.tgz",
"integrity": "sha512-F1Z+5UCFpmQUzJa11agbyPVMbpgT/qA3/SKyJ1jyBgm7dUcUEa8v9JwDkerSQXfakBwFljIxhOJqGkjUwZ9FSA==",
"devOptional": true,
"license": "MIT",
"peerDependencies": {
@@ -12747,6 +12341,16 @@
"integrity": "sha512-yVn6RZmHiGnxRKR9sJb3iVV2XTF1Ghh2DiWRZ3dMnGc43yUdWWF/kX6lQyk3+P84iprfWKU/8zFTrlkvtFm1ug==",
"license": "MIT"
},
"node_modules/deep-extend": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
"integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==",
"devOptional": true,
"license": "MIT",
"engines": {
"node": ">=4.0.0"
}
},
"node_modules/deep-is": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
@@ -13071,7 +12675,8 @@
"version": "0.5.16",
"resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz",
"integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==",
"license": "MIT"
"license": "MIT",
"peer": true
},
"node_modules/dom-converter": {
"version": "0.2.0",
@@ -13257,10 +12862,26 @@
"devOptional": true,
"license": "MIT"
},
"node_modules/ejs": {
"version": "3.1.10",
"resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz",
"integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
"jake": "^10.8.5"
},
"bin": {
"ejs": "bin/cli.js"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/electron-to-chromium": {
"version": "1.5.218",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.218.tgz",
"integrity": "sha512-uwwdN0TUHs8u6iRgN8vKeWZMRll4gBkz+QMqdS7DDe49uiK68/UX92lFb61oiFPrpYZNeZIqa4bA7O6Aiasnzg==",
"version": "1.5.180",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.180.tgz",
"integrity": "sha512-ED+GEyEh3kYMwt2faNmgMB0b8O5qtATGgR4RmRsIp4T6p7B8vdMbIedYndnvZfsaXvSzegtpfqRMDNCjjiSduA==",
"devOptional": true,
"license": "ISC"
},
@@ -13295,9 +12916,9 @@
}
},
"node_modules/emoji-regex": {
"version": "10.5.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.5.0.tgz",
"integrity": "sha512-lb49vf1Xzfx080OKA0o6l8DQQpV+6Vg95zyCJX9VB/BqKYlhG7N4wgROUUHRA+ZPUefLnteQOad7z1kT2bV7bg==",
"version": "10.4.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.4.0.tgz",
"integrity": "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==",
"devOptional": true,
"license": "MIT"
},
@@ -13331,10 +12952,20 @@
"node": ">= 0.8"
}
},
"node_modules/end-of-stream": {
"version": "1.4.5",
"resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz",
"integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==",
"devOptional": true,
"license": "MIT",
"dependencies": {
"once": "^1.4.0"
}
},
"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.18.2",
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.2.tgz",
"integrity": "sha512-6Jw4sE1maoRJo3q8MsSIn2onJFbLTOjY9hlx4DZXmOKvLRd1Ok2kXmAGXaafL2+ijsJZ1ClYbl/pmqr9+k4iUQ==",
"devOptional": true,
"license": "MIT",
"dependencies": {
@@ -13372,9 +13003,9 @@
}
},
"node_modules/error-ex": {
"version": "1.3.4",
"resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz",
"integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==",
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
"integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
"devOptional": true,
"license": "MIT",
"dependencies": {
@@ -13641,7 +13272,6 @@
"deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.",
"devOptional": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@eslint-community/eslint-utils": "^4.2.0",
"@eslint-community/regexpp": "^4.4.0",
@@ -13699,7 +13329,6 @@
"integrity": "sha512-T75QYQVQX57jiNgpF9r1KegMICE94VYwoFQyMGhrvc+lB8YF2E/M/PYDaQe1AJcWaEgqLE+ErXV1Og/+6Vyzew==",
"devOptional": true,
"license": "MIT",
"peer": true,
"dependencies": {
"eslint-config-airbnb-base": "^15.0.0",
"object.assign": "^4.1.2",
@@ -13742,7 +13371,6 @@
"integrity": "sha512-GPxI5URre6dDpJ0CtcthSZVBAfI+Uw7un5OYNVxP2EYi3H81Jw701yFP7AU+/vCE7xBtFmjge7kfhhk4+RAiig==",
"devOptional": true,
"license": "MIT",
"peer": true,
"dependencies": {
"eslint-config-airbnb-base": "^15.0.0"
},
@@ -14126,9 +13754,9 @@
"license": "0BSD"
},
"node_modules/eslint-plugin-formatjs/node_modules/typescript": {
"version": "5.9.2",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.2.tgz",
"integrity": "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==",
"version": "5.8.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz",
"integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==",
"devOptional": true,
"license": "Apache-2.0",
"bin": {
@@ -14145,7 +13773,6 @@
"integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==",
"devOptional": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@rtsao/scc": "^1.1.0",
"array-includes": "^3.1.9",
@@ -14203,7 +13830,6 @@
"integrity": "sha512-63Bog4iIethyo8smBklORknVjB0T2dwB8Mr/hIC+fBS0uyHdYYpzM/Ed+YC8VxTjlXHEWFOdmgwcDn1U2L9VCA==",
"devOptional": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@babel/runtime": "^7.20.7",
"aria-query": "^5.1.3",
@@ -14242,7 +13868,6 @@
"integrity": "sha512-73QQMKALArI8/7xGLNI/3LylrEYrlKZSb5C9+q3OtOewTnMQi5cT+aE9E41sLCmli3I9PGGmD1yiZydyo4FEPw==",
"devOptional": true,
"license": "MIT",
"peer": true,
"dependencies": {
"array-includes": "^3.1.6",
"array.prototype.flatmap": "^1.3.1",
@@ -14274,7 +13899,6 @@
"integrity": "sha512-Ck77j8hF7l9N4S/rzSLOWEKpn994YH6iwUK8fr9mXIaQvGpQYmOnQLbiue1u5kI5T1y+gdgqosnEAO9NCz0DBg==",
"devOptional": true,
"license": "MIT",
"peer": true,
"engines": {
"node": ">=10"
},
@@ -14618,6 +14242,16 @@
"node": ">= 0.8.0"
}
},
"node_modules/expand-template": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz",
"integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==",
"devOptional": true,
"license": "(MIT OR WTFPL)",
"engines": {
"node": ">=6"
}
},
"node_modules/expect": {
"version": "29.7.0",
"resolved": "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz",
@@ -14705,6 +14339,20 @@
"devOptional": true,
"license": "MIT"
},
"node_modules/external-editor": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz",
"integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==",
"license": "MIT",
"dependencies": {
"chardet": "^0.7.0",
"iconv-lite": "^0.4.24",
"tmp": "^0.0.33"
},
"engines": {
"node": ">=4"
}
},
"node_modules/fast-deep-equal": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
@@ -14718,6 +14366,13 @@
"integrity": "sha512-lEJeOH5VL5R09j6AA0D4Uvq7AgsHw0dAImQQ+F3iSyHZuAxyQfWobsagGpTcOPvJr3urmKRHrs+Gs9hV+/Qm/Q==",
"license": "MIT"
},
"node_modules/fast-fifo": {
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz",
"integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==",
"devOptional": true,
"license": "MIT"
},
"node_modules/fast-glob": {
"version": "3.3.3",
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz",
@@ -14757,9 +14412,9 @@
"license": "MIT"
},
"node_modules/fast-uri": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz",
"integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==",
"version": "3.0.6",
"resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.6.tgz",
"integrity": "sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==",
"devOptional": true,
"funding": [
{
@@ -14893,17 +14548,50 @@
}
},
"node_modules/file-selector": {
"version": "0.10.0",
"resolved": "https://registry.npmjs.org/file-selector/-/file-selector-0.10.0.tgz",
"integrity": "sha512-iXLQxZTDe9qtBDkpaU4msOWNbh/4JxYSux7BsVxgt+0HBCpj9qPUFjD3SDBPLCJDoU3MsJh1i+CseQ/9488F/A==",
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/file-selector/-/file-selector-0.6.0.tgz",
"integrity": "sha512-QlZ5yJC0VxHxQQsQhXvBaC7VRJ2uaxTf+Tfpu4Z/OcVQJVpZO+DGU0rkoVW5ce2SccxugvpBJoMvUs59iILYdw==",
"license": "MIT",
"dependencies": {
"tslib": "^2.7.0"
"tslib": "^2.4.0"
},
"engines": {
"node": ">= 12"
}
},
"node_modules/filelist": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz",
"integrity": "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
"minimatch": "^5.0.1"
}
},
"node_modules/filelist/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,
"license": "MIT",
"dependencies": {
"balanced-match": "^1.0.0"
}
},
"node_modules/filelist/node_modules/minimatch": {
"version": "5.1.6",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz",
"integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==",
"dev": true,
"license": "ISC",
"dependencies": {
"brace-expansion": "^2.0.1"
},
"engines": {
"node": ">=10"
}
},
"node_modules/filesize": {
"version": "8.0.7",
"resolved": "https://registry.npmjs.org/filesize/-/filesize-8.0.7.tgz",
@@ -15073,9 +14761,9 @@
}
},
"node_modules/follow-redirects": {
"version": "1.15.11",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz",
"integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==",
"version": "1.15.9",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz",
"integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==",
"funding": [
{
"type": "individual",
@@ -15245,9 +14933,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.3",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.3.tgz",
"integrity": "sha512-qsITQPfmvMOSAdeyZ+12I1c+CKSstAFAwu+97zrnWAbIr5u8wfsExUzCesVLC8NgHuRUqNN4Zy6UPWUTRGslcA==",
"license": "MIT",
"dependencies": {
"asynckit": "^0.4.0",
@@ -15261,9 +14949,9 @@
}
},
"node_modules/form-urlencoded": {
"version": "6.1.6",
"resolved": "https://registry.npmjs.org/form-urlencoded/-/form-urlencoded-6.1.6.tgz",
"integrity": "sha512-0a2GKWoNjT55lPrjZWFUiJ8rK9e3rihCyNqZP2k/GSPfkjemZoDrYrNsvRSQHrKJ4qnD/wXj7KSQomz/lbF2Ew==",
"version": "6.1.5",
"resolved": "https://registry.npmjs.org/form-urlencoded/-/form-urlencoded-6.1.5.tgz",
"integrity": "sha512-9EMyy7kvglRcR027EtEPCZ2JYfi1xYFuGTsgVJ+yWmRlhc+dwSCwRIOSCH0cUYCAb0+REe6s8aPqXAG8lYVkZw==",
"license": "MIT"
},
"node_modules/formidable": {
@@ -15318,6 +15006,13 @@
"node": ">= 0.6"
}
},
"node_modules/fs-constants": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
"integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==",
"devOptional": true,
"license": "MIT"
},
"node_modules/fs-extra": {
"version": "9.1.0",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz",
@@ -15334,9 +15029,9 @@
}
},
"node_modules/fs-monkey": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.1.0.tgz",
"integrity": "sha512-QMUezzXWII9EV5aTFXW1UBVUO77wYPpjqIF8/AviUCThNeSYZykpoTixUeaNNBwmCev0AMDWMAni+f8Hxb1IFw==",
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.6.tgz",
"integrity": "sha512-b1FMfwetIKymC0eioW7mTywihSQE4oLzQn1dB6rZB5fx/3NpNEdAWeCSMB+60/AeT0TCXsxzAlcYVEFCTAksWg==",
"devOptional": true,
"license": "Unlicense"
},
@@ -15528,6 +15223,13 @@
"url": "https://github.com/privatenumber/get-tsconfig?sponsor=1"
}
},
"node_modules/github-from-package": {
"version": "0.0.0",
"resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz",
"integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==",
"devOptional": true,
"license": "MIT"
},
"node_modules/glob": {
"version": "7.2.3",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
@@ -15562,22 +15264,6 @@
"node": ">= 6"
}
},
"node_modules/glob-to-regex.js": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/glob-to-regex.js/-/glob-to-regex.js-1.0.1.tgz",
"integrity": "sha512-CG/iEvgQqfzoVsMUbxSJcwbG2JwyZ3naEqPkeltwl0BSS8Bp83k3xlGms+0QdWFUAwV+uvo80wNswKF6FWEkKg==",
"license": "Apache-2.0",
"engines": {
"node": ">=10.0"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/streamich"
},
"peerDependencies": {
"tslib": "2"
}
},
"node_modules/glob-to-regexp": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz",
@@ -15738,38 +15424,6 @@
"devOptional": true,
"license": "MIT"
},
"node_modules/handlebars": {
"version": "4.7.8",
"resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz",
"integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"minimist": "^1.2.5",
"neo-async": "^2.6.2",
"source-map": "^0.6.1",
"wordwrap": "^1.0.0"
},
"bin": {
"handlebars": "bin/handlebars"
},
"engines": {
"node": ">=0.4.7"
},
"optionalDependencies": {
"uglify-js": "^3.1.4"
}
},
"node_modules/handlebars/node_modules/source-map": {
"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",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/harmony-reflect": {
"version": "1.6.2",
"resolved": "https://registry.npmjs.org/harmony-reflect/-/harmony-reflect-1.6.2.tgz",
@@ -16213,6 +15867,22 @@
"node": ">=10.17.0"
}
},
"node_modules/husky": {
"version": "9.1.7",
"resolved": "https://registry.npmjs.org/husky/-/husky-9.1.7.tgz",
"integrity": "sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA==",
"dev": true,
"license": "MIT",
"bin": {
"husky": "bin.js"
},
"engines": {
"node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/typicode"
}
},
"node_modules/hyperdyperid": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/hyperdyperid/-/hyperdyperid-1.2.0.tgz",
@@ -16244,7 +15914,6 @@
"version": "0.4.24",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
"integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
"devOptional": true,
"license": "MIT",
"dependencies": {
"safer-buffer": ">= 2.1.2 < 3"
@@ -16310,17 +15979,17 @@
}
},
"node_modules/image-minimizer-webpack-plugin": {
"version": "4.1.4",
"resolved": "https://registry.npmjs.org/image-minimizer-webpack-plugin/-/image-minimizer-webpack-plugin-4.1.4.tgz",
"integrity": "sha512-A2DLYuCyu7icbGdv8OMGFQKPXvsztWAueBkT3yQ7KVW1YGnAJKtgLYELkN7/aUday05DzEdKRaLE5Bnh/9S2UQ==",
"version": "3.8.3",
"resolved": "https://registry.npmjs.org/image-minimizer-webpack-plugin/-/image-minimizer-webpack-plugin-3.8.3.tgz",
"integrity": "sha512-Ex0cjNJc2FUSuwN7WHNyxkIZINP0M9lrN+uWJznMcsehiM5Z7ELwk+SEkSGEookK1GUd2wf+09jy1PEH5a5XmQ==",
"devOptional": true,
"license": "MIT",
"dependencies": {
"schema-utils": "^4.2.0",
"serialize-javascript": "^6.0.2"
"serialize-javascript": "^6.0.1"
},
"engines": {
"node": ">= 18.12.0"
"node": ">= 12.13.0"
},
"funding": {
"type": "opencollective",
@@ -16474,16 +16143,16 @@
"license": "ISC"
},
"node_modules/inquirer": {
"version": "8.2.7",
"resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.7.tgz",
"integrity": "sha512-UjOaSel/iddGZJ5xP/Eixh6dY1XghiBw4XK13rCCIJcJfyhhoul/7KhLLUGtebEj6GDYM6Vnx/mVsjx2L/mFIA==",
"version": "8.2.6",
"resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.6.tgz",
"integrity": "sha512-M1WuAmb7pn9zdFRtQYk26ZBoY043Sse0wVDdk4Bppr+JOXyQYybdtvK+l9wUibhtjdjvtoiNy8tk+EgsYIUqKg==",
"license": "MIT",
"dependencies": {
"@inquirer/external-editor": "^1.0.0",
"ansi-escapes": "^4.2.1",
"chalk": "^4.1.1",
"cli-cursor": "^3.1.0",
"cli-width": "^3.0.0",
"external-editor": "^3.0.3",
"figures": "^3.0.0",
"lodash": "^4.17.21",
"mute-stream": "0.0.8",
@@ -17388,9 +17057,9 @@
}
},
"node_modules/istanbul-reports": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz",
"integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==",
"version": "3.1.7",
"resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.7.tgz",
"integrity": "sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==",
"devOptional": true,
"license": "BSD-3-Clause",
"dependencies": {
@@ -17434,17 +17103,36 @@
"@pkgjs/parseargs": "^0.11.0"
}
},
"node_modules/jake": {
"version": "10.9.2",
"resolved": "https://registry.npmjs.org/jake/-/jake-10.9.2.tgz",
"integrity": "sha512-2P4SQ0HrLQ+fw6llpLnOaGAvN2Zu6778SJMrCUwns4fOoG9ayrTiZk3VV8sCPkVZF8ab0zksVpS8FDY5pRCNBA==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
"async": "^3.2.3",
"chalk": "^4.0.2",
"filelist": "^1.0.4",
"minimatch": "^3.1.2"
},
"bin": {
"jake": "bin/cli.js"
},
"engines": {
"node": ">=10"
}
},
"node_modules/jest": {
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/jest/-/jest-30.2.0.tgz",
"integrity": "sha512-F26gjC0yWN8uAA5m5Ss8ZQf5nDHWGlN/xWZIh8S5SRbsEKBovwZhxGd6LJlbZYxBgCYOtreSUyb8hpXyGC5O4A==",
"version": "30.0.4",
"resolved": "https://registry.npmjs.org/jest/-/jest-30.0.4.tgz",
"integrity": "sha512-9QE0RS4WwTj/TtTC4h/eFVmFAhGNVerSB9XpJh8sqaXlP73ILcPcZ7JWjjEtJJe2m8QyBLKKfPQuK+3F+Xij/g==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/core": "30.2.0",
"@jest/types": "30.2.0",
"@jest/core": "30.0.4",
"@jest/types": "30.0.1",
"import-local": "^3.2.0",
"jest-cli": "30.2.0"
"jest-cli": "30.0.4"
},
"bin": {
"jest": "bin/jest.js"
@@ -17462,14 +17150,14 @@
}
},
"node_modules/jest-changed-files": {
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-30.2.0.tgz",
"integrity": "sha512-L8lR1ChrRnSdfeOvTrwZMlnWV8G/LLjQ0nG9MBclwWZidA2N5FviRki0Bvh20WRMOX31/JYvzdqTJrk5oBdydQ==",
"version": "30.0.2",
"resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-30.0.2.tgz",
"integrity": "sha512-Ius/iRST9FKfJI+I+kpiDh8JuUlAISnRszF9ixZDIqJF17FckH5sOzKC8a0wd0+D+8em5ADRHA5V5MnfeDk2WA==",
"dev": true,
"license": "MIT",
"dependencies": {
"execa": "^5.1.1",
"jest-util": "30.2.0",
"jest-util": "30.0.2",
"p-limit": "^3.1.0"
},
"engines": {
@@ -17477,9 +17165,9 @@
}
},
"node_modules/jest-changed-files/node_modules/@jest/schemas": {
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz",
"integrity": "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==",
"version": "30.0.1",
"resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.1.tgz",
"integrity": "sha512-+g/1TKjFuGrf1Hh0QPCv0gISwBxJ+MQSNXmG9zjHy7BmFhtoJ9fdNhWJp3qUKRi93AOZHXtdxZgJ1vAtz6z65w==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -17490,14 +17178,14 @@
}
},
"node_modules/jest-changed-files/node_modules/@jest/types": {
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-30.2.0.tgz",
"integrity": "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg==",
"version": "30.0.1",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-30.0.1.tgz",
"integrity": "sha512-HGwoYRVF0QSKJu1ZQX0o5ZrUrrhj0aOOFA8hXrumD7SIzjouevhawbTjmXdwOmURdGluU9DM/XvGm3NyFoiQjw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/pattern": "30.0.1",
"@jest/schemas": "30.0.5",
"@jest/schemas": "30.0.1",
"@types/istanbul-lib-coverage": "^2.0.6",
"@types/istanbul-reports": "^3.0.4",
"@types/node": "*",
@@ -17509,20 +17197,20 @@
}
},
"node_modules/jest-changed-files/node_modules/@sinclair/typebox": {
"version": "0.34.41",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.41.tgz",
"integrity": "sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g==",
"version": "0.34.37",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.37.tgz",
"integrity": "sha512-2TRuQVgQYfy+EzHRTIvkhv2ADEouJ2xNS/Vq+W5EuuewBdOrvATvljZTxHWZSTYr2sTjTHpGvucaGAt67S2akw==",
"dev": true,
"license": "MIT"
},
"node_modules/jest-changed-files/node_modules/jest-util": {
"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==",
"version": "30.0.2",
"resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.0.2.tgz",
"integrity": "sha512-8IyqfKS4MqprBuUpZNlFB5l+WFehc8bfCe1HSZFHzft2mOuND8Cvi9r1musli+u6F3TqanCZ/Ik4H4pXUolZIg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/types": "30.2.0",
"@jest/types": "30.0.1",
"@types/node": "*",
"chalk": "^4.1.2",
"ci-info": "^4.2.0",
@@ -17534,9 +17222,9 @@
}
},
"node_modules/jest-changed-files/node_modules/picomatch": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz",
"integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
"dev": true,
"license": "MIT",
"engines": {
@@ -17547,29 +17235,29 @@
}
},
"node_modules/jest-circus": {
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-30.2.0.tgz",
"integrity": "sha512-Fh0096NC3ZkFx05EP2OXCxJAREVxj1BcW/i6EWqqymcgYKWjyyDpral3fMxVcHXg6oZM7iULer9wGRFvfpl+Tg==",
"version": "30.0.4",
"resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-30.0.4.tgz",
"integrity": "sha512-o6UNVfbXbmzjYgmVPtSQrr5xFZCtkDZGdTlptYvGFSN80RuOOlTe73djvMrs+QAuSERZWcHBNIOMH+OEqvjWuw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/environment": "30.2.0",
"@jest/expect": "30.2.0",
"@jest/test-result": "30.2.0",
"@jest/types": "30.2.0",
"@jest/environment": "30.0.4",
"@jest/expect": "30.0.4",
"@jest/test-result": "30.0.4",
"@jest/types": "30.0.1",
"@types/node": "*",
"chalk": "^4.1.2",
"co": "^4.6.0",
"dedent": "^1.6.0",
"is-generator-fn": "^2.1.0",
"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",
"jest-each": "30.0.2",
"jest-matcher-utils": "30.0.4",
"jest-message-util": "30.0.2",
"jest-runtime": "30.0.4",
"jest-snapshot": "30.0.4",
"jest-util": "30.0.2",
"p-limit": "^3.1.0",
"pretty-format": "30.2.0",
"pretty-format": "30.0.2",
"pure-rand": "^7.0.0",
"slash": "^3.0.0",
"stack-utils": "^2.0.6"
@@ -17579,9 +17267,9 @@
}
},
"node_modules/jest-circus/node_modules/@jest/schemas": {
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz",
"integrity": "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==",
"version": "30.0.1",
"resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.1.tgz",
"integrity": "sha512-+g/1TKjFuGrf1Hh0QPCv0gISwBxJ+MQSNXmG9zjHy7BmFhtoJ9fdNhWJp3qUKRi93AOZHXtdxZgJ1vAtz6z65w==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -17592,14 +17280,14 @@
}
},
"node_modules/jest-circus/node_modules/@jest/types": {
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-30.2.0.tgz",
"integrity": "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg==",
"version": "30.0.1",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-30.0.1.tgz",
"integrity": "sha512-HGwoYRVF0QSKJu1ZQX0o5ZrUrrhj0aOOFA8hXrumD7SIzjouevhawbTjmXdwOmURdGluU9DM/XvGm3NyFoiQjw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/pattern": "30.0.1",
"@jest/schemas": "30.0.5",
"@jest/schemas": "30.0.1",
"@types/istanbul-lib-coverage": "^2.0.6",
"@types/istanbul-reports": "^3.0.4",
"@types/node": "*",
@@ -17611,9 +17299,9 @@
}
},
"node_modules/jest-circus/node_modules/@sinclair/typebox": {
"version": "0.34.41",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.41.tgz",
"integrity": "sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g==",
"version": "0.34.37",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.37.tgz",
"integrity": "sha512-2TRuQVgQYfy+EzHRTIvkhv2ADEouJ2xNS/Vq+W5EuuewBdOrvATvljZTxHWZSTYr2sTjTHpGvucaGAt67S2akw==",
"dev": true,
"license": "MIT"
},
@@ -17631,51 +17319,51 @@
}
},
"node_modules/jest-circus/node_modules/jest-diff": {
"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==",
"version": "30.0.4",
"resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-30.0.4.tgz",
"integrity": "sha512-TSjceIf6797jyd+R64NXqicttROD+Qf98fex7CowmlSn7f8+En0da1Dglwr1AXxDtVizoxXYZBlUQwNhoOXkNw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/diff-sequences": "30.0.1",
"@jest/get-type": "30.1.0",
"@jest/get-type": "30.0.1",
"chalk": "^4.1.2",
"pretty-format": "30.2.0"
"pretty-format": "30.0.2"
},
"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.2.0",
"resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-30.2.0.tgz",
"integrity": "sha512-dQ94Nq4dbzmUWkQ0ANAWS9tBRfqCrn0bV9AMYdOi/MHW726xn7eQmMeRTpX2ViC00bpNaWXq+7o4lIQ3AX13Hg==",
"version": "30.0.4",
"resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-30.0.4.tgz",
"integrity": "sha512-ubCewJ54YzeAZ2JeHHGVoU+eDIpQFsfPQs0xURPWoNiO42LGJ+QGgfSf+hFIRplkZDkhH5MOvuxHKXRTUU3dUQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/get-type": "30.1.0",
"@jest/get-type": "30.0.1",
"chalk": "^4.1.2",
"jest-diff": "30.2.0",
"pretty-format": "30.2.0"
"jest-diff": "30.0.4",
"pretty-format": "30.0.2"
},
"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.2.0",
"resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.2.0.tgz",
"integrity": "sha512-y4DKFLZ2y6DxTWD4cDe07RglV88ZiNEdlRfGtqahfbIjfsw1nMCPx49Uev4IA/hWn3sDKyAnSPwoYSsAEdcimw==",
"version": "30.0.2",
"resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.0.2.tgz",
"integrity": "sha512-vXywcxmr0SsKXF/bAD7t7nMamRvPuJkras00gqYeB1V0WllxZrbZ0paRr3XqpFU2sYYjD0qAaG2fRyn/CGZ0aw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/code-frame": "^7.27.1",
"@jest/types": "30.2.0",
"@jest/types": "30.0.1",
"@types/stack-utils": "^2.0.3",
"chalk": "^4.1.2",
"graceful-fs": "^4.2.11",
"micromatch": "^4.0.8",
"pretty-format": "30.2.0",
"pretty-format": "30.0.2",
"slash": "^3.0.0",
"stack-utils": "^2.0.6"
},
@@ -17684,13 +17372,13 @@
}
},
"node_modules/jest-circus/node_modules/jest-util": {
"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==",
"version": "30.0.2",
"resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.0.2.tgz",
"integrity": "sha512-8IyqfKS4MqprBuUpZNlFB5l+WFehc8bfCe1HSZFHzft2mOuND8Cvi9r1musli+u6F3TqanCZ/Ik4H4pXUolZIg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/types": "30.2.0",
"@jest/types": "30.0.1",
"@types/node": "*",
"chalk": "^4.1.2",
"ci-info": "^4.2.0",
@@ -17702,9 +17390,9 @@
}
},
"node_modules/jest-circus/node_modules/picomatch": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz",
"integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
"dev": true,
"license": "MIT",
"engines": {
@@ -17715,13 +17403,13 @@
}
},
"node_modules/jest-circus/node_modules/pretty-format": {
"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==",
"version": "30.0.2",
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.0.2.tgz",
"integrity": "sha512-yC5/EBSOrTtqhCKfLHqoUIAXVRZnukHPwWBJWR7h84Q3Be1DRQZLncwcfLoPA5RPQ65qfiCMqgYwdUuQ//eVpg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/schemas": "30.0.5",
"@jest/schemas": "30.0.1",
"ansi-styles": "^5.2.0",
"react-is": "^18.3.1"
},
@@ -17747,21 +17435,21 @@
}
},
"node_modules/jest-cli": {
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-30.2.0.tgz",
"integrity": "sha512-Os9ukIvADX/A9sLt6Zse3+nmHtHaE6hqOsjQtNiugFTbKRHYIYtZXNGNK9NChseXy7djFPjndX1tL0sCTlfpAA==",
"version": "30.0.4",
"resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-30.0.4.tgz",
"integrity": "sha512-3dOrP3zqCWBkjoVG1zjYJpD9143N9GUCbwaF2pFF5brnIgRLHmKcCIw+83BvF1LxggfMWBA0gxkn6RuQVuRhIQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/core": "30.2.0",
"@jest/test-result": "30.2.0",
"@jest/types": "30.2.0",
"@jest/core": "30.0.4",
"@jest/test-result": "30.0.4",
"@jest/types": "30.0.1",
"chalk": "^4.1.2",
"exit-x": "^0.2.2",
"import-local": "^3.2.0",
"jest-config": "30.2.0",
"jest-util": "30.2.0",
"jest-validate": "30.2.0",
"jest-config": "30.0.4",
"jest-util": "30.0.2",
"jest-validate": "30.0.2",
"yargs": "^17.7.2"
},
"bin": {
@@ -17780,9 +17468,9 @@
}
},
"node_modules/jest-cli/node_modules/@jest/schemas": {
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz",
"integrity": "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==",
"version": "30.0.1",
"resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.1.tgz",
"integrity": "sha512-+g/1TKjFuGrf1Hh0QPCv0gISwBxJ+MQSNXmG9zjHy7BmFhtoJ9fdNhWJp3qUKRi93AOZHXtdxZgJ1vAtz6z65w==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -17793,14 +17481,14 @@
}
},
"node_modules/jest-cli/node_modules/@jest/types": {
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-30.2.0.tgz",
"integrity": "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg==",
"version": "30.0.1",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-30.0.1.tgz",
"integrity": "sha512-HGwoYRVF0QSKJu1ZQX0o5ZrUrrhj0aOOFA8hXrumD7SIzjouevhawbTjmXdwOmURdGluU9DM/XvGm3NyFoiQjw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/pattern": "30.0.1",
"@jest/schemas": "30.0.5",
"@jest/schemas": "30.0.1",
"@types/istanbul-lib-coverage": "^2.0.6",
"@types/istanbul-reports": "^3.0.4",
"@types/node": "*",
@@ -17812,20 +17500,20 @@
}
},
"node_modules/jest-cli/node_modules/@sinclair/typebox": {
"version": "0.34.41",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.41.tgz",
"integrity": "sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g==",
"version": "0.34.37",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.37.tgz",
"integrity": "sha512-2TRuQVgQYfy+EzHRTIvkhv2ADEouJ2xNS/Vq+W5EuuewBdOrvATvljZTxHWZSTYr2sTjTHpGvucaGAt67S2akw==",
"dev": true,
"license": "MIT"
},
"node_modules/jest-cli/node_modules/jest-util": {
"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==",
"version": "30.0.2",
"resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.0.2.tgz",
"integrity": "sha512-8IyqfKS4MqprBuUpZNlFB5l+WFehc8bfCe1HSZFHzft2mOuND8Cvi9r1musli+u6F3TqanCZ/Ik4H4pXUolZIg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/types": "30.2.0",
"@jest/types": "30.0.1",
"@types/node": "*",
"chalk": "^4.1.2",
"ci-info": "^4.2.0",
@@ -17837,9 +17525,9 @@
}
},
"node_modules/jest-cli/node_modules/picomatch": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz",
"integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
"dev": true,
"license": "MIT",
"engines": {
@@ -17850,34 +17538,34 @@
}
},
"node_modules/jest-config": {
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/jest-config/-/jest-config-30.2.0.tgz",
"integrity": "sha512-g4WkyzFQVWHtu6uqGmQR4CQxz/CH3yDSlhzXMWzNjDx843gYjReZnMRanjRCq5XZFuQrGDxgUaiYWE8BRfVckA==",
"version": "30.0.4",
"resolved": "https://registry.npmjs.org/jest-config/-/jest-config-30.0.4.tgz",
"integrity": "sha512-3dzbO6sh34thAGEjJIW0fgT0GA0EVlkski6ZzMcbW6dzhenylXAE/Mj2MI4HonroWbkKc6wU6bLVQ8dvBSZ9lA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/core": "^7.27.4",
"@jest/get-type": "30.1.0",
"@jest/get-type": "30.0.1",
"@jest/pattern": "30.0.1",
"@jest/test-sequencer": "30.2.0",
"@jest/types": "30.2.0",
"babel-jest": "30.2.0",
"@jest/test-sequencer": "30.0.4",
"@jest/types": "30.0.1",
"babel-jest": "30.0.4",
"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.2.0",
"jest-docblock": "30.2.0",
"jest-environment-node": "30.2.0",
"jest-circus": "30.0.4",
"jest-docblock": "30.0.1",
"jest-environment-node": "30.0.4",
"jest-regex-util": "30.0.1",
"jest-resolve": "30.2.0",
"jest-runner": "30.2.0",
"jest-util": "30.2.0",
"jest-validate": "30.2.0",
"jest-resolve": "30.0.2",
"jest-runner": "30.0.4",
"jest-util": "30.0.2",
"jest-validate": "30.0.2",
"micromatch": "^4.0.8",
"parse-json": "^5.2.0",
"pretty-format": "30.2.0",
"pretty-format": "30.0.2",
"slash": "^3.0.0",
"strip-json-comments": "^3.1.1"
},
@@ -17902,23 +17590,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==",
"version": "7.28.0",
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.0.tgz",
"integrity": "sha512-UlLAnTPrFdNGoFtbSXwcGFQBtQZJCNjaN6hQNP3UPvuNXT1i82N26KL3dZeIpNalWywr9IuQuncaAfUaS1g6sQ==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@ampproject/remapping": "^2.2.0",
"@babel/code-frame": "^7.27.1",
"@babel/generator": "^7.28.3",
"@babel/generator": "^7.28.0",
"@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/helper-module-transforms": "^7.27.3",
"@babel/helpers": "^7.27.6",
"@babel/parser": "^7.28.0",
"@babel/template": "^7.27.2",
"@babel/traverse": "^7.28.4",
"@babel/types": "^7.28.4",
"@jridgewell/remapping": "^2.3.5",
"@babel/traverse": "^7.28.0",
"@babel/types": "^7.28.0",
"convert-source-map": "^2.0.0",
"debug": "^4.1.0",
"gensync": "^1.0.0-beta.2",
@@ -17934,9 +17621,9 @@
}
},
"node_modules/jest-config/node_modules/@jest/schemas": {
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz",
"integrity": "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==",
"version": "30.0.1",
"resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.1.tgz",
"integrity": "sha512-+g/1TKjFuGrf1Hh0QPCv0gISwBxJ+MQSNXmG9zjHy7BmFhtoJ9fdNhWJp3qUKRi93AOZHXtdxZgJ1vAtz6z65w==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -17947,23 +17634,23 @@
}
},
"node_modules/jest-config/node_modules/@jest/transform": {
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/@jest/transform/-/transform-30.2.0.tgz",
"integrity": "sha512-XsauDV82o5qXbhalKxD7p4TZYYdwcaEXC77PPD2HixEFF+6YGppjrAAQurTl2ECWcEomHBMMNS9AH3kcCFx8jA==",
"version": "30.0.4",
"resolved": "https://registry.npmjs.org/@jest/transform/-/transform-30.0.4.tgz",
"integrity": "sha512-atvy4hRph/UxdCIBp+UB2jhEA/jJiUeGZ7QPgBi9jUUKNgi3WEoMXGNG7zbbELG2+88PMabUNCDchmqgJy3ELg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/core": "^7.27.4",
"@jest/types": "30.2.0",
"@jest/types": "30.0.1",
"@jridgewell/trace-mapping": "^0.3.25",
"babel-plugin-istanbul": "^7.0.1",
"babel-plugin-istanbul": "^7.0.0",
"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.2.0",
"jest-haste-map": "30.0.2",
"jest-regex-util": "30.0.1",
"jest-util": "30.2.0",
"jest-util": "30.0.2",
"micromatch": "^4.0.8",
"pirates": "^4.0.7",
"slash": "^3.0.0",
@@ -17974,14 +17661,14 @@
}
},
"node_modules/jest-config/node_modules/@jest/types": {
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-30.2.0.tgz",
"integrity": "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg==",
"version": "30.0.1",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-30.0.1.tgz",
"integrity": "sha512-HGwoYRVF0QSKJu1ZQX0o5ZrUrrhj0aOOFA8hXrumD7SIzjouevhawbTjmXdwOmURdGluU9DM/XvGm3NyFoiQjw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/pattern": "30.0.1",
"@jest/schemas": "30.0.5",
"@jest/schemas": "30.0.1",
"@types/istanbul-lib-coverage": "^2.0.6",
"@types/istanbul-reports": "^3.0.4",
"@types/node": "*",
@@ -17993,9 +17680,9 @@
}
},
"node_modules/jest-config/node_modules/@sinclair/typebox": {
"version": "0.34.41",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.41.tgz",
"integrity": "sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g==",
"version": "0.34.37",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.37.tgz",
"integrity": "sha512-2TRuQVgQYfy+EzHRTIvkhv2ADEouJ2xNS/Vq+W5EuuewBdOrvATvljZTxHWZSTYr2sTjTHpGvucaGAt67S2akw==",
"dev": true,
"license": "MIT"
},
@@ -18013,16 +17700,16 @@
}
},
"node_modules/jest-config/node_modules/babel-jest": {
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-30.2.0.tgz",
"integrity": "sha512-0YiBEOxWqKkSQWL9nNGGEgndoeL0ZpWrbLMNL5u/Kaxrli3Eaxlt3ZtIDktEvXt4L/R9r3ODr2zKwGM/2BjxVw==",
"version": "30.0.4",
"resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-30.0.4.tgz",
"integrity": "sha512-UjG2j7sAOqsp2Xua1mS/e+ekddkSu3wpf4nZUSvXNHuVWdaOUXQ77+uyjJLDE9i0atm5x4kds8K9yb5lRsRtcA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/transform": "30.2.0",
"@jest/transform": "30.0.4",
"@types/babel__core": "^7.20.5",
"babel-plugin-istanbul": "^7.0.1",
"babel-preset-jest": "30.2.0",
"babel-plugin-istanbul": "^7.0.0",
"babel-preset-jest": "30.0.1",
"chalk": "^4.1.2",
"graceful-fs": "^4.2.11",
"slash": "^3.0.0"
@@ -18031,18 +17718,15 @@
"node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
},
"peerDependencies": {
"@babel/core": "^7.11.0 || ^8.0.0-0"
"@babel/core": "^7.11.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==",
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-7.0.0.tgz",
"integrity": "sha512-C5OzENSx/A+gt7t4VH1I2XsflxyPUmXRFPKBxt33xncdOmq7oROVM3bZv9Ysjjkv8OJYDMa+tKuKMvqU/H3xdw==",
"dev": true,
"license": "BSD-3-Clause",
"workspaces": [
"test/babel-8"
],
"dependencies": {
"@babel/helper-plugin-utils": "^7.0.0",
"@istanbuljs/load-nyc-config": "^1.0.0",
@@ -18055,12 +17739,14 @@
}
},
"node_modules/jest-config/node_modules/babel-plugin-jest-hoist": {
"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==",
"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,
"license": "MIT",
"dependencies": {
"@babel/template": "^7.27.2",
"@babel/types": "^7.27.3",
"@types/babel__core": "^7.20.5"
},
"engines": {
@@ -18068,20 +17754,20 @@
}
},
"node_modules/jest-config/node_modules/babel-preset-jest": {
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-30.2.0.tgz",
"integrity": "sha512-US4Z3NOieAQumwFnYdUWKvUKh8+YSnS/gB3t6YBiz0bskpu7Pine8pPCheNxlPEW4wnUkma2a94YuW2q3guvCQ==",
"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,
"license": "MIT",
"dependencies": {
"babel-plugin-jest-hoist": "30.2.0",
"babel-preset-current-node-syntax": "^1.2.0"
"babel-plugin-jest-hoist": "30.0.1",
"babel-preset-current-node-syntax": "^1.1.0"
},
"engines": {
"node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
},
"peerDependencies": {
"@babel/core": "^7.11.0 || ^8.0.0-beta.1"
"@babel/core": "^7.11.0"
}
},
"node_modules/jest-config/node_modules/brace-expansion": {
@@ -18146,20 +17832,20 @@
}
},
"node_modules/jest-config/node_modules/jest-haste-map": {
"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==",
"version": "30.0.2",
"resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-30.0.2.tgz",
"integrity": "sha512-telJBKpNLeCb4MaX+I5k496556Y2FiKR/QLZc0+MGBYl4k3OO0472drlV2LUe7c1Glng5HuAu+5GLYp//GpdOQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/types": "30.2.0",
"@jest/types": "30.0.1",
"@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.2.0",
"jest-worker": "30.2.0",
"jest-util": "30.0.2",
"jest-worker": "30.0.2",
"micromatch": "^4.0.8",
"walker": "^1.0.8"
},
@@ -18181,13 +17867,13 @@
}
},
"node_modules/jest-config/node_modules/jest-util": {
"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==",
"version": "30.0.2",
"resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.0.2.tgz",
"integrity": "sha512-8IyqfKS4MqprBuUpZNlFB5l+WFehc8bfCe1HSZFHzft2mOuND8Cvi9r1musli+u6F3TqanCZ/Ik4H4pXUolZIg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/types": "30.2.0",
"@jest/types": "30.0.1",
"@types/node": "*",
"chalk": "^4.1.2",
"ci-info": "^4.2.0",
@@ -18215,9 +17901,9 @@
}
},
"node_modules/jest-config/node_modules/picomatch": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz",
"integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
"dev": true,
"license": "MIT",
"engines": {
@@ -18228,13 +17914,13 @@
}
},
"node_modules/jest-config/node_modules/pretty-format": {
"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==",
"version": "30.0.2",
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.0.2.tgz",
"integrity": "sha512-yC5/EBSOrTtqhCKfLHqoUIAXVRZnukHPwWBJWR7h84Q3Be1DRQZLncwcfLoPA5RPQ65qfiCMqgYwdUuQ//eVpg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/schemas": "30.0.5",
"@jest/schemas": "30.0.1",
"ansi-styles": "^5.2.0",
"react-is": "^18.3.1"
},
@@ -18338,9 +18024,9 @@
"license": "MIT"
},
"node_modules/jest-docblock": {
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-30.2.0.tgz",
"integrity": "sha512-tR/FFgZKS1CXluOQzZvNH3+0z9jXr3ldGSD8bhyuxvlVUwbeLOGynkunvlTMxchC5urrKndYiwCFC0DLVjpOCA==",
"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,
"license": "MIT",
"dependencies": {
@@ -18351,26 +18037,26 @@
}
},
"node_modules/jest-each": {
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/jest-each/-/jest-each-30.2.0.tgz",
"integrity": "sha512-lpWlJlM7bCUf1mfmuqTA8+j2lNURW9eNafOy99knBM01i5CQeY5UH1vZjgT9071nDJac1M4XsbyI44oNOdhlDQ==",
"version": "30.0.2",
"resolved": "https://registry.npmjs.org/jest-each/-/jest-each-30.0.2.tgz",
"integrity": "sha512-ZFRsTpe5FUWFQ9cWTMguCaiA6kkW5whccPy9JjD1ezxh+mJeqmz8naL8Fl/oSbNJv3rgB0x87WBIkA5CObIUZQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/get-type": "30.1.0",
"@jest/types": "30.2.0",
"@jest/get-type": "30.0.1",
"@jest/types": "30.0.1",
"chalk": "^4.1.2",
"jest-util": "30.2.0",
"pretty-format": "30.2.0"
"jest-util": "30.0.2",
"pretty-format": "30.0.2"
},
"engines": {
"node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
}
},
"node_modules/jest-each/node_modules/@jest/schemas": {
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz",
"integrity": "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==",
"version": "30.0.1",
"resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.1.tgz",
"integrity": "sha512-+g/1TKjFuGrf1Hh0QPCv0gISwBxJ+MQSNXmG9zjHy7BmFhtoJ9fdNhWJp3qUKRi93AOZHXtdxZgJ1vAtz6z65w==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -18381,14 +18067,14 @@
}
},
"node_modules/jest-each/node_modules/@jest/types": {
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-30.2.0.tgz",
"integrity": "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg==",
"version": "30.0.1",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-30.0.1.tgz",
"integrity": "sha512-HGwoYRVF0QSKJu1ZQX0o5ZrUrrhj0aOOFA8hXrumD7SIzjouevhawbTjmXdwOmURdGluU9DM/XvGm3NyFoiQjw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/pattern": "30.0.1",
"@jest/schemas": "30.0.5",
"@jest/schemas": "30.0.1",
"@types/istanbul-lib-coverage": "^2.0.6",
"@types/istanbul-reports": "^3.0.4",
"@types/node": "*",
@@ -18400,9 +18086,9 @@
}
},
"node_modules/jest-each/node_modules/@sinclair/typebox": {
"version": "0.34.41",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.41.tgz",
"integrity": "sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g==",
"version": "0.34.37",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.37.tgz",
"integrity": "sha512-2TRuQVgQYfy+EzHRTIvkhv2ADEouJ2xNS/Vq+W5EuuewBdOrvATvljZTxHWZSTYr2sTjTHpGvucaGAt67S2akw==",
"dev": true,
"license": "MIT"
},
@@ -18420,13 +18106,13 @@
}
},
"node_modules/jest-each/node_modules/jest-util": {
"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==",
"version": "30.0.2",
"resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.0.2.tgz",
"integrity": "sha512-8IyqfKS4MqprBuUpZNlFB5l+WFehc8bfCe1HSZFHzft2mOuND8Cvi9r1musli+u6F3TqanCZ/Ik4H4pXUolZIg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/types": "30.2.0",
"@jest/types": "30.0.1",
"@types/node": "*",
"chalk": "^4.1.2",
"ci-info": "^4.2.0",
@@ -18438,9 +18124,9 @@
}
},
"node_modules/jest-each/node_modules/picomatch": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz",
"integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
"dev": true,
"license": "MIT",
"engines": {
@@ -18451,13 +18137,13 @@
}
},
"node_modules/jest-each/node_modules/pretty-format": {
"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==",
"version": "30.0.2",
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.0.2.tgz",
"integrity": "sha512-yC5/EBSOrTtqhCKfLHqoUIAXVRZnukHPwWBJWR7h84Q3Be1DRQZLncwcfLoPA5RPQ65qfiCMqgYwdUuQ//eVpg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/schemas": "30.0.5",
"@jest/schemas": "30.0.1",
"ansi-styles": "^5.2.0",
"react-is": "^18.3.1"
},
@@ -18560,28 +18246,28 @@
}
},
"node_modules/jest-environment-node": {
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-30.2.0.tgz",
"integrity": "sha512-ElU8v92QJ9UrYsKrxDIKCxu6PfNj4Hdcktcn0JX12zqNdqWHB0N+hwOnnBBXvjLd2vApZtuLUGs1QSY+MsXoNA==",
"version": "30.0.4",
"resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-30.0.4.tgz",
"integrity": "sha512-p+rLEzC2eThXqiNh9GHHTC0OW5Ca4ZfcURp7scPjYBcmgpR9HG6750716GuUipYf2AcThU3k20B31USuiaaIEg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/environment": "30.2.0",
"@jest/fake-timers": "30.2.0",
"@jest/types": "30.2.0",
"@jest/environment": "30.0.4",
"@jest/fake-timers": "30.0.4",
"@jest/types": "30.0.1",
"@types/node": "*",
"jest-mock": "30.2.0",
"jest-util": "30.2.0",
"jest-validate": "30.2.0"
"jest-mock": "30.0.2",
"jest-util": "30.0.2",
"jest-validate": "30.0.2"
},
"engines": {
"node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
}
},
"node_modules/jest-environment-node/node_modules/@jest/schemas": {
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz",
"integrity": "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==",
"version": "30.0.1",
"resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.1.tgz",
"integrity": "sha512-+g/1TKjFuGrf1Hh0QPCv0gISwBxJ+MQSNXmG9zjHy7BmFhtoJ9fdNhWJp3qUKRi93AOZHXtdxZgJ1vAtz6z65w==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -18592,14 +18278,14 @@
}
},
"node_modules/jest-environment-node/node_modules/@jest/types": {
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-30.2.0.tgz",
"integrity": "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg==",
"version": "30.0.1",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-30.0.1.tgz",
"integrity": "sha512-HGwoYRVF0QSKJu1ZQX0o5ZrUrrhj0aOOFA8hXrumD7SIzjouevhawbTjmXdwOmURdGluU9DM/XvGm3NyFoiQjw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/pattern": "30.0.1",
"@jest/schemas": "30.0.5",
"@jest/schemas": "30.0.1",
"@types/istanbul-lib-coverage": "^2.0.6",
"@types/istanbul-reports": "^3.0.4",
"@types/node": "*",
@@ -18611,20 +18297,20 @@
}
},
"node_modules/jest-environment-node/node_modules/@sinclair/typebox": {
"version": "0.34.41",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.41.tgz",
"integrity": "sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g==",
"version": "0.34.37",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.37.tgz",
"integrity": "sha512-2TRuQVgQYfy+EzHRTIvkhv2ADEouJ2xNS/Vq+W5EuuewBdOrvATvljZTxHWZSTYr2sTjTHpGvucaGAt67S2akw==",
"dev": true,
"license": "MIT"
},
"node_modules/jest-environment-node/node_modules/jest-util": {
"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==",
"version": "30.0.2",
"resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.0.2.tgz",
"integrity": "sha512-8IyqfKS4MqprBuUpZNlFB5l+WFehc8bfCe1HSZFHzft2mOuND8Cvi9r1musli+u6F3TqanCZ/Ik4H4pXUolZIg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/types": "30.2.0",
"@jest/types": "30.0.1",
"@types/node": "*",
"chalk": "^4.1.2",
"ci-info": "^4.2.0",
@@ -18636,9 +18322,9 @@
}
},
"node_modules/jest-environment-node/node_modules/picomatch": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz",
"integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
"dev": true,
"license": "MIT",
"engines": {
@@ -18717,23 +18403,23 @@
}
},
"node_modules/jest-leak-detector": {
"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==",
"version": "30.0.2",
"resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-30.0.2.tgz",
"integrity": "sha512-U66sRrAYdALq+2qtKffBLDWsQ/XoNNs2Lcr83sc9lvE/hEpNafJlq2lXCPUBMNqamMECNxSIekLfe69qg4KMIQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/get-type": "30.1.0",
"pretty-format": "30.2.0"
"@jest/get-type": "30.0.1",
"pretty-format": "30.0.2"
},
"engines": {
"node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
}
},
"node_modules/jest-leak-detector/node_modules/@jest/schemas": {
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz",
"integrity": "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==",
"version": "30.0.1",
"resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.1.tgz",
"integrity": "sha512-+g/1TKjFuGrf1Hh0QPCv0gISwBxJ+MQSNXmG9zjHy7BmFhtoJ9fdNhWJp3qUKRi93AOZHXtdxZgJ1vAtz6z65w==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -18744,9 +18430,9 @@
}
},
"node_modules/jest-leak-detector/node_modules/@sinclair/typebox": {
"version": "0.34.41",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.41.tgz",
"integrity": "sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g==",
"version": "0.34.37",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.37.tgz",
"integrity": "sha512-2TRuQVgQYfy+EzHRTIvkhv2ADEouJ2xNS/Vq+W5EuuewBdOrvATvljZTxHWZSTYr2sTjTHpGvucaGAt67S2akw==",
"dev": true,
"license": "MIT"
},
@@ -18764,13 +18450,13 @@
}
},
"node_modules/jest-leak-detector/node_modules/pretty-format": {
"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==",
"version": "30.0.2",
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.0.2.tgz",
"integrity": "sha512-yC5/EBSOrTtqhCKfLHqoUIAXVRZnukHPwWBJWR7h84Q3Be1DRQZLncwcfLoPA5RPQ65qfiCMqgYwdUuQ//eVpg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/schemas": "30.0.5",
"@jest/schemas": "30.0.1",
"ansi-styles": "^5.2.0",
"react-is": "^18.3.1"
},
@@ -18903,24 +18589,24 @@
}
},
"node_modules/jest-mock": {
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-30.2.0.tgz",
"integrity": "sha512-JNNNl2rj4b5ICpmAcq+WbLH83XswjPbjH4T7yvGzfAGCPh1rw+xVNbtk+FnRslvt9lkCcdn9i1oAoKUuFsOxRw==",
"version": "30.0.2",
"resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-30.0.2.tgz",
"integrity": "sha512-PnZOHmqup/9cT/y+pXIVbbi8ID6U1XHRmbvR7MvUy4SLqhCbwpkmXhLbsWbGewHrV5x/1bF7YDjs+x24/QSvFA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/types": "30.2.0",
"@jest/types": "30.0.1",
"@types/node": "*",
"jest-util": "30.2.0"
"jest-util": "30.0.2"
},
"engines": {
"node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
}
},
"node_modules/jest-mock/node_modules/@jest/schemas": {
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz",
"integrity": "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==",
"version": "30.0.1",
"resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.1.tgz",
"integrity": "sha512-+g/1TKjFuGrf1Hh0QPCv0gISwBxJ+MQSNXmG9zjHy7BmFhtoJ9fdNhWJp3qUKRi93AOZHXtdxZgJ1vAtz6z65w==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -18931,14 +18617,14 @@
}
},
"node_modules/jest-mock/node_modules/@jest/types": {
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-30.2.0.tgz",
"integrity": "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg==",
"version": "30.0.1",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-30.0.1.tgz",
"integrity": "sha512-HGwoYRVF0QSKJu1ZQX0o5ZrUrrhj0aOOFA8hXrumD7SIzjouevhawbTjmXdwOmURdGluU9DM/XvGm3NyFoiQjw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/pattern": "30.0.1",
"@jest/schemas": "30.0.5",
"@jest/schemas": "30.0.1",
"@types/istanbul-lib-coverage": "^2.0.6",
"@types/istanbul-reports": "^3.0.4",
"@types/node": "*",
@@ -18950,20 +18636,20 @@
}
},
"node_modules/jest-mock/node_modules/@sinclair/typebox": {
"version": "0.34.41",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.41.tgz",
"integrity": "sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g==",
"version": "0.34.37",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.37.tgz",
"integrity": "sha512-2TRuQVgQYfy+EzHRTIvkhv2ADEouJ2xNS/Vq+W5EuuewBdOrvATvljZTxHWZSTYr2sTjTHpGvucaGAt67S2akw==",
"dev": true,
"license": "MIT"
},
"node_modules/jest-mock/node_modules/jest-util": {
"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==",
"version": "30.0.2",
"resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.0.2.tgz",
"integrity": "sha512-8IyqfKS4MqprBuUpZNlFB5l+WFehc8bfCe1HSZFHzft2mOuND8Cvi9r1musli+u6F3TqanCZ/Ik4H4pXUolZIg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/types": "30.2.0",
"@jest/types": "30.0.1",
"@types/node": "*",
"chalk": "^4.1.2",
"ci-info": "^4.2.0",
@@ -18975,9 +18661,9 @@
}
},
"node_modules/jest-mock/node_modules/picomatch": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz",
"integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
"dev": true,
"license": "MIT",
"engines": {
@@ -19016,18 +18702,18 @@
}
},
"node_modules/jest-resolve": {
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-30.2.0.tgz",
"integrity": "sha512-TCrHSxPlx3tBY3hWNtRQKbtgLhsXa1WmbJEqBlTBrGafd5fiQFByy2GNCEoGR+Tns8d15GaL9cxEzKOO3GEb2A==",
"version": "30.0.2",
"resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-30.0.2.tgz",
"integrity": "sha512-q/XT0XQvRemykZsvRopbG6FQUT6/ra+XV6rPijyjT6D0msOyCvR2A5PlWZLd+fH0U8XWKZfDiAgrUNDNX2BkCw==",
"dev": true,
"license": "MIT",
"dependencies": {
"chalk": "^4.1.2",
"graceful-fs": "^4.2.11",
"jest-haste-map": "30.2.0",
"jest-haste-map": "30.0.2",
"jest-pnp-resolver": "^1.2.3",
"jest-util": "30.2.0",
"jest-validate": "30.2.0",
"jest-util": "30.0.2",
"jest-validate": "30.0.2",
"slash": "^3.0.0",
"unrs-resolver": "^1.7.11"
},
@@ -19036,14 +18722,14 @@
}
},
"node_modules/jest-resolve-dependencies": {
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-30.2.0.tgz",
"integrity": "sha512-xTOIGug/0RmIe3mmCqCT95yO0vj6JURrn1TKWlNbhiAefJRWINNPgwVkrVgt/YaerPzY3iItufd80v3lOrFJ2w==",
"version": "30.0.4",
"resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-30.0.4.tgz",
"integrity": "sha512-EQBYow19B/hKr4gUTn+l8Z+YLlP2X0IoPyp0UydOtrcPbIOYzJ8LKdFd+yrbwztPQvmlBFUwGPPEzHH1bAvFAw==",
"dev": true,
"license": "MIT",
"dependencies": {
"jest-regex-util": "30.0.1",
"jest-snapshot": "30.2.0"
"jest-snapshot": "30.0.4"
},
"engines": {
"node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
@@ -19060,9 +18746,9 @@
}
},
"node_modules/jest-resolve/node_modules/@jest/schemas": {
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz",
"integrity": "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==",
"version": "30.0.1",
"resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.1.tgz",
"integrity": "sha512-+g/1TKjFuGrf1Hh0QPCv0gISwBxJ+MQSNXmG9zjHy7BmFhtoJ9fdNhWJp3qUKRi93AOZHXtdxZgJ1vAtz6z65w==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -19073,14 +18759,14 @@
}
},
"node_modules/jest-resolve/node_modules/@jest/types": {
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-30.2.0.tgz",
"integrity": "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg==",
"version": "30.0.1",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-30.0.1.tgz",
"integrity": "sha512-HGwoYRVF0QSKJu1ZQX0o5ZrUrrhj0aOOFA8hXrumD7SIzjouevhawbTjmXdwOmURdGluU9DM/XvGm3NyFoiQjw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/pattern": "30.0.1",
"@jest/schemas": "30.0.5",
"@jest/schemas": "30.0.1",
"@types/istanbul-lib-coverage": "^2.0.6",
"@types/istanbul-reports": "^3.0.4",
"@types/node": "*",
@@ -19092,27 +18778,27 @@
}
},
"node_modules/jest-resolve/node_modules/@sinclair/typebox": {
"version": "0.34.41",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.41.tgz",
"integrity": "sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g==",
"version": "0.34.37",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.37.tgz",
"integrity": "sha512-2TRuQVgQYfy+EzHRTIvkhv2ADEouJ2xNS/Vq+W5EuuewBdOrvATvljZTxHWZSTYr2sTjTHpGvucaGAt67S2akw==",
"dev": true,
"license": "MIT"
},
"node_modules/jest-resolve/node_modules/jest-haste-map": {
"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==",
"version": "30.0.2",
"resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-30.0.2.tgz",
"integrity": "sha512-telJBKpNLeCb4MaX+I5k496556Y2FiKR/QLZc0+MGBYl4k3OO0472drlV2LUe7c1Glng5HuAu+5GLYp//GpdOQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/types": "30.2.0",
"@jest/types": "30.0.1",
"@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.2.0",
"jest-worker": "30.2.0",
"jest-util": "30.0.2",
"jest-worker": "30.0.2",
"micromatch": "^4.0.8",
"walker": "^1.0.8"
},
@@ -19134,13 +18820,13 @@
}
},
"node_modules/jest-resolve/node_modules/jest-util": {
"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==",
"version": "30.0.2",
"resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.0.2.tgz",
"integrity": "sha512-8IyqfKS4MqprBuUpZNlFB5l+WFehc8bfCe1HSZFHzft2mOuND8Cvi9r1musli+u6F3TqanCZ/Ik4H4pXUolZIg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/types": "30.2.0",
"@jest/types": "30.0.1",
"@types/node": "*",
"chalk": "^4.1.2",
"ci-info": "^4.2.0",
@@ -19152,9 +18838,9 @@
}
},
"node_modules/jest-resolve/node_modules/picomatch": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz",
"integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
"dev": true,
"license": "MIT",
"engines": {
@@ -19175,32 +18861,32 @@
}
},
"node_modules/jest-runner": {
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-30.2.0.tgz",
"integrity": "sha512-PqvZ2B2XEyPEbclp+gV6KO/F1FIFSbIwewRgmROCMBo/aZ6J1w8Qypoj2pEOcg3G2HzLlaP6VUtvwCI8dM3oqQ==",
"version": "30.0.4",
"resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-30.0.4.tgz",
"integrity": "sha512-mxY0vTAEsowJwvFJo5pVivbCpuu6dgdXRmt3v3MXjBxFly7/lTk3Td0PaMyGOeNQUFmSuGEsGYqhbn7PA9OekQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@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",
"@jest/console": "30.0.4",
"@jest/environment": "30.0.4",
"@jest/test-result": "30.0.4",
"@jest/transform": "30.0.4",
"@jest/types": "30.0.1",
"@types/node": "*",
"chalk": "^4.1.2",
"emittery": "^0.13.1",
"exit-x": "^0.2.2",
"graceful-fs": "^4.2.11",
"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",
"jest-docblock": "30.0.1",
"jest-environment-node": "30.0.4",
"jest-haste-map": "30.0.2",
"jest-leak-detector": "30.0.2",
"jest-message-util": "30.0.2",
"jest-resolve": "30.0.2",
"jest-runtime": "30.0.4",
"jest-util": "30.0.2",
"jest-watcher": "30.0.4",
"jest-worker": "30.0.2",
"p-limit": "^3.1.0",
"source-map-support": "0.5.13"
},
@@ -19209,22 +18895,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==",
"version": "7.28.0",
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.0.tgz",
"integrity": "sha512-UlLAnTPrFdNGoFtbSXwcGFQBtQZJCNjaN6hQNP3UPvuNXT1i82N26KL3dZeIpNalWywr9IuQuncaAfUaS1g6sQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@ampproject/remapping": "^2.2.0",
"@babel/code-frame": "^7.27.1",
"@babel/generator": "^7.28.3",
"@babel/generator": "^7.28.0",
"@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/helper-module-transforms": "^7.27.3",
"@babel/helpers": "^7.27.6",
"@babel/parser": "^7.28.0",
"@babel/template": "^7.27.2",
"@babel/traverse": "^7.28.4",
"@babel/types": "^7.28.4",
"@jridgewell/remapping": "^2.3.5",
"@babel/traverse": "^7.28.0",
"@babel/types": "^7.28.0",
"convert-source-map": "^2.0.0",
"debug": "^4.1.0",
"gensync": "^1.0.0-beta.2",
@@ -19240,9 +18926,9 @@
}
},
"node_modules/jest-runner/node_modules/@jest/schemas": {
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz",
"integrity": "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==",
"version": "30.0.1",
"resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.1.tgz",
"integrity": "sha512-+g/1TKjFuGrf1Hh0QPCv0gISwBxJ+MQSNXmG9zjHy7BmFhtoJ9fdNhWJp3qUKRi93AOZHXtdxZgJ1vAtz6z65w==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -19253,23 +18939,23 @@
}
},
"node_modules/jest-runner/node_modules/@jest/transform": {
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/@jest/transform/-/transform-30.2.0.tgz",
"integrity": "sha512-XsauDV82o5qXbhalKxD7p4TZYYdwcaEXC77PPD2HixEFF+6YGppjrAAQurTl2ECWcEomHBMMNS9AH3kcCFx8jA==",
"version": "30.0.4",
"resolved": "https://registry.npmjs.org/@jest/transform/-/transform-30.0.4.tgz",
"integrity": "sha512-atvy4hRph/UxdCIBp+UB2jhEA/jJiUeGZ7QPgBi9jUUKNgi3WEoMXGNG7zbbELG2+88PMabUNCDchmqgJy3ELg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/core": "^7.27.4",
"@jest/types": "30.2.0",
"@jest/types": "30.0.1",
"@jridgewell/trace-mapping": "^0.3.25",
"babel-plugin-istanbul": "^7.0.1",
"babel-plugin-istanbul": "^7.0.0",
"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.2.0",
"jest-haste-map": "30.0.2",
"jest-regex-util": "30.0.1",
"jest-util": "30.2.0",
"jest-util": "30.0.2",
"micromatch": "^4.0.8",
"pirates": "^4.0.7",
"slash": "^3.0.0",
@@ -19280,14 +18966,14 @@
}
},
"node_modules/jest-runner/node_modules/@jest/types": {
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-30.2.0.tgz",
"integrity": "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg==",
"version": "30.0.1",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-30.0.1.tgz",
"integrity": "sha512-HGwoYRVF0QSKJu1ZQX0o5ZrUrrhj0aOOFA8hXrumD7SIzjouevhawbTjmXdwOmURdGluU9DM/XvGm3NyFoiQjw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/pattern": "30.0.1",
"@jest/schemas": "30.0.5",
"@jest/schemas": "30.0.1",
"@types/istanbul-lib-coverage": "^2.0.6",
"@types/istanbul-reports": "^3.0.4",
"@types/node": "*",
@@ -19299,9 +18985,9 @@
}
},
"node_modules/jest-runner/node_modules/@sinclair/typebox": {
"version": "0.34.41",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.41.tgz",
"integrity": "sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g==",
"version": "0.34.37",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.37.tgz",
"integrity": "sha512-2TRuQVgQYfy+EzHRTIvkhv2ADEouJ2xNS/Vq+W5EuuewBdOrvATvljZTxHWZSTYr2sTjTHpGvucaGAt67S2akw==",
"dev": true,
"license": "MIT"
},
@@ -19319,14 +19005,11 @@
}
},
"node_modules/jest-runner/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==",
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-7.0.0.tgz",
"integrity": "sha512-C5OzENSx/A+gt7t4VH1I2XsflxyPUmXRFPKBxt33xncdOmq7oROVM3bZv9Ysjjkv8OJYDMa+tKuKMvqU/H3xdw==",
"dev": true,
"license": "BSD-3-Clause",
"workspaces": [
"test/babel-8"
],
"dependencies": {
"@babel/helper-plugin-utils": "^7.0.0",
"@istanbuljs/load-nyc-config": "^1.0.0",
@@ -19369,20 +19052,20 @@
}
},
"node_modules/jest-runner/node_modules/jest-haste-map": {
"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==",
"version": "30.0.2",
"resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-30.0.2.tgz",
"integrity": "sha512-telJBKpNLeCb4MaX+I5k496556Y2FiKR/QLZc0+MGBYl4k3OO0472drlV2LUe7c1Glng5HuAu+5GLYp//GpdOQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/types": "30.2.0",
"@jest/types": "30.0.1",
"@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.2.0",
"jest-worker": "30.2.0",
"jest-util": "30.0.2",
"jest-worker": "30.0.2",
"micromatch": "^4.0.8",
"walker": "^1.0.8"
},
@@ -19394,19 +19077,19 @@
}
},
"node_modules/jest-runner/node_modules/jest-message-util": {
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.2.0.tgz",
"integrity": "sha512-y4DKFLZ2y6DxTWD4cDe07RglV88ZiNEdlRfGtqahfbIjfsw1nMCPx49Uev4IA/hWn3sDKyAnSPwoYSsAEdcimw==",
"version": "30.0.2",
"resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.0.2.tgz",
"integrity": "sha512-vXywcxmr0SsKXF/bAD7t7nMamRvPuJkras00gqYeB1V0WllxZrbZ0paRr3XqpFU2sYYjD0qAaG2fRyn/CGZ0aw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/code-frame": "^7.27.1",
"@jest/types": "30.2.0",
"@jest/types": "30.0.1",
"@types/stack-utils": "^2.0.3",
"chalk": "^4.1.2",
"graceful-fs": "^4.2.11",
"micromatch": "^4.0.8",
"pretty-format": "30.2.0",
"pretty-format": "30.0.2",
"slash": "^3.0.0",
"stack-utils": "^2.0.6"
},
@@ -19425,13 +19108,13 @@
}
},
"node_modules/jest-runner/node_modules/jest-util": {
"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==",
"version": "30.0.2",
"resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.0.2.tgz",
"integrity": "sha512-8IyqfKS4MqprBuUpZNlFB5l+WFehc8bfCe1HSZFHzft2mOuND8Cvi9r1musli+u6F3TqanCZ/Ik4H4pXUolZIg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/types": "30.2.0",
"@jest/types": "30.0.1",
"@types/node": "*",
"chalk": "^4.1.2",
"ci-info": "^4.2.0",
@@ -19443,9 +19126,9 @@
}
},
"node_modules/jest-runner/node_modules/picomatch": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz",
"integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
"dev": true,
"license": "MIT",
"engines": {
@@ -19456,13 +19139,13 @@
}
},
"node_modules/jest-runner/node_modules/pretty-format": {
"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==",
"version": "30.0.2",
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.0.2.tgz",
"integrity": "sha512-yC5/EBSOrTtqhCKfLHqoUIAXVRZnukHPwWBJWR7h84Q3Be1DRQZLncwcfLoPA5RPQ65qfiCMqgYwdUuQ//eVpg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/schemas": "30.0.5",
"@jest/schemas": "30.0.1",
"ansi-styles": "^5.2.0",
"react-is": "^18.3.1"
},
@@ -19515,32 +19198,32 @@
}
},
"node_modules/jest-runtime": {
"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==",
"version": "30.0.4",
"resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-30.0.4.tgz",
"integrity": "sha512-tUQrZ8+IzoZYIHoPDQEB4jZoPyzBjLjq7sk0KVyd5UPRjRDOsN7o6UlvaGF8ddpGsjznl9PW+KRgWqCNO+Hn7w==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/environment": "30.2.0",
"@jest/fake-timers": "30.2.0",
"@jest/globals": "30.2.0",
"@jest/environment": "30.0.4",
"@jest/fake-timers": "30.0.4",
"@jest/globals": "30.0.4",
"@jest/source-map": "30.0.1",
"@jest/test-result": "30.2.0",
"@jest/transform": "30.2.0",
"@jest/types": "30.2.0",
"@jest/test-result": "30.0.4",
"@jest/transform": "30.0.4",
"@jest/types": "30.0.1",
"@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.2.0",
"jest-message-util": "30.2.0",
"jest-mock": "30.2.0",
"jest-haste-map": "30.0.2",
"jest-message-util": "30.0.2",
"jest-mock": "30.0.2",
"jest-regex-util": "30.0.1",
"jest-resolve": "30.2.0",
"jest-snapshot": "30.2.0",
"jest-util": "30.2.0",
"jest-resolve": "30.0.2",
"jest-snapshot": "30.0.4",
"jest-util": "30.0.2",
"slash": "^3.0.0",
"strip-bom": "^4.0.0"
},
@@ -19549,22 +19232,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==",
"version": "7.28.0",
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.0.tgz",
"integrity": "sha512-UlLAnTPrFdNGoFtbSXwcGFQBtQZJCNjaN6hQNP3UPvuNXT1i82N26KL3dZeIpNalWywr9IuQuncaAfUaS1g6sQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@ampproject/remapping": "^2.2.0",
"@babel/code-frame": "^7.27.1",
"@babel/generator": "^7.28.3",
"@babel/generator": "^7.28.0",
"@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/helper-module-transforms": "^7.27.3",
"@babel/helpers": "^7.27.6",
"@babel/parser": "^7.28.0",
"@babel/template": "^7.27.2",
"@babel/traverse": "^7.28.4",
"@babel/types": "^7.28.4",
"@jridgewell/remapping": "^2.3.5",
"@babel/traverse": "^7.28.0",
"@babel/types": "^7.28.0",
"convert-source-map": "^2.0.0",
"debug": "^4.1.0",
"gensync": "^1.0.0-beta.2",
@@ -19580,9 +19263,9 @@
}
},
"node_modules/jest-runtime/node_modules/@jest/schemas": {
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz",
"integrity": "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==",
"version": "30.0.1",
"resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.1.tgz",
"integrity": "sha512-+g/1TKjFuGrf1Hh0QPCv0gISwBxJ+MQSNXmG9zjHy7BmFhtoJ9fdNhWJp3qUKRi93AOZHXtdxZgJ1vAtz6z65w==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -19593,23 +19276,23 @@
}
},
"node_modules/jest-runtime/node_modules/@jest/transform": {
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/@jest/transform/-/transform-30.2.0.tgz",
"integrity": "sha512-XsauDV82o5qXbhalKxD7p4TZYYdwcaEXC77PPD2HixEFF+6YGppjrAAQurTl2ECWcEomHBMMNS9AH3kcCFx8jA==",
"version": "30.0.4",
"resolved": "https://registry.npmjs.org/@jest/transform/-/transform-30.0.4.tgz",
"integrity": "sha512-atvy4hRph/UxdCIBp+UB2jhEA/jJiUeGZ7QPgBi9jUUKNgi3WEoMXGNG7zbbELG2+88PMabUNCDchmqgJy3ELg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/core": "^7.27.4",
"@jest/types": "30.2.0",
"@jest/types": "30.0.1",
"@jridgewell/trace-mapping": "^0.3.25",
"babel-plugin-istanbul": "^7.0.1",
"babel-plugin-istanbul": "^7.0.0",
"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.2.0",
"jest-haste-map": "30.0.2",
"jest-regex-util": "30.0.1",
"jest-util": "30.2.0",
"jest-util": "30.0.2",
"micromatch": "^4.0.8",
"pirates": "^4.0.7",
"slash": "^3.0.0",
@@ -19620,14 +19303,14 @@
}
},
"node_modules/jest-runtime/node_modules/@jest/types": {
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-30.2.0.tgz",
"integrity": "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg==",
"version": "30.0.1",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-30.0.1.tgz",
"integrity": "sha512-HGwoYRVF0QSKJu1ZQX0o5ZrUrrhj0aOOFA8hXrumD7SIzjouevhawbTjmXdwOmURdGluU9DM/XvGm3NyFoiQjw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/pattern": "30.0.1",
"@jest/schemas": "30.0.5",
"@jest/schemas": "30.0.1",
"@types/istanbul-lib-coverage": "^2.0.6",
"@types/istanbul-reports": "^3.0.4",
"@types/node": "*",
@@ -19639,9 +19322,9 @@
}
},
"node_modules/jest-runtime/node_modules/@sinclair/typebox": {
"version": "0.34.41",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.41.tgz",
"integrity": "sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g==",
"version": "0.34.37",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.37.tgz",
"integrity": "sha512-2TRuQVgQYfy+EzHRTIvkhv2ADEouJ2xNS/Vq+W5EuuewBdOrvATvljZTxHWZSTYr2sTjTHpGvucaGAt67S2akw==",
"dev": true,
"license": "MIT"
},
@@ -19659,14 +19342,11 @@
}
},
"node_modules/jest-runtime/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==",
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-7.0.0.tgz",
"integrity": "sha512-C5OzENSx/A+gt7t4VH1I2XsflxyPUmXRFPKBxt33xncdOmq7oROVM3bZv9Ysjjkv8OJYDMa+tKuKMvqU/H3xdw==",
"dev": true,
"license": "BSD-3-Clause",
"workspaces": [
"test/babel-8"
],
"dependencies": {
"@babel/helper-plugin-utils": "^7.0.0",
"@istanbuljs/load-nyc-config": "^1.0.0",
@@ -19740,20 +19420,20 @@
}
},
"node_modules/jest-runtime/node_modules/jest-haste-map": {
"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==",
"version": "30.0.2",
"resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-30.0.2.tgz",
"integrity": "sha512-telJBKpNLeCb4MaX+I5k496556Y2FiKR/QLZc0+MGBYl4k3OO0472drlV2LUe7c1Glng5HuAu+5GLYp//GpdOQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/types": "30.2.0",
"@jest/types": "30.0.1",
"@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.2.0",
"jest-worker": "30.2.0",
"jest-util": "30.0.2",
"jest-worker": "30.0.2",
"micromatch": "^4.0.8",
"walker": "^1.0.8"
},
@@ -19765,19 +19445,19 @@
}
},
"node_modules/jest-runtime/node_modules/jest-message-util": {
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.2.0.tgz",
"integrity": "sha512-y4DKFLZ2y6DxTWD4cDe07RglV88ZiNEdlRfGtqahfbIjfsw1nMCPx49Uev4IA/hWn3sDKyAnSPwoYSsAEdcimw==",
"version": "30.0.2",
"resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.0.2.tgz",
"integrity": "sha512-vXywcxmr0SsKXF/bAD7t7nMamRvPuJkras00gqYeB1V0WllxZrbZ0paRr3XqpFU2sYYjD0qAaG2fRyn/CGZ0aw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/code-frame": "^7.27.1",
"@jest/types": "30.2.0",
"@jest/types": "30.0.1",
"@types/stack-utils": "^2.0.3",
"chalk": "^4.1.2",
"graceful-fs": "^4.2.11",
"micromatch": "^4.0.8",
"pretty-format": "30.2.0",
"pretty-format": "30.0.2",
"slash": "^3.0.0",
"stack-utils": "^2.0.6"
},
@@ -19796,13 +19476,13 @@
}
},
"node_modules/jest-runtime/node_modules/jest-util": {
"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==",
"version": "30.0.2",
"resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.0.2.tgz",
"integrity": "sha512-8IyqfKS4MqprBuUpZNlFB5l+WFehc8bfCe1HSZFHzft2mOuND8Cvi9r1musli+u6F3TqanCZ/Ik4H4pXUolZIg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/types": "30.2.0",
"@jest/types": "30.0.1",
"@types/node": "*",
"chalk": "^4.1.2",
"ci-info": "^4.2.0",
@@ -19830,9 +19510,9 @@
}
},
"node_modules/jest-runtime/node_modules/picomatch": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz",
"integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
"dev": true,
"license": "MIT",
"engines": {
@@ -19843,13 +19523,13 @@
}
},
"node_modules/jest-runtime/node_modules/pretty-format": {
"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==",
"version": "30.0.2",
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.0.2.tgz",
"integrity": "sha512-yC5/EBSOrTtqhCKfLHqoUIAXVRZnukHPwWBJWR7h84Q3Be1DRQZLncwcfLoPA5RPQ65qfiCMqgYwdUuQ//eVpg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/schemas": "30.0.5",
"@jest/schemas": "30.0.1",
"ansi-styles": "^5.2.0",
"react-is": "^18.3.1"
},
@@ -19902,9 +19582,9 @@
}
},
"node_modules/jest-snapshot": {
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-30.2.0.tgz",
"integrity": "sha512-5WEtTy2jXPFypadKNpbNkZ72puZCa6UjSr/7djeecHWOu7iYhSXSnHScT8wBz3Rn8Ena5d5RYRcsyKIeqG1IyA==",
"version": "30.0.4",
"resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-30.0.4.tgz",
"integrity": "sha512-S/8hmSkeUib8WRUq9pWEb5zMfsOjiYWDWzFzKnjX7eDyKKgimsu9hcmsUEg8a7dPAw8s/FacxsXquq71pDgPjQ==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -19913,20 +19593,20 @@
"@babel/plugin-syntax-jsx": "^7.27.1",
"@babel/plugin-syntax-typescript": "^7.27.1",
"@babel/types": "^7.27.3",
"@jest/expect-utils": "30.2.0",
"@jest/get-type": "30.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",
"@jest/expect-utils": "30.0.4",
"@jest/get-type": "30.0.1",
"@jest/snapshot-utils": "30.0.4",
"@jest/transform": "30.0.4",
"@jest/types": "30.0.1",
"babel-preset-current-node-syntax": "^1.1.0",
"chalk": "^4.1.2",
"expect": "30.2.0",
"expect": "30.0.4",
"graceful-fs": "^4.2.11",
"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",
"jest-diff": "30.0.4",
"jest-matcher-utils": "30.0.4",
"jest-message-util": "30.0.2",
"jest-util": "30.0.2",
"pretty-format": "30.0.2",
"semver": "^7.7.2",
"synckit": "^0.11.8"
},
@@ -19935,22 +19615,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==",
"version": "7.28.0",
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.0.tgz",
"integrity": "sha512-UlLAnTPrFdNGoFtbSXwcGFQBtQZJCNjaN6hQNP3UPvuNXT1i82N26KL3dZeIpNalWywr9IuQuncaAfUaS1g6sQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@ampproject/remapping": "^2.2.0",
"@babel/code-frame": "^7.27.1",
"@babel/generator": "^7.28.3",
"@babel/generator": "^7.28.0",
"@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/helper-module-transforms": "^7.27.3",
"@babel/helpers": "^7.27.6",
"@babel/parser": "^7.28.0",
"@babel/template": "^7.27.2",
"@babel/traverse": "^7.28.4",
"@babel/types": "^7.28.4",
"@jridgewell/remapping": "^2.3.5",
"@babel/traverse": "^7.28.0",
"@babel/types": "^7.28.0",
"convert-source-map": "^2.0.0",
"debug": "^4.1.0",
"gensync": "^1.0.0-beta.2",
@@ -19976,22 +19656,22 @@
}
},
"node_modules/jest-snapshot/node_modules/@jest/expect-utils": {
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-30.2.0.tgz",
"integrity": "sha512-1JnRfhqpD8HGpOmQp180Fo9Zt69zNtC+9lR+kT7NVL05tNXIi+QC8Csz7lfidMoVLPD3FnOtcmp0CEFnxExGEA==",
"version": "30.0.4",
"resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-30.0.4.tgz",
"integrity": "sha512-EgXecHDNfANeqOkcak0DxsoVI4qkDUsR7n/Lr2vtmTBjwLPBnnPOF71S11Q8IObWzxm2QgQoY6f9hzrRD3gHRA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/get-type": "30.1.0"
"@jest/get-type": "30.0.1"
},
"engines": {
"node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
}
},
"node_modules/jest-snapshot/node_modules/@jest/schemas": {
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz",
"integrity": "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==",
"version": "30.0.1",
"resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.1.tgz",
"integrity": "sha512-+g/1TKjFuGrf1Hh0QPCv0gISwBxJ+MQSNXmG9zjHy7BmFhtoJ9fdNhWJp3qUKRi93AOZHXtdxZgJ1vAtz6z65w==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -20002,23 +19682,23 @@
}
},
"node_modules/jest-snapshot/node_modules/@jest/transform": {
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/@jest/transform/-/transform-30.2.0.tgz",
"integrity": "sha512-XsauDV82o5qXbhalKxD7p4TZYYdwcaEXC77PPD2HixEFF+6YGppjrAAQurTl2ECWcEomHBMMNS9AH3kcCFx8jA==",
"version": "30.0.4",
"resolved": "https://registry.npmjs.org/@jest/transform/-/transform-30.0.4.tgz",
"integrity": "sha512-atvy4hRph/UxdCIBp+UB2jhEA/jJiUeGZ7QPgBi9jUUKNgi3WEoMXGNG7zbbELG2+88PMabUNCDchmqgJy3ELg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/core": "^7.27.4",
"@jest/types": "30.2.0",
"@jest/types": "30.0.1",
"@jridgewell/trace-mapping": "^0.3.25",
"babel-plugin-istanbul": "^7.0.1",
"babel-plugin-istanbul": "^7.0.0",
"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.2.0",
"jest-haste-map": "30.0.2",
"jest-regex-util": "30.0.1",
"jest-util": "30.2.0",
"jest-util": "30.0.2",
"micromatch": "^4.0.8",
"pirates": "^4.0.7",
"slash": "^3.0.0",
@@ -20029,14 +19709,14 @@
}
},
"node_modules/jest-snapshot/node_modules/@jest/types": {
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-30.2.0.tgz",
"integrity": "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg==",
"version": "30.0.1",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-30.0.1.tgz",
"integrity": "sha512-HGwoYRVF0QSKJu1ZQX0o5ZrUrrhj0aOOFA8hXrumD7SIzjouevhawbTjmXdwOmURdGluU9DM/XvGm3NyFoiQjw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/pattern": "30.0.1",
"@jest/schemas": "30.0.5",
"@jest/schemas": "30.0.1",
"@types/istanbul-lib-coverage": "^2.0.6",
"@types/istanbul-reports": "^3.0.4",
"@types/node": "*",
@@ -20048,9 +19728,9 @@
}
},
"node_modules/jest-snapshot/node_modules/@sinclair/typebox": {
"version": "0.34.41",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.41.tgz",
"integrity": "sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g==",
"version": "0.34.37",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.37.tgz",
"integrity": "sha512-2TRuQVgQYfy+EzHRTIvkhv2ADEouJ2xNS/Vq+W5EuuewBdOrvATvljZTxHWZSTYr2sTjTHpGvucaGAt67S2akw==",
"dev": true,
"license": "MIT"
},
@@ -20068,14 +19748,11 @@
}
},
"node_modules/jest-snapshot/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==",
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-7.0.0.tgz",
"integrity": "sha512-C5OzENSx/A+gt7t4VH1I2XsflxyPUmXRFPKBxt33xncdOmq7oROVM3bZv9Ysjjkv8OJYDMa+tKuKMvqU/H3xdw==",
"dev": true,
"license": "BSD-3-Clause",
"workspaces": [
"test/babel-8"
],
"dependencies": {
"@babel/helper-plugin-utils": "^7.0.0",
"@istanbuljs/load-nyc-config": "^1.0.0",
@@ -20088,18 +19765,18 @@
}
},
"node_modules/jest-snapshot/node_modules/expect": {
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/expect/-/expect-30.2.0.tgz",
"integrity": "sha512-u/feCi0GPsI+988gU2FLcsHyAHTU0MX1Wg68NhAnN7z/+C5wqG+CY8J53N9ioe8RXgaoz0nBR/TYMf3AycUuPw==",
"version": "30.0.4",
"resolved": "https://registry.npmjs.org/expect/-/expect-30.0.4.tgz",
"integrity": "sha512-dDLGjnP2cKbEppxVICxI/Uf4YemmGMPNy0QytCbfafbpYk9AFQsxb8Uyrxii0RPK7FWgLGlSem+07WirwS3cFQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/expect-utils": "30.2.0",
"@jest/get-type": "30.1.0",
"jest-matcher-utils": "30.2.0",
"jest-message-util": "30.2.0",
"jest-mock": "30.2.0",
"jest-util": "30.2.0"
"@jest/expect-utils": "30.0.4",
"@jest/get-type": "30.0.1",
"jest-matcher-utils": "30.0.4",
"jest-message-util": "30.0.2",
"jest-mock": "30.0.2",
"jest-util": "30.0.2"
},
"engines": {
"node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
@@ -20123,36 +19800,36 @@
}
},
"node_modules/jest-snapshot/node_modules/jest-diff": {
"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==",
"version": "30.0.4",
"resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-30.0.4.tgz",
"integrity": "sha512-TSjceIf6797jyd+R64NXqicttROD+Qf98fex7CowmlSn7f8+En0da1Dglwr1AXxDtVizoxXYZBlUQwNhoOXkNw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/diff-sequences": "30.0.1",
"@jest/get-type": "30.1.0",
"@jest/get-type": "30.0.1",
"chalk": "^4.1.2",
"pretty-format": "30.2.0"
"pretty-format": "30.0.2"
},
"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.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==",
"version": "30.0.2",
"resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-30.0.2.tgz",
"integrity": "sha512-telJBKpNLeCb4MaX+I5k496556Y2FiKR/QLZc0+MGBYl4k3OO0472drlV2LUe7c1Glng5HuAu+5GLYp//GpdOQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/types": "30.2.0",
"@jest/types": "30.0.1",
"@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.2.0",
"jest-worker": "30.2.0",
"jest-util": "30.0.2",
"jest-worker": "30.0.2",
"micromatch": "^4.0.8",
"walker": "^1.0.8"
},
@@ -20164,35 +19841,35 @@
}
},
"node_modules/jest-snapshot/node_modules/jest-matcher-utils": {
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-30.2.0.tgz",
"integrity": "sha512-dQ94Nq4dbzmUWkQ0ANAWS9tBRfqCrn0bV9AMYdOi/MHW726xn7eQmMeRTpX2ViC00bpNaWXq+7o4lIQ3AX13Hg==",
"version": "30.0.4",
"resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-30.0.4.tgz",
"integrity": "sha512-ubCewJ54YzeAZ2JeHHGVoU+eDIpQFsfPQs0xURPWoNiO42LGJ+QGgfSf+hFIRplkZDkhH5MOvuxHKXRTUU3dUQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/get-type": "30.1.0",
"@jest/get-type": "30.0.1",
"chalk": "^4.1.2",
"jest-diff": "30.2.0",
"pretty-format": "30.2.0"
"jest-diff": "30.0.4",
"pretty-format": "30.0.2"
},
"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.2.0",
"resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.2.0.tgz",
"integrity": "sha512-y4DKFLZ2y6DxTWD4cDe07RglV88ZiNEdlRfGtqahfbIjfsw1nMCPx49Uev4IA/hWn3sDKyAnSPwoYSsAEdcimw==",
"version": "30.0.2",
"resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.0.2.tgz",
"integrity": "sha512-vXywcxmr0SsKXF/bAD7t7nMamRvPuJkras00gqYeB1V0WllxZrbZ0paRr3XqpFU2sYYjD0qAaG2fRyn/CGZ0aw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/code-frame": "^7.27.1",
"@jest/types": "30.2.0",
"@jest/types": "30.0.1",
"@types/stack-utils": "^2.0.3",
"chalk": "^4.1.2",
"graceful-fs": "^4.2.11",
"micromatch": "^4.0.8",
"pretty-format": "30.2.0",
"pretty-format": "30.0.2",
"slash": "^3.0.0",
"stack-utils": "^2.0.6"
},
@@ -20211,13 +19888,13 @@
}
},
"node_modules/jest-snapshot/node_modules/jest-util": {
"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==",
"version": "30.0.2",
"resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.0.2.tgz",
"integrity": "sha512-8IyqfKS4MqprBuUpZNlFB5l+WFehc8bfCe1HSZFHzft2mOuND8Cvi9r1musli+u6F3TqanCZ/Ik4H4pXUolZIg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/types": "30.2.0",
"@jest/types": "30.0.1",
"@types/node": "*",
"chalk": "^4.1.2",
"ci-info": "^4.2.0",
@@ -20229,9 +19906,9 @@
}
},
"node_modules/jest-snapshot/node_modules/picomatch": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz",
"integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
"dev": true,
"license": "MIT",
"engines": {
@@ -20242,13 +19919,13 @@
}
},
"node_modules/jest-snapshot/node_modules/pretty-format": {
"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==",
"version": "30.0.2",
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.0.2.tgz",
"integrity": "sha512-yC5/EBSOrTtqhCKfLHqoUIAXVRZnukHPwWBJWR7h84Q3Be1DRQZLncwcfLoPA5RPQ65qfiCMqgYwdUuQ//eVpg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/schemas": "30.0.5",
"@jest/schemas": "30.0.1",
"ansi-styles": "^5.2.0",
"react-is": "^18.3.1"
},
@@ -20348,27 +20025,27 @@
}
},
"node_modules/jest-validate": {
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-30.2.0.tgz",
"integrity": "sha512-FBGWi7dP2hpdi8nBoWxSsLvBFewKAg0+uSQwBaof4Y4DPgBabXgpSYC5/lR7VmnIlSpASmCi/ntRWPbv7089Pw==",
"version": "30.0.2",
"resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-30.0.2.tgz",
"integrity": "sha512-noOvul+SFER4RIvNAwGn6nmV2fXqBq67j+hKGHKGFCmK4ks/Iy1FSrqQNBLGKlu4ZZIRL6Kg1U72N1nxuRCrGQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/get-type": "30.1.0",
"@jest/types": "30.2.0",
"@jest/get-type": "30.0.1",
"@jest/types": "30.0.1",
"camelcase": "^6.3.0",
"chalk": "^4.1.2",
"leven": "^3.1.0",
"pretty-format": "30.2.0"
"pretty-format": "30.0.2"
},
"engines": {
"node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
}
},
"node_modules/jest-validate/node_modules/@jest/schemas": {
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz",
"integrity": "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==",
"version": "30.0.1",
"resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.1.tgz",
"integrity": "sha512-+g/1TKjFuGrf1Hh0QPCv0gISwBxJ+MQSNXmG9zjHy7BmFhtoJ9fdNhWJp3qUKRi93AOZHXtdxZgJ1vAtz6z65w==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -20379,14 +20056,14 @@
}
},
"node_modules/jest-validate/node_modules/@jest/types": {
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-30.2.0.tgz",
"integrity": "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg==",
"version": "30.0.1",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-30.0.1.tgz",
"integrity": "sha512-HGwoYRVF0QSKJu1ZQX0o5ZrUrrhj0aOOFA8hXrumD7SIzjouevhawbTjmXdwOmURdGluU9DM/XvGm3NyFoiQjw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/pattern": "30.0.1",
"@jest/schemas": "30.0.5",
"@jest/schemas": "30.0.1",
"@types/istanbul-lib-coverage": "^2.0.6",
"@types/istanbul-reports": "^3.0.4",
"@types/node": "*",
@@ -20398,9 +20075,9 @@
}
},
"node_modules/jest-validate/node_modules/@sinclair/typebox": {
"version": "0.34.41",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.41.tgz",
"integrity": "sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g==",
"version": "0.34.37",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.37.tgz",
"integrity": "sha512-2TRuQVgQYfy+EzHRTIvkhv2ADEouJ2xNS/Vq+W5EuuewBdOrvATvljZTxHWZSTYr2sTjTHpGvucaGAt67S2akw==",
"dev": true,
"license": "MIT"
},
@@ -20418,13 +20095,13 @@
}
},
"node_modules/jest-validate/node_modules/pretty-format": {
"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==",
"version": "30.0.2",
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.0.2.tgz",
"integrity": "sha512-yC5/EBSOrTtqhCKfLHqoUIAXVRZnukHPwWBJWR7h84Q3Be1DRQZLncwcfLoPA5RPQ65qfiCMqgYwdUuQ//eVpg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/schemas": "30.0.5",
"@jest/schemas": "30.0.1",
"ansi-styles": "^5.2.0",
"react-is": "^18.3.1"
},
@@ -20440,19 +20117,19 @@
"license": "MIT"
},
"node_modules/jest-watcher": {
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-30.2.0.tgz",
"integrity": "sha512-PYxa28dxJ9g777pGm/7PrbnMeA0Jr7osHP9bS7eJy9DuAjMgdGtxgf0uKMyoIsTWAkIbUW5hSDdJ3urmgXBqxg==",
"version": "30.0.4",
"resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-30.0.4.tgz",
"integrity": "sha512-YESbdHDs7aQOCSSKffG8jXqOKFqw4q4YqR+wHYpR5GWEQioGvL0BfbcjvKIvPEM0XGfsfJrka7jJz3Cc3gI4VQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/test-result": "30.2.0",
"@jest/types": "30.2.0",
"@jest/test-result": "30.0.4",
"@jest/types": "30.0.1",
"@types/node": "*",
"ansi-escapes": "^4.3.2",
"chalk": "^4.1.2",
"emittery": "^0.13.1",
"jest-util": "30.2.0",
"jest-util": "30.0.2",
"string-length": "^4.0.2"
},
"engines": {
@@ -20460,9 +20137,9 @@
}
},
"node_modules/jest-watcher/node_modules/@jest/schemas": {
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz",
"integrity": "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==",
"version": "30.0.1",
"resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.1.tgz",
"integrity": "sha512-+g/1TKjFuGrf1Hh0QPCv0gISwBxJ+MQSNXmG9zjHy7BmFhtoJ9fdNhWJp3qUKRi93AOZHXtdxZgJ1vAtz6z65w==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -20473,14 +20150,14 @@
}
},
"node_modules/jest-watcher/node_modules/@jest/types": {
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-30.2.0.tgz",
"integrity": "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg==",
"version": "30.0.1",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-30.0.1.tgz",
"integrity": "sha512-HGwoYRVF0QSKJu1ZQX0o5ZrUrrhj0aOOFA8hXrumD7SIzjouevhawbTjmXdwOmURdGluU9DM/XvGm3NyFoiQjw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/pattern": "30.0.1",
"@jest/schemas": "30.0.5",
"@jest/schemas": "30.0.1",
"@types/istanbul-lib-coverage": "^2.0.6",
"@types/istanbul-reports": "^3.0.4",
"@types/node": "*",
@@ -20492,20 +20169,20 @@
}
},
"node_modules/jest-watcher/node_modules/@sinclair/typebox": {
"version": "0.34.41",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.41.tgz",
"integrity": "sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g==",
"version": "0.34.37",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.37.tgz",
"integrity": "sha512-2TRuQVgQYfy+EzHRTIvkhv2ADEouJ2xNS/Vq+W5EuuewBdOrvATvljZTxHWZSTYr2sTjTHpGvucaGAt67S2akw==",
"dev": true,
"license": "MIT"
},
"node_modules/jest-watcher/node_modules/jest-util": {
"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==",
"version": "30.0.2",
"resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.0.2.tgz",
"integrity": "sha512-8IyqfKS4MqprBuUpZNlFB5l+WFehc8bfCe1HSZFHzft2mOuND8Cvi9r1musli+u6F3TqanCZ/Ik4H4pXUolZIg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/types": "30.2.0",
"@jest/types": "30.0.1",
"@types/node": "*",
"chalk": "^4.1.2",
"ci-info": "^4.2.0",
@@ -20517,9 +20194,9 @@
}
},
"node_modules/jest-watcher/node_modules/picomatch": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz",
"integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
"dev": true,
"license": "MIT",
"engines": {
@@ -20530,15 +20207,15 @@
}
},
"node_modules/jest-worker": {
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-30.2.0.tgz",
"integrity": "sha512-0Q4Uk8WF7BUwqXHuAjc23vmopWJw5WH7w2tqBoUOZpOjW/ZnR44GXXd1r82RvnmI2GZge3ivrYXk/BE2+VtW2g==",
"version": "30.0.2",
"resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-30.0.2.tgz",
"integrity": "sha512-RN1eQmx7qSLFA+o9pfJKlqViwL5wt+OL3Vff/A+/cPsmuw7NPwfgl33AP+/agRmHzPOFgXviRycR9kYwlcRQXg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/node": "*",
"@ungap/structured-clone": "^1.3.0",
"jest-util": "30.2.0",
"jest-util": "30.0.2",
"merge-stream": "^2.0.0",
"supports-color": "^8.1.1"
},
@@ -20547,9 +20224,9 @@
}
},
"node_modules/jest-worker/node_modules/@jest/schemas": {
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz",
"integrity": "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==",
"version": "30.0.1",
"resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.1.tgz",
"integrity": "sha512-+g/1TKjFuGrf1Hh0QPCv0gISwBxJ+MQSNXmG9zjHy7BmFhtoJ9fdNhWJp3qUKRi93AOZHXtdxZgJ1vAtz6z65w==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -20560,14 +20237,14 @@
}
},
"node_modules/jest-worker/node_modules/@jest/types": {
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-30.2.0.tgz",
"integrity": "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg==",
"version": "30.0.1",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-30.0.1.tgz",
"integrity": "sha512-HGwoYRVF0QSKJu1ZQX0o5ZrUrrhj0aOOFA8hXrumD7SIzjouevhawbTjmXdwOmURdGluU9DM/XvGm3NyFoiQjw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/pattern": "30.0.1",
"@jest/schemas": "30.0.5",
"@jest/schemas": "30.0.1",
"@types/istanbul-lib-coverage": "^2.0.6",
"@types/istanbul-reports": "^3.0.4",
"@types/node": "*",
@@ -20579,20 +20256,20 @@
}
},
"node_modules/jest-worker/node_modules/@sinclair/typebox": {
"version": "0.34.41",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.41.tgz",
"integrity": "sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g==",
"version": "0.34.37",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.37.tgz",
"integrity": "sha512-2TRuQVgQYfy+EzHRTIvkhv2ADEouJ2xNS/Vq+W5EuuewBdOrvATvljZTxHWZSTYr2sTjTHpGvucaGAt67S2akw==",
"dev": true,
"license": "MIT"
},
"node_modules/jest-worker/node_modules/jest-util": {
"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==",
"version": "30.0.2",
"resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.0.2.tgz",
"integrity": "sha512-8IyqfKS4MqprBuUpZNlFB5l+WFehc8bfCe1HSZFHzft2mOuND8Cvi9r1musli+u6F3TqanCZ/Ik4H4pXUolZIg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/types": "30.2.0",
"@jest/types": "30.0.1",
"@types/node": "*",
"chalk": "^4.1.2",
"ci-info": "^4.2.0",
@@ -20604,9 +20281,9 @@
}
},
"node_modules/jest-worker/node_modules/picomatch": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz",
"integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
"dev": true,
"license": "MIT",
"engines": {
@@ -20633,9 +20310,9 @@
}
},
"node_modules/jest/node_modules/@jest/schemas": {
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz",
"integrity": "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==",
"version": "30.0.1",
"resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.1.tgz",
"integrity": "sha512-+g/1TKjFuGrf1Hh0QPCv0gISwBxJ+MQSNXmG9zjHy7BmFhtoJ9fdNhWJp3qUKRi93AOZHXtdxZgJ1vAtz6z65w==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -20646,14 +20323,14 @@
}
},
"node_modules/jest/node_modules/@jest/types": {
"version": "30.2.0",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-30.2.0.tgz",
"integrity": "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg==",
"version": "30.0.1",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-30.0.1.tgz",
"integrity": "sha512-HGwoYRVF0QSKJu1ZQX0o5ZrUrrhj0aOOFA8hXrumD7SIzjouevhawbTjmXdwOmURdGluU9DM/XvGm3NyFoiQjw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/pattern": "30.0.1",
"@jest/schemas": "30.0.5",
"@jest/schemas": "30.0.1",
"@types/istanbul-lib-coverage": "^2.0.6",
"@types/istanbul-reports": "^3.0.4",
"@types/node": "*",
@@ -20665,9 +20342,9 @@
}
},
"node_modules/jest/node_modules/@sinclair/typebox": {
"version": "0.34.41",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.41.tgz",
"integrity": "sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g==",
"version": "0.34.37",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.37.tgz",
"integrity": "sha512-2TRuQVgQYfy+EzHRTIvkhv2ADEouJ2xNS/Vq+W5EuuewBdOrvATvljZTxHWZSTYr2sTjTHpGvucaGAt67S2akw==",
"dev": true,
"license": "MIT"
},
@@ -20695,9 +20372,9 @@
"license": "MIT"
},
"node_modules/js-toml": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/js-toml/-/js-toml-1.0.2.tgz",
"integrity": "sha512-/7IQ//bzn2a/5IDazPUNzlW7bsjxS51cxciYZDR+Z+3Le60yzT0YfI8KOWqTtBcZkXXVklhWd2OuGd8ZksB0wQ==",
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/js-toml/-/js-toml-1.0.1.tgz",
"integrity": "sha512-rHd/IolpFm2V5BmHCEY8CckHs8NDsYZZ64H5RNgA6Opsr9vX4QyTiQPplgtqg7b3ztqYShZC38nl6CUg7QuhXg==",
"license": "MIT",
"dependencies": {
"chevrotain": "^11.0.3",
@@ -20842,9 +20519,9 @@
}
},
"node_modules/jsonfile": {
"version": "6.2.0",
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz",
"integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==",
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz",
"integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==",
"license": "MIT",
"dependencies": {
"universalify": "^2.0.0"
@@ -20941,14 +20618,14 @@
}
},
"node_modules/launch-editor": {
"version": "2.11.1",
"resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.11.1.tgz",
"integrity": "sha512-SEET7oNfgSaB6Ym0jufAdCeo3meJVeCaaDyzRygy0xsp2BFKCprcfHljTq4QkzTLUxEKkFK6OK4811YM2oSrRg==",
"version": "2.10.0",
"resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.10.0.tgz",
"integrity": "sha512-D7dBRJo/qcGX9xlvt/6wUYzQxjh5G1RvZPgPv8vi4KRU99DVQL/oW7tnVOCCTm2HGeo3C5HvGE5Yrh6UBoZ0vA==",
"devOptional": true,
"license": "MIT",
"dependencies": {
"picocolors": "^1.1.1",
"shell-quote": "^1.8.3"
"picocolors": "^1.0.0",
"shell-quote": "^1.8.1"
}
},
"node_modules/leven": {
@@ -21197,13 +20874,13 @@
}
},
"node_modules/magic-string": {
"version": "0.30.19",
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.19.tgz",
"integrity": "sha512-2N21sPY9Ws53PZvsEpVtNuSW+ScYbQdp4b9qUaL+9QkHUrGFKo56Lg9Emg5s9V/qrtNBmiR01sYhUOwu3H+VOw==",
"version": "0.30.17",
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz",
"integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==",
"devOptional": true,
"license": "MIT",
"dependencies": {
"@jridgewell/sourcemap-codec": "^1.5.5"
"@jridgewell/sourcemap-codec": "^1.5.0"
}
},
"node_modules/mailto-link": {
@@ -21422,12 +21099,13 @@
}
},
"node_modules/mimic-response": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz",
"integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==",
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz",
"integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==",
"devOptional": true,
"license": "MIT",
"engines": {
"node": ">=8"
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
@@ -21511,6 +21189,13 @@
"node": ">=16 || 14 >=14.17"
}
},
"node_modules/mkdirp-classic": {
"version": "0.5.3",
"resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz",
"integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==",
"devOptional": true,
"license": "MIT"
},
"node_modules/mrmime": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz",
@@ -21574,10 +21259,17 @@
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
}
},
"node_modules/napi-build-utils": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-2.0.0.tgz",
"integrity": "sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==",
"devOptional": true,
"license": "MIT"
},
"node_modules/napi-postinstall": {
"version": "0.3.3",
"resolved": "https://registry.npmjs.org/napi-postinstall/-/napi-postinstall-0.3.3.tgz",
"integrity": "sha512-uTp172LLXSxuSYHv/kou+f6KW3SMppU9ivthaVTXian9sOt3XM/zHYHpRZiLgQoxeWfYUnslNWQHF1+G71xcow==",
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/napi-postinstall/-/napi-postinstall-0.3.0.tgz",
"integrity": "sha512-M7NqKyhODKV1gRLdkwE7pDsZP2/SC2a2vHkOYh9MCpKMbWVfyVfUw5MaH83Fv6XMjxr5jryUp3IDDL9rlxsTeA==",
"devOptional": true,
"license": "MIT",
"bin": {
@@ -21632,6 +21324,32 @@
"tslib": "^2.0.3"
}
},
"node_modules/node-abi": {
"version": "3.75.0",
"resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.75.0.tgz",
"integrity": "sha512-OhYaY5sDsIka7H7AtijtI9jwGYLyl29eQn/W623DiN/MIv5sUqc4g7BIDThX+gb7di9f6xK02nkp8sdfFWZLTg==",
"devOptional": true,
"license": "MIT",
"dependencies": {
"semver": "^7.3.5"
},
"engines": {
"node": ">=10"
}
},
"node_modules/node-abi/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==",
"devOptional": true,
"license": "ISC",
"bin": {
"semver": "bin/semver.js"
},
"engines": {
"node": ">=10"
}
},
"node_modules/node-addon-api": {
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz",
@@ -21657,9 +21375,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.19",
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz",
"integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==",
"devOptional": true,
"license": "MIT"
},
@@ -21710,9 +21428,9 @@
}
},
"node_modules/nwsapi": {
"version": "2.2.22",
"resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.22.tgz",
"integrity": "sha512-ujSMe1OWVn55euT1ihwCI1ZcAaAU3nxUiDwfDQldc51ZXaB9m2AyOn6/jh1BLe2t/G8xd6uKG1UBF2aZJeg2SQ==",
"version": "2.2.20",
"resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.20.tgz",
"integrity": "sha512-/ieB+mDe4MrrKMT8z+mQL8klXydZWGR5Dowt4RAGKbJ3kIGEx3X4ljUo+6V73IXtUPWgfOlU5B9MlGxFO5T+cA==",
"devOptional": true,
"license": "MIT"
},
@@ -21902,9 +21620,9 @@
}
},
"node_modules/on-headers": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.1.0.tgz",
"integrity": "sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A==",
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz",
"integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==",
"devOptional": true,
"license": "MIT",
"engines": {
@@ -22661,7 +22379,6 @@
}
],
"license": "MIT",
"peer": true,
"dependencies": {
"nanoid": "^3.3.7",
"picocolors": "^1.1.1",
@@ -23338,13 +23055,13 @@
}
},
"node_modules/postcss-rtlcss": {
"version": "5.7.1",
"resolved": "https://registry.npmjs.org/postcss-rtlcss/-/postcss-rtlcss-5.7.1.tgz",
"integrity": "sha512-zE68CuARv5StOG/UQLa0W1Y/raUTzgJlfjtas43yh3/G1BFmoPEaHxPRHgeowXRFFhW33FehrNgsljxRLmPVWw==",
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/postcss-rtlcss/-/postcss-rtlcss-5.1.2.tgz",
"integrity": "sha512-cmcgRoO1wL7IJyVHw0RneWI/5Oe75NLC2NLlQLsNI7hcui+yRcW4RrILfQa4FqKQRLTU4r5eF0YPi1qZpMzQpA==",
"devOptional": true,
"license": "Apache-2.0",
"dependencies": {
"rtlcss": "4.3.0"
"rtlcss": "4.1.1"
},
"engines": {
"node": ">=18.0.0"
@@ -23405,6 +23122,73 @@
"integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==",
"license": "MIT"
},
"node_modules/prebuild-install": {
"version": "7.1.3",
"resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.3.tgz",
"integrity": "sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==",
"devOptional": true,
"license": "MIT",
"dependencies": {
"detect-libc": "^2.0.0",
"expand-template": "^2.0.3",
"github-from-package": "0.0.0",
"minimist": "^1.2.3",
"mkdirp-classic": "^0.5.3",
"napi-build-utils": "^2.0.0",
"node-abi": "^3.3.0",
"pump": "^3.0.0",
"rc": "^1.2.7",
"simple-get": "^4.0.0",
"tar-fs": "^2.0.0",
"tunnel-agent": "^0.6.0"
},
"bin": {
"prebuild-install": "bin.js"
},
"engines": {
"node": ">=10"
}
},
"node_modules/prebuild-install/node_modules/detect-libc": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.4.tgz",
"integrity": "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==",
"devOptional": true,
"license": "Apache-2.0",
"engines": {
"node": ">=8"
}
},
"node_modules/prebuild-install/node_modules/tar-fs": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.3.tgz",
"integrity": "sha512-090nwYJDmlhwFwEW3QQl+vaNnxsO2yVsd45eTKRBzSzu+hlb1w2K9inVq5b0ngXuLVqQ4ApvsUHHnu/zQNkWAg==",
"devOptional": true,
"license": "MIT",
"dependencies": {
"chownr": "^1.1.1",
"mkdirp-classic": "^0.5.2",
"pump": "^3.0.0",
"tar-stream": "^2.1.4"
}
},
"node_modules/prebuild-install/node_modules/tar-stream": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz",
"integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==",
"devOptional": true,
"license": "MIT",
"dependencies": {
"bl": "^4.0.3",
"end-of-stream": "^1.4.1",
"fs-constants": "^1.0.0",
"inherits": "^2.0.3",
"readable-stream": "^3.1.1"
},
"engines": {
"node": ">=6"
}
},
"node_modules/prelude-ls": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
@@ -23446,6 +23230,7 @@
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz",
"integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==",
"license": "MIT",
"peer": true,
"dependencies": {
"ansi-regex": "^5.0.1",
"ansi-styles": "^5.0.0",
@@ -23460,6 +23245,7 @@
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
"integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
"license": "MIT",
"peer": true,
"engines": {
"node": ">=10"
},
@@ -23471,7 +23257,8 @@
"version": "17.0.2",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
"integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==",
"license": "MIT"
"license": "MIT",
"peer": true
},
"node_modules/process": {
"version": "0.11.10",
@@ -23508,7 +23295,6 @@
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
"integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
"license": "MIT",
"peer": true,
"dependencies": {
"loose-envify": "^1.4.0",
"object-assign": "^4.1.1",
@@ -23567,6 +23353,17 @@
"integrity": "sha512-5MZ0I9i5JWVO7SizvOviKvZU2qaBbl2KQX150FAA+fJBwYpwOUId7aNygURWSdPzlsA/xZ/InUKXqBbzM0czTA==",
"license": "MIT"
},
"node_modules/pump": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/pump/-/pump-3.0.3.tgz",
"integrity": "sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==",
"devOptional": true,
"license": "MIT",
"dependencies": {
"end-of-stream": "^1.1.0",
"once": "^1.3.1"
}
},
"node_modules/punycode": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
@@ -23761,12 +23558,37 @@
"node": ">= 0.8"
}
},
"node_modules/rc": {
"version": "1.2.8",
"resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
"integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==",
"devOptional": true,
"license": "(BSD-2-Clause OR MIT OR Apache-2.0)",
"dependencies": {
"deep-extend": "^0.6.0",
"ini": "~1.3.0",
"minimist": "^1.2.0",
"strip-json-comments": "~2.0.1"
},
"bin": {
"rc": "cli.js"
}
},
"node_modules/rc/node_modules/strip-json-comments": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
"integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==",
"devOptional": true,
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/react": {
"version": "18.3.1",
"resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz",
"integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==",
"license": "MIT",
"peer": true,
"dependencies": {
"loose-envify": "^1.1.0"
},
@@ -23925,7 +23747,6 @@
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz",
"integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==",
"license": "MIT",
"peer": true,
"dependencies": {
"loose-envify": "^1.1.0",
"scheduler": "^0.23.2"
@@ -23968,7 +23789,6 @@
"resolved": "https://registry.npmjs.org/react-error-boundary/-/react-error-boundary-4.1.2.tgz",
"integrity": "sha512-GQDxZ5Jd+Aq/qUxbCm1UtzmL/s++V7zKgE8yMktJiCQXCCFZnMZh9ng+6/Ne6PjNSXH0L9CjeOEREfRnq6Duag==",
"license": "MIT",
"peer": true,
"dependencies": {
"@babel/runtime": "^7.12.5"
},
@@ -24204,7 +24024,6 @@
"resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.2.9.tgz",
"integrity": "sha512-Gx4L3uM182jEEayZfRbI/G11ZpYdNAnBs70lFVMNdHJI76XYtR+7m0MN+eAs7UHBPhWXcnFPaS+9owSCJQHNpQ==",
"license": "MIT",
"peer": true,
"dependencies": {
"@babel/runtime": "^7.15.4",
"@types/react-redux": "^7.1.20",
@@ -24237,7 +24056,6 @@
"integrity": "sha512-FPvF2XxTSikpJxcr+bHut2H4gJ17+18Uy20D5/F+SKzFap62R3cM5wH6b8WN3LyGSYeQilLEcJcR1fjBSI2S1A==",
"devOptional": true,
"license": "MIT",
"peer": true,
"engines": {
"node": ">=0.10.0"
}
@@ -24308,12 +24126,12 @@
}
},
"node_modules/react-router": {
"version": "6.30.2",
"resolved": "https://registry.npmjs.org/react-router/-/react-router-6.30.2.tgz",
"integrity": "sha512-H2Bm38Zu1bm8KUE5NVWRMzuIyAV8p/JrOaBJAwVmp37AXG72+CZJlEBw6pdn9i5TBgLMhNDgijS4ZlblpHyWTA==",
"version": "6.30.1",
"resolved": "https://registry.npmjs.org/react-router/-/react-router-6.30.1.tgz",
"integrity": "sha512-X1m21aEmxGXqENEPG3T6u0Th7g0aS4ZmoNynhbs+Cn+q+QGTLt+d5IQ2bHAXKzKcxGJjxACpVbnYQSCRcfxHlQ==",
"license": "MIT",
"dependencies": {
"@remix-run/router": "1.23.1"
"@remix-run/router": "1.23.0"
},
"engines": {
"node": ">=14.0.0"
@@ -24323,14 +24141,13 @@
}
},
"node_modules/react-router-dom": {
"version": "6.30.2",
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.30.2.tgz",
"integrity": "sha512-l2OwHn3UUnEVUqc6/1VMmR1cvZryZ3j3NzapC2eUXO1dB0sYp5mvwdjiXhpUbRb21eFow3qSxpP8Yv6oAU824Q==",
"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==",
"license": "MIT",
"peer": true,
"dependencies": {
"@remix-run/router": "1.23.1",
"react-router": "6.30.2"
"@remix-run/router": "1.23.0",
"react-router": "6.30.1"
},
"engines": {
"node": ">=14.0.0"
@@ -24530,7 +24347,6 @@
"resolved": "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz",
"integrity": "sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==",
"license": "MIT",
"peer": true,
"dependencies": {
"@babel/runtime": "^7.9.2"
}
@@ -24557,12 +24373,12 @@
}
},
"node_modules/redux-saga": {
"version": "1.4.2",
"resolved": "https://registry.npmjs.org/redux-saga/-/redux-saga-1.4.2.tgz",
"integrity": "sha512-QLIn/q+7MX/B+MkGJ/K6R3//60eJ4QNy65eqPsJrfGezbxdh1Jx+37VRKE2K4PsJnNET5JufJtgWdT30WBa+6w==",
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/redux-saga/-/redux-saga-1.3.0.tgz",
"integrity": "sha512-J9RvCeAZXSTAibFY0kGw6Iy4EdyDNW7k6Q+liwX+bsck7QVsU78zz8vpBRweEfANxnnlG/xGGeOvf6r8UXzNJQ==",
"license": "MIT",
"dependencies": {
"@redux-saga/core": "^1.4.2"
"@redux-saga/core": "^1.3.0"
}
},
"node_modules/redux-thunk": {
@@ -24605,9 +24421,9 @@
"license": "MIT"
},
"node_modules/regenerate-unicode-properties": {
"version": "10.2.2",
"resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.2.tgz",
"integrity": "sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g==",
"version": "10.2.0",
"resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.0.tgz",
"integrity": "sha512-DqHn3DwbmmPVzeKj9woBadqmXxLvQoQIwu7nopMc72ztvxVmVk2SBhSnx67zuye5TP+lJsb/TBQsjLKhnDf3MA==",
"devOptional": true,
"license": "MIT",
"dependencies": {
@@ -24652,18 +24468,18 @@
}
},
"node_modules/regexpu-core": {
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-6.3.1.tgz",
"integrity": "sha512-DzcswPr252wEr7Qz8AyAVbfyBDKLoYp6eRA1We2Fa9qirRFSdtkP5sHr3yglDKy2BbA0fd2T+j/CUSKes3FeVQ==",
"version": "6.2.0",
"resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-6.2.0.tgz",
"integrity": "sha512-H66BPQMrv+V16t8xtmq+UC0CBpiTBA60V8ibS1QVReIp8T1z8hwFxqcGzm9K6lgsN7sB5edVH8a+ze6Fqm4weA==",
"devOptional": true,
"license": "MIT",
"dependencies": {
"regenerate": "^1.4.2",
"regenerate-unicode-properties": "^10.2.2",
"regenerate-unicode-properties": "^10.2.0",
"regjsgen": "^0.8.0",
"regjsparser": "^0.12.0",
"unicode-match-property-ecmascript": "^2.0.0",
"unicode-match-property-value-ecmascript": "^2.2.1"
"unicode-match-property-value-ecmascript": "^2.1.0"
},
"engines": {
"node": ">=4"
@@ -24910,9 +24726,9 @@
}
},
"node_modules/rtlcss": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/rtlcss/-/rtlcss-4.3.0.tgz",
"integrity": "sha512-FI+pHEn7Wc4NqKXMXFM+VAYKEj/mRIcW4h24YVwVtyjI+EqGrLc2Hx/Ny0lrZ21cBWU2goLy36eqMcNj3AQJig==",
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/rtlcss/-/rtlcss-4.1.1.tgz",
"integrity": "sha512-/oVHgBtnPNcggP2aVXQjSy6N1mMAfHg4GSag0QtZBlD5bdDgAHwr4pydqJGd+SUCu9260+Pjqbjwtvu7EMH1KQ==",
"devOptional": true,
"license": "MIT",
"dependencies": {
@@ -25190,7 +25006,6 @@
"integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
"devOptional": true,
"license": "MIT",
"peer": true,
"dependencies": {
"fast-deep-equal": "^3.1.3",
"fast-uri": "^3.0.1",
@@ -25492,58 +25307,46 @@
"license": "MIT"
},
"node_modules/sharp": {
"version": "0.34.3",
"resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.3.tgz",
"integrity": "sha512-eX2IQ6nFohW4DbvHIOLRB3MHFpYqaqvXd3Tp5e/T/dSH83fxaNJQRvDMhASmkNTsNTVF2/OOopzRCt7xokgPfg==",
"version": "0.32.6",
"resolved": "https://registry.npmjs.org/sharp/-/sharp-0.32.6.tgz",
"integrity": "sha512-KyLTWwgcR9Oe4d9HwCwNM2l7+J0dUQwn/yf7S0EnTtb0eVS4RxO0eUSvxPtzT4F3SY+C4K6fqdv/DO27sJ/v/w==",
"devOptional": true,
"hasInstallScript": true,
"license": "Apache-2.0",
"dependencies": {
"color": "^4.2.3",
"detect-libc": "^2.0.4",
"semver": "^7.7.2"
"detect-libc": "^2.0.2",
"node-addon-api": "^6.1.0",
"prebuild-install": "^7.1.1",
"semver": "^7.5.4",
"simple-get": "^4.0.1",
"tar-fs": "^3.0.4",
"tunnel-agent": "^0.6.0"
},
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
"node": ">=14.15.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
},
"optionalDependencies": {
"@img/sharp-darwin-arm64": "0.34.3",
"@img/sharp-darwin-x64": "0.34.3",
"@img/sharp-libvips-darwin-arm64": "1.2.0",
"@img/sharp-libvips-darwin-x64": "1.2.0",
"@img/sharp-libvips-linux-arm": "1.2.0",
"@img/sharp-libvips-linux-arm64": "1.2.0",
"@img/sharp-libvips-linux-ppc64": "1.2.0",
"@img/sharp-libvips-linux-s390x": "1.2.0",
"@img/sharp-libvips-linux-x64": "1.2.0",
"@img/sharp-libvips-linuxmusl-arm64": "1.2.0",
"@img/sharp-libvips-linuxmusl-x64": "1.2.0",
"@img/sharp-linux-arm": "0.34.3",
"@img/sharp-linux-arm64": "0.34.3",
"@img/sharp-linux-ppc64": "0.34.3",
"@img/sharp-linux-s390x": "0.34.3",
"@img/sharp-linux-x64": "0.34.3",
"@img/sharp-linuxmusl-arm64": "0.34.3",
"@img/sharp-linuxmusl-x64": "0.34.3",
"@img/sharp-wasm32": "0.34.3",
"@img/sharp-win32-arm64": "0.34.3",
"@img/sharp-win32-ia32": "0.34.3",
"@img/sharp-win32-x64": "0.34.3"
}
},
"node_modules/sharp/node_modules/detect-libc": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.0.tgz",
"integrity": "sha512-vEtk+OcP7VBRtQZ1EJ3bdgzSfBjgnEalLTp5zjJrS+2Z1w2KZly4SBdac/WDU3hhsNAZ9E8SC96ME4Ey8MZ7cg==",
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.4.tgz",
"integrity": "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==",
"devOptional": true,
"license": "Apache-2.0",
"engines": {
"node": ">=8"
}
},
"node_modules/sharp/node_modules/node-addon-api": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-6.1.0.tgz",
"integrity": "sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==",
"devOptional": true,
"license": "MIT"
},
"node_modules/sharp/node_modules/semver": {
"version": "7.7.2",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz",
@@ -25669,10 +25472,57 @@
"integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
"license": "ISC"
},
"node_modules/simple-concat": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz",
"integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==",
"devOptional": true,
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
],
"license": "MIT"
},
"node_modules/simple-get": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz",
"integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==",
"devOptional": true,
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
],
"license": "MIT",
"dependencies": {
"decompress-response": "^6.0.0",
"once": "^1.3.1",
"simple-concat": "^1.0.0"
}
},
"node_modules/simple-swizzle": {
"version": "0.2.4",
"resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.4.tgz",
"integrity": "sha512-nAu1WFPQSMNr2Zn9PGSZK9AGn4t/y97lEm+MXTtUDwfP0ksAIX4nO+6ruD9Jwut4C49SB1Ws+fbXsm/yScWOHw==",
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz",
"integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==",
"devOptional": true,
"license": "MIT",
"dependencies": {
@@ -25680,9 +25530,9 @@
}
},
"node_modules/simple-swizzle/node_modules/is-arrayish": {
"version": "0.3.4",
"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.4.tgz",
"integrity": "sha512-m6UrgzFVUYawGBh1dUsWR5M2Clqic9RVXC/9f8ceNlv2IcO9j9J/z8UoCLPqtsPBFNzEpfR3xftohbfqDx8EQA==",
"version": "0.3.2",
"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz",
"integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==",
"devOptional": true,
"license": "MIT"
},
@@ -25775,13 +25625,13 @@
"license": "MIT"
},
"node_modules/source-map": {
"version": "0.7.6",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz",
"integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==",
"version": "0.7.4",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz",
"integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==",
"devOptional": true,
"license": "BSD-3-Clause",
"engines": {
"node": ">= 12"
"node": ">= 8"
}
},
"node_modules/source-map-js": {
@@ -25968,6 +25818,20 @@
"component-emitter": "^2.0.0"
}
},
"node_modules/streamx": {
"version": "2.22.1",
"resolved": "https://registry.npmjs.org/streamx/-/streamx-2.22.1.tgz",
"integrity": "sha512-znKXEBxfatz2GBNK02kRnCXjV+AA4kjZIUxeWSr3UGirZMJfTE9uiwKHobnbgxWyL/JWro8tTq+vOqAK1/qbSA==",
"devOptional": true,
"license": "MIT",
"dependencies": {
"fast-fifo": "^1.3.2",
"text-decoder": "^1.1.0"
},
"optionalDependencies": {
"bare-events": "^2.2.0"
}
},
"node_modules/strict-uri-encode": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz",
@@ -26192,7 +26056,6 @@
"integrity": "sha512-+xU0IA1StzqAqFs/QtXkK+XJa7wpS4X5H+JQccRKsRCElgeLGocFU1U/UMvMUylKFw6vwGV+Y/a2wb2pm5rFFQ==",
"hasInstallScript": true,
"license": "Apache-2.0",
"peer": true,
"dependencies": {
"@bundled-es-modules/deepmerge": "^4.3.1",
"@bundled-es-modules/glob": "^10.4.2",
@@ -26216,9 +26079,9 @@
}
},
"node_modules/style-dictionary/node_modules/chalk": {
"version": "5.6.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz",
"integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==",
"version": "5.4.1",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-5.4.1.tgz",
"integrity": "sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==",
"license": "MIT",
"engines": {
"node": "^12.17.0 || ^14.13 || >=16.0.0"
@@ -26271,21 +26134,21 @@
}
},
"node_modules/superagent": {
"version": "10.2.3",
"resolved": "https://registry.npmjs.org/superagent/-/superagent-10.2.3.tgz",
"integrity": "sha512-y/hkYGeXAj7wUMjxRbB21g/l6aAEituGXM9Rwl4o20+SX3e8YOSV6BxFXl+dL3Uk0mjSL3kCbNkwURm8/gEDig==",
"version": "10.2.2",
"resolved": "https://registry.npmjs.org/superagent/-/superagent-10.2.2.tgz",
"integrity": "sha512-vWMq11OwWCC84pQaFPzF/VO3BrjkCeewuvJgt1jfV0499Z1QSAWN4EqfMM5WlFDDX9/oP8JjlDKpblrmEoyu4Q==",
"devOptional": true,
"license": "MIT",
"dependencies": {
"component-emitter": "^1.3.1",
"component-emitter": "^1.3.0",
"cookiejar": "^2.1.4",
"debug": "^4.3.7",
"debug": "^4.3.4",
"fast-safe-stringify": "^2.1.1",
"form-data": "^4.0.4",
"form-data": "^4.0.0",
"formidable": "^3.5.4",
"methods": "^1.1.2",
"mime": "2.6.0",
"qs": "^6.11.2"
"qs": "^6.11.0"
},
"engines": {
"node": ">=14.18.0"
@@ -26452,13 +26315,13 @@
"license": "MIT"
},
"node_modules/synckit": {
"version": "0.11.11",
"resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.11.tgz",
"integrity": "sha512-MeQTA1r0litLUf0Rp/iisCaL8761lKAZHaimlbGK4j0HysC4PLfqygQj9srcs0m2RdtDYnF8UuYyKpbjHYp7Jw==",
"version": "0.11.8",
"resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.8.tgz",
"integrity": "sha512-+XZ+r1XGIJGeQk3VvXhT6xx/VpbHsRzsTkGgF6E5RX9TTXD0118l87puaEBZ566FhqblC6U0d4XnubznJDm30A==",
"dev": true,
"license": "MIT",
"dependencies": {
"@pkgr/core": "^0.2.9"
"@pkgr/core": "^0.2.4"
},
"engines": {
"node": "^14.18.0 || >=16.0.0"
@@ -26474,28 +26337,51 @@
"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.2.2",
"resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.2.tgz",
"integrity": "sha512-Re10+NauLTMCudc7T5WLFLAwDhQ0JWdrMK+9B2M8zR5hRExKmsRDCBA7/aV/pNJFltmBFO5BAMlQFi/vq3nKOg==",
"devOptional": true,
"license": "MIT",
"engines": {
"node": ">=6"
}
},
"node_modules/tar-fs": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.1.0.tgz",
"integrity": "sha512-5Mty5y/sOF1YWj1J6GiBodjlDc05CUR8PKXrsnFAiSG0xA+GHeWLovaZPYUDXkH/1iKRf2+M5+OrRgzC7O9b7w==",
"devOptional": true,
"license": "MIT",
"dependencies": {
"pump": "^3.0.0",
"tar-stream": "^3.1.5"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/webpack"
"optionalDependencies": {
"bare-fs": "^4.0.1",
"bare-path": "^3.0.0"
}
},
"node_modules/tar-stream": {
"version": "3.1.7",
"resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.7.tgz",
"integrity": "sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==",
"devOptional": true,
"license": "MIT",
"dependencies": {
"b4a": "^1.6.4",
"fast-fifo": "^1.2.0",
"streamx": "^2.15.0"
}
},
"node_modules/terser": {
"version": "5.44.0",
"resolved": "https://registry.npmjs.org/terser/-/terser-5.44.0.tgz",
"integrity": "sha512-nIVck8DK+GM/0Frwd+nIhZ84pR/BX7rmXMfYwyg+Sri5oGVE99/E3KvXqpC2xHFxyqXyGHTKBSioxxplrO4I4w==",
"version": "5.43.1",
"resolved": "https://registry.npmjs.org/terser/-/terser-5.43.1.tgz",
"integrity": "sha512-+6erLbBm0+LROX2sPXlUYx/ux5PyE9K/a92Wrt6oA+WDAoFTdpHE5tCYCI5PNzq2y8df4rA+QgHLJuR4jNymsg==",
"devOptional": true,
"license": "BSD-2-Clause",
"dependencies": {
"@jridgewell/source-map": "^0.3.3",
"acorn": "^8.15.0",
"acorn": "^8.14.0",
"commander": "^2.20.0",
"source-map-support": "~0.5.20"
},
@@ -26615,6 +26501,16 @@
"node": ">=8"
}
},
"node_modules/text-decoder": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.2.3.tgz",
"integrity": "sha512-3/o9z3X0X0fTupwsYvR03pJ/DjWuqqrfwBgTQzdWDiQSm9KitAyz/9WqsT2JQW7KV2m+bC2ol/zqpW37NHxLaA==",
"devOptional": true,
"license": "Apache-2.0",
"dependencies": {
"b4a": "^1.6.4"
}
},
"node_modules/text-table": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
@@ -26623,17 +26519,13 @@
"license": "MIT"
},
"node_modules/thingies": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/thingies/-/thingies-2.5.0.tgz",
"integrity": "sha512-s+2Bwztg6PhWUD7XMfeYm5qliDdSiZm7M7n8KjTkIsm3l/2lgVRc2/Gx/v+ZX8lT4FMA+i8aQvhcWylldc+ZNw==",
"license": "MIT",
"version": "1.21.0",
"resolved": "https://registry.npmjs.org/thingies/-/thingies-1.21.0.tgz",
"integrity": "sha512-hsqsJsFMsV+aD4s3CWKk85ep/3I9XzYV/IXaSouJMYIoDlgyi11cBhsqYe9/geRfB0YIikBQg6raRaM+nIMP9g==",
"license": "Unlicense",
"engines": {
"node": ">=10.18"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/streamich"
},
"peerDependencies": {
"tslib": "^2"
}
@@ -26670,14 +26562,14 @@
"license": "MIT"
},
"node_modules/tinyglobby": {
"version": "0.2.15",
"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz",
"integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==",
"version": "0.2.14",
"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.14.tgz",
"integrity": "sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==",
"devOptional": true,
"license": "MIT",
"dependencies": {
"fdir": "^6.5.0",
"picomatch": "^4.0.3"
"fdir": "^6.4.4",
"picomatch": "^4.0.2"
},
"engines": {
"node": ">=12.0.0"
@@ -26687,14 +26579,11 @@
}
},
"node_modules/tinyglobby/node_modules/fdir": {
"version": "6.5.0",
"resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
"integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
"version": "6.4.6",
"resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.6.tgz",
"integrity": "sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==",
"devOptional": true,
"license": "MIT",
"engines": {
"node": ">=12.0.0"
},
"peerDependencies": {
"picomatch": "^3 || ^4"
},
@@ -26705,12 +26594,11 @@
}
},
"node_modules/tinyglobby/node_modules/picomatch": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz",
"integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
"devOptional": true,
"license": "MIT",
"peer": true,
"engines": {
"node": ">=12"
},
@@ -26809,9 +26697,9 @@
}
},
"node_modules/tree-dump": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/tree-dump/-/tree-dump-1.1.0.tgz",
"integrity": "sha512-rMuvhU4MCDbcbnleZTFezWsaZXRFemSqAM+7jPnzUl1fo9w3YEKOxAeui0fz3OI4EU4hf23iyA7uQRVko+UaBA==",
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/tree-dump/-/tree-dump-1.0.3.tgz",
"integrity": "sha512-il+Cv80yVHFBwokQSfd4bldvr1Md951DpgAGfmhydt04L+YzHgubm2tQ7zueWDcGENKHq0ZvGFR/hjvNXilHEg==",
"license": "Apache-2.0",
"engines": {
"node": ">=10.0"
@@ -26838,20 +26726,19 @@
}
},
"node_modules/ts-jest": {
"version": "29.4.5",
"resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.4.5.tgz",
"integrity": "sha512-HO3GyiWn2qvTQA4kTgjDcXiMwYQt68a1Y8+JuLRVpdIzm+UOLSHgl/XqR4c6nzJkq5rOkjc02O2I7P7l/Yof0Q==",
"version": "29.4.0",
"resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.4.0.tgz",
"integrity": "sha512-d423TJMnJGu80/eSgfQ5w/R+0zFJvdtTxwtF9KzFFunOpSeD+79lHJQIiAhluJoyGRbvj9NZJsl9WjCUo0ND7Q==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"bs-logger": "^0.2.6",
"ejs": "^3.1.10",
"fast-json-stable-stringify": "^2.1.0",
"handlebars": "^4.7.8",
"json5": "^2.2.3",
"lodash.memoize": "^4.1.2",
"make-error": "^1.3.6",
"semver": "^7.7.3",
"semver": "^7.7.2",
"type-fest": "^4.41.0",
"yargs-parser": "^21.1.1"
},
@@ -26892,9 +26779,9 @@
}
},
"node_modules/ts-jest/node_modules/semver": {
"version": "7.7.3",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz",
"integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==",
"version": "7.7.2",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz",
"integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==",
"dev": true,
"license": "ISC",
"bin": {
@@ -26998,8 +26885,7 @@
"version": "2.8.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
"license": "0BSD",
"peer": true
"license": "0BSD"
},
"node_modules/tsutils": {
"version": "3.21.0",
@@ -27024,6 +26910,19 @@
"devOptional": true,
"license": "0BSD"
},
"node_modules/tunnel-agent": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
"integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==",
"devOptional": true,
"license": "Apache-2.0",
"dependencies": {
"safe-buffer": "^5.0.1"
},
"engines": {
"node": "*"
}
},
"node_modules/type-check": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
@@ -27053,7 +26952,6 @@
"integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
"devOptional": true,
"license": "(MIT OR CC0-1.0)",
"peer": true,
"engines": {
"node": ">=10"
},
@@ -27159,7 +27057,6 @@
"integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==",
"devOptional": true,
"license": "Apache-2.0",
"peer": true,
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
@@ -27192,20 +27089,6 @@
"typescript-compare": "^0.0.2"
}
},
"node_modules/uglify-js": {
"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,
"bin": {
"uglifyjs": "bin/uglifyjs"
},
"engines": {
"node": ">=0.8.0"
}
},
"node_modules/unbox-primitive": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz",
@@ -27241,9 +27124,9 @@
}
},
"node_modules/undici-types": {
"version": "7.11.0",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.11.0.tgz",
"integrity": "sha512-kt1ZriHTi7MU+Z/r9DOdAI3ONdaR3M3csEaRc6ewa4f4dTvX4cQCbJ4NkEn0ohE4hHtq85+PhPSTY+pO/1PwgA==",
"version": "7.8.0",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.8.0.tgz",
"integrity": "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw==",
"devOptional": true,
"license": "MIT"
},
@@ -27282,9 +27165,9 @@
}
},
"node_modules/unicode-match-property-value-ecmascript": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.1.tgz",
"integrity": "sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg==",
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.0.tgz",
"integrity": "sha512-4IehN3V/+kkr5YeSSDDQG8QLqO26XpL2XP3GQtqwlT/QYSECAwFztxVHjlbh0+gjJ3XmNLS0zDsbgs9jWKExLg==",
"devOptional": true,
"license": "MIT",
"engines": {
@@ -27292,9 +27175,9 @@
}
},
"node_modules/unicode-property-aliases-ecmascript": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.2.0.tgz",
"integrity": "sha512-hpbDzxUY9BFwX+UeBnxv3Sh1q7HFxj48DTmXchNgRa46lO8uj3/1iEn3MiNUYTg1g9ctIqXCCERn8gYZhHC5lQ==",
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz",
"integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==",
"devOptional": true,
"license": "MIT",
"engines": {
@@ -27340,13 +27223,12 @@
}
},
"node_modules/unrs-resolver": {
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/unrs-resolver/-/unrs-resolver-1.11.1.tgz",
"integrity": "sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg==",
"version": "1.11.0",
"resolved": "https://registry.npmjs.org/unrs-resolver/-/unrs-resolver-1.11.0.tgz",
"integrity": "sha512-uw3hCGO/RdAEAb4zgJ3C/v6KIAFFOtBoxR86b2Ejc5TnH7HrhTWJR2o0A9ullC3eWMegKQCw/arQ/JivywQzkg==",
"devOptional": true,
"hasInstallScript": true,
"license": "MIT",
"peer": true,
"dependencies": {
"napi-postinstall": "^0.3.0"
},
@@ -27354,25 +27236,25 @@
"url": "https://opencollective.com/unrs-resolver"
},
"optionalDependencies": {
"@unrs/resolver-binding-android-arm-eabi": "1.11.1",
"@unrs/resolver-binding-android-arm64": "1.11.1",
"@unrs/resolver-binding-darwin-arm64": "1.11.1",
"@unrs/resolver-binding-darwin-x64": "1.11.1",
"@unrs/resolver-binding-freebsd-x64": "1.11.1",
"@unrs/resolver-binding-linux-arm-gnueabihf": "1.11.1",
"@unrs/resolver-binding-linux-arm-musleabihf": "1.11.1",
"@unrs/resolver-binding-linux-arm64-gnu": "1.11.1",
"@unrs/resolver-binding-linux-arm64-musl": "1.11.1",
"@unrs/resolver-binding-linux-ppc64-gnu": "1.11.1",
"@unrs/resolver-binding-linux-riscv64-gnu": "1.11.1",
"@unrs/resolver-binding-linux-riscv64-musl": "1.11.1",
"@unrs/resolver-binding-linux-s390x-gnu": "1.11.1",
"@unrs/resolver-binding-linux-x64-gnu": "1.11.1",
"@unrs/resolver-binding-linux-x64-musl": "1.11.1",
"@unrs/resolver-binding-wasm32-wasi": "1.11.1",
"@unrs/resolver-binding-win32-arm64-msvc": "1.11.1",
"@unrs/resolver-binding-win32-ia32-msvc": "1.11.1",
"@unrs/resolver-binding-win32-x64-msvc": "1.11.1"
"@unrs/resolver-binding-android-arm-eabi": "1.11.0",
"@unrs/resolver-binding-android-arm64": "1.11.0",
"@unrs/resolver-binding-darwin-arm64": "1.11.0",
"@unrs/resolver-binding-darwin-x64": "1.11.0",
"@unrs/resolver-binding-freebsd-x64": "1.11.0",
"@unrs/resolver-binding-linux-arm-gnueabihf": "1.11.0",
"@unrs/resolver-binding-linux-arm-musleabihf": "1.11.0",
"@unrs/resolver-binding-linux-arm64-gnu": "1.11.0",
"@unrs/resolver-binding-linux-arm64-musl": "1.11.0",
"@unrs/resolver-binding-linux-ppc64-gnu": "1.11.0",
"@unrs/resolver-binding-linux-riscv64-gnu": "1.11.0",
"@unrs/resolver-binding-linux-riscv64-musl": "1.11.0",
"@unrs/resolver-binding-linux-s390x-gnu": "1.11.0",
"@unrs/resolver-binding-linux-x64-gnu": "1.11.0",
"@unrs/resolver-binding-linux-x64-musl": "1.11.0",
"@unrs/resolver-binding-wasm32-wasi": "1.11.0",
"@unrs/resolver-binding-win32-arm64-msvc": "1.11.0",
"@unrs/resolver-binding-win32-ia32-msvc": "1.11.0",
"@unrs/resolver-binding-win32-x64-msvc": "1.11.0"
}
},
"node_modules/update-browserslist-db": {
@@ -27537,9 +27419,9 @@
}
},
"node_modules/use-sync-external-store": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz",
"integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==",
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.5.0.tgz",
"integrity": "sha512-Rb46I4cGGVBmjamjphe8L/UnvJD+uPPtTkNvX5mZgqdbavhI4EbgIWJiIHXJ8bc/i9EQGPRh4DwEURJ552Do0A==",
"license": "MIT",
"peerDependencies": {
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
@@ -27710,24 +27592,22 @@
}
},
"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.99.9",
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.99.9.tgz",
"integrity": "sha512-brOPwM3JnmOa+7kd3NsmOUOwbDAj8FT9xDsG3IW0MgbN9yZV7Oi/s/+MNQ/EcSMqw7qfoRyXPoeEWT8zLVdVGg==",
"devOptional": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@types/eslint-scope": "^3.7.7",
"@types/estree": "^1.0.8",
"@types/estree": "^1.0.6",
"@types/json-schema": "^7.0.15",
"@webassemblyjs/ast": "^1.14.1",
"@webassemblyjs/wasm-edit": "^1.14.1",
"@webassemblyjs/wasm-parser": "^1.14.1",
"acorn": "^8.15.0",
"acorn-import-phases": "^1.0.3",
"acorn": "^8.14.0",
"browserslist": "^4.24.0",
"chrome-trace-event": "^1.0.2",
"enhanced-resolve": "^5.17.3",
"enhanced-resolve": "^5.17.1",
"es-module-lexer": "^1.2.1",
"eslint-scope": "5.1.1",
"events": "^3.2.0",
@@ -27741,7 +27621,7 @@
"tapable": "^2.1.1",
"terser-webpack-plugin": "^5.3.11",
"watchpack": "^2.4.1",
"webpack-sources": "^3.3.3"
"webpack-sources": "^3.2.3"
},
"bin": {
"webpack": "bin/webpack.js"
@@ -27824,7 +27704,6 @@
"integrity": "sha512-pIDJHIEI9LR0yxHXQ+Qh95k2EvXpWzZ5l+d+jIo+RdSm9MiHfzazIxwwni/p7+x4eJZuvG1AJwgC4TNQ7NRgsg==",
"devOptional": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@discoveryjs/json-ext": "^0.5.0",
"@webpack-cli/configtest": "^2.1.1",
@@ -27905,7 +27784,6 @@
"integrity": "sha512-0XavAZbNJ5sDrCbkpWL8mia0o5WPOd2YGtxrEiZkBK9FjLppIUK2TgxK6qGD2P3hUXTJNNPVibrerKcx5WkR1g==",
"devOptional": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@types/bonjour": "^3.5.9",
"@types/connect-history-api-fallback": "^1.3.5",
@@ -28248,13 +28126,6 @@
"node": ">=0.10.0"
}
},
"node_modules/wordwrap": {
"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"
},
"node_modules/wrap-ansi": {
"version": "6.2.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
@@ -28373,9 +28244,9 @@
"license": "ISC"
},
"node_modules/yaml": {
"version": "2.8.1",
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.1.tgz",
"integrity": "sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw==",
"version": "2.8.0",
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.0.tgz",
"integrity": "sha512-4lLa/EcQCB0cJkyts+FpIRx5G/llPxfP6VQU5KByHEhLxY3IJCH0f0Hy1MHI8sClTvsIb8qwRJ6R/ZdlDJ/leQ==",
"license": "ISC",
"bin": {
"yaml": "bin.mjs"

View File

@@ -19,6 +19,11 @@
"dev": "PUBLIC_PATH=/authn/ MFE_CONFIG_API_URL='http://localhost:8000/api/mfe_config/v1' fedx-scripts webpack-dev-server --progress --host apps.local.openedx.io",
"test": "fedx-scripts jest --coverage --passWithNoTests"
},
"husky": {
"hooks": {
"pre-commit": "npm run lint"
}
},
"author": "edX",
"license": "AGPL-3.0",
"homepage": "https://github.com/openedx/frontend-app-authn#readme",
@@ -35,8 +40,8 @@
"@fortawesome/fontawesome-svg-core": "6.7.2",
"@fortawesome/free-brands-svg-icons": "6.7.2",
"@fortawesome/free-solid-svg-icons": "6.7.2",
"@fortawesome/react-fontawesome": "0.2.6",
"@openedx/frontend-plugin-framework": "^1.7.0",
"@fortawesome/react-fontawesome": "0.2.2",
"@openedx/frontend-plugin-framework": "^1.3.0",
"@openedx/paragon": "^23.4.2",
"@optimizely/react-sdk": "^2.9.1",
"@redux-devtools/extension": "3.3.0",
@@ -46,22 +51,23 @@
"classnames": "2.5.1",
"core-js": "3.43.0",
"fastest-levenshtein": "1.0.16",
"form-urlencoded": "6.1.6",
"form-urlencoded": "6.1.5",
"prop-types": "15.8.1",
"query-string": "7.1.3",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-error-boundary": "^4.0.13",
"react-helmet": "6.1.0",
"react-loading-skeleton": "3.5.0",
"react-redux": "7.2.9",
"react-responsive": "8.2.0",
"react-router": "6.30.2",
"react-router-dom": "6.30.2",
"react-router": "6.30.1",
"react-router-dom": "6.30.1",
"react-zendesk": "^0.1.13",
"redux": "4.2.1",
"redux-logger": "3.0.6",
"redux-mock-store": "1.5.5",
"redux-saga": "1.4.2",
"redux-saga": "1.3.0",
"redux-thunk": "2.4.2",
"regenerator-runtime": "0.14.1",
"reselect": "5.1.1",
@@ -69,12 +75,15 @@
},
"devDependencies": {
"@edx/browserslist-config": "^1.1.1",
"@openedx/frontend-build": "^14.6.2",
"babel-plugin-formatjs": "10.5.41",
"@edx/reactifex": "1.1.0",
"@openedx/frontend-build": "^14.6.1",
"copy-webpack-plugin": "^11.0.0",
"babel-plugin-formatjs": "10.5.39",
"eslint-plugin-import": "2.32.0",
"glob": "7.2.3",
"history": "5.3.0",
"jest": "30.2.0",
"husky": "9.1.7",
"jest": "30.0.4",
"react-test-renderer": "^18.3.1",
"ts-jest": "^29.4.0"
}

View File

@@ -1,25 +1,32 @@
<!doctype html>
<!DOCTYPE html>
<html lang="en-us">
<head>
<title><%= (process.env.SITE_NAME && process.env.SITE_NAME != 'null') ? 'Authentication | ' + process.env.SITE_NAME : 'Authentication' %></title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="shortcut icon" href="<%=htmlWebpackPlugin.options.FAVICON_URL%>" type="image/x-icon"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/iframe-resizer/4.4.4/iframeResizer.contentWindow.min.js"
integrity="sha512-IWwZFBvHzN41wNI6etRLLuLrDDj/6AwJcPt7cmKJAzluYTIHHQ1PF8wh0rSy05jxEvvjflVvH2MxeV6riyEEXg=="
crossorigin="anonymous"
referrerpolicy="no-referrer">
</script>
<% if (process.env.OPTIMIZELY_URL) { %>
<script
src="<%= process.env.OPTIMIZELY_URL %>"
></script>
<% } else if (process.env.OPTIMIZELY_PROJECT_ID) { %>
<script
src="<%= process.env.MARKETING_SITE_BASE_URL %>/optimizelyjs/<%= process.env.OPTIMIZELY_PROJECT_ID %>.js"
></script>
<% } %>
<title>
<%= (process.env.SITE_NAME && process.env.SITE_NAME !='null' ) ?
'Authentication | ' + process.env.SITE_NAME : 'Authentication' %>
</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="robots" content="noindex, nofollow" />
<link
rel="shortcut icon"
href="<%=htmlWebpackPlugin.options.FAVICON_URL%>"
type="image/x-icon"
/>
<script defer src="https://www.edx.org/beam-wrapper.js" ></script>
<script
src="https://cdnjs.cloudflare.com/ajax/libs/iframe-resizer/4.4.4/iframeResizer.contentWindow.min.js"
integrity="sha512-IWwZFBvHzN41wNI6etRLLuLrDDj/6AwJcPt7cmKJAzluYTIHHQ1PF8wh0rSy05jxEvvjflVvH2MxeV6riyEEXg=="
crossorigin="anonymous"
referrerpolicy="no-referrer"
></script>
<% if (process.env.OPTIMIZELY_URL) { %>
<script src="<%= process.env.OPTIMIZELY_URL %>"></script>
<% } else if (process.env.OPTIMIZELY_PROJECT_ID) { %>
<script src="<%= process.env.MARKETING_SITE_BASE_URL %>/optimizelyjs/<%= process.env.OPTIMIZELY_PROJECT_ID %>.js"></script>
<% } %>
</head>
<body>
<div id="root"></div>
</body>

2
public/robots.txt Normal file
View File

@@ -0,0 +1,2 @@
User-agent: *
Disallow: /

View File

@@ -6,7 +6,7 @@ import { Helmet } from 'react-helmet';
import { Navigate, Route, Routes } from 'react-router-dom';
import {
EmbeddedRegistrationRoute, NotFoundPage, registerIcons, UnAuthOnlyRoute, Zendesk,
EmbeddedRegistrationRoute, NotFoundPage, registerIcons, RouteTracker, UnAuthOnlyRoute,
} from './common-components';
import configureStore from './data/configureStore';
import {
@@ -22,6 +22,7 @@ import {
import { updatePathWithQueryParams } from './data/utils';
import { ForgotPasswordPage } from './forgot-password';
import Logistration from './logistration/Logistration';
import MainAppSlot from './plugin-slots/MainAppSlot';
import { ProgressiveProfiling } from './progressive-profiling';
import { RecommendationsPage } from './recommendations';
import { RegistrationPage } from './register';
@@ -36,7 +37,6 @@ const MainApp = () => (
<Helmet>
<link rel="shortcut icon" href={getConfig().FAVICON_URL} type="image/x-icon" />
</Helmet>
{getConfig().ZENDESK_KEY && <Zendesk />}
<Routes>
<Route path="/" element={<Navigate replace to={updatePathWithQueryParams(REGISTER_PAGE)} />} />
<Route
@@ -57,6 +57,8 @@ const MainApp = () => (
<Route path={PAGE_NOT_FOUND} element={<NotFoundPage />} />
<Route path="*" element={<Navigate replace to={PAGE_NOT_FOUND} />} />
</Routes>
<RouteTracker />
<MainAppSlot />
</AppProvider>
);

22
src/cohesion/constants.js Normal file
View File

@@ -0,0 +1,22 @@
export const PAGE_TYPES = {
ACCOUNT_CREATION: 'account-creation',
SIGN_IN: 'sign-in',
};
export const ELEMENT_TYPES = {
BUTTON: 'BUTTON',
};
export const EVENT_TYPES = { ElementClicked: 'redventures.usertracking.v3.ElementClicked' };
export const ELEMENT_TEXT = {
CREATE_ACCOUNT: 'create-account',
OPT_IN_TEXT: 'I agree that edx may send me marketing messages',
SIGN_IN: 'Sign In',
};
export const ELEMENT_NAME = {
SIGN_IN: PAGE_TYPES.SIGN_IN,
OPT_OUT: 'opt-out',
CREATE_ACCOUNT: 'Create an account for free',
};

View File

@@ -0,0 +1,6 @@
export const SET_COHESION_EVENT_ELEMENT_STATES = 'SET_COHESION_EVENT_ELEMENT_STATES';
export const setCohesionEventStates = (eventData) => ({
type: SET_COHESION_EVENT_ELEMENT_STATES,
payload: eventData,
});

View File

@@ -0,0 +1,17 @@
import { SET_COHESION_EVENT_ELEMENT_STATES } from './actions';
export const storeName = 'cohesion';
export const defaultState = {
eventData: {},
};
export const reducer = (state = defaultState, action = {}) => {
if (action.type === SET_COHESION_EVENT_ELEMENT_STATES) {
return {
...state,
eventData: action.payload,
};
}
return state;
};

24
src/cohesion/trackers.js Normal file
View File

@@ -0,0 +1,24 @@
import { EVENT_TYPES } from './constants';
/**
* Tracks cohesion events by setting the page type and tracking a click event.
*
* @param {string} pageType - The type of page where the event occurred.
* @param {string} elementType - The type of the web element (e.g., 'BUTTON', 'LINK').
* @param {string} webElementText - The text content of the web element.
* @param {string} webElementName - The name of the web element.
*/
const trackCohesionEvent = (eventData) => {
window.chsn_pageType = eventData.pageType;
const webElement = {
elementType: eventData.elementType,
text: eventData.webElementText,
name: eventData.webElementName,
};
window.tagular?.('beam', {
'@type': EVENT_TYPES.ElementClicked,
webElement,
});
};
export default trackCohesionEvent;

6
src/cohesion/utils.js Normal file
View File

@@ -0,0 +1,6 @@
const mockTagular = () => {
const getTagular = jest.fn();
window.tagular = getTagular;
};
export default mockTagular;

View File

@@ -60,7 +60,7 @@ const InstitutionLogistration = props => {
className="btn nav-item p-0 mb-1 institutions--provider-link"
destination={lmsBaseUrl + provider.loginUrl}
>
{provider.name}
{provider?.name}
</Hyperlink>
</td>
</tr>

View File

@@ -1,11 +1,15 @@
import { useSelector } from 'react-redux';
import { getConfig } from '@edx/frontend-platform';
import PropTypes from 'prop-types';
import { Navigate } from 'react-router-dom';
import trackCohesionEvent from '../cohesion/trackers';
import {
AUTHN_PROGRESSIVE_PROFILING, RECOMMENDATIONS, REDIRECT,
} from '../data/constants';
import { setCookie } from '../data/utils';
import setCookie from '../data/utils/cookies';
import { redirectWithDelay } from '../data/utils/dataUtils';
const RedirectLogistration = (props) => {
const {
@@ -20,10 +24,16 @@ const RedirectLogistration = (props) => {
userId,
registrationEmbedded,
host,
currectProvider,
} = props;
const cohesionEventData = useSelector(state => state.cohesion.eventData);
let finalRedirectUrl = '';
if (success) {
// This event is used by cohesion upon successful login and registration
if (!currectProvider) {
trackCohesionEvent(cohesionEventData);
}
// If we're in a third party auth pipeline, we must complete the pipeline
// once user has successfully logged in. Otherwise, redirect to the specified redirect url.
// Note: For multiple enterprise use case, we need to make sure that user first visits the
@@ -75,8 +85,7 @@ const RedirectLogistration = (props) => {
/>
);
}
window.location.href = finalRedirectUrl;
redirectWithDelay(finalRedirectUrl);
}
return null;
@@ -94,6 +103,7 @@ RedirectLogistration.defaultProps = {
userId: null,
registrationEmbedded: false,
host: '',
currectProvider: '',
};
RedirectLogistration.propTypes = {
@@ -108,6 +118,7 @@ RedirectLogistration.propTypes = {
userId: PropTypes.number,
registrationEmbedded: PropTypes.bool,
host: PropTypes.string,
currectProvider: PropTypes.string,
};
export default RedirectLogistration;

View File

@@ -0,0 +1,15 @@
import { useEffect } from 'react';
import { useLocation } from 'react-router-dom';
const RouteTracker = () => {
const location = useLocation();
useEffect(() => {
window.tagular?.('pageView');
}, [location]);
return null;
};
export default RouteTracker;

View File

@@ -1,4 +1,5 @@
import React from 'react';
import { useSelector } from 'react-redux';
import { getConfig } from '@edx/frontend-platform';
import { useIntl } from '@edx/frontend-platform/i18n';
@@ -8,17 +9,35 @@ import { Login } from '@openedx/paragon/icons';
import PropTypes from 'prop-types';
import messages from './messages';
import { LOGIN_PAGE, SUPPORTED_ICON_CLASSES } from '../data/constants';
import { ELEMENT_TYPES, PAGE_TYPES } from '../cohesion/constants';
import trackCohesionEvent from '../cohesion/trackers';
import {
LOGIN_PAGE, REGISTER_PAGE, SUPPORTED_ICON_CLASSES,
} from '../data/constants';
import { setCookie } from '../data/utils';
import { redirectWithDelay } from '../data/utils/dataUtils';
const SocialAuthProviders = (props) => {
const { formatMessage } = useIntl();
const { referrer, socialAuthProviders } = props;
const registrationFields = useSelector(state => state.register.registrationFormData);
function handleSubmit(e) {
function handleSubmit(e, providerName) {
e.preventDefault();
const eventData = {
pageType: referrer === LOGIN_PAGE ? PAGE_TYPES.SIGN_IN : PAGE_TYPES.ACCOUNT_CREATION,
elementType: ELEMENT_TYPES.BUTTON,
webElementText: providerName,
webElementName: providerName.toLowerCase(),
};
// This event is used by cohesion upon successful login
trackCohesionEvent(eventData);
if (referrer === REGISTER_PAGE) {
setCookie('marketingEmailsOptIn', registrationFields?.configurableFormFields?.marketingEmailsOptIn);
}
const url = e.currentTarget.dataset.providerUrl;
window.location.href = getConfig().LMS_BASE_URL + url;
redirectWithDelay(getConfig().LMS_BASE_URL + url);
}
const socialAuth = socialAuthProviders.map((provider, index) => (
@@ -28,7 +47,7 @@ const SocialAuthProviders = (props) => {
type="button"
className={`btn-social btn-${provider.id} ${index % 2 === 0 ? 'mr-3' : ''}`}
data-provider-url={referrer === LOGIN_PAGE ? provider.loginUrl : provider.registerUrl}
onClick={handleSubmit}
onClick={(event) => handleSubmit(event, provider?.name)}
>
{provider.iconImage ? (
<div aria-hidden="true">

View File

@@ -7,6 +7,7 @@ import PropTypes from 'prop-types';
import messages from './messages';
import { LOGIN_PAGE, REGISTER_PAGE } from '../data/constants';
import setCookie from '../data/utils/cookies';
const ThirdPartyAuthAlert = (props) => {
const { formatMessage } = useIntl();
@@ -20,7 +21,10 @@ const ThirdPartyAuthAlert = (props) => {
message = formatMessage(messages['register.third.party.auth.account.not.linked'], { currentProvider, platformName });
}
if (!currentProvider) {
if (currentProvider) {
// Setting this cookie to capture marketingEmailsOptIn for SSO flow on the onboarding component
setCookie('ssoPipelineRedirectionDone', true);
} else {
return null;
}

View File

@@ -4,9 +4,8 @@ import { getConfig } from '@edx/frontend-platform';
import { fetchAuthenticatedUser, getAuthenticatedUser } from '@edx/frontend-platform/auth';
import PropTypes from 'prop-types';
import {
DEFAULT_REDIRECT_URL,
} from '../data/constants';
import { RESET_PAGE } from '../data/constants';
import { updatePathWithQueryParams } from '../data/utils';
/**
* This wrapper redirects the requester to our default redirect url if they are
@@ -25,7 +24,12 @@ const UnAuthOnlyRoute = ({ children }) => {
if (isReady) {
if (authUser && authUser.username) {
global.location.href = getConfig().LMS_BASE_URL.concat(DEFAULT_REDIRECT_URL);
const updatedPath = updatePathWithQueryParams(window.location.pathname);
if (updatedPath.startsWith(RESET_PAGE)) {
global.location.href = getConfig().LMS_BASE_URL;
return null;
}
global.location.href = getConfig().LMS_BASE_URL.concat(updatedPath);
return null;
}

View File

@@ -13,9 +13,15 @@ export const getThirdPartyAuthContextBegin = () => ({
type: THIRD_PARTY_AUTH_CONTEXT.BEGIN,
});
export const getThirdPartyAuthContextSuccess = (fieldDescriptions, optionalFields, thirdPartyAuthContext) => ({
export const getThirdPartyAuthContextSuccess = (
fieldDescriptions,
optionalFields,
thirdPartyAuthContext,
countriesCodesList) => ({
type: THIRD_PARTY_AUTH_CONTEXT.SUCCESS,
payload: { fieldDescriptions, optionalFields, thirdPartyAuthContext },
payload: {
fieldDescriptions, optionalFields, thirdPartyAuthContext, countriesCodesList,
},
});
export const getThirdPartyAuthContextFailure = () => ({

View File

@@ -0,0 +1,83 @@
export const registerFields = {
fields: {
country: {
name: 'country',
error_message: 'Select your country or region of residence',
},
honor_code: {
name: 'honor_code',
type: 'tos_and_honor_code',
error_message: '',
},
},
};
export const progressiveProfilingFields = {
extended_profile: [],
fields: {
level_of_education: {
name: 'level_of_education',
type: 'select',
label: 'Highest level of education completed',
error_message: '',
options: [
[
'p',
'Doctorate',
],
[
'm',
"Master's or professional degree",
],
[
'b',
"Bachelor's degree",
],
[
'a',
'Associate degree',
],
[
'hs',
'Secondary/high school',
],
[
'jhs',
'Junior secondary/junior high/middle school',
],
[
'none',
'No formal education',
],
[
'other',
'Other education',
],
],
},
gender: {
name: 'gender',
type: 'select',
label: 'Gender',
error_message: '',
options: [
[
'm',
'Male',
],
[
'f',
'Female',
],
[
'o',
'Other/Prefer Not to Say',
],
],
},
},
};
export const FIELD_LABELS = {
COUNTRY: 'country',
};

View File

@@ -35,6 +35,7 @@ const reducer = (state = defaultState, action = {}) => {
optionalFields: action.payload.optionalFields,
thirdPartyAuthContext: action.payload.thirdPartyAuthContext,
thirdPartyAuthApiStatus: COMPLETE_STATE,
countriesCodesList: action.payload.countriesCodesList,
};
}
case THIRD_PARTY_AUTH_CONTEXT.FAILURE:

View File

@@ -1,3 +1,4 @@
import { getConfig } from '@edx/frontend-platform';
import { logError } from '@edx/frontend-platform/logging';
import { call, put, takeEvery } from 'redux-saga/effects';
@@ -7,7 +8,9 @@ import {
getThirdPartyAuthContextSuccess,
THIRD_PARTY_AUTH_CONTEXT,
} from './actions';
import { progressiveProfilingFields, registerFields } from './constants';
import {
getCountryList,
getThirdPartyAuthContext,
} from './service';
import { setCountryFromThirdPartyAuthContext } from '../../register/data/actions';
@@ -18,9 +21,25 @@ export function* fetchThirdPartyAuthContext(action) {
const {
fieldDescriptions, optionalFields, thirdPartyAuthContext,
} = yield call(getThirdPartyAuthContext, action.payload.urlParams);
const countriesCodesList = (yield call(getCountryList)) || [];
yield put(setCountryFromThirdPartyAuthContext(thirdPartyAuthContext.countryCode));
yield put(getThirdPartyAuthContextSuccess(fieldDescriptions, optionalFields, thirdPartyAuthContext));
// hard code country field, level of education and gender fields
if (getConfig().ENABLE_HARD_CODE_OPTIONAL_FIELDS) {
yield put(getThirdPartyAuthContextSuccess(
registerFields,
progressiveProfilingFields,
thirdPartyAuthContext,
countriesCodesList,
));
} else {
yield put(getThirdPartyAuthContextSuccess(
fieldDescriptions,
optionalFields,
thirdPartyAuthContext,
countriesCodesList,
));
}
} catch (e) {
yield put(getThirdPartyAuthContextFailure());
logError(e);

View File

@@ -1,5 +1,8 @@
import { getConfig } from '@edx/frontend-platform';
import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
import { logError } from '@edx/frontend-platform/logging';
import { FIELD_LABELS } from './constants';
// eslint-disable-next-line import/prefer-default-export
export async function getThirdPartyAuthContext(urlParams) {
@@ -23,3 +26,28 @@ export async function getThirdPartyAuthContext(urlParams) {
thirdPartyAuthContext: data.contextData || {},
};
}
function extractCountryList(data) {
return data?.fields
.find(({ name }) => name === FIELD_LABELS.COUNTRY)
?.options?.map(({ value }) => (value)) || [];
}
export async function getCountryList() {
try {
const requestConfig = {
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
isPublic: true,
};
const { data } = await getAuthenticatedHttpClient()
.get(
`${getConfig().LMS_BASE_URL}/user_api/v1/account/registration/`,
requestConfig,
);
return extractCountryList(data);
} catch (e) {
logError(e);
return [];
}
}

View File

@@ -8,6 +8,11 @@ import * as api from '../service';
const { loggingService } = initializeMockLogging();
jest.mock('../service', () => ({
getCountryList: jest.fn(),
getThirdPartyAuthContext: jest.fn(),
}));
describe('fetchThirdPartyAuthContext', () => {
const params = {
payload: { urlParams: {} },
@@ -31,6 +36,7 @@ describe('fetchThirdPartyAuthContext', () => {
thirdPartyAuthContext: data,
fieldDescriptions: {},
optionalFields: {},
countriesCodesList: [],
}));
const dispatched = [];
@@ -44,7 +50,7 @@ describe('fetchThirdPartyAuthContext', () => {
expect(dispatched).toEqual([
actions.getThirdPartyAuthContextBegin(),
setCountryFromThirdPartyAuthContext(),
actions.getThirdPartyAuthContextSuccess({}, {}, data),
actions.getThirdPartyAuthContextSuccess({}, {}, data, []),
]);
getThirdPartyAuthContext.mockClear();
});

View File

@@ -2,6 +2,7 @@ export { default as RedirectLogistration } from './RedirectLogistration';
export { default as registerIcons } from './RegisterFaIcons';
export { default as EmbeddedRegistrationRoute } from './EmbeddedRegistrationRoute';
export { default as UnAuthOnlyRoute } from './UnAuthOnlyRoute';
export { default as RouteTracker } from './RouteTracker';
export { default as NotFoundPage } from './NotFoundPage';
export { default as SocialAuthProviders } from './SocialAuthProviders';
export { default as ThirdPartyAuthAlert } from './ThirdPartyAuthAlert';

View File

@@ -1,6 +1,7 @@
import React from 'react';
import { Provider } from 'react-redux';
import { IntlProvider } from '@edx/frontend-platform/i18n';
import { injectIntl, IntlProvider } from '@edx/frontend-platform/i18n';
import { fireEvent, render } from '@testing-library/react';
import { act } from 'react-dom/test-utils';
import { MemoryRouter } from 'react-router-dom';
@@ -36,6 +37,7 @@ describe('FormGroup', () => {
describe('PasswordField', () => {
const mockStore = configureStore();
const IntlPasswordField = injectIntl(PasswordField);
let props = {};
let store = {};
@@ -64,7 +66,7 @@ describe('PasswordField', () => {
});
it('should show/hide password on icon click', () => {
const { getByLabelText } = render(reduxWrapper(<PasswordField {...props} />));
const { getByLabelText } = render(reduxWrapper(<IntlPasswordField {...props} />));
const passwordInput = getByLabelText('Password');
const showPasswordButton = getByLabelText('Show password');
@@ -77,7 +79,7 @@ describe('PasswordField', () => {
});
it('should show password requirement tooltip on focus', async () => {
const { getByLabelText } = render(reduxWrapper(<PasswordField {...props} />));
const { getByLabelText } = render(reduxWrapper(<IntlPasswordField {...props} />));
const passwordInput = getByLabelText('Password');
jest.useFakeTimers();
await act(async () => {
@@ -94,7 +96,7 @@ describe('PasswordField', () => {
...props,
value: '',
};
const { getByLabelText } = render(reduxWrapper(<PasswordField {...props} />));
const { getByLabelText } = render(reduxWrapper(<IntlPasswordField {...props} />));
const passwordInput = getByLabelText('Password');
jest.useFakeTimers();
await act(async () => {
@@ -117,7 +119,7 @@ describe('PasswordField', () => {
});
it('should update password requirement checks', async () => {
const { getByLabelText } = render(reduxWrapper(<PasswordField {...props} />));
const { getByLabelText } = render(reduxWrapper(<IntlPasswordField {...props} />));
const passwordInput = getByLabelText('Password');
jest.useFakeTimers();
await act(async () => {
@@ -140,7 +142,7 @@ describe('PasswordField', () => {
});
it('should not run validations when blur is fired on password icon click', () => {
const { container, getByLabelText } = render(reduxWrapper(<PasswordField {...props} />));
const { container, getByLabelText } = render(reduxWrapper(<IntlPasswordField {...props} />));
const passwordInput = container.querySelector('input[name="password"]');
const passwordIcon = getByLabelText('Show password');
@@ -161,7 +163,7 @@ describe('PasswordField', () => {
...props,
handleBlur: jest.fn(),
};
const { container } = render(reduxWrapper(<PasswordField {...props} />));
const { container } = render(reduxWrapper(<IntlPasswordField {...props} />));
const passwordInput = container.querySelector('input[name="password"]');
fireEvent.blur(passwordInput, {
@@ -179,7 +181,7 @@ describe('PasswordField', () => {
...props,
handleErrorChange: jest.fn(),
};
const { container } = render(reduxWrapper(<PasswordField {...props} />));
const { container } = render(reduxWrapper(<IntlPasswordField {...props} />));
const passwordInput = container.querySelector('input[name="password"]');
fireEvent.blur(passwordInput, {
@@ -202,7 +204,7 @@ describe('PasswordField', () => {
handleErrorChange: jest.fn(),
};
const { getByLabelText } = render(reduxWrapper(<PasswordField {...props} />));
const { getByLabelText } = render(reduxWrapper(<IntlPasswordField {...props} />));
const passwordIcon = getByLabelText('Show password');
@@ -222,7 +224,7 @@ describe('PasswordField', () => {
handleErrorChange: jest.fn(),
};
const { getByLabelText } = render(reduxWrapper(<PasswordField {...props} />));
const { getByLabelText } = render(reduxWrapper(<IntlPasswordField {...props} />));
const passwordIcon = getByLabelText('Show password');
@@ -246,7 +248,7 @@ describe('PasswordField', () => {
...props,
handleErrorChange: jest.fn(),
};
const { getByLabelText } = render(reduxWrapper(<PasswordField {...props} />));
const { getByLabelText } = render(reduxWrapper(<IntlPasswordField {...props} />));
const passwordField = getByLabelText('Password');
fireEvent.blur(passwordField, {
target: {
@@ -266,7 +268,7 @@ describe('PasswordField', () => {
handleErrorChange: jest.fn(),
handleBlur: jest.fn(),
};
const { getByLabelText } = render(reduxWrapper(<PasswordField {...props} />));
const { getByLabelText } = render(reduxWrapper(<IntlPasswordField {...props} />));
const passwordIcon = getByLabelText('Show password');

View File

@@ -1,16 +1,35 @@
import React from 'react';
import { Provider } from 'react-redux';
import { IntlProvider } from '@edx/frontend-platform/i18n';
import renderer from 'react-test-renderer';
import configureStore from 'redux-mock-store';
import registerIcons from '../RegisterFaIcons';
import SocialAuthProviders from '../SocialAuthProviders';
registerIcons();
const mockStore = configureStore();
describe('SocialAuthProviders', () => {
let props = {};
const initialState = {
register: {
registrationFormData: {
configurableFormFields: {
marketingEmailsOptIn: true,
},
},
},
};
const store = mockStore(initialState);
const reduxWrapper = children => (
<IntlProvider locale="en">
<Provider store={store}>{children}</Provider>
</IntlProvider>
);
const appleProvider = {
id: 'oa2-apple-id',
name: 'Apple',
@@ -30,11 +49,11 @@ describe('SocialAuthProviders', () => {
it('should match social auth provider with iconImage snapshot', () => {
props = { socialAuthProviders: [appleProvider, facebookProvider] };
const tree = renderer.create(
const tree = renderer.create(reduxWrapper(
<IntlProvider locale="en">
<SocialAuthProviders {...props} />
</IntlProvider>,
).toJSON();
)).toJSON();
expect(tree).toMatchSnapshot();
});
@@ -48,11 +67,11 @@ describe('SocialAuthProviders', () => {
}],
};
const tree = renderer.create(
const tree = renderer.create(reduxWrapper(
<IntlProvider locale="en">
<SocialAuthProviders {...props} />
</IntlProvider>,
).toJSON();
)).toJSON();
expect(tree).toMatchSnapshot();
});
@@ -66,11 +85,11 @@ describe('SocialAuthProviders', () => {
}],
};
const tree = renderer.create(
const tree = renderer.create(reduxWrapper(
<IntlProvider locale="en">
<SocialAuthProviders {...props} />
</IntlProvider>,
).toJSON();
)).toJSON();
expect(tree).toMatchSnapshot();
});

View File

@@ -11,6 +11,7 @@ const configuration = {
MARKETING_EMAILS_OPT_IN: process.env.MARKETING_EMAILS_OPT_IN || '',
SHOW_CONFIGURABLE_EDX_FIELDS: process.env.SHOW_CONFIGURABLE_EDX_FIELDS || false,
SHOW_REGISTRATION_LINKS: process.env.SHOW_REGISTRATION_LINKS !== 'false',
ENABLE_HARD_CODE_OPTIONAL_FIELDS: process.env.ENABLE_HARD_CODE_OPTIONAL_FIELDS || false,
ENABLE_IMAGE_LAYOUT: process.env.ENABLE_IMAGE_LAYOUT || false,
// Links
ACTIVATION_EMAIL_SUPPORT_LINK: process.env.ACTIVATION_EMAIL_SUPPORT_LINK || null,
@@ -35,6 +36,7 @@ const configuration = {
ZENDESK_LOGO_URL: process.env.ZENDESK_LOGO_URL,
ALGOLIA_APP_ID: process.env.ALGOLIA_APP_ID || '',
ALGOLIA_SEARCH_API_KEY: process.env.ALGOLIA_SEARCH_API_KEY || '',
AUTO_GENERATED_USERNAME_EXPERIMENT_ID: process.env.AUTO_GENERATED_USERNAME_EXPERIMENT_ID || '',
};
export default configuration;

View File

@@ -37,3 +37,4 @@ export const VALID_EMAIL_REGEX = '(^[-!#$%&\'*+/=?^_`{}|~0-9A-Z]+(\\.[-!#$%&\'*+
// things like auto-enrollment upon login and registration.
export const AUTH_PARAMS = ['course_id', 'enrollment_action', 'course_mode', 'email_opt_in', 'purchase_workflow', 'next', 'register_for_free', 'track', 'is_account_recovery', 'variant', 'host', 'cta'];
export const REDIRECT = 'redirect';
export const APP_NAME = 'authn_mfe';

View File

@@ -1,5 +1,6 @@
import { combineReducers } from 'redux';
import { reducer as cohesionReducer, storeName as cohesionStoreName } from '../cohesion/data/reducers';
import {
reducer as commonComponentsReducer,
storeName as commonComponentsStoreName,
@@ -31,6 +32,7 @@ const createRootReducer = () => combineReducers({
[commonComponentsStoreName]: commonComponentsReducer,
[forgotPasswordStoreName]: forgotPasswordReducer,
[resetPasswordStoreName]: resetPasswordReducer,
[cohesionStoreName]: cohesionReducer,
[authnProgressiveProfilingStoreName]: authnProgressiveProfilingReducers,
});
export default createRootReducer;

37
src/data/segment/utils.js Normal file
View File

@@ -0,0 +1,37 @@
/* eslint-disable import/prefer-default-export */
import { sendPageEvent, sendTrackEvent } from '@edx/frontend-platform/analytics';
import { APP_NAME } from '../constants';
export const LINK_TIMEOUT = 300;
/**
* Creates an event tracker function that sends a tracking event with the given name and options.
*
* @param {string} name - The name of the event to be tracked.
* @param {object} [options={}] - Additional options to be included with the event.
* @returns {function} - A function that, when called, sends the tracking event.
*/
export const createEventTracker = (name, options = {}) => () => sendTrackEvent(
name,
{ ...options, app_name: APP_NAME },
);
/**
* Creates an event tracker function that sends a tracking event with the given name and options.
*
* @param {string} name - The name of the event to be tracked.
* @param {object} [options={}] - Additional options to be included with the event.
* @returns {function} - A function that, when called, sends the tracking event.
*/
export const createPageEventTracker = (name, options = null) => () => sendPageEvent(
name,
options,
{ app_name: APP_NAME },
);
export const createLinkTracker = (tracker, href) => (e) => {
e.preventDefault();
tracker();
return setTimeout(() => { window.location.href = href; }, LINK_TIMEOUT);
};

View File

@@ -11,3 +11,11 @@ export default function setCookie(cookieName, cookieValue, cookieExpiry) {
cookies.set(cookieName, cookieValue, options);
}
}
export function removeCookie(cookieName) {
if (cookieName) {
const cookies = new Cookies();
const options = { domain: getConfig().SESSION_COOKIE_DOMAIN, path: '/' };
cookies.remove(cookieName, options);
}
}

View File

@@ -81,3 +81,9 @@ export const isHostAvailableInQueryParams = () => {
const queryParams = getAllPossibleQueryParams();
return 'host' in queryParams;
};
export const redirectWithDelay = (redirectUrl) => {
setTimeout(() => {
window.location.href = redirectUrl;
}, 1000);
};

View File

@@ -8,4 +8,4 @@ export {
windowScrollTo,
} from './dataUtils';
export { default as AsyncActionType } from './reduxUtils';
export { default as setCookie } from './cookies';
export { default as setCookie, removeCookie } from './cookies';

View File

@@ -2,7 +2,6 @@ import React, { useEffect, useState } from 'react';
import { connect } from 'react-redux';
import { getConfig } from '@edx/frontend-platform';
import { sendPageEvent, sendTrackEvent } from '@edx/frontend-platform/analytics';
import { useIntl } from '@edx/frontend-platform/i18n';
import {
Form,
@@ -25,6 +24,10 @@ import BaseContainer from '../base-container';
import { FormGroup } from '../common-components';
import { DEFAULT_STATE, LOGIN_PAGE, VALID_EMAIL_REGEX } from '../data/constants';
import { updatePathWithQueryParams, windowScrollTo } from '../data/utils';
import {
trackForgotPasswordPageEvent,
trackForgotPasswordPageViewed,
} from '../tracking/trackers/forgotpassword';
const ForgotPasswordPage = (props) => {
const platformName = getConfig().SITE_NAME;
@@ -41,8 +44,8 @@ const ForgotPasswordPage = (props) => {
const navigate = useNavigate();
useEffect(() => {
sendPageEvent('login_and_registration', 'reset');
sendTrackEvent('edx.bi.password_reset_form.viewed', { category: 'user-engagement' });
trackForgotPasswordPageEvent();
trackForgotPasswordPageViewed();
}, []);
useEffect(() => {

View File

@@ -1,7 +1,8 @@
import React from 'react';
import { Provider } from 'react-redux';
import { mergeConfig } from '@edx/frontend-platform';
import { configure, IntlProvider } from '@edx/frontend-platform/i18n';
import { configure, injectIntl, IntlProvider } from '@edx/frontend-platform/i18n';
import {
fireEvent, render, screen,
} from '@testing-library/react';
@@ -25,6 +26,7 @@ jest.mock('react-router-dom', () => ({
useNavigate: () => mockedNavigator,
}));
const IntlForgotPasswordPage = injectIntl(ForgotPasswordPage);
const mockStore = configureStore();
const initialState = {
@@ -76,7 +78,7 @@ describe('ForgotPasswordPage', () => {
);
it('not should display need other help signing in button', () => {
const { queryByTestId } = render(reduxWrapper(<ForgotPasswordPage {...props} />));
const { queryByTestId } = render(reduxWrapper(<IntlForgotPasswordPage {...props} />));
const forgotPasswordButton = queryByTestId('forgot-password');
expect(forgotPasswordButton).toBeNull();
});
@@ -85,14 +87,14 @@ describe('ForgotPasswordPage', () => {
mergeConfig({
LOGIN_ISSUE_SUPPORT_LINK: '/support',
});
render(reduxWrapper(<ForgotPasswordPage {...props} />));
render(reduxWrapper(<IntlForgotPasswordPage {...props} />));
const forgotPasswordButton = screen.findByText('Need help signing in?');
expect(forgotPasswordButton).toBeDefined();
});
it('should display email validation error message', async () => {
const validationMessage = 'We were unable to contact you.Enter a valid email address below.';
const { container } = render(reduxWrapper(<ForgotPasswordPage {...props} />));
const { container } = render(reduxWrapper(<IntlForgotPasswordPage {...props} />));
const emailInput = screen.getByLabelText('Email');
@@ -113,7 +115,7 @@ describe('ForgotPasswordPage', () => {
const expectedMessage = 'We were unable to contact you.'
+ 'An error has occurred. Try refreshing the page, or check your internet connection.';
const { container } = render(reduxWrapper(<ForgotPasswordPage {...props} />));
const { container } = render(reduxWrapper(<IntlForgotPasswordPage {...props} />));
const alertElements = container.querySelectorAll('.alert-danger');
const validationErrors = alertElements[0].textContent;
@@ -122,7 +124,7 @@ describe('ForgotPasswordPage', () => {
it('should display empty email validation message', async () => {
const validationMessage = 'We were unable to contact you.Enter your email below.';
const { container } = render(reduxWrapper(<ForgotPasswordPage {...props} />));
const { container } = render(reduxWrapper(<IntlForgotPasswordPage {...props} />));
const submitButton = screen.getByText('Submit');
fireEvent.click(submitButton);
@@ -139,7 +141,7 @@ describe('ForgotPasswordPage', () => {
forgotPassword: { status: 'forbidden' },
});
const { container } = render(reduxWrapper(<ForgotPasswordPage {...props} />));
const { container } = render(reduxWrapper(<IntlForgotPasswordPage {...props} />));
const alertElements = container.querySelectorAll('.alert-danger');
const validationErrors = alertElements[0].textContent;
@@ -147,7 +149,7 @@ describe('ForgotPasswordPage', () => {
});
it('should not display any error message on change event', () => {
render(reduxWrapper(<ForgotPasswordPage {...props} />));
render(reduxWrapper(<IntlForgotPasswordPage {...props} />));
const emailInput = screen.getByLabelText('Email');
@@ -170,7 +172,7 @@ describe('ForgotPasswordPage', () => {
};
store.dispatch = jest.fn(store.dispatch);
render(reduxWrapper(<ForgotPasswordPage {...props} />));
render(reduxWrapper(<IntlForgotPasswordPage {...props} />));
const emailInput = screen.getByLabelText('Email');
fireEvent.blur(emailInput);
@@ -185,7 +187,7 @@ describe('ForgotPasswordPage', () => {
emailValidationError: validationMessage,
email: '',
};
const { container } = render(reduxWrapper(<ForgotPasswordPage {...props} />));
const { container } = render(reduxWrapper(<IntlForgotPasswordPage {...props} />));
const validationElement = container.querySelector('.pgn__form-text-invalid');
expect(validationElement.textContent).toEqual(validationMessage);
});
@@ -203,7 +205,7 @@ describe('ForgotPasswordPage', () => {
store.dispatch = jest.fn(store.dispatch);
render(reduxWrapper(<ForgotPasswordPage {...props} />));
render(reduxWrapper(<IntlForgotPasswordPage {...props} />));
const emailInput = screen.getByLabelText('Email');
fireEvent.focus(emailInput);
@@ -217,7 +219,7 @@ describe('ForgotPasswordPage', () => {
emailValidationError: '',
email: '',
};
render(reduxWrapper(<ForgotPasswordPage {...props} />));
render(reduxWrapper(<IntlForgotPasswordPage {...props} />));
const errorElement = screen.queryByTestId('email-invalid-feedback');
expect(errorElement).toBeNull();
});
@@ -234,7 +236,7 @@ describe('ForgotPasswordPage', () => {
+ 'receive a password reset message after 1 minute, verify that you entered the correct email address,'
+ ' or check your spam folder. If you need further assistance, contact technical support.';
const { container } = render(reduxWrapper(<ForgotPasswordPage {...props} />));
const { container } = render(reduxWrapper(<IntlForgotPasswordPage {...props} />));
const successElement = findByTextContent(container, successMessage);
expect(successElement).toBeDefined();
@@ -252,7 +254,7 @@ describe('ForgotPasswordPage', () => {
+ 'This password reset link is invalid. It may have been used already. '
+ 'Enter your email below to receive a new link.';
const { container } = render(reduxWrapper(<ForgotPasswordPage {...props} />));
const { container } = render(reduxWrapper(<IntlForgotPasswordPage {...props} />));
const successElement = findByTextContent(container, successMessage);
expect(successElement).toBeDefined();
@@ -260,7 +262,7 @@ describe('ForgotPasswordPage', () => {
});
it('should redirect onto login page', async () => {
const { container } = render(reduxWrapper(<ForgotPasswordPage {...props} />));
const { container } = render(reduxWrapper(<IntlForgotPasswordPage {...props} />));
const navElement = container.querySelector('nav');
const anchorElement = navElement.querySelector('a');

View File

@@ -2,7 +2,7 @@ import React from 'react';
import { getConfig } from '@edx/frontend-platform';
import { FormattedMessage, useIntl } from '@edx/frontend-platform/i18n';
import { Alert } from '@openedx/paragon';
import { Alert, Hyperlink } from '@openedx/paragon';
import { CheckCircle, Error } from '@openedx/paragon/icons';
import PropTypes from 'prop-types';
@@ -36,19 +36,17 @@ const AccountActivationMessage = ({ messageType }) => {
break;
}
case ACCOUNT_ACTIVATION_MESSAGE.ERROR: {
const supportLink = (
<Alert.Link href={getConfig().ACTIVATION_EMAIL_SUPPORT_LINK}>
{formatMessage(messages['account.activation.support.link'])}
</Alert.Link>
const supportEmail = (
<Hyperlink isInline destination={`mailto:${getConfig().INFO_EMAIL}`}>{getConfig().INFO_EMAIL}</Hyperlink>
);
heading = formatMessage(messages[`account.${activationOrConfirmation}.error.message.title`]);
activationMessage = (
<FormattedMessage
id="account.activation.error.message"
defaultMessage="Something went wrong, please {supportLink} to resolve this issue."
defaultMessage="Something went wrong, please contact {supportEmail} to resolve this issue."
description="Account activation error message"
values={{ supportLink }}
values={{ supportEmail }}
/>
);
break;

View File

@@ -1,4 +1,5 @@
import React, { useEffect, useState } from 'react';
import { useSelector } from 'react-redux';
import { getConfig } from '@edx/frontend-platform';
import { useIntl } from '@edx/frontend-platform/i18n';
@@ -10,19 +11,23 @@ import PropTypes from 'prop-types';
import { Link, useNavigate } from 'react-router-dom';
import messages from './messages';
import trackCohesionEvent from '../cohesion/trackers';
import { DEFAULT_REDIRECT_URL, RESET_PAGE } from '../data/constants';
import { updatePathWithQueryParams } from '../data/utils';
import { redirectWithDelay } from '../data/utils/dataUtils';
import useMobileResponsive from '../data/utils/useMobileResponsive';
const ChangePasswordPrompt = ({ variant, redirectUrl }) => {
const isMobileView = useMobileResponsive();
const [redirectToResetPasswordPage, setRedirectToResetPasswordPage] = useState(false);
const cohesionEventData = useSelector(state => state.cohesion.eventData);
const handlers = {
handleToggleOff: () => {
if (variant === 'block') {
setRedirectToResetPasswordPage(true);
} else {
window.location.href = redirectUrl || getConfig().LMS_BASE_URL.concat(DEFAULT_REDIRECT_URL);
trackCohesionEvent(cohesionEventData);
redirectWithDelay(redirectUrl || getConfig().LMS_BASE_URL.concat(DEFAULT_REDIRECT_URL));
}
},
};

View File

@@ -1,17 +1,29 @@
import {
useCallback, useEffect, useMemo, useState,
} from 'react';
import { useDispatch, useSelector } from 'react-redux';
import React, { useEffect, useMemo, useState } from 'react';
import { connect, useDispatch } from 'react-redux';
import { getConfig } from '@edx/frontend-platform';
import { sendPageEvent, sendTrackEvent } from '@edx/frontend-platform/analytics';
import { useIntl } from '@edx/frontend-platform/i18n';
import { Form, StatefulButton } from '@openedx/paragon';
import { injectIntl, useIntl } from '@edx/frontend-platform/i18n';
import {
Form, StatefulButton,
} from '@openedx/paragon';
import PropTypes from 'prop-types';
import { Helmet } from 'react-helmet';
import Skeleton from 'react-loading-skeleton';
import { Link } from 'react-router-dom';
import AccountActivationMessage from './AccountActivationMessage';
import {
backupLoginFormBegin,
dismissPasswordResetBanner,
loginRequest,
} from './data/actions';
import { INVALID_FORM, TPA_AUTHENTICATION_FAILURE } from './data/constants';
import LoginFailureMessage from './LoginFailure';
import messages from './messages';
import {
ELEMENT_NAME, ELEMENT_TEXT, ELEMENT_TYPES, PAGE_TYPES,
} from '../cohesion/constants';
import { setCohesionEventStates } from '../cohesion/data/actions';
import {
FormGroup,
InstitutionLogistration,
@@ -19,12 +31,11 @@ import {
RedirectLogistration,
ThirdPartyAuthAlert,
} from '../common-components';
import AccountActivationMessage from './AccountActivationMessage';
import { getThirdPartyAuthContext } from '../common-components/data/actions';
import { thirdPartyAuthContextSelector } from '../common-components/data/selectors';
import EnterpriseSSO from '../common-components/EnterpriseSSO';
import ThirdPartyAuth from '../common-components/ThirdPartyAuth';
import { PENDING_STATE, RESET_PAGE } from '../data/constants';
import { DEFAULT_STATE, PENDING_STATE, RESET_PAGE } from '../data/constants';
import {
getActivationStatus,
getAllPossibleQueryParams,
@@ -32,72 +43,65 @@ import {
getTpaProvider,
updatePathWithQueryParams,
} from '../data/utils';
import { removeCookie } from '../data/utils/cookies';
import ResetPasswordSuccess from '../reset-password/ResetPasswordSuccess';
import { backupLoginFormBegin, dismissPasswordResetBanner, loginRequest } from './data/actions';
import { INVALID_FORM, TPA_AUTHENTICATION_FAILURE } from './data/constants';
import LoginFailureMessage from './LoginFailure';
import messages from './messages';
import {
trackForgotPasswordLinkClick, trackLoginPageViewed, trackLoginSuccess,
} from '../tracking/trackers/login';
const LoginPage = ({
institutionLogin,
handleInstitutionLogin,
}) => {
const dispatch = useDispatch();
const backupFormState = useCallback((data) => dispatch(backupLoginFormBegin(data)), [dispatch]);
const getTPADataFromBackend = useCallback(() => dispatch(getThirdPartyAuthContext()), [dispatch]);
const LoginPage = (props) => {
const {
backedUpFormData,
loginErrorCode,
loginErrorContext,
loginResult,
shouldBackupState,
thirdPartyAuthContext: {
providers,
currentProvider,
secondaryProviders,
finishAuthUrl,
platformName,
errorMessage: thirdPartyErrorMessage,
},
thirdPartyAuthApiStatus,
institutionLogin,
showResetPasswordSuccessBanner,
submitState,
thirdPartyAuthContext,
thirdPartyAuthApiStatus,
} = useSelector((state) => ({
backedUpFormData: state.login.loginFormData,
loginErrorCode: state.login.loginErrorCode,
loginErrorContext: state.login.loginErrorContext,
loginResult: state.login.loginResult,
shouldBackupState: state.login.shouldBackupState,
showResetPasswordSuccessBanner: state.login.showResetPasswordSuccessBanner,
submitState: state.login.submitState,
thirdPartyAuthContext: thirdPartyAuthContextSelector(state),
thirdPartyAuthApiStatus: state.commonComponents.thirdPartyAuthApiStatus,
}));
const {
providers,
currentProvider,
secondaryProviders,
finishAuthUrl,
platformName,
errorMessage: thirdPartyErrorMessage,
} = thirdPartyAuthContext;
// Actions
backupFormState,
handleInstitutionLogin,
getTPADataFromBackend,
} = props;
const { formatMessage } = useIntl();
const dispatch = useDispatch();
const activationMsgType = getActivationStatus();
const queryParams = useMemo(() => getAllPossibleQueryParams(), []);
const [formFields, setFormFields] = useState({ ...backedUpFormData.formFields });
const [errorCode, setErrorCode] = useState({
type: '',
count: 0,
context: {},
});
const [errorCode, setErrorCode] = useState({ type: '', count: 0, context: {} });
const [errors, setErrors] = useState({ ...backedUpFormData.errors });
const tpaHint = getTpaHint();
useEffect(() => {
sendPageEvent('login_and_registration', 'login');
trackLoginPageViewed();
}, []);
useEffect(() => {
if (loginResult.success) {
trackLoginSuccess();
// Remove this cookie that was set to capture marketingEmailsOptIn for the onboarding component
removeCookie('ssoPipelineRedirectionDone');
}
}, [loginResult]);
useEffect(() => {
const payload = { ...queryParams };
if (tpaHint) {
payload.tpa_hint = tpaHint;
}
getTPADataFromBackend(payload);
}, [queryParams, tpaHint, getTPADataFromBackend]);
}, [getTPADataFromBackend, queryParams, tpaHint]);
/**
* Backup the login form in redux when login page is toggled.
*/
@@ -108,7 +112,7 @@ const LoginPage = ({
errors: { ...errors },
});
}
}, [backupFormState, shouldBackupState, formFields, errors]);
}, [shouldBackupState, formFields, errors, backupFormState]);
useEffect(() => {
if (loginErrorCode) {
@@ -133,10 +137,7 @@ const LoginPage = ({
}, [thirdPartyErrorMessage]);
const validateFormFields = (payload) => {
const {
emailOrUsername,
password,
} = payload;
const { emailOrUsername, password } = payload;
const fieldErrors = { ...errors };
if (emailOrUsername === '') {
@@ -153,19 +154,24 @@ const LoginPage = ({
const handleSubmit = (event) => {
event.preventDefault();
const eventData = {
pageType: PAGE_TYPES.SIGN_IN,
elementType: ELEMENT_TYPES.BUTTON,
webElementText: ELEMENT_TEXT.SIGN_IN,
webElementName: ELEMENT_NAME.SIGN_IN,
};
dispatch(setCohesionEventStates(eventData));
if (showResetPasswordSuccessBanner) {
dispatch(dismissPasswordResetBanner());
props.dismissPasswordResetBanner();
}
const formData = { ...formFields };
const validationErrors = validateFormFields(formData);
if (validationErrors.emailOrUsername || validationErrors.password) {
setErrors({ ...validationErrors });
setErrorCode(prevState => ({
type: INVALID_FORM,
count: prevState.count + 1,
context: {},
}));
setErrorCode(prevState => ({ type: INVALID_FORM, count: prevState.count + 1, context: {} }));
return;
}
@@ -175,35 +181,20 @@ const LoginPage = ({
password: formData.password,
...queryParams,
};
dispatch(loginRequest(payload));
props.loginRequest(payload);
};
const handleOnChange = (event) => {
const {
name,
value,
} = event.target;
setFormFields(prevState => ({
...prevState,
[name]: value,
}));
const { name, value } = event.target;
setFormFields(prevState => ({ ...prevState, [name]: value }));
};
const handleOnFocus = (event) => {
const { name } = event.target;
setErrors(prevErrors => ({
...prevErrors,
[name]: '',
}));
};
const trackForgotPasswordLinkClick = () => {
sendTrackEvent('edx.bi.password-reset_form.toggled', { category: 'user-engagement' });
setErrors(prevErrors => ({ ...prevErrors, [name]: '' }));
};
const {
provider,
skipHintedLogin,
} = getTpaProvider(tpaHint, providers, secondaryProviders);
const { provider, skipHintedLogin } = getTpaProvider(tpaHint, providers, secondaryProviders);
if (tpaHint) {
if (thirdPartyAuthApiStatus === PENDING_STATE) {
@@ -237,6 +228,7 @@ const LoginPage = ({
success={loginResult.success}
redirectUrl={loginResult.redirectUrl}
finishAuthUrl={finishAuthUrl}
currentProvider={currentProvider}
/>
<div className="mw-xs mt-3 mb-2">
<LoginFailureMessage
@@ -310,9 +302,88 @@ const LoginPage = ({
);
};
const mapStateToProps = state => {
const loginPageState = state.login;
return {
backedUpFormData: loginPageState.loginFormData,
loginErrorCode: loginPageState.loginErrorCode,
loginErrorContext: loginPageState.loginErrorContext,
loginResult: loginPageState.loginResult,
shouldBackupState: loginPageState.shouldBackupState,
showResetPasswordSuccessBanner: loginPageState.showResetPasswordSuccessBanner,
submitState: loginPageState.submitState,
thirdPartyAuthContext: thirdPartyAuthContextSelector(state),
thirdPartyAuthApiStatus: state.commonComponents.thirdPartyAuthApiStatus,
};
};
LoginPage.propTypes = {
backedUpFormData: PropTypes.shape({
formFields: PropTypes.shape({}),
errors: PropTypes.shape({}),
}),
loginErrorCode: PropTypes.string,
loginErrorContext: PropTypes.shape({
email: PropTypes.string,
redirectUrl: PropTypes.string,
context: PropTypes.shape({}),
}),
loginResult: PropTypes.shape({
redirectUrl: PropTypes.string,
success: PropTypes.bool,
}),
shouldBackupState: PropTypes.bool,
showResetPasswordSuccessBanner: PropTypes.bool,
submitState: PropTypes.string,
thirdPartyAuthApiStatus: PropTypes.string,
institutionLogin: PropTypes.bool.isRequired,
thirdPartyAuthContext: PropTypes.shape({
currentProvider: PropTypes.string,
errorMessage: PropTypes.string,
platformName: PropTypes.string,
providers: PropTypes.arrayOf(PropTypes.shape({})),
secondaryProviders: PropTypes.arrayOf(PropTypes.shape({})),
finishAuthUrl: PropTypes.string,
}),
// Actions
backupFormState: PropTypes.func.isRequired,
dismissPasswordResetBanner: PropTypes.func.isRequired,
loginRequest: PropTypes.func.isRequired,
getTPADataFromBackend: PropTypes.func.isRequired,
handleInstitutionLogin: PropTypes.func.isRequired,
};
export default LoginPage;
LoginPage.defaultProps = {
backedUpFormData: {
formFields: {
emailOrUsername: '', password: '',
},
errors: {
emailOrUsername: '', password: '',
},
},
loginErrorCode: null,
loginErrorContext: {},
loginResult: {},
shouldBackupState: false,
showResetPasswordSuccessBanner: false,
submitState: DEFAULT_STATE,
thirdPartyAuthApiStatus: PENDING_STATE,
thirdPartyAuthContext: {
currentProvider: null,
errorMessage: null,
finishAuthUrl: null,
providers: [],
secondaryProviders: [],
},
};
export default connect(
mapStateToProps,
{
backupFormState: backupLoginFormBegin,
dismissPasswordResetBanner,
loginRequest,
getTPADataFromBackend: getThirdPartyAuthContext,
},
)(injectIntl(LoginPage));

View File

@@ -95,11 +95,6 @@ const messages = defineMessages({
defaultMessage: 'Your account could not be activated',
description: 'Account Activation error message title',
},
'account.activation.support.link': {
id: 'account.activation.support.link',
defaultMessage: 'contact support',
description: 'Link text used in account activation error message to go to learner help center',
},
// Email Confirmation Strings
'account.confirmation.success.message.title': {
id: 'account.confirmation.success.message.title',

View File

@@ -1,5 +1,7 @@
import React from 'react';
import { mergeConfig } from '@edx/frontend-platform';
import { IntlProvider } from '@edx/frontend-platform/i18n';
import { injectIntl, IntlProvider } from '@edx/frontend-platform/i18n';
import {
render, screen,
} from '@testing-library/react';
@@ -7,6 +9,8 @@ import {
import AccountActivationMessage from '../AccountActivationMessage';
import { ACCOUNT_ACTIVATION_MESSAGE } from '../data/constants';
const IntlAccountActivationMessage = injectIntl(AccountActivationMessage);
describe('AccountActivationMessage', () => {
beforeEach(() => {
mergeConfig({
@@ -17,7 +21,7 @@ describe('AccountActivationMessage', () => {
it('should match account already activated message', () => {
render(
<IntlProvider locale="en">
<AccountActivationMessage messageType={ACCOUNT_ACTIVATION_MESSAGE.INFO} />
<IntlAccountActivationMessage messageType={ACCOUNT_ACTIVATION_MESSAGE.INFO} />
</IntlProvider>,
);
@@ -32,7 +36,7 @@ describe('AccountActivationMessage', () => {
it('should match account activated success message', () => {
render(
<IntlProvider locale="en">
<AccountActivationMessage messageType={ACCOUNT_ACTIVATION_MESSAGE.SUCCESS} />
<IntlAccountActivationMessage messageType={ACCOUNT_ACTIVATION_MESSAGE.SUCCESS} />
</IntlProvider>,
);
@@ -49,12 +53,12 @@ describe('AccountActivationMessage', () => {
it('should match account activation error message', () => {
render(
<IntlProvider locale="en">
<AccountActivationMessage messageType={ACCOUNT_ACTIVATION_MESSAGE.ERROR} />
<IntlAccountActivationMessage messageType={ACCOUNT_ACTIVATION_MESSAGE.ERROR} />
</IntlProvider>,
);
const expectedMessage = 'Your account could not be activated'
+ 'Something went wrong, please contact support to resolve this issue.';
+ 'Something went wrong, please contact to resolve this issue.';
expect(screen.getByText(
'',
@@ -65,7 +69,7 @@ describe('AccountActivationMessage', () => {
it('should not display anything for invalid message type', () => {
const { container } = render(
<IntlProvider locale="en">
<AccountActivationMessage messageType="invalid-message" />
<IntlAccountActivationMessage messageType="invalid-message" />
</IntlProvider>,
);
@@ -84,7 +88,7 @@ describe('EmailConfirmationMessage', () => {
it('should match email already confirmed message', () => {
render(
<IntlProvider locale="en">
<AccountActivationMessage messageType={ACCOUNT_ACTIVATION_MESSAGE.INFO} />
<IntlAccountActivationMessage messageType={ACCOUNT_ACTIVATION_MESSAGE.INFO} />
</IntlProvider>,
);
@@ -99,7 +103,7 @@ describe('EmailConfirmationMessage', () => {
it('should match email confirmation success message', () => {
render(
<IntlProvider locale="en">
<AccountActivationMessage messageType={ACCOUNT_ACTIVATION_MESSAGE.SUCCESS} />
<IntlAccountActivationMessage messageType={ACCOUNT_ACTIVATION_MESSAGE.SUCCESS} />
</IntlProvider>,
);
const expectedMessage = 'Success! You have confirmed your email.Sign in to continue.';
@@ -113,11 +117,11 @@ describe('EmailConfirmationMessage', () => {
it('should match email confirmation error message', () => {
render(
<IntlProvider locale="en">
<AccountActivationMessage messageType={ACCOUNT_ACTIVATION_MESSAGE.ERROR} />
<IntlAccountActivationMessage messageType={ACCOUNT_ACTIVATION_MESSAGE.ERROR} />
</IntlProvider>,
);
const expectedMessage = 'Your email could not be confirmed'
+ 'Something went wrong, please contact support to resolve this issue.';
+ 'Something went wrong, please contact to resolve this issue.';
expect(screen.getByText(
'',
{ selector: '#account-activation-message' },

View File

@@ -1,15 +1,30 @@
import React from 'react';
import { Provider } from 'react-redux';
import { getConfig } from '@edx/frontend-platform';
import { IntlProvider } from '@edx/frontend-platform/i18n';
import { injectIntl, IntlProvider } from '@edx/frontend-platform/i18n';
import {
fireEvent, render, screen,
fireEvent, render, screen, waitFor,
} from '@testing-library/react';
import { act } from 'react-dom/test-utils';
import { MemoryRouter } from 'react-router-dom';
import configureStore from 'redux-mock-store';
import mockTagular from '../../cohesion/utils';
import { RESET_PAGE } from '../../data/constants';
import ChangePasswordPrompt from '../ChangePasswordPrompt';
const IntlChangePasswordPrompt = injectIntl(ChangePasswordPrompt);
const mockedNavigator = jest.fn();
const mockStore = configureStore();
mockTagular();
const eventData = {
pageType: 'test-page',
elementType: 'test-element-type',
webElementText: 'test-element-text',
webElementName: 'test-element-name',
};
jest.mock('react-router-dom', () => ({
...(jest.requireActual('react-router-dom')),
@@ -18,8 +33,14 @@ jest.mock('react-router-dom', () => ({
describe('ChangePasswordPromptTests', () => {
let props = {};
let store = {};
const initialState = {
cohesion: { eventData: {} },
};
beforeAll(() => {
store = mockStore(initialState);
Object.defineProperty(window, 'matchMedia', {
writable: true,
value: jest.fn().mockImplementation(query => ({
@@ -28,38 +49,56 @@ describe('ChangePasswordPromptTests', () => {
});
});
it('[nudge modal] should redirect to next url when user clicks close button', () => {
it('[nudge modal] should redirect to next url when user clicks close button', async () => {
const dashboardUrl = getConfig().BASE_URL.concat('/dashboard');
props = {
variant: 'nudge',
redirectUrl: dashboardUrl,
};
store = mockStore({
...initialState,
cohesion: {
eventData,
},
});
delete window.location;
window.location = { href: getConfig().BASE_URL };
render(
<IntlProvider locale="en">
<MemoryRouter>
<ChangePasswordPrompt {...props} />
</MemoryRouter>
<Provider store={store}>
<MemoryRouter>
<IntlChangePasswordPrompt {...props} />
</MemoryRouter>
</Provider>
</IntlProvider>,
);
fireEvent.click(screen.getByText('Close'));
expect(window.location.href).toBe(dashboardUrl);
await waitFor(() => {
expect(window.location.href).toBe(dashboardUrl);
}, { timeout: 1100 });
});
it('[block modal] should redirect to reset password page when user clicks outside modal', async () => {
props = {
variant: 'block',
};
store = mockStore({
...initialState,
cohesion: {
eventData,
},
});
render(
<IntlProvider locale="en">
<MemoryRouter>
<ChangePasswordPrompt {...props} />
</MemoryRouter>
<Provider store={store}>
<MemoryRouter>
<IntlChangePasswordPrompt {...props} />
</MemoryRouter>
</Provider>
</IntlProvider>,
);

View File

@@ -1,8 +1,12 @@
import { IntlProvider } from '@edx/frontend-platform/i18n';
import React from 'react';
import { Provider } from 'react-redux';
import { injectIntl, IntlProvider } from '@edx/frontend-platform/i18n';
import {
render, screen,
} from '@testing-library/react';
import { MemoryRouter } from 'react-router-dom';
import configureStore from 'redux-mock-store';
import {
ACCOUNT_LOCKED_OUT,
@@ -23,11 +27,27 @@ import LoginFailureMessage from '../LoginFailure';
jest.mock('@edx/frontend-platform/auth', () => ({
getAuthService: jest.fn(),
}));
const mockStore = configureStore();
const IntlLoginFailureMessage = injectIntl(LoginFailureMessage);
const eventData = {
pageType: 'test-page',
elementType: 'test-element-type',
webElementText: 'test-element-text',
webElementName: 'test-element-name',
};
describe('LoginFailureMessage', () => {
let props = {};
let store = {};
const initialState = {
cohesion: { eventData: {} },
};
beforeAll(() => {
store = mockStore(initialState);
Object.defineProperty(window, 'matchMedia', {
writable: true,
value: jest.fn().mockImplementation(query => ({
@@ -44,7 +64,7 @@ describe('LoginFailureMessage', () => {
render(
<IntlProvider locale="en">
<LoginFailureMessage {...props} />
<IntlLoginFailureMessage {...props} />
</IntlProvider>,
);
@@ -72,7 +92,7 @@ describe('LoginFailureMessage', () => {
render(
<IntlProvider locale="en">
<LoginFailureMessage {...props} />
<IntlLoginFailureMessage {...props} />
</IntlProvider>,
);
@@ -102,7 +122,7 @@ describe('LoginFailureMessage', () => {
render(
<IntlProvider locale="en">
<LoginFailureMessage {...props} />
<IntlLoginFailureMessage {...props} />
</IntlProvider>,
);
@@ -128,7 +148,7 @@ describe('LoginFailureMessage', () => {
render(
<IntlProvider locale="en">
<LoginFailureMessage {...props} />
<IntlLoginFailureMessage {...props} />
</IntlProvider>,
);
@@ -148,7 +168,7 @@ describe('LoginFailureMessage', () => {
render(
<IntlProvider locale="en">
<LoginFailureMessage {...props} />
<IntlLoginFailureMessage {...props} />
</IntlProvider>,
);
@@ -172,7 +192,7 @@ describe('LoginFailureMessage', () => {
render(
<IntlProvider locale="en">
<LoginFailureMessage {...props} />
<IntlLoginFailureMessage {...props} />
</IntlProvider>,
);
@@ -192,7 +212,7 @@ describe('LoginFailureMessage', () => {
render(
<IntlProvider locale="en">
<LoginFailureMessage {...props} />
<IntlLoginFailureMessage {...props} />
</IntlProvider>,
);
@@ -212,7 +232,7 @@ describe('LoginFailureMessage', () => {
render(
<IntlProvider locale="en">
<LoginFailureMessage {...props} />
<IntlLoginFailureMessage {...props} />
</IntlProvider>,
);
@@ -232,7 +252,7 @@ describe('LoginFailureMessage', () => {
render(
<IntlProvider locale="en">
<LoginFailureMessage {...props} />
<IntlLoginFailureMessage {...props} />
</IntlProvider>,
);
@@ -251,7 +271,7 @@ describe('LoginFailureMessage', () => {
render(
<IntlProvider locale="en">
<LoginFailureMessage {...props} />
<IntlLoginFailureMessage {...props} />
</IntlProvider>,
);
@@ -271,7 +291,7 @@ describe('LoginFailureMessage', () => {
render(
<IntlProvider locale="en">
<LoginFailureMessage {...props} />
<IntlLoginFailureMessage {...props} />
</IntlProvider>,
);
@@ -294,11 +314,19 @@ describe('LoginFailureMessage', () => {
errorCount: 0,
};
store = mockStore({
...initialState,
cohesion: {
eventData,
},
});
render(
<IntlProvider locale="en">
<MemoryRouter>
<LoginFailureMessage {...props} />
</MemoryRouter>
<Provider store={store}>
<MemoryRouter>
<IntlLoginFailureMessage {...props} />
</MemoryRouter>
</Provider>
</IntlProvider>,
);
@@ -319,12 +347,20 @@ describe('LoginFailureMessage', () => {
errorCode: REQUIRE_PASSWORD_CHANGE,
errorCount: 0,
};
store = mockStore({
...initialState,
cohesion: {
eventData,
},
});
render(
<IntlProvider locale="en">
<MemoryRouter>
<LoginFailureMessage {...props} />
</MemoryRouter>
<Provider store={store}>
<MemoryRouter>
<IntlLoginFailureMessage {...props} />
</MemoryRouter>
</Provider>
</IntlProvider>,
);
@@ -355,7 +391,7 @@ describe('LoginFailureMessage', () => {
render(
<IntlProvider locale="en">
<LoginFailureMessage {...props} />
<IntlLoginFailureMessage {...props} />
</IntlProvider>,
);

View File

@@ -1,8 +1,9 @@
import React from 'react';
import { Provider } from 'react-redux';
import { getConfig, mergeConfig } from '@edx/frontend-platform';
import { sendPageEvent, sendTrackEvent } from '@edx/frontend-platform/analytics';
import { IntlProvider } from '@edx/frontend-platform/i18n';
import { injectIntl, IntlProvider } from '@edx/frontend-platform/i18n';
import {
fireEvent, render, screen, waitFor,
} from '@testing-library/react';
@@ -10,7 +11,10 @@ import { act } from 'react-dom/test-utils';
import { MemoryRouter } from 'react-router-dom';
import configureStore from 'redux-mock-store';
import { COMPLETE_STATE, LOGIN_PAGE, PENDING_STATE } from '../../data/constants';
import mockTagular from '../../cohesion/utils';
import {
APP_NAME, COMPLETE_STATE, LOGIN_PAGE, PENDING_STATE,
} from '../../data/constants';
import { backupLoginFormBegin, dismissPasswordResetBanner, loginRequest } from '../data/actions';
import { INTERNAL_SERVER_ERROR } from '../data/constants';
import LoginPage from '../LoginPage';
@@ -22,7 +26,9 @@ jest.mock('@edx/frontend-platform/analytics', () => ({
jest.mock('@edx/frontend-platform/auth', () => ({
getAuthService: jest.fn(),
}));
mockTagular();
const IntlLoginPage = injectIntl(LoginPage);
const mockStore = configureStore();
describe('LoginPage', () => {
@@ -41,14 +47,6 @@ describe('LoginPage', () => {
const initialState = {
login: {
loginResult: { success: false, redirectUrl: '' },
loginFormData: {
formFields: {
emailOrUsername: '', password: '',
},
errors: {
emailOrUsername: '', password: '',
},
},
},
commonComponents: {
thirdPartyAuthApiStatus: null,
@@ -62,6 +60,7 @@ describe('LoginPage', () => {
register: {
validationApiRateLimited: false,
},
cohesion: { eventData: {} },
};
const secondaryProviders = {
@@ -94,7 +93,7 @@ describe('LoginPage', () => {
it('should submit form for valid input', () => {
store.dispatch = jest.fn(store.dispatch);
render(reduxWrapper(<LoginPage {...props} />));
render(reduxWrapper(<IntlLoginPage {...props} />));
fireEvent.change(screen.getByText(
'',
@@ -115,7 +114,7 @@ describe('LoginPage', () => {
it('should not dispatch loginRequest on empty form submission', () => {
store.dispatch = jest.fn(store.dispatch);
render(reduxWrapper(<LoginPage {...props} />));
render(reduxWrapper(<IntlLoginPage {...props} />));
fireEvent.click(screen.getByText(
'',
@@ -134,7 +133,7 @@ describe('LoginPage', () => {
});
store.dispatch = jest.fn(store.dispatch);
render(reduxWrapper(<LoginPage {...props} />));
render(reduxWrapper(<IntlLoginPage {...props} />));
fireEvent.click(screen.getByText(
'',
{ selector: '.btn-brand' },
@@ -148,7 +147,7 @@ describe('LoginPage', () => {
it('should match state for invalid email (less than 2 characters), on form submission', () => {
store.dispatch = jest.fn(store.dispatch);
render(reduxWrapper(<LoginPage {...props} />));
render(reduxWrapper(<IntlLoginPage {...props} />));
fireEvent.change(screen.getByText(
'',
@@ -168,7 +167,7 @@ describe('LoginPage', () => {
});
it('should show error messages for required fields on empty form submission', () => {
const { container } = render(reduxWrapper(<LoginPage {...props} />));
const { container } = render(reduxWrapper(<IntlLoginPage {...props} />));
fireEvent.click(screen.getByText(
'',
{ selector: '.btn-brand' },
@@ -182,7 +181,7 @@ describe('LoginPage', () => {
});
it('should run frontend validations for emailOrUsername field on form submission', () => {
const { container } = render(reduxWrapper(<LoginPage {...props} />));
const { container } = render(reduxWrapper(<IntlLoginPage {...props} />));
fireEvent.change(screen.getByText(
'',
@@ -201,7 +200,7 @@ describe('LoginPage', () => {
it('should reset field related error messages on onFocus event', async () => {
store.dispatch = jest.fn(store.dispatch);
render(reduxWrapper(<LoginPage {...props} />));
render(reduxWrapper(<IntlLoginPage {...props} />));
await act(async () => {
// clicking submit button with empty fields to make the errors appear
@@ -230,7 +229,7 @@ describe('LoginPage', () => {
// ******** test form buttons and links ********
it('should match default button state', () => {
render(reduxWrapper(<LoginPage {...props} />));
render(reduxWrapper(<IntlLoginPage {...props} />));
expect(screen.getByText('Sign in')).toBeDefined();
});
@@ -243,7 +242,7 @@ describe('LoginPage', () => {
},
});
render(reduxWrapper(<LoginPage {...props} />));
render(reduxWrapper(<IntlLoginPage {...props} />));
expect(screen.getByText(
'pending',
@@ -251,7 +250,7 @@ describe('LoginPage', () => {
});
it('should show forgot password link', () => {
render(reduxWrapper(<LoginPage {...props} />));
render(reduxWrapper(<IntlLoginPage {...props} />));
expect(screen.getByText(
'Forgot password',
@@ -271,7 +270,7 @@ describe('LoginPage', () => {
},
});
render(reduxWrapper(<LoginPage {...props} />));
render(reduxWrapper(<IntlLoginPage {...props} />));
expect(screen.getByText(
'',
{ selector: `#${ssoProvider.id}` },
@@ -293,7 +292,7 @@ describe('LoginPage', () => {
},
});
const { queryByText } = render(reduxWrapper(<LoginPage {...props} />));
const { queryByText } = render(reduxWrapper(<IntlLoginPage {...props} />));
expect(queryByText('Company or school credentials')).toBeNull();
expect(queryByText('Or sign in with:')).toBeNull();
expect(queryByText('Institution/campus credentials')).toBeNull();
@@ -313,7 +312,7 @@ describe('LoginPage', () => {
},
});
const { queryByText } = render(reduxWrapper(<LoginPage {...props} />));
const { queryByText } = render(reduxWrapper(<IntlLoginPage {...props} />));
expect(queryByText('Company or school credentials')).toBeNull();
expect(queryByText('Or sign in with:')).toBeNull();
});
@@ -333,7 +332,7 @@ describe('LoginPage', () => {
},
});
const { queryByText } = render(reduxWrapper(<LoginPage {...props} />));
const { queryByText } = render(reduxWrapper(<IntlLoginPage {...props} />));
expect(queryByText('Or sign in with:')).toBeDefined();
expect(queryByText('Company or school credentials')).toBeDefined();
expect(queryByText('Institution/campus credentials')).toBeDefined();
@@ -358,7 +357,7 @@ describe('LoginPage', () => {
},
});
const { queryByText } = render(reduxWrapper(<LoginPage {...props} />));
const { queryByText } = render(reduxWrapper(<IntlLoginPage {...props} />));
expect(queryByText('Or sign in with:')).toBeDefined();
expect(queryByText('Company or school credentials')).toBeNull();
expect(queryByText('Institution/campus credentials')).toBeDefined();
@@ -386,7 +385,7 @@ describe('LoginPage', () => {
},
});
const { queryByText } = render(reduxWrapper(<LoginPage {...props} />));
const { queryByText } = render(reduxWrapper(<IntlLoginPage {...props} />));
expect(queryByText('Or sign in with:')).toBeDefined();
expect(queryByText('Institution/campus credentials')).toBeDefined();
@@ -406,7 +405,7 @@ describe('LoginPage', () => {
},
});
const { queryByText } = render(reduxWrapper(<LoginPage {...props} />));
const { queryByText } = render(reduxWrapper(<IntlLoginPage {...props} />));
expect(queryByText('Or sign in with:')).toBeNull();
expect(queryByText('Institution/campus credentials')).toBeNull();
expect(queryByText('Company or school credentials')).toBeNull();
@@ -424,7 +423,7 @@ describe('LoginPage', () => {
},
});
const { queryByText } = render(reduxWrapper(<LoginPage {...props} />));
const { queryByText } = render(reduxWrapper(<IntlLoginPage {...props} />));
expect(queryByText('Or sign in with:')).toBeDefined();
expect(queryByText('Company or school credentials')).toBeNull();
expect(queryByText('Institution/campus credentials')).toBeDefined();
@@ -447,7 +446,7 @@ describe('LoginPage', () => {
},
});
render(reduxWrapper(<LoginPage {...props} />));
render(reduxWrapper(<IntlLoginPage {...props} />));
expect(screen.getByText(
'',
{ selector: '#login-failure-alert' },
@@ -471,7 +470,7 @@ describe('LoginPage', () => {
+ 'linked '}${ getConfig().SITE_NAME } account. To link your accounts, sign in now using your ${
getConfig().SITE_NAME } password.`;
render(reduxWrapper(<LoginPage {...props} />));
render(reduxWrapper(<IntlLoginPage {...props} />));
expect(screen.getByText(
'',
{ selector: '#tpa-alert' },
@@ -490,7 +489,7 @@ describe('LoginPage', () => {
},
},
});
render(reduxWrapper(<LoginPage {...props} />));
render(reduxWrapper(<IntlLoginPage {...props} />));
expect(screen.getByText(
'',
{ selector: '#login-failure-alert' },
@@ -507,7 +506,7 @@ describe('LoginPage', () => {
},
});
render(reduxWrapper(<LoginPage {...props} />));
render(reduxWrapper(<IntlLoginPage {...props} />));
expect(screen.getByText(
'',
{ selector: '#login-failure-alert' },
@@ -516,7 +515,7 @@ describe('LoginPage', () => {
// ******** test redirection ********
it('should redirect to url returned by login endpoint after successful authentication', () => {
it('should redirect to url returned by login endpoint after successful authentication', async () => {
const dashboardURL = 'https://test.com/testing-dashboard/';
store = mockStore({
...initialState,
@@ -531,11 +530,13 @@ describe('LoginPage', () => {
delete window.location;
window.location = { href: getConfig().BASE_URL };
render(reduxWrapper(<LoginPage {...props} />));
expect(window.location.href).toBe(dashboardURL);
render(reduxWrapper(<IntlLoginPage {...props} />));
await waitFor(() => {
expect(window.location.href).toBe(dashboardURL);
}, { timeout: 1100 });
});
it('should redirect to finishAuthUrl upon successful login via SSO', () => {
it('should redirect to finishAuthUrl upon successful login via SSO', async () => {
const authCompleteUrl = '/auth/complete/google-oauth2/';
store = mockStore({
...initialState,
@@ -558,11 +559,13 @@ describe('LoginPage', () => {
delete window.location;
window.location = { href: getConfig().BASE_URL };
render(reduxWrapper(<LoginPage {...props} />));
expect(window.location.href).toBe(getConfig().LMS_BASE_URL + authCompleteUrl);
render(reduxWrapper(<IntlLoginPage {...props} />));
await waitFor(() => {
expect(window.location.href).toBe(getConfig().LMS_BASE_URL + authCompleteUrl);
}, { timeout: 1100 });
});
it('should redirect to social auth provider url on SSO button click', () => {
it('should redirect to social auth provider url on SSO button click', async () => {
store = mockStore({
...initialState,
commonComponents: {
@@ -577,16 +580,18 @@ describe('LoginPage', () => {
delete window.location;
window.location = { href: getConfig().BASE_URL };
render(reduxWrapper(<LoginPage {...props} />));
render(reduxWrapper(<IntlLoginPage {...props} />));
fireEvent.click(screen.getByText(
'',
{ selector: '#oa2-apple-id' },
));
expect(window.location.href).toBe(getConfig().LMS_BASE_URL + ssoProvider.loginUrl);
await waitFor(() => {
expect(window.location.href).toBe(getConfig().LMS_BASE_URL + ssoProvider.loginUrl);
}, { timeout: 1100 });
});
it('should redirect to finishAuthUrl upon successful authentication via SSO', () => {
it('should redirect to finishAuthUrl upon successful authentication via SSO', async () => {
const finishAuthUrl = '/auth/complete/google-oauth2/';
store = mockStore({
...initialState,
@@ -606,8 +611,10 @@ describe('LoginPage', () => {
delete window.location;
window.location = { href: getConfig().BASE_URL };
render(reduxWrapper(<LoginPage {...props} />));
expect(window.location.href).toBe(getConfig().LMS_BASE_URL + finishAuthUrl);
render(reduxWrapper(<IntlLoginPage {...props} />));
await waitFor(() => {
expect(window.location.href).toBe(getConfig().LMS_BASE_URL + finishAuthUrl);
}, { timeout: 1100 });
});
// ******** test hinted third party auth ********
@@ -628,7 +635,7 @@ describe('LoginPage', () => {
delete window.location;
window.location = { href: getConfig().BASE_URL.concat(LOGIN_PAGE), search: `?next=/dashboard&tpa_hint=${ssoProvider.id}` };
render(reduxWrapper(<LoginPage {...props} />));
render(reduxWrapper(<IntlLoginPage {...props} />));
expect(screen.getByText(
'',
{ selector: `#${ssoProvider.id}` },
@@ -655,7 +662,7 @@ describe('LoginPage', () => {
delete window.location;
window.location = { href: getConfig().BASE_URL.concat(LOGIN_PAGE), search: `?next=/dashboard&tpa_hint=${ssoProvider.id}` };
const { container } = render(reduxWrapper(<LoginPage {...props} />));
const { container } = render(reduxWrapper(<IntlLoginPage {...props} />));
expect(container.querySelector('.react-loading-skeleton')).toBeTruthy();
});
@@ -677,7 +684,7 @@ describe('LoginPage', () => {
window.location = { href: getConfig().BASE_URL.concat(LOGIN_PAGE), search: `?next=/dashboard&tpa_hint=${secondaryProviders.id}` };
secondaryProviders.iconImage = null;
render(reduxWrapper(<LoginPage {...props} />));
render(reduxWrapper(<IntlLoginPage {...props} />));
expect(window.location.href).toEqual(getConfig().LMS_BASE_URL + secondaryProviders.loginUrl);
});
@@ -697,7 +704,7 @@ describe('LoginPage', () => {
delete window.location;
window.location = { href: getConfig().BASE_URL.concat(LOGIN_PAGE), search: '?next=/dashboard&tpa_hint=invalid' };
const { container } = render(reduxWrapper(<LoginPage {...props} />));
const { container } = render(reduxWrapper(<IntlLoginPage {...props} />));
expect(container.querySelector(`#${ssoProvider.id}`).querySelector('#provider-name').textContent).toEqual(`${ssoProvider.name}`);
mergeConfig({
@@ -721,7 +728,7 @@ describe('LoginPage', () => {
delete window.location;
window.location = { href: getConfig().BASE_URL.concat(LOGIN_PAGE), search: `?tpa_hint=${ssoProvider.id}` };
render(reduxWrapper(<LoginPage {...props} />));
render(reduxWrapper(<IntlLoginPage {...props} />));
expect(screen.getByText(
'Show me other ways to sign in or register',
).textContent).toBeDefined();
@@ -747,7 +754,7 @@ describe('LoginPage', () => {
delete window.location;
window.location = { href: getConfig().BASE_URL.concat(LOGIN_PAGE), search: `?tpa_hint=${ssoProvider.id}` };
render(reduxWrapper(<LoginPage {...props} />));
render(reduxWrapper(<IntlLoginPage {...props} />));
expect(screen.getByText(
'Show me other ways to sign in',
).textContent).toBeDefined();
@@ -756,8 +763,8 @@ describe('LoginPage', () => {
// ******** miscellaneous tests ********
it('should send page event when login page is rendered', () => {
render(reduxWrapper(<LoginPage {...props} />));
expect(sendPageEvent).toHaveBeenCalledWith('login_and_registration', 'login');
render(reduxWrapper(<IntlLoginPage {...props} />));
expect(sendPageEvent).toHaveBeenCalledWith('login_and_registration', 'login', { app_name: APP_NAME });
});
it('tests that form is in invalid state when it is submitted', () => {
@@ -770,7 +777,7 @@ describe('LoginPage', () => {
});
store.dispatch = jest.fn(store.dispatch);
render(reduxWrapper(<LoginPage {...props} />));
render(reduxWrapper(<IntlLoginPage {...props} />));
expect(store.dispatch).toHaveBeenCalledWith(backupLoginFormBegin(
{
formFields: {
@@ -784,13 +791,13 @@ describe('LoginPage', () => {
});
it('should send track event when forgot password link is clicked', () => {
render(reduxWrapper(<LoginPage {...props} />));
render(reduxWrapper(<IntlLoginPage {...props} />));
fireEvent.click(screen.getByText(
'Forgot password',
{ selector: '#forgot-password' },
));
expect(sendTrackEvent).toHaveBeenCalledWith('edx.bi.password-reset_form.toggled', { category: 'user-engagement' });
expect(sendTrackEvent).toHaveBeenCalledWith('edx.bi.password-reset_form.toggled', { category: 'user-engagement', app_name: APP_NAME });
});
it('should backup the login form state when shouldBackupState is true', () => {
@@ -803,7 +810,7 @@ describe('LoginPage', () => {
});
store.dispatch = jest.fn(store.dispatch);
render(reduxWrapper(<LoginPage {...props} />));
render(reduxWrapper(<IntlLoginPage {...props} />));
expect(store.dispatch).toHaveBeenCalledWith(backupLoginFormBegin(
{
formFields: {
@@ -832,7 +839,7 @@ describe('LoginPage', () => {
},
});
const { container } = render(reduxWrapper(<LoginPage {...props} />));
const { container } = render(reduxWrapper(<IntlLoginPage {...props} />));
expect(container.querySelector('input#emailOrUsername').value).toEqual('john_doe');
expect(container.querySelector('input#password').value).toEqual('test-password');
});

View File

@@ -1,5 +1,5 @@
import React, { useEffect, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { connect } from 'react-redux';
import { getConfig } from '@edx/frontend-platform';
import { sendPageEvent, sendTrackEvent } from '@edx/frontend-platform/analytics';
@@ -20,24 +20,20 @@ import {
tpaProvidersSelector,
} from '../common-components/data/selectors';
import messages from '../common-components/messages';
import { LOGIN_PAGE, REGISTER_PAGE } from '../data/constants';
import { APP_NAME, LOGIN_PAGE, REGISTER_PAGE } from '../data/constants';
import {
getTpaHint, getTpaProvider, updatePathWithQueryParams,
} from '../data/utils';
import { LoginPage } from '../login';
import { backupLoginForm } from '../login/data/actions';
import LoginComponentSlot from '../plugin-slots/LoginComponentSlot';
import { RegistrationPage } from '../register';
import { backupRegistrationForm } from '../register/data/actions';
const Logistration = ({
selectedPage,
}) => {
const Logistration = (props) => {
const { selectedPage, tpaProviders } = props;
const tpaHint = getTpaHint();
const tpaProviders = useSelector(tpaProvidersSelector);
const dispatch = useDispatch();
const {
providers,
secondaryProviders,
providers, secondaryProviders,
} = tpaProviders;
const { formatMessage } = useIntl();
const [institutionLogin, setInstitutionLogin] = useState(false);
@@ -49,8 +45,7 @@ const Logistration = ({
useEffect(() => {
const authService = getAuthService();
if (authService) {
authService.getCsrfTokenService()
.getCsrfToken(getConfig().LMS_BASE_URL);
authService.getCsrfTokenService().getCsrfToken(getConfig().LMS_BASE_URL);
}
});
@@ -61,11 +56,11 @@ const Logistration = ({
}, [navigate, disablePublicAccountCreation]);
const handleInstitutionLogin = (e) => {
sendTrackEvent('edx.bi.institution_login_form.toggled', { category: 'user-engagement' });
sendTrackEvent('edx.bi.institution_login_form.toggled', { category: 'user-engagement', app_name: APP_NAME });
if (typeof e === 'string') {
sendPageEvent('login_and_registration', e === '/login' ? 'login' : 'register');
sendPageEvent('login_and_registration', e === '/login' ? 'login' : 'register', { app_name: APP_NAME });
} else {
sendPageEvent('login_and_registration', e.target.dataset.eventName);
sendPageEvent('login_and_registration', e.target.dataset.eventName, { app_name: APP_NAME });
}
setInstitutionLogin(!institutionLogin);
@@ -75,12 +70,13 @@ const Logistration = ({
if (tabKey === currentTab) {
return;
}
sendTrackEvent(`edx.bi.${tabKey.replace('/', '')}_form.toggled`, { category: 'user-engagement' });
dispatch(clearThirdPartyAuthContextErrorMessage());
sendTrackEvent(`edx.bi.${tabKey.replace('/', '')}_form.toggled`, { category: 'user-engagement', app_name: APP_NAME });
props.clearThirdPartyAuthContextErrorMessage();
if (tabKey === LOGIN_PAGE) {
dispatch(backupRegistrationForm());
props.backupRegistrationForm();
} else if (tabKey === REGISTER_PAGE) {
dispatch(backupLoginForm());
props.backupLoginForm();
}
setKey(tabKey);
};
@@ -116,10 +112,7 @@ const Logistration = ({
{!institutionLogin && (
<h3 className="mb-4.5">{formatMessage(messages['logistration.sign.in'])}</h3>
)}
<LoginComponentSlot
institutionLogin={institutionLogin}
handleInstitutionLogin={handleInstitutionLogin}
/>
<LoginPage institutionLogin={institutionLogin} handleInstitutionLogin={handleInstitutionLogin} />
</div>
</>
)
@@ -132,16 +125,12 @@ const Logistration = ({
</Tabs>
)
: (!isValidTpaHint() && !hideRegistrationLink && (
<Tabs
defaultActiveKey={selectedPage}
id="controlled-tab"
onSelect={(tabKey) => handleOnSelect(tabKey, selectedPage)}
>
<Tabs defaultActiveKey={selectedPage} id="controlled-tab" onSelect={(tabKey) => handleOnSelect(tabKey, selectedPage)}>
<Tab title={formatMessage(messages['logistration.register'])} eventKey={REGISTER_PAGE} />
<Tab title={formatMessage(messages['logistration.sign.in'])} eventKey={LOGIN_PAGE} />
</Tabs>
))}
{key && (
{ key && (
<Navigate to={updatePathWithQueryParams(key)} replace />
)}
<div id="main-content" className="main-content">
@@ -151,12 +140,7 @@ const Logistration = ({
</h3>
)}
{selectedPage === LOGIN_PAGE
? (
<LoginComponentSlot
institutionLogin={institutionLogin}
handleInstitutionLogin={handleInstitutionLogin}
/>
)
? <LoginPage institutionLogin={institutionLogin} handleInstitutionLogin={handleInstitutionLogin} />
: (
<RegistrationPage
institutionLogin={institutionLogin}
@@ -173,10 +157,35 @@ const Logistration = ({
Logistration.propTypes = {
selectedPage: PropTypes.string,
backupLoginForm: PropTypes.func.isRequired,
backupRegistrationForm: PropTypes.func.isRequired,
clearThirdPartyAuthContextErrorMessage: PropTypes.func.isRequired,
tpaProviders: PropTypes.shape({
providers: PropTypes.arrayOf(PropTypes.shape({})),
secondaryProviders: PropTypes.arrayOf(PropTypes.shape({})),
}),
};
Logistration.defaultProps = {
tpaProviders: {
providers: [],
secondaryProviders: [],
},
};
Logistration.defaultProps = {
selectedPage: REGISTER_PAGE,
};
export default Logistration;
const mapStateToProps = state => ({
tpaProviders: tpaProvidersSelector(state),
});
export default connect(
mapStateToProps,
{
backupLoginForm,
backupRegistrationForm,
clearThirdPartyAuthContextErrorMessage,
},
)(Logistration);

View File

@@ -1,8 +1,9 @@
import React from 'react';
import { Provider } from 'react-redux';
import { getConfig, mergeConfig } from '@edx/frontend-platform';
import { sendPageEvent, sendTrackEvent } from '@edx/frontend-platform/analytics';
import { configure, IntlProvider } from '@edx/frontend-platform/i18n';
import { configure, injectIntl, IntlProvider } from '@edx/frontend-platform/i18n';
import { fireEvent, render, screen } from '@testing-library/react';
import { MemoryRouter } from 'react-router-dom';
import configureStore from 'redux-mock-store';
@@ -10,18 +11,24 @@ import configureStore from 'redux-mock-store';
import Logistration from './Logistration';
import { clearThirdPartyAuthContextErrorMessage } from '../common-components/data/actions';
import {
APP_NAME,
COMPLETE_STATE, LOGIN_PAGE, REGISTER_PAGE,
} from '../data/constants';
import { backupLoginForm } from '../login/data/actions';
import { backupRegistrationForm } from '../register/data/actions';
import { NOT_INITIALIZED } from '../register/data/optimizelyExperiment/helper';
import useAutoGeneratedUsernameExperimentVariation
from '../register/data/optimizelyExperiment/useAutoGeneratedUsernameExperimentVariation';
jest.mock('@edx/frontend-platform/analytics', () => ({
sendPageEvent: jest.fn(),
sendTrackEvent: jest.fn(),
}));
jest.mock('@edx/frontend-platform/auth');
jest.mock('../register/data/optimizelyExperiment/useAutoGeneratedUsernameExperimentVariation', () => jest.fn());
const mockStore = configureStore();
const IntlLogistration = injectIntl(Logistration);
describe('Logistration', () => {
let store = {};
@@ -48,30 +55,21 @@ describe('Logistration', () => {
marketingEmailsOptIn: true,
},
formFields: {
name: '',
email: '',
username: '',
password: '',
name: '', email: '', username: '', password: '',
},
emailSuggestion: {
suggestion: '',
type: '',
suggestion: '', type: '',
},
errors: {
name: '',
email: '',
username: '',
password: '',
name: '', email: '', username: '', password: '',
},
},
registrationResult: {
success: false,
redirectUrl: '',
},
registrationResult: { success: false, redirectUrl: '' },
registrationError: {},
usernameSuggestions: [],
validationApiRateLimited: false,
},
cohesion: { eventData: {} },
commonComponents: {
thirdPartyAuthContext: {
providers: [],
@@ -79,18 +77,7 @@ describe('Logistration', () => {
},
},
login: {
loginResult: {
success: false,
redirectUrl: '',
},
loginFormData: {
formFields: {
emailOrUsername: '', password: '',
},
errors: {
emailOrUsername: '', password: '',
},
},
loginResult: { success: false, redirectUrl: '' },
},
};
@@ -103,6 +90,7 @@ describe('Logistration', () => {
})),
}));
useAutoGeneratedUsernameExperimentVariation.mockReturnValue(NOT_INITIALIZED);
configure({
loggingService: { logError: jest.fn() },
config: {
@@ -114,7 +102,7 @@ describe('Logistration', () => {
});
it('should do nothing when user clicks on the same tab (login/register) again', () => {
const { container } = render(reduxWrapper(<Logistration />));
const { container } = render(reduxWrapper(<IntlLogistration />));
// While staying on the registration form, clicking the register tab again
fireEvent.click(container.querySelector('a[data-rb-event-key="/register"]'));
@@ -126,14 +114,14 @@ describe('Logistration', () => {
ALLOW_PUBLIC_ACCOUNT_CREATION: true,
});
const { container } = render(reduxWrapper(<Logistration />));
const { container } = render(reduxWrapper(<IntlLogistration />));
expect(container.querySelector('RegistrationPage')).toBeDefined();
});
it('should render login page', () => {
const props = { selectedPage: LOGIN_PAGE };
const { container } = render(reduxWrapper(<Logistration {...props} />));
const { container } = render(reduxWrapper(<IntlLogistration {...props} />));
expect(container.querySelector('LoginPage')).toBeDefined();
});
@@ -144,7 +132,7 @@ describe('Logistration', () => {
});
let props = { selectedPage: LOGIN_PAGE };
const { rerender } = render(reduxWrapper(<Logistration {...props} />));
const { rerender } = render(reduxWrapper(<IntlLogistration {...props} />));
// verifying sign in heading
expect(screen.getByRole('heading', { level: 3 }).textContent).toEqual('Sign in');
@@ -152,7 +140,7 @@ describe('Logistration', () => {
// register page is still accessible when SHOW_REGISTRATION_LINKS is false
// but it needs to be accessed directly
props = { selectedPage: REGISTER_PAGE };
rerender(reduxWrapper(<Logistration {...props} />));
rerender(reduxWrapper(<IntlLogistration {...props} />));
// verifying register heading
expect(screen.getByRole('heading', { level: 3 }).textContent).toEqual('Register');
@@ -179,7 +167,7 @@ describe('Logistration', () => {
});
const props = { selectedPage: LOGIN_PAGE };
const { container } = render(reduxWrapper(<Logistration {...props} />));
const { container } = render(reduxWrapper(<IntlLogistration {...props} />));
// verifying sign in heading for institution login false
expect(screen.getByRole('heading', { level: 3 }).textContent).toEqual('Sign in');
@@ -209,7 +197,7 @@ describe('Logistration', () => {
});
const props = { selectedPage: LOGIN_PAGE };
render(reduxWrapper(<Logistration {...props} />));
render(reduxWrapper(<IntlLogistration {...props} />));
expect(screen.getByText('Institution/campus credentials')).toBeDefined();
// on clicking "Institution/campus credentials" button, it should display institution login page
@@ -240,11 +228,11 @@ describe('Logistration', () => {
});
const props = { selectedPage: LOGIN_PAGE };
render(reduxWrapper(<Logistration {...props} />));
render(reduxWrapper(<IntlLogistration {...props} />));
fireEvent.click(screen.getByText('Institution/campus credentials'));
expect(sendTrackEvent).toHaveBeenCalledWith('edx.bi.institution_login_form.toggled', { category: 'user-engagement' });
expect(sendPageEvent).toHaveBeenCalledWith('login_and_registration', 'institution_login');
expect(sendTrackEvent).toHaveBeenCalledWith('edx.bi.institution_login_form.toggled', { category: 'user-engagement', app_name: APP_NAME });
expect(sendPageEvent).toHaveBeenCalledWith('login_and_registration', 'institution_login', { app_name: APP_NAME });
mergeConfig({
DISABLE_ENTERPRISE_LOGIN: '',
@@ -272,7 +260,7 @@ describe('Logistration', () => {
delete window.location;
window.location = { hostname: getConfig().SITE_NAME, href: getConfig().BASE_URL };
render(reduxWrapper(<Logistration />));
render(reduxWrapper(<IntlLogistration />));
fireEvent.click(screen.getByText('Institution/campus credentials'));
expect(screen.getByText('Test University')).toBeDefined();
@@ -283,7 +271,7 @@ describe('Logistration', () => {
it('should fire action to backup registration form on tab click', () => {
store.dispatch = jest.fn(store.dispatch);
const { container } = render(reduxWrapper(<Logistration />));
const { container } = render(reduxWrapper(<IntlLogistration />));
fireEvent.click(container.querySelector('a[data-rb-event-key="/login"]'));
expect(store.dispatch).toHaveBeenCalledWith(backupRegistrationForm());
});
@@ -291,14 +279,14 @@ describe('Logistration', () => {
it('should fire action to backup login form on tab click', () => {
store.dispatch = jest.fn(store.dispatch);
const props = { selectedPage: LOGIN_PAGE };
const { container } = render(reduxWrapper(<Logistration {...props} />));
const { container } = render(reduxWrapper(<IntlLogistration {...props} />));
fireEvent.click(container.querySelector('a[data-rb-event-key="/register"]'));
expect(store.dispatch).toHaveBeenCalledWith(backupLoginForm());
});
it('should clear tpa context errorMessage tab click', () => {
store.dispatch = jest.fn(store.dispatch);
const { container } = render(reduxWrapper(<Logistration />));
const { container } = render(reduxWrapper(<IntlLogistration />));
fireEvent.click(container.querySelector('a[data-rb-event-key="/login"]'));
expect(store.dispatch).toHaveBeenCalledWith(clearThirdPartyAuthContextErrorMessage());
});

View File

@@ -1,47 +0,0 @@
# Login Component Slot
### Slot ID: `org.openedx.frontend.authn.login_component.v1`
## Description
This slot is used to replace/modify/hide the login component.
## Example
### Default content
![Default Login Page](./default_component.png)
### With a prepended message
![Login Page with ](./component_with_prefix.png)
The following `env.config.jsx` will add a message before the login component.
```js
import { DIRECT_PLUGIN, PLUGIN_OPERATIONS } from '@openedx/frontend-plugin-framework';
// Load environment variables from .env file
const config = {
...process.env,
pluginSlots: {
'org.openedx.frontend.authn.login_component.v1': {
keepDefault: true,
plugins: [
{
op: PLUGIN_OPERATIONS.Insert,
widget: {
id: 'test_plugin',
type: DIRECT_PLUGIN,
priority: 1,
RenderWidget: () => (
<h2>You're logging into TEST Instance.</h2>
)
},
},
],
},
},
};
export default config;
```

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.5 KiB

View File

@@ -1,31 +0,0 @@
import React from 'react';
import { PluginSlot } from '@openedx/frontend-plugin-framework';
import PropTypes from 'prop-types';
import LoginPage from '../../login/LoginPage';
const LoginComponentSlot = ({
institutionLogin,
handleInstitutionLogin,
}) => (
<PluginSlot
id="org.openedx.frontend.authn.login_component.v1"
pluginProps={{
isInstitutionLogin: institutionLogin,
setInstitutionLogin: handleInstitutionLogin,
}}
>
<LoginPage
institutionLogin={institutionLogin}
handleInstitutionLogin={handleInstitutionLogin}
/>
</PluginSlot>
);
LoginComponentSlot.propTypes = {
institutionLogin: PropTypes.bool,
handleInstitutionLogin: PropTypes.func,
};
export default LoginComponentSlot;

View File

@@ -0,0 +1,29 @@
import { PluginSlot } from '@openedx/frontend-plugin-framework';
import { render } from '@testing-library/react';
import MainAppSlot from './index';
jest.mock('@openedx/frontend-plugin-framework', () => ({
PluginSlot: jest.fn(() => null),
}));
describe('MainAppSlot', () => {
it('renders without crashing', () => {
render(<MainAppSlot />);
});
it('renders a PluginSlot component', () => {
render(<MainAppSlot />);
expect(PluginSlot).toHaveBeenCalled();
});
it('passes the correct id prop to PluginSlot', () => {
render(<MainAppSlot />);
expect(PluginSlot).toHaveBeenCalledWith({ id: 'main_app_slot' }, {});
});
it('does not render any children', () => {
const { container } = render(<MainAppSlot />);
expect(container.firstChild).toBeNull();
});
});

View File

@@ -0,0 +1,41 @@
# Main App Slot
### Slot ID: `main_app_slot`
## Description
This slot is used for adding content at the root level.
## Example
The following `env.config.jsx` will render a component at the MFE root level.
![Screenshot of Content added after the Main App Slot](./images/main_app_slot.png)
```js
import {
DIRECT_PLUGIN,
PLUGIN_OPERATIONS,
} from "@openedx/frontend-plugin-framework";
import { ExampleComponent } from "@openedx/frontend-plugin-example";
const config = {
pluginSlots: {
main_app_slot: {
plugins: [
{
op: PLUGIN_OPERATIONS.Insert,
widget: {
id: "example-component",
type: DIRECT_PLUGIN,
priority: 60,
RenderWidget: ExampleComponent,
},
},
],
},
},
};
export default config;
```

Binary file not shown.

After

Width:  |  Height:  |  Size: 269 KiB

View File

@@ -0,0 +1,7 @@
import { PluginSlot } from '@openedx/frontend-plugin-framework';
const MainAppSlot = () => (
<PluginSlot id="main_app_slot" />
);
export default MainAppSlot;

View File

@@ -0,0 +1,3 @@
# `frontend-app-authn` Plugin Slots
- [`main_app_slot`](./MainAppSlot/)

View File

@@ -2,7 +2,7 @@ import React, { useEffect, useState } from 'react';
import { connect } from 'react-redux';
import { getConfig, snakeCaseObject } from '@edx/frontend-platform';
import { identifyAuthenticatedUser, sendPageEvent, sendTrackEvent } from '@edx/frontend-platform/analytics';
import { identifyAuthenticatedUser } from '@edx/frontend-platform/analytics';
import {
AxiosJwtAuthService,
configure as configureAuth,
@@ -39,6 +39,13 @@ import {
import isOneTrustFunctionalCookieEnabled from '../data/oneTrust';
import { getAllPossibleQueryParams, isHostAvailableInQueryParams } from '../data/utils';
import { FormFieldRenderer } from '../field-renderer';
import {
trackDisablePostRegistrationRecommendations,
trackProgressiveProfilingPageViewed,
trackProgressiveProfilingSkipLinkClick,
trackProgressiveProfilingSubmitClick,
trackProgressiveProfilingSupportLinkCLick,
} from '../tracking/trackers/progressive-profiling';
const ProgressiveProfiling = (props) => {
const { formatMessage } = useIntl();
@@ -98,14 +105,13 @@ const ProgressiveProfiling = (props) => {
useEffect(() => {
if (authenticatedUser?.userId) {
identifyAuthenticatedUser(authenticatedUser.userId);
sendPageEvent('login_and_registration', 'welcome');
trackProgressiveProfilingPageViewed();
}
}, [authenticatedUser]);
useEffect(() => {
if (!enablePostRegistrationRecommendations) {
sendTrackEvent(
'edx.bi.user.recommendations.not.enabled',
trackDisablePostRegistrationRecommendations(
{ functionalCookiesConsent, page: 'authn_recommendations' },
);
return;
@@ -149,29 +155,23 @@ const ProgressiveProfiling = (props) => {
});
}
props.saveUserProfile(authenticatedUser.username, snakeCaseObject(payload));
sendTrackEvent(
'edx.bi.welcome.page.submit.clicked',
{
isGenderSelected: !!values.gender,
isYearOfBirthSelected: !!values.year_of_birth,
isLevelOfEducationSelected: !!values.level_of_education,
isWorkExperienceSelected: !!values.work_experience,
host: queryParams?.host || '',
},
);
const eventProperties = {
isGenderSelected: !!values.gender,
isYearOfBirthSelected: !!values.year_of_birth,
isLevelOfEducationSelected: !!values.level_of_education,
isWorkExperienceSelected: !!values.work_experience,
host: queryParams?.host || '',
};
trackProgressiveProfilingSubmitClick(eventProperties);
};
const handleSkip = (e) => {
e.preventDefault();
window.history.replaceState(location.state, null, '');
setShowModal(true);
sendTrackEvent(
'edx.bi.welcome.page.skip.link.clicked',
{
host: queryParams?.host || '',
},
);
trackProgressiveProfilingSkipLinkClick({
host: queryParams?.host || '',
});
};
const onChangeHandler = (e) => {
@@ -242,7 +242,7 @@ const ProgressiveProfiling = (props) => {
destination={getConfig().AUTHN_PROGRESSIVE_PROFILING_SUPPORT_LINK}
target="_blank"
showLaunchIcon={false}
onClick={() => (sendTrackEvent('edx.bi.welcome.page.support.link.clicked'))}
onClick={() => (trackProgressiveProfilingSupportLinkCLick())}
>
{formatMessage(messages['optional.fields.information.link'])}
</Hyperlink>

View File

@@ -1,16 +1,19 @@
import React from 'react';
import { Provider } from 'react-redux';
import { getConfig, mergeConfig } from '@edx/frontend-platform';
import { identifyAuthenticatedUser, sendTrackEvent } from '@edx/frontend-platform/analytics';
import { getAuthenticatedUser } from '@edx/frontend-platform/auth';
import { configure, IntlProvider } from '@edx/frontend-platform/i18n';
import { configure, injectIntl, IntlProvider } from '@edx/frontend-platform/i18n';
import {
fireEvent, render, screen,
fireEvent, render, screen, waitFor,
} from '@testing-library/react';
import { MemoryRouter, mockNavigate, useLocation } from 'react-router-dom';
import configureStore from 'redux-mock-store';
import mockTagular from '../../cohesion/utils';
import {
APP_NAME,
AUTHN_PROGRESSIVE_PROFILING,
COMPLETE_STATE, DEFAULT_REDIRECT_URL,
EMBEDDED,
@@ -21,7 +24,9 @@ import {
import { saveUserProfile } from '../data/actions';
import ProgressiveProfiling from '../ProgressiveProfiling';
const IntlProgressiveProfilingPage = injectIntl(ProgressiveProfiling);
const mockStore = configureStore();
mockTagular();
jest.mock('@edx/frontend-platform/analytics', () => ({
sendPageEvent: jest.fn(),
@@ -52,6 +57,13 @@ jest.mock('react-router-dom', () => {
};
});
const eventData = {
pageType: 'test-page',
elementType: 'test-element-type',
webElementText: 'test-element-text',
webElementName: 'test-element-name',
};
describe('ProgressiveProfilingTests', () => {
let store = {};
@@ -112,7 +124,7 @@ describe('ProgressiveProfilingTests', () => {
mergeConfig({
AUTHN_PROGRESSIVE_PROFILING_SUPPORT_LINK: '',
});
const { queryByRole } = render(reduxWrapper(<ProgressiveProfiling />));
const { queryByRole } = render(reduxWrapper(<IntlProgressiveProfilingPage />));
const button = queryByRole('button', { name: /learn more about how we use this information/i });
expect(button).toBeNull();
@@ -123,7 +135,7 @@ describe('ProgressiveProfilingTests', () => {
AUTHN_PROGRESSIVE_PROFILING_SUPPORT_LINK: 'http://localhost:1999/support',
});
const { getByText } = render(reduxWrapper(<ProgressiveProfiling />));
const { getByText } = render(reduxWrapper(<IntlProgressiveProfilingPage />));
const learnMoreButton = getByText('Learn more about how we use this information.');
@@ -133,7 +145,7 @@ describe('ProgressiveProfilingTests', () => {
it('should open modal on pressing skip for now button', () => {
delete window.location;
window.location = { href: getConfig().BASE_URL.concat(AUTHN_PROGRESSIVE_PROFILING) };
const { getByRole } = render(reduxWrapper(<ProgressiveProfiling />));
const { getByRole } = render(reduxWrapper(<IntlProgressiveProfilingPage />));
const skipButton = getByRole('button', { name: /skip for now/i });
fireEvent.click(skipButton);
@@ -141,14 +153,15 @@ describe('ProgressiveProfilingTests', () => {
const modalContentContainer = document.getElementsByClassName('.pgn__modal-content-container');
expect(modalContentContainer).toBeTruthy();
const payload = { host: '', app_name: APP_NAME };
expect(sendTrackEvent).toHaveBeenCalledWith('edx.bi.welcome.page.skip.link.clicked', { host: '' });
expect(sendTrackEvent).toHaveBeenCalledWith('edx.bi.welcome.page.skip.link.clicked', payload);
});
// ******** test event functionality ********
it('should make identify call to segment on progressive profiling page', () => {
render(reduxWrapper(<ProgressiveProfiling />));
render(reduxWrapper(<IntlProgressiveProfilingPage />));
expect(identifyAuthenticatedUser).toHaveBeenCalledWith(3);
expect(identifyAuthenticatedUser).toHaveBeenCalled();
@@ -158,12 +171,12 @@ describe('ProgressiveProfilingTests', () => {
mergeConfig({
AUTHN_PROGRESSIVE_PROFILING_SUPPORT_LINK: 'http://localhost:1999/support',
});
render(reduxWrapper(<ProgressiveProfiling />));
render(reduxWrapper(<IntlProgressiveProfilingPage />));
const supportLink = screen.getByRole('link', { name: /learn more about how we use this information/i });
fireEvent.click(supportLink);
expect(sendTrackEvent).toHaveBeenCalledWith('edx.bi.welcome.page.support.link.clicked');
expect(sendTrackEvent).toHaveBeenCalledWith('edx.bi.welcome.page.support.link.clicked', { app_name: APP_NAME });
});
it('should set empty host property value for non-embedded experience', () => {
@@ -173,10 +186,11 @@ describe('ProgressiveProfilingTests', () => {
isLevelOfEducationSelected: false,
isWorkExperienceSelected: false,
host: '',
app_name: APP_NAME,
};
delete window.location;
window.location = { href: getConfig().BASE_URL.concat(AUTHN_PROGRESSIVE_PROFILING) };
render(reduxWrapper(<ProgressiveProfiling />));
render(reduxWrapper(<IntlProgressiveProfilingPage />));
const nextButton = screen.getByText('Next');
fireEvent.click(nextButton);
@@ -192,7 +206,7 @@ describe('ProgressiveProfilingTests', () => {
extended_profile: [{ field_name: 'company', field_value: 'test company' }],
};
store.dispatch = jest.fn(store.dispatch);
const { getByLabelText, getByText } = render(reduxWrapper(<ProgressiveProfiling />));
const { getByLabelText, getByText } = render(reduxWrapper(<IntlProgressiveProfilingPage />));
const genderSelect = getByLabelText('Gender');
const companyInput = getByLabelText('Company');
@@ -214,7 +228,7 @@ describe('ProgressiveProfilingTests', () => {
},
});
const { container } = render(reduxWrapper(<ProgressiveProfiling />));
const { container } = render(reduxWrapper(<IntlProgressiveProfilingPage />));
const errorElement = container.querySelector('#pp-page-errors');
expect(errorElement).toBeTruthy();
@@ -230,7 +244,7 @@ describe('ProgressiveProfilingTests', () => {
href: getConfig().BASE_URL,
};
render(reduxWrapper(<ProgressiveProfiling />));
render(reduxWrapper(<IntlProgressiveProfilingPage />));
expect(window.location.href).toEqual(DASHBOARD_URL);
});
@@ -247,8 +261,11 @@ describe('ProgressiveProfilingTests', () => {
...initialState.welcomePage,
success: true,
},
cohesion: {
eventData,
},
});
const { container } = render(reduxWrapper(<ProgressiveProfiling />));
const { container } = render(reduxWrapper(<IntlProgressiveProfilingPage />));
const nextButton = container.querySelector('button.btn-brand');
expect(nextButton.textContent).toEqual('Next');
@@ -273,13 +290,18 @@ describe('ProgressiveProfilingTests', () => {
...initialState.welcomePage,
success: true,
},
cohesion: {
eventData,
},
});
const { container } = render(reduxWrapper(<ProgressiveProfiling />));
const { container } = render(reduxWrapper(<IntlProgressiveProfilingPage />));
const nextButton = container.querySelector('button.btn-brand');
expect(nextButton.textContent).toEqual('Submit');
expect(window.location.href).toEqual(redirectUrl);
await waitFor(() => {
expect(window.location.href).toEqual(redirectUrl);
}, { timeout: 1100 });
});
});
@@ -309,12 +331,12 @@ describe('ProgressiveProfilingTests', () => {
href: getConfig().BASE_URL.concat(AUTHN_PROGRESSIVE_PROFILING),
search: `?host=${host}&variant=${EMBEDDED}`,
};
render(reduxWrapper(<ProgressiveProfiling />));
render(reduxWrapper(<IntlProgressiveProfilingPage />));
const skipLinkButton = screen.getByText('Skip for now');
fireEvent.click(skipLinkButton);
expect(sendTrackEvent).toHaveBeenCalledWith('edx.bi.welcome.page.skip.link.clicked', { host });
expect(sendTrackEvent).toHaveBeenCalledWith('edx.bi.welcome.page.skip.link.clicked', { host, app_name: APP_NAME });
});
it('should show spinner while fetching the optional fields', () => {
@@ -334,7 +356,7 @@ describe('ProgressiveProfilingTests', () => {
},
});
const { container } = render(reduxWrapper(<ProgressiveProfiling />));
const { container } = render(reduxWrapper(<IntlProgressiveProfilingPage />));
const tpaSpinnerElement = container.querySelector('#tpa-spinner');
expect(tpaSpinnerElement).toBeTruthy();
@@ -347,13 +369,14 @@ describe('ProgressiveProfilingTests', () => {
isLevelOfEducationSelected: false,
isWorkExperienceSelected: false,
host: 'http://example.com',
app_name: APP_NAME,
};
delete window.location;
window.location = {
href: getConfig().BASE_URL.concat(AUTHN_PROGRESSIVE_PROFILING),
search: `?host=${host}`,
};
render(reduxWrapper(<ProgressiveProfiling />));
render(reduxWrapper(<IntlProgressiveProfilingPage />));
const submitButton = screen.getByText('Next');
fireEvent.click(submitButton);
@@ -368,7 +391,7 @@ describe('ProgressiveProfilingTests', () => {
search: `?variant=${EMBEDDED}&host=${host}`,
};
const { container } = render(reduxWrapper(<ProgressiveProfiling />));
const { container } = render(reduxWrapper(<IntlProgressiveProfilingPage />));
const genderField = container.querySelector('#gender');
expect(genderField).toBeTruthy();
@@ -389,11 +412,11 @@ describe('ProgressiveProfilingTests', () => {
},
});
render(reduxWrapper(<ProgressiveProfiling />));
render(reduxWrapper(<IntlProgressiveProfilingPage />));
expect(window.location.href).toBe(DASHBOARD_URL);
});
it('should redirect to provided redirect url', () => {
it('should redirect to provided redirect url', async () => {
const redirectUrl = 'https://redirect-test.com';
delete window.location;
window.location = {
@@ -415,12 +438,17 @@ describe('ProgressiveProfilingTests', () => {
...initialState.welcomePage,
success: true,
},
cohesion: {
eventData,
},
});
render(reduxWrapper(<ProgressiveProfiling />));
render(reduxWrapper(<IntlProgressiveProfilingPage />));
const submitButton = screen.getByText('Submit');
fireEvent.click(submitButton);
expect(window.location.href).toBe(redirectUrl);
await waitFor(() => {
expect(window.location.href).toBe(redirectUrl);
}, { timeout: 1100 });
});
});
});

View File

@@ -1,9 +1,13 @@
import { IntlProvider } from '@edx/frontend-platform/i18n';
import React from 'react';
import { injectIntl, IntlProvider } from '@edx/frontend-platform/i18n';
import { render } from '@testing-library/react';
import SmallLayout from './SmallLayout';
import mockedRecommendedProducts from '../data/tests/mockedData';
const IntlRecommendationsSmallLayoutPage = injectIntl(SmallLayout);
jest.mock('react-router-dom', () => ({
...jest.requireActual('react-router-dom'),
useLocation: jest.fn(),
@@ -32,7 +36,7 @@ describe('RecommendationsPageTests', () => {
});
it('should render recommendations when recommendations are not loading', () => {
const { container } = render(reduxWrapper(<SmallLayout {...props} />));
const { container } = render(reduxWrapper(<IntlRecommendationsSmallLayoutPage {...props} />));
const reactLoadingSkeleton = container.querySelector('.react-loading-skeleton');
@@ -44,7 +48,7 @@ describe('RecommendationsPageTests', () => {
...props,
isLoading: true,
};
const { container } = render(reduxWrapper(<SmallLayout {...props} />));
const { container } = render(reduxWrapper(<IntlRecommendationsSmallLayoutPage {...props} />));
const reactLoadingSkeleton = container.querySelector('.react-loading-skeleton');

View File

@@ -1,12 +1,10 @@
import React from 'react';
import { render } from '@testing-library/react';
import { renderHook } from '@testing-library/react';
import algoliasearchHelper from 'algoliasearch-helper';
import mockedRecommendedProducts from './mockedData';
import CreateAlgoliaSearchHelperMock from './test_utils/test_utils';
import isOneTrustFunctionalCookieEnabled from '../../../data/oneTrust';
import useAlgoliaRecommendations from '../hooks/useAlgoliaRecommendations';
import CreateAlgoliaSearchHelperMock from './test_utils/test_utils';
jest.mock('algoliasearch-helper');
@@ -19,23 +17,6 @@ jest.mock('../../../data/algolia', () => ({
jest.mock('../algoliaResultsParser', () => jest.fn((course) => course));
const renderHook = (hookCallback) => {
const result = {
current: null,
};
const Component = () => {
const val = hookCallback();
React.useEffect(() => {
result.current = val;
});
return null;
};
render(<Component />);
return { result };
};
describe('useAlgoliaRecommendations Tests', () => {
const MockSearchHelperWithData = new CreateAlgoliaSearchHelperMock(mockedRecommendedProducts);
const MockSearchHelperWithoutData = new CreateAlgoliaSearchHelperMock();
@@ -47,10 +28,8 @@ describe('useAlgoliaRecommendations Tests', () => {
() => useAlgoliaRecommendations('PK', 'Introductory'),
);
expect(result.current.recommendations)
.toEqual(mockedRecommendedProducts);
expect(result.current.isLoading)
.toBe(false);
expect(result.current.recommendations).toEqual(mockedRecommendedProducts);
expect(result.current.isLoading).toBe(false);
});
it('should not fetch recommendations if functional cookies are not set', async () => {
@@ -60,10 +39,8 @@ describe('useAlgoliaRecommendations Tests', () => {
() => useAlgoliaRecommendations('PK', 'Introductory'),
);
expect(result.current.recommendations)
.toEqual([]);
expect(result.current.isLoading)
.toBe(false);
expect(result.current.recommendations).toEqual([]);
expect(result.current.isLoading).toBe(false);
});
it('should return empty list if no recommendations returned from Algolia', async () => {
@@ -73,9 +50,7 @@ describe('useAlgoliaRecommendations Tests', () => {
() => useAlgoliaRecommendations('PK', 'Introductory'),
);
expect(result.current.recommendations)
.toEqual([]);
expect(result.current.isLoading)
.toBe(false);
expect(result.current.recommendations).toEqual([]);
expect(result.current.isLoading).toBe(false);
});
});

View File

@@ -1,12 +1,14 @@
import React from 'react';
import { Provider } from 'react-redux';
import { IntlProvider } from '@edx/frontend-platform/i18n';
import { injectIntl, IntlProvider } from '@edx/frontend-platform/i18n';
import { render } from '@testing-library/react';
import configureStore from 'redux-mock-store';
import mockedProductData from './mockedData';
import RecommendationList from '../RecommendationsList';
const IntlRecommendationList = injectIntl(RecommendationList);
const mockStore = configureStore();
describe('RecommendationsListTests', () => {
@@ -23,7 +25,7 @@ describe('RecommendationsListTests', () => {
userId: 1234567,
};
const { container } = render(reduxWrapper(<RecommendationList {...props} />));
const { container } = render(reduxWrapper(<IntlRecommendationList {...props} />));
const recommendationCards = container.querySelectorAll('.recommendation-card');
expect(recommendationCards.length).toEqual(mockedProductData.length);
@@ -35,7 +37,7 @@ describe('RecommendationsListTests', () => {
userId: 1234567,
};
const { getByText } = render(reduxWrapper(<RecommendationList {...props} />));
const { getByText } = render(reduxWrapper(<IntlRecommendationList {...props} />));
const firstFooterContent = getByText('1 Course');
const secondFooterContent = getByText('2 Courses');

View File

@@ -1,8 +1,9 @@
import React from 'react';
import { Provider } from 'react-redux';
import { getConfig } from '@edx/frontend-platform';
import { sendTrackEvent } from '@edx/frontend-platform/analytics';
import { IntlProvider } from '@edx/frontend-platform/i18n';
import { injectIntl, IntlProvider } from '@edx/frontend-platform/i18n';
import { useMediaQuery } from '@openedx/paragon';
import { fireEvent, render } from '@testing-library/react';
import { useLocation } from 'react-router-dom';
@@ -15,6 +16,7 @@ import mockedRecommendedProducts from '../data/tests/mockedData';
import RecommendationsPage from '../RecommendationsPage';
import { eventNames, getProductMapping } from '../track';
const IntlRecommendationsPage = injectIntl(RecommendationsPage);
const mockStore = configureStore();
jest.mock('@edx/frontend-platform/analytics', () => ({
@@ -75,7 +77,7 @@ describe('RecommendationsPageTests', () => {
});
it('should redirect to dashboard if user is not coming from registration workflow', () => {
render(reduxWrapper(<RecommendationsPage />));
render(reduxWrapper(<IntlRecommendationsPage />));
expect(window.location.href).toEqual(dashboardUrl);
});
@@ -84,14 +86,14 @@ describe('RecommendationsPageTests', () => {
recommendations: [],
isLoading: false,
});
render(reduxWrapper(<RecommendationsPage />));
render(reduxWrapper(<IntlRecommendationsPage />));
expect(window.location.href).toEqual(dashboardUrl);
});
it('should redirect user if they click "Skip for now" button', () => {
mockUseLocation();
jest.useFakeTimers();
const { container } = render(reduxWrapper(<RecommendationsPage />));
const { container } = render(reduxWrapper(<IntlRecommendationsPage />));
const skipButton = container.querySelector('.pgn__stateful-btn-state-default');
fireEvent.click(skipButton);
jest.advanceTimersByTime(300);
@@ -101,7 +103,7 @@ describe('RecommendationsPageTests', () => {
it('should display recommendations small layout for small screen', () => {
mockUseLocation();
useMediaQuery.mockReturnValue(true);
const { container } = render(reduxWrapper(<RecommendationsPage />));
const { container } = render(reduxWrapper(<IntlRecommendationsPage />));
const recommendationsSmallLayout = container.querySelector('#recommendations-small-layout');
const reactLoadingSkeleton = container.querySelector('.react-loading-skeleton');
@@ -113,7 +115,7 @@ describe('RecommendationsPageTests', () => {
it('should display recommendations large layout for large screen', () => {
mockUseLocation();
useMediaQuery.mockReturnValue(false);
const { container } = render(reduxWrapper(<RecommendationsPage />));
const { container } = render(reduxWrapper(<IntlRecommendationsPage />));
const pgnCollapsible = container.querySelector('.pgn_collapsible');
const reactLoadingSkeleton = container.querySelector('.react-loading-skeleton');
@@ -129,7 +131,7 @@ describe('RecommendationsPageTests', () => {
recommendations: [],
isLoading: true,
});
const { container } = render(reduxWrapper(<RecommendationsPage />));
const { container } = render(reduxWrapper(<IntlRecommendationsPage />));
const reactLoadingSkeleton = container.querySelector('.react-loading-skeleton');
@@ -143,7 +145,7 @@ describe('RecommendationsPageTests', () => {
recommendations: [],
isLoading: true,
});
const { container } = render(reduxWrapper(<RecommendationsPage />));
const { container } = render(reduxWrapper(<IntlRecommendationsPage />));
const reactLoadingSkeleton = container.querySelector('.react-loading-skeleton');
@@ -158,7 +160,7 @@ describe('RecommendationsPageTests', () => {
});
useMediaQuery.mockReturnValue(false);
render(reduxWrapper(<RecommendationsPage />));
render(reduxWrapper(<IntlRecommendationsPage />));
expect(sendTrackEvent).toBeCalled();
expect(sendTrackEvent).toHaveBeenCalledWith(

View File

@@ -15,7 +15,7 @@ const generateProductKey = (product) => (
export const getProductMapping = (recommendedProducts) => recommendedProducts.map((product) => ({
product_key: generateProductKey(product),
product_line: product.cardType,
product_source: product.productSource.name,
product_source: product?.productSource?.name,
}));
export const trackRecommendationClick = (product, position, userId) => {
@@ -25,7 +25,7 @@ export const trackRecommendationClick = (product, position, userId) => {
recommendation_type: product.recommendationType,
product_key: generateProductKey(product),
product_line: product.cardType,
product_source: product.productSource.name,
product_source: product?.productSource?.name,
user_id: userId,
});

View File

@@ -1,7 +1,8 @@
import React from 'react';
import { Provider } from 'react-redux';
import { mergeConfig } from '@edx/frontend-platform';
import { IntlProvider } from '@edx/frontend-platform/i18n';
import { injectIntl, IntlProvider } from '@edx/frontend-platform/i18n';
import { fireEvent, render } from '@testing-library/react';
import { BrowserRouter as Router } from 'react-router-dom';
import configureStore from 'redux-mock-store';
@@ -9,6 +10,7 @@ import configureStore from 'redux-mock-store';
import { COUNTRY_CODE_KEY, COUNTRY_DISPLAY_KEY } from './validator';
import { CountryField } from '../index';
const IntlCountryField = injectIntl(CountryField);
const mockStore = configureStore();
jest.mock('react-router-dom', () => {
@@ -80,7 +82,7 @@ describe('CountryField', () => {
};
it('should run country field validation when onBlur is fired', () => {
const { container } = render(routerWrapper(reduxWrapper(<CountryField {...props} />)));
const { container } = render(routerWrapper(reduxWrapper(<IntlCountryField {...props} />)));
const countryInput = container.querySelector('input[name="country"]');
fireEvent.blur(countryInput, {
@@ -95,7 +97,7 @@ describe('CountryField', () => {
});
it('should run country field validation when country name is invalid', () => {
const { container } = render(routerWrapper(reduxWrapper(<CountryField {...props} />)));
const { container } = render(routerWrapper(reduxWrapper(<IntlCountryField {...props} />)));
const countryInput = container.querySelector('input[name="country"]');
fireEvent.blur(countryInput, {
@@ -110,7 +112,7 @@ describe('CountryField', () => {
});
it('should not run country field validation when onBlur is fired by drop-down arrow icon click', () => {
const { container } = render(routerWrapper(reduxWrapper(<CountryField {...props} />)));
const { container } = render(routerWrapper(reduxWrapper(<IntlCountryField {...props} />)));
const countryInput = container.querySelector('input[name="country"]');
const dropdownArrowIcon = container.querySelector('.btn-icon.pgn__form-autosuggest__icon-button');
@@ -123,7 +125,7 @@ describe('CountryField', () => {
});
it('should update errors for frontend validations', () => {
const { container } = render(routerWrapper(reduxWrapper(<CountryField {...props} />)));
const { container } = render(routerWrapper(reduxWrapper(<IntlCountryField {...props} />)));
const countryInput = container.querySelector('input[name="country"]');
fireEvent.blur(countryInput, { target: { value: '', name: 'country' } });
@@ -133,7 +135,7 @@ describe('CountryField', () => {
});
it('should clear error on focus', () => {
const { container } = render(routerWrapper(reduxWrapper(<CountryField {...props} />)));
const { container } = render(routerWrapper(reduxWrapper(<IntlCountryField {...props} />)));
const countryInput = container.querySelector('input[name="country"]');
fireEvent.focus(countryInput);
@@ -151,7 +153,7 @@ describe('CountryField', () => {
},
});
const { container } = render(routerWrapper(reduxWrapper(<CountryField {...props} />)));
const { container } = render(routerWrapper(reduxWrapper(<IntlCountryField {...props} />)));
container.querySelector('input[name="country"]');
expect(props.onChangeHandler).toHaveBeenCalledTimes(1);
@@ -162,7 +164,7 @@ describe('CountryField', () => {
});
it('should set option on dropdown menu item click', () => {
const { container } = render(routerWrapper(reduxWrapper(<CountryField {...props} />)));
const { container } = render(routerWrapper(reduxWrapper(<IntlCountryField {...props} />)));
const dropdownButton = container.querySelector('.pgn__form-autosuggest__icon-button');
fireEvent.click(dropdownButton);
@@ -179,7 +181,7 @@ describe('CountryField', () => {
it('should set value on change', () => {
const { container } = render(
routerWrapper(reduxWrapper(<CountryField {...props} />)),
routerWrapper(reduxWrapper(<IntlCountryField {...props} />)),
);
const countryInput = container.querySelector('input[name="country"]');
@@ -198,7 +200,7 @@ describe('CountryField', () => {
errorMessage: 'country error message',
};
const { container } = render(routerWrapper(reduxWrapper(<CountryField {...props} />)));
const { container } = render(routerWrapper(reduxWrapper(<IntlCountryField {...props} />)));
const feedbackElement = container.querySelector('div[feedback-for="country"]');
expect(feedbackElement).toBeTruthy();

View File

@@ -1,7 +1,8 @@
import React from 'react';
import { Provider } from 'react-redux';
import { getConfig } from '@edx/frontend-platform';
import { IntlProvider } from '@edx/frontend-platform/i18n';
import { injectIntl, IntlProvider } from '@edx/frontend-platform/i18n';
import { fireEvent, render } from '@testing-library/react';
import { BrowserRouter as Router } from 'react-router-dom';
import configureStore from 'redux-mock-store';
@@ -9,6 +10,7 @@ import configureStore from 'redux-mock-store';
import { clearRegistrationBackendError, fetchRealtimeValidations } from '../../data/actions';
import { EmailField } from '../index';
const IntlEmailField = injectIntl(EmailField);
const mockStore = configureStore();
jest.mock('react-router-dom', () => {
@@ -78,7 +80,7 @@ describe('EmailField', () => {
};
it('should run email field validation when onBlur is fired', () => {
const { container } = render(routerWrapper(reduxWrapper(<EmailField {...props} />)));
const { container } = render(routerWrapper(reduxWrapper(<IntlEmailField {...props} />)));
const emailInput = container.querySelector('input#email');
fireEvent.blur(emailInput, { target: { value: '', name: 'email' } });
@@ -90,7 +92,7 @@ describe('EmailField', () => {
});
it('should update errors for frontend validations', () => {
const { container } = render(routerWrapper(reduxWrapper(<EmailField {...props} />)));
const { container } = render(routerWrapper(reduxWrapper(<IntlEmailField {...props} />)));
const emailInput = container.querySelector('input#email');
fireEvent.blur(emailInput, { target: { value: 'ab', name: 'email' } });
@@ -103,7 +105,7 @@ describe('EmailField', () => {
});
it('should clear error on focus', () => {
const { container } = render(routerWrapper(reduxWrapper(<EmailField {...props} />)));
const { container } = render(routerWrapper(reduxWrapper(<IntlEmailField {...props} />)));
const emailInput = container.querySelector('input#email');
fireEvent.focus(emailInput, { target: { value: '', name: 'email' } });
@@ -117,7 +119,7 @@ describe('EmailField', () => {
it('should call backend validation api on blur event, if frontend validations have passed', () => {
store.dispatch = jest.fn(store.dispatch);
const { container } = render(routerWrapper(reduxWrapper(<EmailField {...props} />)));
const { container } = render(routerWrapper(reduxWrapper(<IntlEmailField {...props} />)));
// Enter a valid email so that frontend validations are passed
const emailInput = container.querySelector('input#email');
@@ -127,7 +129,7 @@ describe('EmailField', () => {
});
it('should give email suggestions for common service provider domain typos', () => {
const { container } = render(routerWrapper(reduxWrapper(<EmailField {...props} />)));
const { container } = render(routerWrapper(reduxWrapper(<IntlEmailField {...props} />)));
const emailInput = container.querySelector('input#email');
fireEvent.blur(emailInput, { target: { value: 'john@yopmail.com', name: 'email' } });
@@ -137,7 +139,7 @@ describe('EmailField', () => {
});
it('should be able to click on email suggestions and set it as value', () => {
const { container } = render(routerWrapper(reduxWrapper(<EmailField {...props} />)));
const { container } = render(routerWrapper(reduxWrapper(<IntlEmailField {...props} />)));
const emailInput = container.querySelector('input#email');
fireEvent.blur(emailInput, { target: { value: 'john@yopmail.com', name: 'email' } });
@@ -152,7 +154,7 @@ describe('EmailField', () => {
});
it('should give error for common top level domain mistakes', () => {
const { container } = render(routerWrapper(reduxWrapper(<EmailField {...props} />)));
const { container } = render(routerWrapper(reduxWrapper(<IntlEmailField {...props} />)));
const emailInput = container.querySelector('input#email');
fireEvent.blur(emailInput, { target: { value: 'john@gmail.mistake', name: 'email' } });
@@ -162,7 +164,7 @@ describe('EmailField', () => {
});
it('should give error and suggestion for invalid email', () => {
const { container } = render(routerWrapper(reduxWrapper(<EmailField {...props} />)));
const { container } = render(routerWrapper(reduxWrapper(<IntlEmailField {...props} />)));
const emailInput = container.querySelector('input#email');
fireEvent.blur(emailInput, { target: { value: 'john@gmail', name: 'email' } });
@@ -192,7 +194,7 @@ describe('EmailField', () => {
store.dispatch = jest.fn(store.dispatch);
const { container } = render(routerWrapper(reduxWrapper(<EmailField {...props} />)));
const { container } = render(routerWrapper(reduxWrapper(<IntlEmailField {...props} />)));
const emailInput = container.querySelector('input#email');
fireEvent.focus(emailInput, { target: { value: 'a@gmail.com', name: 'email' } });
@@ -201,7 +203,7 @@ describe('EmailField', () => {
});
it('should clear email suggestions when close icon is clicked', () => {
const { container } = render(routerWrapper(reduxWrapper(<EmailField {...props} />)));
const { container } = render(routerWrapper(reduxWrapper(<IntlEmailField {...props} />)));
const emailInput = container.querySelector('input#email');
fireEvent.blur(emailInput, { target: { value: 'john@gmail.mistake', name: 'email' } });
@@ -222,7 +224,7 @@ describe('EmailField', () => {
confirmEmailValue: 'confirmEmail@yopmail.com',
};
const { container } = render(routerWrapper(reduxWrapper(<EmailField {...props} />)));
const { container } = render(routerWrapper(reduxWrapper(<IntlEmailField {...props} />)));
const emailInput = container.querySelector('input#email');
fireEvent.blur(emailInput, { target: { value: 'differentEmail@yopmail.com', name: 'email' } });

View File

@@ -1,9 +1,13 @@
import React from 'react';
import { getConfig, mergeConfig } from '@edx/frontend-platform';
import { IntlProvider } from '@edx/frontend-platform/i18n';
import { injectIntl, IntlProvider } from '@edx/frontend-platform/i18n';
import { render } from '@testing-library/react';
import { HonorCode } from '../index';
const IntlHonorCode = injectIntl(HonorCode);
describe('HonorCodeTest', () => {
mergeConfig({
PRIVACY_POLICY: 'http://privacy-policy.com',
@@ -24,7 +28,7 @@ describe('HonorCodeTest', () => {
const errorMessage = `You must agree to the ${getConfig().SITE_NAME} Honor Code`;
const { container } = render(
<IntlProvider locale="en">
<HonorCode
<IntlHonorCode
errorMessage={errorMessage}
onChangeHandler={changeHandler}
/>
@@ -39,7 +43,7 @@ describe('HonorCodeTest', () => {
const expectedMsg = 'I agree to the Your Platform Name Here\u00a0Honor Codein a new tab';
const { container } = render(
<IntlProvider locale="en">
<HonorCode onChangeHandler={changeHandler} />
<IntlHonorCode onChangeHandler={changeHandler} />
</IntlProvider>,
);
@@ -52,7 +56,7 @@ describe('HonorCodeTest', () => {
it('should render Terms of Service and Honor code field', () => {
const { container } = render(
<IntlProvider locale="en">
<HonorCode fieldType="tos_and_honor_code" onChangeHandler={changeHandler} />
<IntlHonorCode fieldType="tos_and_honor_code" onChangeHandler={changeHandler} />
</IntlProvider>,
);
const expectedMsg = 'By creating an account, you agree to the Terms of Service and Honor Code and you '

View File

@@ -1,6 +1,7 @@
import React from 'react';
import { Provider } from 'react-redux';
import { IntlProvider } from '@edx/frontend-platform/i18n';
import { injectIntl, IntlProvider } from '@edx/frontend-platform/i18n';
import { fireEvent, render } from '@testing-library/react';
import { BrowserRouter as Router } from 'react-router-dom';
import configureStore from 'redux-mock-store';
@@ -8,6 +9,7 @@ import configureStore from 'redux-mock-store';
import { clearRegistrationBackendError, fetchRealtimeValidations } from '../../data/actions';
import { NameField } from '../index';
const IntlNameField = injectIntl(NameField);
const mockStore = configureStore();
jest.mock('react-router-dom', () => {
@@ -67,7 +69,7 @@ describe('NameField', () => {
const fieldValidation = { name: 'Enter your full name' };
it('should run name field validation when onBlur is fired', () => {
const { container } = render(routerWrapper(reduxWrapper(<NameField {...props} />)));
const { container } = render(routerWrapper(reduxWrapper(<IntlNameField {...props} />)));
const nameInput = container.querySelector('input#name');
fireEvent.blur(nameInput, { target: { value: '', name: 'name' } });
@@ -80,7 +82,7 @@ describe('NameField', () => {
});
it('should update errors for frontend validations', () => {
const { container } = render(routerWrapper(reduxWrapper(<NameField {...props} />)));
const { container } = render(routerWrapper(reduxWrapper(<IntlNameField {...props} />)));
const nameInput = container.querySelector('input#name');
fireEvent.blur(nameInput, { target: { value: 'https://invalid-name.com', name: 'name' } });
@@ -93,7 +95,7 @@ describe('NameField', () => {
});
it('should clear error on focus', () => {
const { container } = render(routerWrapper(reduxWrapper(<NameField {...props} />)));
const { container } = render(routerWrapper(reduxWrapper(<IntlNameField {...props} />)));
const nameInput = container.querySelector('input#name');
fireEvent.focus(nameInput, { target: { value: '', name: 'name' } });
@@ -111,7 +113,7 @@ describe('NameField', () => {
...props,
shouldFetchUsernameSuggestions: true,
};
const { container } = render(routerWrapper(reduxWrapper(<NameField {...props} />)));
const { container } = render(routerWrapper(reduxWrapper(<IntlNameField {...props} />)));
const nameInput = container.querySelector('input#name');
// Enter a valid name so that frontend validations are passed
@@ -133,7 +135,7 @@ describe('NameField', () => {
});
store.dispatch = jest.fn(store.dispatch);
const { container } = render(routerWrapper(reduxWrapper(<NameField {...props} />)));
const { container } = render(routerWrapper(reduxWrapper(<IntlNameField {...props} />)));
const nameInput = container.querySelector('input#name');

View File

@@ -11,7 +11,7 @@ export const INVALID_NAME_REGEX = /https?:\/\/(?:[-\w.]|(?:%[\da-fA-F]{2}))*/g;
const validateName = (value, formatMessage) => {
let fieldError = '';
if (!value.trim()) {
if (!value || (value && !value.trim())) {
fieldError = formatMessage(messages['empty.name.field.error']);
} else if (URL_REGEX.test(value) || HTML_REGEX.test(value) || INVALID_NAME_REGEX.test(value)) {
fieldError = formatMessage(messages['name.validation.message']);

View File

@@ -1,9 +1,13 @@
import React from 'react';
import { getConfig } from '@edx/frontend-platform';
import { IntlProvider } from '@edx/frontend-platform/i18n';
import { injectIntl, IntlProvider } from '@edx/frontend-platform/i18n';
import { fireEvent, render } from '@testing-library/react';
import { TermsOfService } from '../index';
const IntlTermsOfService = injectIntl(TermsOfService);
describe('TermsOfServiceTest', () => {
let value = false;
@@ -19,7 +23,7 @@ describe('TermsOfServiceTest', () => {
const errorMessage = `You must agree to the ${getConfig().SITE_NAME} Terms of Service`;
const { container } = render(
<IntlProvider locale="en">
<TermsOfService errorMessage={errorMessage} onChangeHandler={changeHandler} />
<IntlTermsOfService errorMessage={errorMessage} onChangeHandler={changeHandler} />
</IntlProvider>,
);
const errorElement = container.querySelector('.form-text-size');
@@ -29,7 +33,7 @@ describe('TermsOfServiceTest', () => {
it('should render Terms of Service field', () => {
const { container } = render(
<IntlProvider locale="en">
<TermsOfService onChangeHandler={changeHandler} />
<IntlTermsOfService onChangeHandler={changeHandler} />
</IntlProvider>,
);
@@ -44,7 +48,7 @@ describe('TermsOfServiceTest', () => {
it('should change value when Terms of Service field is checked', () => {
const { container } = render(
<IntlProvider locale="en">
<TermsOfService onChangeHandler={changeHandler} />
<IntlTermsOfService onChangeHandler={changeHandler} />
</IntlProvider>,
);
const field = container.querySelector('input#tos');

View File

@@ -101,7 +101,7 @@ const UsernameField = (props) => {
};
const suggestedUsernames = () => (
<div className={className} role="listbox">
<div className={className}>
<span className="text-gray username-suggestion--label">{formatMessage(messages['registration.username.suggestion.label'])}</span>
<div className="username-scroll-suggested--form-field">
{usernameSuggestions.map((username, index) => (
@@ -112,9 +112,7 @@ const UsernameField = (props) => {
className="username-suggestions--chip data-hj-suppress"
autoComplete={props.autoComplete}
key={`suggestion-${index.toString()}`}
tabIndex={0}
onClick={(e) => handleSuggestionClick(e, username)}
role="option"
>
{username}
</Button>
@@ -125,7 +123,7 @@ const UsernameField = (props) => {
);
if (usernameSuggestions.length > 0 && errorMessage && value === ' ') {
className = 'username-suggestions';
className = 'username-suggestions__error';
iconButton = <IconButton src={Close} iconAs={Icon} alt="Close" onClick={() => handleUsernameSuggestionClose()} variant="black" size="sm" className="username-suggestions__close__button" />;
suggestedUsernameDiv = suggestedUsernames();
} else if (usernameSuggestions.length > 0 && value === ' ') {
@@ -136,15 +134,14 @@ const UsernameField = (props) => {
suggestedUsernameDiv = suggestedUsernames();
}
return (
<div className="username__form-group-wrapper">
<FormGroup
{...props}
handleChange={handleOnChange}
handleFocus={handleOnFocus}
handleBlur={handleOnBlur}
>
{suggestedUsernameDiv}
<FormGroup
{...props}
handleChange={handleOnChange}
handleFocus={handleOnFocus}
handleBlur={handleOnBlur}
/>
</div>
</FormGroup>
);
};

View File

@@ -1,6 +1,7 @@
import React from 'react';
import { Provider } from 'react-redux';
import { IntlProvider } from '@edx/frontend-platform/i18n';
import { injectIntl, IntlProvider } from '@edx/frontend-platform/i18n';
import { fireEvent, render } from '@testing-library/react';
import { BrowserRouter as Router } from 'react-router-dom';
import configureStore from 'redux-mock-store';
@@ -8,6 +9,7 @@ import configureStore from 'redux-mock-store';
import { clearRegistrationBackendError, clearUsernameSuggestions, fetchRealtimeValidations } from '../../data/actions';
import { UsernameField } from '../index';
const IntlUsernameField = injectIntl(UsernameField);
const mockStore = configureStore();
jest.mock('react-router-dom', () => {
@@ -71,7 +73,7 @@ describe('UsernameField', () => {
};
it('should run username field validation when onBlur is fired', () => {
const { container } = render(routerWrapper(reduxWrapper(<UsernameField {...props} />)));
const { container } = render(routerWrapper(reduxWrapper(<IntlUsernameField {...props} />)));
const usernameField = container.querySelector('input#username');
fireEvent.blur(usernameField, { target: { value: '', name: 'username' } });
@@ -84,7 +86,7 @@ describe('UsernameField', () => {
});
it('should update errors for frontend validations', () => {
const { container } = render(routerWrapper(reduxWrapper(<UsernameField {...props} />)));
const { container } = render(routerWrapper(reduxWrapper(<IntlUsernameField {...props} />)));
const usernameField = container.querySelector('input#username');
fireEvent.blur(usernameField, { target: { value: 'user#', name: 'username' } });
@@ -97,7 +99,7 @@ describe('UsernameField', () => {
});
it('should clear error on focus', () => {
const { container } = render(routerWrapper(reduxWrapper(<UsernameField {...props} />)));
const { container } = render(routerWrapper(reduxWrapper(<IntlUsernameField {...props} />)));
const usernameField = container.querySelector('input#username');
fireEvent.focus(usernameField, { target: { value: '', name: 'username' } });
@@ -110,7 +112,7 @@ describe('UsernameField', () => {
});
it('should remove space from field on focus if space exists', () => {
const { container } = render(routerWrapper(reduxWrapper(<UsernameField {...props} />)));
const { container } = render(routerWrapper(reduxWrapper(<IntlUsernameField {...props} />)));
const usernameField = container.querySelector('input#username');
fireEvent.focus(usernameField, { target: { value: ' ', name: 'username' } });
@@ -123,7 +125,7 @@ describe('UsernameField', () => {
it('should call backend validation api on blur event, if frontend validations have passed', () => {
store.dispatch = jest.fn(store.dispatch);
const { container } = render(routerWrapper(reduxWrapper(<UsernameField {...props} />)));
const { container } = render(routerWrapper(reduxWrapper(<IntlUsernameField {...props} />)));
const usernameField = container.querySelector('input#username');
// Enter a valid username so that frontend validations are passed
@@ -133,7 +135,7 @@ describe('UsernameField', () => {
});
it('should remove space from the start of username on change', () => {
const { container } = render(routerWrapper(reduxWrapper(<UsernameField {...props} />)));
const { container } = render(routerWrapper(reduxWrapper(<IntlUsernameField {...props} />)));
const usernameField = container.querySelector('input#username');
fireEvent.change(usernameField, { target: { value: ' test-user', name: 'username' } });
@@ -144,7 +146,7 @@ describe('UsernameField', () => {
});
it('should not set username if it is more than 30 character long', () => {
const { container } = render(routerWrapper(reduxWrapper(<UsernameField {...props} />)));
const { container } = render(routerWrapper(reduxWrapper(<IntlUsernameField {...props} />)));
const usernameField = container.querySelector('input#username');
fireEvent.change(usernameField, { target: { value: 'why_this_is_not_valid_username_', name: 'username' } });
@@ -155,7 +157,7 @@ describe('UsernameField', () => {
it('should clear username suggestions when username field is focused in', () => {
store.dispatch = jest.fn(store.dispatch);
const { container } = render(routerWrapper(reduxWrapper(<UsernameField {...props} />)));
const { container } = render(routerWrapper(reduxWrapper(<IntlUsernameField {...props} />)));
const usernameField = container.querySelector('input#username');
fireEvent.focus(usernameField);
@@ -177,7 +179,7 @@ describe('UsernameField', () => {
errorMessage: 'It looks like this username is already taken',
};
const { container } = render(routerWrapper(reduxWrapper(<UsernameField {...props} />)));
const { container } = render(routerWrapper(reduxWrapper(<IntlUsernameField {...props} />)));
const usernameSuggestions = container.querySelectorAll('button.username-suggestions--chip');
expect(usernameSuggestions.length).toEqual(3);
});
@@ -196,7 +198,7 @@ describe('UsernameField', () => {
value: ' ',
};
const { container } = render(routerWrapper(reduxWrapper(<UsernameField {...props} />)));
const { container } = render(routerWrapper(reduxWrapper(<IntlUsernameField {...props} />)));
const usernameSuggestions = container.querySelectorAll('button.username-suggestions--chip');
expect(usernameSuggestions.length).toEqual(3);
});
@@ -216,7 +218,7 @@ describe('UsernameField', () => {
errorMessage: 'username error',
};
const { container } = render(routerWrapper(reduxWrapper(<UsernameField {...props} />)));
const { container } = render(routerWrapper(reduxWrapper(<IntlUsernameField {...props} />)));
const usernameSuggestions = container.querySelectorAll('button.username-suggestions--chip');
expect(usernameSuggestions.length).toEqual(3);
});
@@ -230,7 +232,7 @@ describe('UsernameField', () => {
},
});
render(routerWrapper(reduxWrapper(<UsernameField {...props} />)));
render(routerWrapper(reduxWrapper(<IntlUsernameField {...props} />)));
expect(props.handleChange).toHaveBeenCalledTimes(1);
expect(props.handleChange).toHaveBeenCalledWith(
{ target: { name: 'username', value: ' ' } },
@@ -251,7 +253,7 @@ describe('UsernameField', () => {
value: ' ',
};
const { container } = render(routerWrapper(reduxWrapper(<UsernameField {...props} />)));
const { container } = render(routerWrapper(reduxWrapper(<IntlUsernameField {...props} />)));
const usernameSuggestion = container.querySelector('.username-suggestions--chip');
fireEvent.click(usernameSuggestion);
expect(props.handleChange).toHaveBeenCalledTimes(1);
@@ -275,7 +277,7 @@ describe('UsernameField', () => {
value: ' ',
};
const { container } = render(routerWrapper(reduxWrapper(<UsernameField {...props} />)));
const { container } = render(routerWrapper(reduxWrapper(<IntlUsernameField {...props} />)));
let closeButton = container.querySelector('button.username-suggestions__close__button');
fireEvent.click(closeButton);
expect(store.dispatch).toHaveBeenCalledWith(clearUsernameSuggestions());
@@ -285,7 +287,7 @@ describe('UsernameField', () => {
errorMessage: 'username error',
};
render(routerWrapper(reduxWrapper(<UsernameField {...props} />)));
render(routerWrapper(reduxWrapper(<IntlUsernameField {...props} />)));
closeButton = container.querySelector('button.username-suggestions__close__button');
fireEvent.click(closeButton);
expect(store.dispatch).toHaveBeenCalledWith(clearUsernameSuggestions());
@@ -307,7 +309,7 @@ describe('UsernameField', () => {
store.dispatch = jest.fn(store.dispatch);
const { container } = render(routerWrapper(reduxWrapper(<UsernameField {...props} />)));
const { container } = render(routerWrapper(reduxWrapper(<IntlUsernameField {...props} />)));
const usernameField = container.querySelector('input#username');
fireEvent.focus(usernameField, { target: { value: 'test', name: 'username' } });

View File

@@ -4,7 +4,6 @@ import React, {
import { useDispatch, useSelector } from 'react-redux';
import { getConfig } from '@edx/frontend-platform';
import { sendPageEvent, sendTrackEvent } from '@edx/frontend-platform/analytics';
import { useIntl } from '@edx/frontend-platform/i18n';
import { Form, Spinner, StatefulButton } from '@openedx/paragon';
import classNames from 'classnames';
@@ -12,12 +11,19 @@ import PropTypes from 'prop-types';
import { Helmet } from 'react-helmet';
import Skeleton from 'react-loading-skeleton';
import {
InstitutionLogistration,
PasswordField,
RedirectLogistration,
ThirdPartyAuthAlert,
} from '../common-components';
import ConfigurableRegistrationForm from './components/ConfigurableRegistrationForm';
import RegistrationFailure from './components/RegistrationFailure';
import {
backupRegistrationFormBegin,
clearRegistrationBackendError,
registerNewUser,
setAutoGeneratedUsernameExperimentData,
setEmailSuggestionInStore,
setUserPipelineDataLoaded,
} from './data/actions';
@@ -25,6 +31,8 @@ import {
FORM_SUBMISSION_ERROR,
TPA_AUTHENTICATION_FAILURE,
} from './data/constants';
import { AUTO_GENERATED_USERNAME_REGISTRATION_EXP_VARIATION, NOT_INITIALIZED } from './data/optimizelyExperiment/helper';
import useAutoGeneratedUsernameExperimentVariation from './data/optimizelyExperiment/useAutoGeneratedUsernameExperimentVariation';
import getBackendValidations from './data/selectors';
import {
isFormValid, prepareRegistrationPayload,
@@ -32,21 +40,20 @@ import {
import messages from './messages';
import { EmailField, NameField, UsernameField } from './RegistrationFields';
import {
InstitutionLogistration,
PasswordField,
RedirectLogistration,
ThirdPartyAuthAlert,
} from '../common-components';
ELEMENT_NAME, ELEMENT_TEXT, ELEMENT_TYPES, PAGE_TYPES,
} from '../cohesion/constants';
import { setCohesionEventStates } from '../cohesion/data/actions';
import { getThirdPartyAuthContext as getRegistrationDataFromBackend } from '../common-components/data/actions';
import EnterpriseSSO from '../common-components/EnterpriseSSO';
import ThirdPartyAuth from '../common-components/ThirdPartyAuth';
import {
COMPLETE_STATE, PENDING_STATE, REGISTER_PAGE,
APP_NAME, COMPLETE_STATE, PENDING_STATE,
REGISTER_PAGE,
} from '../data/constants';
import {
getAllPossibleQueryParams, getTpaHint, getTpaProvider, isHostAvailableInQueryParams, setCookie,
getAllPossibleQueryParams, getTpaHint, getTpaProvider, isHostAvailableInQueryParams, removeCookie, setCookie,
} from '../data/utils';
import { trackRegistrationPageViewed, trackRegistrationSuccess } from '../tracking/trackers/register';
/**
* Main Registration Page component
*/
@@ -68,6 +75,7 @@ const RegistrationPage = (props) => {
} = props;
const backedUpFormData = useSelector(state => state.register.registrationFormData);
const initExpVariation = useSelector(state => state.register.autoGeneratedUsernameExperimentVariation);
const registrationError = useSelector(state => state.register.registrationError);
const registrationErrorCode = registrationError?.errorCode;
const registrationResult = useSelector(state => state.register.registrationResult);
@@ -85,6 +93,7 @@ const RegistrationPage = (props) => {
const providers = useSelector(state => state.commonComponents.thirdPartyAuthContext.providers);
const secondaryProviders = useSelector(state => state.commonComponents.thirdPartyAuthContext.secondaryProviders);
const pipelineUserDetails = useSelector(state => state.commonComponents.thirdPartyAuthContext.pipelineUserDetails);
const countriesCodesList = useSelector(state => state.commonComponents.countriesCodesList);
const backendValidations = useSelector(getBackendValidations);
const queryParams = useMemo(() => getAllPossibleQueryParams(), []);
@@ -103,6 +112,12 @@ const RegistrationPage = (props) => {
? formatMessage(messages['create.account.cta.button'], { label: cta })
: formatMessage(messages['create.account.for.free.button']);
const autoGeneratedUsernameExpVariation = useAutoGeneratedUsernameExperimentVariation(
initExpVariation, registrationEmbedded, tpaHint, currentProvider, thirdPartyAuthApiStatus,
);
const hideUsernameField = flags.autoGeneratedUsernameEnabled
|| autoGeneratedUsernameExpVariation === AUTO_GENERATED_USERNAME_REGISTRATION_EXP_VARIATION;
/**
* Set the userPipelineDetails data in formFields for only first time
*/
@@ -128,7 +143,7 @@ const RegistrationPage = (props) => {
useEffect(() => {
if (!formStartTime) {
sendPageEvent('login_and_registration', 'register');
trackRegistrationPageViewed();
const payload = { ...queryParams, is_register_page: true };
if (tpaHint) {
payload.tpa_hint = tpaHint;
@@ -149,8 +164,10 @@ const RegistrationPage = (props) => {
formFields: { ...formFields },
errors: { ...errors },
}));
dispatch(setAutoGeneratedUsernameExperimentData(autoGeneratedUsernameExpVariation));
}
}, [shouldBackupState, configurableFormFields, formFields, errors, dispatch, backedUpFormData]);
}, [shouldBackupState, configurableFormFields, // eslint-disable-line react-hooks/exhaustive-deps
formFields, errors, dispatch, backedUpFormData]);
useEffect(() => {
if (backendValidations) {
@@ -171,10 +188,15 @@ const RegistrationPage = (props) => {
useEffect(() => {
if (registrationResult.success) {
// This event is used by GTM
sendTrackEvent('edx.bi.user.account.registered.client', {});
trackRegistrationSuccess();
// This is used by the "User Retention Rate Event" on GTM
setCookie(getConfig().USER_RETENTION_COOKIE_NAME, true);
// Remove marketingEmailsOptIn cookie that was set on SSO registration flow
removeCookie('marketingEmailsOptIn');
// Remove this cookie that was set to capture marketingEmailsOptIn for the onboarding component
removeCookie('ssoPipelineRedirectionDone');
}
}, [registrationResult]);
@@ -210,13 +232,13 @@ const RegistrationPage = (props) => {
const registerUser = () => {
const totalRegistrationTime = (Date.now() - formStartTime) / 1000;
let payload = { ...formFields };
let payload = { ...formFields, app_name: APP_NAME };
if (currentProvider) {
delete payload.password;
payload.social_auth_provider = currentProvider;
}
if (flags.autoGeneratedUsernameEnabled) {
if (hideUsernameField) {
delete payload.username;
}
@@ -251,6 +273,14 @@ const RegistrationPage = (props) => {
const handleSubmit = (e) => {
e.preventDefault();
const eventData = {
pageType: PAGE_TYPES.ACCOUNT_CREATION,
elementType: ELEMENT_TYPES.BUTTON,
webElementText: ELEMENT_TEXT.CREATE_ACCOUNT,
webElementName: ELEMENT_NAME.CREATE_ACCOUNT,
};
dispatch(setCohesionEventStates(eventData));
registerUser();
};
@@ -285,107 +315,112 @@ const RegistrationPage = (props) => {
redirectToProgressiveProfilingPage={
getConfig().ENABLE_PROGRESSIVE_PROFILING_ON_AUTHN && !!Object.keys(optionalFields.fields).length
}
currentProvider={currentProvider}
/>
{autoSubmitRegForm && !errorCode.type ? (
<div className="mw-xs mt-5 text-center">
<Spinner animation="border" variant="primary" id="tpa-spinner" />
</div>
) : (
<div
className={classNames(
'mw-xs mt-3',
{ 'w-100 m-auto pt-4 main-content': registrationEmbedded },
)}
>
<ThirdPartyAuthAlert
currentProvider={currentProvider}
platformName={platformName}
referrer={REGISTER_PAGE}
/>
<RegistrationFailure
errorCode={errorCode.type}
failureCount={errorCode.count}
context={{ provider: currentProvider, errorMessage: thirdPartyAuthErrorMessage }}
/>
<Form id="registration-form" name="registration-form">
<NameField
name="name"
value={formFields.name}
shouldFetchUsernameSuggestions={!formFields.username.trim()}
handleChange={handleOnChange}
handleErrorChange={handleErrorChange}
errorMessage={errors.name}
helpText={[formatMessage(messages['help.text.name'])]}
floatingLabel={formatMessage(messages['registration.fullname.label'])}
{(autoSubmitRegForm && !errorCode.type)
|| (!autoGeneratedUsernameExpVariation && !(
autoGeneratedUsernameExpVariation === NOT_INITIALIZED
|| registrationEmbedded || !!tpaHint || !!currentProvider))
? (
<div className="mw-xs mt-5 text-center">
<Spinner animation="border" variant="primary" id="tpa-spinner" />
</div>
) : (
<div
className={classNames(
'mw-xs mt-3',
{ 'w-100 m-auto pt-4 main-content': registrationEmbedded },
)}
>
<ThirdPartyAuthAlert
currentProvider={currentProvider}
platformName={platformName}
referrer={REGISTER_PAGE}
/>
<EmailField
name="email"
value={formFields.email}
confirmEmailValue={configurableFormFields?.confirm_email}
handleErrorChange={handleErrorChange}
handleChange={handleOnChange}
errorMessage={errors.email}
helpText={[formatMessage(messages['help.text.email'])]}
floatingLabel={formatMessage(messages['registration.email.label'])}
<RegistrationFailure
errorCode={errorCode.type}
failureCount={errorCode.count}
context={{ provider: currentProvider, errorMessage: thirdPartyAuthErrorMessage }}
/>
{!flags.autoGeneratedUsernameEnabled && (
<UsernameField
name="username"
spellCheck="false"
value={formFields.username}
<Form id="registration-form" name="registration-form">
<NameField
name="name"
value={formFields.name}
shouldFetchUsernameSuggestions={!formFields.username.trim()}
handleChange={handleOnChange}
handleErrorChange={handleErrorChange}
errorMessage={errors.username}
helpText={[formatMessage(messages['help.text.username.1']), formatMessage(messages['help.text.username.2'])]}
floatingLabel={formatMessage(messages['registration.username.label'])}
errorMessage={errors.name}
helpText={[formatMessage(messages['help.text.name'])]}
floatingLabel={formatMessage(messages['registration.fullname.label'])}
/>
)}
{!currentProvider && (
<PasswordField
name="password"
value={formFields.password}
handleChange={handleOnChange}
<EmailField
name="email"
value={formFields.email}
confirmEmailValue={configurableFormFields?.confirm_email}
handleErrorChange={handleErrorChange}
errorMessage={errors.password}
floatingLabel={formatMessage(messages['registration.password.label'])}
handleChange={handleOnChange}
errorMessage={errors.email}
helpText={[formatMessage(messages['help.text.email'])]}
floatingLabel={formatMessage(messages['registration.email.label'])}
/>
)}
<ConfigurableRegistrationForm
email={formFields.email}
fieldErrors={errors}
formFields={configurableFormFields}
setFieldErrors={registrationEmbedded ? setTemporaryErrors : setErrors}
setFormFields={setConfigurableFormFields}
autoSubmitRegisterForm={autoSubmitRegForm}
fieldDescriptions={fieldDescriptions}
/>
<StatefulButton
id="register-user"
name="register-user"
type="submit"
variant="brand"
className="register-button mt-4 mb-4"
state={submitState}
labels={{
default: buttonLabel,
pending: '',
}}
onClick={handleSubmit}
onMouseDown={(e) => e.preventDefault()}
/>
{!registrationEmbedded && (
<ThirdPartyAuth
currentProvider={currentProvider}
providers={providers}
secondaryProviders={secondaryProviders}
handleInstitutionLogin={handleInstitutionLogin}
thirdPartyAuthApiStatus={thirdPartyAuthApiStatus}
{!hideUsernameField && (
<UsernameField
name="username"
spellCheck="false"
value={formFields.username}
handleChange={handleOnChange}
handleErrorChange={handleErrorChange}
errorMessage={errors.username}
helpText={[formatMessage(messages['help.text.username.1']), formatMessage(messages['help.text.username.2'])]}
floatingLabel={formatMessage(messages['registration.username.label'])}
/>
)}
{!currentProvider && (
<PasswordField
name="password"
value={formFields.password}
handleChange={handleOnChange}
handleErrorChange={handleErrorChange}
errorMessage={errors.password}
floatingLabel={formatMessage(messages['registration.password.label'])}
/>
)}
<ConfigurableRegistrationForm
email={formFields.email}
fieldErrors={errors}
formFields={configurableFormFields}
setFieldErrors={registrationEmbedded ? setTemporaryErrors : setErrors}
setFormFields={setConfigurableFormFields}
autoSubmitRegisterForm={autoSubmitRegForm}
fieldDescriptions={fieldDescriptions}
countriesCodesList={countriesCodesList}
/>
)}
</Form>
</div>
)}
<StatefulButton
id="register-user"
name="register-user"
type="submit"
variant="brand"
className="register-button mt-4 mb-4"
state={submitState}
labels={{
default: buttonLabel,
pending: '',
}}
onClick={handleSubmit}
onMouseDown={(e) => e.preventDefault()}
/>
{!registrationEmbedded && (
<ThirdPartyAuth
currentProvider={currentProvider}
providers={providers}
secondaryProviders={secondaryProviders}
handleInstitutionLogin={handleInstitutionLogin}
thirdPartyAuthApiStatus={thirdPartyAuthApiStatus}
/>
)}
</Form>
</div>
)}
</>
);
};

View File

@@ -1,11 +1,12 @@
import React from 'react';
import { Provider } from 'react-redux';
import { getConfig, mergeConfig } from '@edx/frontend-platform';
import { sendPageEvent, sendTrackEvent } from '@edx/frontend-platform/analytics';
import {
configure, getLocale, IntlProvider,
configure, getLocale, injectIntl, IntlProvider,
} from '@edx/frontend-platform/i18n';
import { fireEvent, render } from '@testing-library/react';
import { fireEvent, render, waitFor } from '@testing-library/react';
import { mockNavigate, BrowserRouter as Router } from 'react-router-dom';
import configureStore from 'redux-mock-store';
@@ -16,9 +17,13 @@ import {
setUserPipelineDataLoaded,
} from './data/actions';
import { INTERNAL_SERVER_ERROR } from './data/constants';
import mockTagular from '../cohesion/utils';
import { NOT_INITIALIZED } from './data/optimizelyExperiment/helper';
import useAutoGeneratedUsernameExperimentVariation
from './data/optimizelyExperiment/useAutoGeneratedUsernameExperimentVariation';
import RegistrationPage from './RegistrationPage';
import {
AUTHN_PROGRESSIVE_PROFILING, COMPLETE_STATE, PENDING_STATE, REGISTER_PAGE,
APP_NAME, AUTHN_PROGRESSIVE_PROFILING, COMPLETE_STATE, PENDING_STATE, REGISTER_PAGE,
} from '../data/constants';
jest.mock('@edx/frontend-platform/analytics', () => ({
@@ -29,8 +34,11 @@ jest.mock('@edx/frontend-platform/i18n', () => ({
...jest.requireActual('@edx/frontend-platform/i18n'),
getLocale: jest.fn(),
}));
jest.mock('./data/optimizelyExperiment/useAutoGeneratedUsernameExperimentVariation', () => jest.fn());
const IntlRegistrationPage = injectIntl(RegistrationPage);
const mockStore = configureStore();
mockTagular();
jest.mock('react-router-dom', () => {
const mockNavigation = jest.fn();
@@ -100,6 +108,7 @@ describe('RegistrationPage', () => {
usernameSuggestions: [],
},
cohesion: { eventData: {} },
commonComponents: {
thirdPartyAuthApiStatus: null,
thirdPartyAuthContext,
@@ -126,6 +135,7 @@ describe('RegistrationPage', () => {
institutionLogin: false,
};
window.location = { search: '' };
useAutoGeneratedUsernameExperimentVariation.mockReturnValue(NOT_INITIALIZED);
});
afterEach(() => {
@@ -183,10 +193,11 @@ describe('RegistrationPage', () => {
honor_code: true,
total_registration_time: 0,
next: '/course/demo-course-url',
app_name: APP_NAME,
};
store.dispatch = jest.fn(store.dispatch);
const { getByLabelText, container } = render(routerWrapper(reduxWrapper(<RegistrationPage {...props} />)));
const { getByLabelText, container } = render(routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)));
populateRequiredFields(getByLabelText, payload);
const button = container.querySelector('button.btn-brand');
fireEvent.click(button);
@@ -205,6 +216,7 @@ describe('RegistrationPage', () => {
honor_code: true,
social_auth_provider: 'Apple',
total_registration_time: 0,
app_name: APP_NAME,
};
store = mockStore({
@@ -218,7 +230,7 @@ describe('RegistrationPage', () => {
},
});
store.dispatch = jest.fn(store.dispatch);
const { getByLabelText, container } = render(routerWrapper(reduxWrapper(<RegistrationPage {...props} />)));
const { getByLabelText, container } = render(routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)));
populateRequiredFields(getByLabelText, formPayload, true);
const button = container.querySelector('button.btn-brand');
@@ -241,7 +253,7 @@ describe('RegistrationPage', () => {
};
store.dispatch = jest.fn(store.dispatch);
const { getByLabelText, container } = render(routerWrapper(reduxWrapper(<RegistrationPage {...props} />)));
const { getByLabelText, container } = render(routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)));
populateRequiredFields(getByLabelText, formPayload, true);
const button = container.querySelector('button.btn-brand');
@@ -266,7 +278,7 @@ describe('RegistrationPage', () => {
};
store.dispatch = jest.fn(store.dispatch);
const { getByLabelText, container } = render(routerWrapper(reduxWrapper(<RegistrationPage {...props} />)));
const { getByLabelText, container } = render(routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)));
populateRequiredFields(getByLabelText, formPayload, true);
const button = container.querySelector('button.btn-brand');
fireEvent.click(button);
@@ -290,10 +302,11 @@ describe('RegistrationPage', () => {
honor_code: true,
total_registration_time: 0,
marketing_emails_opt_in: true,
app_name: APP_NAME,
};
store.dispatch = jest.fn(store.dispatch);
const { getByLabelText, container } = render(routerWrapper(reduxWrapper(<RegistrationPage {...props} />)));
const { getByLabelText, container } = render(routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)));
populateRequiredFields(getByLabelText, payload);
const button = container.querySelector('button.btn-brand');
fireEvent.click(button);
@@ -316,10 +329,11 @@ describe('RegistrationPage', () => {
country: 'Pakistan',
honor_code: true,
total_registration_time: 0,
app_name: APP_NAME,
};
store.dispatch = jest.fn(store.dispatch);
const { getByLabelText, container } = render(routerWrapper(reduxWrapper(<RegistrationPage {...props} />)));
const { getByLabelText, container } = render(routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)));
populateRequiredFields(getByLabelText, payload, false, true);
const button = container.querySelector('button.btn-brand');
fireEvent.click(button);
@@ -334,7 +348,7 @@ describe('RegistrationPage', () => {
ENABLE_AUTO_GENERATED_USERNAME: true,
});
const { queryByLabelText } = render(routerWrapper(reduxWrapper(<RegistrationPage {...props} />)));
const { queryByLabelText } = render(routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)));
expect(queryByLabelText('Username')).toBeNull();
mergeConfig({
@@ -345,7 +359,7 @@ describe('RegistrationPage', () => {
it('should not dispatch registerNewUser on empty form Submission', () => {
store.dispatch = jest.fn(store.dispatch);
const { container } = render(routerWrapper(reduxWrapper(<RegistrationPage {...props} />)));
const { container } = render(routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)));
const button = container.querySelector('button.btn-brand');
fireEvent.click(button);
@@ -356,7 +370,7 @@ describe('RegistrationPage', () => {
// ******** test registration form validations ********
it('should show error messages for required fields on empty form submission', () => {
const { container } = render(routerWrapper(reduxWrapper(<RegistrationPage {...props} />)));
const { container } = render(routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)));
const button = container.querySelector('button.btn-brand');
fireEvent.click(button);
@@ -384,7 +398,7 @@ describe('RegistrationPage', () => {
},
},
});
const { container } = render(routerWrapper(reduxWrapper(<IntlProvider locale="en"><RegistrationPage {...props} /></IntlProvider>)));
const { container } = render(routerWrapper(reduxWrapper(<IntlProvider locale="en"><IntlRegistrationPage {...props} /></IntlProvider>)));
const usernameFeedback = container.querySelector('div[feedback-for="username"]');
const emailFeedback = container.querySelector('div[feedback-for="email"]');
@@ -393,7 +407,7 @@ describe('RegistrationPage', () => {
});
it('should clear error on focus', () => {
const { container } = render(routerWrapper(reduxWrapper(<RegistrationPage {...props} />)));
const { container } = render(routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)));
const submitButton = container.querySelector('button.btn-brand');
fireEvent.click(submitButton);
@@ -422,7 +436,7 @@ describe('RegistrationPage', () => {
store.dispatch = jest.fn(store.dispatch);
const { container } = render(routerWrapper(reduxWrapper(
<RegistrationPage {...props} />,
<IntlRegistrationPage {...props} />,
)));
const emailInput = container.querySelector('input#email');
@@ -433,7 +447,7 @@ describe('RegistrationPage', () => {
// ******** test form buttons and fields ********
it('should match default button state', () => {
const { container } = render(routerWrapper(reduxWrapper(<RegistrationPage {...props} />)));
const { container } = render(routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)));
const button = container.querySelector('button[type="submit"] span');
expect(button.textContent).toEqual('Create an account for free');
});
@@ -447,7 +461,7 @@ describe('RegistrationPage', () => {
},
});
const { container } = render(routerWrapper(reduxWrapper(<RegistrationPage {...props} />)));
const { container } = render(routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)));
const button = container.querySelector('button[type="submit"] span.sr-only');
expect(button.textContent).toEqual('pending');
@@ -458,7 +472,7 @@ describe('RegistrationPage', () => {
MARKETING_EMAILS_OPT_IN: 'true',
});
const { container } = render(routerWrapper(reduxWrapper(<RegistrationPage {...props} />)));
const { container } = render(routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)));
const checkboxDivs = container.querySelectorAll('div.form-field--checkbox');
expect(checkboxDivs.length).toEqual(1);
@@ -471,7 +485,7 @@ describe('RegistrationPage', () => {
const buttonLabel = 'Register';
delete window.location;
window.location = { href: getConfig().BASE_URL, search: `?cta=${buttonLabel}` };
const { container } = render(reduxWrapper(<RegistrationPage {...props} />));
const { container } = render(reduxWrapper(<IntlRegistrationPage {...props} />));
const button = container.querySelector('button[type="submit"] span');
const buttonText = button.textContent;
@@ -490,11 +504,11 @@ describe('RegistrationPage', () => {
},
});
render(routerWrapper(reduxWrapper(<RegistrationPage {...props} />)));
render(routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)));
expect(document.cookie).toMatch(`${getConfig().USER_RETENTION_COOKIE_NAME}=true`);
});
it('should redirect to url returned in registration result after successful account creation', () => {
it('should redirect to url returned in registration result after successful account creation', async () => {
const dashboardURL = 'https://test.com/testing-dashboard/';
store = mockStore({
...initialState,
@@ -508,11 +522,13 @@ describe('RegistrationPage', () => {
});
delete window.location;
window.location = { href: getConfig().BASE_URL };
render(routerWrapper(reduxWrapper(<RegistrationPage {...props} />)));
expect(window.location.href).toBe(dashboardURL);
render(routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)));
await waitFor(() => {
expect(window.location.href).toBe(dashboardURL);
}, { timeout: 1100 });
});
it('should redirect to dashboard if features flags are configured but no optional fields are configured', () => {
it('should redirect to dashboard if features flags are configured but no optional fields are configured', async () => {
mergeConfig({
ENABLE_PROGRESSIVE_PROFILING_ON_AUTHN: true,
});
@@ -535,8 +551,10 @@ describe('RegistrationPage', () => {
});
delete window.location;
window.location = { href: getConfig().BASE_URL };
render(routerWrapper(reduxWrapper(<RegistrationPage {...props} />)));
expect(window.location.href).toBe(dashboardUrl);
render(routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)));
await waitFor(() => {
expect(window.location.href).toBe(dashboardUrl);
}, { timeout: 1100 });
});
it('should redirect to progressive profiling page if optional fields are configured', () => {
@@ -566,7 +584,7 @@ describe('RegistrationPage', () => {
render(reduxWrapper(
<Router>
<RegistrationPage {...props} />
<IntlRegistrationPage {...props} />
</Router>,
));
expect(mockNavigate).toHaveBeenCalledWith(AUTHN_PROGRESSIVE_PROFILING);
@@ -584,13 +602,13 @@ describe('RegistrationPage', () => {
});
store.dispatch = jest.fn(store.dispatch);
render(routerWrapper(reduxWrapper(<RegistrationPage {...props} />)));
render(routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)));
expect(store.dispatch).toHaveBeenCalledWith(backupRegistrationFormBegin({ ...registrationFormData }));
});
it('should send page event when register page is rendered', () => {
render(routerWrapper(reduxWrapper(<RegistrationPage {...props} />)));
expect(sendPageEvent).toHaveBeenCalledWith('login_and_registration', 'register');
render(routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)));
expect(sendPageEvent).toHaveBeenCalledWith('login_and_registration', 'register', { app_name: APP_NAME });
});
it('should send track event when user has successfully registered', () => {
@@ -607,8 +625,8 @@ describe('RegistrationPage', () => {
delete window.location;
window.location = { href: getConfig().BASE_URL };
render(routerWrapper(reduxWrapper(<RegistrationPage {...props} />)));
expect(sendTrackEvent).toHaveBeenCalledWith('edx.bi.user.account.registered.client', {});
render(routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)));
expect(sendTrackEvent).toHaveBeenCalledWith('edx.bi.user.account.registered.client', { app_name: APP_NAME });
});
it('should populate form with pipeline user details', () => {
@@ -633,7 +651,7 @@ describe('RegistrationPage', () => {
store.dispatch = jest.fn(store.dispatch);
const { container } = render(reduxWrapper(
<Router>
<RegistrationPage {...props} />
<IntlRegistrationPage {...props} />
</Router>,
));
@@ -656,7 +674,7 @@ describe('RegistrationPage', () => {
},
});
const { container } = render(routerWrapper(reduxWrapper(<RegistrationPage {...props} />)));
const { container } = render(routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)));
const validationErrors = container.querySelector('div#validation-errors');
expect(validationErrors.textContent).toContain(
'An error has occurred. Try refreshing the page, or check your internet connection.',
@@ -683,7 +701,7 @@ describe('RegistrationPage', () => {
},
});
const { container } = render(routerWrapper(reduxWrapper(<RegistrationPage {...props} />)));
const { container } = render(routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)));
const fullNameInput = container.querySelector('input#name');
const usernameInput = container.querySelector('input#username');
@@ -729,14 +747,14 @@ describe('RegistrationPage', () => {
},
},
});
render(routerWrapper(reduxWrapper(<RegistrationPage {...props} />)));
render(routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)));
expect(window.parent.postMessage).toHaveBeenCalledTimes(2);
});
it('should not display validations error on blur event when embedded variant is rendered', () => {
delete window.location;
window.location = { href: getConfig().BASE_URL.concat(REGISTER_PAGE), search: '?host=http://localhost/host-website' };
const { container } = render(reduxWrapper(<RegistrationPage {...props} />));
const { container } = render(reduxWrapper(<IntlRegistrationPage {...props} />));
const usernameInput = container.querySelector('input#username');
fireEvent.blur(usernameInput, { target: { value: '', name: 'username' } });
@@ -764,7 +782,7 @@ describe('RegistrationPage', () => {
},
});
const { container } = render(routerWrapper(reduxWrapper(
<RegistrationPage {...props} />),
<IntlRegistrationPage {...props} />),
));
const usernameFeedback = container.querySelector('div[feedback-for="username"]');
@@ -781,7 +799,7 @@ describe('RegistrationPage', () => {
search: '?host=http://localhost/host-website',
};
const { container } = render(routerWrapper(reduxWrapper(<RegistrationPage {...props} />)));
const { container } = render(routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)));
const submitButton = container.querySelector('button.btn-brand');
fireEvent.click(submitButton);
@@ -822,7 +840,7 @@ describe('RegistrationPage', () => {
});
store.dispatch = jest.fn(store.dispatch);
const { container } = render(routerWrapper(reduxWrapper(<RegistrationPage {...props} />)));
const { container } = render(routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)));
const spinnerElement = container.querySelector('#tpa-spinner');
const registrationFormElement = container.querySelector('#registration-form');
@@ -873,7 +891,7 @@ describe('RegistrationPage', () => {
});
store.dispatch = jest.fn(store.dispatch);
render(routerWrapper(reduxWrapper(<RegistrationPage {...props} />)));
render(routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)));
expect(store.dispatch).toHaveBeenCalledWith(registerNewUser({
name: 'John Doe',
username: 'john_doe',
@@ -881,6 +899,7 @@ describe('RegistrationPage', () => {
country: 'PK',
social_auth_provider: 'Apple',
total_registration_time: 0,
app_name: APP_NAME,
}));
});
});

View File

@@ -1,10 +1,16 @@
import React, { useEffect, useMemo } from 'react';
import React, { useCallback, useEffect, useMemo } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { getConfig } from '@edx/frontend-platform';
import { getCountryList, getLocale, useIntl } from '@edx/frontend-platform/i18n';
import PropTypes from 'prop-types';
import {
ELEMENT_NAME, ELEMENT_TEXT, ELEMENT_TYPES, PAGE_TYPES,
} from '../../cohesion/constants';
import trackCohesionEvent from '../../cohesion/trackers';
import { FormFieldRenderer } from '../../field-renderer';
import { backupRegistrationFormBegin } from '../data/actions';
import { FIELDS } from '../data/constants';
import messages from '../messages';
import { CountryField, HonorCode, TermsOfService } from '../RegistrationFields';
@@ -31,13 +37,14 @@ const ConfigurableRegistrationForm = (props) => {
setFieldErrors,
setFormFields,
autoSubmitRegistrationForm,
countriesCodesList,
} = props;
const dispatch = useDispatch();
/** The reason for adding the entry 'United States' is that Chrome browser aut-fill the form with the 'Unites
States' instead of 'United States of America' which does not exist in country dropdown list and gets the user
confused and unable to create an account. So we added the United States entry in the dropdown list.
*/
const countryList = useMemo(() => getCountryList(getLocale()).concat([{ code: 'US', name: 'United States' }]), []);
let showTermsOfServiceAndHonorCode = false;
let showCountryField = false;
@@ -50,6 +57,8 @@ const ConfigurableRegistrationForm = (props) => {
showMarketingEmailOptInCheckbox: getConfig().MARKETING_EMAILS_OPT_IN,
};
const backedUpFormData = useSelector(state => state.register.registrationFormData);
/**
* If auto submitting register form, we will check tos and honor code fields if they exist for feature parity.
*/
@@ -70,6 +79,16 @@ const ConfigurableRegistrationForm = (props) => {
}
}, [autoSubmitRegistrationForm]); // eslint-disable-line react-hooks/exhaustive-deps
const removeDisabledCountries = useCallback((countryList) => {
if (!countriesCodesList.length) {
return countryList;
}
return countryList.filter(({ code }) => countriesCodesList.find(x => x === code));
}, [countriesCodesList]);
const countryList = useMemo(() => removeDisabledCountries(
getCountryList(getLocale()).concat([{ code: 'US', name: 'United States' }])), [removeDisabledCountries]);
const handleErrorChange = (fieldName, error) => {
if (fieldName) {
setFieldErrors(prevErrors => ({
@@ -90,6 +109,25 @@ const ConfigurableRegistrationForm = (props) => {
setFieldErrors(prevErrors => ({ ...prevErrors, [name]: '' }));
}
}
// setting marketingEmailsOptIn state for SSO authentication flow for register API call
if (name === 'marketingEmailsOptIn') {
if (!value) {
const cohesionEventData = {
pageType: PAGE_TYPES.ACCOUNT_CREATION,
elementType: ELEMENT_TYPES.BUTTON,
webElementText: ELEMENT_TEXT.OPT_IN_TEXT,
webElementName: ELEMENT_NAME.OPT_OUT,
};
trackCohesionEvent(cohesionEventData);
}
dispatch(backupRegistrationFormBegin({
...backedUpFormData,
configurableFormFields: {
...backedUpFormData.configurableFormFields,
[name]: value,
},
}));
}
setFormFields(prevState => ({ ...prevState, [name]: value }));
};
@@ -231,11 +269,16 @@ ConfigurableRegistrationForm.propTypes = {
setFieldErrors: PropTypes.func.isRequired,
setFormFields: PropTypes.func.isRequired,
autoSubmitRegistrationForm: PropTypes.bool,
countriesCodesList: PropTypes.arrayOf(PropTypes.shape({
code: PropTypes.string.isRequired,
name: PropTypes.string.isRequired,
})),
};
ConfigurableRegistrationForm.defaultProps = {
fieldDescriptions: {},
autoSubmitRegistrationForm: false,
countriesCodesList: [],
};
export default ConfigurableRegistrationForm;

View File

@@ -9,7 +9,6 @@ import PropTypes from 'prop-types';
import { windowScrollTo } from '../../data/utils';
import {
FORBIDDEN_REQUEST,
FORBIDDEN_USERNAME,
INTERNAL_SERVER_ERROR,
TPA_AUTHENTICATION_FAILURE,
TPA_SESSION_EXPIRED,
@@ -49,9 +48,6 @@ const RegistrationFailureMessage = (props) => {
case TPA_SESSION_EXPIRED:
errorMessage = formatMessage(messages['registration.tpa.session.expired'], { provider: context.provider });
break;
case FORBIDDEN_USERNAME:
errorMessage = formatMessage(messages['registration.forbidden.username']);
break;
default:
errorMessage = formatMessage(messages['registration.empty.form.submission.error']);
break;

View File

@@ -1,15 +1,20 @@
import React from 'react';
import { Provider } from 'react-redux';
import { mergeConfig } from '@edx/frontend-platform';
import {
getLocale, IntlProvider,
getLocale, injectIntl, IntlProvider,
} from '@edx/frontend-platform/i18n';
import { fireEvent, render } from '@testing-library/react';
import { BrowserRouter as Router } from 'react-router-dom';
import configureStore from 'redux-mock-store';
import { APP_NAME } from '../../../data/constants';
import { registerNewUser } from '../../data/actions';
import { FIELDS } from '../../data/constants';
import { NOT_INITIALIZED } from '../../data/optimizelyExperiment/helper';
import useAutoGeneratedUsernameExperimentVariation
from '../../data/optimizelyExperiment/useAutoGeneratedUsernameExperimentVariation';
import RegistrationPage from '../../RegistrationPage';
import ConfigurableRegistrationForm from '../ConfigurableRegistrationForm';
@@ -21,7 +26,10 @@ jest.mock('@edx/frontend-platform/i18n', () => ({
...jest.requireActual('@edx/frontend-platform/i18n'),
getLocale: jest.fn(),
}));
jest.mock('../../data/optimizelyExperiment/useAutoGeneratedUsernameExperimentVariation', () => jest.fn());
const IntlConfigurableRegistrationForm = injectIntl(ConfigurableRegistrationForm);
const IntlRegistrationPage = injectIntl(RegistrationPage);
const mockStore = configureStore();
jest.mock('react-router-dom', () => {
@@ -91,6 +99,7 @@ describe('ConfigurableRegistrationForm', () => {
registrationFormData,
usernameSuggestions: [],
},
cohesion: { eventData: {} },
commonComponents: {
thirdPartyAuthApiStatus: null,
thirdPartyAuthContext,
@@ -118,6 +127,7 @@ describe('ConfigurableRegistrationForm', () => {
};
window.location = { search: '' };
getLocale.mockImplementationOnce(() => ('en-us'));
useAutoGeneratedUsernameExperimentVariation.mockReturnValue(NOT_INITIALIZED);
});
afterEach(() => {
@@ -155,7 +165,7 @@ describe('ConfigurableRegistrationForm', () => {
};
render(routerWrapper(reduxWrapper(
<ConfigurableRegistrationForm {...props} />,
<IntlConfigurableRegistrationForm {...props} />,
)));
expect(document.querySelector('#profession')).toBeTruthy();
@@ -182,10 +192,11 @@ describe('ConfigurableRegistrationForm', () => {
},
},
autoSubmitRegistrationForm: true,
countriesCodesList: [{ code: 'AX', name: 'Åland Islands' }, { code: 'AL', name: 'Albania' }],
};
render(routerWrapper(reduxWrapper(
<ConfigurableRegistrationForm {...props} />,
<IntlConfigurableRegistrationForm {...props} />,
)));
expect(props.setFormFields).toHaveBeenCalledTimes(2);
@@ -212,7 +223,7 @@ describe('ConfigurableRegistrationForm', () => {
},
},
});
render(routerWrapper(reduxWrapper(<RegistrationPage {...props} />)));
render(routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)));
expect(document.querySelector('#profession')).toBeTruthy();
expect(document.querySelector('#tos')).toBeTruthy();
});
@@ -246,7 +257,7 @@ describe('ConfigurableRegistrationForm', () => {
};
store.dispatch = jest.fn(store.dispatch);
const { getByLabelText, container } = render(routerWrapper(reduxWrapper(<RegistrationPage {...props} />)));
const { getByLabelText, container } = render(routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)));
populateRequiredFields(getByLabelText, payload);
@@ -257,7 +268,7 @@ describe('ConfigurableRegistrationForm', () => {
fireEvent.click(submitButton);
expect(store.dispatch).toHaveBeenCalledWith(registerNewUser({ ...payload, country: 'PK' }));
expect(store.dispatch).toHaveBeenCalledWith(registerNewUser({ ...payload, country: 'PK', app_name: APP_NAME }));
});
it('should show error messages for required fields on empty form submission', () => {
@@ -281,7 +292,7 @@ describe('ConfigurableRegistrationForm', () => {
},
});
const { container } = render(routerWrapper(reduxWrapper(<RegistrationPage {...props} />)));
const { container } = render(routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)));
const submitButton = container.querySelector('button.btn-brand');
fireEvent.click(submitButton);
@@ -307,7 +318,7 @@ describe('ConfigurableRegistrationForm', () => {
},
},
});
const { container } = render(routerWrapper(reduxWrapper(<RegistrationPage {...props} />)));
const { container } = render(routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)));
const countryInput = container.querySelector('input[name="country"]');
fireEvent.change(countryInput, { target: { value: 'Pak', name: 'country' } });
fireEvent.blur(countryInput, { target: { value: 'Pak', name: 'country' } });
@@ -332,7 +343,7 @@ describe('ConfigurableRegistrationForm', () => {
},
},
});
const { getByLabelText, container } = render(routerWrapper(reduxWrapper(<RegistrationPage {...props} />)));
const { getByLabelText, container } = render(routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)));
const emailInput = getByLabelText('Email');
const confirmEmailInput = getByLabelText('Confirm Email');
@@ -368,7 +379,7 @@ describe('ConfigurableRegistrationForm', () => {
},
},
});
const { getByLabelText, container } = render(routerWrapper(reduxWrapper(<RegistrationPage {...props} />)));
const { getByLabelText, container } = render(routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)));
populateRequiredFields(getByLabelText, formPayload, true);
fireEvent.change(
@@ -403,7 +414,7 @@ describe('ConfigurableRegistrationForm', () => {
});
const { getByLabelText, container } = render(
routerWrapper(reduxWrapper(<RegistrationPage {...props} />)),
routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)),
);
const professionInput = getByLabelText('Profession');

View File

@@ -1,8 +1,9 @@
import React from 'react';
import { Provider } from 'react-redux';
import { mergeConfig } from '@edx/frontend-platform';
import {
configure, getLocale, IntlProvider,
configure, getLocale, injectIntl, IntlProvider,
} from '@edx/frontend-platform/i18n';
import { render, screen } from '@testing-library/react';
import { BrowserRouter as Router } from 'react-router-dom';
@@ -11,6 +12,9 @@ import configureStore from 'redux-mock-store';
import {
FORBIDDEN_REQUEST, INTERNAL_SERVER_ERROR, TPA_AUTHENTICATION_FAILURE, TPA_SESSION_EXPIRED,
} from '../../data/constants';
import { NOT_INITIALIZED } from '../../data/optimizelyExperiment/helper';
import useAutoGeneratedUsernameExperimentVariation
from '../../data/optimizelyExperiment/useAutoGeneratedUsernameExperimentVariation';
import RegistrationPage from '../../RegistrationPage';
import RegistrationFailureMessage from '../RegistrationFailure';
@@ -22,7 +26,10 @@ jest.mock('@edx/frontend-platform/i18n', () => ({
...jest.requireActual('@edx/frontend-platform/i18n'),
getLocale: jest.fn(),
}));
jest.mock('../../data/optimizelyExperiment/useAutoGeneratedUsernameExperimentVariation', () => jest.fn());
const IntlRegistrationPage = injectIntl(RegistrationPage);
const IntlRegistrationFailure = injectIntl(RegistrationFailureMessage);
const mockStore = configureStore();
jest.mock('react-router-dom', () => {
@@ -92,6 +99,7 @@ describe('RegistrationFailure', () => {
registrationFormData,
usernameSuggestions: [],
},
cohesion: { eventData: {} },
commonComponents: {
thirdPartyAuthApiStatus: null,
thirdPartyAuthContext,
@@ -118,6 +126,7 @@ describe('RegistrationFailure', () => {
institutionLogin: false,
};
window.location = { search: '' };
useAutoGeneratedUsernameExperimentVariation.mockReturnValue(NOT_INITIALIZED);
});
afterEach(() => {
@@ -134,7 +143,7 @@ describe('RegistrationFailure', () => {
failureCount: 0,
};
const { container } = render(reduxWrapper(<RegistrationFailureMessage {...props} />));
const { container } = render(reduxWrapper(<IntlRegistrationFailure {...props} />));
const alertHeading = container.querySelectorAll('div.alert-heading');
expect(alertHeading.length).toEqual(1);
@@ -150,7 +159,7 @@ describe('RegistrationFailure', () => {
failureCount: 0,
};
const { container } = render(reduxWrapper(<RegistrationFailureMessage {...props} />));
const { container } = render(reduxWrapper(<IntlRegistrationFailure {...props} />));
const alertHeading = container.querySelectorAll('div.alert-heading');
expect(alertHeading.length).toEqual(1);
@@ -169,7 +178,7 @@ describe('RegistrationFailure', () => {
failureCount: 0,
};
const { container } = render(reduxWrapper(<RegistrationFailureMessage {...props} />));
const { container } = render(reduxWrapper(<IntlRegistrationFailure {...props} />));
const alertHeading = container.querySelectorAll('div.alert-heading');
expect(alertHeading.length).toEqual(1);
@@ -188,7 +197,7 @@ describe('RegistrationFailure', () => {
failureCount: 0,
};
const { container } = render(reduxWrapper(<RegistrationFailureMessage {...props} />));
const { container } = render(reduxWrapper(<IntlRegistrationFailure {...props} />));
const alertHeading = container.querySelectorAll('div.alert-heading');
expect(alertHeading.length).toEqual(1);
@@ -208,7 +217,7 @@ describe('RegistrationFailure', () => {
},
});
render(routerWrapper(reduxWrapper(<RegistrationPage {...props} />)));
render(routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)));
const validationError = screen.queryByText('An error has occurred. Try refreshing the page, or check your internet connection.');
expect(validationError).not.toBeNull();

View File

@@ -1,16 +1,21 @@
import React from 'react';
import { Provider } from 'react-redux';
import { getConfig, mergeConfig } from '@edx/frontend-platform';
import {
configure, getLocale, IntlProvider,
configure, getLocale, injectIntl, IntlProvider,
} from '@edx/frontend-platform/i18n';
import { fireEvent, render } from '@testing-library/react';
import { fireEvent, render, waitFor } from '@testing-library/react';
import { BrowserRouter as Router } from 'react-router-dom';
import configureStore from 'redux-mock-store';
import mockTagular from '../../../cohesion/utils';
import {
COMPLETE_STATE, LOGIN_PAGE, PENDING_STATE, REGISTER_PAGE,
} from '../../../data/constants';
import { NOT_INITIALIZED } from '../../data/optimizelyExperiment/helper';
import useAutoGeneratedUsernameExperimentVariation
from '../../data/optimizelyExperiment/useAutoGeneratedUsernameExperimentVariation';
import RegistrationPage from '../../RegistrationPage';
jest.mock('@edx/frontend-platform/analytics', () => ({
@@ -21,7 +26,10 @@ jest.mock('@edx/frontend-platform/i18n', () => ({
...jest.requireActual('@edx/frontend-platform/i18n'),
getLocale: jest.fn(),
}));
jest.mock('../../data/optimizelyExperiment/useAutoGeneratedUsernameExperimentVariation', () => jest.fn());
mockTagular();
const IntlRegistrationPage = injectIntl(RegistrationPage);
const mockStore = configureStore();
jest.mock('react-router-dom', () => {
@@ -92,6 +100,7 @@ describe('ThirdPartyAuth', () => {
registrationFormData,
usernameSuggestions: [],
},
cohesion: { eventData: {} },
commonComponents: {
thirdPartyAuthApiStatus: null,
thirdPartyAuthContext,
@@ -118,6 +127,7 @@ describe('ThirdPartyAuth', () => {
institutionLogin: false,
};
window.location = { search: '' };
useAutoGeneratedUsernameExperimentVariation.mockReturnValue(NOT_INITIALIZED);
});
afterEach(() => {
@@ -155,7 +165,7 @@ describe('ThirdPartyAuth', () => {
});
const { queryByLabelText } = render(
routerWrapper(reduxWrapper(<RegistrationPage {...props} />, { store })),
routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />, { store })),
);
const passwordField = queryByLabelText('Password');
@@ -180,7 +190,7 @@ describe('ThirdPartyAuth', () => {
window.location = { href: getConfig().BASE_URL.concat(LOGIN_PAGE), search: `?next=/dashboard&tpa_hint=${ssoProvider.id}` };
const { container } = render(
routerWrapper(reduxWrapper(<RegistrationPage {...props} />)),
routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)),
);
const tpaButton = container.querySelector(`button#${ssoProvider.id}`);
@@ -205,7 +215,7 @@ describe('ThirdPartyAuth', () => {
search: `?next=/dashboard&tpa_hint=${ssoProvider.id}`,
};
const { container } = render(routerWrapper(reduxWrapper(<RegistrationPage {...props} />)));
const { container } = render(routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)));
const skeletonElement = container.querySelector('.react-loading-skeleton');
expect(skeletonElement).toBeTruthy();
@@ -229,7 +239,7 @@ describe('ThirdPartyAuth', () => {
window.location = { href: getConfig().BASE_URL.concat(REGISTER_PAGE), search: `?next=/dashboard&tpa_hint=${ssoProvider.id}` };
ssoProvider.iconImage = null;
const { container } = render(routerWrapper(reduxWrapper(<RegistrationPage {...props} />)));
const { container } = render(routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)));
const iconElement = container.querySelector(`button#${ssoProvider.id} div span.pgn__icon`);
expect(iconElement).toBeTruthy();
@@ -252,7 +262,7 @@ describe('ThirdPartyAuth', () => {
delete window.location;
window.location = { href: getConfig().BASE_URL.concat(REGISTER_PAGE), search: `?next=/dashboard&tpa_hint=${secondaryProviders.id}` };
render(routerWrapper(reduxWrapper(<RegistrationPage {...props} />)));
render(routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)));
expect(window.location.href).toEqual(getConfig().LMS_BASE_URL + secondaryProviders.registerUrl);
});
@@ -273,7 +283,7 @@ describe('ThirdPartyAuth', () => {
delete window.location;
window.location = { href: getConfig().BASE_URL.concat(LOGIN_PAGE), search: '?next=/dashboard&tpa_hint=invalid' };
const { container } = render(routerWrapper(reduxWrapper(<RegistrationPage {...props} />)));
const { container } = render(routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)));
const providerButton = container.querySelector(`button#${ssoProvider.id} span#provider-name`);
expect(providerButton.textContent).toEqual(expectedMessage);
@@ -292,7 +302,7 @@ describe('ThirdPartyAuth', () => {
});
const { container } = render(
routerWrapper(reduxWrapper(<RegistrationPage {...props} />, { store })),
routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />, { store })),
);
const buttonsWithId = container.querySelectorAll(`button#${ssoProvider.id}`);
@@ -313,7 +323,7 @@ describe('ThirdPartyAuth', () => {
});
const { container } = render(
routerWrapper(reduxWrapper(<RegistrationPage {...props} />)),
routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)),
);
const buttonsWithId = container.querySelectorAll(`button#${ssoProvider.id}`);
@@ -327,12 +337,12 @@ describe('ThirdPartyAuth', () => {
institutionLogin: true,
};
const { getByText } = render(routerWrapper(reduxWrapper(<RegistrationPage {...props} />)));
const { getByText } = render(routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)));
const headingElement = getByText('Register with institution/campus credentials');
expect(headingElement).toBeTruthy();
});
it('should redirect to social auth provider url on SSO button click', () => {
it('should redirect to social auth provider url on SSO button click', async () => {
const registerUrl = '/auth/login/apple-id/?auth_entry=register&next=/dashboard';
store = mockStore({
...initialState,
@@ -352,16 +362,18 @@ describe('ThirdPartyAuth', () => {
window.location = { href: getConfig().BASE_URL };
const { container } = render(
routerWrapper(reduxWrapper(<RegistrationPage {...props} />)),
routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)),
);
const ssoButton = container.querySelector('button#oa2-apple-id');
fireEvent.click(ssoButton);
expect(window.location.href).toBe(getConfig().LMS_BASE_URL + registerUrl);
await waitFor(() => {
expect(window.location.href).toBe(getConfig().LMS_BASE_URL + registerUrl);
}, { timeout: 1100 });
});
it('should redirect to finishAuthUrl upon successful registration via SSO', () => {
it('should redirect to finishAuthUrl upon successful registration via SSO', async () => {
const authCompleteUrl = '/auth/complete/google-oauth2/';
store = mockStore({
...initialState,
@@ -383,8 +395,10 @@ describe('ThirdPartyAuth', () => {
delete window.location;
window.location = { href: getConfig().BASE_URL };
render(routerWrapper(reduxWrapper(<RegistrationPage {...props} />)));
expect(window.location.href).toBe(getConfig().LMS_BASE_URL + authCompleteUrl);
render(routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)));
await waitFor(() => {
expect(window.location.href).toBe(getConfig().LMS_BASE_URL + authCompleteUrl);
}, { timeout: 1100 });
});
// ******** test alert messages ********
@@ -404,7 +418,7 @@ describe('ThirdPartyAuth', () => {
const expectedMessage = `${'You\'ve successfully signed into Apple! We just need a little more information before '
+ 'you start learning with '}${ getConfig().SITE_NAME }.`;
const { container } = render(routerWrapper(reduxWrapper(<RegistrationPage {...props} />)));
const { container } = render(routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)));
const tpaAlert = container.querySelector('#tpa-alert p');
expect(tpaAlert.textContent).toEqual(expectedMessage);
});
@@ -435,7 +449,7 @@ describe('ThirdPartyAuth', () => {
store.dispatch = jest.fn(store.dispatch);
const { container } = render(
routerWrapper(reduxWrapper(<RegistrationPage {...props} />)),
routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)),
);
const alertHeading = container.querySelector('div.alert-heading');

View File

@@ -8,7 +8,7 @@ export const REGISTRATION_CLEAR_BACKEND_ERROR = 'REGISTRATION_CLEAR_BACKEND_ERRO
export const REGISTER_SET_COUNTRY_CODE = 'REGISTER_SET_COUNTRY_CODE';
export const REGISTER_SET_USER_PIPELINE_DATA_LOADED = 'REGISTER_SET_USER_PIPELINE_DATA_LOADED';
export const REGISTER_SET_EMAIL_SUGGESTIONS = 'REGISTER_SET_EMAIL_SUGGESTIONS';
export const REGISTER_SET_AUTO_GENERATED_USERNAME_REGISTRATION_EXP_DATA = 'REGISTER_SET_AUTO_GENERATED_USERNAME_REGISTRATION_EXP_DATA';
// Backup registration form
export const backupRegistrationForm = () => ({
type: BACKUP_REGISTRATION_DATA.BASE,
@@ -83,3 +83,9 @@ export const setUserPipelineDataLoaded = (value) => ({
type: REGISTER_SET_USER_PIPELINE_DATA_LOADED,
payload: { value },
});
// Auto Generated Username Registration Experiment Actions
export const setAutoGeneratedUsernameExperimentData = (autoGeneratedRegExpVariation) => ({
type: REGISTER_SET_AUTO_GENERATED_USERNAME_REGISTRATION_EXP_DATA,
payload: { autoGeneratedRegExpVariation },
});

View File

@@ -11,4 +11,3 @@ export const FORM_SUBMISSION_ERROR = 'form-submission-error';
export const INTERNAL_SERVER_ERROR = 'internal-server-error';
export const TPA_AUTHENTICATION_FAILURE = 'tpa-authentication-failure';
export const TPA_SESSION_EXPIRED = 'tpa-session-expired';
export const FORBIDDEN_USERNAME = 'forbidden-username';

View File

@@ -0,0 +1,30 @@
/**
* This file contains data for auto generated username Optimizely experiment
*/
import { getConfig } from '@edx/frontend-platform';
export const NOT_INITIALIZED = 'experiment-not-initialized';
export const CONTROL = 'control-registration-page';
export const AUTO_GENERATED_USERNAME_REGISTRATION_EXP_VARIATION = 'auto-generated-username-register-page';
const AUTO_GENERATED_USERNAME_EXP_PAGE = 'targeting_for_auto_generated_username_page';
export function getAutoGeneratedUsernameExperimentVariation() {
try {
if (window.optimizely
&& window.optimizely.get('data').experiments[getConfig().AUTO_GENERATED_USERNAME_EXPERIMENT_ID]) {
const selectedVariant = window.optimizely.get('state').getVariationMap()[
getConfig().AUTO_GENERATED_USERNAME_EXPERIMENT_ID
];
return selectedVariant?.name;
}
} catch (e) { /* empty */ }
return '';
}
export function activateAutoGeneratedUsernameExperiment() {
window.optimizely = window.optimizely || [];
window.optimizely.push({
type: 'page',
pageName: AUTO_GENERATED_USERNAME_EXP_PAGE,
});
}

View File

@@ -0,0 +1,53 @@
import { useEffect, useState } from 'react';
import {
activateAutoGeneratedUsernameExperiment,
getAutoGeneratedUsernameExperimentVariation,
NOT_INITIALIZED,
} from './helper';
import { COMPLETE_STATE } from '../../../data/constants';
/**
* This hook returns activates multi step registration experiment and returns the experiment
* variation for the user.
*/
const useAutoGeneratedUsernameExperimentVariation = (
initExpVariation,
registrationEmbedded,
tpaHint,
currentProvider,
thirdPartyAuthApiStatus,
) => {
const [variation, setVariation] = useState(initExpVariation);
useEffect(() => {
if (initExpVariation || registrationEmbedded || !!tpaHint || !!currentProvider
|| thirdPartyAuthApiStatus !== COMPLETE_STATE) {
return variation;
}
const getVariation = () => {
const expVariation = getAutoGeneratedUsernameExperimentVariation();
if (expVariation) {
setVariation(expVariation);
} else {
// This is to handle the case when user dont get variation for some reason, the register page
// shows unlimited spinner.
setVariation(NOT_INITIALIZED);
}
};
activateAutoGeneratedUsernameExperiment();
const timer = setTimeout(getVariation, 300);
return () => {
clearTimeout(timer);
};
}, [ // eslint-disable-line react-hooks/exhaustive-deps
initExpVariation, currentProvider, registrationEmbedded, thirdPartyAuthApiStatus, tpaHint,
]);
return variation;
};
export default useAutoGeneratedUsernameExperimentVariation;

View File

@@ -3,6 +3,7 @@ import {
REGISTER_CLEAR_USERNAME_SUGGESTIONS,
REGISTER_FORM_VALIDATIONS,
REGISTER_NEW_USER,
REGISTER_SET_AUTO_GENERATED_USERNAME_REGISTRATION_EXP_DATA,
REGISTER_SET_COUNTRY_CODE,
REGISTER_SET_EMAIL_SUGGESTIONS,
REGISTER_SET_USER_PIPELINE_DATA_LOADED,
@@ -39,6 +40,7 @@ export const defaultState = {
usernameSuggestions: [],
validationApiRateLimited: false,
shouldBackupState: false,
autoGeneratedUsernameExperimentVariation: '',
};
const reducer = (state = defaultState, action = {}) => {
@@ -55,6 +57,12 @@ const reducer = (state = defaultState, action = {}) => {
registrationFormData: { ...action.payload },
userPipelineDataLoaded: state.userPipelineDataLoaded,
};
case REGISTER_SET_AUTO_GENERATED_USERNAME_REGISTRATION_EXP_DATA: {
return {
...state,
autoGeneratedUsernameExperimentVariation: action.payload.autoGeneratedRegExpVariation,
};
}
case REGISTER_NEW_USER.BEGIN:
return {
...state,

View File

@@ -1,14 +1,11 @@
import { camelCaseObject } from '@edx/frontend-platform';
import { logError, logInfo } from '@edx/frontend-platform/logging';
import {
call, put, race, take, takeEvery,
} from 'redux-saga/effects';
import { call, put, takeEvery } from 'redux-saga/effects';
import {
fetchRealtimeValidationsBegin,
fetchRealtimeValidationsFailure,
fetchRealtimeValidationsSuccess,
REGISTER_CLEAR_USERNAME_SUGGESTIONS,
REGISTER_FORM_VALIDATIONS,
REGISTER_NEW_USER,
registerNewUserBegin,
@@ -44,15 +41,9 @@ export function* handleNewUserRegistration(action) {
export function* fetchRealtimeValidations(action) {
try {
yield put(fetchRealtimeValidationsBegin());
const { fieldValidations } = yield call(getFieldsValidations, action.payload.formPayload);
const { response } = yield race({
response: call(getFieldsValidations, action.payload.formPayload),
cancel: take(REGISTER_CLEAR_USERNAME_SUGGESTIONS),
});
if (response) {
yield put(fetchRealtimeValidationsSuccess(camelCaseObject(response.fieldValidations)));
}
yield put(fetchRealtimeValidationsSuccess(camelCaseObject(fieldValidations)));
} catch (e) {
if (e.response && e.response.status === 403) {
yield put(fetchRealtimeValidationsFailure());

View File

@@ -38,6 +38,7 @@ describe('Registration Reducer Tests', () => {
usernameSuggestions: [],
validationApiRateLimited: false,
shouldBackupState: false,
autoGeneratedUsernameExperimentVariation: '',
};
it('should return the initial state', () => {

View File

@@ -43,39 +43,31 @@ export const isFormValid = (
Object.keys(payload).forEach(key => {
switch (key) {
case 'name':
if (!fieldErrors.name) {
fieldErrors.name = validateName(payload.name, formatMessage);
}
fieldErrors.name = validateName(payload.name, formatMessage);
if (fieldErrors.name) { isValid = false; }
break;
case 'email': {
if (!fieldErrors.email) {
const {
fieldError, confirmEmailError, suggestion,
} = validateEmail(payload.email, configurableFormFields?.confirm_email, formatMessage);
if (fieldError) {
fieldErrors.email = fieldError;
isValid = false;
}
if (confirmEmailError) {
fieldErrors.confirm_email = confirmEmailError;
isValid = false;
}
emailSuggestion = suggestion;
const {
fieldError, confirmEmailError, suggestion,
} = validateEmail(payload.email, configurableFormFields?.confirm_email, formatMessage);
if (fieldError) {
fieldErrors.email = fieldError;
isValid = false;
}
if (confirmEmailError) {
fieldErrors.confirm_email = confirmEmailError;
isValid = false;
}
emailSuggestion = suggestion;
if (fieldErrors.email) { isValid = false; }
break;
}
case 'username':
if (!fieldErrors.username) {
fieldErrors.username = validateUsername(payload.username, formatMessage);
}
fieldErrors.username = validateUsername(payload.username, formatMessage);
if (fieldErrors.username) { isValid = false; }
break;
case 'password':
if (!fieldErrors.password) {
fieldErrors.password = validatePasswordField(payload.password, formatMessage);
}
fieldErrors.password = validatePasswordField(payload.password, formatMessage);
if (fieldErrors.password) { isValid = false; }
break;
default:

View File

@@ -162,11 +162,6 @@ const messages = defineMessages({
defaultMessage: 'Registration using {provider} has timed out.',
description: '',
},
'registration.forbidden.username': {
id: 'registration.forbidden.username',
defaultMessage: 'Usernames can\'t include words that could be mistaken for course roles. Please choose a different username.',
description: '',
},
'registration.tpa.authentication.failure': {
id: 'registration.tpa.authentication.failure',
defaultMessage: 'We are sorry, you are not authorized to access {platform_name} via this channel. '

View File

@@ -18,7 +18,7 @@ import { useNavigate, useParams } from 'react-router-dom';
import { resetPassword, validateToken } from './data/actions';
import {
FORM_SUBMISSION_ERROR, PASSWORD_RESET_ERROR, PASSWORD_VALIDATION_ERROR, TOKEN_STATE,
FORM_SUBMISSION_ERROR, PASSWORD_RESET_ERROR, PASSWORD_VALIDATION_ERROR, SUCCESS, TOKEN_STATE,
} from './data/constants';
import { resetPasswordResultSelector } from './data/selectors';
import { validatePassword } from './data/service';
@@ -30,6 +30,7 @@ import {
LETTER_REGEX, LOGIN_PAGE, NUMBER_REGEX, RESET_PAGE,
} from '../data/constants';
import { getAllPossibleQueryParams, updatePathWithQueryParams, windowScrollTo } from '../data/utils';
import { trackPasswordResetSuccess, trackResetPasswordPageViewed } from '../tracking/trackers/reset-password';
const ResetPasswordPage = (props) => {
const { formatMessage } = useIntl();
@@ -42,6 +43,15 @@ const ResetPasswordPage = (props) => {
const { token } = useParams();
const navigate = useNavigate();
useEffect(() => {
if (props.status === TOKEN_STATE.VALID) {
trackResetPasswordPageViewed();
}
if (props.status === SUCCESS) {
trackPasswordResetSuccess();
}
}, [props.status]);
useEffect(() => {
if (props.status !== TOKEN_STATE.PENDING && props.status !== PASSWORD_RESET_ERROR) {
setErrorCode(props.status);
@@ -139,7 +149,7 @@ const ResetPasswordPage = (props) => {
}
} else if (props.status === PASSWORD_RESET_ERROR) {
navigate(updatePathWithQueryParams(RESET_PAGE));
} else if (props.status === 'success') {
} else if (props.status === SUCCESS) {
navigate(updatePathWithQueryParams(LOGIN_PAGE));
} else {
return (

View File

@@ -1,6 +1,7 @@
import React from 'react';
import { Provider } from 'react-redux';
import { configure, IntlProvider } from '@edx/frontend-platform/i18n';
import { configure, injectIntl, IntlProvider } from '@edx/frontend-platform/i18n';
import {
fireEvent, render, screen,
} from '@testing-library/react';
@@ -18,6 +19,11 @@ import ResetPasswordPage from '../ResetPasswordPage';
const mockedNavigator = jest.fn();
const token = '1c-bmjdkc-5e60e084cf8113048ca7';
jest.mock('@edx/frontend-platform/analytics', () => ({
sendPageEvent: jest.fn(),
sendTrackEvent: jest.fn(),
}));
jest.mock('@edx/frontend-platform/auth');
jest.mock('react-router-dom', () => ({
...(jest.requireActual('react-router-dom')),
@@ -25,6 +31,7 @@ jest.mock('react-router-dom', () => ({
useParams: jest.fn().mockReturnValue({ token }),
}));
const IntlResetPasswordPage = injectIntl(ResetPasswordPage);
const mockStore = configureStore();
describe('ResetPasswordPage', () => {
@@ -93,7 +100,7 @@ describe('ResetPasswordPage', () => {
}));
store.dispatch = jest.fn(store.dispatch);
render(reduxWrapper(<ResetPasswordPage {...props} />));
render(reduxWrapper(<IntlResetPasswordPage {...props} />));
const newPasswordInput = screen.getByLabelText('New password');
const confirmPasswordInput = screen.getByLabelText('Confirm password');
@@ -118,7 +125,7 @@ describe('ResetPasswordPage', () => {
status: TOKEN_STATE.VALID,
},
});
render(reduxWrapper(<ResetPasswordPage {...props} />));
render(reduxWrapper(<IntlResetPasswordPage {...props} />));
const resetPasswordButton = screen.getByRole('button', { name: /Reset password/i, id: 'submit-new-password' });
fireEvent.click(resetPasswordButton);
@@ -142,7 +149,7 @@ describe('ResetPasswordPage', () => {
status: TOKEN_STATE.VALID,
},
});
render(reduxWrapper(<ResetPasswordPage {...props} />));
render(reduxWrapper(<IntlResetPasswordPage {...props} />));
const confirmPasswordInput = screen.getByLabelText('Confirm password');
fireEvent.change(confirmPasswordInput, { target: { value: 'password-mismatch' } });
@@ -161,7 +168,7 @@ describe('ResetPasswordPage', () => {
},
});
const { container } = render(reduxWrapper(<ResetPasswordPage {...props} />));
const { container } = render(reduxWrapper(<IntlResetPasswordPage {...props} />));
const alertElements = container.querySelectorAll('.alert-danger');
const rateLimitError = alertElements[0].textContent;
@@ -177,7 +184,7 @@ describe('ResetPasswordPage', () => {
},
});
const { container } = render(reduxWrapper(<ResetPasswordPage {...props} />));
const { container } = render(reduxWrapper(<IntlResetPasswordPage {...props} />));
const alertElements = container.querySelectorAll('.alert-danger');
const internalServerError = alertElements[0].textContent;
expect(internalServerError).toBe(validationMessage);
@@ -186,7 +193,7 @@ describe('ResetPasswordPage', () => {
// ******** miscellaneous tests ********
it('should call validation on password field when blur event fires', () => {
const resetPasswordPage = render(reduxWrapper(<ResetPasswordPage {...props} />));
const resetPasswordPage = render(reduxWrapper(<IntlResetPasswordPage {...props} />));
const expectedText = 'Password criteria has not been metPassword must contain at least 8 characters, at least one letter, and at least one number';
const newPasswordInput = resetPasswordPage.container.querySelector('input#newPassword');
newPasswordInput.value = 'test-password';
@@ -205,7 +212,7 @@ describe('ResetPasswordPage', () => {
TOKEN_STATE.PENDING,
};
render(reduxWrapper(<ResetPasswordPage {...props} />));
render(reduxWrapper(<IntlResetPasswordPage {...props} />));
expect(store.dispatch).toHaveBeenCalledWith(validateToken(token));
});
@@ -214,19 +221,19 @@ describe('ResetPasswordPage', () => {
status:
PASSWORD_RESET_ERROR,
};
render(reduxWrapper(<ResetPasswordPage {...props} />));
render(reduxWrapper(<IntlResetPasswordPage {...props} />));
expect(mockedNavigator).toHaveBeenCalledWith(RESET_PAGE);
});
it('should redirect the user to root url of the application ', async () => {
props = {
status: SUCCESS,
};
render(reduxWrapper(<ResetPasswordPage {...props} />));
render(reduxWrapper(<IntlResetPasswordPage {...props} />));
expect(mockedNavigator).toHaveBeenCalledWith(LOGIN_PAGE);
});
it('shows spinner during token validation', () => {
render(reduxWrapper(<ResetPasswordPage {...props} />));
render(reduxWrapper(<IntlResetPasswordPage {...props} />));
const spinnerElement = document.getElementsByClassName('div.spinner-header');
expect(spinnerElement).toBeTruthy();
@@ -235,7 +242,7 @@ describe('ResetPasswordPage', () => {
// ******** redirection tests ********
it('by clicking on sign in tab should redirect onto login page', async () => {
const { getByText } = render(reduxWrapper(<ResetPasswordPage {...props} />));
const { getByText } = render(reduxWrapper(<IntlResetPasswordPage {...props} />));
const signInTab = getByText('Sign in');

View File

@@ -65,15 +65,10 @@
margin-right: 0.25rem;
}
.username__form-group-wrapper {
position: relative;
}
.username-suggestions {
position: absolute;
inset: 0;
padding-left: 15px;
z-index: 100;
position: relative;
margin-top: -2.5rem;
margin-left: 15px;
}
.username-suggestions__close__button {
@@ -81,6 +76,13 @@
position: absolute;
}
.username-suggestions__error {
position: relative;
margin-top: -13.7%;
margin-bottom: 11%;
margin-left: 15px;
}
.username-scroll-suggested--form-field {
width: 20rem;
white-space: nowrap;

View File

@@ -0,0 +1,22 @@
import { createEventTracker, createPageEventTracker } from '../../data/segment/utils';
export const eventNames = {
loginAndRegistration: 'login_and_registration',
forgotPasswordPageViewed: 'edx.bi.password_reset_form.viewed',
};
export const categories = {
userEngagement: 'user-engagement',
};
// Event tracker for forgot password page viewed
export const trackForgotPasswordPageViewed = () => createEventTracker(
eventNames.forgotPasswordPageViewed,
{
category: categories.userEngagement,
},
)();
export const trackForgotPasswordPageEvent = () => {
createPageEventTracker(eventNames.loginAndRegistration, 'forgot-password')();
};

View File

@@ -0,0 +1,29 @@
import { createEventTracker, createPageEventTracker } from '../../data/segment/utils';
export const eventNames = {
forgotPasswordLinkClicked: 'edx.bi.password-reset_form.toggled',
loginAndRegistration: 'login_and_registration',
registerFormToggled: 'edx.bi.register_form.toggled',
loginSuccess: 'edx.bi.user.account.authenticated.client',
};
export const categories = {
userEngagement: 'user-engagement',
};
// Event tracker for Forgot Password link click
export const trackForgotPasswordLinkClick = () => createEventTracker(
eventNames.forgotPasswordLinkClicked,
{ category: categories.userEngagement },
)();
// Tracks the login page event.
export const trackLoginPageViewed = () => {
createPageEventTracker(eventNames.loginAndRegistration, 'login')();
};
// Tracks the login sucess event.
export const trackLoginSuccess = () => createEventTracker(
eventNames.loginSuccess,
{},
)();

View File

@@ -0,0 +1,37 @@
import { createEventTracker, createPageEventTracker } from '../../data/segment/utils';
export const eventNames = {
progressiveProfilingSubmitClick: 'edx.bi.welcome.page.submit.clicked',
progressiveProfilingSkipLinkClick: 'edx.bi.welcome.page.skip.link.clicked',
disablePostRegistrationRecommendations: 'edx.bi.user.recommendations.not.enabled',
progressiveProfilingSupportLinkCLick: 'edx.bi.welcome.page.support.link.clicked',
loginAndRegistration: 'login_and_registration',
};
// Event link tracker for Progressive profiling skip button click
export const trackProgressiveProfilingSkipLinkClick = evenProperties => createEventTracker(
eventNames.progressiveProfilingSkipLinkClick, { ...evenProperties },
)();
// Event tracker for progressive profiling submit button click
export const trackProgressiveProfilingSubmitClick = (evenProperties) => createEventTracker(
eventNames.progressiveProfilingSubmitClick,
{ ...evenProperties },
)();
// Event tracker for progressive profiling submit button click
export const trackDisablePostRegistrationRecommendations = (evenProperties) => createEventTracker(
eventNames.disablePostRegistrationRecommendations,
{ ...evenProperties },
)();
// Tracks the progressive profiling page event.
export const trackProgressiveProfilingPageViewed = () => {
createPageEventTracker(eventNames.loginAndRegistration, 'welcome')();
};
// Tracks the progressive profiling spport link click.
export const trackProgressiveProfilingSupportLinkCLick = () => createEventTracker(
eventNames.progressiveProfilingSupportLinkCLick,
{},
)();

View File

@@ -0,0 +1,22 @@
import { createEventTracker, createPageEventTracker } from '../../data/segment/utils';
export const eventNames = {
loginAndRegistration: 'login_and_registration',
registrationSuccess: 'edx.bi.user.account.registered.client',
loginFormToggled: 'edx.bi.login_form.toggled',
};
export const categories = {
userEngagement: 'user-engagement',
};
// Event tracker for successful registration
export const trackRegistrationSuccess = () => createEventTracker(
eventNames.registrationSuccess,
{},
)();
// Tracks the progressive profiling page event.
export const trackRegistrationPageViewed = () => {
createPageEventTracker(eventNames.loginAndRegistration, 'register')();
};

View File

@@ -0,0 +1,14 @@
import { createEventTracker, createPageEventTracker } from '../../data/segment/utils';
export const eventNames = {
loginAndRegistration: 'login_and_registration',
resetPasswordSuccess: 'edx.bi.user.password.reset.success',
};
export const trackResetPasswordPageViewed = () => {
createPageEventTracker(eventNames.loginAndRegistration, 'reset-password')();
};
export const trackPasswordResetSuccess = () => {
createEventTracker(eventNames.resetPasswordSuccess, {})();
};

Some files were not shown because too many files have changed in this diff Show More