diff --git a/.eslintignore b/.eslintignore deleted file mode 100644 index 0db94630..00000000 --- a/.eslintignore +++ /dev/null @@ -1,5 +0,0 @@ -coverage/* -dist/ -node_modules/ -__mocks__/ -__snapshots__/ diff --git a/.eslintrc.js b/.eslintrc.js deleted file mode 100644 index b8f9a534..00000000 --- a/.eslintrc.js +++ /dev/null @@ -1,26 +0,0 @@ -const path = require('path'); -const { merge } = require('webpack-merge'); - -const config = require('./tools/eslint/.eslintrc.js'); - -module.exports = merge(config, { - ignorePatterns: [ - 'test-project', - 'docs', - '.eslintrc.js', - 'frontend-base.d.ts', - 'coverage', - 'tools', - 'config', - 'dist', - ], - parserOptions: { - project: path.resolve(__dirname, './tsconfig.json'), - }, - rules: { - 'no-console': 'off', - 'import/no-dynamic-require': 'off', - 'global-require': 'off', - 'no-template-curly-in-string': 'off', - }, -}); diff --git a/.gitignore b/.gitignore index 44c2a7b3..d043b493 100644 --- a/.gitignore +++ b/.gitignore @@ -4,7 +4,7 @@ .vscode coverage dist -config +/config scss node_modules npm-debug.log diff --git a/.npmignore b/.npmignore index 2ed768b0..64c5908d 100644 --- a/.npmignore +++ b/.npmignore @@ -1,6 +1,5 @@ __mocks__ -.eslintignore -./.eslintrc.js +./eslint.config.js .github .gitignore *.test.js diff --git a/README.md b/README.md index b1fe0e8a..9791275a 100644 --- a/README.md +++ b/README.md @@ -132,22 +132,39 @@ Then move the files out of the way (move src to some other sub-dir, mostly) to m - Cease using `AUTHN_MINIMAL_HEADER`, replace it with an actual minimal header. - No more using `process.env` in runtime code. -- `SUPPORT_URL` is now optional and the support link in the header is hidden if it's not present. - Removed dotenv. Use site.config.tsx. - Removed Purge CSS. We do not believe that Purge CSS works properly with Paragon in general, and it is also fundamentally incompatible with module federation as an architecture. - Removed `ensureConfig` function. This sort of type safety should happen with TypeScript types in the site config file. - Removed `ensureDefinedConfig` function. Similar to ensureConfig, this sort of type safety should be handled by TypeScript. - A number of site config variables now have sensible defaults: - - ACCESS_TOKEN_COOKIE_NAME: 'edx-jwt-cookie-header-payload', - - CSRF_TOKEN_API_PATH: '/csrf/api/v1/token', - - LANGUAGE_PREFERENCE_COOKIE_NAME: 'openedx-language-preference', - - USER_INFO_COOKIE_NAME: 'edx-user-info', - - PUBLIC_PATH: '/', - - ENVIRONMENT: 'production', + - accessTokenCookieName: 'edx-jwt-cookie-header-payload', + - csrfTokenApiPath: '/csrf/api/v1/token', + - languagePreferenceCookieName: 'openedx-language-preference', + - userInfoCookieName: 'edx-user-info', + - publicPath: '/', + - environment: 'production', - the `basename` and `history` exports have been replaced by function getters: `getBasename` and `getHistory`. This is because it may not be possible to determine the values of the original constants at code initialization time, since our config may arrive asynchronously. This ensures that anyone trying to get these values gets a current value. - When using MockAuthService, set the authenticated user by calling setAuthenticatedUser after instantiating the service. It's not okay for us to add arbitrary config values to the site config. -- `REFRESH_ACCESS_TOKEN_ENDPOINT` has been replaced with `REFRESH_ACCESS_TOKEN_API_PATH`. It is now a path that defaults to '/login_refresh'. The Auth service assumes it is an endpoint on the LMS, and joins the path with `LMS_BASE_URL`. This change creates more parity with other paths such as `CSRF_TOKEN_API_PATH`. -- `ENABLE_ACCESSIBILITY_PAGE` has been renamed `ACCESSIBILITY_URL` and is now the URL to an accessibility page. +- `REFRESH_ACCESS_TOKEN_ENDPOINT` has been replaced with `refreshAccessTokenApiPath`. It is now a path that defaults to '/login_refresh'. The Auth service assumes it is an endpoint on the LMS, and joins the path with `lmsBaseUrl`. This change creates more parity with other paths such as `csrfTokenApiPath`. + +The following config variables have been removed, in favor of defining roles for specific modules, `externalRoutes`, or app-specific custom config as necessary: + +- ACCOUNT_PROFILE_URL +- ACCOUNT_SETTINGS_URL +- LEARNING_BASE_URL +- ORDER_HISTORY_URL +- MARKETING_SITE_BASE_URL +- LEARNER_DASHBOARD_URL +- STUDIO_BASE_URL +- ACCESSIBILITY_URL +- PRIVACY_POLICY_URL +- TERMS_OF_SERVICE_URL +- SUPPORT_URL +- SUPPORT_EMAIL +- ECOMMERCE_BASE_URL +- DISCOVERY_API_BASE_URL +- CREDENTIALS_BASE_URL +- PUBLISHER_BASE_URL # Working with Tutor diff --git a/docs/decisions/0006-middleware-support-for-http-clients.rst b/docs/decisions/0006-middleware-support-for-http-clients.rst index f064c627..c162446f 100644 --- a/docs/decisions/0006-middleware-support-for-http-clients.rst +++ b/docs/decisions/0006-middleware-support-for-http-clients.rst @@ -31,9 +31,9 @@ Consumers will install the middleware they want to use and provide it to ``initi authMiddleware: [axiosCaseConverter, (client) => axiosRetry(client, { retries: 3 })], }); -If a consumer chooses not to use ``initialize`` and instead the ``configure`` function, the middleware can be passed in the options param:: +If a consumer chooses not to use ``initialize`` and instead the ``configureAuth`` function, the middleware can be passed in the options param:: - configure({ + configureAuth({ loggingService: getLoggingService(), config: getConfig(), options: { diff --git a/docs/decisions/0007-javascript-file-configuration.rst b/docs/decisions/0007-javascript-file-configuration.rst index 328eea0a..600a6f2b 100644 --- a/docs/decisions/0007-javascript-file-configuration.rst +++ b/docs/decisions/0007-javascript-file-configuration.rst @@ -17,11 +17,11 @@ The implementation of this uses templatization and string interpolation to replace any instance of ``process.env.XXXX`` with the value of the environment variable named ``XXXX``. As an example, in our source code we may write:: - const LMS_BASE_URL = process.env.LMS_BASE_URL; + const lmsBaseUrl = process.env.lmsBaseUrl; After the build process runs, the compiled source code will instead read:: - const LMS_BASE_URL = 'http://localhost:18000'; + const lmsBaseUrl = 'http://localhost:18000'; Put another way, `process.env` is not actually an object available at runtime, it's a templatization token that helps the build replace it with a string @@ -76,7 +76,7 @@ This method makes use of an ``site.config.tsx`` file to supply configuration variables to an application:: const config = { - LMS_BASE_URL: 'http://localhost:18000', + lmsBaseUrl: 'http://localhost:18000', BOOLEAN_VAR: false, NULL_VAR: null, NUMBER_VAR: 123 diff --git a/docs/decisions/0008-stylesheet-import-in-site-config.md b/docs/decisions/0008-stylesheet-import-in-site-config.md index eba07011..4888ad1f 100644 --- a/docs/decisions/0008-stylesheet-import-in-site-config.md +++ b/docs/decisions/0008-stylesheet-import-in-site-config.md @@ -21,7 +21,7 @@ As a best practice, a project should have a top-level SCSS file as a peer to the The `project.scss` file should import the stylesheet from the shell: ```diff -+ @import '@openedx/frontend-base/shell/index.scss'; ++ @import '@openedx/frontend-base/shell/app.scss'; // other styles ``` diff --git a/docs/how_tos/automatic-case-conversion.rst b/docs/how_tos/automatic-case-conversion.rst index d1f25ab7..38e82c0a 100644 --- a/docs/how_tos/automatic-case-conversion.rst +++ b/docs/how_tos/automatic-case-conversion.rst @@ -5,7 +5,7 @@ How to: Convert SnakeCase to CamelCase automatically for API Requests Introduction ************ -When using the HTTP client from ``@edx/frontend-platform``, you are making an API request to an +When using the HTTP client from ``@openedx/frontend-base``, you are making an API request to an Open edX service which requires you to handle snake-cased <-> camelCase conversions manually. The manual conversion quickly gets tedious, and is error prone if you forget to do it. @@ -26,11 +26,11 @@ as a middleware when calling ``initialize`` in the consumer:: authMiddleware: [axiosCaseConverter], }); -Or, if you choose to use ``configure`` instead:: +Or, if you choose to use ``configureAuth`` instead:: import axiosCaseConverter from 'axios-case-converter'; - configure({ + configureAuth({ loggingService: getLoggingService(), config: getConfig(), options: { diff --git a/docs/how_tos/i18n.rst b/docs/how_tos/i18n.rst index 7d17c6ff..644c780e 100644 --- a/docs/how_tos/i18n.rst +++ b/docs/how_tos/i18n.rst @@ -96,24 +96,24 @@ Load up your translation files #. In ``App.jsx``, make the following changes:: - import { IntlProvider, getMessages, configure } from '@edx/frontend-platform/i18n'; + import { IntlProvider, getMessages, configureI18n } from '@edx/frontend-base'; import messages from './i18n/index'; // A map of all messages by locale - configure({ + configureI18n({ messages, - config: getConfig(), // ENVIRONMENT and LANGUAGE_PREFERENCE_COOKIE_NAME are required + config: getConfig(), // environment and languagePreferenceCookieName are required loggingService: getLoggingService(), // An object with logError and logInfo methods }); // ...inside ReactDOM.render... -#. As of this writing, ``frontend-platform/i18n`` reads the locale from the user language preference cookie, or, if none is found, from the browser's language setting. You can verify everything is working by changing your language preference in your account settings. If you are not logged in, you can change your browser language to one of the languages you have translations for. +#. As of this writing, ``frontend-base`` reads the locale from the user language preference cookie, or, if none is found, from the browser's language setting. You can verify everything is working by changing your language preference in your account settings. If you are not logged in, you can change your browser language to one of the languages you have translations for. -******************** +************************* Migrating to react-intl@5 -******************** +************************* Initially ``frontend-platform`` used ``react-intl@2`` but as a part of its ``2.0.0`` release the version has been upgraded to ``react-intl@5``. If your application used ``frontend-platform`` < ``2.0.0`` and you decided to upgrade, here's a list of breaking changes that you will need to consider during the upgrade: diff --git a/docs/how_tos/migrate-frontend-app.md b/docs/how_tos/migrate-frontend-app.md index a1e6e2a4..b3a614c0 100644 --- a/docs/how_tos/migrate-frontend-app.md +++ b/docs/how_tos/migrate-frontend-app.md @@ -111,9 +111,11 @@ With the exception of any custom scripts, replace the `scripts` section of your ``` "scripts": { "build": "PORT=YOUR_PORT openedx build", + "build:legacy": "openedx build:legacy", // TODO: Does this target exist? "build:module": "PORT=YOUR_PORT openedx build:module", "dev": "PORT=YOUR_PORT openedx dev", "dev:module": "PORT=YOUR_PORT openedx dev:module", + "dev:legacy": "PORT=YOUR_PORT openedx dev:legacy", "i18n_extract": "openedx formatjs extract", "lint": "openedx lint .", "lint:fix": "openedx lint --fix .", @@ -145,10 +147,14 @@ With the exception of any custom scripts, replace the `scripts` section of your This means that the code from the library can be safely tree-shaken by webpack. -```diff -+ "sideEffects": false, +```json +"sideEffects": [ + "*.css", + "*.scss" +], ``` -+ + +// TODO: Maybe put scss and css files in side effects. They have side effects and need to be excluded so they get bundled. - `config` @@ -167,6 +173,8 @@ The config block must also include an `exposes` configuration that describes you + }, ``` +If you used the "exports" field in package.json it changes the way importing/requiring/TS/node works and everything starts to break. + The entries in `exposes` are: 1. A key that is compatible with the [Package entry points](https://nodejs.org/api/packages.html#package-entry-points) specification. Generally the name of your module prefixed with `./`. @@ -176,15 +184,24 @@ The entries in `exposes` are: Create an `app.d.ts` file in the root of your MFE with the following contents: -``` +```ts /// + +declare module 'site.config' { + export default ProjectSiteConfig; +} + +declare module '*.svg' { + const content: string; + export default content; +} ``` ## 7. Add a tsconfig JSON files Create a `tsconfig.json` file and add the following contents to it: -``` +```json { "extends": "@openedx/frontend-base/config/tsconfig.json", "compilerOptions": { @@ -195,7 +212,7 @@ Create a `tsconfig.json` file and add the following contents to it: "src/**/*", "app.d.ts", "babel.config.js", - ".eslintrc.js", + "eslint.config.js", "jest.config.js", "test.site.config.tsx", "site.config.*.tsx", @@ -295,35 +312,57 @@ mergeConfig(siteConfig); ``` -## 11. Edit `.eslintrc.js` +## 11. Replace `.eslintrc.js` with `eslint.config.js` -Replace the import from 'frontend-build' with 'frontend-base'. +ESLint has been upgraded to v9, which has a new 'flat' file format. Replace the repository's `.eslintrc.js` file with a new `eslint.config.js` file with the following contents: -```diff -- const { createConfig } = require('@openedx/frontend-build'); -+ const { createConfig } = require('@openedx/frontend-base/config'); ``` +// @ts-check -Use 'lint' instead of 'eslint' as the config type for createConfig() +const { createLintConfig } = require('@openedx/frontend-base/config'); +module.exports = createLintConfig( + { + files: [ + 'src/**/*', + 'site.config.*', + ], + }, +); ``` -module.exports = createConfig('lint', { - // ... custom config -}) -``` -You will also need to set the `project` in `parserOptions`. An uncustomized `.eslintrc.js` file looks like: +## 12. Replace `.eslintignore`, if it exists, with entries in `eslint.config.js` + +The base eslint config provided by frontend-base ignores a number of common folders by default: ``` -const path = require('path'); + { + ignores: [ + 'coverage/*', + 'dist/*', + 'node_modules/*', + '**/__mocks__/*', + '**/__snapshots__/*', + ], + }, +``` -const { createConfig } = require('@openedx/frontend-base/config'); +You can configure additional ignores in your own `eslint.config.js` file using the above syntax, as a separate object from the existing 'files' object: -module.exports = createConfig('lint', { - parserOptions: { - project: path.resolve(__dirname, './tsconfig.json'), +```diff +module.exports = createLintConfig( + { + files: [ + 'src/**/*', + 'site.config.*', + ], }, -}); ++ { ++ ignores: [ ++ 'ignoredfolder/*' ++ ] ++ } +); ``` ## 12. Search for any other usages of `frontend-build` @@ -417,14 +456,90 @@ jest.mock('@openedx/frontend-base', () => ({ In this case, the default implementations of most frontend-base exports are included, and only the three afterward are mocked. In most cases, this should work. If you have a more complicated mocking situation in your test, you may need to refactor the test. -## 18. Delete the `.env` and `.env.development` files. +## 18. Delete the `.env` and `.env.development` files and create site.config files. + +Frontend-base uses `site.config.*.tsx` files for configuration, rather than .env files. The development file is site.config.dev.tsx, and the production file is site.config.prod.tsx. If you want to run a webpack build from your library, you will need to add a `site.config` file, such as `site.config.dev.tsx`. These files are ignored via `.gitignore` and will not be checked in. There will be resources available to help writing these files. +Site config is a new schema for configuration. Notably, config variables are camelCased like normal JavaScript variables, rather than SCREAMING_SNAKE_CASE. + +### Required config + +The required configuration at the time of this writing is: + +- appId: string +- siteName: string +- baseUrl: string +- lmsBaseUrl: string +- loginUrl: string +- logoutUrl: string + +### Optional config + +Other configuration is now optional, and many values have been given sensible defaults. But these configuration variables are also available (as of this writing): + +- accessTokenCookieName: string +- languagePreferenceCookieName: string +- userInfoCookieName: string +- csrfTokenApiPath: string +- refreshAccessTokenApiPath: string +- ignoredErrorRegex: RegExp | null +- segmentKey: string | null +- environment: EnvironmentTypes +- mfeConfigApiUrl: string | null +- publicPath: string + +### URL Config changes + +Note that the .env files and env.config.js files also include a number of URLs for various micro-frontends and services. These URLs should now be expressed as part of the `apps` config as route roles, and used in code via `getUrlForRouteRole()`. Or as externalRoutes. + +``` +// Creating a route role with for 'example' in an App +const app: App = { + routes: [{ + path: '/example', + id: 'example.page', + Component: ExamplePage, + handle: { + role: 'example' + } + }], +}; + +// Using the role in code to link to the page +const examplePageUrl = getUrlForRouteRole('example'); +``` + +### App-specific config values + +App-specific configuration can be expressed by adding a `custom` section to SiteConfig which allows arbitrary config variables. + +``` +const config: ProjectSiteConfig = { + // ... Other config + + custom: { + appId: 'myapp', + myCustomVariableName: 'my custom variable value', + } +} +``` + +These variables can be used in code with the `getAppConfig` function: + +``` +getAppConfig('myapp').myCustomVariableName +``` + +If you have fully converted your app over to the new module architecture, you can add custom variables to the `config` object in your `App` definition and they will be available via `getAppConfig`. + ## 19. Replace the `.env.test` file with configuration in `test.site.config.tsx` file We're moving away from .env files because they're not expressive enough (only string types!) to configure an Open edX frontend. Instead, the test suite has been configured to expect a `test.site.config.tsx` file. If you're initializing an application in your tests, `frontend-base` will pick up this configuration and make it available to `getConfig()`, etc. If you need to manually access the variables, you can import `site.config` in your test files: +Note that test.site.config.tsx has a different naming scheme than `site.config.*.tsx` because it's intended to be checked in, and `site.config.*.tsx` is git-ignored. + ```diff + import config from 'site.config'; ``` @@ -440,35 +555,21 @@ import { ProjectSiteConfig } from '@openedx/frontend-base'; const config: ProjectSiteConfig = { apps: [], - ACCESS_TOKEN_COOKIE_NAME: 'edx-jwt-cookie-header-payload', - BASE_URL: 'http://localhost:8080', - ACCOUNT_PROFILE_URL: 'http://localhost:1995', - 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:18000/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_API_PATH: '/login_refresh', - SEGMENT_KEY: '', - SITE_NAME: 'localhost', - USER_INFO_COOKIE_NAME: 'edx-user-info', - APP_ID: 'authn', - ENVIRONMENT: 'dev', - ACCOUNT_SETTINGS_URL: 'http://localhost:1997', - DISCOVERY_API_BASE_URL: 'http://localhost:18381', - IGNORED_ERROR_REGEX: null, - LEARNING_BASE_URL: 'http://localhost:2000', - PUBLIC_PATH: '/', - PUBLISHER_BASE_URL: 'http://localhost:18400', - STUDIO_BASE_URL: 'http://localhost:18010', + accessTokenCookieName: 'edx-jwt-cookie-header-payload', + baseUrl: 'http://localhost:8080', + csrfTokenApiPath: '/csrf/api/v1/token', + languagePreferenceCookieName: 'openedx-language-preference', + lmsBaseUrl: 'http://localhost:18000', + loginUrl: 'http://localhost:18000/login', + logoutUrl: 'http://localhost:18000/logout', + refreshAccessTokenApiPath: '/login_refresh', + segmentKey: '', + siteName: 'localhost', + userInfoCookieName: 'edx-user-info', + appId: 'authn', + environment: 'dev', + ignoredErrorRegex: null, + publicPath: '/', }; export default config; @@ -476,11 +577,11 @@ export default config; ## 20. Remove initialization -In your index.(jsx|tsx) file, you need to remove the subscribe and initialization code. If you have customizations here, they will need to migrate to your `site.config` file instead and take advantage of the shell's provided customization mechanisms. **This functionality is still a work in progress.** +In your index.(jsx|tsx) file, you need to remove the subscribe and initialization code. If you have customizations here, they will need to migrate to your `site.config` file instead and take advantage of the shell's provided customization mechanisms. ## 21. Migrate header/footer dependencies -If your application uses a custom header or footer, you can use the shell's header and footer plugin slots to provide your custom header/footer components. This is done through the `site.config` file. **This functionality is still a work in progress.** +If your application uses a custom header or footer, you can use the shell's header and footer plugin slots to provide your custom header/footer components. This is done through the `site.config` file. ## 22. Export the modules of your app in your index.ts file. @@ -518,21 +619,67 @@ This file will be ignored via `.gitignore`, as it is part of your 'project', not Your modules will need environment variables that your system merged into config in index.jsx - we need to document and expect those when the module is loaded. You'll need this list in the next step. -## 27. Stop using process.env +## 26. Stop using process.env -Instead, custom variables must go through site config. +Instead, custom variables must go through site config. This can be done by adding a 'config' object to the App's definition -- Move all your custom variables into the `custom: {}` block of site config. -- Throughout your app, wherever you use one of these variables, get it from `getConfig().custom` instead of from `process.env`. +## 27. Convert @import to @use in SCSS files. -As we decide on the module boundaries of our library, we'll be able to move these into module-specific configuration in site config. `custom` is a temporary home for this config. +@import is deprecated in the most recent versions of SASS. -## 26. More art than science: find your module boundaries +When you do this, you will find that variables and mixins from Paragon, in particular, are likely to result in errors when building the app in webpack. To fix this, you must `@use` the paragon core SCSS file in the file where you want to use the variable or mixin: -From this step on, things get a bit more subjective. At this point you need to ensure that the modules in your library are decoupled and well-bounded. If you use Redux, this may mean creating individual redux stores for each module, including adding a context so that they're separate from any "upstream" redux stores that may exist. +``` +@use "@openedx/paragon/scss/core/core" as paragon; +``` -https://react-redux.js.org/using-react-redux/accessing-store#multiple-stores +And then prefix the variable/mixin usage with `paragon.`: + +``` +// Using a mixin +@include paragon.media-breakpoint-up(lg) { + +} -## 27. Subdomains!? +// Or a variable +paragon.$primary-700 +``` + +## 28. Changes to i18n + +configureI18n no longer takes `config` or `loggingService` as options + +The `getLoggingService` export from _i18n_ has also been removed. No one should be using that. + +`getLanguageList` has been removed. Modules that need a list of countries should install `@cospired/i18n-iso-languages` as a dependency. + +`getSupportedLanguageList` now returns an array of objects containing the `name` and `code` of all the languages that have translations bundled with the app, rather than a hard-coded list. + +`getCountryList` has been removed. MFEs that need a list of countries should install `i18n-iso-countries` or `countries-list` as a dependency. + +The getCountryList function can be reproduced from this file in frontend-platform: https://github.com/openedx/frontend-platform/blob/master/src/i18n/countries.js + +frontend-app-account should use the supported language list from frontend-base, rather than the hard-coded list in https://github.com/openedx/frontend-app-account/blob/master/src/account-settings/site-language/constants.js + +This would help it match the behavior of the footer's language dropdown. -## 28. Add LEARNER_DASHBOARD_URL to config +## 29. Removal of pubsub-js + +frontend-platform used pubsub-js behind the scenes for event subscriptions/publishing. It used it in a very rudimentary way, and the library was noisy in test suites, complaining about being re-initialized. Because of these reasons, we've removed our dependency on pubsub-js and replaced it with a simple subscription system with a very similar API: + +- `subscribe(topic: string, callback: (topic: string, data?: any) => void)` +- `publish(topic: string, data?: any)` +- `unsubscribe(topic: string, callback: (topic: string, data?: any) => void)` +- `clearAllSubscriptions()` + +The unsubscribe function as a different API than pubsub-js's unsubscribe function, taking a topic and a callback rather than an unsubscribe token. + +Consumers who were using the `PubSub` global variable should instead import the above functions directly from `@openedx/frontend-base`. + +### 31. React router move to data router. + +## 30. More art than science: find your module boundaries + +From this step on, things get a bit more subjective. At this point you need to ensure that the modules in your library are decoupled and well-bounded. If you use Redux, this may mean creating individual redux stores for each module, including adding a context so that they're separate from any "upstream" redux stores that may exist. + +https://react-redux.js.org/using-react-redux/accessing-store#multiple-stores diff --git a/eslint.config.js b/eslint.config.js new file mode 100644 index 00000000..b10cb1ab --- /dev/null +++ b/eslint.config.js @@ -0,0 +1,18 @@ +// @ts-check + +const tseslint = require('typescript-eslint'); +const eslintConfig = require('./tools/eslint/base.eslint.config.js'); + +module.exports = tseslint.config( + { + extends: eslintConfig, + }, + { + ignores: [ + 'tools/*', + 'test-project/*', + 'config/*', + 'docs/*', + ], + }, +); diff --git a/frontend-base.d.ts b/frontend-base.d.ts index 4278d0e1..14df28b0 100644 --- a/frontend-base.d.ts +++ b/frontend-base.d.ts @@ -1,5 +1,3 @@ -import { ProjectSiteConfig } from "./index"; - declare module 'site.config' { export default ProjectSiteConfig; } diff --git a/index.ts b/index.ts index 494669de..7d0464ca 100644 --- a/index.ts +++ b/index.ts @@ -1,123 +1,7 @@ -export { - APP_ANALYTICS_INITIALIZED, - APP_AUTH_INITIALIZED, - APP_CONFIG_INITIALIZED, - APP_I18N_INITIALIZED, - APP_INIT_ERROR, - APP_LOGGING_INITIALIZED, - APP_PUBSUB_INITIALIZED, - APP_READY, - APP_TOPIC, - AUTHENTICATED_USER_CHANGED, - AUTHENTICATED_USER_TOPIC, - AppContext, - AppProvider, - AuthenticatedPageRoute, - AxiosJwtAuthService, - CONFIG_CHANGED, - CONFIG_TOPIC, - Divider, - ErrorBoundary, - ErrorPage, - FormattedDate, - FormattedMessage, - FormattedNumber, - FormattedPlural, - FormattedRelativeTime, - FormattedTime, - IntlProvider, - LOCALE_CHANGED, - LOCALE_TOPIC, - LoginRedirect, - MockAnalyticsService, - MockAuthService, - MockLoggingService, - NewRelicLoggingService, - PageWrap, - Plugin, - PluginSlot, - SegmentAnalyticsService, - auth, - camelCaseObject, - configureAnalytics, - configureAuth, - configureI18n, - configureLogging, - convertKeyNames, - createIntl, - defineMessages, - ensureAuthenticatedUser, - fetchAuthenticatedUser, - getAnalyticsService, - getAuthService, - getAuthenticatedHttpClient, - getAuthenticatedUser, - getBasename, - getConfig, - getCountryList, - getCountryMessages, - getHistory, - getHttpClient, - getLanguageList, - getLanguageMessages, - getLocale, - getLoggingService, - getLoginRedirectUrl, - getLogoutRedirectUrl, - getMessages, - getPath, - getPrimaryLanguageSubtag, - getQueryParameters, - handleRtl, - hydrateAuthenticatedUser, - identifyAnonymousUser, - identifyAuthenticatedUser, - initError, - initialize, - initializeMockApp, - injectIntl, - intlShape, - isRtl, - logError, - logInfo, - mergeConfig, - mergeMessages, - mockMessages, - modifyObjectKeys, - parseURL, - publish, - redirectToLogin, - redirectToLogout, - resetAnalyticsService, - resetLoggingService, - sendPageEvent, - sendTrackEvent, - sendTrackingLogEvent, - setAuthenticatedUser, - setConfig, - snakeCaseObject, - subscribe, - unsubscribe, - useAppEvent, - useAuthenticatedUser, - useConfig, - useIntl -} from './runtime'; +export * from './runtime'; -export type { - ApplicationModuleConfig, - ExternalAppConfig, - FederatedAppConfig, - InsertDirectPluginWidget, - InsertIframePluginWidget, - InternalAppConfig, - ProjectModuleConfig, - ProjectSiteConfig -} from './types'; +export type * from './types'; -export { - AppConfigTypes, - EnvironmentTypes, - PluginOperations, - PluginTypes -} from './types'; +export * from './types'; + +export * from './shell'; diff --git a/package-lock.json b/package-lock.json index aed282d9..82c5166c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,50 +13,47 @@ "@babel/preset-env": "^7.24.8", "@babel/preset-react": "^7.24.7", "@babel/preset-typescript": "^7.24.7", - "@cospired/i18n-iso-languages": "^4.2.0", "@edx/new-relic-source-map-webpack-plugin": "2.1.0", + "@eslint/compat": "^1.2.1", + "@eslint/js": "^9.13.0", "@formatjs/cli": "^6.0.3", - "@formatjs/intl-pluralrules": "^4.3.3", - "@formatjs/intl-relativetimeformat": "^10.0.1", "@formatjs/ts-transformer": "^3.13.14", - "@module-federation/enhanced": "^0.4.0", - "@module-federation/runtime": "^0.2.6", - "@pmmmwh/react-refresh-webpack-plugin": "0.5.15", + "@module-federation/enhanced": "^0.6.12", + "@module-federation/runtime": "^0.6.12", + "@pmmmwh/react-refresh-webpack-plugin": "^0.5.15", + "@stylistic/eslint-plugin": "^2.9.0", + "@types/eslint__js": "^8.42.3", "@types/gradient-string": "^1.1.6", - "@typescript-eslint/eslint-plugin": "^6.21.0", - "@typescript-eslint/parser": "^6.21.0", - "autoprefixer": "10.4.19", + "autoprefixer": "^10.4.20", "axios": "^1.7.7", "axios-cache-interceptor": "^1.6.0", "babel-jest": "^29.7.0", "babel-plugin-formatjs": "^10.5.16", - "chalk": "4.1.2", + "chalk": "^4.1.2", "classnames": "^2.5.1", - "clean-webpack-plugin": "4.0.0", + "clean-webpack-plugin": "^4.0.0", "compression": "^1.7.4", - "css-loader": "5.2.7", - "cssnano": "6.0.3", - "eslint": "8.44.0", - "eslint-config-airbnb": "19.0.4", - "eslint-config-airbnb-typescript": "^17.0.0", - "eslint-plugin-formatjs": "^4.12.2", - "eslint-plugin-import": "2.27.5", - "eslint-plugin-jsx-a11y": "6.7.1", - "eslint-plugin-react": "7.32.2", - "eslint-plugin-react-hooks": "4.6.0", + "css-loader": "^7.1.2", + "cssnano": "^6.1.2", + "eslint": "^9.13.0", + "eslint-plugin-formatjs": "^5.1.3", + "eslint-plugin-jest": "^28.8.3", + "eslint-plugin-jsx-a11y": "^6.10.1", + "eslint-plugin-react": "^7.37.2", + "eslint-plugin-react-hooks": "^5.0.0", "express": "^4.18.2", "file-loader": "6.2.0", "fork-ts-checker-webpack-plugin": "^9.0.2", "form-urlencoded": "^6.1.5", "glob": "^7.2.3", + "globals": "^15.11.0", "gradient-string": "^2.0.2", "history": "^4.10.1", "html-webpack-plugin": "5.6.0", - "i18n-iso-countries": "^4.3.1", "identity-obj-proxy": "3.0.0", "image-minimizer-webpack-plugin": "3.8.3", - "jest": "29.6.1", - "jest-environment-jsdom": "29.6.1", + "jest": "^29.7.0", + "jest-environment-jsdom": "^29.7.0", "jwt-decode": "^3.1.2", "localforage": "^1.10.0", "localforage-memoryStorageDriver": "^0.9.2", @@ -66,12 +63,11 @@ "lodash.snakecase": "^4.1.1", "mini-css-extract-plugin": "1.6.2", "parse5": "7.1.2", - "postcss": "8.4.40", + "postcss": "^8.4.47", "postcss-custom-media": "10.0.8", "postcss-loader": "7.3.4", - "postcss-rtlcss": "5.1.2", + "postcss-rtlcss": "^5.5.0", "prop-types": "^15.8.1", - "pubsub-js": "^1.9.4", "react-dev-utils": "12.0.1", "react-focus-on": "^3.9.4", "react-intl": "^6.6.6", @@ -79,20 +75,22 @@ "react-refresh-typescript": "^2.0.9", "react-responsive": "^10.0.0", "react-transition-group": "^4.4.5", - "resolve-url-loader": "5.0.0", - "sass": "1.69.7", - "sass-loader": "13.3.3", - "sharp": "0.32.6", + "resolve-url-loader": "^5.0.0", + "sass-embedded": "^1.80.4", + "sass-loader": "^16.0.2", + "sharp": "^0.33.5", "source-map-loader": "4.0.2", - "style-loader": "3.3.4", + "style-loader": "^4.0.0", "ts-loader": "^9.5.1", - "typescript": "^5.5.3", + "typescript": "^5.6.3", + "typescript-eslint": "^8.11.0", "universal-cookie": "^4.0.4", - "url-loader": "4.1.1", - "webpack": "^5.89.0", + "url-loader": "^4.1.1", + "uuid": "^11.0.2", + "webpack": "^5.95.0", "webpack-bundle-analyzer": "^4.10.1", "webpack-cli": "^5.1.4", - "webpack-dev-server": "^4.15.1", + "webpack-dev-server": "^5.1.0", "webpack-merge": "^5.10.0", "webpack-remove-empty-scripts": "1.0.4" }, @@ -109,7 +107,7 @@ "@testing-library/user-event": "^14.5.2", "@tsconfig/node18": "^18.2.4", "@types/compression": "^1.7.5", - "@types/jest": "^29.5.12", + "@types/jest": "^29.5.14", "@types/lodash.camelcase": "^4.3.9", "@types/lodash.merge": "^4.6.9", "@types/node": "^18.19.43", @@ -1024,6 +1022,14 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/plugin-transform-classes/node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "engines": { + "node": ">=4" + } + }, "node_modules/@babel/plugin-transform-computed-properties": { "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.24.7.tgz", @@ -1919,6 +1925,14 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/traverse/node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "engines": { + "node": ">=4" + } + }, "node_modules/@babel/types": { "version": "7.25.6", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.25.6.tgz", @@ -1937,13 +1951,10 @@ "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==" }, - "node_modules/@cospired/i18n-iso-languages": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@cospired/i18n-iso-languages/-/i18n-iso-languages-4.2.0.tgz", - "integrity": "sha512-vy8cq1176MTxVwB1X9niQjcIYOH29F8Huxtx8hLmT5Uz3l1ztGDGri8KN/4zE7LV2mCT7JrcAoNV/I9yb+lNUw==", - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } + "node_modules/@bufbuild/protobuf": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@bufbuild/protobuf/-/protobuf-2.2.0.tgz", + "integrity": "sha512-+imAQkHf7U/Rwvu0wk1XWgsP3WnpCWmK7B48f0XqSNzgk64+grljTKC7pnO/xBiEMUziF7vKRfbBnOQhg126qQ==" }, "node_modules/@csstools/cascade-layer-name-parser": { "version": "1.0.13", @@ -2044,6 +2055,15 @@ "@newrelic/publish-sourcemap": "^5.0.1" } }, + "node_modules/@emnapi/runtime": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.3.1.tgz", + "integrity": "sha512-kEBmG8KyqtxJZv+ygbEim+KCGtIq1fC22Ms3S4ziXmYKm8uyoLX0MHONVKwp+9opg390VaKRNt4a7A9NwmpNhw==", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, "node_modules/@eslint-community/eslint-utils": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", @@ -2066,15 +2086,52 @@ "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, + "node_modules/@eslint/compat": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@eslint/compat/-/compat-1.2.1.tgz", + "integrity": "sha512-JbHG2TWuCeNzh87fXo+/46Z1LEo9DBA9T188d0fZgGxAD+cNyS6sx9fdiyxjGPBMyQVRlCutTByZ6a5+YMkF7g==", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "peerDependencies": { + "eslint": "^9.10.0" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + }, + "node_modules/@eslint/config-array": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.18.0.tgz", + "integrity": "sha512-fTxvnS1sRMu3+JjXwJG0j/i4RT9u4qJ+lqS/yCGap4lH4zZGzQ7tu+xZqQmcMZq5OBZDL4QRxQzRjkWcGt8IVw==", + "dependencies": { + "@eslint/object-schema": "^2.1.4", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/core": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.7.0.tgz", + "integrity": "sha512-xp5Jirz5DyPYlPiKat8jaq0EmYvDXKKpzTbxXMpT9eqlRJkRKIz9AGMdlvYjih+im+QlhWrpvVjl8IPC/lHlUw==", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, "node_modules/@eslint/eslintrc": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", - "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.1.0.tgz", + "integrity": "sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==", "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", - "espree": "^9.6.0", - "globals": "^13.19.0", + "espree": "^10.0.1", + "globals": "^14.0.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.0", @@ -2082,7 +2139,7 @@ "strip-json-comments": "^3.1.1" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "url": "https://opencollective.com/eslint" @@ -2093,24 +2150,12 @@ "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" }, - "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, "node_modules/@eslint/eslintrc/node_modules/globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", - "dependencies": { - "type-fest": "^0.20.2" - }, + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", "engines": { - "node": ">=8" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -2127,34 +2172,31 @@ "js-yaml": "bin/js-yaml.js" } }, - "node_modules/@eslint/eslintrc/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dependencies": { - "brace-expansion": "^1.1.7" - }, + "node_modules/@eslint/js": { + "version": "9.13.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.13.0.tgz", + "integrity": "sha512-IFLyoY4d72Z5y/6o/BazFBezupzI/taV8sGumxTAVw3lXG9A6md1Dc34T9s1FoD/an9pJH8RHbAxsaEbBed9lA==", "engines": { - "node": "*" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@eslint/eslintrc/node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "node_modules/@eslint/object-schema": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.4.tgz", + "integrity": "sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ==", "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@eslint/js": { - "version": "8.44.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.44.0.tgz", - "integrity": "sha512-Ag+9YM4ocKQx9AarydN0KY2j0ErMHNIocPDrVo8zAE44xLTjEtz81OdR68/cydGtk6m6jDb5Za3r2useMzYmSw==", + "node_modules/@eslint/plugin-kit": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.1.tgz", + "integrity": "sha512-HFZ4Mp26nbWk9d/BpvP0YNL6W4UoZF0VFcTw/aPPA8RpOxeFQgK+ClABGgAUXs9Y/RGX/l1vOmrqz1MQt9MNuw==", + "dependencies": { + "levn": "^0.4.1" + }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, "node_modules/@formatjs/cli": { @@ -2204,15 +2246,6 @@ } } }, - "node_modules/@formatjs/ecma402-abstract": { - "version": "1.11.4", - "resolved": "https://registry.npmjs.org/@formatjs/ecma402-abstract/-/ecma402-abstract-1.11.4.tgz", - "integrity": "sha512-EBikYFp2JCdIfGEb5G9dyCkTGDmC57KSHhRQOC3aYxoPWVZvfWCDjZwkGYHN7Lis/fmuWl906bnNTJifDQ3sXw==", - "dependencies": { - "@formatjs/intl-localematcher": "0.2.25", - "tslib": "^2.1.0" - } - }, "node_modules/@formatjs/fast-memoize": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/@formatjs/fast-memoize/-/fast-memoize-2.2.0.tgz", @@ -2350,34 +2383,6 @@ "tslib": "^2.4.0" } }, - "node_modules/@formatjs/intl-localematcher": { - "version": "0.2.25", - "resolved": "https://registry.npmjs.org/@formatjs/intl-localematcher/-/intl-localematcher-0.2.25.tgz", - "integrity": "sha512-YmLcX70BxoSopLFdLr1Ds99NdlTI2oWoLbaUW2M406lxOIPzE1KQhRz2fPUkq34xVZQaihCoU29h0KK7An3bhA==", - "dependencies": { - "tslib": "^2.1.0" - } - }, - "node_modules/@formatjs/intl-pluralrules": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/@formatjs/intl-pluralrules/-/intl-pluralrules-4.3.3.tgz", - "integrity": "sha512-NLZN8gf2qLpCuc0m565IbKLNUarEGOzk0mkdTkE4XTuNCofzoQTurW6lL3fmDlneAoYl2FiTdHa5q4o2vZF50g==", - "dependencies": { - "@formatjs/ecma402-abstract": "1.11.4", - "@formatjs/intl-localematcher": "0.2.25", - "tslib": "^2.1.0" - } - }, - "node_modules/@formatjs/intl-relativetimeformat": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/@formatjs/intl-relativetimeformat/-/intl-relativetimeformat-10.0.1.tgz", - "integrity": "sha512-AABPQtPjFilXegQsnmVHrSlzjFNUffAEk5DgowY6b7WSwDI7g2W6QgW903/lbZ58emhphAbgHdtKeUBXqTiLpw==", - "dependencies": { - "@formatjs/ecma402-abstract": "1.11.4", - "@formatjs/intl-localematcher": "0.2.25", - "tslib": "^2.1.0" - } - }, "node_modules/@formatjs/intl/node_modules/@formatjs/ecma402-abstract": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/@formatjs/ecma402-abstract/-/ecma402-abstract-2.0.0.tgz", @@ -2456,38 +2461,24 @@ "react": ">=16.x" } }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.11.14", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", - "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", - "deprecated": "Use @eslint/config-array instead", - "dependencies": { - "@humanwhocodes/object-schema": "^2.0.2", - "debug": "^4.3.1", - "minimatch": "^3.0.5" - }, + "node_modules/@humanfs/core": { + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.0.tgz", + "integrity": "sha512-2cbWIHbZVEweE853g8jymffCA+NCMiuqeECeBBLm8dg2oFdjuGJhgN4UAbI+6v0CKbbhvtXA4qV8YR5Ji86nmw==", "engines": { - "node": ">=10.10.0" - } - }, - "node_modules/@humanwhocodes/config-array/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "node": ">=18.18.0" } }, - "node_modules/@humanwhocodes/config-array/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "node_modules/@humanfs/node": { + "version": "0.16.5", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.5.tgz", + "integrity": "sha512-KSPA4umqSG4LHYRodq31VDwKAvaTF4xmVlzM8Aeh4PlU1JQ3IG0wiA8C25d3RQ9nJyM3mBHyI53K06VVL/oFFg==", "dependencies": { - "brace-expansion": "^1.1.7" + "@humanfs/core": "^0.19.0", + "@humanwhocodes/retry": "^0.3.0" }, "engines": { - "node": "*" + "node": ">=18.18.0" } }, "node_modules/@humanwhocodes/module-importer": { @@ -2502,141 +2493,489 @@ "url": "https://github.com/sponsors/nzakas" } }, - "node_modules/@humanwhocodes/object-schema": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", - "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", - "deprecated": "Use @eslint/object-schema instead" - }, - "node_modules/@istanbuljs/load-nyc-config": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", - "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", - "dependencies": { - "camelcase": "^5.3.1", - "find-up": "^4.1.0", - "get-package-type": "^0.1.0", - "js-yaml": "^3.13.1", - "resolve-from": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/schema": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", - "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "node_modules/@humanwhocodes/retry": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz", + "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==", "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/console": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.7.0.tgz", - "integrity": "sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==", - "dependencies": { - "@jest/types": "^29.6.3", - "@types/node": "*", - "chalk": "^4.0.0", - "jest-message-util": "^29.7.0", - "jest-util": "^29.7.0", - "slash": "^3.0.0" + "node": ">=18.18" }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" } }, - "node_modules/@jest/core": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.7.0.tgz", - "integrity": "sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==", - "dependencies": { - "@jest/console": "^29.7.0", - "@jest/reporters": "^29.7.0", - "@jest/test-result": "^29.7.0", - "@jest/transform": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.9", - "jest-changed-files": "^29.7.0", - "jest-config": "^29.7.0", - "jest-haste-map": "^29.7.0", - "jest-message-util": "^29.7.0", - "jest-regex-util": "^29.6.3", - "jest-resolve": "^29.7.0", - "jest-resolve-dependencies": "^29.7.0", - "jest-runner": "^29.7.0", - "jest-runtime": "^29.7.0", - "jest-snapshot": "^29.7.0", - "jest-util": "^29.7.0", - "jest-validate": "^29.7.0", - "jest-watcher": "^29.7.0", - "micromatch": "^4.0.4", - "pretty-format": "^29.7.0", - "slash": "^3.0.0", - "strip-ansi": "^6.0.0" - }, + "node_modules/@img/sharp-darwin-arm64": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.33.5.tgz", + "integrity": "sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + "funding": { + "url": "https://opencollective.com/libvips" }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } + "optionalDependencies": { + "@img/sharp-libvips-darwin-arm64": "1.0.4" } }, - "node_modules/@jest/core/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "node_modules/@img/sharp-darwin-x64": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.33.5.tgz", + "integrity": "sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=10" + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@jest/core/node_modules/pretty-format": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", - "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", - "dependencies": { - "@jest/schemas": "^29.6.3", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" + "url": "https://opencollective.com/libvips" }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "optionalDependencies": { + "@img/sharp-libvips-darwin-x64": "1.0.4" } }, - "node_modules/@jest/core/node_modules/react-is": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", - "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==" - }, - "node_modules/@jest/environment": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz", - "integrity": "sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==", - "dependencies": { - "@jest/fake-timers": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/node": "*", - "jest-mock": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node_modules/@img/sharp-libvips-darwin-arm64": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.0.4.tgz", + "integrity": "sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" } }, - "node_modules/@jest/expect": { + "node_modules/@img/sharp-libvips-darwin-x64": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.0.4.tgz", + "integrity": "sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.0.5.tgz", + "integrity": "sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm64": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.0.4.tgz", + "integrity": "sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-s390x": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.0.4.tgz", + "integrity": "sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA==", + "cpu": [ + "s390x" + ], + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-x64": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.0.4.tgz", + "integrity": "sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-arm64": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.0.4.tgz", + "integrity": "sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-x64": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.0.4.tgz", + "integrity": "sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-linux-arm": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.33.5.tgz", + "integrity": "sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ==", + "cpu": [ + "arm" + ], + "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.0.5" + } + }, + "node_modules/@img/sharp-linux-arm64": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.33.5.tgz", + "integrity": "sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA==", + "cpu": [ + "arm64" + ], + "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.0.4" + } + }, + "node_modules/@img/sharp-linux-s390x": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.33.5.tgz", + "integrity": "sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q==", + "cpu": [ + "s390x" + ], + "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.0.4" + } + }, + "node_modules/@img/sharp-linux-x64": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.33.5.tgz", + "integrity": "sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA==", + "cpu": [ + "x64" + ], + "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.0.4" + } + }, + "node_modules/@img/sharp-linuxmusl-arm64": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.33.5.tgz", + "integrity": "sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g==", + "cpu": [ + "arm64" + ], + "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.0.4" + } + }, + "node_modules/@img/sharp-linuxmusl-x64": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.33.5.tgz", + "integrity": "sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw==", + "cpu": [ + "x64" + ], + "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.0.4" + } + }, + "node_modules/@img/sharp-wasm32": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.33.5.tgz", + "integrity": "sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg==", + "cpu": [ + "wasm32" + ], + "optional": true, + "dependencies": { + "@emnapi/runtime": "^1.2.0" + }, + "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.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.33.5.tgz", + "integrity": "sha512-T36PblLaTwuVJ/zw/LaH0PdZkRz5rd3SmMHX8GSmR7vtNSP5Z6bQkExdSK7xGWyxLw4sUknBuugTelgw2faBbQ==", + "cpu": [ + "ia32" + ], + "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.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.33.5.tgz", + "integrity": "sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "dependencies": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/console": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.7.0.tgz", + "integrity": "sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/core": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.7.0.tgz", + "integrity": "sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==", + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/reporters": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-changed-files": "^29.7.0", + "jest-config": "^29.7.0", + "jest-haste-map": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-resolve-dependencies": "^29.7.0", + "jest-runner": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "jest-watcher": "^29.7.0", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/core/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@jest/core/node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/core/node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==" + }, + "node_modules/@jest/environment": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz", + "integrity": "sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==", + "dependencies": { + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.7.0.tgz", "integrity": "sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==", @@ -2911,7 +3250,58 @@ "lodash": "^4.17.21" }, "engines": { - "node": ">=v12.0.0" + "node": ">=v12.0.0" + } + }, + "node_modules/@jsonjoy.com/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-q6XAnWQDIMA3+FTiOYajoYqySkO+JSat0ytXGSuRdq9uXE7o92gzuQwQM14xaCRlBLGq3v5miDGC4vkVTn54xA==", + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/json-pack": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/json-pack/-/json-pack-1.1.0.tgz", + "integrity": "sha512-zlQONA+msXPPwHWZMKFVS78ewFczIll5lXiVPwFPCZUsrOKdxc2AvxU1HoNBmMRhqDZUR9HkC3UOm+6pME6Xsg==", + "dependencies": { + "@jsonjoy.com/base64": "^1.1.1", + "@jsonjoy.com/util": "^1.1.2", + "hyperdyperid": "^1.2.0", + "thingies": "^1.20.0" + }, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/util": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/util/-/util-1.5.0.tgz", + "integrity": "sha512-ojoNsrIuPI9g6o8UxhraZQSyF2ByJanAY4cTFbc8Mf2AXEF4aQRGY1dJxyJpuyav8r9FGflEt/Ff3u5Nt6YMPA==", + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" } }, "node_modules/@leichtgewicht/ip-codec": { @@ -2920,24 +3310,51 @@ "integrity": "sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==" }, "node_modules/@module-federation/bridge-react-webpack-plugin": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/@module-federation/bridge-react-webpack-plugin/-/bridge-react-webpack-plugin-0.4.0.tgz", - "integrity": "sha512-su/ZpRZcyZ8yVa5+zmZyh2pW/BdCQsto52Xmp75GRgPgwG7IrczcQ/GlMCHZz9hQQdmLEQuPe4BIvpnH+GS9Jw==", + "version": "0.6.12", + "resolved": "https://registry.npmjs.org/@module-federation/bridge-react-webpack-plugin/-/bridge-react-webpack-plugin-0.6.12.tgz", + "integrity": "sha512-AF+5iKtfBsQU8XDudw55C5zo442uiqU3hY1uGJInr+/v16MrXviFQqrZ2VuXKiu9C8vPXbsAtBNB6MbOH5JARA==", + "dependencies": { + "@module-federation/sdk": "0.6.12", + "@types/semver": "7.5.8", + "semver": "7.6.3" + } + }, + "node_modules/@module-federation/bridge-react-webpack-plugin/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@module-federation/data-prefetch": { + "version": "0.6.12", + "resolved": "https://registry.npmjs.org/@module-federation/data-prefetch/-/data-prefetch-0.6.12.tgz", + "integrity": "sha512-Pg0N/H9stucS6Olmrc8Ib75f5bqx0I3ayWgkY5dahe2B8E3Bhbr1zw3seidPKXIosemRZxA11QsPD5of5SyNmA==", "dependencies": { - "@module-federation/sdk": "0.4.0" + "@module-federation/runtime": "0.6.12", + "@module-federation/sdk": "0.6.12", + "fs-extra": "9.1.0" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" } }, "node_modules/@module-federation/dts-plugin": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/@module-federation/dts-plugin/-/dts-plugin-0.4.0.tgz", - "integrity": "sha512-KCFIdUh6PhoNqU8OlLmbhjec+wWyo9HAUukR84TnjiktVYMcCqmlmSeWoma2llyPE3GeOHqln+cPR7hMPXbR6w==", + "version": "0.6.12", + "resolved": "https://registry.npmjs.org/@module-federation/dts-plugin/-/dts-plugin-0.6.12.tgz", + "integrity": "sha512-JFoHXVrwQDqcbRc7Ws/19zmCajx3xyRZarvM8592OLoLOK/QzrA9xg/o1ltiC4a7tRA3aubm9clo+pzVgqECwQ==", "dependencies": { - "@module-federation/managers": "0.4.0", - "@module-federation/sdk": "0.4.0", - "@module-federation/third-party-dts-extractor": "0.4.0", + "@module-federation/managers": "0.6.12", + "@module-federation/sdk": "0.6.12", + "@module-federation/third-party-dts-extractor": "0.6.12", "adm-zip": "^0.5.10", "ansi-colors": "^4.1.3", - "axios": "^1.6.7", + "axios": "^1.7.4", "chalk": "3.0.0", "fs-extra": "9.1.0", "isomorphic-ws": "5.0.0", @@ -2946,7 +3363,7 @@ "log4js": "6.9.1", "node-schedule": "2.1.1", "rambda": "^9.1.0", - "ws": "8.17.1" + "ws": "8.18.0" }, "peerDependencies": { "typescript": "^4.9.0 || ^5.0.0", @@ -2971,17 +3388,18 @@ } }, "node_modules/@module-federation/enhanced": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/@module-federation/enhanced/-/enhanced-0.4.0.tgz", - "integrity": "sha512-F398RJioMiU4zpXjtF+bJG7sROGNnY1dyPxwfhAnfDxtm/5urWnR2od2+zTvucyWdNeWQxbEe9XUOpgt42egqw==", - "dependencies": { - "@module-federation/bridge-react-webpack-plugin": "0.4.0", - "@module-federation/dts-plugin": "0.4.0", - "@module-federation/managers": "0.4.0", - "@module-federation/manifest": "0.4.0", - "@module-federation/rspack": "0.4.0", - "@module-federation/runtime-tools": "0.4.0", - "@module-federation/sdk": "0.4.0", + "version": "0.6.12", + "resolved": "https://registry.npmjs.org/@module-federation/enhanced/-/enhanced-0.6.12.tgz", + "integrity": "sha512-HkcXPbgugcYKq5gFWWh/VSlPYEPEunVFWAINgKPu03YGSTDaFRo9jbvNWA+CR7pFNUOMTg2weudlP10olbvPdQ==", + "dependencies": { + "@module-federation/bridge-react-webpack-plugin": "0.6.12", + "@module-federation/data-prefetch": "0.6.12", + "@module-federation/dts-plugin": "0.6.12", + "@module-federation/managers": "0.6.12", + "@module-federation/manifest": "0.6.12", + "@module-federation/rspack": "0.6.12", + "@module-federation/runtime-tools": "0.6.12", + "@module-federation/sdk": "0.6.12", "btoa": "^1.2.1", "upath": "2.0.1" }, @@ -3003,23 +3421,23 @@ } }, "node_modules/@module-federation/managers": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/@module-federation/managers/-/managers-0.4.0.tgz", - "integrity": "sha512-c4apAaQjwR01qlDSNwPfBBTTzVyErO6POayaRIeAoQMoJLgf+HvL2YFsVPTc4+n8w4lNBMAghPr/BVGlTK9SJQ==", + "version": "0.6.12", + "resolved": "https://registry.npmjs.org/@module-federation/managers/-/managers-0.6.12.tgz", + "integrity": "sha512-86UH9UuGBkoQvUOW7Xgl5PEyTj86YLUfvnj7MBS7p7XEJyFjcg1EwlS+JJGmLx0csovWgNkaUlNveKiZjYIbTQ==", "dependencies": { - "@module-federation/sdk": "0.4.0", + "@module-federation/sdk": "0.6.12", "find-pkg": "2.0.0", "fs-extra": "9.1.0" } }, "node_modules/@module-federation/manifest": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/@module-federation/manifest/-/manifest-0.4.0.tgz", - "integrity": "sha512-TT2H5z3tFtkVarWz6Zsyi4T6wGxxRQjk3O6lSjYrZzWDYyVnrVhAkBgcN9WlkxqSY/V/ifZlTUWUpfSMObRTig==", + "version": "0.6.12", + "resolved": "https://registry.npmjs.org/@module-federation/manifest/-/manifest-0.6.12.tgz", + "integrity": "sha512-blpSrM9mQfV56L7jZAgjWL5xoBeSFxdQtQoiIyrs6CC4v2RCMGVwJeBGyvenwvu+K1sLeWZN2dVU9E+WBqDgnQ==", "dependencies": { - "@module-federation/dts-plugin": "0.4.0", - "@module-federation/managers": "0.4.0", - "@module-federation/sdk": "0.4.0", + "@module-federation/dts-plugin": "0.6.12", + "@module-federation/managers": "0.6.12", + "@module-federation/sdk": "0.6.12", "chalk": "3.0.0", "find-pkg": "2.0.0" } @@ -3037,16 +3455,16 @@ } }, "node_modules/@module-federation/rspack": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/@module-federation/rspack/-/rspack-0.4.0.tgz", - "integrity": "sha512-yPzJwVs/JQcWPw5wy79nEydYAX74TMOJqf4AQijEpdAcE52wWSAm84GymZmAAo55rC74wLGy/DgqQlYNF8WIxw==", + "version": "0.6.12", + "resolved": "https://registry.npmjs.org/@module-federation/rspack/-/rspack-0.6.12.tgz", + "integrity": "sha512-hGduVfTEf7xYcaSOWTJG6Y8SzOEjClImpc8mw6MbysBDf62dK4fWE/1nY+ienHlkMTuONg44DulTUSgh/Aotjw==", "dependencies": { - "@module-federation/bridge-react-webpack-plugin": "0.4.0", - "@module-federation/dts-plugin": "0.4.0", - "@module-federation/managers": "0.4.0", - "@module-federation/manifest": "0.4.0", - "@module-federation/runtime-tools": "0.4.0", - "@module-federation/sdk": "0.4.0" + "@module-federation/bridge-react-webpack-plugin": "0.6.12", + "@module-federation/dts-plugin": "0.6.12", + "@module-federation/managers": "0.6.12", + "@module-federation/manifest": "0.6.12", + "@module-federation/runtime-tools": "0.6.12", + "@module-federation/sdk": "0.6.12" }, "peerDependencies": { "typescript": "^4.9.0 || ^5.0.0", @@ -3062,44 +3480,31 @@ } }, "node_modules/@module-federation/runtime": { - "version": "0.2.8", - "resolved": "https://registry.npmjs.org/@module-federation/runtime/-/runtime-0.2.8.tgz", - "integrity": "sha512-8xmA/+z1zD09F5qU8VnSWLExqTCVWoHOguXsCX79kkqp7i0c+D2YaebWzlQ2kku+DU+0VIzXpQ3BBcumZ3v3wQ==", + "version": "0.6.12", + "resolved": "https://registry.npmjs.org/@module-federation/runtime/-/runtime-0.6.12.tgz", + "integrity": "sha512-zNIhdNc/LcYUqb5guAZRyIGEVQSSALbr7TLuIyzF9eF4jVKBnkOcR/kphaisspkhc467x/mC99/41TzCfAORfA==", "dependencies": { - "@module-federation/sdk": "0.2.8" + "@module-federation/sdk": "0.6.12" } }, "node_modules/@module-federation/runtime-tools": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/@module-federation/runtime-tools/-/runtime-tools-0.4.0.tgz", - "integrity": "sha512-Mr/ewsZbKmv4ZG3FYNrfdgRh5OauJy5IiZ/Z5jtYlNkLfYjUBHSBkh986l/Bpa385+RCCPs3Lg6yFBQlOiYlug==", - "dependencies": { - "@module-federation/runtime": "0.4.0", - "@module-federation/webpack-bundler-runtime": "0.4.0" - } - }, - "node_modules/@module-federation/runtime-tools/node_modules/@module-federation/runtime": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/@module-federation/runtime/-/runtime-0.4.0.tgz", - "integrity": "sha512-zEhMil0JbB0eS1bflV9qOJFJNmDCWMJbKUN7Xw5OMLDnveKTg9l/rLqDGwt/kAP0/Lhq1PNuXEvYm1CeIKKU8A==", + "version": "0.6.12", + "resolved": "https://registry.npmjs.org/@module-federation/runtime-tools/-/runtime-tools-0.6.12.tgz", + "integrity": "sha512-oiTRUZ/Sj+Nw10oheh8EizhYavBfAWCmlScTtjxSFvya2ixt6h4j1Z2EV0SFpylI7WugjkckRNEsUq1UCCCuLQ==", "dependencies": { - "@module-federation/sdk": "0.4.0" + "@module-federation/runtime": "0.6.12", + "@module-federation/webpack-bundler-runtime": "0.6.12" } }, - "node_modules/@module-federation/runtime/node_modules/@module-federation/sdk": { - "version": "0.2.8", - "resolved": "https://registry.npmjs.org/@module-federation/sdk/-/sdk-0.2.8.tgz", - "integrity": "sha512-eGMnJxdRDgt6dtMv8gkAlzEbTPWVHb3AHUNUG0w56wcbIF0RHC6kmvpHpSQyq4DVGWv3U4g/ZiH5BvBlqEelDQ==" - }, "node_modules/@module-federation/sdk": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/@module-federation/sdk/-/sdk-0.4.0.tgz", - "integrity": "sha512-fQ/5aABzksXajRLJsocN9XkW8SOB5JRt7xoDmkFFEeb0HLmcbq5K5GURImPm/jysy0Y7a6DkpxhzP9QJU2Z1Zw==" + "version": "0.6.12", + "resolved": "https://registry.npmjs.org/@module-federation/sdk/-/sdk-0.6.12.tgz", + "integrity": "sha512-QC2uwlnDPxf7OYJAKot0zCJl95VV+iBmvCKGGeXLlzbdBFYIFpmE8IkFBLQqTRxtSKF9hv2z4Zltonu7YjRUdQ==" }, "node_modules/@module-federation/third-party-dts-extractor": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/@module-federation/third-party-dts-extractor/-/third-party-dts-extractor-0.4.0.tgz", - "integrity": "sha512-zXIfgHiOyZFF6rLjHFt0LJ1SgjO5t/UP05HQgIyMvyZ/Q1cQAcNHGy4iLshrPHthh25sJkClAcrfNTw3/JD9xQ==", + "version": "0.6.12", + "resolved": "https://registry.npmjs.org/@module-federation/third-party-dts-extractor/-/third-party-dts-extractor-0.6.12.tgz", + "integrity": "sha512-jhHjd4WYA+Td1c0wK5zYxDEXyZYV4ldIUb2blnE8GuwXRWr5nbdG4RgmPbV7ISyQo6B+uEmE55YIbLeX5r6M5g==", "dependencies": { "find-pkg": "2.0.0", "fs-extra": "9.1.0", @@ -3107,20 +3512,12 @@ } }, "node_modules/@module-federation/webpack-bundler-runtime": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/@module-federation/webpack-bundler-runtime/-/webpack-bundler-runtime-0.4.0.tgz", - "integrity": "sha512-IVwqAuBxvgj2j2HEkV2Q1tDrD9ha6mS0qkBgbtabBjbg8fDc4k+NCmZMB7ou5DCojchqtKXBH2iYNzX062CQ8A==", - "dependencies": { - "@module-federation/runtime": "0.4.0", - "@module-federation/sdk": "0.4.0" - } - }, - "node_modules/@module-federation/webpack-bundler-runtime/node_modules/@module-federation/runtime": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/@module-federation/runtime/-/runtime-0.4.0.tgz", - "integrity": "sha512-zEhMil0JbB0eS1bflV9qOJFJNmDCWMJbKUN7Xw5OMLDnveKTg9l/rLqDGwt/kAP0/Lhq1PNuXEvYm1CeIKKU8A==", + "version": "0.6.12", + "resolved": "https://registry.npmjs.org/@module-federation/webpack-bundler-runtime/-/webpack-bundler-runtime-0.6.12.tgz", + "integrity": "sha512-LeeRualyA6vA2syhzveNK61JFTMixUFu08JD+jW6OcubXN7EV11K8w6IyWemQ5qmM8V2sDjXCebOyZ+TGafSdg==", "dependencies": { - "@module-federation/sdk": "0.4.0" + "@module-federation/runtime": "0.6.12", + "@module-federation/sdk": "0.6.12" } }, "node_modules/@newrelic/publish-sourcemap": { @@ -3170,17 +3567,10 @@ } }, "node_modules/@openedx/paragon": { - "version": "22.8.1", - "resolved": "https://registry.npmjs.org/@openedx/paragon/-/paragon-22.8.1.tgz", - "integrity": "sha512-lm2x0tvNZrtJvp0L+cjvLLmkE9NoUbNIzt9L1FaOx9g92gf8rFVgq4aadq7IVAjN12HW19/QJMEJaQ0SVsvY2A==", + "version": "22.9.0", + "resolved": "https://registry.npmjs.org/@openedx/paragon/-/paragon-22.9.0.tgz", + "integrity": "sha512-r5xD+z64U3phkgT4ooUQaxE/4Rv0D91tpS3kA+mLfOT1vMD8jXIjDZp+/k4BEw4yqWQ8Eyb//ar8xiwL/ugojQ==", "peer": true, - "workspaces": [ - "example", - "component-generator", - "www", - "icons", - "dependent-usage-analyzer" - ], "dependencies": { "@fortawesome/fontawesome-svg-core": "^6.1.1", "@fortawesome/react-fontawesome": "^0.1.18", @@ -3267,25 +3657,325 @@ "resolved": "https://registry.npmjs.org/react-responsive/-/react-responsive-8.2.0.tgz", "integrity": "sha512-iagCqVrw4QSjhxKp3I/YK6+ODkWY6G+YPElvdYKiUUbywwh9Ds0M7r26Fj2/7dWFFbOpcGnJE6uE7aMck8j5Qg==", "peer": true, - "dependencies": { - "hyphenate-style-name": "^1.0.0", - "matchmediaquery": "^0.3.0", - "prop-types": "^15.6.1", - "shallow-equal": "^1.1.0" + "dependencies": { + "hyphenate-style-name": "^1.0.0", + "matchmediaquery": "^0.3.0", + "prop-types": "^15.6.1", + "shallow-equal": "^1.1.0" + }, + "engines": { + "node": ">= 0.10" + }, + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "node_modules/@openedx/paragon/node_modules/shallow-equal": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/shallow-equal/-/shallow-equal-1.2.1.tgz", + "integrity": "sha512-S4vJDjHHMBaiZuT9NPb616CSmLf618jawtv3sufLl6ivK8WocjAo58cXwbRV1cgqxH0Qbv+iUt6m05eqEa2IRA==", + "peer": true + }, + "node_modules/@openedx/paragon/node_modules/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "peer": true, + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/@parcel/watcher": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.4.1.tgz", + "integrity": "sha512-HNjmfLQEVRZmHRET336f20H/8kOozUGwk7yajvsonjNxbj2wBTK1WsQuHkD5yYh9RxFGL2EyDHryOihOwUoKDA==", + "optional": true, + "peer": true, + "dependencies": { + "detect-libc": "^1.0.3", + "is-glob": "^4.0.3", + "micromatch": "^4.0.5", + "node-addon-api": "^7.0.0" + }, + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "@parcel/watcher-android-arm64": "2.4.1", + "@parcel/watcher-darwin-arm64": "2.4.1", + "@parcel/watcher-darwin-x64": "2.4.1", + "@parcel/watcher-freebsd-x64": "2.4.1", + "@parcel/watcher-linux-arm-glibc": "2.4.1", + "@parcel/watcher-linux-arm64-glibc": "2.4.1", + "@parcel/watcher-linux-arm64-musl": "2.4.1", + "@parcel/watcher-linux-x64-glibc": "2.4.1", + "@parcel/watcher-linux-x64-musl": "2.4.1", + "@parcel/watcher-win32-arm64": "2.4.1", + "@parcel/watcher-win32-ia32": "2.4.1", + "@parcel/watcher-win32-x64": "2.4.1" + } + }, + "node_modules/@parcel/watcher-android-arm64": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.4.1.tgz", + "integrity": "sha512-LOi/WTbbh3aTn2RYddrO8pnapixAziFl6SMxHM69r3tvdSm94JtCenaKgk1GRg5FJ5wpMCpHeW+7yqPlvZv7kg==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "android" + ], + "peer": true, + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-darwin-arm64": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.4.1.tgz", + "integrity": "sha512-ln41eihm5YXIY043vBrrHfn94SIBlqOWmoROhsMVTSXGh0QahKGy77tfEywQ7v3NywyxBBkGIfrWRHm0hsKtzA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], + "peer": true, + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-darwin-x64": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.4.1.tgz", + "integrity": "sha512-yrw81BRLjjtHyDu7J61oPuSoeYWR3lDElcPGJyOvIXmor6DEo7/G2u1o7I38cwlcoBHQFULqF6nesIX3tsEXMg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "peer": true, + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-freebsd-x64": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.4.1.tgz", + "integrity": "sha512-TJa3Pex/gX3CWIx/Co8k+ykNdDCLx+TuZj3f3h7eOjgpdKM+Mnix37RYsYU4LHhiYJz3DK5nFCCra81p6g050w==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "freebsd" + ], + "peer": true, + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm-glibc": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.4.1.tgz", + "integrity": "sha512-4rVYDlsMEYfa537BRXxJ5UF4ddNwnr2/1O4MHM5PjI9cvV2qymvhwZSFgXqbS8YoTk5i/JR0L0JDs69BUn45YA==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-glibc": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.4.1.tgz", + "integrity": "sha512-BJ7mH985OADVLpbrzCLgrJ3TOpiZggE9FMblfO65PlOCdG++xJpKUJ0Aol74ZUIYfb8WsRlUdgrZxKkz3zXWYA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-musl": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.4.1.tgz", + "integrity": "sha512-p4Xb7JGq3MLgAfYhslU2SjoV9G0kI0Xry0kuxeG/41UfpjHGOhv7UoUDAz/jb1u2elbhazy4rRBL8PegPJFBhA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-x64-glibc": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.4.1.tgz", + "integrity": "sha512-s9O3fByZ/2pyYDPoLM6zt92yu6P4E39a03zvO0qCHOTjxmt3GHRMLuRZEWhWLASTMSrrnVNWdVI/+pUElJBBBg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-x64-musl": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.4.1.tgz", + "integrity": "sha512-L2nZTYR1myLNST0O632g0Dx9LyMNHrn6TOt76sYxWLdff3cB22/GZX2UPtJnaqQPdCRoszoY5rcOj4oMTtp5fQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-arm64": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.4.1.tgz", + "integrity": "sha512-Uq2BPp5GWhrq/lcuItCHoqxjULU1QYEcyjSO5jqqOK8RNFDBQnenMMx4gAl3v8GiWa59E9+uDM7yZ6LxwUIfRg==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ], + "peer": true, + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-ia32": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.4.1.tgz", + "integrity": "sha512-maNRit5QQV2kgHFSYwftmPBxiuK5u4DXjbXx7q6eKjq5dsLXZ4FJiVvlcw35QXzk0KrUecJmuVFbj4uV9oYrcw==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "win32" + ], + "peer": true, + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-x64": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.4.1.tgz", + "integrity": "sha512-+DvS92F9ezicfswqrvIRM2njcYJbd5mb9CUgtrHCHmvn7pPPa+nMDRu1o1bYYz/l5IB2NVGNJWiH7h1E58IF2A==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "peer": true, + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher/node_modules/detect-libc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", + "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==", + "optional": true, + "peer": true, + "bin": { + "detect-libc": "bin/detect-libc.js" }, "engines": { - "node": ">= 0.10" - }, - "peerDependencies": { - "react": ">=16.8.0" + "node": ">=0.10" } }, - "node_modules/@openedx/paragon/node_modules/shallow-equal": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/shallow-equal/-/shallow-equal-1.2.1.tgz", - "integrity": "sha512-S4vJDjHHMBaiZuT9NPb616CSmLf618jawtv3sufLl6ivK8WocjAo58cXwbRV1cgqxH0Qbv+iUt6m05eqEa2IRA==", - "peer": true - }, "node_modules/@pmmmwh/react-refresh-webpack-plugin": { "version": "0.5.15", "resolved": "https://registry.npmjs.org/@pmmmwh/react-refresh-webpack-plugin/-/react-refresh-webpack-plugin-0.5.15.tgz", @@ -3399,6 +4089,46 @@ "@sinonjs/commons": "^3.0.0" } }, + "node_modules/@stylistic/eslint-plugin": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin/-/eslint-plugin-2.9.0.tgz", + "integrity": "sha512-OrDyFAYjBT61122MIY1a3SfEgy3YCMgt2vL4eoPmvTwDBwyQhAXurxNQznlRD/jESNfYWfID8Ej+31LljvF7Xg==", + "dependencies": { + "@typescript-eslint/utils": "^8.8.0", + "eslint-visitor-keys": "^4.1.0", + "espree": "^10.2.0", + "estraverse": "^5.3.0", + "picomatch": "^4.0.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "peerDependencies": { + "eslint": ">=8.40.0" + } + }, + "node_modules/@stylistic/eslint-plugin/node_modules/eslint-visitor-keys": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.1.0.tgz", + "integrity": "sha512-Q7lok0mqMUSf5a/AdAZkA5a/gHcO6snwQClVNNvFKCAVlxXucdU8pKydU5ZVZjBx5xr37vGbFFWtLQYreLzrZg==", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@stylistic/eslint-plugin/node_modules/picomatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/@testing-library/dom": { "version": "8.20.1", "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-8.20.1.tgz", @@ -3640,14 +4370,22 @@ "integrity": "sha512-LKVP3cgXBT9RYj+t+9FDKwS5tdI+rPBXaNSkma7hvqy35lc7mAokC2zsqWJH0LaqIt3B962nuYI77hsJoT1gow==" }, "node_modules/@types/eslint": { - "version": "8.56.12", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.12.tgz", - "integrity": "sha512-03ruubjWyOHlmljCVoxSuNDdmfZDzsrrz0P2LeJsOXr+ZwFQ+0yQIwNCwt/GYhV7Z31fgtXJTAEs+FYlEL851g==", + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz", + "integrity": "sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==", "dependencies": { "@types/estree": "*", "@types/json-schema": "*" } }, + "node_modules/@types/eslint__js": { + "version": "8.42.3", + "resolved": "https://registry.npmjs.org/@types/eslint__js/-/eslint__js-8.42.3.tgz", + "integrity": "sha512-alfG737uhmPdnvkrLdZLcEKJ/B8s9Y4hrZ+YAdzUeoArBlSUERA2E87ROfOaS4jd/C45fzOoZzidLc1IPwLqOw==", + "dependencies": { + "@types/eslint": "*" + } + }, "node_modules/@types/estree": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", @@ -3766,9 +4504,9 @@ } }, "node_modules/@types/jest": { - "version": "29.5.13", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.13.tgz", - "integrity": "sha512-wd+MVEZCHt23V0/L642O5APvspWply/rGY5BcW4SUETo2UzPU3Z26qr8jC2qxpimI2jjx9h7+2cj2FwIr01bXg==", + "version": "29.5.14", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.14.tgz", + "integrity": "sha512-ZN+4sdnLUbo8EVvVc2ao0GFW6oVrQRPn4K2lglySj7APvSrgzxHiNNK99us4WDMi57xxA2yggblIAMNhXOotLQ==", "dev": true, "dependencies": { "expect": "^29.0.0", @@ -3827,11 +4565,6 @@ "resolved": "https://registry.npmjs.org/@types/json-stable-stringify/-/json-stable-stringify-1.0.36.tgz", "integrity": "sha512-b7bq23s4fgBB76n34m2b3RBf6M369B0Z9uRR8aHTMd8kZISRkmDEpPD8hhpYvDFzr3bJCPES96cm3Q6qRNDbQw==" }, - "node_modules/@types/json5": { - "version": "0.0.29", - "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", - "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==" - }, "node_modules/@types/linkify-it": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-5.0.0.tgz", @@ -3910,9 +4643,9 @@ "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==" }, "node_modules/@types/picomatch": { - "version": "2.3.4", - "resolved": "https://registry.npmjs.org/@types/picomatch/-/picomatch-2.3.4.tgz", - "integrity": "sha512-0so8lU8O5zatZS/2Fi4zrwks+vZv7e0dygrgEZXljODXBig97l4cPQD+9LabXfGJOWwoRkTVz6Q4edZvD12UOA==" + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/picomatch/-/picomatch-3.0.1.tgz", + "integrity": "sha512-1MRgzpzY0hOp9pW/kLRxeQhUWwil6gnrUYd3oEpeYBqp/FexhaCPv3F8LsYr47gtUU45fO2cm1dbwkSrHEo8Uw==" }, "node_modules/@types/prop-types": { "version": "15.7.13", @@ -3958,9 +4691,9 @@ } }, "node_modules/@types/retry": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", - "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==" + "version": "0.12.2", + "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.2.tgz", + "integrity": "sha512-XISRgDJ2Tc5q4TRqvgJtzsRkFYNJzZrhTdtMoGVBttwzzQJkPnS3WWTFc7kuDRoPtPakl+T+OfdEUjYJj7Jbow==" }, "node_modules/@types/scheduler": { "version": "0.16.8", @@ -4056,32 +4789,30 @@ "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==" }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.21.0.tgz", - "integrity": "sha512-oy9+hTPCUFpngkEZUSzbf9MxI65wbKFoQYsgPdILTfbUldp5ovUuphZVe4i30emU9M/kP+T64Di0mxl7dSw3MA==", - "dependencies": { - "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "6.21.0", - "@typescript-eslint/type-utils": "6.21.0", - "@typescript-eslint/utils": "6.21.0", - "@typescript-eslint/visitor-keys": "6.21.0", - "debug": "^4.3.4", + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.11.0.tgz", + "integrity": "sha512-KhGn2LjW1PJT2A/GfDpiyOfS4a8xHQv2myUagTM5+zsormOmBlYsnQ6pobJ8XxJmh6hnHwa2Mbe3fPrDJoDhbA==", + "dependencies": { + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "8.11.0", + "@typescript-eslint/type-utils": "8.11.0", + "@typescript-eslint/utils": "8.11.0", + "@typescript-eslint/visitor-keys": "8.11.0", "graphemer": "^1.4.0", - "ignore": "^5.2.4", + "ignore": "^5.3.1", "natural-compare": "^1.4.0", - "semver": "^7.5.4", - "ts-api-utils": "^1.0.1" + "ts-api-utils": "^1.3.0" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^6.0.0 || ^6.0.0-alpha", - "eslint": "^7.0.0 || ^8.0.0" + "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", + "eslint": "^8.57.0 || ^9.0.0" }, "peerDependenciesMeta": { "typescript": { @@ -4089,37 +4820,26 @@ } } }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/semver": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/@typescript-eslint/parser": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.21.0.tgz", - "integrity": "sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ==", - "dependencies": { - "@typescript-eslint/scope-manager": "6.21.0", - "@typescript-eslint/types": "6.21.0", - "@typescript-eslint/typescript-estree": "6.21.0", - "@typescript-eslint/visitor-keys": "6.21.0", + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.11.0.tgz", + "integrity": "sha512-lmt73NeHdy1Q/2ul295Qy3uninSqi6wQI18XwSpm8w0ZbQXUpjCAWP1Vlv/obudoBiIjJVjlztjQ+d/Md98Yxg==", + "dependencies": { + "@typescript-eslint/scope-manager": "8.11.0", + "@typescript-eslint/types": "8.11.0", + "@typescript-eslint/typescript-estree": "8.11.0", + "@typescript-eslint/visitor-keys": "8.11.0", "debug": "^4.3.4" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" + "eslint": "^8.57.0 || ^9.0.0" }, "peerDependenciesMeta": { "typescript": { @@ -4128,15 +4848,15 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.21.0.tgz", - "integrity": "sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg==", + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.11.0.tgz", + "integrity": "sha512-Uholz7tWhXmA4r6epo+vaeV7yjdKy5QFCERMjs1kMVsLRKIrSdM6o21W2He9ftp5PP6aWOVpD5zvrvuHZC0bMQ==", "dependencies": { - "@typescript-eslint/types": "6.21.0", - "@typescript-eslint/visitor-keys": "6.21.0" + "@typescript-eslint/types": "8.11.0", + "@typescript-eslint/visitor-keys": "8.11.0" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", @@ -4144,25 +4864,22 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.21.0.tgz", - "integrity": "sha512-rZQI7wHfao8qMX3Rd3xqeYSMCL3SoiSQLBATSiVKARdFGCYSRvmViieZjqc58jKgs8Y8i9YvVVhRbHSTA4VBag==", + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.11.0.tgz", + "integrity": "sha512-ItiMfJS6pQU0NIKAaybBKkuVzo6IdnAhPFZA/2Mba/uBjuPQPet/8+zh5GtLHwmuFRShZx+8lhIs7/QeDHflOg==", "dependencies": { - "@typescript-eslint/typescript-estree": "6.21.0", - "@typescript-eslint/utils": "6.21.0", + "@typescript-eslint/typescript-estree": "8.11.0", + "@typescript-eslint/utils": "8.11.0", "debug": "^4.3.4", - "ts-api-utils": "^1.0.1" + "ts-api-utils": "^1.3.0" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, - "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" - }, "peerDependenciesMeta": { "typescript": { "optional": true @@ -4170,11 +4887,11 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.21.0.tgz", - "integrity": "sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg==", + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.11.0.tgz", + "integrity": "sha512-tn6sNMHf6EBAYMvmPUaKaVeYvhUsrE6x+bXQTxjQRp360h1giATU0WvgeEys1spbvb5R+VpNOZ+XJmjD8wOUHw==", "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", @@ -4182,21 +4899,21 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.21.0.tgz", - "integrity": "sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ==", + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.11.0.tgz", + "integrity": "sha512-yHC3s1z1RCHoCz5t06gf7jH24rr3vns08XXhfEqzYpd6Hll3z/3g23JRi0jM8A47UFKNc3u/y5KIMx8Ynbjohg==", "dependencies": { - "@typescript-eslint/types": "6.21.0", - "@typescript-eslint/visitor-keys": "6.21.0", + "@typescript-eslint/types": "8.11.0", + "@typescript-eslint/visitor-keys": "8.11.0", "debug": "^4.3.4", - "globby": "^11.1.0", + "fast-glob": "^3.3.2", "is-glob": "^4.0.3", - "minimatch": "9.0.3", - "semver": "^7.5.4", - "ts-api-utils": "^1.0.1" + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", @@ -4208,6 +4925,20 @@ } } }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { "version": "7.6.3", "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", @@ -4220,50 +4951,36 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.21.0.tgz", - "integrity": "sha512-NfWVaC8HP9T8cbKQxHcsJBY5YE1O33+jpMwN45qzWWaPDZgLIbo12toGMWnmhvCpd3sIxkpDw3Wv1B3dYrbDQQ==", + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.11.0.tgz", + "integrity": "sha512-CYiX6WZcbXNJV7UNB4PLDIBtSdRmRI/nb0FMyqHPTQD1rMjA0foPLaPUV39C/MxkTd/QKSeX+Gb34PPsDVC35g==", "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@types/json-schema": "^7.0.12", - "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "6.21.0", - "@typescript-eslint/types": "6.21.0", - "@typescript-eslint/typescript-estree": "6.21.0", - "semver": "^7.5.4" + "@typescript-eslint/scope-manager": "8.11.0", + "@typescript-eslint/types": "8.11.0", + "@typescript-eslint/typescript-estree": "8.11.0" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" - } - }, - "node_modules/@typescript-eslint/utils/node_modules/semver": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" + "eslint": "^8.57.0 || ^9.0.0" } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.21.0.tgz", - "integrity": "sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A==", + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.11.0.tgz", + "integrity": "sha512-EaewX6lxSjRJnc+99+dqzTeoDZUfyrA52d2/HRrkI830kgovWsmIiTfmr0NZorzqic7ga+1bS60lRBUgR3n/Bw==", "dependencies": { - "@typescript-eslint/types": "6.21.0", - "eslint-visitor-keys": "^3.4.1" + "@typescript-eslint/types": "8.11.0", + "eslint-visitor-keys": "^3.4.3" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", @@ -4728,6 +5445,7 @@ "version": "5.1.3", "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.1.3.tgz", "integrity": "sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==", + "dev": true, "dependencies": { "deep-equal": "^2.0.5" } @@ -4787,6 +5505,25 @@ "node": ">=0.10.0" } }, + "node_modules/array.prototype.findlast": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz", + "integrity": "sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/array.prototype.flat": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz", @@ -4864,9 +5601,9 @@ "peer": true }, "node_modules/ast-types-flow": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz", - "integrity": "sha512-eBvWn1lvIApYMhzQMsu9ciLfkBY499mFZlNqG+/9WR7PVlroQw0vG30cOQQbaKz3sCEc44TAOu2ykzqXSNnwag==" + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.8.tgz", + "integrity": "sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==" }, "node_modules/asynckit": { "version": "0.4.0", @@ -4891,9 +5628,9 @@ } }, "node_modules/autoprefixer": { - "version": "10.4.19", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.19.tgz", - "integrity": "sha512-BaENR2+zBZ8xXhM4pUaKUxlVdxZ0EZhjvbopwnXmxRUfqDmwSpC2lAi/QXvx7NRdPCo1WKEcEF6mV64si1z4Ew==", + "version": "10.4.20", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.20.tgz", + "integrity": "sha512-XY25y5xSv/wEoqzDyXXME4AFfkZI0P23z6Fs3YgymDnKJkCGOnkL0iTxCa85UTqaSgfcqyf3UA6+c7wUvx/16g==", "funding": [ { "type": "opencollective", @@ -4909,11 +5646,11 @@ } ], "dependencies": { - "browserslist": "^4.23.0", - "caniuse-lite": "^1.0.30001599", + "browserslist": "^4.23.3", + "caniuse-lite": "^1.0.30001646", "fraction.js": "^4.3.7", "normalize-range": "^0.1.2", - "picocolors": "^1.0.0", + "picocolors": "^1.0.1", "postcss-value-parser": "^4.2.0" }, "bin": { @@ -4941,9 +5678,9 @@ } }, "node_modules/axe-core": { - "version": "4.10.0", - "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.10.0.tgz", - "integrity": "sha512-Mr2ZakwQ7XUAjp7pAwQWRhhK8mQQ6JAaNWSjmjxil0R8BPioMtQsTLOolGYkji1rcL++3dCqZA3zWqpT+9Ew6g==", + "version": "4.10.2", + "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.10.2.tgz", + "integrity": "sha512-RE3mdQ7P3FRSe7eqCWoeQ/Z9QXrtniSjp1wUjt5nRC3WIpz5rSCve6o3fsZ2aCpJtrZjSZgjwXAoTO5k4tEI0w==", "engines": { "node": ">=4" } @@ -4991,18 +5728,13 @@ } }, "node_modules/axobject-query": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-3.2.4.tgz", - "integrity": "sha512-aPTElBrbifBU1krmZxGZOlBkslORe7Ll7+BDnI50Wy4LgOt69luMgevkDfTq1O/ZgprooPCtWpjCwKSZw/iZ4A==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz", + "integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==", "engines": { "node": ">= 0.4" } }, - "node_modules/b4a": { - "version": "1.6.7", - "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.7.tgz", - "integrity": "sha512-OnAYlL5b7LEkALw87fUVafQw5rVR9RjwGd4KUwNQ6DrrNmaVaUCgLipfVlzrPQ4tWOR9P0IXGNOx50jYCCdSJg==" - }, "node_modules/babel-jest": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz", @@ -5151,48 +5883,6 @@ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, - "node_modules/bare-events": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.5.0.tgz", - "integrity": "sha512-/E8dDe9dsbLyh2qrZ64PEPadOQ0F4gbl1sUJOrmph7xOiIxfY8vwab/4bFLh4Y88/Hk/ujKcrQKc+ps0mv873A==", - "optional": true - }, - "node_modules/bare-fs": { - "version": "2.3.5", - "resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-2.3.5.tgz", - "integrity": "sha512-SlE9eTxifPDJrT6YgemQ1WGFleevzwY+XAP1Xqgl56HtcrisC2CHCZ2tq6dBpcH2TnNxwUEUGhweo+lrQtYuiw==", - "optional": true, - "dependencies": { - "bare-events": "^2.0.0", - "bare-path": "^2.0.0", - "bare-stream": "^2.0.0" - } - }, - "node_modules/bare-os": { - "version": "2.4.4", - "resolved": "https://registry.npmjs.org/bare-os/-/bare-os-2.4.4.tgz", - "integrity": "sha512-z3UiI2yi1mK0sXeRdc4O1Kk8aOa/e+FNWZcTiPB/dfTWyLypuE99LibgRaQki914Jq//yAWylcAt+mknKdixRQ==", - "optional": true - }, - "node_modules/bare-path": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/bare-path/-/bare-path-2.1.3.tgz", - "integrity": "sha512-lh/eITfU8hrj9Ru5quUp0Io1kJWIk1bTjzo7JH1P5dWmQ2EL4hFUlfI8FonAhSlgIfhn63p84CDY/x+PisgcXA==", - "optional": true, - "dependencies": { - "bare-os": "^2.1.0" - } - }, - "node_modules/bare-stream": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-2.3.0.tgz", - "integrity": "sha512-pVRWciewGUeCyKEuRxwv06M079r+fRjAQjBEK2P6OYGrO43O+Z0LrPZZEjlc4mB6C2RpZ9AxJ1s7NLEtOHO6eA==", - "optional": true, - "dependencies": { - "b4a": "^1.6.6", - "streamx": "^2.20.0" - } - }, "node_modules/base64-js": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", @@ -5210,7 +5900,8 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "peer": true }, "node_modules/batch": { "version": "0.6.1", @@ -5240,6 +5931,7 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "peer": true, "dependencies": { "buffer": "^5.5.0", "inherits": "^2.0.4", @@ -5417,16 +6109,36 @@ "url": "https://feross.org/support" } ], + "peer": true, "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.1.13" } }, + "node_modules/buffer-builder": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/buffer-builder/-/buffer-builder-0.2.0.tgz", + "integrity": "sha512-7VPMEPuYznPSoR21NE1zvd2Xna6c/CloiZCfcMXR1Jny6PjX0N4Nsa38zcBFo/FMK+BlA+FLKbJCQ0i2yxp+Xg==" + }, "node_modules/buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" }, + "node_modules/bundle-name": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.0.tgz", + "integrity": "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==", + "dependencies": { + "run-applescript": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/bytes": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", @@ -5621,11 +6333,6 @@ "node": ">= 6" } }, - "node_modules/chownr": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", - "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" - }, "node_modules/chrome-trace-event": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz", @@ -5833,6 +6540,11 @@ "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==" }, + "node_modules/colorjs.io": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/colorjs.io/-/colorjs.io-0.5.2.tgz", + "integrity": "sha512-twmVoizEW7ylZSN32OgKdXRmo1qg+wT5/6C3xu5b9QsWzSFAhHLn2xd8ro0diCsKfCj1RdaTP/nrcW+vAoQPIw==" + }, "node_modules/combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", @@ -5906,11 +6618,6 @@ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" }, - "node_modules/confusing-browser-globals": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.11.tgz", - "integrity": "sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA==" - }, "node_modules/connect-history-api-fallback": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz", @@ -5963,9 +6670,9 @@ "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==" }, "node_modules/cookie": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", - "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", + "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", "engines": { "node": ">= 0.6" } @@ -6116,47 +6823,37 @@ } }, "node_modules/css-loader": { - "version": "5.2.7", - "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-5.2.7.tgz", - "integrity": "sha512-Q7mOvpBNBG7YrVGMxRxcBJZFL75o+cH2abNASdibkj/fffYD8qWbInZrD0S9ccI6vZclF3DsHE7njGlLtaHbhg==", + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-7.1.2.tgz", + "integrity": "sha512-6WvYYn7l/XEGN8Xu2vWFt9nVzrCn39vKyTEFf/ExEyoksJjjSZV/0/35XPlMbpnr6VGhZIUg5yJrL8tGfes/FA==", "dependencies": { "icss-utils": "^5.1.0", - "loader-utils": "^2.0.0", - "postcss": "^8.2.15", - "postcss-modules-extract-imports": "^3.0.0", - "postcss-modules-local-by-default": "^4.0.0", - "postcss-modules-scope": "^3.0.0", + "postcss": "^8.4.33", + "postcss-modules-extract-imports": "^3.1.0", + "postcss-modules-local-by-default": "^4.0.5", + "postcss-modules-scope": "^3.2.0", "postcss-modules-values": "^4.0.0", - "postcss-value-parser": "^4.1.0", - "schema-utils": "^3.0.0", - "semver": "^7.3.5" + "postcss-value-parser": "^4.2.0", + "semver": "^7.5.4" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 18.12.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/webpack" }, "peerDependencies": { - "webpack": "^4.27.0 || ^5.0.0" - } - }, - "node_modules/css-loader/node_modules/schema-utils": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", - "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", - "dependencies": { - "@types/json-schema": "^7.0.8", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" - }, - "engines": { - "node": ">= 10.13.0" + "@rspack/core": "0.x || 1.x", + "webpack": "^5.27.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + }, + "webpack": { + "optional": true + } } }, "node_modules/css-loader/node_modules/semver": { @@ -6231,12 +6928,12 @@ } }, "node_modules/cssnano": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-6.0.3.tgz", - "integrity": "sha512-MRq4CIj8pnyZpcI2qs6wswoYoDD1t0aL28n+41c1Ukcpm56m1h6mCexIHBGjfZfnTqtGSSCP4/fB1ovxgjBOiw==", + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-6.1.2.tgz", + "integrity": "sha512-rYk5UeX7VAM/u0lNqewCdasdtPK81CgX8wJFLEIXHbV2oldWRgJAsZrdhRXkV1NJzA2g850KiFm9mMU2HxNxMA==", "dependencies": { - "cssnano-preset-default": "^6.0.3", - "lilconfig": "^3.0.0" + "cssnano-preset-default": "^6.1.2", + "lilconfig": "^3.1.1" }, "engines": { "node": "^14 || ^16 || >=18.0" @@ -6468,20 +7165,6 @@ "node": ">=0.10" } }, - "node_modules/decompress-response": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", - "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", - "dependencies": { - "mimic-response": "^3.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/dedent": { "version": "1.5.3", "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.3.tgz", @@ -6499,6 +7182,7 @@ "version": "2.2.3", "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.3.tgz", "integrity": "sha512-ZIwpnevOurS8bpT4192sqAowWM76JDKSHYzMLty3BZGSswgq6pBaH3DhCSW5xVAZICZyKdOBPjwww5wfgT/6PA==", + "dev": true, "dependencies": { "array-buffer-byte-length": "^1.0.0", "call-bind": "^1.0.5", @@ -6526,14 +7210,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "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==", - "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", @@ -6547,15 +7223,30 @@ "node": ">=0.10.0" } }, - "node_modules/default-gateway": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz", - "integrity": "sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==", + "node_modules/default-browser": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.2.1.tgz", + "integrity": "sha512-WY/3TUME0x3KPYdRRxEJJvXRHV4PyPoUsxtZa78lwItwRQRHhd2U9xOscaT/YTf8uCXIAjeJOFBVEh/7FtD8Xg==", "dependencies": { - "execa": "^5.0.0" + "bundle-name": "^4.1.0", + "default-browser-id": "^5.0.0" }, "engines": { - "node": ">= 10" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-browser-id": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-5.0.0.tgz", + "integrity": "sha512-A6p/pu/6fyBcA1TRz/GqWYPViplrftcW2gZC9q79ngNCKAeR/X3gcEdXQHl4KNXV+3wgIJ1CPkJQ3IHM6lcsyA==", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/defaults": { @@ -6755,11 +7446,6 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, - "node_modules/diacritics": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/diacritics/-/diacritics-1.3.0.tgz", - "integrity": "sha512-wlwEkqcsaxvPJML+rDh/2iS824jbREk6DUMUKkEaSlxdYHeS43cClJtsWglvw2RfeXGm6ohKDqsXteJ5sP5enA==" - }, "node_modules/diff-sequences": { "version": "29.6.3", "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", @@ -6791,14 +7477,14 @@ } }, "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", "dependencies": { "esutils": "^2.0.2" }, "engines": { - "node": ">=6.0.0" + "node": ">=0.10.0" } }, "node_modules/dom-accessibility-api": { @@ -6969,14 +7655,6 @@ "node": ">= 0.8" } }, - "node_modules/end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "dependencies": { - "once": "^1.4.0" - } - }, "node_modules/enhanced-resolve": { "version": "5.17.1", "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz", @@ -7109,6 +7787,7 @@ "version": "1.1.3", "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.3.tgz", "integrity": "sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==", + "dev": true, "dependencies": { "call-bind": "^1.0.2", "get-intrinsic": "^1.1.3", @@ -7124,6 +7803,30 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/es-iterator-helpers": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.1.0.tgz", + "integrity": "sha512-/SurEfycdyssORP/E+bj4sEu1CWw4EmLDsHynHwSXQ7utgbrMRWW195pTrCjFgFCddf/UkYm3oqKPRq5i8bJbw==", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.3", + "es-errors": "^1.3.0", + "es-set-tostringtag": "^2.0.3", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "globalthis": "^1.0.4", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.0.3", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.7", + "iterator.prototype": "^1.1.3", + "safe-array-concat": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/es-module-lexer": { "version": "1.5.4", "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.4.tgz", @@ -7231,283 +7934,211 @@ } }, "node_modules/eslint": { - "version": "8.44.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.44.0.tgz", - "integrity": "sha512-0wpHoUbDUHgNCyvFB5aXLiQVfK9B0at6gUvzy83k4kAsQ/u769TQDX6iKC+aO4upIHO9WSaA3QoXYQDHbNwf1A==", + "version": "9.13.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.13.0.tgz", + "integrity": "sha512-EYZK6SX6zjFHST/HRytOdA/zE72Cq/bfw45LSyuwrdvcclb/gqV8RRQxywOBEWO2+WDpva6UZa4CcDeJKzUCFA==", "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.4.0", - "@eslint/eslintrc": "^2.1.0", - "@eslint/js": "8.44.0", - "@humanwhocodes/config-array": "^0.11.10", + "@eslint-community/regexpp": "^4.11.0", + "@eslint/config-array": "^0.18.0", + "@eslint/core": "^0.7.0", + "@eslint/eslintrc": "^3.1.0", + "@eslint/js": "9.13.0", + "@eslint/plugin-kit": "^0.2.0", + "@humanfs/node": "^0.16.5", "@humanwhocodes/module-importer": "^1.0.1", - "@nodelib/fs.walk": "^1.2.8", - "ajv": "^6.10.0", + "@humanwhocodes/retry": "^0.3.1", + "@types/estree": "^1.0.6", + "@types/json-schema": "^7.0.15", + "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", "debug": "^4.3.2", - "doctrine": "^3.0.0", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.2.0", - "eslint-visitor-keys": "^3.4.1", - "espree": "^9.6.0", - "esquery": "^1.4.2", + "eslint-scope": "^8.1.0", + "eslint-visitor-keys": "^4.1.0", + "espree": "^10.2.0", + "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", + "file-entry-cache": "^8.0.0", "find-up": "^5.0.0", "glob-parent": "^6.0.2", - "globals": "^13.19.0", - "graphemer": "^1.4.0", "ignore": "^5.2.0", - "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", - "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", "optionator": "^0.9.3", - "strip-ansi": "^6.0.1", - "strip-json-comments": "^3.1.0", "text-table": "^0.2.0" }, "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-config-airbnb": { - "version": "19.0.4", - "resolved": "https://registry.npmjs.org/eslint-config-airbnb/-/eslint-config-airbnb-19.0.4.tgz", - "integrity": "sha512-T75QYQVQX57jiNgpF9r1KegMICE94VYwoFQyMGhrvc+lB8YF2E/M/PYDaQe1AJcWaEgqLE+ErXV1Og/+6Vyzew==", - "dependencies": { - "eslint-config-airbnb-base": "^15.0.0", - "object.assign": "^4.1.2", - "object.entries": "^1.1.5" - }, - "engines": { - "node": "^10.12.0 || ^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "peerDependencies": { - "eslint": "^7.32.0 || ^8.2.0", - "eslint-plugin-import": "^2.25.3", - "eslint-plugin-jsx-a11y": "^6.5.1", - "eslint-plugin-react": "^7.28.0", - "eslint-plugin-react-hooks": "^4.3.0" - } - }, - "node_modules/eslint-config-airbnb-base": { - "version": "15.0.0", - "resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-15.0.0.tgz", - "integrity": "sha512-xaX3z4ZZIcFLvh2oUNvcX5oEofXda7giYmuplVxoOg5A7EXJMrUyqRgR+mhDhPK8LZ4PttFOBvCYDbX3sUoUig==", - "dependencies": { - "confusing-browser-globals": "^1.0.10", - "object.assign": "^4.1.2", - "object.entries": "^1.1.5", - "semver": "^6.3.0" + "eslint": "bin/eslint.js" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, - "peerDependencies": { - "eslint": "^7.32.0 || ^8.2.0", - "eslint-plugin-import": "^2.25.2" - } - }, - "node_modules/eslint-config-airbnb-typescript": { - "version": "17.1.0", - "resolved": "https://registry.npmjs.org/eslint-config-airbnb-typescript/-/eslint-config-airbnb-typescript-17.1.0.tgz", - "integrity": "sha512-GPxI5URre6dDpJ0CtcthSZVBAfI+Uw7un5OYNVxP2EYi3H81Jw701yFP7AU+/vCE7xBtFmjge7kfhhk4+RAiig==", - "dependencies": { - "eslint-config-airbnb-base": "^15.0.0" + "funding": { + "url": "https://eslint.org/donate" }, "peerDependencies": { - "@typescript-eslint/eslint-plugin": "^5.13.0 || ^6.0.0", - "@typescript-eslint/parser": "^5.0.0 || ^6.0.0", - "eslint": "^7.32.0 || ^8.2.0", - "eslint-plugin-import": "^2.25.3" - } - }, - "node_modules/eslint-import-resolver-node": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", - "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==", - "dependencies": { - "debug": "^3.2.7", - "is-core-module": "^2.13.0", - "resolve": "^1.22.4" - } - }, - "node_modules/eslint-import-resolver-node/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/eslint-module-utils": { - "version": "2.11.1", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.11.1.tgz", - "integrity": "sha512-EwcbfLOhwVMAfatfqLecR2yv3dE5+kQ8kx+Rrt0DvDXEVwW86KQ/xbMDQhtp5l42VXukD5SOF8mQQHbaNtO0CQ==", - "dependencies": { - "debug": "^3.2.7" - }, - "engines": { - "node": ">=4" + "jiti": "*" }, "peerDependenciesMeta": { - "eslint": { + "jiti": { "optional": true } } }, - "node_modules/eslint-module-utils/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dependencies": { - "ms": "^2.1.1" - } - }, "node_modules/eslint-plugin-formatjs": { - "version": "4.13.3", - "resolved": "https://registry.npmjs.org/eslint-plugin-formatjs/-/eslint-plugin-formatjs-4.13.3.tgz", - "integrity": "sha512-4j3IVwaLEXblnvH2/ZIOZwc9zaaZf2+zyn/b8oLJRt6kMCTu2rIs4UsIxy5nBRYZzsBSh7k34JJ5/ngGtJ3kYw==", - "dependencies": { - "@formatjs/icu-messageformat-parser": "2.7.8", - "@formatjs/ts-transformer": "3.13.14", - "@types/eslint": "7 || 8", - "@types/picomatch": "^2.3.0", - "@typescript-eslint/utils": "^6.18.1", - "emoji-regex": "^10.2.1", + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-formatjs/-/eslint-plugin-formatjs-5.1.3.tgz", + "integrity": "sha512-6PweMZPBPFX4Corrn2PoKGKPdiUiHabvOts76XuW9//UWSybUUBBqmPtdc+GUTOurv3/kkowBE7r7XsJ1KaSaw==", + "dependencies": { + "@formatjs/icu-messageformat-parser": "2.8.0", + "@formatjs/ts-transformer": "3.13.18", + "@types/eslint": "9", + "@types/picomatch": "3", + "@typescript-eslint/utils": "8.11.0", + "emoji-regex": "10", "magic-string": "^0.30.0", - "picomatch": "^2.3.1", - "tslib": "2.6.2", + "picomatch": "2 || 3 || 4", + "tslib": "^2.7.0", "typescript": "5", "unicode-emoji-utils": "^1.2.0" }, "peerDependencies": { - "eslint": "7 || 8" + "eslint": "9" } }, - "node_modules/eslint-plugin-formatjs/node_modules/tslib": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", - "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" + "node_modules/eslint-plugin-formatjs/node_modules/@formatjs/ecma402-abstract": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@formatjs/ecma402-abstract/-/ecma402-abstract-2.2.0.tgz", + "integrity": "sha512-IpM+ev1E4QLtstniOE29W1rqH9eTdx5hQdNL8pzrflMj/gogfaoONZqL83LUeQScHAvyMbpqP5C9MzNf+fFwhQ==", + "dependencies": { + "@formatjs/fast-memoize": "2.2.1", + "@formatjs/intl-localematcher": "0.5.5", + "tslib": "^2.7.0" + } }, - "node_modules/eslint-plugin-import": { - "version": "2.27.5", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.27.5.tgz", - "integrity": "sha512-LmEt3GVofgiGuiE+ORpnvP+kAm3h6MLZJ4Q5HCyHADofsb4VzXFsRiWj3c0OFiV+3DWFh0qg3v9gcPlfc3zRow==", + "node_modules/eslint-plugin-formatjs/node_modules/@formatjs/fast-memoize": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@formatjs/fast-memoize/-/fast-memoize-2.2.1.tgz", + "integrity": "sha512-XS2RcOSyWxmUB7BUjj3mlPH0exsUzlf6QfhhijgI941WaJhVxXQ6mEWkdUFIdnKi3TuTYxRdelsgv3mjieIGIA==", "dependencies": { - "array-includes": "^3.1.6", - "array.prototype.flat": "^1.3.1", - "array.prototype.flatmap": "^1.3.1", - "debug": "^3.2.7", - "doctrine": "^2.1.0", - "eslint-import-resolver-node": "^0.3.7", - "eslint-module-utils": "^2.7.4", - "has": "^1.0.3", - "is-core-module": "^2.11.0", - "is-glob": "^4.0.3", - "minimatch": "^3.1.2", - "object.values": "^1.1.6", - "resolve": "^1.22.1", - "semver": "^6.3.0", - "tsconfig-paths": "^3.14.1" - }, - "engines": { - "node": ">=4" - }, - "peerDependencies": { - "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" + "tslib": "^2.7.0" } }, - "node_modules/eslint-plugin-import/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "node_modules/eslint-plugin-formatjs/node_modules/@formatjs/icu-messageformat-parser": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-2.8.0.tgz", + "integrity": "sha512-r2un3fmF9oJv3mOkH+wwQZ037VpqmdfahbcCZ9Lh+p6Sx+sNsonI7Zcr6jNMm1s+Si7ejQORS4Ezlh05mMPAXA==", "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "@formatjs/ecma402-abstract": "2.2.0", + "@formatjs/icu-skeleton-parser": "1.8.4", + "tslib": "^2.7.0" } }, - "node_modules/eslint-plugin-import/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "node_modules/eslint-plugin-formatjs/node_modules/@formatjs/icu-skeleton-parser": { + "version": "1.8.4", + "resolved": "https://registry.npmjs.org/@formatjs/icu-skeleton-parser/-/icu-skeleton-parser-1.8.4.tgz", + "integrity": "sha512-LMQ1+Wk1QSzU4zpd5aSu7+w5oeYhupRwZnMQckLPRYhSjf2/8JWQ882BauY9NyHxs5igpuQIXZDgfkaH3PoATg==", "dependencies": { - "ms": "^2.1.1" + "@formatjs/ecma402-abstract": "2.2.0", + "tslib": "^2.7.0" } }, - "node_modules/eslint-plugin-import/node_modules/doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "node_modules/eslint-plugin-formatjs/node_modules/@formatjs/intl-localematcher": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/@formatjs/intl-localematcher/-/intl-localematcher-0.5.5.tgz", + "integrity": "sha512-t5tOGMgZ/i5+ALl2/offNqAQq/lfUnKLEw0mXQI4N4bqpedhrSE+fyKLpwnd22sK0dif6AV+ufQcTsKShB9J1g==", "dependencies": { - "esutils": "^2.0.2" + "tslib": "^2.7.0" + } + }, + "node_modules/eslint-plugin-formatjs/node_modules/@formatjs/ts-transformer": { + "version": "3.13.18", + "resolved": "https://registry.npmjs.org/@formatjs/ts-transformer/-/ts-transformer-3.13.18.tgz", + "integrity": "sha512-bRUJsYLJ4n7GcKAa3a05ePmlsJPum0whNzqr4scUazH6DNr5twLLd2qzmQ9Qu4DDSA/l5X7+ZyuawYxYIpmpAQ==", + "dependencies": { + "@formatjs/icu-messageformat-parser": "2.8.0", + "@types/json-stable-stringify": "1", + "@types/node": "14 || 16 || 17 || 18 || 20", + "chalk": "4", + "json-stable-stringify": "1", + "tslib": "^2.7.0", + "typescript": "5" }, - "engines": { - "node": ">=0.10.0" + "peerDependencies": { + "ts-jest": ">=27" + }, + "peerDependenciesMeta": { + "ts-jest": { + "optional": true + } } }, - "node_modules/eslint-plugin-import/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "node_modules/eslint-plugin-jest": { + "version": "28.8.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-28.8.3.tgz", + "integrity": "sha512-HIQ3t9hASLKm2IhIOqnu+ifw7uLZkIlR7RYNv7fMcEi/p0CIiJmfriStQS2LDkgtY4nyLbIZAD+JL347Yc2ETQ==", "dependencies": { - "brace-expansion": "^1.1.7" + "@typescript-eslint/utils": "^6.0.0 || ^7.0.0 || ^8.0.0" }, "engines": { - "node": "*" + "node": "^16.10.0 || ^18.12.0 || >=20.0.0" + }, + "peerDependencies": { + "@typescript-eslint/eslint-plugin": "^6.0.0 || ^7.0.0 || ^8.0.0", + "eslint": "^7.0.0 || ^8.0.0 || ^9.0.0", + "jest": "*" + }, + "peerDependenciesMeta": { + "@typescript-eslint/eslint-plugin": { + "optional": true + }, + "jest": { + "optional": true + } } }, "node_modules/eslint-plugin-jsx-a11y": { - "version": "6.7.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.7.1.tgz", - "integrity": "sha512-63Bog4iIethyo8smBklORknVjB0T2dwB8Mr/hIC+fBS0uyHdYYpzM/Ed+YC8VxTjlXHEWFOdmgwcDn1U2L9VCA==", - "dependencies": { - "@babel/runtime": "^7.20.7", - "aria-query": "^5.1.3", - "array-includes": "^3.1.6", - "array.prototype.flatmap": "^1.3.1", - "ast-types-flow": "^0.0.7", - "axe-core": "^4.6.2", - "axobject-query": "^3.1.1", + "version": "6.10.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.10.1.tgz", + "integrity": "sha512-zHByM9WTUMnfsDTafGXRiqxp6lFtNoSOWBY6FonVRn3A+BUwN1L/tdBXT40BcBJi0cZjOGTXZ0eD/rTG9fEJ0g==", + "dependencies": { + "aria-query": "^5.3.2", + "array-includes": "^3.1.8", + "array.prototype.flatmap": "^1.3.2", + "ast-types-flow": "^0.0.8", + "axe-core": "^4.10.0", + "axobject-query": "^4.1.0", "damerau-levenshtein": "^1.0.8", "emoji-regex": "^9.2.2", - "has": "^1.0.3", - "jsx-ast-utils": "^3.3.3", - "language-tags": "=1.0.5", + "es-iterator-helpers": "^1.1.0", + "hasown": "^2.0.2", + "jsx-ast-utils": "^3.3.5", + "language-tags": "^1.0.9", "minimatch": "^3.1.2", - "object.entries": "^1.1.6", - "object.fromentries": "^2.0.6", - "semver": "^6.3.0" + "object.fromentries": "^2.0.8", + "safe-regex-test": "^1.0.3", + "string.prototype.includes": "^2.0.1" }, "engines": { "node": ">=4.0" }, "peerDependencies": { - "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9" } }, - "node_modules/eslint-plugin-jsx-a11y/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "node_modules/eslint-plugin-jsx-a11y/node_modules/aria-query": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.2.tgz", + "integrity": "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==", + "engines": { + "node": ">= 0.4" } }, "node_modules/eslint-plugin-jsx-a11y/node_modules/emoji-regex": { @@ -7515,85 +8146,46 @@ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" }, - "node_modules/eslint-plugin-jsx-a11y/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, "node_modules/eslint-plugin-react": { - "version": "7.32.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.32.2.tgz", - "integrity": "sha512-t2fBMa+XzonrrNkyVirzKlvn5RXzzPwRHtMvLAtVZrt8oxgnTQaYbU6SXTOO1mwQgp1y5+toMSKInnzGr0Knqg==", - "dependencies": { - "array-includes": "^3.1.6", - "array.prototype.flatmap": "^1.3.1", - "array.prototype.tosorted": "^1.1.1", + "version": "7.37.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.2.tgz", + "integrity": "sha512-EsTAnj9fLVr/GZleBLFbj/sSuXeWmp1eXIN60ceYnZveqEaUCyW4X+Vh4WTdUhCkW4xutXYqTXCUSyqD4rB75w==", + "dependencies": { + "array-includes": "^3.1.8", + "array.prototype.findlast": "^1.2.5", + "array.prototype.flatmap": "^1.3.2", + "array.prototype.tosorted": "^1.1.4", "doctrine": "^2.1.0", + "es-iterator-helpers": "^1.1.0", "estraverse": "^5.3.0", + "hasown": "^2.0.2", "jsx-ast-utils": "^2.4.1 || ^3.0.0", "minimatch": "^3.1.2", - "object.entries": "^1.1.6", - "object.fromentries": "^2.0.6", - "object.hasown": "^1.1.2", - "object.values": "^1.1.6", + "object.entries": "^1.1.8", + "object.fromentries": "^2.0.8", + "object.values": "^1.2.0", "prop-types": "^15.8.1", - "resolve": "^2.0.0-next.4", - "semver": "^6.3.0", - "string.prototype.matchall": "^4.0.8" + "resolve": "^2.0.0-next.5", + "semver": "^6.3.1", + "string.prototype.matchall": "^4.0.11", + "string.prototype.repeat": "^1.0.0" }, "engines": { "node": ">=4" }, "peerDependencies": { - "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7" } }, "node_modules/eslint-plugin-react-hooks": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz", - "integrity": "sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-5.0.0.tgz", + "integrity": "sha512-hIOwI+5hYGpJEc4uPRmz2ulCjAGD/N13Lukkh8cLV0i2IRk/bdZDYjgLVHj+U9Z704kLIdIO6iueGvxNur0sgw==", "engines": { "node": ">=10" }, "peerDependencies": { - "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0" - } - }, - "node_modules/eslint-plugin-react/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/eslint-plugin-react/node_modules/doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eslint-plugin-react/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0" } }, "node_modules/eslint-plugin-react/node_modules/resolve": { @@ -7613,15 +8205,15 @@ } }, "node_modules/eslint-scope": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", - "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.1.0.tgz", + "integrity": "sha512-14dSvlhaVhKKsa9Fx1l8A17s7ah7Ef7wCakJ10LYk6+GYmP9yDti2oq2SEwcyndt6knfcZyhyxwY3i9yL78EQw==", "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "url": "https://opencollective.com/eslint" @@ -7638,18 +8230,15 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint/node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" - }, - "node_modules/eslint/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "node_modules/eslint/node_modules/eslint-visitor-keys": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.1.0.tgz", + "integrity": "sha512-Q7lok0mqMUSf5a/AdAZkA5a/gHcO6snwQClVNNvFKCAVlxXucdU8pKydU5ZVZjBx5xr37vGbFFWtLQYreLzrZg==", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, "node_modules/eslint/node_modules/find-up": { @@ -7667,31 +8256,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/eslint/node_modules/globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, "node_modules/eslint/node_modules/locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", @@ -7706,17 +8270,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/eslint/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, "node_modules/eslint/node_modules/p-locate": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", @@ -7731,28 +8284,28 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/eslint/node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "node_modules/espree": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.2.0.tgz", + "integrity": "sha512-upbkBJbckcCNBDBDXEbuhjbP68n+scUd3k/U2EkyM9nw+I/jPiL4cLF/Al06CF96wRltFda16sxDFrxsI1v0/g==", + "dependencies": { + "acorn": "^8.12.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.1.0" + }, "engines": { - "node": ">=10" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://opencollective.com/eslint" } }, - "node_modules/espree": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", - "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", - "dependencies": { - "acorn": "^8.9.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" - }, + "node_modules/espree/node_modules/eslint-visitor-keys": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.1.0.tgz", + "integrity": "sha512-Q7lok0mqMUSf5a/AdAZkA5a/gHcO6snwQClVNNvFKCAVlxXucdU8pKydU5ZVZjBx5xr37vGbFFWtLQYreLzrZg==", "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "url": "https://opencollective.com/eslint" @@ -7859,14 +8412,6 @@ "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==", - "engines": { - "node": ">=6" - } - }, "node_modules/expand-tilde": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", @@ -7894,16 +8439,16 @@ } }, "node_modules/express": { - "version": "4.21.0", - "resolved": "https://registry.npmjs.org/express/-/express-4.21.0.tgz", - "integrity": "sha512-VqcNGcj/Id5ZT1LZ/cfihi3ttTn+NJmkli2eZADigjq29qTlWi/hAQ43t/VLPq8+UX06FCEx3ByOYet6ZFblng==", + "version": "4.21.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.1.tgz", + "integrity": "sha512-YSFlK1Ee0/GC8QaO91tHcDxJiE/X4FbpAyQWkxAvG6AXCuR65YzK8ua6D9hvi/TzUfZMpc+BwuM1IPw8fmQBiQ==", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", "body-parser": "1.20.3", "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.6.0", + "cookie": "0.7.1", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", @@ -7995,11 +8540,6 @@ "resolved": "https://registry.npmjs.org/fast-defer/-/fast-defer-1.1.8.tgz", "integrity": "sha512-lEJeOH5VL5R09j6AA0D4Uvq7AgsHw0dAImQQ+F3iSyHZuAxyQfWobsagGpTcOPvJr3urmKRHrs+Gs9hV+/Qm/Q==" }, - "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==" - }, "node_modules/fast-glob": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", @@ -8101,14 +8641,14 @@ } }, "node_modules/file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", "dependencies": { - "flat-cache": "^3.0.4" + "flat-cache": "^4.0.0" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": ">=16.0.0" } }, "node_modules/file-loader": { @@ -8260,31 +8800,15 @@ } }, "node_modules/flat-cache": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", - "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", "dependencies": { "flatted": "^3.2.9", - "keyv": "^4.5.3", - "rimraf": "^3.0.2" + "keyv": "^4.5.4" }, "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/flat-cache/node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node": ">=16" } }, "node_modules/flatted": { @@ -8366,37 +8890,17 @@ "webpack": "^5.11.0" } }, - "node_modules/fork-ts-checker-webpack-plugin/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, "node_modules/fork-ts-checker-webpack-plugin/node_modules/fs-extra": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", - "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/fork-ts-checker-webpack-plugin/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", "dependencies": { - "brace-expansion": "^1.1.7" + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" }, "engines": { - "node": "*" + "node": ">=12" } }, "node_modules/fork-ts-checker-webpack-plugin/node_modules/schema-utils": { @@ -8482,11 +8986,6 @@ "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==" - }, "node_modules/fs-extra": { "version": "9.1.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", @@ -8634,11 +9133,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "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==" - }, "node_modules/glob": { "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", @@ -8675,26 +9169,6 @@ "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==" }, - "node_modules/glob/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/glob/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, "node_modules/global-modules": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz", @@ -8731,11 +9205,14 @@ } }, "node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "version": "15.11.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-15.11.0.tgz", + "integrity": "sha512-yeyNSjdbyVaWurlwCpcA6XNBrHTMIeDdj0/hnvX/OLJ9ekOXYbLsLinH/MucQyGvNnXhidTdNhTtJaffL2sMfw==", "engines": { - "node": ">=4" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/globalthis": { @@ -8829,14 +9306,6 @@ "resolved": "https://registry.npmjs.org/harmony-reflect/-/harmony-reflect-1.6.2.tgz", "integrity": "sha512-HIp/n38R9kQjDEziXyDTuW3vvoxxyxjxFzXLrBr18uB47GnSt+G9D29fqrpM5ZkspMcPICud3XsBJQ4Y2URg8g==" }, - "node_modules/has": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.4.tgz", - "integrity": "sha512-qdSAmqLF6209RFj4VVItywPMbm3vWylknmB3nvNiUIs72xAimcM8nVYxYr7ncvZq5qzk9MKIZR8ijqD/1QuYjQ==", - "engines": { - "node": ">= 0.4.0" - } - }, "node_modules/has-bigints": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", @@ -9202,9 +9671,9 @@ } }, "node_modules/http-proxy-middleware": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz", - "integrity": "sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw==", + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.7.tgz", + "integrity": "sha512-fgVY8AV7qU7z/MmXJ/rxwbrtQH4jBQ9m7kp3llF0liB7glmFeVZFBepQb32T3y8n8k2+AEYuMPCpinYW+/CuRA==", "dependencies": { "@types/http-proxy": "^1.17.8", "http-proxy": "^1.18.1", @@ -9244,22 +9713,19 @@ "node": ">=10.17.0" } }, + "node_modules/hyperdyperid": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/hyperdyperid/-/hyperdyperid-1.2.0.tgz", + "integrity": "sha512-Y93lCzHYgGWdrJ66yIktxiaGULYc6oGiABxhcO5AufBeOyoIdZF7bIfLaOrbM0iGIOXQQgxxRrFEnb+Y6w1n4A==", + "engines": { + "node": ">=10.18" + } + }, "node_modules/hyphenate-style-name": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/hyphenate-style-name/-/hyphenate-style-name-1.1.0.tgz", "integrity": "sha512-WDC/ui2VVRrz3jOVi+XtjqkDjiVjTtFaAGiW37k6b+ohyQ5wYDOGkvCZa8+H0nx3gyvv0+BST9xuOgIyGQ00gw==" }, - "node_modules/i18n-iso-countries": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/i18n-iso-countries/-/i18n-iso-countries-4.3.1.tgz", - "integrity": "sha512-yxeCvmT8yO1p/epv93c1OHnnYNNMOX6NUNpNfuvzSIcDyripS7OGeKXgzYGd5QI31UK+GBrMG0nPFNv0jrHggw==", - "dependencies": { - "diacritics": "^1.3.0" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", @@ -9310,7 +9776,8 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "peer": true }, "node_modules/ignore": { "version": "5.3.2", @@ -9563,6 +10030,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", + "dev": true, "dependencies": { "call-bind": "^1.0.2", "has-tostringtag": "^1.0.0" @@ -9594,6 +10062,20 @@ "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==" }, + "node_modules/is-async-function": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.0.0.tgz", + "integrity": "sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-bigint": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", @@ -9729,6 +10211,17 @@ "node": ">=0.10.0" } }, + "node_modules/is-finalizationregistry": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.0.2.tgz", + "integrity": "sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw==", + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", @@ -9770,6 +10263,37 @@ "node": ">=0.10.0" } }, + "node_modules/is-inside-container": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", + "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", + "dependencies": { + "is-docker": "^3.0.0" + }, + "bin": { + "is-inside-container": "cli.js" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-inside-container/node_modules/is-docker": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", + "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-interactive": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", @@ -9801,6 +10325,17 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-network-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-network-error/-/is-network-error-1.1.0.tgz", + "integrity": "sha512-tUdRRAnhT+OtCZR/LxZelH/C7QtjtFrTu5tXCA8pl55eTUElUHT+GPYV8MBMBvea/j+NxQqVt3LbWMRir7Gx9g==", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", @@ -9853,14 +10388,6 @@ "node": ">=6" } }, - "node_modules/is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "engines": { - "node": ">=8" - } - }, "node_modules/is-plain-obj": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", @@ -10152,15 +10679,30 @@ "node": ">=8" } }, + "node_modules/iterator.prototype": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.3.tgz", + "integrity": "sha512-FW5iMbeQ6rBGm/oKgzq2aW4KvAGpxPzYES8N4g4xNXUKpL1mclMvOe+76AcLDTvD+Ze+sOpVhgdAQEKF4L9iGQ==", + "dependencies": { + "define-properties": "^1.2.1", + "get-intrinsic": "^1.2.1", + "has-symbols": "^1.0.3", + "reflect.getprototypeof": "^1.0.4", + "set-function-name": "^2.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/jest": { - "version": "29.6.1", - "resolved": "https://registry.npmjs.org/jest/-/jest-29.6.1.tgz", - "integrity": "sha512-Nirw5B4nn69rVUZtemCQhwxOBhm0nsp3hmtF4rzCeWD7BkjAXRIji7xWQfnTNbz9g0aVsBX6aZK3n+23LM6uDw==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz", + "integrity": "sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==", "dependencies": { - "@jest/core": "^29.6.1", - "@jest/types": "^29.6.1", + "@jest/core": "^29.7.0", + "@jest/types": "^29.6.3", "import-local": "^3.0.2", - "jest-cli": "^29.6.1" + "jest-cli": "^29.7.0" }, "bin": { "jest": "bin/jest.js" @@ -10513,17 +11055,17 @@ "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==" }, "node_modules/jest-environment-jsdom": { - "version": "29.6.1", - "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-29.6.1.tgz", - "integrity": "sha512-PoY+yLaHzVRhVEjcVKSfJ7wXmJW4UqPYNhR05h7u/TK0ouf6DmRNZFBL/Z00zgQMyWGMBXn69/FmOvhEJu8cIw==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-29.7.0.tgz", + "integrity": "sha512-k9iQbsf9OyOfdzWH8HDmrRT0gSIcX+FLNW7IQq94tFX0gynPwqDTW0Ho6iMVNjGz/nb+l/vW3dWM2bbLLpkbXA==", "dependencies": { - "@jest/environment": "^29.6.1", - "@jest/fake-timers": "^29.6.1", - "@jest/types": "^29.6.1", + "@jest/environment": "^29.7.0", + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", "@types/jsdom": "^20.0.0", "@types/node": "*", - "jest-mock": "^29.6.1", - "jest-util": "^29.6.1", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0", "jsdom": "^20.0.0" }, "engines": { @@ -11395,11 +11937,14 @@ "integrity": "sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ==" }, "node_modules/language-tags": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.5.tgz", - "integrity": "sha512-qJhlO9cGXi6hBGKoxEG/sKZDAHD5Hnu9Hs4WbOY3pCWXDhw0N8x1NenNzm2EnNLkLkk7J2SdxAkDSbb6ftT+UQ==", + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.9.tgz", + "integrity": "sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==", "dependencies": { - "language-subtag-registry": "~0.3.2" + "language-subtag-registry": "^0.3.20" + }, + "engines": { + "node": ">=0.10" } }, "node_modules/launch-editor": { @@ -11639,9 +12184,9 @@ } }, "node_modules/magic-string": { - "version": "0.30.11", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.11.tgz", - "integrity": "sha512-+Wri9p0QHMy+545hKww7YAu5NyzF8iomPL/RQazugQ9+Ez4Ic3mERMd8ZTX5rfK944j+560ZJi8iAwgak1Ac7A==", + "version": "0.30.12", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.12.tgz", + "integrity": "sha512-Ea8I3sQMVXr8JhN4z+H/d8zwo+tYDgHE9+5G4Wnrwhs0gaK9fXTKx0Tw5Xwsd/bCPTTZNRAdpyzvoeORe9LYpw==", "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0" } @@ -11864,17 +12409,6 @@ "node": ">=6" } }, - "node_modules/mimic-response": { - "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==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/min-indent": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", @@ -11927,25 +12461,23 @@ "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" }, "node_modules/minimatch": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", - "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dependencies": { - "brace-expansion": "^2.0.1" + "brace-expansion": "^1.1.7" }, "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node": "*" } }, - "node_modules/minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node_modules/minimatch/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, "node_modules/mkdirp": { @@ -11960,11 +12492,6 @@ "node": ">=10" } }, - "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==" - }, "node_modules/mrmime": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.0.tgz", @@ -12013,11 +12540,6 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, - "node_modules/napi-build-utils": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", - "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==" - }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -12045,37 +12567,17 @@ "tslib": "^2.0.3" } }, - "node_modules/node-abi": { - "version": "3.68.0", - "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.68.0.tgz", - "integrity": "sha512-7vbj10trelExNjFSBm5kTvZXXa7pZyKWx9RCKIyqe6I9Ev3IzGpQoqBP3a+cOdxY+pWj6VkP28n/2wWysBHD/A==", - "dependencies": { - "semver": "^7.3.5" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/node-abi/node_modules/semver": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/node-abort-controller": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/node-abort-controller/-/node-abort-controller-3.1.1.tgz", "integrity": "sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ==" }, "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==" + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", + "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", + "optional": true, + "peer": true }, "node_modules/node-forge": { "version": "1.3.1", @@ -12136,16 +12638,6 @@ "url": "https://opencollective.com/nodemon" } }, - "node_modules/nodemon/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, "node_modules/nodemon/node_modules/has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", @@ -12155,18 +12647,6 @@ "node": ">=4" } }, - "node_modules/nodemon/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, "node_modules/nodemon/node_modules/semver": { "version": "7.6.3", "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", @@ -12268,6 +12748,7 @@ "version": "1.1.6", "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.6.tgz", "integrity": "sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==", + "dev": true, "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1" @@ -12334,22 +12815,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/object.hasown": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.4.tgz", - "integrity": "sha512-FZ9LZt9/RHzGySlBARE3VF+gE26TxR38SdmqOqliuTnl9wrKulaQs+4dee1V+Io8VfxqzAfHu6YuRgUy8OHoTg==", - "dependencies": { - "define-properties": "^1.2.1", - "es-abstract": "^1.23.2", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/object.values": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.0.tgz", @@ -12537,15 +13002,19 @@ } }, "node_modules/p-retry": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz", - "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-6.2.0.tgz", + "integrity": "sha512-JA6nkq6hKyWLLasXQXUrO4z8BUZGUt/LjlJxx8Gb2+2ntodU/SS63YZ8b0LUTbQ8ZB9iwOfhEPhg4ykKnn2KsA==", "dependencies": { - "@types/retry": "0.12.0", + "@types/retry": "0.12.2", + "is-network-error": "^1.0.0", "retry": "^0.13.1" }, "engines": { - "node": ">=8" + "node": ">=16.17" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/p-try": { @@ -12825,9 +13294,9 @@ } }, "node_modules/postcss": { - "version": "8.4.40", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.40.tgz", - "integrity": "sha512-YF2kKIUzAofPMpfH6hOi2cGnv/HrUlfucspc7pDyvv7kGdqXrfj8SCl/t8owkEgKEuu8ZcRjSOxFxVLqwChZ2Q==", + "version": "8.4.47", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.47.tgz", + "integrity": "sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==", "funding": [ { "type": "opencollective", @@ -12844,8 +13313,8 @@ ], "dependencies": { "nanoid": "^3.3.7", - "picocolors": "^1.0.1", - "source-map-js": "^1.2.0" + "picocolors": "^1.1.0", + "source-map-js": "^1.2.1" }, "engines": { "node": "^10 || ^12 || >=14" @@ -13317,11 +13786,11 @@ } }, "node_modules/postcss-rtlcss": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/postcss-rtlcss/-/postcss-rtlcss-5.1.2.tgz", - "integrity": "sha512-cmcgRoO1wL7IJyVHw0RneWI/5Oe75NLC2NLlQLsNI7hcui+yRcW4RrILfQa4FqKQRLTU4r5eF0YPi1qZpMzQpA==", + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/postcss-rtlcss/-/postcss-rtlcss-5.5.0.tgz", + "integrity": "sha512-NkUw3Pq6JNLk/4yE4BszZNpvmLvcX5phTNA0X2thOOPmVVR7sgQXWY+0UjvucsLFL9mQ9IY+YckLyy07yLVijQ==", "dependencies": { - "rtlcss": "4.1.1" + "rtlcss": "4.3.0" }, "engines": { "node": ">=18.0.0" @@ -13376,57 +13845,6 @@ "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" }, - "node_modules/prebuild-install": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.2.tgz", - "integrity": "sha512-UnNke3IQb6sgarcZIDU3gbMeTp/9SSU1DAIkil7PrqG1vZlBtY5msYccSKSHDqa3hNg436IXK+SNImReuA1wEQ==", - "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": "^1.0.1", - "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/tar-fs": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", - "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", - "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==", - "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", @@ -13549,20 +13967,6 @@ "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", "dev": true }, - "node_modules/pubsub-js": { - "version": "1.9.4", - "resolved": "https://registry.npmjs.org/pubsub-js/-/pubsub-js-1.9.4.tgz", - "integrity": "sha512-hJYpaDvPH4w8ZX/0Fdf9ma1AwRgU353GfbaVfPjfJQf1KxZ2iHaHl3fAUw1qlJIR5dr4F3RzjGaWohYUEyoh7A==" - }, - "node_modules/pump": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.2.tgz", - "integrity": "sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==", - "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", @@ -13651,11 +14055,6 @@ } ] }, - "node_modules/queue-tick": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/queue-tick/-/queue-tick-1.0.1.tgz", - "integrity": "sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==" - }, "node_modules/rambda": { "version": "9.3.0", "resolved": "https://registry.npmjs.org/rambda/-/rambda-9.3.0.tgz", @@ -13699,28 +14098,6 @@ "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==", - "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==", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/react": { "version": "17.0.2", "resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz", @@ -13818,15 +14195,6 @@ "node": ">=14" } }, - "node_modules/react-dev-utils/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, "node_modules/react-dev-utils/node_modules/cosmiconfig": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-6.0.0.tgz", @@ -13917,17 +14285,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/react-dev-utils/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, "node_modules/react-dev-utils/node_modules/p-locate": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", @@ -14484,26 +14841,6 @@ "node": ">=6.0.0" } }, - "node_modules/recursive-readdir/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/recursive-readdir/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, "node_modules/redent": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", @@ -14526,6 +14863,26 @@ "@babel/runtime": "^7.9.2" } }, + "node_modules/reflect.getprototypeof": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.6.tgz", + "integrity": "sha512-fmfw4XgoDke3kdI6h4xcUz1dG8uaiv5q9gcEwLS4Pnth2kxT+GZ7YehS1JTMGBQmtV7Y4GFGbs2re2NqhdozUg==", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.1", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "globalthis": "^1.0.3", + "which-builtin-type": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/regenerate": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", @@ -14837,9 +15194,9 @@ } }, "node_modules/rtlcss": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/rtlcss/-/rtlcss-4.1.1.tgz", - "integrity": "sha512-/oVHgBtnPNcggP2aVXQjSy6N1mMAfHg4GSag0QtZBlD5bdDgAHwr4pydqJGd+SUCu9260+Pjqbjwtvu7EMH1KQ==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/rtlcss/-/rtlcss-4.3.0.tgz", + "integrity": "sha512-FI+pHEn7Wc4NqKXMXFM+VAYKEj/mRIcW4h24YVwVtyjI+EqGrLc2Hx/Ny0lrZ21cBWU2goLy36eqMcNj3AQJig==", "dependencies": { "escalade": "^3.1.1", "picocolors": "^1.0.0", @@ -14853,6 +15210,17 @@ "node": ">=12.0.0" } }, + "node_modules/run-applescript": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.0.0.tgz", + "integrity": "sha512-9by4Ij99JUr/MCFBUkDKLWK3G9HVXmabKz9U5MlIAIuvuzkiOicRYs8XJLxX+xahD+mLiiCYDqF9dKAgtzKP1A==", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/run-async": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", @@ -14888,7 +15256,6 @@ "version": "7.8.1", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", - "peer": true, "dependencies": { "tslib": "^2.1.0" } @@ -14937,44 +15304,403 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, "node_modules/sass": { - "version": "1.69.7", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.69.7.tgz", - "integrity": "sha512-rzj2soDeZ8wtE2egyLXgOOHQvaC2iosZrkF6v3EUG+tBwEvhqUCzm0VP3k9gHF9LXbSrRhT5SksoI56Iw8NPnQ==", + "version": "1.80.4", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.80.4.tgz", + "integrity": "sha512-rhMQ2tSF5CsuuspvC94nPM9rToiAFw2h3JTrLlgmNw1MH79v8Cr3DH6KF6o6r+8oofY3iYVPUf66KzC8yuVN1w==", + "optional": true, + "peer": true, + "dependencies": { + "@parcel/watcher": "^2.4.1", + "chokidar": "^4.0.0", + "immutable": "^4.0.0", + "source-map-js": ">=0.6.2 <2.0.0" + }, + "bin": { + "sass": "sass.js" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded": { + "version": "1.80.4", + "resolved": "https://registry.npmjs.org/sass-embedded/-/sass-embedded-1.80.4.tgz", + "integrity": "sha512-lPzKX5g79ZxohlPxh0pXTPFseWj9RfgYI0cPm14CH5ok77Ujuheq/DCp7RStvNDWS8RCQ8Ii6gJC/5WTkGyrhA==", + "dependencies": { + "@bufbuild/protobuf": "^2.0.0", + "buffer-builder": "^0.2.0", + "colorjs.io": "^0.5.0", + "immutable": "^4.0.0", + "rxjs": "^7.4.0", + "supports-color": "^8.1.1", + "varint": "^6.0.0" + }, + "bin": { + "sass": "dist/bin/sass.js" + }, + "engines": { + "node": ">=16.0.0" + }, + "optionalDependencies": { + "sass-embedded-android-arm": "1.80.4", + "sass-embedded-android-arm64": "1.80.4", + "sass-embedded-android-ia32": "1.80.4", + "sass-embedded-android-riscv64": "1.80.4", + "sass-embedded-android-x64": "1.80.4", + "sass-embedded-darwin-arm64": "1.80.4", + "sass-embedded-darwin-x64": "1.80.4", + "sass-embedded-linux-arm": "1.80.4", + "sass-embedded-linux-arm64": "1.80.4", + "sass-embedded-linux-ia32": "1.80.4", + "sass-embedded-linux-musl-arm": "1.80.4", + "sass-embedded-linux-musl-arm64": "1.80.4", + "sass-embedded-linux-musl-ia32": "1.80.4", + "sass-embedded-linux-musl-riscv64": "1.80.4", + "sass-embedded-linux-musl-x64": "1.80.4", + "sass-embedded-linux-riscv64": "1.80.4", + "sass-embedded-linux-x64": "1.80.4", + "sass-embedded-win32-arm64": "1.80.4", + "sass-embedded-win32-ia32": "1.80.4", + "sass-embedded-win32-x64": "1.80.4" + } + }, + "node_modules/sass-embedded-android-arm": { + "version": "1.80.4", + "resolved": "https://registry.npmjs.org/sass-embedded-android-arm/-/sass-embedded-android-arm-1.80.4.tgz", + "integrity": "sha512-iAZ7AiKTLGxQGTkZ37c2/7YC4lkbP1o3eP/K74YaF8O+qhKTLyLOwV7OcmzIywac7dqLcNuGqhFCmFqTYpewZw==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-android-arm64": { + "version": "1.80.4", + "resolved": "https://registry.npmjs.org/sass-embedded-android-arm64/-/sass-embedded-android-arm64-1.80.4.tgz", + "integrity": "sha512-htAuBmRvvN2d4smrqxZ6WBw4+OOURaoHzq5oZKqS/E35zYl5FHmrJzp4S5e26a0tEBcjca014tfb/uu9cQgnqA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-android-ia32": { + "version": "1.80.4", + "resolved": "https://registry.npmjs.org/sass-embedded-android-ia32/-/sass-embedded-android-ia32-1.80.4.tgz", + "integrity": "sha512-IIee89Jco8/ad2s/oRJTFqpLhBMzg0UXteJyZ5waZPZmkeSR/t9l67Ef1lLQVh9t9/fJ1ViTTiGYm/g/zu6UGw==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-android-riscv64": { + "version": "1.80.4", + "resolved": "https://registry.npmjs.org/sass-embedded-android-riscv64/-/sass-embedded-android-riscv64-1.80.4.tgz", + "integrity": "sha512-iJM2kqmWrOeE1aUyTp3uMAG86hyAqbpbOEV7tv828fUsMRDM4uHsHtmyp2n8P2Y0Y2FnLzJpvIm3SwDXGDzT1Q==", + "cpu": [ + "riscv64" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-android-x64": { + "version": "1.80.4", + "resolved": "https://registry.npmjs.org/sass-embedded-android-x64/-/sass-embedded-android-x64-1.80.4.tgz", + "integrity": "sha512-vd8VrLvUoHeTcsDoIJesXLbQYZH26a8lAzXy6u4+vEuAwikF4WiXBDFrpqiv38QeD3faLeoPtksRsFbAdQqJAA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-darwin-arm64": { + "version": "1.80.4", + "resolved": "https://registry.npmjs.org/sass-embedded-darwin-arm64/-/sass-embedded-darwin-arm64-1.80.4.tgz", + "integrity": "sha512-SJz7EM1i4NXa7CT/njIWMNYJ6CvbHljDIzUAZEe3V3u1KWl/eNO3pbWAnnDN62tBppwgWx/UdDUbAKowsT6Z8w==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-darwin-x64": { + "version": "1.80.4", + "resolved": "https://registry.npmjs.org/sass-embedded-darwin-x64/-/sass-embedded-darwin-x64-1.80.4.tgz", + "integrity": "sha512-J/QlBVO66DLtgALgCmM8rZ5zG0dBCIYW1eXIAnnDwC7vGkbAXMtO60M0O/2WNrAfmFfJz1hvKDLjlsxB2XGBLg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-linux-arm": { + "version": "1.80.4", + "resolved": "https://registry.npmjs.org/sass-embedded-linux-arm/-/sass-embedded-linux-arm-1.80.4.tgz", + "integrity": "sha512-vuaWhc4ebnaY1AgIWNvFv1snxmkWfvlCU7vnQf4qkn3R2Yyd2J+sjkO8o0NgMX8n5XRUSkAaYUJFCH+Nim6KgQ==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-linux-arm64": { + "version": "1.80.4", + "resolved": "https://registry.npmjs.org/sass-embedded-linux-arm64/-/sass-embedded-linux-arm64-1.80.4.tgz", + "integrity": "sha512-hI6zQyrR6qJbvyEHfj8UGXNB8VyUa72jel46406AuxUnViA0RyZDSqXUF8vwVw/Hjv1LkA5ihK9dBmWNbLz1zQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-linux-ia32": { + "version": "1.80.4", + "resolved": "https://registry.npmjs.org/sass-embedded-linux-ia32/-/sass-embedded-linux-ia32-1.80.4.tgz", + "integrity": "sha512-wcPExI8UbYrrJvGvo4v2Q+RktbCp44i3qZQ18hglPcVZOC1IzT9NPqZn0XmrqD4hmNbgsYR+picODkvqGw7iDA==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-linux-musl-arm": { + "version": "1.80.4", + "resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-arm/-/sass-embedded-linux-musl-arm-1.80.4.tgz", + "integrity": "sha512-HWo0G/9tuhj/uSEwte9KiDK2Xezrfh7nhdEH69ZIfOAqP5byTXL7o08TYagbvMAoljR43Vfna6MelV7NUX4WCw==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-linux-musl-arm64": { + "version": "1.80.4", + "resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-arm64/-/sass-embedded-linux-musl-arm64-1.80.4.tgz", + "integrity": "sha512-y8slzQ8Jjkl+53mUDkp3zxcDrTXVVxzpa+6nKh5Ue8l1YU2KdVZG1v2PoDXxE6o99B5I2TVBG8i02IsdYoL8jQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-linux-musl-ia32": { + "version": "1.80.4", + "resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-ia32/-/sass-embedded-linux-musl-ia32-1.80.4.tgz", + "integrity": "sha512-A2WSwnomho491iCeHh3c0YRympfAoJOKr+IyxalTcRH/pjENOWZWZUt00WE2q0tTpEd2V+goWvgS5pmUGewgmg==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-linux-musl-riscv64": { + "version": "1.80.4", + "resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-riscv64/-/sass-embedded-linux-musl-riscv64-1.80.4.tgz", + "integrity": "sha512-tYQsAHZLr2mnlJQBJ8Z/n/ySIFJ9JWpsUsoLe9fYgGDaBUfItdzUnj15CChRWld8vFe/I84hb7fbCtYXrI60Jg==", + "cpu": [ + "riscv64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-linux-musl-x64": { + "version": "1.80.4", + "resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-x64/-/sass-embedded-linux-musl-x64-1.80.4.tgz", + "integrity": "sha512-NZnr+SYbWlmXx0IaSQ8oF0jYkOULp9qKWMmmZQ1mxuGQ3z7tJqFhpH3M+hYkrFNeOq+GaH+nhHGOD4ZNBxeRkg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-linux-riscv64": { + "version": "1.80.4", + "resolved": "https://registry.npmjs.org/sass-embedded-linux-riscv64/-/sass-embedded-linux-riscv64-1.80.4.tgz", + "integrity": "sha512-h/BmU7QONa7ScvQztFp4Th4aSo3X+Olu3I+RYsaH9s7P683WT3f2w5zr+wwP1V4roM5eyKDCRJBuefT3Fkkkgw==", + "cpu": [ + "riscv64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-linux-x64": { + "version": "1.80.4", + "resolved": "https://registry.npmjs.org/sass-embedded-linux-x64/-/sass-embedded-linux-x64-1.80.4.tgz", + "integrity": "sha512-aZbZFs/X9bEmzDiBEiV4IAsKEA0zrCM+s/u2OzvrX4GRvZFJ+/XRTTvf+RTm7mgvTFgfPwCkNGVECQZ1eHh+6A==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-win32-arm64": { + "version": "1.80.4", + "resolved": "https://registry.npmjs.org/sass-embedded-win32-arm64/-/sass-embedded-win32-arm64-1.80.4.tgz", + "integrity": "sha512-8JiatFi2VVFqCdJzKNDteaPC4KPmh8/giaVh7TyMcDhKjnvRLeu3v5V1egTMiwwpnQHuwzU3uqBlm/llVNR2Pw==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-win32-ia32": { + "version": "1.80.4", + "resolved": "https://registry.npmjs.org/sass-embedded-win32-ia32/-/sass-embedded-win32-ia32-1.80.4.tgz", + "integrity": "sha512-SodmTD6mjxEgoq44jWMibmBQvWkCfENK/70zp4qsztcBSOggg3nYUzwG0YpraClAMXpB1xOvzrArWu9/9fguAg==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-win32-x64": { + "version": "1.80.4", + "resolved": "https://registry.npmjs.org/sass-embedded-win32-x64/-/sass-embedded-win32-x64-1.80.4.tgz", + "integrity": "sha512-7+oRRwCCcnOmw152qDiC7x7SphYBo1eLB4KdyThO+7+rYRO8AftXO+kqBPTVSkM8kGp4wxCMF9auPpYBZbjsow==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", "dependencies": { - "chokidar": ">=3.0.0 <4.0.0", - "immutable": "^4.0.0", - "source-map-js": ">=0.6.2 <2.0.0" - }, - "bin": { - "sass": "sass.js" + "has-flag": "^4.0.0" }, "engines": { - "node": ">=14.0.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" } }, "node_modules/sass-loader": { - "version": "13.3.3", - "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-13.3.3.tgz", - "integrity": "sha512-mt5YN2F1MOZr3d/wBRcZxeFgwgkH44wVc2zohO2YF6JiOMkiXe4BYRZpSu2sO1g71mo/j16txzUhsKZlqjVGzA==", + "version": "16.0.2", + "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-16.0.2.tgz", + "integrity": "sha512-Ll6iXZ1EYwYT19SqW4mSBb76vSSi8JgzElmzIerhEGgzB5hRjDQIWsPmuk1UrAXkR16KJHqVY0eH+5/uw9Tmfw==", "dependencies": { "neo-async": "^2.6.2" }, "engines": { - "node": ">= 14.15.0" + "node": ">= 18.12.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/webpack" }, "peerDependencies": { - "fibers": ">= 3.1.0", + "@rspack/core": "0.x || 1.x", "node-sass": "^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0", "sass": "^1.3.0", "sass-embedded": "*", "webpack": "^5.0.0" }, "peerDependenciesMeta": { - "fibers": { + "@rspack/core": { "optional": true }, "node-sass": { @@ -14985,9 +15711,42 @@ }, "sass-embedded": { "optional": true + }, + "webpack": { + "optional": true } } }, + "node_modules/sass/node_modules/chokidar": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.1.tgz", + "integrity": "sha512-n8enUVCED/KVRQlab1hr3MVpcVMvxtZjmEa956u+4YijlmQED223XMSYj2tLuKvr4jcCTzNNMpQDUer72MMmzA==", + "optional": true, + "peer": true, + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/sass/node_modules/readdirp": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.0.2.tgz", + "integrity": "sha512-yDMz9g+VaZkqBYS/ozoBJwaBhTbZo3UNYQHNRw1D3UFQB8oHB4uS/tAODO+ZLjGWmUbKnIlOWO+aaIiAxrUWHA==", + "optional": true, + "peer": true, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/saxes": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", @@ -15270,25 +16029,41 @@ "integrity": "sha512-pfVOw8QZIXpMbhBWvzBISicvToTiM5WBF1EeAUZDDSb5Dt29yl4AYbyywbJFSEsRUMr7gJaxqCdr4L3tQf9wVg==" }, "node_modules/sharp": { - "version": "0.32.6", - "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.32.6.tgz", - "integrity": "sha512-KyLTWwgcR9Oe4d9HwCwNM2l7+J0dUQwn/yf7S0EnTtb0eVS4RxO0eUSvxPtzT4F3SY+C4K6fqdv/DO27sJ/v/w==", + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.33.5.tgz", + "integrity": "sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw==", "hasInstallScript": true, "dependencies": { "color": "^4.2.3", - "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" + "detect-libc": "^2.0.3", + "semver": "^7.6.3" }, "engines": { - "node": ">=14.15.0" + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" }, "funding": { "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-darwin-arm64": "0.33.5", + "@img/sharp-darwin-x64": "0.33.5", + "@img/sharp-libvips-darwin-arm64": "1.0.4", + "@img/sharp-libvips-darwin-x64": "1.0.4", + "@img/sharp-libvips-linux-arm": "1.0.5", + "@img/sharp-libvips-linux-arm64": "1.0.4", + "@img/sharp-libvips-linux-s390x": "1.0.4", + "@img/sharp-libvips-linux-x64": "1.0.4", + "@img/sharp-libvips-linuxmusl-arm64": "1.0.4", + "@img/sharp-libvips-linuxmusl-x64": "1.0.4", + "@img/sharp-linux-arm": "0.33.5", + "@img/sharp-linux-arm64": "0.33.5", + "@img/sharp-linux-s390x": "0.33.5", + "@img/sharp-linux-x64": "0.33.5", + "@img/sharp-linuxmusl-arm64": "0.33.5", + "@img/sharp-linuxmusl-x64": "0.33.5", + "@img/sharp-wasm32": "0.33.5", + "@img/sharp-win32-ia32": "0.33.5", + "@img/sharp-win32-x64": "0.33.5" } }, "node_modules/sharp/node_modules/semver": { @@ -15351,49 +16126,6 @@ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" }, - "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==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "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==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "decompress-response": "^6.0.0", - "once": "^1.3.1", - "simple-concat": "^1.0.0" - } - }, "node_modules/simple-swizzle": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", @@ -15626,6 +16358,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz", "integrity": "sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==", + "dev": true, "dependencies": { "internal-slot": "^1.0.4" }, @@ -15675,19 +16408,6 @@ "node": ">= 4.0.0" } }, - "node_modules/streamx": { - "version": "2.20.1", - "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.20.1.tgz", - "integrity": "sha512-uTa0mU6WUC65iUvzKH4X9hEdvSW7rbPxPtwfWiLMSj3qTdQbAiUboZTxauKfpFuGIGa1C2BYijZ7wgdUXICJhA==", - "dependencies": { - "fast-fifo": "^1.3.2", - "queue-tick": "^1.0.1", - "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", @@ -15754,6 +16474,19 @@ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" }, + "node_modules/string.prototype.includes": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/string.prototype.includes/-/string.prototype.includes-2.0.1.tgz", + "integrity": "sha512-o7+c9bW6zpAdJHTtujeePODAhkuicdAryFsfVKwA+wGw89wJ4GTY484WTucM9hLtDEOpOvI+aHnzqnC5lHp4Rg==", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.3" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/string.prototype.matchall": { "version": "4.0.11", "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.11.tgz", @@ -15779,6 +16512,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/string.prototype.repeat": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/string.prototype.repeat/-/string.prototype.repeat-1.0.0.tgz", + "integrity": "sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==", + "dependencies": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } + }, "node_modules/string.prototype.trim": { "version": "1.2.9", "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz", @@ -15876,18 +16618,18 @@ } }, "node_modules/style-loader": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-3.3.4.tgz", - "integrity": "sha512-0WqXzrsMTyb8yjZJHDqwmnwRJvhALK9LfRtRc6B4UTWe8AijYLZYZ9thuJTZc2VfQWINADW/j+LiJnfy2RoC1w==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-4.0.0.tgz", + "integrity": "sha512-1V4WqhhZZgjVAVJyt7TdDPZoPBPNHbekX4fWnCJL1yQukhCeZhJySUL+gL9y6sNdN95uEOS83Y55SqHcP7MzLA==", "engines": { - "node": ">= 12.13.0" + "node": ">= 18.12.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/webpack" }, "peerDependencies": { - "webpack": "^5.0.0" + "webpack": "^5.27.0" } }, "node_modules/stylehacks": { @@ -16102,29 +16844,6 @@ "node": ">=6" } }, - "node_modules/tar-fs": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.0.6.tgz", - "integrity": "sha512-iokBDQQkUyeXhgPYaZxmczGPhnhXZ0CmrqI+MOb/WFGS9DW5wnfrLgtjUJBvz50vQ3qfRwJ62QVoCFu8mPVu5w==", - "dependencies": { - "pump": "^3.0.0", - "tar-stream": "^3.1.5" - }, - "optionalDependencies": { - "bare-fs": "^2.1.1", - "bare-path": "^2.1.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==", - "dependencies": { - "b4a": "^1.6.4", - "fast-fifo": "^1.2.0", - "streamx": "^2.15.0" - } - }, "node_modules/terser": { "version": "5.34.0", "resolved": "https://registry.npmjs.org/terser/-/terser-5.34.0.tgz", @@ -16254,39 +16973,22 @@ "node": ">=8" } }, - "node_modules/test-exclude/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/test-exclude/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/text-decoder": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.2.0.tgz", - "integrity": "sha512-n1yg1mOj9DNpk3NeZOx7T6jchTbyJS3i3cucbNN6FcdPriMZx7NsgrGpWWdWZZGxD7ES1XB+3uoqHMgOKaN+fg==", - "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", "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==" }, + "node_modules/thingies": { + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/thingies/-/thingies-1.21.0.tgz", + "integrity": "sha512-hsqsJsFMsV+aD4s3CWKk85ep/3I9XzYV/IXaSouJMYIoDlgyi11cBhsqYe9/geRfB0YIikBQg6raRaM+nIMP9g==", + "engines": { + "node": ">=10.18" + }, + "peerDependencies": { + "tslib": "^2" + } + }, "node_modules/through": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", @@ -16416,6 +17118,21 @@ "node": ">=12" } }, + "node_modules/tree-dump": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/tree-dump/-/tree-dump-1.0.2.tgz", + "integrity": "sha512-dpev9ABuLWdEubk+cIaI9cHwRNNDjkBBLXTwI4UCUFdQ5xXKqNXoK4FEciw/vxf+NQ7Cb7sGUyeUtORvHIdRXQ==", + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, "node_modules/ts-api-utils": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", @@ -16457,36 +17174,6 @@ "node": ">=10" } }, - "node_modules/tsconfig-paths": { - "version": "3.15.0", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", - "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", - "dependencies": { - "@types/json5": "^0.0.29", - "json5": "^1.0.2", - "minimist": "^1.2.6", - "strip-bom": "^3.0.0" - } - }, - "node_modules/tsconfig-paths/node_modules/json5": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", - "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", - "dependencies": { - "minimist": "^1.2.0" - }, - "bin": { - "json5": "lib/cli.js" - } - }, - "node_modules/tsconfig-paths/node_modules/strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", - "engines": { - "node": ">=4" - } - }, "node_modules/tslib": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz", @@ -16500,17 +17187,6 @@ "node": ">=0.6.x" } }, - "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==", - "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", @@ -16623,9 +17299,9 @@ } }, "node_modules/typescript": { - "version": "5.6.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.2.tgz", - "integrity": "sha512-NW8ByodCSNCwZeghjN3o+JX5OFH0Ojg6sadjEKY4huZ52TqbJTJnDo5+Tw98lSy63NZvi4n+ez5m2u5d4PkZyw==", + "version": "5.6.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz", + "integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -16634,6 +17310,28 @@ "node": ">=14.17" } }, + "node_modules/typescript-eslint": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.11.0.tgz", + "integrity": "sha512-cBRGnW3FSlxaYwU8KfAewxFK5uzeOAp0l2KebIlPDOT5olVi65KDG/yjBooPBG0kGW/HLkoz1c/iuBFehcS3IA==", + "dependencies": { + "@typescript-eslint/eslint-plugin": "8.11.0", + "@typescript-eslint/parser": "8.11.0", + "@typescript-eslint/utils": "8.11.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, "node_modules/uc.micro": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz", @@ -16935,16 +17633,15 @@ } }, "node_modules/uuid": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", - "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "version": "11.0.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-11.0.2.tgz", + "integrity": "sha512-14FfcOJmqdjbBPdDjFQyk/SdT4NySW4eM0zcG+HqbHP5jzuH56xO3J1DGhgs/cEMCfwYi3HQI1gnTO62iaG+tQ==", "funding": [ "https://github.com/sponsors/broofa", "https://github.com/sponsors/ctavan" ], - "peer": true, "bin": { - "uuid": "dist/bin/uuid" + "uuid": "dist/esm/bin/uuid" } }, "node_modules/v8-to-istanbul": { @@ -16965,6 +17662,11 @@ "resolved": "https://registry.npmjs.org/value-equal/-/value-equal-1.0.1.tgz", "integrity": "sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw==" }, + "node_modules/varint": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/varint/-/varint-6.0.0.tgz", + "integrity": "sha512-cXEIW6cfr15lFv563k4GuVuW/fiwjknytD37jIOLSdSWuOI6WnO/oKwmP2FQTU2l01LP8/M5TSAJpzUaGe3uWg==" + }, "node_modules/vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", @@ -17189,75 +17891,97 @@ } }, "node_modules/webpack-dev-middleware": { - "version": "5.3.4", - "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.4.tgz", - "integrity": "sha512-BVdTqhhs+0IfoeAf7EoH5WE+exCmqGerHfDM0IL096Px60Tq2Mn9MAbnaGUe6HiMa41KMCYF19gyzZmBcq/o4Q==", + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-7.4.2.tgz", + "integrity": "sha512-xOO8n6eggxnwYpy1NlzUKpvrjfJTvae5/D6WOK0S2LSo7vjmo5gCM1DbLUmFqrMTJP+W/0YZNctm7jasWvLuBA==", "dependencies": { "colorette": "^2.0.10", - "memfs": "^3.4.3", + "memfs": "^4.6.0", "mime-types": "^2.1.31", + "on-finished": "^2.4.1", "range-parser": "^1.2.1", "schema-utils": "^4.0.0" }, "engines": { - "node": ">= 12.13.0" + "node": ">= 18.12.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/webpack" }, "peerDependencies": { - "webpack": "^4.0.0 || ^5.0.0" + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "webpack": { + "optional": true + } + } + }, + "node_modules/webpack-dev-middleware/node_modules/memfs": { + "version": "4.14.0", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-4.14.0.tgz", + "integrity": "sha512-JUeY0F/fQZgIod31Ja1eJgiSxLn7BfQlCnqhwXFBzFHEw63OdLK7VJUJ7bnzNsWgCyoUP5tEp1VRY8rDaYzqOA==", + "dependencies": { + "@jsonjoy.com/json-pack": "^1.0.3", + "@jsonjoy.com/util": "^1.3.0", + "tree-dump": "^1.0.1", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">= 4.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" } }, "node_modules/webpack-dev-server": { - "version": "4.15.2", - "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.15.2.tgz", - "integrity": "sha512-0XavAZbNJ5sDrCbkpWL8mia0o5WPOd2YGtxrEiZkBK9FjLppIUK2TgxK6qGD2P3hUXTJNNPVibrerKcx5WkR1g==", - "dependencies": { - "@types/bonjour": "^3.5.9", - "@types/connect-history-api-fallback": "^1.3.5", - "@types/express": "^4.17.13", - "@types/serve-index": "^1.9.1", - "@types/serve-static": "^1.13.10", - "@types/sockjs": "^0.3.33", - "@types/ws": "^8.5.5", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-5.1.0.tgz", + "integrity": "sha512-aQpaN81X6tXie1FoOB7xlMfCsN19pSvRAeYUHOdFWOlhpQ/LlbfTqYwwmEDFV0h8GGuqmCmKmT+pxcUV/Nt2gQ==", + "dependencies": { + "@types/bonjour": "^3.5.13", + "@types/connect-history-api-fallback": "^1.5.4", + "@types/express": "^4.17.21", + "@types/serve-index": "^1.9.4", + "@types/serve-static": "^1.15.5", + "@types/sockjs": "^0.3.36", + "@types/ws": "^8.5.10", "ansi-html-community": "^0.0.8", - "bonjour-service": "^1.0.11", - "chokidar": "^3.5.3", + "bonjour-service": "^1.2.1", + "chokidar": "^3.6.0", "colorette": "^2.0.10", "compression": "^1.7.4", "connect-history-api-fallback": "^2.0.0", - "default-gateway": "^6.0.3", - "express": "^4.17.3", + "express": "^4.19.2", "graceful-fs": "^4.2.6", - "html-entities": "^2.3.2", + "html-entities": "^2.4.0", "http-proxy-middleware": "^2.0.3", - "ipaddr.js": "^2.0.1", - "launch-editor": "^2.6.0", - "open": "^8.0.9", - "p-retry": "^4.5.0", - "rimraf": "^3.0.2", - "schema-utils": "^4.0.0", - "selfsigned": "^2.1.1", + "ipaddr.js": "^2.1.0", + "launch-editor": "^2.6.1", + "open": "^10.0.3", + "p-retry": "^6.2.0", + "schema-utils": "^4.2.0", + "selfsigned": "^2.4.1", "serve-index": "^1.9.1", "sockjs": "^0.3.24", "spdy": "^4.0.2", - "webpack-dev-middleware": "^5.3.4", - "ws": "^8.13.0" + "webpack-dev-middleware": "^7.4.2", + "ws": "^8.18.0" }, "bin": { "webpack-dev-server": "bin/webpack-dev-server.js" }, "engines": { - "node": ">= 12.13.0" + "node": ">= 18.12.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/webpack" }, "peerDependencies": { - "webpack": "^4.37.0 || ^5.0.0" + "webpack": "^5.0.0" }, "peerDependenciesMeta": { "webpack": { @@ -17268,6 +17992,17 @@ } } }, + "node_modules/webpack-dev-server/node_modules/define-lazy-prop": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", + "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/webpack-dev-server/node_modules/ipaddr.js": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.2.0.tgz", @@ -17276,19 +18011,35 @@ "node": ">= 10" } }, - "node_modules/webpack-dev-server/node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", + "node_modules/webpack-dev-server/node_modules/is-wsl": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.0.tgz", + "integrity": "sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==", "dependencies": { - "glob": "^7.1.3" + "is-inside-container": "^1.0.0" }, - "bin": { - "rimraf": "bin.js" + "engines": { + "node": ">=16" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/webpack-dev-server/node_modules/open": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/open/-/open-10.1.0.tgz", + "integrity": "sha512-mnkeQ1qP5Ue2wd+aivTD3NHd/lZ96Lu0jgf0pwktLPtx6cTZiH7tyeGRRHs0zX0rbrahXPnXlUnbeXyaBBuIaw==", + "dependencies": { + "default-browser": "^5.2.1", + "define-lazy-prop": "^3.0.0", + "is-inside-container": "^1.0.0", + "is-wsl": "^3.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/webpack-merge": { @@ -17476,6 +18227,31 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/which-builtin-type": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.1.4.tgz", + "integrity": "sha512-bppkmBSsHFmIMSl8BO9TbsyzsvGjVoppt8xUiGzwiu/bhDCGxnpOKCxgqj6GuyHE0mINMDecBFPlOm2hzY084w==", + "dependencies": { + "function.prototype.name": "^1.1.6", + "has-tostringtag": "^1.0.2", + "is-async-function": "^2.0.0", + "is-date-object": "^1.0.5", + "is-finalizationregistry": "^1.0.2", + "is-generator-function": "^1.0.10", + "is-regex": "^1.1.4", + "is-weakref": "^1.0.2", + "isarray": "^2.0.5", + "which-boxed-primitive": "^1.0.2", + "which-collection": "^1.0.2", + "which-typed-array": "^1.1.15" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/which-collection": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", @@ -17556,9 +18332,9 @@ } }, "node_modules/ws": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", - "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", + "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", "engines": { "node": ">=10.0.0" }, diff --git a/package.json b/package.json index 7a23dbf6..2a404531 100644 --- a/package.json +++ b/package.json @@ -25,12 +25,13 @@ "clean": "rm -rf dist", "docs": "jsdoc -c jsdoc.json", "docs:watch": "nodemon -w runtime -w docs/template -w README.md -e js,jsx,ts,tsx --exec npm run docs", - "lint": "eslint .", + "lint": "eslint .; npm run lint:tools; npm --prefix ./test-project run lint", + "lint:tools": "cd ./tools && eslint . && cd ..", "test": "npm run test:tools && npm run test:app && npm run test:runtime && npm run test:shell", "test:app": "npm --prefix ./test-project i; npm --prefix ./test-project run build", - "test:tools": "jest tools --config tools/jest.config.js --no-cache", - "test:runtime": "jest runtime --config runtime/jest.config.js --no-cache", - "test:shell": "jest shell --config shell/jest.config.js --no-cache" + "test:tools": "jest tools --config tools/jest.config.js", + "test:runtime": "jest runtime --config runtime/jest.config.js", + "test:shell": "jest shell --config shell/jest.config.js --passWithNoTests --coverage" }, "repository": { "type": "git", @@ -52,50 +53,47 @@ "@babel/preset-env": "^7.24.8", "@babel/preset-react": "^7.24.7", "@babel/preset-typescript": "^7.24.7", - "@cospired/i18n-iso-languages": "^4.2.0", "@edx/new-relic-source-map-webpack-plugin": "2.1.0", + "@eslint/compat": "^1.2.1", + "@eslint/js": "^9.13.0", "@formatjs/cli": "^6.0.3", - "@formatjs/intl-pluralrules": "^4.3.3", - "@formatjs/intl-relativetimeformat": "^10.0.1", "@formatjs/ts-transformer": "^3.13.14", - "@module-federation/enhanced": "^0.4.0", - "@module-federation/runtime": "^0.2.6", - "@pmmmwh/react-refresh-webpack-plugin": "0.5.15", + "@module-federation/enhanced": "^0.6.12", + "@module-federation/runtime": "^0.6.12", + "@pmmmwh/react-refresh-webpack-plugin": "^0.5.15", + "@stylistic/eslint-plugin": "^2.9.0", + "@types/eslint__js": "^8.42.3", "@types/gradient-string": "^1.1.6", - "@typescript-eslint/eslint-plugin": "^6.21.0", - "@typescript-eslint/parser": "^6.21.0", - "autoprefixer": "10.4.19", + "autoprefixer": "^10.4.20", "axios": "^1.7.7", "axios-cache-interceptor": "^1.6.0", "babel-jest": "^29.7.0", "babel-plugin-formatjs": "^10.5.16", - "chalk": "4.1.2", + "chalk": "^4.1.2", "classnames": "^2.5.1", - "clean-webpack-plugin": "4.0.0", + "clean-webpack-plugin": "^4.0.0", "compression": "^1.7.4", - "css-loader": "5.2.7", - "cssnano": "6.0.3", - "eslint": "8.44.0", - "eslint-config-airbnb": "19.0.4", - "eslint-config-airbnb-typescript": "^17.0.0", - "eslint-plugin-formatjs": "^4.12.2", - "eslint-plugin-import": "2.27.5", - "eslint-plugin-jsx-a11y": "6.7.1", - "eslint-plugin-react": "7.32.2", - "eslint-plugin-react-hooks": "4.6.0", + "css-loader": "^7.1.2", + "cssnano": "^6.1.2", + "eslint": "^9.13.0", + "eslint-plugin-formatjs": "^5.1.3", + "eslint-plugin-jest": "^28.8.3", + "eslint-plugin-jsx-a11y": "^6.10.1", + "eslint-plugin-react": "^7.37.2", + "eslint-plugin-react-hooks": "^5.0.0", "express": "^4.18.2", "file-loader": "6.2.0", "fork-ts-checker-webpack-plugin": "^9.0.2", "form-urlencoded": "^6.1.5", "glob": "^7.2.3", + "globals": "^15.11.0", "gradient-string": "^2.0.2", "history": "^4.10.1", "html-webpack-plugin": "5.6.0", - "i18n-iso-countries": "^4.3.1", "identity-obj-proxy": "3.0.0", "image-minimizer-webpack-plugin": "3.8.3", - "jest": "29.6.1", - "jest-environment-jsdom": "29.6.1", + "jest": "^29.7.0", + "jest-environment-jsdom": "^29.7.0", "jwt-decode": "^3.1.2", "localforage": "^1.10.0", "localforage-memoryStorageDriver": "^0.9.2", @@ -105,12 +103,11 @@ "lodash.snakecase": "^4.1.1", "mini-css-extract-plugin": "1.6.2", "parse5": "7.1.2", - "postcss": "8.4.40", + "postcss": "^8.4.47", "postcss-custom-media": "10.0.8", "postcss-loader": "7.3.4", - "postcss-rtlcss": "5.1.2", + "postcss-rtlcss": "^5.5.0", "prop-types": "^15.8.1", - "pubsub-js": "^1.9.4", "react-dev-utils": "12.0.1", "react-focus-on": "^3.9.4", "react-intl": "^6.6.6", @@ -118,20 +115,22 @@ "react-refresh-typescript": "^2.0.9", "react-responsive": "^10.0.0", "react-transition-group": "^4.4.5", - "resolve-url-loader": "5.0.0", - "sass": "1.69.7", - "sass-loader": "13.3.3", - "sharp": "0.32.6", + "resolve-url-loader": "^5.0.0", + "sass-embedded": "^1.80.4", + "sass-loader": "^16.0.2", + "sharp": "^0.33.5", "source-map-loader": "4.0.2", - "style-loader": "3.3.4", + "style-loader": "^4.0.0", "ts-loader": "^9.5.1", - "typescript": "^5.5.3", + "typescript": "^5.6.3", + "typescript-eslint": "^8.11.0", "universal-cookie": "^4.0.4", - "url-loader": "4.1.1", - "webpack": "^5.89.0", + "url-loader": "^4.1.1", + "uuid": "^11.0.2", + "webpack": "^5.95.0", "webpack-bundle-analyzer": "^4.10.1", "webpack-cli": "^5.1.4", - "webpack-dev-server": "^4.15.1", + "webpack-dev-server": "^5.1.0", "webpack-merge": "^5.10.0", "webpack-remove-empty-scripts": "1.0.4" }, @@ -143,7 +142,7 @@ "@testing-library/user-event": "^14.5.2", "@tsconfig/node18": "^18.2.4", "@types/compression": "^1.7.5", - "@types/jest": "^29.5.12", + "@types/jest": "^29.5.14", "@types/lodash.camelcase": "^4.3.9", "@types/lodash.merge": "^4.6.9", "@types/node": "^18.19.43", diff --git a/runtime/analytics/SegmentAnalyticsService.js b/runtime/analytics/SegmentAnalyticsService.js index 579a24e9..8fa63511 100644 --- a/runtime/analytics/SegmentAnalyticsService.js +++ b/runtime/analytics/SegmentAnalyticsService.js @@ -9,8 +9,8 @@ class SegmentAnalyticsService { constructor({ httpClient, loggingService, config }) { this.loggingService = loggingService; this.httpClient = httpClient; - this.trackingLogApiUrl = `${config.LMS_BASE_URL}/event`; - this.segmentKey = config.SEGMENT_KEY; + this.trackingLogApiUrl = `${config.lmsBaseUrl}/event`; + this.segmentKey = config.segmentKey; this.hasIdentifyBeenCalled = false; this.segmentInitialized = false; @@ -70,11 +70,11 @@ class SegmentAnalyticsService { // for methods in Analytics.js so that you never have to wait // for it to load to actually record data. The `method` is // stored as the first argument, so we can replay the data. - analytics.factory = method => ((...args) => { + analytics.factory = method => (...args) => { args.unshift(method); analytics.push(args); return analytics; - }); + }; // For each of our methods, generate a queueing stub. analytics.methods.forEach((key) => { @@ -98,7 +98,7 @@ class SegmentAnalyticsService { // Insert our script next to the first script element. const first = document.getElementsByTagName('script')[0]; first.parentNode.insertBefore(script, first); - analytics._loadOptions = options; // eslint-disable-line no-underscore-dangle + analytics._loadOptions = options; this.segmentInitialized = true; }; @@ -201,7 +201,7 @@ class SegmentAnalyticsService { // This is added to handle the google analytics blocked case which is injected into // the DOM by segment.min.js. setTimeout(() => { - if (!global.ga || !global.ga.create || !global.google_tag_manager) { + if (!global.ga?.create || !global.google_tag_manager) { this.segmentInitialized = false; resolve(); } diff --git a/runtime/analytics/index.js b/runtime/analytics/index.ts similarity index 87% rename from runtime/analytics/index.js rename to runtime/analytics/index.ts index 8f6d3af2..36613629 100644 --- a/runtime/analytics/index.js +++ b/runtime/analytics/index.ts @@ -1,12 +1,12 @@ export { - configure, + configureAnalytics, + getAnalyticsService, identifyAnonymousUser, identifyAuthenticatedUser, + resetAnalyticsService, sendPageEvent, sendTrackEvent, - sendTrackingLogEvent, - getAnalyticsService, - resetAnalyticsService, + sendTrackingLogEvent } from './interface'; -export { default as SegmentAnalyticsService } from './SegmentAnalyticsService'; export { default as MockAnalyticsService } from './MockAnalyticsService'; +export { default as SegmentAnalyticsService } from './SegmentAnalyticsService'; diff --git a/runtime/analytics/interface.js b/runtime/analytics/interface.js index d035f2ef..fda71053 100755 --- a/runtime/analytics/interface.js +++ b/runtime/analytics/interface.js @@ -16,7 +16,7 @@ * SegmentAnalyticsService * } from '@openedx/frontend-base'; * - * configure(SegmentAnalyticsService, { + * configureAnalytics(SegmentAnalyticsService, { * config: getConfig(), * loggingService: getLoggingService(), * httpClient: getAuthenticatedHttpClient(), @@ -55,7 +55,7 @@ let service; * @param {*} options * @returns {AnalyticsService} */ -export function configure(AnalyticsService, options) { +export function configureAnalytics(AnalyticsService, options) { PropTypes.checkPropTypes(optionsShape, options, 'property', 'Analytics'); service = new AnalyticsService(options); PropTypes.checkPropTypes(serviceShape, service, 'property', 'AnalyticsService'); diff --git a/runtime/analytics/interface.test.js b/runtime/analytics/interface.test.js index 5f704781..1f63c436 100644 --- a/runtime/analytics/interface.test.js +++ b/runtime/analytics/interface.test.js @@ -1,5 +1,5 @@ import { - configure, + configureAnalytics, identifyAnonymousUser, identifyAuthenticatedUser, sendPageEvent, @@ -57,14 +57,14 @@ describe('Analytics', () => { }); } - describe('with valid SEGMENT_KEY', () => { + describe('with valid segmentKey', () => { beforeEach(() => { - service = configure(SegmentAnalyticsService, { + service = configureAnalytics(SegmentAnalyticsService, { loggingService: mockLoggingService, httpClient: mockAuthApiClient, config: { - LMS_BASE_URL: 'https://example.com', - SEGMENT_KEY: 'test-key', + lmsBaseUrl: 'https://example.com', + segmentKey: 'test-key', }, }); @@ -192,14 +192,14 @@ describe('Analytics', () => { }); }); - describe('with invalid SEGMENT_KEY', () => { + describe('with invalid segmentKey', () => { beforeEach(() => { - service = configure(SegmentAnalyticsService, { + service = configureAnalytics(SegmentAnalyticsService, { loggingService: mockLoggingService, httpClient: mockAuthApiClient, config: { - LMS_BASE_URL: 'https://example.com', - SEGMENT_KEY: '', + lmsBaseUrl: 'https://example.com', + segmentKey: '', }, }); diff --git a/runtime/auth/AxiosJwtAuthService.js b/runtime/auth/AxiosJwtAuthService.js index a6311bf3..41e4b669 100644 --- a/runtime/auth/AxiosJwtAuthService.js +++ b/runtime/auth/AxiosJwtAuthService.js @@ -1,23 +1,23 @@ import axios from 'axios'; import PropTypes from 'prop-types'; -import { logFrontendAuthError } from './utils'; import { camelCaseObject } from '../utils'; -import createJwtTokenProviderInterceptor from './interceptors/createJwtTokenProviderInterceptor'; +import AxiosCsrfTokenService from './AxiosCsrfTokenService'; +import AxiosJwtTokenService from './AxiosJwtTokenService'; import createCsrfTokenProviderInterceptor from './interceptors/createCsrfTokenProviderInterceptor'; +import createJwtTokenProviderInterceptor from './interceptors/createJwtTokenProviderInterceptor'; import createProcessAxiosRequestErrorInterceptor from './interceptors/createProcessAxiosRequestErrorInterceptor'; -import AxiosJwtTokenService from './AxiosJwtTokenService'; -import AxiosCsrfTokenService from './AxiosCsrfTokenService'; import configureCache from './LocalForageCache'; +import { logFrontendAuthError } from './utils'; const optionsPropTypes = { config: PropTypes.shape({ - BASE_URL: PropTypes.string.isRequired, - LMS_BASE_URL: PropTypes.string.isRequired, - LOGIN_URL: PropTypes.string.isRequired, - LOGOUT_URL: PropTypes.string.isRequired, - REFRESH_ACCESS_TOKEN_API_PATH: PropTypes.string.isRequired, - ACCESS_TOKEN_COOKIE_NAME: PropTypes.string.isRequired, - CSRF_TOKEN_API_PATH: PropTypes.string.isRequired, + baseUrl: PropTypes.string.isRequired, + lmsBaseUrl: PropTypes.string.isRequired, + loginUrl: PropTypes.string.isRequired, + logoutUrl: PropTypes.string.isRequired, + refreshAccessTokenApiPath: PropTypes.string.isRequired, + accessTokenCookieName: PropTypes.string.isRequired, + csrfTokenApiPath: PropTypes.string.isRequired, }).isRequired, loggingService: PropTypes.shape({ logError: PropTypes.func.isRequired, @@ -33,13 +33,13 @@ class AxiosJwtAuthService { /** * @param {Object} options * @param {Object} options.config - * @param {string} options.config.BASE_URL - * @param {string} options.config.LMS_BASE_URL - * @param {string} options.config.LOGIN_URL - * @param {string} options.config.LOGOUT_URL - * @param {string} options.config.REFRESH_ACCESS_TOKEN_API_PATH - * @param {string} options.config.ACCESS_TOKEN_COOKIE_NAME - * @param {string} options.config.CSRF_TOKEN_API_PATH + * @param {string} options.config.baseUrl + * @param {string} options.config.lmsBaseUrl + * @param {string} options.config.loginUrl + * @param {string} options.config.logoutUrl + * @param {string} options.config.refreshAccessTokenApiPath + * @param {string} options.config.accessTokenCookieName + * @param {string} options.config.csrfTokenApiPath * @param {Object} options.loggingService requires logError and logInfo methods */ constructor(options) { @@ -55,11 +55,11 @@ class AxiosJwtAuthService { this.loggingService = options.loggingService; this.jwtTokenService = new AxiosJwtTokenService( this.loggingService, - this.config.ACCESS_TOKEN_COOKIE_NAME, - this.config.LMS_BASE_URL, - this.config.REFRESH_ACCESS_TOKEN_API_PATH, + this.config.accessTokenCookieName, + this.config.lmsBaseUrl, + this.config.refreshAccessTokenApiPath, ); - this.csrfTokenService = new AxiosCsrfTokenService(this.config.CSRF_TOKEN_API_PATH); + this.csrfTokenService = new AxiosCsrfTokenService(this.config.csrfTokenApiPath); this.authenticatedHttpClient = this.addAuthenticationToHttpClient(axios.create()); this.httpClient = axios.create(); configureCache() @@ -160,8 +160,8 @@ class AxiosJwtAuthService { * * @param {string} redirectUrl The URL the user should be redirected to after logging in. */ - getLoginRedirectUrl(redirectUrl = this.config.BASE_URL) { - return `${this.config.LOGIN_URL}?next=${encodeURIComponent(redirectUrl)}`; + getLoginRedirectUrl(redirectUrl = this.config.baseUrl) { + return `${this.config.loginUrl}?next=${encodeURIComponent(redirectUrl)}`; } /** @@ -169,7 +169,7 @@ class AxiosJwtAuthService { * * @param {string} redirectUrl The URL the user should be redirected to after logging in. */ - redirectToLogin(redirectUrl = this.config.BASE_URL) { + redirectToLogin(redirectUrl = this.config.baseUrl) { global.location.assign(this.getLoginRedirectUrl(redirectUrl)); } @@ -183,8 +183,8 @@ class AxiosJwtAuthService { * * @param {string} redirectUrl The URL the user should be redirected to after logging out. */ - getLogoutRedirectUrl(redirectUrl = this.config.BASE_URL) { - return `${this.config.LOGOUT_URL}?redirect_url=${encodeURIComponent(redirectUrl)}`; + getLogoutRedirectUrl(redirectUrl = this.config.baseUrl) { + return `${this.config.logoutUrl}?redirect_url=${encodeURIComponent(redirectUrl)}`; } /** @@ -192,7 +192,7 @@ class AxiosJwtAuthService { * * @param {string} redirectUrl The URL the user should be redirected to after logging out. */ - redirectToLogout(redirectUrl = this.config.BASE_URL) { + redirectToLogout(redirectUrl = this.config.baseUrl) { global.location.assign(this.getLogoutRedirectUrl(redirectUrl)); } @@ -250,16 +250,15 @@ class AxiosJwtAuthService { * Ensures a user is authenticated. It will redirect to login when not * authenticated. * - * @param {string} [redirectUrl=config.BASE_URL] to return user after login when not + * @param {string} [redirectUrl=config.baseUrl] to return user after login when not * authenticated. * @returns {Promise} */ - async ensureAuthenticatedUser(redirectUrl = this.config.BASE_URL) { + async ensureAuthenticatedUser(redirectUrl = this.config.baseUrl) { await this.fetchAuthenticatedUser(); if (this.getAuthenticatedUser() === null) { - const isRedirectFromLoginPage = global.document.referrer - && global.document.referrer.startsWith(this.config.LOGIN_URL); + const isRedirectFromLoginPage = global.document.referrer?.startsWith(this.config.loginUrl); if (isRedirectFromLoginPage) { const redirectLoopError = new Error('Redirect from login page. Rejecting to avoid infinite redirect loop.'); @@ -295,7 +294,7 @@ class AxiosJwtAuthService { const user = this.getAuthenticatedUser(); if (user !== null) { const response = await this.authenticatedHttpClient - .get(`${this.config.LMS_BASE_URL}/api/user/v1/accounts/${user.username}`); + .get(`${this.config.lmsBaseUrl}/api/user/v1/accounts/${user.username}`); this.setAuthenticatedUser({ ...user, ...camelCaseObject(response.data) }); } } @@ -305,9 +304,9 @@ class AxiosJwtAuthService { * * @param {HttpClient} newHttpClient * @param {Object} config - * @param {string} [config.REFRESH_ACCESS_TOKEN_API_PATH] - * @param {string} [config.ACCESS_TOKEN_COOKIE_NAME] - * @param {string} [config.CSRF_TOKEN_API_PATH] + * @param {string} [config.refreshAccessTokenApiPath] + * @param {string} [config.accessTokenCookieName] + * @param {string} [config.csrfTokenApiPath] * @returns {HttpClient} A configured Axios HTTP client. */ addAuthenticationToHttpClient(newHttpClient) { @@ -331,7 +330,7 @@ class AxiosJwtAuthService { // headers. const attachCsrfTokenInterceptor = createCsrfTokenProviderInterceptor({ csrfTokenService: this.csrfTokenService, - CSRF_TOKEN_API_PATH: this.config.CSRF_TOKEN_API_PATH, + csrfTokenApiPath: this.config.csrfTokenApiPath, shouldSkip: (axiosRequestConfig) => { const { method, isCsrfExempt } = axiosRequestConfig; const CSRF_PROTECTED_METHODS = ['post', 'put', 'patch', 'delete']; diff --git a/runtime/auth/AxiosJwtAuthService.test.jsx b/runtime/auth/AxiosJwtAuthService.test.jsx index 37a351a1..540516ed 100644 --- a/runtime/auth/AxiosJwtAuthService.test.jsx +++ b/runtime/auth/AxiosJwtAuthService.test.jsx @@ -70,7 +70,7 @@ Object.keys(jwtTokens).forEach((jwtTokenName) => { }); const mockCsrfToken = 'thetokenvalue'; -const mockApiEndpointPath = `${authOptions.config.BASE_URL}/api/v1/test`; +const mockApiEndpointPath = `${authOptions.config.baseUrl}/api/v1/test`; global.location ??= { ...global.location, assign: jest.fn() }; @@ -87,7 +87,7 @@ let cachedClient = null; // Helpers const setJwtCookieTo = (jwtCookieValue) => { mockCookies.get.mockImplementation((cookieName) => { - if (cookieName === authOptions.config.ACCESS_TOKEN_COOKIE_NAME) { + if (cookieName === authOptions.config.accessTokenCookieName) { return jwtCookieValue; } return undefined; @@ -105,16 +105,16 @@ const setJwtTokenRefreshResponseTo = (status, jwtCookieValue, responseEpochSecon }); }; -function expectLogout(redirectUrl = authOptions.config.BASE_URL) { +function expectLogout(redirectUrl = authOptions.config.baseUrl) { const encodedRedirectUrl = encodeURIComponent(redirectUrl); expect(global.location.assign) - .toHaveBeenCalledWith(`${authOptions.config.LOGOUT_URL}?redirect_url=${encodedRedirectUrl}`); + .toHaveBeenCalledWith(`${authOptions.config.logoutUrl}?redirect_url=${encodedRedirectUrl}`); } -function expectLogin(redirectUrl = authOptions.config.BASE_URL) { +function expectLogin(redirectUrl = authOptions.config.baseUrl) { const encodedRedirectUrl = encodeURIComponent(redirectUrl); expect(global.location.assign) - .toHaveBeenCalledWith(`${authOptions.config.LOGIN_URL}?next=${encodedRedirectUrl}`); + .toHaveBeenCalledWith(`${authOptions.config.loginUrl}?next=${encodedRedirectUrl}`); } // customAttributes is sent into expect.objectContaining @@ -319,7 +319,7 @@ describe('authenticatedHttpClient usage', () => { expectRequestToHaveCsrfToken(axiosMock.history[method][0]); expectRequestToHaveJwtAuth(axiosMock.history[method][0]); expect(csrfTokensAxiosMock.history.get[0].url) - .toEqual(`${global.location.origin}${authOptions.config.CSRF_TOKEN_API_PATH}`); + .toEqual(`${global.location.origin}${authOptions.config.csrfTokenApiPath}`); }); }); }); @@ -730,7 +730,7 @@ describe('redirectToLogin', () => { service.redirectToLogin('http://edx.org/dashboard'); expectLogin('http://edx.org/dashboard'); service.redirectToLogin(); - expectLogin(authOptions.config.BASE_URL); + expectLogin(authOptions.config.baseUrl); }); }); @@ -739,7 +739,7 @@ describe('redirectToLogout', () => { service.redirectToLogout('http://edx.org/'); expectLogout('http://edx.org/'); service.redirectToLogout(); - expectLogout(authOptions.config.BASE_URL); + expectLogout(authOptions.config.baseUrl); }); }); @@ -762,7 +762,7 @@ describe('hydrateAuthenticatedUser', () => { administrator: false, name: 'test user', }); - axiosMock.onGet(`${authOptions.config.LMS_BASE_URL}/api/user/v1/accounts/the_user`).reply(200, { + axiosMock.onGet(`${authOptions.config.lmsBaseUrl}/api/user/v1/accounts/the_user`).reply(200, { additional: 'data', }); await service.hydrateAuthenticatedUser(); @@ -825,15 +825,15 @@ describe('ensureAuthenticatedUser', () => { it('attempts to refresh a missing jwt token and redirects user to login', () => { setJwtCookieTo(null); expect.hasAssertions(); - return service.ensureAuthenticatedUser(`${authOptions.config.BASE_URL}/route`).catch((unauthorizedError) => { + return service.ensureAuthenticatedUser(`${authOptions.config.baseUrl}/route`).catch((unauthorizedError) => { expect(unauthorizedError.isRedirecting).toBe(true); expectSingleCallToJwtTokenRefresh(); - expectLogin(`${authOptions.config.BASE_URL}/route`); + expectLogin(`${authOptions.config.baseUrl}/route`); }); }); it('throws an error and does not redirect if the referrer is the login page', () => { - jest.spyOn(global.document, 'referrer', 'get').mockReturnValue(authOptions.config.LOGIN_URL); + jest.spyOn(global.document, 'referrer', 'get').mockReturnValue(authOptions.config.loginUrl); setJwtCookieTo(null); expect.hasAssertions(); return service.ensureAuthenticatedUser().catch(() => { diff --git a/runtime/auth/AxiosJwtTokenService.js b/runtime/auth/AxiosJwtTokenService.js index 9b28ed2e..69227275 100644 --- a/runtime/auth/AxiosJwtTokenService.js +++ b/runtime/auth/AxiosJwtTokenService.js @@ -61,8 +61,7 @@ export default class AxiosJwtTokenService { try { try { axiosResponse = await this.httpClient.post(`${this.tokenRefreshBaseUrl}${this.tokenRefreshPath}`); - // eslint-disable-next-line max-len - if (axiosResponse.data && axiosResponse.data.response_epoch_seconds) { + if (axiosResponse.data?.response_epoch_seconds) { responseServerEpochSeconds = axiosResponse.data.response_epoch_seconds; } } catch (error) { @@ -125,8 +124,6 @@ export default class AxiosJwtTokenService { } try { - // Eslint is incorrect - refresh() DOES return a promise. - // eslint-disable-next-line @typescript-eslint/return-await return await this.refresh(); } catch (e) { // TODO: Fix these. They're still using loggingService as a singleton. diff --git a/runtime/auth/LocalForageCache.js b/runtime/auth/LocalForageCache.js index 0b9416b2..596033da 100644 --- a/runtime/auth/LocalForageCache.js +++ b/runtime/auth/LocalForageCache.js @@ -1,13 +1,12 @@ -/* eslint-disable no-underscore-dangle */ -import localforage from 'localforage'; -import memoryDriver from 'localforage-memoryStorageDriver'; +import axios from 'axios'; import { - setupCache, - defaultKeyGenerator, - defaultHeaderInterpreter, buildStorage, + defaultHeaderInterpreter, + defaultKeyGenerator, + setupCache, } from 'axios-cache-interceptor'; -import axios from 'axios'; +import localforage from 'localforage'; +import memoryDriver from 'localforage-memoryStorageDriver'; /** * Async function to configure localforage and setup the cache @@ -71,7 +70,6 @@ export default async function configureCache() { // // https://axios-cache-interceptor.js.org/#/pages/development-mode // https://axios-cache-interceptor.js.org/#/pages/global-configuration?id=debug - // eslint-disable-next-line no-console debug: console.log, }, ); diff --git a/runtime/auth/MockAuthService.js b/runtime/auth/MockAuthService.js index cc9e7c88..6f0508a8 100644 --- a/runtime/auth/MockAuthService.js +++ b/runtime/auth/MockAuthService.js @@ -10,13 +10,13 @@ const userPropTypes = PropTypes.shape({ const optionsPropTypes = { config: PropTypes.shape({ - BASE_URL: PropTypes.string.isRequired, - LMS_BASE_URL: PropTypes.string.isRequired, - LOGIN_URL: PropTypes.string.isRequired, - LOGOUT_URL: PropTypes.string.isRequired, - REFRESH_ACCESS_TOKEN_API_PATH: PropTypes.string.isRequired, - ACCESS_TOKEN_COOKIE_NAME: PropTypes.string.isRequired, - CSRF_TOKEN_API_PATH: PropTypes.string.isRequired, + baseUrl: PropTypes.string.isRequired, + lmsBaseUrl: PropTypes.string.isRequired, + loginUrl: PropTypes.string.isRequired, + logoutUrl: PropTypes.string.isRequired, + refreshAccessTokenApiPath: PropTypes.string.isRequired, + accessTokenCookieName: PropTypes.string.isRequired, + csrfTokenApiPath: PropTypes.string.isRequired, }).isRequired, loggingService: PropTypes.shape({ logError: PropTypes.func.isRequired, @@ -60,7 +60,7 @@ const optionsPropTypes = { * administrator: false, * }, * }); - * configure(MockAuthService, { config: getConfig(), loggingService: mockLoggingService }); + * configureAuth(MockAuthService, { config: getConfig(), loggingService: mockLoggingService }); * const mockAdapter = new MockAdapter(getAuthenticatedHttpClient()); * // Mock calls for your tests. This configuration can be done in any sort of test setup. * mockAdapter.onGet(...); @@ -76,13 +76,13 @@ class MockAuthService { /** * @param {Object} options * @param {Object} options.config - * @param {string} options.config.BASE_URL - * @param {string} options.config.LMS_BASE_URL - * @param {string} options.config.LOGIN_URL - * @param {string} options.config.LOGOUT_URL - * @param {string} options.config.REFRESH_ACCESS_TOKEN_API_PATH - * @param {string} options.config.ACCESS_TOKEN_COOKIE_NAME - * @param {string} options.config.CSRF_TOKEN_API_PATH + * @param {string} options.config.baseUrl + * @param {string} options.config.lmsBaseUrl + * @param {string} options.config.loginUrl + * @param {string} options.config.logoutUrl + * @param {string} options.config.refreshAccessTokenApiPath + * @param {string} options.config.accessTokenCookieName + * @param {string} options.config.csrfTokenApiPath * @param {Object} options.loggingService requires logError and logInfo methods */ constructor(options) { @@ -156,7 +156,7 @@ class MockAuthService { * @param {string} redirectUrl The URL the user should be redirected to after logging in. */ getLoginRedirectUrl = jest.fn( - (redirectUrl = this.config.BASE_URL) => `${this.config.LOGIN_URL}?next=${encodeURIComponent(redirectUrl)}`, + (redirectUrl = this.config.baseUrl) => `${this.config.loginUrl}?next=${encodeURIComponent(redirectUrl)}`, ); /** @@ -166,7 +166,7 @@ class MockAuthService { * * @param {string} redirectUrl The URL the user should be redirected to after logging in. */ - redirectToLogin = jest.fn((redirectUrl = this.config.BASE_URL) => { + redirectToLogin = jest.fn((redirectUrl = this.config.baseUrl) => { // Do nothing after getting the URL - this preserves the calls properly, but doesn't redirect. this.getLoginRedirectUrl(redirectUrl); }); @@ -183,7 +183,7 @@ class MockAuthService { * * @param {string} redirectUrl The URL the user should be redirected to after logging out. */ - getLogoutRedirectUrl = jest.fn((redirectUrl = this.config.BASE_URL) => `${this.config.LOGOUT_URL}?redirect_url=${encodeURIComponent(redirectUrl)}`); + getLogoutRedirectUrl = jest.fn((redirectUrl = this.config.baseUrl) => `${this.config.logoutUrl}?redirect_url=${encodeURIComponent(redirectUrl)}`); /** * A Jest mock function (jest.fn()) @@ -192,7 +192,7 @@ class MockAuthService { * * @param {string} redirectUrl The URL the user should be redirected to after logging out. */ - redirectToLogout = jest.fn((redirectUrl = this.config.BASE_URL) => { + redirectToLogout = jest.fn((redirectUrl = this.config.baseUrl) => { // Do nothing after getting the URL - this preserves the calls properly, but doesn't redirect. this.getLogoutRedirectUrl(redirectUrl); }); @@ -235,12 +235,12 @@ class MockAuthService { * * Ensures a user is authenticated. It will redirect to login when not authenticated. * - * @param {string} [redirectUrl=config.BASE_URL] to return user after login when not + * @param {string} [redirectUrl=config.baseUrl] to return user after login when not * authenticated. * @returns {UserData|null} Resolves to the user's access token if they are * logged in. */ - ensureAuthenticatedUser = jest.fn((redirectUrl = this.config.BASE_URL) => { + ensureAuthenticatedUser = jest.fn((redirectUrl = this.config.baseUrl) => { this.fetchAuthenticatedUser(); if (this.getAuthenticatedUser() === null) { diff --git a/runtime/auth/index.js b/runtime/auth/index.ts similarity index 92% rename from runtime/auth/index.js rename to runtime/auth/index.ts index 779c43f0..eaf890bb 100644 --- a/runtime/auth/index.js +++ b/runtime/auth/index.ts @@ -1,19 +1,19 @@ +export { default as AxiosJwtAuthService } from './AxiosJwtAuthService'; export { - AUTHENTICATED_USER_TOPIC, AUTHENTICATED_USER_CHANGED, - configure, + AUTHENTICATED_USER_TOPIC, + configureAuth, + ensureAuthenticatedUser, + fetchAuthenticatedUser, getAuthenticatedHttpClient, + getAuthenticatedUser, getAuthService, getHttpClient, getLoginRedirectUrl, - redirectToLogin, getLogoutRedirectUrl, - redirectToLogout, - getAuthenticatedUser, - setAuthenticatedUser, - fetchAuthenticatedUser, - ensureAuthenticatedUser, hydrateAuthenticatedUser, + redirectToLogin, + redirectToLogout, + setAuthenticatedUser } from './interface'; -export { default as AxiosJwtAuthService } from './AxiosJwtAuthService'; export { default as MockAuthService } from './MockAuthService'; diff --git a/runtime/auth/interceptors/createCsrfTokenProviderInterceptor.js b/runtime/auth/interceptors/createCsrfTokenProviderInterceptor.js index bdff94d9..6ccad1bd 100644 --- a/runtime/auth/interceptors/createCsrfTokenProviderInterceptor.js +++ b/runtime/auth/interceptors/createCsrfTokenProviderInterceptor.js @@ -1,5 +1,5 @@ const createCsrfTokenProviderInterceptor = (options) => { - const { csrfTokenService, CSRF_TOKEN_API_PATH, shouldSkip } = options; + const { csrfTokenService, csrfTokenApiPath, shouldSkip } = options; // Creating the interceptor inside this closure to // maintain reference to the options supplied. @@ -16,7 +16,7 @@ const createCsrfTokenProviderInterceptor = (options) => { // (namely our retry request interceptor below) to access the original request // and handle it appropriately try { - csrfToken = await csrfTokenService.getCsrfToken(url, CSRF_TOKEN_API_PATH); + csrfToken = await csrfTokenService.getCsrfToken(url, csrfTokenApiPath); } catch (error) { const requestError = Object.create(error); requestError.message = `[getCsrfToken] ${requestError.message}`; @@ -26,7 +26,6 @@ const createCsrfTokenProviderInterceptor = (options) => { } const CSRF_HEADER_NAME = 'X-CSRFToken'; - // eslint-disable-next-line no-param-reassign axiosRequestConfig.headers[CSRF_HEADER_NAME] = csrfToken; return axiosRequestConfig; }; diff --git a/runtime/auth/interceptors/createJwtTokenProviderInterceptor.js b/runtime/auth/interceptors/createJwtTokenProviderInterceptor.js index ae4279e5..b9f57953 100644 --- a/runtime/auth/interceptors/createJwtTokenProviderInterceptor.js +++ b/runtime/auth/interceptors/createJwtTokenProviderInterceptor.js @@ -27,7 +27,6 @@ const createJwtTokenProviderInterceptor = (options) => { } // Add the proper headers to tell the server to look for the jwt cookie - // eslint-disable-next-line no-param-reassign axiosRequestConfig.headers['USE-JWT-COOKIE'] = true; return axiosRequestConfig; }; diff --git a/runtime/auth/interceptors/createRetryInterceptor.js b/runtime/auth/interceptors/createRetryInterceptor.js index 65360e18..55cfef4c 100644 --- a/runtime/auth/interceptors/createRetryInterceptor.js +++ b/runtime/auth/interceptors/createRetryInterceptor.js @@ -52,7 +52,9 @@ const createRetryInterceptor = (options = {}) => { try { const backoffDelay = getBackoffMilliseconds(nthRetry); // Delay (wrapped in a promise so we can await the setTimeout) - await new Promise(resolve => { setTimeout(resolve, backoffDelay); }); + await new Promise(resolve => { + setTimeout(resolve, backoffDelay); + }); // Make retry request retryResponse = await httpClient.request(config); } catch (e) { diff --git a/runtime/auth/interface.js b/runtime/auth/interface.js index ecf85231..be885fb7 100644 --- a/runtime/auth/interface.js +++ b/runtime/auth/interface.js @@ -10,14 +10,14 @@ * * ``` * import { - * configure, + * configureAuth, * fetchAuthenticatedUser, * getAuthenticatedHttpClient, * getConfig, * getLoggingService * } from '@openedx/frontend-base'; * - * configure({ + * configureAuth({ * loggingService: getLoggingService(), * config: getConfig(), * }); @@ -35,6 +35,7 @@ * @module Auth */ import PropTypes from 'prop-types'; +import { publish } from '../subscriptions'; /** * @constant @@ -55,13 +56,13 @@ export const AUTHENTICATED_USER_CHANGED = `${AUTHENTICATED_USER_TOPIC}.CHANGED`; const optionsShape = { config: PropTypes.shape({ - BASE_URL: PropTypes.string.isRequired, - LMS_BASE_URL: PropTypes.string.isRequired, - LOGIN_URL: PropTypes.string.isRequired, - LOGOUT_URL: PropTypes.string.isRequired, - REFRESH_ACCESS_TOKEN_API_PATH: PropTypes.string.isRequired, - ACCESS_TOKEN_COOKIE_NAME: PropTypes.string.isRequired, - CSRF_TOKEN_API_PATH: PropTypes.string.isRequired, + baseUrl: PropTypes.string.isRequired, + lmsBaseUrl: PropTypes.string.isRequired, + loginUrl: PropTypes.string.isRequired, + logoutUrl: PropTypes.string.isRequired, + refreshAccessTokenApiPath: PropTypes.string.isRequired, + accessTokenCookieName: PropTypes.string.isRequired, + csrfTokenApiPath: PropTypes.string.isRequired, }).isRequired, loggingService: PropTypes.shape({ logError: PropTypes.func.isRequired, @@ -91,7 +92,7 @@ let service; * @param {*} options * @returns {AuthService} */ -export function configure(AuthService, options) { +export function configureAuth(AuthService, options) { PropTypes.checkPropTypes(optionsShape, options, 'property', 'Auth'); service = new AuthService(options); PropTypes.checkPropTypes(serviceShape, service, 'property', 'AuthService'); @@ -206,7 +207,7 @@ export function getAuthenticatedUser() { */ export function setAuthenticatedUser(authUser) { service.setAuthenticatedUser(authUser); - global.PubSub.publish(AUTHENTICATED_USER_CHANGED); + publish(AUTHENTICATED_USER_CHANGED); } /** @@ -224,7 +225,7 @@ export async function fetchAuthenticatedUser(options = {}) { * Ensures a user is authenticated. It will redirect to login when not * authenticated. * - * @param {string} [redirectUrl=config.BASE_URL] to return user after login when not + * @param {string} [redirectUrl=config.baseUrl] to return user after login when not * authenticated. * @returns {Promise} */ @@ -247,7 +248,7 @@ export async function ensureAuthenticatedUser(redirectUrl) { */ export async function hydrateAuthenticatedUser() { await service.hydrateAuthenticatedUser(); - global.PubSub.publish(AUTHENTICATED_USER_CHANGED); + publish(AUTHENTICATED_USER_CHANGED); } /** diff --git a/runtime/auth/utils.js b/runtime/auth/utils.js index 92c174e5..b9aca0f2 100644 --- a/runtime/auth/utils.js +++ b/runtime/auth/utils.js @@ -101,5 +101,5 @@ export { getUrlParts, logFrontendAuthError, processAxiosError, - processAxiosErrorAndThrow, + processAxiosErrorAndThrow }; diff --git a/runtime/config.ts b/runtime/config/index.ts similarity index 51% rename from runtime/config.ts rename to runtime/config/index.ts index f1ac6ebf..8a833c76 100644 --- a/runtime/config.ts +++ b/runtime/config/index.ts @@ -2,7 +2,7 @@ * #### Import members from **@edx/frontend-base** * * The configuration module provides utilities for working with an application's configuration - * document (ConfigDocument). Configuration variables can be supplied to the + * document (SiteConfig). Configuration variables can be supplied to the * application in three different ways. They are applied in the following order: * * - Site Configuration File (site.config.tsx) @@ -33,7 +33,7 @@ * Exporting a config object: * ``` * const config = { - * LMS_BASE_URL: 'http://localhost:18000' + * lmsBaseUrl: 'http://localhost:18000' * }; * * export default config; @@ -43,7 +43,7 @@ * ``` * function getConfig() { * return { - * LMS_BASE_URL: 'http://localhost:18000' + * lmsBaseUrl: 'http://localhost:18000' * }; * } * ``` @@ -53,7 +53,7 @@ * function getAsyncConfig() { * return new Promise((resolve, reject) => { * resolve({ - * LMS_BASE_URL: 'http://localhost:18000' + * lmsBaseUrl: 'http://localhost:18000' * }); * }); * } @@ -73,7 +73,7 @@ * config: () => { * mergeConfig({ * CUSTOM_VARIABLE: 'custom value', - * LMS_BASE_URL: 'http://localhost:18001' // You can override variables, but this is uncommon. + * lmsBaseUrl: 'http://localhost:18001' // You can override variables, but this is uncommon. * }, 'App config override handler'); * }, * }, @@ -88,7 +88,7 @@ * * https://github.com/openedx/edx-platform/blob/master/lms/djangoapps/mfe_config_api/docs/decisions/0001-mfe-config-api.rst * - * The runtime configuration method can be enabled by supplying a MFE_CONFIG_API_URL via one of the other + * The runtime configuration method can be enabled by supplying a mfeConfigApiUrl via one of the other * two configuration methods above. * * Runtime configuration is particularly useful if you need to supply different configurations to @@ -101,65 +101,50 @@ */ import merge from 'lodash.merge'; -import 'pubsub-js'; import { - AppConfigTypes, ApplicationModuleConfig, ConfigurableAppConfig, EnvironmentTypes, SiteConfig -} from '../types'; -import { CONFIG_CHANGED } from './constants'; + App, + AppConfig, + EnvironmentTypes, + OptionalSiteConfig, + Remote, + RequiredSiteConfig, + SiteConfig +} from '../../types'; +import { ACTIVE_ROLES_CHANGED, APPS_CHANGED, CONFIG_CHANGED } from '../constants'; +import { publish } from '../subscriptions'; let config: SiteConfig = { - ACCESS_TOKEN_COOKIE_NAME: 'edx-jwt-cookie-header-payload', - CSRF_TOKEN_API_PATH: '/csrf/api/v1/token', - ENVIRONMENT: EnvironmentTypes.PRODUCTION, - IGNORED_ERROR_REGEX: null, - LANGUAGE_PREFERENCE_COOKIE_NAME: 'openedx-language-preference', - PUBLIC_PATH: '/', - REFRESH_ACCESS_TOKEN_API_PATH: '/login_refresh', - USER_INFO_COOKIE_NAME: 'edx-user-info', - MFE_CONFIG_API_URL: null, + accessTokenCookieName: 'edx-jwt-cookie-header-payload', + csrfTokenApiPath: '/csrf/api/v1/token', + environment: EnvironmentTypes.PRODUCTION, + ignoredErrorRegex: null, + languagePreferenceCookieName: 'openedx-language-preference', + publicPath: '/', + refreshAccessTokenApiPath: '/login_refresh', + userInfoCookieName: 'edx-user-info', + mfeConfigApiUrl: null, - SEGMENT_KEY: null, - SUPPORT_EMAIL: null, + segmentKey: null, - // Optional Frontends - ORDER_HISTORY_URL: null, - SUPPORT_URL: null, - TERMS_OF_SERVICE_URL: null, - PRIVACY_POLICY_URL: null, - ACCESSIBILITY_URL: null, + apps: [], + remotes: [], + federatedApps: [], + externalRoutes: [], - // Optional Backends - CREDENTIALS_BASE_URL: null, - DISCOVERY_API_BASE_URL: null, - ECOMMERCE_BASE_URL: null, - PUBLISHER_BASE_URL: null, - - apps: {}, - pluginSlots: {}, - custom: {}, - - APP_ID: '', - BASE_URL: '', - SITE_NAME: '', + appId: '', + baseUrl: '', + siteName: '', // Frontends - ACCOUNT_PROFILE_URL: '', - ACCOUNT_SETTINGS_URL: '', - LEARNER_DASHBOARD_URL: '', - LEARNING_BASE_URL: '', - LOGIN_URL: '', - LOGOUT_URL: '', - MARKETING_SITE_BASE_URL: '', + loginUrl: '', + logoutUrl: '', // Backends - LMS_BASE_URL: '', - STUDIO_BASE_URL: '', + lmsBaseUrl: '', - // Branding - FAVICON_URL: '', - LOGO_TRADEMARK_URL: '', - LOGO_URL: '', - LOGO_WHITE_URL: '' + custom: { + appId: '', + }, }; /** @@ -172,18 +157,18 @@ let config: SiteConfig = { * import { getConfig } from '@openedx/frontend-base'; * * const { - * LMS_BASE_URL, + * lmsBaseUrl, * } = getConfig(); * ``` * - * @returns {ConfigDocument} + * @returns {SiteConfig} */ export function getConfig() { return config; } /** - * Replaces the existing ConfigDocument. This is not commonly used, but can be helpful for tests. + * Replaces the existing SiteConfig. This is not commonly used, but can be helpful for tests. * * Example: * @@ -191,15 +176,15 @@ export function getConfig() { * import { setConfig } from '@openedx/frontend-base'; * * setConfig({ - * LMS_BASE_URL, // This is overriding the ENTIRE document - this is not merged in! + * lmsBaseUrl, // This is overriding the ENTIRE document - this is not merged in! * }); * ``` * - * @param {ConfigDocument} newConfig + * @param newConfig A replacement SiteConfig which will completely override the current SiteConfig. */ export function setConfig(newConfig: SiteConfig) { config = newConfig; - global.PubSub.publish(CONFIG_CHANGED); + publish(CONFIG_CHANGED); } /** @@ -218,59 +203,108 @@ export function setConfig(newConfig: SiteConfig) { * * @param {Object} newConfig */ -export function mergeConfig(newConfig: Partial) { +export function mergeConfig(newConfig: Partial & RequiredSiteConfig>) { config = merge(config, newConfig); - global.PubSub.publish(CONFIG_CHANGED); + publish(CONFIG_CHANGED); } -export function patchAppModuleConfig(appId: string, appModuleConfig: ApplicationModuleConfig) { - if (config.apps[appId] !== undefined) { - const app = config.apps[appId]; - if (app.type === AppConfigTypes.INTERNAL || app.type === AppConfigTypes.FEDERATED) { - const configurableApp = app as ConfigurableAppConfig; - configurableApp.config = appModuleConfig; +/** + * patchApp is used to lazy load Apps after the initial SiteConfig.apps array has been created. + * This is most often used after loading FederatedApps. + */ +export function patchApp(app: App) { + config.apps.push(app); + if (app.config !== undefined) { + patchAppConfig(app.config); + } + publish(APPS_CHANGED); + publish(CONFIG_CHANGED); +} + +const appConfigs: Record = {}; + +/** + * addAppConfigs finds any AppConfig objects in the apps in SiteConfig and makes their config + * available to be used by Apps via the getAppConfig() function. This is used at initialization + * time to process any AppConfigs bundled with the site. + */ +export function addAppConfigs() { + const { apps } = getConfig(); + for (const app of apps) { + if (app.config !== undefined) { + patchAppConfig(app.config); } } + publish(CONFIG_CHANGED); +} + +export function getAppConfig(id: string) { + return appConfigs[id]; +} + +export function patchAppConfig(appConfig: AppConfig) { + appConfigs[appConfig.appId] = appConfig; } /** - * An object describing the current application configuration. - * - * In its most basic form, this document contains some sensible defaults. The initialization - * process then merges additional configuration into this document using the configuration methods - * described above. (Site configuration file, initialization config handler, and runtime - * configuration) - * - * @name ConfigDocument - * @memberof module:Config - * @property {string} ACCESS_TOKEN_COOKIE_NAME - * @property {string} ACCOUNT_PROFILE_URL - * @property {string} ACCOUNT_SETTINGS_URL - * @property {string} BASE_URL The URL of the current application. - * @property {string} CREDENTIALS_BASE_URL - * @property {string} CSRF_TOKEN_API_PATH - * @property {string} DISCOVERY_API_BASE_URL - * @property {string} PUBLISHER_BASE_URL - * @property {string} ECOMMERCE_BASE_URL - * @property {string} ENVIRONMENT This is one of: development, production, or test. - * @property {string} IGNORED_ERROR_REGEX - * @property {string} LANGUAGE_PREFERENCE_COOKIE_NAME - * @property {string} LEARNING_BASE_URL - * @property {string} LMS_BASE_URL - * @property {string} LOGIN_URL - * @property {string} LOGOUT_URL - * @property {string} STUDIO_BASE_URL - * @property {string} MARKETING_SITE_BASE_URL - * @property {string} ORDER_HISTORY_URL - * @property {string} REFRESH_ACCESS_TOKEN_API_PATH - * @property {string} SEGMENT_KEY - * @property {string} SITE_NAME - * @property {string} USER_INFO_COOKIE_NAME - * @property {string} LOGO_URL - * @property {string} LOGO_TRADEMARK_URL - * @property {string} LOGO_WHITE_URL - * @property {string} FAVICON_URL - * @property {string} MFE_CONFIG_API_URL - * @property {string} APP_ID - * @property {string} SUPPORT_URL + * This function will attempt to add the supplied remotes to the SiteConfig. If a remote with that + * ID already exists, it will not be added. If changes are made to the SiteConfig, the + * CONFIG_CHANGED event will be published. + * + * @param remotes An array of Remote objects to merge into the SiteConfig's `remotes` array. */ +export function mergeRemotes(remotes: Remote[]) { + const remoteIds = config.remotes.map(remote => remote.id); + let changed = false; + for (const remote of remotes) { + if (!remoteIds.includes(remote.id)) { + config.remotes.push(remote); + changed = true; + } + } + if (changed) { + publish(CONFIG_CHANGED); + } +} + +let activeRouteRoles: string[] = []; + +export function setActiveRouteRoles(roles: string[]) { + activeRouteRoles = roles; + publish(ACTIVE_ROLES_CHANGED); +} + +export function getActiveRouteRoles() { + return activeRouteRoles; +} + +const activeWidgetRoles: Record = {}; + +export function addActiveWidgetRole(role: string) { + if (activeWidgetRoles[role] === undefined) { + activeWidgetRoles[role] = 0; + } + activeWidgetRoles[role] += 1; + publish(ACTIVE_ROLES_CHANGED); +} + +export function removeActiveWidgetRole(role: string) { + if (activeWidgetRoles[role] !== undefined) { + activeWidgetRoles[role] -= 1; + } + if (activeWidgetRoles[role] < 1) { + delete activeWidgetRoles[role]; + } + publish(ACTIVE_ROLES_CHANGED); +} + +export function getActiveWidgetRoles() { + return Object.entries(activeWidgetRoles) + .filter(([, count]: [role: string, count: number]) => count !== undefined && count > 0) + .map(([role]: [role: string, count: number]) => role); +} + +// Gets all active roles from the route roles and widget roles. +export function getActiveRoles() { + return [...getActiveRouteRoles(), ...getActiveWidgetRoles()]; +} diff --git a/runtime/constants.js b/runtime/constants.ts similarity index 93% rename from runtime/constants.js rename to runtime/constants.ts index 99bddd83..04173a50 100644 --- a/runtime/constants.js +++ b/runtime/constants.ts @@ -64,3 +64,9 @@ export const APP_INIT_ERROR = `${APP_TOPIC}.INIT_ERROR`; export const CONFIG_TOPIC = 'CONFIG'; export const CONFIG_CHANGED = `${CONFIG_TOPIC}.CHANGED`; + +export const APPS_TOPIC = 'APPS'; + +export const APPS_CHANGED = `${APPS_TOPIC}.CHANGED`; + +export const ACTIVE_ROLES_CHANGED = 'ACTIVE_ROLES_CHANGED'; diff --git a/runtime/i18n/countries.js b/runtime/i18n/countries.js deleted file mode 100644 index 8acad645..00000000 --- a/runtime/i18n/countries.js +++ /dev/null @@ -1,71 +0,0 @@ -/* eslint-disable import/extensions */ -import COUNTRIES, { langs as countryLangs } from 'i18n-iso-countries'; - -import arLocale from 'i18n-iso-countries/langs/ar.json'; -import enLocale from 'i18n-iso-countries/langs/en.json'; -import esLocale from 'i18n-iso-countries/langs/es.json'; -import frLocale from 'i18n-iso-countries/langs/fr.json'; -import zhLocale from 'i18n-iso-countries/langs/zh.json'; -import caLocale from 'i18n-iso-countries/langs/ca.json'; -import heLocale from 'i18n-iso-countries/langs/he.json'; -import idLocale from 'i18n-iso-countries/langs/id.json'; -import koLocale from 'i18n-iso-countries/langs/ko.json'; -import plLocale from 'i18n-iso-countries/langs/pl.json'; -import ptLocale from 'i18n-iso-countries/langs/pt.json'; -import ruLocale from 'i18n-iso-countries/langs/ru.json'; -import ukLocale from 'i18n-iso-countries/langs/uk.json'; - -import { getPrimaryLanguageSubtag } from './lib'; - -/* - * COUNTRY LISTS - * - * Lists of country names localized in supported languages. - * - * TODO: When we start dynamically loading translations only for the current locale, change this. - */ - -COUNTRIES.registerLocale(arLocale); -COUNTRIES.registerLocale(enLocale); -COUNTRIES.registerLocale(esLocale); -COUNTRIES.registerLocale(frLocale); -COUNTRIES.registerLocale(zhLocale); -COUNTRIES.registerLocale(caLocale); -COUNTRIES.registerLocale(heLocale); -COUNTRIES.registerLocale(idLocale); -COUNTRIES.registerLocale(koLocale); -COUNTRIES.registerLocale(plLocale); -COUNTRIES.registerLocale(ptLocale); -COUNTRIES.registerLocale(ruLocale); -// COUNTRIES.registerLocale(thLocale); // Doesn't exist in lib. -COUNTRIES.registerLocale(ukLocale); - -/** - * Provides a lookup table of country IDs to country names for the current locale. - * - * @memberof module:I18n - */ -export function getCountryMessages(locale) { - const primaryLanguageSubtag = getPrimaryLanguageSubtag(locale); - const languageCode = countryLangs().includes(primaryLanguageSubtag) ? primaryLanguageSubtag : 'en'; - - return COUNTRIES.getNames(languageCode); -} - -/** - * Provides a list of countries represented as objects of the following shape: - * - * { - * key, // The ID of the country - * name // The localized name of the country - * } - * - * TODO: ARCH-878: The list should be sorted alphabetically in the current locale. - * This is useful for populating dropdowns. - * - * @memberof module:I18n - */ -export function getCountryList(locale) { - const countryMessages = getCountryMessages(locale); - return Object.entries(countryMessages).map(([code, name]) => ({ code, name })); -} diff --git a/runtime/i18n/index.js b/runtime/i18n/index.js index 6d439f6f..ffaa6ee6 100644 --- a/runtime/i18n/index.js +++ b/runtime/i18n/index.js @@ -14,7 +14,7 @@ * (in our case English), *even if you gave IntlProvider the correct messages object for that * locale*. * - * Messages are provided to this module via the configure() function below. + * Messages are provided to this module via the configureI18n() function below. * * * @module Internationalization @@ -85,40 +85,34 @@ export { createIntl, + defineMessages, FormattedDate, - FormattedTime, - FormattedRelativeTime, + FormattedMessage, FormattedNumber, FormattedPlural, - FormattedMessage, - defineMessages, + FormattedRelativeTime, + FormattedTime, IntlProvider, - useIntl, + useIntl } from 'react-intl'; export { - intlShape, - configure, - getPrimaryLanguageSubtag, + addAppMessages, + configureI18n, getLocale, + getLocalizedLanguageName, getMessages, - isRtl, + getPrimaryLanguageSubtag, + getSupportedLanguageList, handleRtl, - mergeMessages, + intlShape, + isRtl, LOCALE_CHANGED, LOCALE_TOPIC, + mergeMessages, + updateLocale } from './lib'; export { - default as injectIntl, + default as injectIntl } from './injectIntlWithShim'; - -export { - getCountryList, - getCountryMessages, -} from './countries'; - -export { - getLanguageList, - getLanguageMessages, -} from './languages'; diff --git a/runtime/i18n/injectIntlWithShim.jsx b/runtime/i18n/injectIntlWithShim.jsx index 1141b494..4f5239c9 100644 --- a/runtime/i18n/injectIntlWithShim.jsx +++ b/runtime/i18n/injectIntlWithShim.jsx @@ -2,7 +2,8 @@ import React from 'react'; import { injectIntl } from 'react-intl'; import { EnvironmentTypes } from '../../types'; import { getConfig } from '../config'; -import { getLoggingService, intlShape } from './lib'; +import { getLoggingService } from '../logging'; +import { intlShape } from './lib'; /** * This function wraps react-intl's injectIntl function in order to add error logging to the intl @@ -19,7 +20,7 @@ const injectIntlWithShim = (WrappedComponent) => { value: (definition, ...args) => { if (definition === undefined || definition.id === undefined) { const error = new Error('i18n error: An undefined message was supplied to intl.formatMessage.'); - if (getConfig().ENVIRONMENT === EnvironmentTypes.DEVELOPMENT) { + if (getConfig().environment === EnvironmentTypes.DEVELOPMENT) { console.error(error); // eslint-disable-line no-console return '!!! Missing message supplied to intl.formatMessage !!!'; } diff --git a/runtime/i18n/languages.js b/runtime/i18n/languages.js deleted file mode 100644 index 6ddd3858..00000000 --- a/runtime/i18n/languages.js +++ /dev/null @@ -1,75 +0,0 @@ -/* eslint-disable import/extensions */ -import LANGUAGES, { langs as languageLangs } from '@cospired/i18n-iso-languages'; - -// import arLocale from '@cospired/i18n-iso-languages/langs/ar.json'; -import enLocale from '@cospired/i18n-iso-languages/langs/en.json'; -import esLocale from '@cospired/i18n-iso-languages/langs/es.json'; -import frLocale from '@cospired/i18n-iso-languages/langs/fr.json'; -// import zhLocale from '@cospired/i18n-iso-languages/langs/zh.json'; -// import caLocale from '@cospired/i18n-iso-languages/langs/ca.json'; -// import heLocale from '@cospired/i18n-iso-languages/langs/he.json'; -// import idLocale from '@cospired/i18n-iso-languages/langs/id.json'; -// import koLocale from '@cospired/i18n-iso-languages/langs/ko.json'; -import plLocale from '@cospired/i18n-iso-languages/langs/pl.json'; -import ptLocale from '@cospired/i18n-iso-languages/langs/pt.json'; -// import ruLocale from '@cospired/i18n-iso-languages/langs/ru.json'; -// import thLocale from '@cospired/i18n-iso-languages/langs/th.json'; -// import ukLocale from '@cospired/i18n-iso-languages/langs/uk.json'; - -import { getPrimaryLanguageSubtag } from './lib'; - -/* - * LANGUAGE LISTS - * - * Lists of language names localized in supported languages. - * - * TODO: When we start dynamically loading translations only for the current locale, change this. - * TODO: Also note that a bunch of languages are missing here. They're present but commented out - * for reference. That's because they're not implemented in this library. If you read this and it's - * been a while, go check and see if that's changed! - */ - -// LANGUAGES.registerLocale(arLocale); -LANGUAGES.registerLocale(enLocale); -LANGUAGES.registerLocale(esLocale); -LANGUAGES.registerLocale(frLocale); -// LANGUAGES.registerLocale(zhLocale); -// LANGUAGES.registerLocale(caLocale); -// LANGUAGES.registerLocale(heLocale); -// LANGUAGES.registerLocale(idLocale); -// LANGUAGES.registerLocale(koLocale); -LANGUAGES.registerLocale(plLocale); -LANGUAGES.registerLocale(ptLocale); -// LANGUAGES.registerLocale(ruLocale); -// LANGUAGES.registerLocale(thLocale); -// LANGUAGES.registerLocale(ukLocale); - -/** - * Provides a lookup table of language IDs to language names for the current locale. - * - * @memberof I18n - */ -export const getLanguageMessages = (locale) => { - const primaryLanguageSubtag = getPrimaryLanguageSubtag(locale); - const languageCode = languageLangs().includes(primaryLanguageSubtag) ? primaryLanguageSubtag : 'en'; - - return LANGUAGES.getNames(languageCode); -}; - -/** - * Provides a list of languages represented as objects of the following shape: - * - * { - * key, // The ID of the language - * name // The localized name of the language - * } - * - * TODO: ARCH-878: The list should be sorted alphabetically in the current locale. - * This is useful for populating dropdowns. - * - * @memberof I18n - */ -export const getLanguageList = (locale) => { - const languageMessages = getLanguageMessages(locale); - return Object.entries(languageMessages).map(([code, name]) => ({ code, name })); -}; diff --git a/runtime/i18n/lib.test.js b/runtime/i18n/lib.test.js index fe5ef545..ae73b3ca 100644 --- a/runtime/i18n/lib.test.js +++ b/runtime/i18n/lib.test.js @@ -1,7 +1,5 @@ -/* eslint-disable no-console */ -import { EnvironmentTypes } from '../../types'; import { - configure, + configureI18n, getCookies, getLocale, getMessages, @@ -14,90 +12,6 @@ import { jest.mock('universal-cookie'); describe('lib', () => { - describe('configure', () => { - let originalWarn = null; - - beforeEach(() => { - originalWarn = console.warn; - console.warn = jest.fn(); - }); - - afterEach(() => { - console.warn = originalWarn; - }); - - it('should not call console.warn in production', () => { - configure({ - loggingService: { logError: jest.fn() }, - config: { - ENVIRONMENT: EnvironmentTypes.PRODUCTION, - LANGUAGE_PREFERENCE_COOKIE_NAME: 'yum', - }, - messages: { - 'es-419': {}, - de: {}, - 'en-us': {}, - }, - }); - - expect(console.warn).not.toHaveBeenCalled(); - }); - - it('should warn about unexpected locales', () => { - configure({ - loggingService: { logError: jest.fn() }, - config: { - ENVIRONMENT: EnvironmentTypes.DEVELOPMENT, // turn on warnings! - LANGUAGE_PREFERENCE_COOKIE_NAME: 'yum', - }, - messages: { - ar: {}, - 'es-419': {}, - fr: {}, - 'zh-cn': {}, - ca: {}, - he: {}, - id: {}, - 'ko-kr': {}, - pl: {}, - 'pt-br': {}, - ru: {}, - th: {}, - uk: {}, - uhoh: {}, // invalid locale - }, - }); - - expect(console.warn).toHaveBeenCalledWith('Unexpected locale: uhoh'); - }); - - it('should warn about missing locales', () => { - configure({ - loggingService: { logError: jest.fn() }, - config: { - ENVIRONMENT: EnvironmentTypes.DEVELOPMENT, // turn on warnings! - LANGUAGE_PREFERENCE_COOKIE_NAME: 'yum', - }, - messages: {}, - }); - - expect(console.warn).toHaveBeenCalledTimes(15); - expect(console.warn).toHaveBeenCalledWith('Missing locale: ar'); - expect(console.warn).toHaveBeenCalledWith('Missing locale: es-419'); - expect(console.warn).toHaveBeenCalledWith('Missing locale: fr'); - expect(console.warn).toHaveBeenCalledWith('Missing locale: zh-cn'); - expect(console.warn).toHaveBeenCalledWith('Missing locale: ca'); - expect(console.warn).toHaveBeenCalledWith('Missing locale: he'); - expect(console.warn).toHaveBeenCalledWith('Missing locale: id'); - expect(console.warn).toHaveBeenCalledWith('Missing locale: ko-kr'); - expect(console.warn).toHaveBeenCalledWith('Missing locale: pl'); - expect(console.warn).toHaveBeenCalledWith('Missing locale: pt-br'); - expect(console.warn).toHaveBeenCalledWith('Missing locale: ru'); - expect(console.warn).toHaveBeenCalledWith('Missing locale: th'); - expect(console.warn).toHaveBeenCalledWith('Missing locale: uk'); - }); - }); - describe('getPrimaryLanguageSubtag', () => { it('should work for primary language subtags', () => { expect(getPrimaryLanguageSubtag('en')).toEqual('en'); @@ -114,12 +28,7 @@ describe('lib', () => { describe('getLocale', () => { beforeEach(() => { - configure({ - loggingService: { logError: jest.fn() }, - config: { - ENVIRONMENT: EnvironmentTypes.PRODUCTION, - LANGUAGE_PREFERENCE_COOKIE_NAME: 'yum', - }, + configureI18n({ messages: { 'es-419': {}, de: {}, @@ -159,12 +68,7 @@ describe('lib', () => { describe('getMessages', () => { beforeEach(() => { - configure({ - loggingService: { logError: jest.fn() }, - config: { - ENVIRONMENT: EnvironmentTypes.PRODUCTION, - LANGUAGE_PREFERENCE_COOKIE_NAME: 'yum', - }, + configureI18n({ messages: { 'es-419': { message: 'es-hah' }, de: { message: 'de-hah' }, @@ -216,12 +120,7 @@ describe('lib', () => { it('should do the right thing for non-RTL languages', () => { getCookies().get = jest.fn(() => 'es-419'); - configure({ - loggingService: { logError: jest.fn() }, - config: { - ENVIRONMENT: EnvironmentTypes.PRODUCTION, - LANGUAGE_PREFERENCE_COOKIE_NAME: 'yum', - }, + configureI18n({ messages: { 'es-419': { message: 'es-hah' }, }, @@ -233,12 +132,7 @@ describe('lib', () => { it('should do the right thing for RTL languages', () => { getCookies().get = jest.fn(() => 'ar'); - configure({ - loggingService: { logError: jest.fn() }, - config: { - ENVIRONMENT: EnvironmentTypes.PRODUCTION, - LANGUAGE_PREFERENCE_COOKIE_NAME: 'yum', - }, + configureI18n({ messages: { ar: { message: 'ar-hah' }, }, @@ -252,12 +146,7 @@ describe('lib', () => { describe('mergeMessages', () => { it('should merge objects', () => { - configure({ - loggingService: { logError: jest.fn() }, - config: { - ENVIRONMENT: EnvironmentTypes.PRODUCTION, - LANGUAGE_PREFERENCE_COOKIE_NAME: 'yum', - }, + configureI18n({ messages: { ar: { message: 'ar-hah' }, }, @@ -272,12 +161,7 @@ describe('mergeMessages', () => { }); it('should merge objects from an array', () => { - configure({ - loggingService: { logError: jest.fn() }, - config: { - ENVIRONMENT: EnvironmentTypes.PRODUCTION, - LANGUAGE_PREFERENCE_COOKIE_NAME: 'yum', - }, + configureI18n({ messages: { ar: { message: 'ar-hah' }, }, @@ -292,12 +176,7 @@ describe('mergeMessages', () => { }); it('should merge nested objects from an array', () => { - configure({ - loggingService: { logError: jest.fn() }, - config: { - ENVIRONMENT: EnvironmentTypes.PRODUCTION, - LANGUAGE_PREFERENCE_COOKIE_NAME: 'yum', - }, + configureI18n({ messages: { en: { init: 'initial' }, es: { init: 'inicial' }, @@ -330,12 +209,7 @@ describe('mergeMessages', () => { }); it('should return an empty object if no messages', () => { - configure({ - loggingService: { logError: jest.fn() }, - config: { - ENVIRONMENT: EnvironmentTypes.PRODUCTION, - LANGUAGE_PREFERENCE_COOKIE_NAME: 'yum', - }, + configureI18n({ messages: {}, }); expect(mergeMessages(undefined)).toEqual({}); @@ -345,12 +219,7 @@ describe('mergeMessages', () => { }); it('should return the original object if no messages', () => { - configure({ - loggingService: { logError: jest.fn() }, - config: { - ENVIRONMENT: EnvironmentTypes.PRODUCTION, - LANGUAGE_PREFERENCE_COOKIE_NAME: 'yum', - }, + configureI18n({ messages: { en: { hello: 'world ' } }, }); expect(mergeMessages(undefined)).toEqual({ en: { hello: 'world ' } }); diff --git a/runtime/i18n/lib.ts b/runtime/i18n/lib.ts index fdf8752a..29d180f1 100644 --- a/runtime/i18n/lib.ts +++ b/runtime/i18n/lib.ts @@ -3,72 +3,53 @@ import PropTypes from 'prop-types'; import { MessageFormatElement } from 'react-intl'; import Cookies from 'universal-cookie'; -import '@formatjs/intl-pluralrules/polyfill'; -import '@formatjs/intl-relativetimeformat/polyfill'; - -import '@formatjs/intl-pluralrules/locale-data/ar'; -import '@formatjs/intl-pluralrules/locale-data/ca'; -import '@formatjs/intl-pluralrules/locale-data/en'; -import '@formatjs/intl-pluralrules/locale-data/es'; -import '@formatjs/intl-pluralrules/locale-data/fr'; -import '@formatjs/intl-pluralrules/locale-data/he'; -import '@formatjs/intl-pluralrules/locale-data/id'; -import '@formatjs/intl-pluralrules/locale-data/ko'; -import '@formatjs/intl-pluralrules/locale-data/pl'; -import '@formatjs/intl-pluralrules/locale-data/pt'; -import '@formatjs/intl-pluralrules/locale-data/ru'; -import '@formatjs/intl-pluralrules/locale-data/th'; -import '@formatjs/intl-pluralrules/locale-data/uk'; -import '@formatjs/intl-pluralrules/locale-data/zh'; - -import '@formatjs/intl-relativetimeformat/locale-data/ar'; -import '@formatjs/intl-relativetimeformat/locale-data/ca'; -import '@formatjs/intl-relativetimeformat/locale-data/en'; -import '@formatjs/intl-relativetimeformat/locale-data/es'; -import '@formatjs/intl-relativetimeformat/locale-data/fr'; -import '@formatjs/intl-relativetimeformat/locale-data/he'; -import '@formatjs/intl-relativetimeformat/locale-data/id'; -import '@formatjs/intl-relativetimeformat/locale-data/ko'; -import '@formatjs/intl-relativetimeformat/locale-data/pl'; -import '@formatjs/intl-relativetimeformat/locale-data/pt'; -import '@formatjs/intl-relativetimeformat/locale-data/ru'; -import '@formatjs/intl-relativetimeformat/locale-data/th'; -import '@formatjs/intl-relativetimeformat/locale-data/uk'; -import '@formatjs/intl-relativetimeformat/locale-data/zh'; - -import { EnvironmentTypes, SiteConfig } from '../../types'; -import { LoggingService } from '../logging/types'; +import { LocalizedMessages } from '../../types'; +import { getConfig } from '../config'; +import { publish } from '../subscriptions'; const cookies = new Cookies(); -const supportedLocales = [ - 'ar', // Arabic - // NOTE: 'en' is not included in this list intentionally, since it's the fallback. - 'es-419', // Spanish, Latin American - 'fa', // Farsi - 'fa-ir', // Farsi, Iran - 'fr', // French - 'zh-cn', // Chinese, Simplified - 'ca', // Catalan - 'he', // Hebrew - 'id', // Indonesian - 'ko-kr', // Korean (Korea) - 'pl', // Polish - 'pt-br', // Portuguese (Brazil) - 'ru', // Russian - 'th', // Thai - 'uk', // Ukrainian -]; + +// This list is based on https://help.smartling.com/hc/en-us/articles/1260802028830-Right-to-left-RTL-Languages +// There are very few resources available online outlining the locale codes for RTL languages; +// If this list is inaccurate, we should change it. const rtlLocales = [ - 'ar', // Arabic - 'he', // Hebrew - 'fa', // Farsi (not currently supported) - 'fa-ir', // Farsi Iran - 'ur', // Urdu (not currently supported) + 'ar', // Arabic (International) + 'ar-ae', // Arabic (United Arab Emirates) + 'ar-bh', // Arabic (Bahrain) + 'ar-dj', // Arabic (Djibouti) + 'ar-dz', // Arabic (Algeria) + 'ar-eg', // Arabic (Egypt) + 'ar-iq', // Arabic (Iraq) + 'ar-jo', // Arabic (Jordan) + 'ar-kw', // Arabic (Kuwait) + 'ar-lb', // Arabic (Lebanon) + 'ar-ly', // Arabic (Libya) + 'ar-ma', // Arabic (Morocco) + 'ar-om', // Arabic (Oman) + 'ar-qa', // Arabic (Qatar) + 'ar-sa', // Arabic (Saudi Arabia) + 'ar-sd', // Arabic (Sudan) + 'ar-sy', // Arabic (Syria) + 'ar-tn', // Arabic (Tunisia) + 'ar-ye', // Arabic (Yemen) + 'fa', // Persian + 'fa-af', // Dari/Persian (Afghanistan) + 'fa-ir', // Persian (Iran) + 'he', // Hebrew (he) + 'he-il', // Hebrew + 'iw', // Hebrew (iw) + 'kd', // Kurdish (Sorani) RTL + 'pk-pk', // Panjabi-Shahmuki (Pakistan) + 'ps', // Pushto; Pashto + 'ug', // Uighur; Uyghur + 'ur', // Urdu + 'ur-in', // Urdu (India) + 'ur-pk', // Urdu (Pakistan) + 'yi', // Yiddish + 'yi-us', // Yiddish (United States) ]; -let config: SiteConfig | null = null; -let loggingService: LoggingService | null = null; -let messages: { [locale: string]: Record | Record | undefined }; +let messages: Record | Record | undefined>; /** * @memberof module:Internationalization @@ -82,13 +63,6 @@ let messages: { [locale: string]: Record | Record loggingService; - /** * @memberof module:Internationalization */ @@ -134,7 +108,7 @@ export function getPrimaryLanguageSubtag(code) { */ export function findSupportedLocale(locale) { if (messages === undefined) { - throw new Error('findSupportedLocale called before configuring i18n. Call configure with messages first.'); + throw new Error('findSupportedLocale called before configuring i18n. Call configureI18n with messages first.'); } if (messages[locale] !== undefined) { @@ -159,8 +133,8 @@ export function findSupportedLocale(locale) { * @memberof module:Internationalization */ export function getLocale(locale?: string) { - if (messages === null || config === null) { - throw new Error('getLocale called before configuring i18n. Call configure with messages first.'); + if (messages === null) { + throw new Error('getLocale called before configuring i18n. Call configureI18n with messages first.'); } // 1. Explicit application request @@ -168,8 +142,8 @@ export function getLocale(locale?: string) { return findSupportedLocale(locale); } // 2. User setting in cookie - const cookieLangPref = cookies - .get(config.LANGUAGE_PREFERENCE_COOKIE_NAME); + + const cookieLangPref = cookies.get(getConfig().languagePreferenceCookieName); if (cookieLangPref) { return findSupportedLocale(cookieLangPref.toLowerCase()); } @@ -180,6 +154,32 @@ export function getLocale(locale?: string) { return findSupportedLocale(globalThis.navigator.language.toLowerCase()); } +export function getLocalizedLanguageName(locale) { + const localizedName = (new Intl.DisplayNames([locale], { type: 'language' })).of(locale); + + if (localizedName === undefined) { + throw new Error(`Unsupported locale: ${locale}`); + } + + return `${localizedName.charAt(0).toLocaleUpperCase(locale)}${localizedName.slice(1)}`; +} + +export function getSupportedLanguageList() { + const locales = Object.keys(messages); + locales.push('en'); // 'en' is not in the messages object because it's the default. + locales.sort(); + + return locales.map((locale) => ({ + code: locale, + name: getLocalizedLanguageName(locale), + })); +} + +export function updateLocale() { + handleRtl(); + publish(LOCALE_CHANGED); +} + /** * Returns messages for the provided locale, or the user's preferred locale if no argument is * provided. @@ -189,7 +189,7 @@ export function getLocale(locale?: string) { */ export function getMessages(locale = getLocale()) { if (messages === undefined) { - throw new Error('getMessages called before configuring i18n. Call configure with messages first.'); + throw new Error('getMessages called before configuring i18n. Call configureI18n with messages first.'); } return messages[locale]; @@ -219,34 +219,6 @@ export function handleRtl() { } } -const messagesShape = { - ar: PropTypes.objectOf(PropTypes.string), // Arabic - en: PropTypes.objectOf(PropTypes.string), - 'es-419': PropTypes.objectOf(PropTypes.string), // Spanish, Latin American - fr: PropTypes.objectOf(PropTypes.string), // French - 'zh-cn': PropTypes.objectOf(PropTypes.string), // Chinese, Simplified - ca: PropTypes.objectOf(PropTypes.string), // Catalan - he: PropTypes.objectOf(PropTypes.string), // Hebrew - id: PropTypes.objectOf(PropTypes.string), // Indonesian - 'ko-kr': PropTypes.objectOf(PropTypes.string), // Korean (Korea) - pl: PropTypes.objectOf(PropTypes.string), // Polish - 'pt-br': PropTypes.objectOf(PropTypes.string), // Portuguese (Brazil) - ru: PropTypes.objectOf(PropTypes.string), // Russian - th: PropTypes.objectOf(PropTypes.string), // Thai - uk: PropTypes.objectOf(PropTypes.string), // Ukrainian -}; - -const optionsShape = { - config: PropTypes.object.isRequired, - loggingService: PropTypes.shape({ - logError: PropTypes.func.isRequired, - }).isRequired, - messages: PropTypes.oneOfType([ - PropTypes.shape(messagesShape), - PropTypes.arrayOf(PropTypes.shape(messagesShape)), - ]).isRequired, -}; - /** * * @@ -254,17 +226,27 @@ const optionsShape = { * @returns {Object} * @memberof module:Internationalization */ -export function mergeMessages(newMessages) { +export function mergeMessages(newMessages = {}) { const msgs = Array.isArray(newMessages) ? merge({}, ...newMessages) : newMessages; messages = merge(messages, msgs); return messages; } +/** + * Adds all the messages found in the loaded apps. + * + * @memberof module:Internationalization + */ +export function addAppMessages() { + const { apps } = getConfig(); + apps.forEach((app) => { + mergeMessages(app.messages); + }); +} + interface ConfigureI18nOptions { - loggingService: LoggingService, - messages: Array<{ [locale: string]: { [key: string]: string } }> | { [locale: string]: { [key: string]: string } }, - config: SiteConfig, + messages: LocalizedMessages[] | LocalizedMessages, } /** @@ -274,32 +256,11 @@ interface ConfigureI18nOptions { * above), or if an expected locale is not provided. * * @param {Object} options - * @param {LoggingService} options.loggingService - * @param {Object} options.config * @param {Object} options.messages * @memberof module:Internationalization */ -export function configure(options: ConfigureI18nOptions) { - PropTypes.checkPropTypes(optionsShape, options, 'property', 'i18n'); - // eslint-disable-next-line prefer-destructuring - loggingService = options.loggingService; - // eslint-disable-next-line prefer-destructuring - config = options.config; +export function configureI18n(options: ConfigureI18nOptions) { messages = Array.isArray(options.messages) ? merge({}, ...options.messages) : options.messages; - if (config.ENVIRONMENT === EnvironmentTypes.DEVELOPMENT && messages !== undefined) { - Object.keys(messages).forEach((key) => { - if (supportedLocales.indexOf(key) < 0) { - console.warn(`Unexpected locale: ${key}`); // eslint-disable-line no-console - } - }); - - supportedLocales.forEach((key) => { - if (messages === undefined || messages[key] === undefined) { - console.warn(`Missing locale: ${key}`); // eslint-disable-line no-console - } - }); - } - handleRtl(); } diff --git a/runtime/index.ts b/runtime/index.ts index a729d56c..a111b794 100644 --- a/runtime/index.ts +++ b/runtime/index.ts @@ -1,11 +1,11 @@ export { - MockAnalyticsService, - SegmentAnalyticsService, - configure as configureAnalytics, + configureAnalytics, getAnalyticsService, identifyAnonymousUser, identifyAuthenticatedUser, + MockAnalyticsService, resetAnalyticsService, + SegmentAnalyticsService, sendPageEvent, sendTrackEvent, sendTrackingLogEvent @@ -15,67 +15,50 @@ export { AUTHENTICATED_USER_CHANGED, AUTHENTICATED_USER_TOPIC, AxiosJwtAuthService, - MockAuthService, - configure as configureAuth, + configureAuth, ensureAuthenticatedUser, fetchAuthenticatedUser, - getAuthService, getAuthenticatedHttpClient, getAuthenticatedUser, + getAuthService, getHttpClient, getLoginRedirectUrl, getLogoutRedirectUrl, hydrateAuthenticatedUser, + MockAuthService, redirectToLogin, redirectToLogout, setAuthenticatedUser } from './auth'; -export { - getConfig, - mergeConfig, - setConfig -} from './config'; +export * from './config'; -export { - APP_ANALYTICS_INITIALIZED, - APP_AUTH_INITIALIZED, - APP_CONFIG_INITIALIZED, - APP_I18N_INITIALIZED, - APP_INIT_ERROR, - APP_LOGGING_INITIALIZED, - APP_PUBSUB_INITIALIZED, - APP_READY, - APP_TOPIC, - CONFIG_CHANGED, - CONFIG_TOPIC -} from './constants'; +export * from './constants'; export { + configureI18n, + createIntl, + defineMessages, FormattedDate, FormattedMessage, FormattedNumber, FormattedPlural, FormattedRelativeTime, FormattedTime, - IntlProvider, - LOCALE_CHANGED, - LOCALE_TOPIC, - configure as configureI18n, - createIntl, - defineMessages, - getCountryList, - getCountryMessages, - getLanguageList, - getLanguageMessages, getLocale, + getLocalizedLanguageName, getMessages, getPrimaryLanguageSubtag, + getSupportedLanguageList, handleRtl, injectIntl, + IntlProvider, intlShape, isRtl, + LOCALE_CHANGED, + LOCALE_TOPIC, mergeMessages, + updateLocale, useIntl } from './i18n'; @@ -88,26 +71,15 @@ export { } from './initialize'; export { - MockLoggingService, - NewRelicLoggingService, - configure as configureLogging, + configureLogging, getLoggingService, logError, logInfo, + MockLoggingService, + NewRelicLoggingService, resetLoggingService } from './logging'; -export { - Plugin, - PluginSlot -} from './plugins'; - -export { - publish, - subscribe, - unsubscribe -} from './pubSub'; - export { AppContext, AppProvider, @@ -122,6 +94,13 @@ export { useConfig } from './react'; +export { + clearAllSubscriptions, + publish, + subscribe, + unsubscribe +} from './subscriptions'; + export { initializeMockApp, mockMessages @@ -132,7 +111,10 @@ export { convertKeyNames, getPath, getQueryParameters, + isValidVariableName, modifyObjectKeys, parseURL, snakeCaseObject } from './utils'; + +export * from './slots'; diff --git a/runtime/initialize.async.function.config.test.js b/runtime/initialize.async.function.config.test.js index 323bf1cc..e8bb479d 100644 --- a/runtime/initialize.async.function.config.test.js +++ b/runtime/initialize.async.function.config.test.js @@ -1,15 +1,14 @@ -import 'pubsub-js'; -import { initialize } from './initialize'; - import { ensureAuthenticatedUser, fetchAuthenticatedUser, hydrateAuthenticatedUser, } from './auth'; import { getConfig } from './config'; +import { initialize } from './initialize'; import { logError, } from './logging'; +import { clearAllSubscriptions } from './subscriptions'; jest.mock('./logging'); jest.mock('./auth'); @@ -32,7 +31,7 @@ describe('initialize with async function js file config', () => { ensureAuthenticatedUser.mockReset(); hydrateAuthenticatedUser.mockReset(); logError.mockReset(); - global.PubSub.clearAllSubscriptions(); + clearAllSubscriptions(); }); it('should initialize the app with async function javascript file configuration', async () => { diff --git a/runtime/initialize.const.config.test.js b/runtime/initialize.const.config.test.js index 3f30c90c..ec0d7fbe 100644 --- a/runtime/initialize.const.config.test.js +++ b/runtime/initialize.const.config.test.js @@ -1,15 +1,14 @@ -import 'pubsub-js'; -import { initialize } from './initialize'; - import { ensureAuthenticatedUser, fetchAuthenticatedUser, hydrateAuthenticatedUser, } from './auth'; import { getConfig } from './config'; +import { initialize } from './initialize'; import { logError, } from './logging'; +import { clearAllSubscriptions } from './subscriptions'; jest.mock('./logging'); jest.mock('./auth'); @@ -30,7 +29,7 @@ describe('initialize with constant js file config', () => { ensureAuthenticatedUser.mockReset(); hydrateAuthenticatedUser.mockReset(); logError.mockReset(); - global.PubSub.clearAllSubscriptions(); + clearAllSubscriptions(); }); it('should initialize the app with javascript file configuration', async () => { diff --git a/runtime/initialize.function.config.test.js b/runtime/initialize.function.config.test.js index 4683754e..d1a65587 100644 --- a/runtime/initialize.function.config.test.js +++ b/runtime/initialize.function.config.test.js @@ -1,5 +1,3 @@ -import 'pubsub-js'; - import { ensureAuthenticatedUser, fetchAuthenticatedUser, @@ -10,6 +8,7 @@ import { initialize } from './initialize'; import { logError, } from './logging'; +import { clearAllSubscriptions } from './subscriptions'; jest.mock('./logging'); jest.mock('./auth'); @@ -30,7 +29,7 @@ describe('initialize with function js file config', () => { ensureAuthenticatedUser.mockReset(); hydrateAuthenticatedUser.mockReset(); logError.mockReset(); - global.PubSub.clearAllSubscriptions(); + clearAllSubscriptions(); }); it('should initialize the app with javascript file configuration', async () => { diff --git a/runtime/initialize.js b/runtime/initialize.js index 96e6f6b9..a7ef0ae1 100644 --- a/runtime/initialize.js +++ b/runtime/initialize.js @@ -56,17 +56,15 @@ This 'site.config' package is a special 'magic' alias in our webpack configurati folder. It points at an `site.config.tsx` file in the root of an project's repository. */ import siteConfig from 'site.config'; -import { getPath } from './utils'; -// eslint-disable-next-line import/no-cycle import { - configure as configureAnalytics, + configureAnalytics, identifyAnonymousUser, identifyAuthenticatedUser, SegmentAnalyticsService, } from './analytics'; import { AxiosJwtAuthService, - configure as configureAuth, + configureAuth, ensureAuthenticatedUser, fetchAuthenticatedUser, getAuthenticatedHttpClient, @@ -75,7 +73,8 @@ import { } from './auth'; import configureCache from './auth/LocalForageCache'; import { - getConfig, mergeConfig + getConfig, mergeConfig, + patchAppConfig } from './config'; import { APP_ANALYTICS_INITIALIZED, @@ -87,14 +86,16 @@ import { APP_PUBSUB_INITIALIZED, APP_READY, } from './constants'; -import { configure as configureI18n } from './i18n'; +import { configureI18n } from './i18n'; import { - configure as configureLogging, + configureLogging, getLoggingService, logError, NewRelicLoggingService, } from './logging'; import { GoogleAnalyticsLoader } from './scripts'; +import { publish } from './subscriptions'; +import { getPath } from './utils'; /** * A browser history or memory history object created by the [history](https://github.com/ReactTraining/history) @@ -104,7 +105,7 @@ import { GoogleAnalyticsLoader } from './scripts'; * falls back to memory history. */ export const getHistory = () => ((typeof window !== 'undefined') - ? createBrowserHistory({ basename: getPath(getConfig().PUBLIC_PATH) }) + ? createBrowserHistory({ basename: getPath(getConfig().publicPath) }) : createMemoryHistory()); /** @@ -117,7 +118,7 @@ export const getHistory = () => ((typeof window !== 'undefined') * as an ENV variable in the Docker file, and we read it here from that configuration so that it * can be passed into a Router later. */ -export const getBasename = () => getPath(getConfig().PUBLIC_PATH); +export const getBasename = () => getPath(getConfig().publicPath); /** * The default handler for the initialization lifecycle's `initError` phase. Logs the error to the @@ -174,6 +175,13 @@ async function fileConfig() { config = siteConfig; } + // This means the SiteConfig is acting as an app, i.e., 'legacy mode' which allows an MFE to be + // built as its own site using the shell. In that case, we need to move all the 'custom' config + // into our appConfigs object so it can be accessed by the code. + if (config.custom !== undefined) { + patchAppConfig(config.custom); + } + mergeConfig(config); } @@ -184,21 +192,20 @@ async function fileConfig() { */ async function runtimeConfig() { try { - const { MFE_CONFIG_API_URL, APP_ID } = getConfig(); + const { mfeConfigApiUrl, appId } = getConfig(); - if (MFE_CONFIG_API_URL) { + if (mfeConfigApiUrl) { const apiConfig = { headers: { accept: 'application/json' } }; const apiService = await configureCache(); const params = new URLSearchParams(); - params.append('mfe', APP_ID); - const url = `${MFE_CONFIG_API_URL}?${params.toString()}`; + params.append('mfe', appId); + const url = `${mfeConfigApiUrl}?${params.toString()}`; const { data } = await apiService.get(url, apiConfig); mergeConfig(data); } } catch (error) { - // eslint-disable-next-line no-console console.error('Error with config API', error.message); } } @@ -220,7 +227,7 @@ export function loadExternalScripts(externalScripts, data) { */ export async function analytics() { const authenticatedUser = getAuthenticatedUser(); - if (authenticatedUser && authenticatedUser.userId) { + if (authenticatedUser?.userId) { identifyAuthenticatedUser(authenticatedUser.userId); } else { await identifyAnonymousUser(); @@ -280,7 +287,7 @@ function applyOverrideHandlers(overrides) { * redirection for unauthenticated users. Defaults to false, meaning that by default the * application will allow anonymous/unauthenticated sessions. * @param {*} [options.hydrateAuthenticatedUser=false] If true, makes an API call to the user - * account endpoint (`${App.config.LMS_BASE_URL}/api/user/v1/accounts/${username}`) to fetch + * account endpoint (`${App.config.lmsBaseUrl}/api/user/v1/accounts/${username}`) to fetch * detailed account information for the authenticated user. This data is merged into the return * value of `getAuthenticatedUser`, overriding any duplicate keys that already exist. Defaults to * false, meaning that no additional account information will be loaded. @@ -305,20 +312,20 @@ export async function initialize({ try { // Pub/Sub await handlers.pubSub(); - global.PubSub.publish(APP_PUBSUB_INITIALIZED); + publish(APP_PUBSUB_INITIALIZED); // Configuration await fileConfig(); await handlers.config(); await runtimeConfig(); - global.PubSub.publish(APP_CONFIG_INITIALIZED); + publish(APP_CONFIG_INITIALIZED); loadExternalScripts(externalScripts, { config: getConfig(), }); // This allows us to replace the implementations of the logging, analytics, and auth services - // based on keys in the ConfigDocument. The JavaScript File Configuration method is the only + // based on keys in the SiteConfig. The JavaScript File Configuration method is the only // one capable of supplying an alternate implementation since it can import other modules. // If a service wasn't supplied we fall back to the default parameters on the initialize // function signature. @@ -331,16 +338,14 @@ export async function initialize({ config: getConfig(), }); await handlers.logging(); - global.PubSub.publish(APP_LOGGING_INITIALIZED); + publish(APP_LOGGING_INITIALIZED); // Internationalization configureI18n({ messages, - config: getConfig(), - loggingService: getLoggingService(), }); await handlers.i18n(); - global.PubSub.publish(APP_I18N_INITIALIZED); + publish(APP_I18N_INITIALIZED); // Authentication configureAuth(authServiceImpl, { @@ -350,7 +355,7 @@ export async function initialize({ }); await handlers.auth(requireUser, hydrateUser); - global.PubSub.publish(APP_AUTH_INITIALIZED); + publish(APP_AUTH_INITIALIZED); // Analytics configureAnalytics(analyticsServiceImpl, { @@ -359,16 +364,16 @@ export async function initialize({ httpClient: getAuthenticatedHttpClient(), }); await handlers.analytics(); - global.PubSub.publish(APP_ANALYTICS_INITIALIZED); + publish(APP_ANALYTICS_INITIALIZED); // Application Ready await handlers.ready(); - global.PubSub.publish(APP_READY); + publish(APP_READY); } catch (error) { if (!error.isRedirecting) { // Initialization Error await handlers.initError(error); - global.PubSub.publish(APP_INIT_ERROR, error); + publish(APP_INIT_ERROR, error); } } } diff --git a/runtime/initialize.test.js b/runtime/initialize.test.js index bae7a535..50d487ed 100644 --- a/runtime/initialize.test.js +++ b/runtime/initialize.test.js @@ -1,5 +1,5 @@ import { createBrowserHistory } from 'history'; -import 'pubsub-js'; + import { APP_ANALYTICS_INITIALIZED, APP_AUTH_INITIALIZED, @@ -12,10 +12,10 @@ import { } from './constants'; import { getHistory, initialize } from './initialize'; -import { configure as configureAnalytics, SegmentAnalyticsService } from './analytics'; +import { configureAnalytics, SegmentAnalyticsService } from './analytics'; import { AxiosJwtAuthService, - configure as configureAuth, + configureAuth, ensureAuthenticatedUser, fetchAuthenticatedUser, getAuthenticatedHttpClient, @@ -24,13 +24,14 @@ import { } from './auth'; import configureCache from './auth/LocalForageCache'; import { getConfig, mergeConfig } from './config'; -import { configure as configureI18n } from './i18n'; +import { configureI18n } from './i18n'; import { - configure as configureLogging, + configureLogging, getLoggingService, logError, NewRelicLoggingService, } from './logging'; +import { clearAllSubscriptions, subscribe } from './subscriptions'; jest.mock('./logging'); jest.mock('./auth'); @@ -42,29 +43,17 @@ jest.mock('history'); let config = null; const newConfig = { common: { - SITE_NAME: 'Test Case', - LOGO_URL: 'http://test.example.com:18000/theme/logo.png', - LOGO_TRADEMARK_URL: 'http://test.example.com:18000/theme/logo.png', - LOGO_WHITE_URL: 'http://test.example.com:18000/theme/logo.png', - ACCESS_TOKEN_COOKIE_NAME: 'edx-jwt-cookie-header-payload', - FAVICON_URL: 'http://test.example.com:18000/theme/favicon.ico', - CSRF_TOKEN_API_PATH: '/csrf/api/v1/token', - DISCOVERY_API_BASE_URL: 'http://test.example.com:18381', - PUBLISHER_BASE_URL: 'http://test.example.com:18400', - ECOMMERCE_BASE_URL: 'http://test.example.com:18130', - LANGUAGE_PREFERENCE_COOKIE_NAME: 'openedx-language-preference', - LEARNING_BASE_URL: 'http://test.example.com:2000', - LMS_BASE_URL: 'http://test.example.com:18000', - LOGIN_URL: 'http://test.example.com:18000/login', - LOGOUT_URL: 'http://test.example.com:18000/logout', - STUDIO_BASE_URL: 'http://studio.example.com:18010', - MARKETING_SITE_BASE_URL: 'http://test.example.com:18000', - ORDER_HISTORY_URL: 'http://test.example.com:1996/orders', - REFRESH_ACCESS_TOKEN_API_PATH: '/login_refresh', - SEGMENT_KEY: '', - USER_INFO_COOKIE_NAME: 'edx-user-info', - IGNORED_ERROR_REGEX: '', - CREDENTIALS_BASE_URL: 'http://test.example.com:18150', + siteName: 'Test Case', + accessTokenCookieName: 'edx-jwt-cookie-header-payload', + csrfTokenApiPath: '/csrf/api/v1/token', + languagePreferenceCookieName: 'openedx-language-preference', + lmsBaseUrl: 'http://test.example.com:18000', + loginUrl: 'http://test.example.com:18000/login', + logoutUrl: 'http://test.example.com:18000/logout', + refreshAccessTokenApiPath: '/login_refresh', + segmentKey: '', + userInfoCookieName: 'edx-user-info', + ignoredErrorRegex: '', }, auth: { INFO_EMAIL: 'openedx@example.com', @@ -83,7 +72,7 @@ describe('initialize', () => { ensureAuthenticatedUser.mockReset(); hydrateAuthenticatedUser.mockReset(); logError.mockReset(); - global.PubSub.clearAllSubscriptions(); + clearAllSubscriptions(); }); it('should call default handlers in the absence of overrides', async () => { @@ -106,13 +95,13 @@ describe('initialize', () => { } } - global.PubSub.subscribe(APP_PUBSUB_INITIALIZED, checkDispatchedDone); - global.PubSub.subscribe(APP_CONFIG_INITIALIZED, checkDispatchedDone); - global.PubSub.subscribe(APP_LOGGING_INITIALIZED, checkDispatchedDone); - global.PubSub.subscribe(APP_AUTH_INITIALIZED, checkDispatchedDone); - global.PubSub.subscribe(APP_ANALYTICS_INITIALIZED, checkDispatchedDone); - global.PubSub.subscribe(APP_I18N_INITIALIZED, checkDispatchedDone); - global.PubSub.subscribe(APP_READY, checkDispatchedDone); + subscribe(APP_PUBSUB_INITIALIZED, checkDispatchedDone); + subscribe(APP_CONFIG_INITIALIZED, checkDispatchedDone); + subscribe(APP_LOGGING_INITIALIZED, checkDispatchedDone); + subscribe(APP_AUTH_INITIALIZED, checkDispatchedDone); + subscribe(APP_ANALYTICS_INITIALIZED, checkDispatchedDone); + subscribe(APP_I18N_INITIALIZED, checkDispatchedDone); + subscribe(APP_READY, checkDispatchedDone); const messages = { i_am: 'a message' }; await initialize({ messages }); @@ -130,8 +119,6 @@ describe('initialize', () => { }); expect(configureI18n).toHaveBeenCalledWith({ messages, - config, - loggingService: getLoggingService(), }); expect(fetchAuthenticatedUser).toHaveBeenCalled(); expect(ensureAuthenticatedUser).not.toHaveBeenCalled(); @@ -222,7 +209,7 @@ describe('initialize', () => { expect(data).toEqual(new Error('uhoh!')); } - global.PubSub.subscribe(APP_INIT_ERROR, errorHandler); + subscribe(APP_INIT_ERROR, errorHandler); await initialize({ messages: null, @@ -258,7 +245,7 @@ describe('initialize', () => { expect(data).toEqual(new Error('uhoh!')); } - global.PubSub.subscribe(APP_INIT_ERROR, errorHandler); + subscribe(APP_INIT_ERROR, errorHandler); await initialize({ messages: null, @@ -290,8 +277,8 @@ describe('initialize', () => { handlers: { config: () => { mergeConfig({ - MFE_CONFIG_API_URL: 'http://localhost:18000/api/mfe/v1/config', - APP_ID: 'auth', + mfeConfigApiUrl: 'http://localhost:18000/api/mfe/v1/config', + appId: 'auth', }); } } @@ -311,15 +298,13 @@ describe('initialize', () => { }); expect(configureI18n).toHaveBeenCalledWith({ messages, - config, - loggingService: getLoggingService(), }); expect(fetchAuthenticatedUser).toHaveBeenCalled(); expect(ensureAuthenticatedUser).not.toHaveBeenCalled(); expect(hydrateAuthenticatedUser).not.toHaveBeenCalled(); expect(logError).not.toHaveBeenCalled(); - expect(getConfig().SITE_NAME).toBe(newConfig.common.SITE_NAME); + expect(getConfig().siteName).toBe(newConfig.common.siteName); expect(getConfig().INFO_EMAIL).toBe(newConfig.auth.INFO_EMAIL); expect(Object.values(getConfig()).includes(newConfig.learning.DISCUSSIONS_MFE_BASE_URL)).toBeFalsy(); }); @@ -342,8 +327,8 @@ describe('initialize', () => { handlers: { config: () => { mergeConfig({ - MFE_CONFIG_API_URL: 'http://localhost:18000/api/mfe/v1/config', - APP_ID: 'auth', + mfeConfigApiUrl: 'http://localhost:18000/api/mfe/v1/config', + appId: 'auth', }); } } @@ -364,8 +349,6 @@ describe('initialize', () => { }); expect(configureI18n).toHaveBeenCalledWith({ messages, - config, - loggingService: getLoggingService(), }); expect(fetchAuthenticatedUser).toHaveBeenCalled(); expect(ensureAuthenticatedUser).not.toHaveBeenCalled(); diff --git a/runtime/logging/NewRelicLoggingService.js b/runtime/logging/NewRelicLoggingService.js index d52c75fe..c6250718 100644 --- a/runtime/logging/NewRelicLoggingService.js +++ b/runtime/logging/NewRelicLoggingService.js @@ -25,8 +25,8 @@ const pageActionNameInfo = 'INFO'; const pageActionNameIgnoredError = 'IGNORED_ERROR'; function sendPageAction(actionName, message, customAttributes) { - if (getConfig().ENVIRONMENT === EnvironmentTypes.DEVELOPMENT) { - console.log(actionName, message, customAttributes); // eslint-disable-line + if (getConfig().environment === EnvironmentTypes.DEVELOPMENT) { + console.log(actionName, message, customAttributes); } if (window && typeof window.newrelic !== 'undefined') { // https://docs.newrelic.com/docs/browser/new-relic-browser/browser-apis/addpageaction/ @@ -35,8 +35,8 @@ function sendPageAction(actionName, message, customAttributes) { } function sendError(error, customAttributes) { - if (getConfig().ENVIRONMENT === EnvironmentTypes.DEVELOPMENT) { - console.error(error, customAttributes); // eslint-disable-line + if (getConfig().environment === EnvironmentTypes.DEVELOPMENT) { + console.error(error, customAttributes); } if (window && typeof window.newrelic !== 'undefined') { // https://docs.newrelic.com/docs/browser/new-relic-browser/browser-apis/noticeerror/ @@ -45,8 +45,8 @@ function sendError(error, customAttributes) { } function setCustomAttribute(name, value) { - if (getConfig().ENVIRONMENT === EnvironmentTypes.DEVELOPMENT) { - console.log(name, value); // eslint-disable-line + if (getConfig().environment === EnvironmentTypes.DEVELOPMENT) { + console.log(name, value); } if (window && typeof window.newrelic !== 'undefined') { // https://docs.newrelic.com/docs/browser/new-relic-browser/browser-apis/setcustomattribute/ @@ -102,7 +102,7 @@ export default class NewRelicLoggingService { For example, here's a .env line which ignores two specific errors: - IGNORED_ERROR_REGEX='^\\[frontend-auth\\] Unimportant Error|Specific non-critical error #[\\d]+' + ignoredErrorRegex='^\\[frontend-auth\\] Unimportant Error|Specific non-critical error #[\\d]+' This example would ignore errors with the following messages: @@ -119,7 +119,7 @@ export default class NewRelicLoggingService { For edx.org, add new error message regexes in edx-internal YAML as needed. */ - this.ignoredErrorRegexes = config ? config.IGNORED_ERROR_REGEX : undefined; + this.ignoredErrorRegexes = config ? config.ignoredErrorRegex : undefined; } /** diff --git a/runtime/logging/NewRelicLoggingService.test.js b/runtime/logging/NewRelicLoggingService.test.js index 24c792ec..5179d497 100644 --- a/runtime/logging/NewRelicLoggingService.test.js +++ b/runtime/logging/NewRelicLoggingService.test.js @@ -9,22 +9,22 @@ global.newrelic = { let service = null; const configWithIgnoredErrors = { config: { - IGNORED_ERROR_REGEX: /^Ignore this error|very minor/, + ignoredErrorRegex: /^Ignore this error|very minor/, }, }; const configWithNullIgnoredErrors = { config: { - IGNORED_ERROR_REGEX: null, + ignoredErrorRegex: null, }, }; const configWithEmptyIgnoredErrors = { config: { - IGNORED_ERROR_REGEX: '', + ignoredErrorRegex: '', }, }; const configWithWhitespaceIgnoredErrors = { config: { - IGNORED_ERROR_REGEX: ' ', + ignoredErrorRegex: ' ', }, }; const configWithMissingIgnoredErrors = { diff --git a/runtime/logging/index.js b/runtime/logging/index.ts similarity index 84% rename from runtime/logging/index.js rename to runtime/logging/index.ts index dbe09ec8..c7ec935d 100644 --- a/runtime/logging/index.js +++ b/runtime/logging/index.ts @@ -1,9 +1,9 @@ export { + configureLogging, getLoggingService, - resetLoggingService, - configure, - logInfo, logError, + logInfo, + resetLoggingService } from './interface'; -export { default as NewRelicLoggingService } from './NewRelicLoggingService'; export { default as MockLoggingService } from './MockLoggingService'; +export { default as NewRelicLoggingService } from './NewRelicLoggingService'; diff --git a/runtime/logging/interface.js b/runtime/logging/interface.js index 82dbe15c..fbb42c19 100644 --- a/runtime/logging/interface.js +++ b/runtime/logging/interface.js @@ -8,7 +8,7 @@ * you're not using the `initialize` function, logging (via New Relic) can be configured via: * * ``` - * import { getConfig, configure, NewRelicLoggingService, logInfo, logError } from '@openedx/frontend-base'; + * import { getConfig, configureLogging, NewRelicLoggingService, logInfo, logError } from '@openedx/frontend-base'; * * configureLogging(NewRelicLoggingService, { * config: getConfig(), @@ -41,7 +41,7 @@ let service = null; /** * */ -export function configure(LoggingService, options) { +export function configureLogging(LoggingService, options) { PropTypes.checkPropTypes(optionsShape, options, 'property', 'Logging'); service = new LoggingService(options); PropTypes.checkPropTypes(serviceShape, service, 'property', 'LoggingService'); @@ -82,7 +82,7 @@ export function setCustomAttribute(name, value) { /** * - * @throws {Error} Thrown if the logging service has not yet been configured via {@link configure}. + * @throws {Error} Thrown if the logging service has not yet been configured via {@link configureLogging}. * @returns {LoggingService} */ export function getLoggingService() { diff --git a/runtime/plugins/Plugin.jsx b/runtime/plugins/Plugin.jsx deleted file mode 100644 index 84372994..00000000 --- a/runtime/plugins/Plugin.jsx +++ /dev/null @@ -1,98 +0,0 @@ -'use client'; - -import PropTypes from 'prop-types'; -import { - useEffect, useMemo, useState, -} from 'react'; -import { useIntl } from '../i18n'; -import { ErrorBoundary } from '../react'; - -import { PLUGIN_RESIZE } from './data/constants'; -import { - dispatchMountedEvent, dispatchReadyEvent, dispatchUnmountedEvent, useHostEvent, -} from './data/hooks'; -import messages from './Plugin.messages'; - -const ErrorFallbackDefault = () => { - const { formatMessage } = useIntl(); - return ( -
-

- {formatMessage(messages.unexpectedError)} -

-
- ); -}; - -const Plugin = ({ - children, className, style, ready, ErrorFallbackComponent, -}) => { - const [dimensions, setDimensions] = useState({ - width: null, - height: null, - }); - - const finalStyle = useMemo(() => ({ - ...dimensions, - ...style, - }), [dimensions, style]); - - // Need to confirm: When an error is caught here, the logging will be sent to the child MFE's logging service - - const ErrorFallback = ErrorFallbackComponent || ErrorFallbackDefault; - - useHostEvent(PLUGIN_RESIZE, ({ payload }) => { - setDimensions({ - width: payload.width, - height: payload.height, - }); - }); - - useEffect(() => { - dispatchMountedEvent(); - - return () => { - dispatchUnmountedEvent(); - }; - }, []); - - useEffect(() => { - /** Ready defaults to true, but can be used to defer rendering the Plugin until certain processes have - * occurred or conditions have been met */ - if (ready) { - dispatchReadyEvent(); - } - }, [ready]); - - return ( -
- } - > - {children} - -
- ); -}; - -export default Plugin; - -Plugin.propTypes = { - /** The content for the Plugin */ - children: PropTypes.node.isRequired, - /** Classes to apply to the Plugin wrapper component */ - className: PropTypes.string, - /** Custom error fallback component */ - ErrorFallbackComponent: PropTypes.func, - /** If ready is true, it will render the Plugin */ - ready: PropTypes.bool, - /** Styles to apply to the Plugin wrapper component */ - style: PropTypes.shape({}), -}; - -Plugin.defaultProps = { - className: undefined, - ErrorFallbackComponent: null, - style: {}, - ready: true, -}; diff --git a/runtime/plugins/Plugin.test.jsx b/runtime/plugins/Plugin.test.jsx deleted file mode 100644 index 147467b2..00000000 --- a/runtime/plugins/Plugin.test.jsx +++ /dev/null @@ -1,227 +0,0 @@ -/* eslint-disable react/jsx-no-bind */ -/* eslint react/prop-types: off */ - -import { fireEvent } from '@testing-library/dom'; -import '@testing-library/jest-dom'; -import { render } from '@testing-library/react'; - -import { - FormattedMessage, - IntlProvider, -} from '../i18n'; -import { initializeMockApp } from '../testing'; - -import { PluginTypes } from '../../types'; -import { - PLUGIN_MOUNTED, PLUGIN_READY, PLUGIN_RESIZE -} from './data/constants'; -import Plugin from './Plugin'; -import PluginContainer from './PluginContainer'; -import { IFRAME_FEATURE_POLICY } from './PluginContainerIframe'; - -const iframeConfig = { - id: 'iframe_plugin', - url: 'http://localhost/plugin1', - type: PluginTypes.IFRAME, - title: 'test iframe plugin', - priority: 1, -}; - -const directConfig = { - id: 'direct_plugin', - type: PluginTypes.DIRECT, - RenderWidget: ({ id, content }) => (
{content.text}
), - priority: 2, - content: { text: 'This is a direct plugin.' }, -}; - -// Mock ResizeObserver which is unavailable in the context of a test. -global.ResizeObserver = jest.fn(function mockResizeObserver() { - this.observe = jest.fn(); - this.disconnect = jest.fn(); -}); - -describe('PluginContainer', () => { - it('should return a blank page with a null plugin configuration', () => { - // the URL will be empty and an empty div tag will exist where the iFrame should be - // the iFrame will still take up the space assigned by the host MFE - const component = ( - - ); - - const { container } = render(component); - expect(container.firstChild).toBeNull(); - }); - - it('should render a Plugin iFrame Container when given an iFrame config', async () => { - const component = ( - Loading} /> - ); - - const { container } = render(component); - - const iframeElement = container.querySelector('iframe'); - const fallbackElement = container.querySelector('div'); - - expect(iframeElement).toBeInTheDocument(); - expect(fallbackElement).toBeInTheDocument(); - - expect(fallbackElement.innerHTML).toEqual('Loading'); - - // Ensure the iframe has the proper attributes - expect(iframeElement.attributes.getNamedItem('allow').value).toEqual(IFRAME_FEATURE_POLICY); - expect(iframeElement.attributes.getNamedItem('src').value).toEqual(iframeConfig.url); - expect(iframeElement.attributes.getNamedItem('title').value).toEqual(iframeConfig.title); - // The component isn't ready, since the class has 'd-none' - expect(iframeElement.attributes.getNamedItem('class').value).toEqual('border border-0 w-100 d-none'); - - jest.spyOn(iframeElement.contentWindow, 'postMessage'); - - expect(iframeElement.contentWindow.postMessage).not.toHaveBeenCalled(); - - // Dispatch a 'mounted' event manually. - const mountedEvent = new Event('message'); - mountedEvent.data = { - type: PLUGIN_MOUNTED, - }; - mountedEvent.source = iframeElement.contentWindow; - fireEvent(window, mountedEvent); - - expect(iframeElement.contentWindow.postMessage).toHaveBeenCalledWith( - { - type: PLUGIN_RESIZE, - payload: { - width: 0, // There's no width/height here in jsdom-land. - height: 0, - }, - }, - 'http://localhost/plugin1', - ); - - // Dispatch a 'ready' event manually. - const readyEvent = new Event('message'); - readyEvent.data = { - type: PLUGIN_READY, - }; - readyEvent.source = iframeElement.contentWindow; - fireEvent(window, readyEvent); - - expect(iframeElement.attributes.getNamedItem('class').value).toEqual('border border-0 w-100'); - }); - - it('should render a Plugin Direct Container when given a Direct config', async () => { - const component = ( - Loading} /> - ); - - const { getByTestId } = render(component); - - expect(getByTestId(directConfig.id)).toBeInTheDocument(); - }); -}); - -describe('Plugin', () => { - let logError = jest.fn(); - - const error = ( - - ); - - beforeEach(async () => { - // This is a gross hack to suppress error logs in the invalid parentSelector test - jest.spyOn(console, 'error'); - global.console.error.mockImplementation(() => {}); - - const { loggingService } = initializeMockApp(); - logError = loggingService.logError; - }); - - afterEach(() => { - global.console.error.mockRestore(); - jest.clearAllMocks(); - }); - - const ExplodingComponent = () => { - throw new Error(error); - }; - - const HealthyComponent = () => ( -
- -
- ); - - const ErrorFallbackComponent = () => ( -
-

- -

-
-
- ); - - const PluginPageWrapper = ({ - params, FallbackComponent, ChildComponent, - }) => ( - - - - - - ); - - it('should render children if no error', () => { - const component = ( - - ); - const { container } = render(component); - expect(container).toHaveTextContent('Hello World!'); - }); - - it('should throw an error if the child component fails', () => { - const component = ( - - ); - - const { container } = render(component); - expect(container).toHaveTextContent('Oh geez'); - - expect(logError).toHaveBeenCalledTimes(1); - expect(logError).toHaveBeenCalledWith( - new Error(error), - expect.objectContaining({ - stack: expect.stringContaining('ExplodingComponent'), - }), - ); - }); - - it('should render the default fallback component when one is not passed into the Plugin', () => { - const component = ( - - ); - - const { container } = render(component); - expect(container).toHaveTextContent('Oops! An error occurred.'); - }); -}); diff --git a/runtime/plugins/PluginContainer.jsx b/runtime/plugins/PluginContainer.jsx deleted file mode 100644 index 7c244133..00000000 --- a/runtime/plugins/PluginContainer.jsx +++ /dev/null @@ -1,55 +0,0 @@ -'use client'; - -import PropTypes from 'prop-types'; - -import PluginContainerDirect from './PluginContainerDirect'; -import PluginContainerIframe from './PluginContainerIframe'; - -import { PluginTypes } from '../../types'; -import { pluginConfigShape, slotOptionsShape } from './data/shapes'; - -function PluginContainer({ config, slotOptions, ...props }) { - if (!config) { - return null; - } - - // this will allow for future plugin types to be inserted in the PluginErrorBoundary - let renderer = null; - switch (config.type) { - case PluginTypes.IFRAME: - renderer = ( - - ); - break; - case PluginTypes.DIRECT: - renderer = ( - - ); - break; - default: - break; - } - - return renderer; -} - -export default PluginContainer; - -PluginContainer.propTypes = { - /** Configuration for the Plugin in this container — i.e pluginSlot[id].example_plugin */ - config: PropTypes.shape(pluginConfigShape), - /** Options passed to the PluginSlot */ - slotOptions: PropTypes.shape(slotOptionsShape), -}; - -PluginContainer.defaultProps = { - config: null, - slotOptions: {}, -}; diff --git a/runtime/plugins/PluginContainerDirect.jsx b/runtime/plugins/PluginContainerDirect.jsx deleted file mode 100644 index 23127407..00000000 --- a/runtime/plugins/PluginContainerDirect.jsx +++ /dev/null @@ -1,40 +0,0 @@ -import React, { Suspense } from 'react'; -import PropTypes from 'prop-types'; - -import { directPluginConfigShape, slotOptionsShape } from './data/shapes'; -import { mergeRenderWidgetPropsWithPluginContent } from './data/utils'; - -function PluginContainerDirect({ - config, slotOptions, loadingFallback, ...props -}) { - const { RenderWidget, id } = config; - - // When applicable, merge base RenderWidget props with custom plugin content, if any. - const propsForRenderWidget = mergeRenderWidgetPropsWithPluginContent({ - pluginSlotOptions: slotOptions, - pluginConfig: config, - renderWidgetProps: props, - }); - - return ( - - - - ); -} - -PluginContainerDirect.propTypes = { - /** Configuration for the Plugin in this container (i.e. pluginSlot[id].example_plugin) */ - config: PropTypes.shape(directPluginConfigShape).isRequired, - /** Custom fallback component used when component is not ready (i.e. "loading") */ - loadingFallback: PropTypes.node, - /** Options passed to the PluginSlot */ - slotOptions: PropTypes.shape(slotOptionsShape), -}; - -PluginContainerDirect.defaultProps = { - loadingFallback: null, - slotOptions: {}, -}; - -export default PluginContainerDirect; diff --git a/runtime/plugins/PluginContainerIframe.jsx b/runtime/plugins/PluginContainerIframe.jsx deleted file mode 100644 index 22aa0795..00000000 --- a/runtime/plugins/PluginContainerIframe.jsx +++ /dev/null @@ -1,97 +0,0 @@ -import React, { - useEffect, useState, -} from 'react'; -import PropTypes from 'prop-types'; -// eslint-disable-next-line import/no-extraneous-dependencies -import classNames from 'classnames'; - -import { - PLUGIN_MOUNTED, - PLUGIN_READY, - PLUGIN_RESIZE, -} from './data/constants'; -import { - dispatchPluginEvent, - useElementSize, - usePluginEvent, -} from './data/hooks'; -import { iframePluginConfigShape } from './data/shapes'; - -/** - * Feature policy for iframe, allowing access to certain courseware-related media. - * - * We must use the wildcard (*) origin for each feature, as courseware content - * may be embedded in external iframes. Notably, xblock-lti-consumer is a popular - * block that iframes external course content. - - * This policy was selected in conference with the edX Security Working Group. - * Changes to it should be vetted by them (security@edx.org). - */ -export const IFRAME_FEATURE_POLICY = ( - 'fullscreen; microphone *; camera *; midi *; geolocation *; encrypted-media *' -); - -function PluginContainerIframe({ - config, loadingFallback, className, ...props -}) { - const { url, title } = config; - const [mounted, setMounted] = useState(false); - const [ready, setReady] = useState(false); - - const [iframeRef, iframeElement, width, height] = useElementSize(); - - useEffect(() => { - if (mounted) { - dispatchPluginEvent(iframeElement, { - type: PLUGIN_RESIZE, - payload: { - width, - height, - }, - }, url); - } - }, [iframeElement, mounted, width, height, url]); - - usePluginEvent(iframeElement, PLUGIN_MOUNTED, () => { - setMounted(true); - }); - - usePluginEvent(iframeElement, PLUGIN_READY, () => { - setReady(true); - }); - - return ( - <> -