diff --git a/.github/workflows/shared-component-visual-tests.yaml b/.github/workflows/shared-component-visual-tests.yaml
index 85f10aaa78..98d258349e 100644
--- a/.github/workflows/shared-component-visual-tests.yaml
+++ b/.github/workflows/shared-component-visual-tests.yaml
@@ -49,6 +49,16 @@ jobs:
if: steps.playwright-cache.outputs.cache-hit != 'true'
run: "yarn playwright install --with-deps --only-shell"
+ - name: Build Element Web resources
+ # Needed to prepare language files
+ run: "yarn build:res"
+
+ - name: Build storybook dependencies
+ # When the first test is ran, it will fail because the dependencies are not yet built.
+ # This step is to ensure that the dependencies are built before running the tests.
+ run: "yarn test:storybook:ci"
+ continue-on-error: true
+
- name: Run Visual tests
run: "yarn test:storybook:ci"
diff --git a/.storybook/languageAddon.tsx b/.storybook/languageAddon.tsx
new file mode 100644
index 0000000000..0e46e9b25b
--- /dev/null
+++ b/.storybook/languageAddon.tsx
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2025 New Vector Ltd.
+ *
+ * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
+ * Please see LICENSE files in the repository root for full details.
+ */
+
+import { Addon, types, useGlobals } from "storybook/manager-api";
+import { WithTooltip, IconButton, TooltipLinkList } from "storybook/internal/components";
+import React from "react";
+import { GlobeIcon } from "@storybook/icons";
+
+// We can't import `shared/i18n.tsx` directly here.
+// The storybook addon doesn't seem to benefit the vite config of storybook and we can't resolve the alias in i18n.tsx.
+import json from "../webapp/i18n/languages.json";
+const languages = Object.keys(json).filter((lang) => lang !== "default");
+
+/**
+ * Returns the title of a language in the user's locale.
+ */
+function languageTitle(language: string): string {
+ return new Intl.DisplayNames([language], { type: "language", style: "short" }).of(language) || language;
+}
+
+export const languageAddon: Addon = {
+ title: "Language Selector",
+ type: types.TOOL,
+ render: ({ active }) => {
+ const [globals, updateGlobals] = useGlobals();
+ const selectedLanguage = globals.language || "en";
+
+ return (
+ {
+ return (
+ ({
+ id: language,
+ title: languageTitle(language),
+ active: selectedLanguage === language,
+ onClick: async () => {
+ // Update the global state with the selected language
+ updateGlobals({ language });
+ onHide();
+ },
+ }))}
+ />
+ );
+ }}
+ >
+
+
+ {languageTitle(selectedLanguage)}
+
+
+ );
+ },
+};
diff --git a/.storybook/main.ts b/.storybook/main.ts
index f2195f3f49..ef8b8cd19c 100644
--- a/.storybook/main.ts
+++ b/.storybook/main.ts
@@ -6,9 +6,13 @@ Please see LICENSE files in the repository root for full details.
*/
import type { StorybookConfig } from "@storybook/react-vite";
+import path from "node:path";
+import { nodePolyfills } from "vite-plugin-node-polyfills";
+import { mergeConfig } from "vite";
const config: StorybookConfig = {
stories: ["../src/shared-components/**/*.stories.@(js|jsx|mjs|ts|tsx)"],
+ staticDirs: ["../webapp"],
addons: ["@storybook/addon-docs", "@storybook/addon-designs"],
framework: "@storybook/react-vite",
core: {
@@ -17,5 +21,17 @@ const config: StorybookConfig = {
typescript: {
reactDocgen: "react-docgen-typescript",
},
+ async viteFinal(config) {
+ return mergeConfig(config, {
+ resolve: {
+ alias: {
+ // Alias used by i18n.tsx
+ $webapp: path.resolve("webapp"),
+ },
+ },
+ // Needed for counterpart to work
+ plugins: [nodePolyfills({ include: ["process", "util"] })],
+ });
+ },
};
export default config;
diff --git a/.storybook/manager.js b/.storybook/manager.js
index e1b872fef8..1b08ef7825 100644
--- a/.storybook/manager.js
+++ b/.storybook/manager.js
@@ -5,9 +5,14 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
Please see LICENSE files in the repository root for full details.
*/
+import React from "react";
+
import { addons } from "storybook/manager-api";
import ElementTheme from "./ElementTheme";
+import { languageAddon } from "./languageAddon";
addons.setConfig({
theme: ElementTheme,
});
+
+addons.register("elementhq/language", () => addons.add("language", languageAddon));
diff --git a/.storybook/preview.tsx b/.storybook/preview.tsx
index a8dc63d39c..8d7516680a 100644
--- a/.storybook/preview.tsx
+++ b/.storybook/preview.tsx
@@ -1,13 +1,15 @@
import type { ArgTypes, Preview, Decorator } from "@storybook/react-vite";
+import { addons } from "storybook/preview-api";
import "../res/css/shared.pcss";
import "./preview.css";
import React, { useLayoutEffect } from "react";
+import { FORCE_RE_RENDER } from "storybook/internal/core-events";
+import { setLanguage } from "../src/shared-components/i18n";
export const globalTypes = {
theme: {
name: "Theme",
- defaultValue: "system",
description: "Global theme for components",
toolbar: {
icon: "circlehollow",
@@ -21,6 +23,14 @@ export const globalTypes = {
],
},
},
+ language: {
+ name: "Language",
+ description: "Global language for components",
+ },
+ initialGlobals: {
+ theme: "system",
+ language: "en",
+ },
} satisfies ArgTypes;
const allThemesClasses = globalTypes.theme.toolbar.items.map(({ value }) => `cpd-theme-${value}`);
@@ -48,9 +58,33 @@ const withThemeProvider: Decorator = (Story, context) => {
);
};
+const LanguageSwitcher: React.FC<{
+ language: string;
+}> = ({ language }) => {
+ useLayoutEffect(() => {
+ const changeLanguage = async (language: string) => {
+ await setLanguage(language);
+ // Force the component to re-render to apply the new language
+ addons.getChannel().emit(FORCE_RE_RENDER);
+ };
+ changeLanguage(language);
+ }, [language]);
+
+ return null;
+};
+
+export const withLanguageProvider: Decorator = (Story, context) => {
+ return (
+ <>
+
+
+ >
+ );
+};
+
const preview: Preview = {
tags: ["autodocs"],
- decorators: [withThemeProvider],
+ decorators: [withThemeProvider, withLanguageProvider],
};
export default preview;
diff --git a/package.json b/package.json
index c585bfc9b5..fef29cd1f5 100644
--- a/package.json
+++ b/package.json
@@ -193,6 +193,7 @@
"@sentry/webpack-plugin": "^3.0.0",
"@storybook/addon-designs": "^10.0.1",
"@storybook/addon-docs": "^9.0.12",
+ "@storybook/icons": "^1.4.0",
"@storybook/react-vite": "^9.0.15",
"@storybook/test-runner": "^0.23.0",
"@stylistic/eslint-plugin": "^5.0.0",
@@ -306,6 +307,7 @@
"typescript": "5.8.3",
"util": "^0.12.5",
"vite": "^7.0.1",
+ "vite-plugin-node-polyfills": "^0.24.0",
"web-streams-polyfill": "^4.0.0",
"webpack": "^5.89.0",
"webpack-bundle-analyzer": "^4.8.0",
diff --git a/src/accessibility/KeyboardShortcuts.ts b/src/accessibility/KeyboardShortcuts.ts
index ec5b8312b9..e3cc42a775 100644
--- a/src/accessibility/KeyboardShortcuts.ts
+++ b/src/accessibility/KeyboardShortcuts.ts
@@ -8,7 +8,8 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
Please see LICENSE files in the repository root for full details.
*/
-import { _td, type TranslationKey } from "../languageHandler";
+// Import i18n.tsx instead of languageHandler to avoid circular deps
+import { _td, type TranslationKey } from "../shared-components/i18n";
import { IS_MAC, IS_ELECTRON, Key } from "../Keyboard";
import { type IBaseSetting } from "../settings/Settings";
import { type KeyCombo } from "../KeyBindingsManager";
diff --git a/src/languageHandler.tsx b/src/languageHandler.tsx
index 175f9c149f..9ac6cce1c5 100644
--- a/src/languageHandler.tsx
+++ b/src/languageHandler.tsx
@@ -1,49 +1,49 @@
/*
-Copyright 2024 New Vector Ltd.
-Copyright 2019-2022 The Matrix.org Foundation C.I.C.
-Copyright 2019 Michael Telatynski <7t3chguy@gmail.com>
-Copyright 2017 MTRNord and Cooperative EITA
-Copyright 2017 Vector Creations Ltd.
-
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
-Please see LICENSE files in the repository root for full details.
-*/
+ * Copyright 2025 New Vector Ltd.
+ *
+ * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
+ * Please see LICENSE files in the repository root for full details.
+ */
import counterpart from "counterpart";
-import React from "react";
import { logger } from "matrix-js-sdk/src/logger";
import { type Optional } from "matrix-events-sdk";
import { MapWithDefault } from "matrix-js-sdk/src/utils";
-import { normalizeLanguageKey, type TranslationKey as _TranslationKey, KEY_SEPARATOR } from "matrix-web-i18n";
import { type TranslationStringsObject } from "@matrix-org/react-sdk-module-api";
import _ from "lodash";
-import type Translations from "./i18n/strings/en_EN.json";
import SettingsStore from "./settings/SettingsStore";
import PlatformPeg from "./PlatformPeg";
import { SettingLevel } from "./settings/SettingLevel";
import { retry } from "./utils/promise";
import SdkConfig from "./SdkConfig";
import { ModuleRunner } from "./modules/ModuleRunner";
+import {
+ _t,
+ normalizeLanguageKey,
+ type TranslationKey,
+ type IVariables,
+ KEY_SEPARATOR,
+ getLangsJson,
+} from "./shared-components/i18n";
-// @ts-ignore - $webapp is a webpack resolve alias pointing to the output directory, see webpack config
-import webpackLangJsonUrl from "$webapp/i18n/languages.json";
-
-export { normalizeLanguageKey, getNormalizedLanguageKeys } from "matrix-web-i18n";
+export {
+ _t,
+ type IVariables,
+ type Tags,
+ type TranslationKey,
+ type TranslatedString,
+ _td,
+ _tDom,
+ lookupString,
+ sanitizeForTranslation,
+ normalizeLanguageKey,
+ getNormalizedLanguageKeys,
+ substitute,
+} from "./shared-components/i18n";
const i18nFolder = "i18n/";
-// Control whether to also return original, untranslated strings
-// Useful for debugging and testing
-const ANNOTATE_STRINGS = false;
-
-// We use english strings as keys, some of which contain full stops
-counterpart.setSeparator(KEY_SEPARATOR);
-
-// see `translateWithFallback` for an explanation of fallback handling
-const FALLBACK_LOCALE = "en";
-counterpart.setFallbackLocale(FALLBACK_LOCALE);
-
export interface ErrorOptions {
// Because we're mixing the substitution variables and `cause` into the same object
// below, we want them to always explicitly say whether there is an underlying error
@@ -96,353 +96,6 @@ export function getUserLanguage(): string {
}
}
-/**
- * A type representing the union of possible keys into the translation file using `|` delimiter to access nested fields.
- * @example `common|error` to access `error` within the `common` sub-object.
- * {
- * "common": {
- * "error": "Error"
- * }
- * }
- */
-export type TranslationKey = _TranslationKey;
-
-// Function which only purpose is to mark that a string is translatable
-// Does not actually do anything. It's helpful for automatic extraction of translatable strings
-export function _td(s: TranslationKey): TranslationKey {
- return s;
-}
-
-function isValidTranslation(translated: string): boolean {
- return typeof translated === "string" && !translated.startsWith("missing translation:");
-}
-
-/**
- * to improve screen reader experience translations that are not in the main page language
- * eg a translation that fell back to english from another language
- * should be wrapped with an appropriate `lang='en'` attribute
- * counterpart's `translate` doesn't expose a way to determine if the resulting translation
- * is in the target locale or a fallback locale
- * for this reason, force fallbackLocale === locale in the first call to translate
- * and fallback 'manually' so we can mark fallback strings appropriately
- * */
-const translateWithFallback = (text: string, options?: IVariables): { translated: string; isFallback?: boolean } => {
- const translated = counterpart.translate(text, { ...options, fallbackLocale: counterpart.getLocale() });
- if (isValidTranslation(translated)) {
- return { translated };
- }
-
- const fallbackTranslated = counterpart.translate(text, { ...options, locale: FALLBACK_LOCALE });
- if (isValidTranslation(fallbackTranslated)) {
- return { translated: fallbackTranslated, isFallback: true };
- }
-
- // Even the translation via FALLBACK_LOCALE failed; this can happen if
- //
- // 1. The string isn't in the translations dictionary, usually because you're in develop
- // and haven't run yarn i18n
- // 2. Loading the translation resources over the network failed, which can happen due to
- // to network or if the client tried to load a translation that's been removed from the
- // server.
- //
- // At this point, its the lesser evil to show the i18n key which will be in English but not human-friendly,
- // so the user can still make out *something*, rather than an opaque possibly-untranslated "missing translation" error.
- return { translated: text, isFallback: true };
-};
-
-// Wrapper for counterpart's translation function so that it handles nulls and undefineds properly
-// Takes the same arguments as counterpart.translate()
-function safeCounterpartTranslate(text: string, variables?: IVariables): { translated: string; isFallback?: boolean } {
- // Don't do substitutions in counterpart. We handle it ourselves so we can replace with React components
- // However, still pass the variables to counterpart so that it can choose the correct plural if count is given
- // It is enough to pass the count variable, but in the future counterpart might make use of other information too
- const options: IVariables & {
- interpolate: boolean;
- } = { ...variables, interpolate: false };
-
- // Horrible hack to avoid https://github.com/vector-im/element-web/issues/4191
- // The interpolation library that counterpart uses does not support undefined/null
- // values and instead will throw an error. This is a problem since everywhere else
- // in JS land passing undefined/null will simply stringify instead, and when converting
- // valid ES6 template strings to i18n strings it's extremely easy to pass undefined/null
- // if there are no existing null guards. To avoid this making the app completely inoperable,
- // we'll check all the values for undefined/null and stringify them here.
- if (options && typeof options === "object") {
- Object.keys(options).forEach((k) => {
- if (options[k] === undefined) {
- logger.warn("safeCounterpartTranslate called with undefined interpolation name: " + k);
- options[k] = "undefined";
- }
- if (options[k] === null) {
- logger.warn("safeCounterpartTranslate called with null interpolation name: " + k);
- options[k] = "null";
- }
- });
- }
- return translateWithFallback(text, options);
-}
-
-/**
- * The value a variable or tag can take for a translation interpolation.
- */
-type SubstitutionValue = number | string | React.ReactNode | ((sub: string) => React.ReactNode);
-
-export interface IVariables {
- count?: number;
- [key: string]: SubstitutionValue;
-}
-
-export type Tags = Record;
-
-export type TranslatedString = string | React.ReactNode;
-
-// For development/testing purposes it is useful to also output the original string
-// Don't do that for release versions
-const annotateStrings = (result: TranslatedString, translationKey: TranslationKey): TranslatedString => {
- if (!ANNOTATE_STRINGS) {
- return result;
- }
-
- if (typeof result === "string") {
- return `@@${translationKey}##${result}@@`;
- } else {
- return (
-
- {result}
-
- );
- }
-};
-
-/*
- * Translates text and optionally also replaces XML-ish elements in the text with e.g. React components
- * @param {string} text The untranslated text, e.g "click here now to %(foo)s".
- * @param {object} variables Variable substitutions, e.g { foo: 'bar' }
- * @param {object} tags Tag substitutions e.g. { 'a': (sub) => {sub} }
- *
- * In both variables and tags, the values to substitute with can be either simple strings, React components,
- * or functions that return the value to use in the substitution (e.g. return a React component). In case of
- * a tag replacement, the function receives as the argument the text inside the element corresponding to the tag.
- *
- * Use tag substitutions if you need to translate text between tags (e.g. "Click here!"), otherwise
- * you will end up with literal "" in your output, rather than HTML. Note that you can also use variable
- * substitution to insert React components, but you can't use it to translate text between tags.
- *
- * @return a React component if any non-strings were used in substitutions, otherwise a string
- */
-// eslint-next-line @typescript-eslint/naming-convention
-export function _t(text: TranslationKey, variables?: IVariables): string;
-export function _t(text: TranslationKey, variables: IVariables | undefined, tags: Tags): React.ReactNode;
-export function _t(text: TranslationKey, variables?: IVariables, tags?: Tags): TranslatedString {
- // The translation returns text so there's no XSS vector here (no unsafe HTML, no code execution)
- const { translated } = safeCounterpartTranslate(text, variables);
- const substituted = substitute(translated, variables, tags);
-
- return annotateStrings(substituted, text);
-}
-
-/**
- * Utility function to look up a string by its translation key without resolving variables & tags
- * @param key - the translation key to return the value for
- */
-export function lookupString(key: TranslationKey): string {
- return safeCounterpartTranslate(key, {}).translated;
-}
-
-/*
- * Wraps normal _t function and adds atttribution for translations that used a fallback locale
- * Wraps translations that fell back from active locale to fallback locale with a `>`
- * @param {string} text The untranslated text, e.g "click here now to %(foo)s".
- * @param {object} variables Variable substitutions, e.g { foo: 'bar' }
- * @param {object} tags Tag substitutions e.g. { 'a': (sub) => {sub} }
- *
- * @return a React component if any non-strings were used in substitutions
- * or translation used a fallback locale, otherwise a string
- */
-// eslint-next-line @typescript-eslint/naming-convention
-export function _tDom(text: TranslationKey, variables?: IVariables): TranslatedString;
-export function _tDom(text: TranslationKey, variables: IVariables, tags: Tags): React.ReactNode;
-export function _tDom(text: TranslationKey, variables?: IVariables, tags?: Tags): TranslatedString {
- // The translation returns text so there's no XSS vector here (no unsafe HTML, no code execution)
- const { translated, isFallback } = safeCounterpartTranslate(text, variables);
- const substituted = substitute(translated, variables, tags);
-
- // wrap en fallback translation with lang attribute for screen readers
- const result = isFallback ? {substituted} : substituted;
-
- return annotateStrings(result, text);
-}
-
-/**
- * Sanitizes unsafe text for the sanitizer, ensuring references to variables will not be considered
- * replaceable by the translation functions.
- * @param {string} text The text to sanitize.
- * @returns {string} The sanitized text.
- */
-export function sanitizeForTranslation(text: string): string {
- // Add a non-breaking space so the regex doesn't trigger when translating.
- return text.replace(/%\(([^)]*)\)/g, "%\xa0($1)");
-}
-
-/*
- * Similar to _t(), except only does substitutions, and no translation
- * @param {string} text The text, e.g "click here now to %(foo)s".
- * @param {object} variables Variable substitutions, e.g { foo: 'bar' }
- * @param {object} tags Tag substitutions e.g. { 'a': (sub) => {sub} }
- *
- * The values to substitute with can be either simple strings, or functions that return the value to use in
- * the substitution (e.g. return a React component). In case of a tag replacement, the function receives as
- * the argument the text inside the element corresponding to the tag.
- *
- * @return a React component if any non-strings were used in substitutions, otherwise a string
- */
-export function substitute(text: string, variables?: IVariables): string;
-export function substitute(text: string, variables: IVariables | undefined, tags: Tags | undefined): string;
-export function substitute(text: string, variables?: IVariables, tags?: Tags): string | React.ReactNode {
- let result: React.ReactNode | string = text;
-
- if (variables !== undefined) {
- const regexpMapping: IVariables = {};
- for (const variable in variables) {
- regexpMapping[`%\\(${variable}\\)s`] = variables[variable];
- }
- result = replaceByRegexes(result as string, regexpMapping);
- }
-
- if (tags !== undefined) {
- const regexpMapping: Tags = {};
- for (const tag in tags) {
- regexpMapping[`(<${tag}>(.*?)<\\/${tag}>|<${tag}>|<${tag}\\s*\\/>)`] = tags[tag];
- }
- result = replaceByRegexes(result as string, regexpMapping);
- }
-
- return result;
-}
-
-/**
- * Replace parts of a text using regular expressions
- * @param text - The text on which to perform substitutions
- * @param mapping - A mapping from regular expressions in string form to replacement string or a
- * function which will receive as the argument the capture groups defined in the regexp. E.g.
- * { 'Hello (.?) World': (sub) => sub.toUpperCase() }
- *
- * @return a React component if any non-strings were used in substitutions, otherwise a string
- */
-export function replaceByRegexes(text: string, mapping: IVariables): string;
-export function replaceByRegexes(text: string, mapping: Tags): React.ReactNode;
-export function replaceByRegexes(text: string, mapping: IVariables | Tags): string | React.ReactNode {
- // We initially store our output as an array of strings and objects (e.g. React components).
- // This will then be converted to a string or a at the end
- const output: SubstitutionValue[] = [text];
-
- // If we insert any components we need to wrap the output in a span. React doesn't like just an array of components.
- let shouldWrapInSpan = false;
-
- for (const regexpString in mapping) {
- // TODO: Cache regexps
- const regexp = new RegExp(regexpString, "g");
-
- // Loop over what output we have so far and perform replacements
- // We look for matches: if we find one, we get three parts: everything before the match, the replaced part,
- // and everything after the match. Insert all three into the output. We need to do this because we can insert objects.
- // Otherwise there would be no need for the splitting and we could do simple replacement.
- let matchFoundSomewhere = false; // If we don't find a match anywhere we want to log it
- for (let outputIndex = 0; outputIndex < output.length; outputIndex++) {
- const inputText = output[outputIndex];
- if (typeof inputText !== "string") {
- // We might have inserted objects earlier, don't try to replace them
- continue;
- }
-
- // process every match in the string
- // starting with the first
- let match = regexp.exec(inputText);
-
- if (!match) continue;
- matchFoundSomewhere = true;
-
- // The textual part before the first match
- const head = inputText.slice(0, match.index);
-
- const parts: SubstitutionValue[] = [];
- // keep track of prevMatch
- let prevMatch;
- while (match) {
- // store prevMatch
- prevMatch = match;
- const capturedGroups = match.slice(2);
-
- let replaced: SubstitutionValue;
- // If substitution is a function, call it
- if (mapping[regexpString] instanceof Function) {
- replaced = ((mapping as Tags)[regexpString] as (...subs: string[]) => string)(...capturedGroups);
- } else {
- replaced = mapping[regexpString];
- }
-
- if (typeof replaced === "object") {
- shouldWrapInSpan = true;
- }
-
- // Here we also need to check that it actually is a string before comparing against one
- // The head and tail are always strings
- if (typeof replaced !== "string" || replaced !== "") {
- parts.push(replaced);
- }
-
- // try the next match
- match = regexp.exec(inputText);
-
- // add the text between prevMatch and this one
- // or the end of the string if prevMatch is the last match
- let tail;
- if (match) {
- const startIndex = prevMatch.index + prevMatch[0].length;
- tail = inputText.slice(startIndex, match.index);
- } else {
- tail = inputText.slice(prevMatch.index + prevMatch[0].length);
- }
- if (tail) {
- parts.push(tail);
- }
- }
-
- // Insert in reverse order as splice does insert-before and this way we get the final order correct
- // remove the old element at the same time
- output.splice(outputIndex, 1, ...parts);
-
- if (head !== "") {
- // Don't push empty nodes, they are of no use
- output.splice(outputIndex, 0, head);
- }
- }
- if (!matchFoundSomewhere) {
- if (
- // The current regexp did not match anything in the input. Missing
- // matches is entirely possible because you might choose to show some
- // variables only in the case of e.g. plurals. It's still a bit
- // suspicious, and could be due to an error, so log it. However, not
- // showing count is so common that it's not worth logging. And other
- // commonly unused variables here, if there are any.
- regexpString !== "%\\(count\\)s" &&
- // Ignore the `locale` option which can be used to override the locale
- // in counterpart
- regexpString !== "%\\(locale\\)s"
- ) {
- logger.log(`Could not find ${regexp} in ${text}`);
- }
- }
- }
-
- if (shouldWrapInSpan) {
- return React.createElement("span", null, ...(output as Array));
- } else {
- // eslint-disable-next-line @typescript-eslint/no-base-to-string
- return output.join("");
- }
-}
-
// Allow overriding the text displayed when no translation exists
// Currently only used in unit tests to avoid having to load
// the translations in element-web
@@ -450,10 +103,6 @@ export function setMissingEntryGenerator(f: (value: string) => void): void {
counterpart.setMissingEntryGenerator(f);
}
-type Languages = {
- [lang: string]: string;
-};
-
export async function setLanguage(...preferredLangs: string[]): Promise {
PlatformPeg.get()?.setLanguage(preferredLangs);
@@ -554,24 +203,6 @@ export function pickBestLanguage(langs: string[]): string {
return langs[0];
}
-async function getLangsJson(): Promise {
- let url: string;
- if (typeof webpackLangJsonUrl === "string") {
- // in Jest this 'url' isn't a URL, so just fall through
- url = webpackLangJsonUrl;
- } else {
- url = i18nFolder + "languages.json";
- }
-
- const res = await fetch(url, { method: "GET" });
-
- if (!res.ok) {
- throw new Error(`Failed to load ${url}, got ${res.status}`);
- }
-
- return res.json();
-}
-
interface ICounterpartTranslation {
[key: string]:
| string
diff --git a/src/settings/Settings.tsx b/src/settings/Settings.tsx
index 1140d24ed8..4ed3752372 100644
--- a/src/settings/Settings.tsx
+++ b/src/settings/Settings.tsx
@@ -11,7 +11,8 @@ import React, { type ReactNode } from "react";
import { UNSTABLE_MSC4133_EXTENDED_PROFILES } from "matrix-js-sdk/src/matrix";
import { type MediaPreviewConfig } from "../@types/media_preview.ts";
-import { _t, _td, type TranslationKey } from "../languageHandler";
+// Import i18n.tsx instead of languageHandler to avoid circular deps
+import { _t, _td, type TranslationKey } from "../shared-components/i18n";
import DeviceIsolationModeController from "./controllers/DeviceIsolationModeController.ts";
import {
NotificationBodyEnabledController,
diff --git a/src/shared-components/i18n.tsx b/src/shared-components/i18n.tsx
new file mode 100644
index 0000000000..e23acff831
--- /dev/null
+++ b/src/shared-components/i18n.tsx
@@ -0,0 +1,432 @@
+/*
+ * Copyright 2025 New Vector Ltd.
+ *
+ * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
+ * Please see LICENSE files in the repository root for full details.
+ */
+
+/*
+ * Translates text and optionally also replaces XML-ish elements in the text with e.g. React components
+ * @param {string} text The untranslated text, e.g "click here now to %(foo)s".
+ * @param {object} variables Variable substitutions, e.g { foo: 'bar' }
+ * @param {object} tags Tag substitutions e.g. { 'a': (sub) => {sub} }
+ *
+ * In both variables and tags, the values to substitute with can be either simple strings, React components,
+ * or functions that return the value to use in the substitution (e.g. return a React component). In case of
+ * a tag replacement, the function receives as the argument the text inside the element corresponding to the tag.
+ *
+ * Use tag substitutions if you need to translate text between tags (e.g. "Click here!"), otherwise
+ * you will end up with literal "" in your output, rather than HTML. Note that you can also use variable
+ * substitution to insert React components, but you can't use it to translate text between tags.
+ *
+ * @return a React component if any non-strings were used in substitutions, otherwise a string
+ */
+import React from "react";
+import { type TranslationKey as _TranslationKey, KEY_SEPARATOR } from "matrix-web-i18n";
+import counterpart from "counterpart";
+
+import type Translations from "../i18n/strings/en_EN.json";
+
+// @ts-ignore - $webapp is a webpack resolve alias pointing to the output directory, see webpack config
+import webpackLangJsonUrl from "$webapp/i18n/languages.json";
+
+export { KEY_SEPARATOR, normalizeLanguageKey, getNormalizedLanguageKeys } from "matrix-web-i18n";
+
+const i18nFolder = "i18n/";
+
+// Control whether to also return original, untranslated strings
+// Useful for debugging and testing
+const ANNOTATE_STRINGS = false;
+
+// We use english strings as keys, some of which contain full stops
+counterpart.setSeparator(KEY_SEPARATOR);
+
+// see `translateWithFallback` for an explanation of fallback handling
+const FALLBACK_LOCALE = "en";
+counterpart.setFallbackLocale(FALLBACK_LOCALE);
+
+/**
+ * A type representing the union of possible keys into the translation file using `|` delimiter to access nested fields.
+ * @example `common|error` to access `error` within the `common` sub-object.
+ * {
+ * "common": {
+ * "error": "Error"
+ * }
+ * }
+ */
+export type TranslationKey = _TranslationKey;
+
+// Function which only purpose is to mark that a string is translatable
+// Does not actually do anything. It's helpful for automatic extraction of translatable strings
+export function _td(s: TranslationKey): TranslationKey {
+ return s;
+}
+
+function isValidTranslation(translated: string): boolean {
+ return typeof translated === "string" && !translated.startsWith("missing translation:");
+}
+
+/**
+ * to improve screen reader experience translations that are not in the main page language
+ * eg a translation that fell back to english from another language
+ * should be wrapped with an appropriate `lang='en'` attribute
+ * counterpart's `translate` doesn't expose a way to determine if the resulting translation
+ * is in the target locale or a fallback locale
+ * for this reason, force fallbackLocale === locale in the first call to translate
+ * and fallback 'manually' so we can mark fallback strings appropriately
+ * */
+const translateWithFallback = (text: string, options?: IVariables): { translated: string; isFallback?: boolean } => {
+ const translated = counterpart.translate(text, { ...options, fallbackLocale: counterpart.getLocale() });
+ if (isValidTranslation(translated)) {
+ return { translated };
+ }
+
+ const fallbackTranslated = counterpart.translate(text, { ...options, locale: FALLBACK_LOCALE });
+ if (isValidTranslation(fallbackTranslated)) {
+ return { translated: fallbackTranslated, isFallback: true };
+ }
+
+ // Even the translation via FALLBACK_LOCALE failed; this can happen if
+ //
+ // 1. The string isn't in the translations dictionary, usually because you're in develop
+ // and haven't run yarn i18n
+ // 2. Loading the translation resources over the network failed, which can happen due to
+ // to network or if the client tried to load a translation that's been removed from the
+ // server.
+ //
+ // At this point, its the lesser evil to show the i18n key which will be in English but not human-friendly,
+ // so the user can still make out *something*, rather than an opaque possibly-untranslated "missing translation" error.
+ return { translated: text, isFallback: true };
+};
+
+// Wrapper for counterpart's translation function so that it handles nulls and undefineds properly
+// Takes the same arguments as counterpart.translate()
+function safeCounterpartTranslate(text: string, variables?: IVariables): { translated: string; isFallback?: boolean } {
+ // Don't do substitutions in counterpart. We handle it ourselves so we can replace with React components
+ // However, still pass the variables to counterpart so that it can choose the correct plural if count is given
+ // It is enough to pass the count variable, but in the future counterpart might make use of other information too
+ const options: IVariables & {
+ interpolate: boolean;
+ } = { ...variables, interpolate: false };
+
+ // Horrible hack to avoid https://github.com/vector-im/element-web/issues/4191
+ // The interpolation library that counterpart uses does not support undefined/null
+ // values and instead will throw an error. This is a problem since everywhere else
+ // in JS land passing undefined/null will simply stringify instead, and when converting
+ // valid ES6 template strings to i18n strings it's extremely easy to pass undefined/null
+ // if there are no existing null guards. To avoid this making the app completely inoperable,
+ // we'll check all the values for undefined/null and stringify them here.
+ if (options && typeof options === "object") {
+ Object.keys(options).forEach((k) => {
+ if (options[k] === undefined) {
+ console.warn("safeCounterpartTranslate called with undefined interpolation name: " + k);
+ options[k] = "undefined";
+ }
+ if (options[k] === null) {
+ console.warn("safeCounterpartTranslate called with null interpolation name: " + k);
+ options[k] = "null";
+ }
+ });
+ }
+ return translateWithFallback(text, options);
+}
+
+/**
+ * The value a variable or tag can take for a translation interpolation.
+ */
+type SubstitutionValue = number | string | React.ReactNode | ((sub: string) => React.ReactNode);
+
+export interface IVariables {
+ count?: number;
+ [key: string]: SubstitutionValue;
+}
+
+export type Tags = Record;
+
+export type TranslatedString = string | React.ReactNode;
+
+// For development/testing purposes it is useful to also output the original string
+// Don't do that for release versions
+const annotateStrings = (result: TranslatedString, translationKey: TranslationKey): TranslatedString => {
+ if (!ANNOTATE_STRINGS) {
+ return result;
+ }
+
+ if (typeof result === "string") {
+ return `@@${translationKey}##${result}@@`;
+ } else {
+ return (
+
+ {result}
+
+ );
+ }
+};
+
+export function _t(text: TranslationKey, variables?: IVariables): string;
+export function _t(text: TranslationKey, variables: IVariables | undefined, tags: Tags): React.ReactNode;
+export function _t(text: TranslationKey, variables?: IVariables, tags?: Tags): TranslatedString {
+ // The translation returns text so there's no XSS vector here (no unsafe HTML, no code execution)
+ const { translated } = safeCounterpartTranslate(text, variables);
+ const substituted = substitute(translated, variables, tags);
+
+ return annotateStrings(substituted, text);
+}
+
+/**
+ * Utility function to look up a string by its translation key without resolving variables & tags
+ * @param key - the translation key to return the value for
+ */
+export function lookupString(key: TranslationKey): string {
+ return safeCounterpartTranslate(key, {}).translated;
+}
+
+/*
+ * Wraps normal _t function and adds atttribution for translations that used a fallback locale
+ * Wraps translations that fell back from active locale to fallback locale with a `>`
+ * @param {string} text The untranslated text, e.g "click here now to %(foo)s".
+ * @param {object} variables Variable substitutions, e.g { foo: 'bar' }
+ * @param {object} tags Tag substitutions e.g. { 'a': (sub) => {sub} }
+ *
+ * @return a React component if any non-strings were used in substitutions
+ * or translation used a fallback locale, otherwise a string
+ */
+// eslint-next-line @typescript-eslint/naming-convention
+export function _tDom(text: TranslationKey, variables?: IVariables): TranslatedString;
+export function _tDom(text: TranslationKey, variables: IVariables, tags: Tags): React.ReactNode;
+export function _tDom(text: TranslationKey, variables?: IVariables, tags?: Tags): TranslatedString {
+ // The translation returns text so there's no XSS vector here (no unsafe HTML, no code execution)
+ const { translated, isFallback } = safeCounterpartTranslate(text, variables);
+ const substituted = substitute(translated, variables, tags);
+
+ // wrap en fallback translation with lang attribute for screen readers
+ const result = isFallback ? {substituted} : substituted;
+
+ return annotateStrings(result, text);
+}
+
+/**
+ * Sanitizes unsafe text for the sanitizer, ensuring references to variables will not be considered
+ * replaceable by the translation functions.
+ * @param {string} text The text to sanitize.
+ * @returns {string} The sanitized text.
+ */
+export function sanitizeForTranslation(text: string): string {
+ // Add a non-breaking space so the regex doesn't trigger when translating.
+ return text.replace(/%\(([^)]*)\)/g, "%\xa0($1)");
+}
+
+/*
+ * Similar to _t(), except only does substitutions, and no translation
+ * @param {string} text The text, e.g "click here now to %(foo)s".
+ * @param {object} variables Variable substitutions, e.g { foo: 'bar' }
+ * @param {object} tags Tag substitutions e.g. { 'a': (sub) => {sub} }
+ *
+ * The values to substitute with can be either simple strings, or functions that return the value to use in
+ * the substitution (e.g. return a React component). In case of a tag replacement, the function receives as
+ * the argument the text inside the element corresponding to the tag.
+ *
+ * @return a React component if any non-strings were used in substitutions, otherwise a string
+ */
+export function substitute(text: string, variables?: IVariables): string;
+export function substitute(text: string, variables: IVariables | undefined, tags: Tags | undefined): string;
+export function substitute(text: string, variables?: IVariables, tags?: Tags): string | React.ReactNode {
+ let result: React.ReactNode | string = text;
+
+ if (variables !== undefined) {
+ const regexpMapping: IVariables = {};
+ for (const variable in variables) {
+ regexpMapping[`%\\(${variable}\\)s`] = variables[variable];
+ }
+ result = replaceByRegexes(result as string, regexpMapping);
+ }
+
+ if (tags !== undefined) {
+ const regexpMapping: Tags = {};
+ for (const tag in tags) {
+ regexpMapping[`(<${tag}>(.*?)<\\/${tag}>|<${tag}>|<${tag}\\s*\\/>)`] = tags[tag];
+ }
+ result = replaceByRegexes(result as string, regexpMapping);
+ }
+
+ return result;
+}
+
+/**
+ * Replace parts of a text using regular expressions
+ * @param text - The text on which to perform substitutions
+ * @param mapping - A mapping from regular expressions in string form to replacement string or a
+ * function which will receive as the argument the capture groups defined in the regexp. E.g.
+ * { 'Hello (.?) World': (sub) => sub.toUpperCase() }
+ *
+ * @return a React component if any non-strings were used in substitutions, otherwise a string
+ */
+export function replaceByRegexes(text: string, mapping: IVariables): string;
+export function replaceByRegexes(text: string, mapping: Tags): React.ReactNode;
+export function replaceByRegexes(text: string, mapping: IVariables | Tags): string | React.ReactNode {
+ // We initially store our output as an array of strings and objects (e.g. React components).
+ // This will then be converted to a string or a at the end
+ const output: SubstitutionValue[] = [text];
+
+ // If we insert any components we need to wrap the output in a span. React doesn't like just an array of components.
+ let shouldWrapInSpan = false;
+
+ for (const regexpString in mapping) {
+ // TODO: Cache regexps
+ const regexp = new RegExp(regexpString, "g");
+
+ // Loop over what output we have so far and perform replacements
+ // We look for matches: if we find one, we get three parts: everything before the match, the replaced part,
+ // and everything after the match. Insert all three into the output. We need to do this because we can insert objects.
+ // Otherwise there would be no need for the splitting and we could do simple replacement.
+ let matchFoundSomewhere = false; // If we don't find a match anywhere we want to log it
+ for (let outputIndex = 0; outputIndex < output.length; outputIndex++) {
+ const inputText = output[outputIndex];
+ if (typeof inputText !== "string") {
+ // We might have inserted objects earlier, don't try to replace them
+ continue;
+ }
+
+ // process every match in the string
+ // starting with the first
+ let match = regexp.exec(inputText);
+
+ if (!match) continue;
+ matchFoundSomewhere = true;
+
+ // The textual part before the first match
+ const head = inputText.slice(0, match.index);
+
+ const parts: SubstitutionValue[] = [];
+ // keep track of prevMatch
+ let prevMatch;
+ while (match) {
+ // store prevMatch
+ prevMatch = match;
+ const capturedGroups = match.slice(2);
+
+ let replaced: SubstitutionValue;
+ // If substitution is a function, call it
+ if (mapping[regexpString] instanceof Function) {
+ replaced = ((mapping as Tags)[regexpString] as (...subs: string[]) => string)(...capturedGroups);
+ } else {
+ replaced = mapping[regexpString];
+ }
+
+ if (typeof replaced === "object") {
+ shouldWrapInSpan = true;
+ }
+
+ // Here we also need to check that it actually is a string before comparing against one
+ // The head and tail are always strings
+ if (typeof replaced !== "string" || replaced !== "") {
+ parts.push(replaced);
+ }
+
+ // try the next match
+ match = regexp.exec(inputText);
+
+ // add the text between prevMatch and this one
+ // or the end of the string if prevMatch is the last match
+ let tail;
+ if (match) {
+ const startIndex = prevMatch.index + prevMatch[0].length;
+ tail = inputText.slice(startIndex, match.index);
+ } else {
+ tail = inputText.slice(prevMatch.index + prevMatch[0].length);
+ }
+ if (tail) {
+ parts.push(tail);
+ }
+ }
+
+ // Insert in reverse order as splice does insert-before and this way we get the final order correct
+ // remove the old element at the same time
+ output.splice(outputIndex, 1, ...parts);
+
+ if (head !== "") {
+ // Don't push empty nodes, they are of no use
+ output.splice(outputIndex, 0, head);
+ }
+ }
+ if (!matchFoundSomewhere) {
+ if (
+ // The current regexp did not match anything in the input. Missing
+ // matches is entirely possible because you might choose to show some
+ // variables only in the case of e.g. plurals. It's still a bit
+ // suspicious, and could be due to an error, so log it. However, not
+ // showing count is so common that it's not worth logging. And other
+ // commonly unused variables here, if there are any.
+ regexpString !== "%\\(count\\)s" &&
+ // Ignore the `locale` option which can be used to override the locale
+ // in counterpart
+ regexpString !== "%\\(locale\\)s"
+ ) {
+ console.log(`Could not find ${regexp} in ${text}`);
+ }
+ }
+ }
+
+ if (shouldWrapInSpan) {
+ return React.createElement("span", null, ...(output as Array));
+ } else {
+ // eslint-disable-next-line @typescript-eslint/no-base-to-string
+ return output.join("");
+ }
+}
+
+type Languages = {
+ [lang: string]: string;
+};
+
+/**
+ * Sets the language for the application.
+ * In Element web,`languageHandler.setLanguage` should be used instead.
+ * @param language
+ */
+export async function setLanguage(language: string): Promise {
+ const availableLanguages = await getLangsJson();
+ const chosenLanguage = language in availableLanguages ? language : "en";
+
+ const languageData = await getLanguage(i18nFolder + availableLanguages[chosenLanguage]);
+
+ counterpart.registerTranslations(chosenLanguage, languageData);
+ counterpart.setLocale(chosenLanguage);
+}
+
+interface ICounterpartTranslation {
+ [key: string]:
+ | string
+ | {
+ [pluralisation: string]: string;
+ };
+}
+
+async function getLanguage(langPath: string): Promise {
+ console.log("Loading language from", langPath);
+ const res = await fetch(langPath, { method: "GET" });
+
+ if (!res.ok) {
+ throw new Error(`Failed to load ${langPath}, got ${res.status}`);
+ }
+
+ return res.json();
+}
+
+export async function getLangsJson(): Promise {
+ let url: string;
+ if (typeof webpackLangJsonUrl === "string") {
+ // in Jest this 'url' isn't a URL, so just fall through
+ url = webpackLangJsonUrl;
+ } else {
+ url = i18nFolder + "languages.json";
+ }
+
+ const res = await fetch(url, { method: "GET" });
+
+ if (!res.ok) {
+ throw new Error(`Failed to load ${url}, got ${res.status}`);
+ }
+
+ return res.json();
+}
diff --git a/yarn.lock b/yarn.lock
index f56f522159..cd4bb55b3f 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -3015,7 +3015,16 @@
resolved "https://registry.yarnpkg.com/@radix-ui/rect/-/rect-1.1.0.tgz#f817d1d3265ac5415dadc67edab30ae196696438"
integrity sha512-A9+lCBZoaMJlVKcRBz2YByCG+Cp2t6nAnMnNba+XiWxnj6r4JUFqfsgwocMBZU9LPtdxC6wB56ySYpc7LQIoJg==
-"@rollup/pluginutils@^5.0.2":
+"@rollup/plugin-inject@^5.0.5":
+ version "5.0.5"
+ resolved "https://registry.yarnpkg.com/@rollup/plugin-inject/-/plugin-inject-5.0.5.tgz#616f3a73fe075765f91c5bec90176608bed277a3"
+ integrity sha512-2+DEJbNBoPROPkgTDNe8/1YXWcqxbN5DTjASVIOx8HS+pITXushyNiBV56RB08zuptzz8gT3YfkqriTBVycepg==
+ dependencies:
+ "@rollup/pluginutils" "^5.0.1"
+ estree-walker "^2.0.2"
+ magic-string "^0.30.3"
+
+"@rollup/pluginutils@^5.0.1", "@rollup/pluginutils@^5.0.2":
version "5.2.0"
resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-5.2.0.tgz#eac25ca5b0bdda4ba735ddaca5fbf26bd435f602"
integrity sha512-qWJ2ZTbmumwiLFomfzTyt5Kng4hwPi9rwCYN4SHb6eaRU1KNO4ccxINHr/VhH4GgPlt1XfSTLX2LBTme8ne4Zw==
@@ -3345,7 +3354,7 @@
resolved "https://registry.yarnpkg.com/@storybook/global/-/global-5.0.0.tgz#b793d34b94f572c1d7d9e0f44fac4e0dbc9572ed"
integrity sha512-FcOqPAXACP0I3oJ/ws6/rrPT9WGhu915Cg8D02a9YxLo0DE9zI+a9A5gRGvmQ09fiWPukqI8ZAEoQEdWUKMQdQ==
-"@storybook/icons@^1.2.12":
+"@storybook/icons@^1.2.12", "@storybook/icons@^1.4.0":
version "1.4.0"
resolved "https://registry.yarnpkg.com/@storybook/icons/-/icons-1.4.0.tgz#7cf7ab3dfb41943930954c4ef493a73798d8b31d"
integrity sha512-Td73IeJxOyalzvjQL+JXx72jlIYHgs+REaHiREOqfpo3A2AYYG71AUbcv+lg7mEDIweKVCxsMQ0UKo634c8XeA==
@@ -4540,7 +4549,7 @@
classnames "^2.5.1"
vaul "^1.0.0"
-"@vector-im/matrix-wysiwyg-wasm@link:../../Library/Caches/Yarn/v6/npm-@vector-im-matrix-wysiwyg-2.38.4-fb0001dea01010a1e3ffc7042596e2d001ce9389-integrity/node_modules/bindings/wysiwyg-wasm":
+"@vector-im/matrix-wysiwyg-wasm@link:../../../../Library/Caches/Yarn/v6/npm-@vector-im-matrix-wysiwyg-2.38.4-fb0001dea01010a1e3ffc7042596e2d001ce9389-integrity/node_modules/bindings/wysiwyg-wasm":
version "0.0.0"
uid ""
@@ -4549,7 +4558,7 @@
resolved "https://registry.yarnpkg.com/@vector-im/matrix-wysiwyg/-/matrix-wysiwyg-2.38.4.tgz#fb0001dea01010a1e3ffc7042596e2d001ce9389"
integrity sha512-X6ky+1cf33SPdEVd6iTmOKfZZ2mDJv9cz3sHtDhuclS6uitK3QE8td/pmGqBj4ek2Ia4y0mnU61LfxvMry1SMA==
dependencies:
- "@vector-im/matrix-wysiwyg-wasm" "link:../../../.cache/yarn/v6/npm-@vector-im-matrix-wysiwyg-2.38.4-fb0001dea01010a1e3ffc7042596e2d001ce9389-integrity/node_modules/bindings/wysiwyg-wasm"
+ "@vector-im/matrix-wysiwyg-wasm" "link:../../../../Library/Caches/Yarn/v6/npm-@vector-im-matrix-wysiwyg-2.38.4-fb0001dea01010a1e3ffc7042596e2d001ce9389-integrity/node_modules/bindings/wysiwyg-wasm"
"@vitest/expect@3.0.9":
version "3.0.9"
@@ -5132,6 +5141,15 @@ arraybuffer.prototype.slice@^1.0.4:
get-intrinsic "^1.2.6"
is-array-buffer "^3.0.4"
+asn1.js@^4.10.1:
+ version "4.10.1"
+ resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-4.10.1.tgz#b9c2bf5805f1e64aadeed6df3a2bfafb5a73f5a0"
+ integrity sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==
+ dependencies:
+ bn.js "^4.0.0"
+ inherits "^2.0.1"
+ minimalistic-assert "^1.0.0"
+
asn1@^0.2.6:
version "0.2.6"
resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.6.tgz#0d3a7bb6e64e02a90c0303b31f292868ea09a08d"
@@ -5148,6 +5166,17 @@ asn1js@^3.0.5:
pvutils "^1.1.3"
tslib "^2.4.0"
+assert@^2.0.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/assert/-/assert-2.1.0.tgz#6d92a238d05dc02e7427c881fb8be81c8448b2dd"
+ integrity sha512-eLHpSK/Y4nhMJ07gDaAzoX/XAKS8PSaojml3M0DM4JpV1LAi5JOJ/p6H/XWrl8L+DzVEvVCW1z3vWAaB9oTsQw==
+ dependencies:
+ call-bind "^1.0.2"
+ is-nan "^1.3.2"
+ object-is "^1.1.5"
+ object.assign "^4.1.4"
+ util "^0.12.5"
+
assertion-error@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-2.0.1.tgz#f641a196b335690b1070bf00b6e7593fec190bf7"
@@ -5476,6 +5505,16 @@ blurhash@^2.0.3:
resolved "https://registry.yarnpkg.com/blurhash/-/blurhash-2.0.5.tgz#efde729fc14a2f03571a6aa91b49cba80d1abe4b"
integrity sha512-cRygWd7kGBQO3VEhPiTgq4Wc43ctsM+o46urrmPOiuAe+07fzlSB9OJVdpgDL0jPqXUVQ9ht7aq7kxOeJHRK+w==
+bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.11.9:
+ version "4.12.2"
+ resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.2.tgz#3d8fed6796c24e177737f7cc5172ee04ef39ec99"
+ integrity sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==
+
+bn.js@^5.2.1:
+ version "5.2.2"
+ resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.2.tgz#82c09f9ebbb17107cd72cb7fd39bd1f9d0aaa566"
+ integrity sha512-v2YAxEmKaBLahNwE1mjp4WON6huMNeuDvagFZW+ASCuA/ku0bXR9hSMw0XpiqMoA3+rmnyck/tPRSFQkoC9Cuw==
+
body-parser@1.20.3:
version "1.20.3"
resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.3.tgz#1953431221c6fb5cd63c4b36d53fab0928e548c6"
@@ -5544,6 +5583,81 @@ braces@^3.0.3, braces@~3.0.2:
dependencies:
fill-range "^7.1.1"
+brorand@^1.0.1, brorand@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f"
+ integrity sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==
+
+browser-resolve@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/browser-resolve/-/browser-resolve-2.0.0.tgz#99b7304cb392f8d73dba741bb2d7da28c6d7842b"
+ integrity sha512-7sWsQlYL2rGLy2IWm8WL8DCTJvYLc/qlOnsakDac87SOoCd16WLsaAMdCiAqsTNHIe+SXfaqyxyo6THoWqs8WQ==
+ dependencies:
+ resolve "^1.17.0"
+
+browserify-aes@^1.0.4, browserify-aes@^1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.2.0.tgz#326734642f403dabc3003209853bb70ad428ef48"
+ integrity sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==
+ dependencies:
+ buffer-xor "^1.0.3"
+ cipher-base "^1.0.0"
+ create-hash "^1.1.0"
+ evp_bytestokey "^1.0.3"
+ inherits "^2.0.1"
+ safe-buffer "^5.0.1"
+
+browserify-cipher@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/browserify-cipher/-/browserify-cipher-1.0.1.tgz#8d6474c1b870bfdabcd3bcfcc1934a10e94f15f0"
+ integrity sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==
+ dependencies:
+ browserify-aes "^1.0.4"
+ browserify-des "^1.0.0"
+ evp_bytestokey "^1.0.0"
+
+browserify-des@^1.0.0:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/browserify-des/-/browserify-des-1.0.2.tgz#3af4f1f59839403572f1c66204375f7a7f703e9c"
+ integrity sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==
+ dependencies:
+ cipher-base "^1.0.1"
+ des.js "^1.0.0"
+ inherits "^2.0.1"
+ safe-buffer "^5.1.2"
+
+browserify-rsa@^4.0.0, browserify-rsa@^4.1.0:
+ version "4.1.1"
+ resolved "https://registry.yarnpkg.com/browserify-rsa/-/browserify-rsa-4.1.1.tgz#06e530907fe2949dc21fc3c2e2302e10b1437238"
+ integrity sha512-YBjSAiTqM04ZVei6sXighu679a3SqWORA3qZTEqZImnlkDIFtKc6pNutpjyZ8RJTjQtuYfeetkxM11GwoYXMIQ==
+ dependencies:
+ bn.js "^5.2.1"
+ randombytes "^2.1.0"
+ safe-buffer "^5.2.1"
+
+browserify-sign@^4.2.3:
+ version "4.2.3"
+ resolved "https://registry.yarnpkg.com/browserify-sign/-/browserify-sign-4.2.3.tgz#7afe4c01ec7ee59a89a558a4b75bd85ae62d4208"
+ integrity sha512-JWCZW6SKhfhjJxO8Tyiiy+XYB7cqd2S5/+WeYHsKdNKFlCBhKbblba1A/HN/90YwtxKc8tCErjffZl++UNmGiw==
+ dependencies:
+ bn.js "^5.2.1"
+ browserify-rsa "^4.1.0"
+ create-hash "^1.2.0"
+ create-hmac "^1.1.7"
+ elliptic "^6.5.5"
+ hash-base "~3.0"
+ inherits "^2.0.4"
+ parse-asn1 "^5.1.7"
+ readable-stream "^2.3.8"
+ safe-buffer "^5.2.1"
+
+browserify-zlib@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/browserify-zlib/-/browserify-zlib-0.2.0.tgz#2869459d9aa3be245fe8fe2ca1f46e2e7f54d73f"
+ integrity sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==
+ dependencies:
+ pako "~1.0.5"
+
browserslist@^4.0.0, browserslist@^4.23.1, browserslist@^4.23.2, browserslist@^4.23.3, browserslist@^4.24.3:
version "4.25.0"
resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.25.0.tgz#986aa9c6d87916885da2b50d8eb577ac8d133b2c"
@@ -5588,7 +5702,12 @@ buffer-from@^1.0.0:
resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5"
integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==
-buffer@^5.5.0:
+buffer-xor@^1.0.3:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9"
+ integrity sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==
+
+buffer@^5.5.0, buffer@^5.7.1:
version "5.7.1"
resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0"
integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==
@@ -5614,6 +5733,11 @@ builtin-modules@^3.3.0:
resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-3.3.0.tgz#cae62812b89801e9656336e46223e030386be7b6"
integrity sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==
+builtin-status-codes@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8"
+ integrity sha512-HpGFw18DgFWlncDfjTa2rcQ4W88O1mC8e8yZ2AvQY5KDaktSTwo+KRf6nHK6FRI5FyRyb/5T6+TSxfP7QyGsmQ==
+
bundle-name@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/bundle-name/-/bundle-name-4.1.0.tgz#f3b96b34160d6431a19d7688135af7cfb8797889"
@@ -5665,7 +5789,7 @@ call-bind-apply-helpers@^1.0.1, call-bind-apply-helpers@^1.0.2:
es-errors "^1.3.0"
function-bind "^1.1.2"
-call-bind@^1.0.2, call-bind@^1.0.7, call-bind@^1.0.8:
+call-bind@^1.0.0, call-bind@^1.0.2, call-bind@^1.0.7, call-bind@^1.0.8:
version "1.0.8"
resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.8.tgz#0736a9660f537e3388826f440d5ec45f744eaa4c"
integrity sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==
@@ -5837,6 +5961,14 @@ ci-info@^4.0.0:
resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-4.1.0.tgz#92319d2fa29d2620180ea5afed31f589bc98cf83"
integrity sha512-HutrvTNsF48wnxkzERIXOe5/mlcfFcbfCmwcg6CJnizbSue78AbDt+1cgl26zwn61WFxhcPykPfZrbqjGmBb4A==
+cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3:
+ version "1.0.6"
+ resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.6.tgz#8fe672437d01cd6c4561af5334e0cc50ff1955f7"
+ integrity sha512-3Ek9H3X6pj5TgenXYtNWdaBon1tgYCaebd+XPg0keyjEbEfkD4KkmAxkQ/i1vYvxdcT5nscLBfq9VJRmCBcFSw==
+ dependencies:
+ inherits "^2.0.4"
+ safe-buffer "^5.2.1"
+
cjs-module-lexer@^1.0.0:
version "1.4.1"
resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.4.1.tgz#707413784dbb3a72aa11c2f2b042a0bef4004170"
@@ -6062,6 +6194,16 @@ connect-history-api-fallback@^2.0.0:
resolved "https://registry.yarnpkg.com/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz#647264845251a0daf25b97ce87834cace0f5f1c8"
integrity sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==
+console-browserify@^1.1.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.2.0.tgz#67063cef57ceb6cf4993a2ab3a55840ae8c49336"
+ integrity sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==
+
+constants-browserify@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75"
+ integrity sha512-xFxOwqIzR/e1k1gLiWEophSCMqXcwVHIH7akf7b/vxcUeGunlj3hvZaaqxwHsTgn+IndtkQJgSztIDWeumWJDQ==
+
content-disposition@0.5.4:
version "0.5.4"
resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.4.tgz#8b82b4efac82512a02bb0b1dcec9d2c5e8eb5bfe"
@@ -6203,6 +6345,47 @@ crc32-stream@^6.0.0:
crc-32 "^1.2.0"
readable-stream "^4.0.0"
+create-ecdh@^4.0.4:
+ version "4.0.4"
+ resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.4.tgz#d6e7f4bffa66736085a0762fd3a632684dabcc4e"
+ integrity sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==
+ dependencies:
+ bn.js "^4.1.0"
+ elliptic "^6.5.3"
+
+create-hash@^1.1.0, create-hash@^1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.2.0.tgz#889078af11a63756bcfb59bd221996be3a9ef196"
+ integrity sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==
+ dependencies:
+ cipher-base "^1.0.1"
+ inherits "^2.0.1"
+ md5.js "^1.3.4"
+ ripemd160 "^2.0.1"
+ sha.js "^2.4.0"
+
+create-hash@~1.1.3:
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.1.3.tgz#606042ac8b9262750f483caddab0f5819172d8fd"
+ integrity sha512-snRpch/kwQhcdlnZKYanNF1m0RDlrCdSKQaH87w1FCFPVPNCQ/Il9QJKAX2jVBZddRdaHBMC+zXa9Gw9tmkNUA==
+ dependencies:
+ cipher-base "^1.0.1"
+ inherits "^2.0.1"
+ ripemd160 "^2.0.0"
+ sha.js "^2.4.0"
+
+create-hmac@^1.1.7:
+ version "1.1.7"
+ resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.7.tgz#69170c78b3ab957147b2b8b04572e47ead2243ff"
+ integrity sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==
+ dependencies:
+ cipher-base "^1.0.3"
+ create-hash "^1.1.0"
+ inherits "^2.0.1"
+ ripemd160 "^2.0.0"
+ safe-buffer "^5.0.1"
+ sha.js "^2.4.8"
+
create-jest@^29.7.0:
version "29.7.0"
resolved "https://registry.yarnpkg.com/create-jest/-/create-jest-29.7.0.tgz#a355c5b3cb1e1af02ba177fe7afd7feee49a5320"
@@ -6216,7 +6399,7 @@ create-jest@^29.7.0:
jest-util "^29.7.0"
prompts "^2.0.1"
-create-require@^1.1.0:
+create-require@^1.1.0, create-require@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333"
integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==
@@ -6244,6 +6427,24 @@ cross-spawn@^7.0.2:
shebang-command "^2.0.0"
which "^2.0.1"
+crypto-browserify@^3.12.1:
+ version "3.12.1"
+ resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.1.tgz#bb8921bec9acc81633379aa8f52d69b0b69e0dac"
+ integrity sha512-r4ESw/IlusD17lgQi1O20Fa3qNnsckR126TdUuBgAu7GBYSIPvdNyONd3Zrxh0xCwA4+6w/TDArBPsMvhur+KQ==
+ dependencies:
+ browserify-cipher "^1.0.1"
+ browserify-sign "^4.2.3"
+ create-ecdh "^4.0.4"
+ create-hash "^1.2.0"
+ create-hmac "^1.1.7"
+ diffie-hellman "^5.0.3"
+ hash-base "~3.0.4"
+ inherits "^2.0.4"
+ pbkdf2 "^3.1.2"
+ public-encrypt "^4.0.3"
+ randombytes "^2.1.0"
+ randomfill "^1.0.4"
+
css-blank-pseudo@^7.0.1:
version "7.0.1"
resolved "https://registry.yarnpkg.com/css-blank-pseudo/-/css-blank-pseudo-7.0.1.tgz#32020bff20a209a53ad71b8675852b49e8d57e46"
@@ -6659,6 +6860,14 @@ dequal@^2.0.3:
resolved "https://registry.yarnpkg.com/dequal/-/dequal-2.0.3.tgz#2644214f1997d39ed0ee0ece72335490a7ac67be"
integrity sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==
+des.js@^1.0.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.1.0.tgz#1d37f5766f3bbff4ee9638e871a8768c173b81da"
+ integrity sha512-r17GxjhUCjSRy8aiJpr8/UadFIzMzJGexI3Nmz4ADi9LYSFx4gTBp80+NaX/YsXWWLhpZ7v/v/ubEc/bCNfKwg==
+ dependencies:
+ inherits "^2.0.1"
+ minimalistic-assert "^1.0.0"
+
destroy@1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015"
@@ -6706,6 +6915,15 @@ diffable-html@^4.1.0:
dependencies:
htmlparser2 "^3.9.2"
+diffie-hellman@^5.0.3:
+ version "5.0.3"
+ resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.3.tgz#40e8ee98f55a2149607146921c63e1ae5f3d2875"
+ integrity sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==
+ dependencies:
+ bn.js "^4.1.0"
+ miller-rabin "^4.0.0"
+ randombytes "^2.0.0"
+
dijkstrajs@^1.0.1:
version "1.0.3"
resolved "https://registry.yarnpkg.com/dijkstrajs/-/dijkstrajs-1.0.3.tgz#4c8dbdea1f0f6478bff94d9c49c784d623e4fc23"
@@ -6820,6 +7038,11 @@ dom-serializer@^2.0.0:
domhandler "^5.0.2"
entities "^4.2.0"
+domain-browser@4.22.0:
+ version "4.22.0"
+ resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-4.22.0.tgz#6ddd34220ec281f9a65d3386d267ddd35c491f9f"
+ integrity sha512-IGBwjF7tNk3cwypFNH/7bfzBcgSCbaMOD3GsaY1AU/JRrnHnYgEM0+9kQt52iZxjNsjBtJYtao146V+f8jFZNw==
+
domelementtype@1, domelementtype@^1.3.1:
version "1.3.1"
resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.3.1.tgz#d048c44b37b0d10a7f2a3d5fee3f4333d790481f"
@@ -6943,6 +7166,19 @@ electron-to-chromium@^1.5.160, electron-to-chromium@^1.5.173:
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.180.tgz#3e4f6e7494d6371e014af176dfdfd43c8a4b56df"
integrity sha512-ED+GEyEh3kYMwt2faNmgMB0b8O5qtATGgR4RmRsIp4T6p7B8vdMbIedYndnvZfsaXvSzegtpfqRMDNCjjiSduA==
+elliptic@^6.5.3, elliptic@^6.5.5:
+ version "6.6.1"
+ resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.6.1.tgz#3b8ffb02670bf69e382c7f65bf524c97c5405c06"
+ integrity sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g==
+ dependencies:
+ bn.js "^4.11.9"
+ brorand "^1.1.0"
+ hash.js "^1.0.0"
+ hmac-drbg "^1.0.1"
+ inherits "^2.0.4"
+ minimalistic-assert "^1.0.1"
+ minimalistic-crypto-utils "^1.0.1"
+
emittery@^0.13.1:
version "0.13.1"
resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.13.1.tgz#c04b8c3457490e0847ae51fced3af52d338e3dad"
@@ -7577,11 +7813,19 @@ eventemitter3@^5.0.1:
resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-5.0.1.tgz#53f5ffd0a492ac800721bb42c66b841de96423c4"
integrity sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==
-events@^3.2.0, events@^3.3.0:
+events@^3.0.0, events@^3.2.0, events@^3.3.0:
version "3.3.0"
resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400"
integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==
+evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz#7fcbdb198dc71959432efe13842684e0525acb02"
+ integrity sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==
+ dependencies:
+ md5.js "^1.3.4"
+ safe-buffer "^5.1.1"
+
except@^0.1.3:
version "0.1.3"
resolved "https://registry.yarnpkg.com/except/-/except-0.1.3.tgz#98261c91958551536b44482238e9783fb73d292a"
@@ -8477,6 +8721,38 @@ has-tostringtag@^1.0.0, has-tostringtag@^1.0.2:
dependencies:
has-symbols "^1.0.3"
+hash-base@^2.0.0:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-2.0.2.tgz#66ea1d856db4e8a5470cadf6fce23ae5244ef2e1"
+ integrity sha512-0TROgQ1/SxE6KmxWSvXHvRj90/Xo1JvZShofnYF+f6ZsGtR4eES7WfrQzPalmyagfKZCXpVnitiRebZulWsbiw==
+ dependencies:
+ inherits "^2.0.1"
+
+hash-base@^3.0.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.1.0.tgz#55c381d9e06e1d2997a883b4a3fddfe7f0d3af33"
+ integrity sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==
+ dependencies:
+ inherits "^2.0.4"
+ readable-stream "^3.6.0"
+ safe-buffer "^5.2.0"
+
+hash-base@~3.0, hash-base@~3.0.4:
+ version "3.0.5"
+ resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.0.5.tgz#52480e285395cf7fba17dc4c9e47acdc7f248a8a"
+ integrity sha512-vXm0l45VbcHEVlTCzs8M+s0VeYsB2lnlAaThoLKGXr3bE/VWDOelNUnycUPEhKEaXARL2TEFjBOyUiM6+55KBg==
+ dependencies:
+ inherits "^2.0.4"
+ safe-buffer "^5.2.1"
+
+hash.js@^1.0.0, hash.js@^1.0.3:
+ version "1.1.7"
+ resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42"
+ integrity sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==
+ dependencies:
+ inherits "^2.0.3"
+ minimalistic-assert "^1.0.1"
+
hasha@^5.0.0:
version "5.2.2"
resolved "https://registry.yarnpkg.com/hasha/-/hasha-5.2.2.tgz#a48477989b3b327aea3c04f53096d816d97522a1"
@@ -8514,6 +8790,15 @@ highlight.js@^11.3.1:
resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-11.11.1.tgz#fca06fa0e5aeecf6c4d437239135fabc15213585"
integrity sha512-Xwwo44whKBVCYoliBQwaPvtd/2tYFkRQtXDWj1nackaV2JPXx3L0+Jvd8/qCJ2p+ML0/XVkJ2q+Mr+UVdpJK5w==
+hmac-drbg@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1"
+ integrity sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==
+ dependencies:
+ hash.js "^1.0.3"
+ minimalistic-assert "^1.0.0"
+ minimalistic-crypto-utils "^1.0.1"
+
hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.2:
version "3.3.2"
resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45"
@@ -8714,6 +8999,11 @@ http-proxy@^1.18.1:
follow-redirects "^1.0.0"
requires-port "^1.0.0"
+https-browserify@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73"
+ integrity sha512-J+FkSdyD+0mA0N+81tMotaRMfSL9SGi+xpD3T6YApKsc3bGSXJlfXri3VyFOeYkfLRQisDk1W+jIFFKBeUBbBg==
+
https-proxy-agent@^5.0.0, https-proxy-agent@^5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz#c59ef224a04fe8b754f3db0063a25ea30d0005d6"
@@ -8823,7 +9113,7 @@ inflight@^1.0.4:
once "^1.3.0"
wrappy "1"
-inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.3:
+inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.3, inherits@~2.0.4:
version "2.0.4"
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
@@ -9074,6 +9364,14 @@ is-map@^2.0.3:
resolved "https://registry.yarnpkg.com/is-map/-/is-map-2.0.3.tgz#ede96b7fe1e270b3c4465e3a465658764926d62e"
integrity sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==
+is-nan@^1.3.2:
+ version "1.3.2"
+ resolved "https://registry.yarnpkg.com/is-nan/-/is-nan-1.3.2.tgz#043a54adea31748b55b6cd4e09aadafa69bd9e1d"
+ integrity sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w==
+ dependencies:
+ call-bind "^1.0.0"
+ define-properties "^1.1.3"
+
is-network-error@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/is-network-error/-/is-network-error-1.1.0.tgz#d26a760e3770226d11c169052f266a4803d9c997"
@@ -9261,6 +9559,11 @@ isobject@^3.0.1:
resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df"
integrity sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==
+isomorphic-timers-promises@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/isomorphic-timers-promises/-/isomorphic-timers-promises-1.0.1.tgz#e4137c24dbc54892de8abae3a4b5c1ffff381598"
+ integrity sha512-u4sej9B1LPSxTGKB/HiuzvEQnXH0ECYkSVQU39koSwmFAxhlEAFl9RdTvLv4TOTQUgBS5O3O5fwUxk6byBZ+IQ==
+
istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.0:
version "3.2.2"
resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz#2d166c4b0644d43a39f04bf6c2edd1e585f31756"
@@ -10421,7 +10724,7 @@ magic-string@0.30.8:
dependencies:
"@jridgewell/sourcemap-codec" "^1.4.15"
-magic-string@^0.30.0:
+magic-string@^0.30.0, magic-string@^0.30.3:
version "0.30.17"
resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.30.17.tgz#450a449673d2460e5bbcfba9a61916a1714c7453"
integrity sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==
@@ -10562,6 +10865,15 @@ matrix-widget-api@^1.10.0:
"@types/events" "^3.0.0"
events "^3.2.0"
+md5.js@^1.3.4:
+ version "1.3.5"
+ resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f"
+ integrity sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==
+ dependencies:
+ hash-base "^3.0.0"
+ inherits "^2.0.1"
+ safe-buffer "^5.1.2"
+
mdn-data@2.0.28:
version "2.0.28"
resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.28.tgz#5ec48e7bef120654539069e1ae4ddc81ca490eba"
@@ -10655,6 +10967,14 @@ micromatch@^4.0.2, micromatch@^4.0.4, micromatch@^4.0.8:
braces "^3.0.3"
picomatch "^2.3.1"
+miller-rabin@^4.0.0:
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.1.tgz#f080351c865b0dc562a8462966daa53543c78a4d"
+ integrity sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==
+ dependencies:
+ bn.js "^4.0.0"
+ brorand "^1.0.1"
+
mime-db@1.52.0:
version "1.52.0"
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70"
@@ -10712,11 +11032,16 @@ mini-css-extract-plugin@2.9.2:
schema-utils "^4.0.0"
tapable "^2.2.1"
-minimalistic-assert@^1.0.0:
+minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7"
integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==
+minimalistic-crypto-utils@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a"
+ integrity sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==
+
minimatch@^10.0.0:
version "10.0.1"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-10.0.1.tgz#ce0521856b453c86e25f2c4c0d03e6ff7ddc440b"
@@ -10921,6 +11246,39 @@ node-releases@^2.0.19:
resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.19.tgz#9e445a52950951ec4d177d843af370b411caf314"
integrity sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==
+node-stdlib-browser@^1.2.0:
+ version "1.3.1"
+ resolved "https://registry.yarnpkg.com/node-stdlib-browser/-/node-stdlib-browser-1.3.1.tgz#f41fa554f720a3df951e40339f4d92ac512222ac"
+ integrity sha512-X75ZN8DCLftGM5iKwoYLA3rjnrAEs97MkzvSd4q2746Tgpg8b8XWiBGiBG4ZpgcAqBgtgPHTiAc8ZMCvZuikDw==
+ dependencies:
+ assert "^2.0.0"
+ browser-resolve "^2.0.0"
+ browserify-zlib "^0.2.0"
+ buffer "^5.7.1"
+ console-browserify "^1.1.0"
+ constants-browserify "^1.0.0"
+ create-require "^1.1.1"
+ crypto-browserify "^3.12.1"
+ domain-browser "4.22.0"
+ events "^3.0.0"
+ https-browserify "^1.0.0"
+ isomorphic-timers-promises "^1.0.1"
+ os-browserify "^0.3.0"
+ path-browserify "^1.0.1"
+ pkg-dir "^5.0.0"
+ process "^0.11.10"
+ punycode "^1.4.1"
+ querystring-es3 "^0.2.1"
+ readable-stream "^3.6.0"
+ stream-browserify "^3.0.0"
+ stream-http "^3.2.0"
+ string_decoder "^1.0.0"
+ timers-browserify "^2.0.4"
+ tty-browserify "0.0.1"
+ url "^0.11.4"
+ util "^0.12.4"
+ vm-browserify "^1.0.1"
+
normalize-package-data@^2.5.0:
version "2.5.0"
resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8"
@@ -11003,6 +11361,14 @@ object-inspect@^1.13.3:
resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.4.tgz#8375265e21bc20d0fa582c22e1b13485d6e00213"
integrity sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==
+object-is@^1.1.5:
+ version "1.1.6"
+ resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.1.6.tgz#1a6a53aed2dd8f7e6775ff870bea58545956ab07"
+ integrity sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==
+ dependencies:
+ call-bind "^1.0.7"
+ define-properties "^1.2.1"
+
object-keys@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e"
@@ -11161,6 +11527,11 @@ opus-recorder@^8.0.3:
resolved "https://registry.yarnpkg.com/opus-recorder/-/opus-recorder-8.0.5.tgz#06d3e32e15da57ebc3f57e41b93033475fcb4e3e"
integrity sha512-tBRXc9Btds7i3bVfA7d5rekAlyOcfsivt5vSIXHxRV1Oa+s6iXFW8omZ0Lm3ABWotVcEyKt96iIIUcgbV07YOw==
+os-browserify@^0.3.0:
+ version "0.3.0"
+ resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.3.0.tgz#854373c7f5c2315914fc9bfc6bd8238fdda1ec27"
+ integrity sha512-gjcpUc3clBf9+210TRaDWbf+rZZZEshZ+DlXMRCeAjp0xhTrnQsKHypIy1J3d5hKdUzj69t708EHtU8P6bUn0A==
+
os-homedir@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3"
@@ -11290,7 +11661,7 @@ pako@^2.0.3:
resolved "https://registry.yarnpkg.com/pako/-/pako-2.1.0.tgz#266cc37f98c7d883545d11335c00fbd4062c9a86"
integrity sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==
-pako@~1.0.2:
+pako@~1.0.2, pako@~1.0.5:
version "1.0.11"
resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf"
integrity sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==
@@ -11310,6 +11681,18 @@ parent-module@^1.0.0:
dependencies:
callsites "^3.0.0"
+parse-asn1@^5.0.0, parse-asn1@^5.1.7:
+ version "5.1.7"
+ resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.7.tgz#73cdaaa822125f9647165625eb45f8a051d2df06"
+ integrity sha512-CTM5kuWR3sx9IFamcl5ErfPl6ea/N8IYwiJ+vpeB2g+1iknv7zBl5uPwbMbRVznRVbrNY6lGuDoE5b30grmbqg==
+ dependencies:
+ asn1.js "^4.10.1"
+ browserify-aes "^1.2.0"
+ evp_bytestokey "^1.0.3"
+ hash-base "~3.0"
+ pbkdf2 "^3.1.2"
+ safe-buffer "^5.2.1"
+
parse-json@^5.0.0, parse-json@^5.2.0:
version "5.2.0"
resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd"
@@ -11371,6 +11754,11 @@ patch-package@^8.0.0:
tmp "^0.0.33"
yaml "^2.2.2"
+path-browserify@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-1.0.1.tgz#d98454a9c3753d5790860f16f68867b9e46be1fd"
+ integrity sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==
+
path-exists@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3"
@@ -11445,6 +11833,18 @@ pbf@^3.2.1, pbf@^3.3.0:
ieee754 "^1.1.12"
resolve-protobuf-schema "^2.1.0"
+pbkdf2@^3.1.2:
+ version "3.1.3"
+ resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.1.3.tgz#8be674d591d65658113424592a95d1517318dd4b"
+ integrity sha512-wfRLBZ0feWRhCIkoMB6ete7czJcnNnqRpcoWQBLqatqXXmelSRqfdDK4F3u9T2s2cXas/hQJcryI/4lAL+XTlA==
+ dependencies:
+ create-hash "~1.1.3"
+ create-hmac "^1.1.7"
+ ripemd160 "=2.0.1"
+ safe-buffer "^5.2.1"
+ sha.js "^2.4.11"
+ to-buffer "^1.2.0"
+
picocolors@^1.0.0, picocolors@^1.0.1, picocolors@^1.1.0, picocolors@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b"
@@ -11489,6 +11889,13 @@ pkg-dir@^4.1.0, pkg-dir@^4.2.0:
dependencies:
find-up "^4.0.0"
+pkg-dir@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-5.0.0.tgz#a02d6aebe6ba133a928f74aec20bafdfe6b8e760"
+ integrity sha512-NPE8TDbzl/3YQYY7CSS228s3g2ollTFnc+Qi3tqmqJp9Vg2ovUpixcJEo2HJScN2Ez+kEaal6y70c0ehqJBJeA==
+ dependencies:
+ find-up "^5.0.0"
+
playwright-core@1.53.2, playwright-core@>=1.2.0, playwright-core@^1.51.0:
version "1.53.2"
resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.53.2.tgz#78f71e2f727713daa8d360dc11c460022c13cf91"
@@ -12329,6 +12736,18 @@ psl@^1.1.33:
resolved "https://registry.yarnpkg.com/psl/-/psl-1.9.0.tgz#d0df2a137f00794565fcaf3b2c00cd09f8d5a5a7"
integrity sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==
+public-encrypt@^4.0.3:
+ version "4.0.3"
+ resolved "https://registry.yarnpkg.com/public-encrypt/-/public-encrypt-4.0.3.tgz#4fcc9d77a07e48ba7527e7cbe0de33d0701331e0"
+ integrity sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==
+ dependencies:
+ bn.js "^4.1.0"
+ browserify-rsa "^4.0.0"
+ create-hash "^1.1.0"
+ parse-asn1 "^5.0.0"
+ randombytes "^2.0.1"
+ safe-buffer "^5.1.2"
+
pump@^3.0.0:
version "3.0.3"
resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.3.tgz#151d979f1a29668dc0025ec589a455b53282268d"
@@ -12337,6 +12756,11 @@ pump@^3.0.0:
end-of-stream "^1.1.0"
once "^1.3.1"
+punycode@^1.4.1:
+ version "1.4.1"
+ resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e"
+ integrity sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==
+
punycode@^2.1.0, punycode@^2.1.1:
version "2.3.1"
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5"
@@ -12375,13 +12799,18 @@ qs@6.13.0:
dependencies:
side-channel "^1.0.6"
-qs@^6.14.0:
+qs@^6.12.3, qs@^6.14.0:
version "6.14.0"
resolved "https://registry.yarnpkg.com/qs/-/qs-6.14.0.tgz#c63fa40680d2c5c941412a0e899c89af60c0a930"
integrity sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==
dependencies:
side-channel "^1.1.0"
+querystring-es3@^0.2.1:
+ version "0.2.1"
+ resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73"
+ integrity sha512-773xhDQnZBMFobEiztv8LIl70ch5MSF/jUQVlhwFyBILqq96anmoctVIYz+ZRp0qbCKATTn6ev02M3r7Ga5vqA==
+
querystring@^0.2.0:
version "0.2.1"
resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.1.tgz#40d77615bb09d16902a85c3e38aa8b5ed761c2dd"
@@ -12407,13 +12836,21 @@ raf-schd@^4.0.2:
resolved "https://registry.yarnpkg.com/raf-schd/-/raf-schd-4.0.3.tgz#5d6c34ef46f8b2a0e880a8fcdb743efc5bfdbc1a"
integrity sha512-tQkJl2GRWh83ui2DiPTJz9wEiMN20syf+5oKfB03yYP7ioZcJwsIK8FjrtLwH1m7C7e+Tt2yYBlrOpdT+dyeIQ==
-randombytes@^2.1.0:
+randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5, randombytes@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a"
integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==
dependencies:
safe-buffer "^5.1.0"
+randomfill@^1.0.4:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/randomfill/-/randomfill-1.0.4.tgz#c92196fc86ab42be983f1bf31778224931d61458"
+ integrity sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==
+ dependencies:
+ randombytes "^2.0.5"
+ safe-buffer "^5.1.0"
+
range-parser@^1.2.1, range-parser@~1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031"
@@ -12640,7 +13077,7 @@ read-pkg@^5.2.0:
parse-json "^5.0.0"
type-fest "^0.6.0"
-readable-stream@^2.0.1, readable-stream@^2.0.5, readable-stream@~2.3.6:
+readable-stream@^2.0.1, readable-stream@^2.0.5, readable-stream@^2.3.8, readable-stream@~2.3.6:
version "2.3.8"
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.8.tgz#91125e8042bba1b9887f49345f6277027ce8be9b"
integrity sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==
@@ -12653,7 +13090,7 @@ readable-stream@^2.0.1, readable-stream@^2.0.5, readable-stream@~2.3.6:
string_decoder "~1.1.1"
util-deprecate "~1.0.1"
-readable-stream@^3.0.6, readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.5.0:
+readable-stream@^3.0.6, readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.5.0, readable-stream@^3.6.0:
version "3.6.2"
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967"
integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==
@@ -12898,7 +13335,7 @@ resolve@^1.1.7, resolve@^1.10.0, resolve@^1.20.0, resolve@^1.22.4, resolve@^1.22
path-parse "^1.0.7"
supports-preserve-symlinks-flag "^1.0.0"
-resolve@^1.22.1, resolve@^1.22.10:
+resolve@^1.17.0, resolve@^1.22.1, resolve@^1.22.10:
version "1.22.10"
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.10.tgz#b663e83ffb09bbf2386944736baae803029b8b39"
integrity sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==
@@ -12971,6 +13408,22 @@ rimraf@^6.0.0:
glob "^11.0.0"
package-json-from-dist "^1.0.0"
+ripemd160@=2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.1.tgz#0f4584295c53a3628af7e6d79aca21ce57d1c6e7"
+ integrity sha512-J7f4wutN8mdbV08MJnXibYpCOPHR+yzy+iQ/AsjMv2j8cLavQ8VGagDFUwwTAdF8FmRKVeNpbTTEwNHCW1g94w==
+ dependencies:
+ hash-base "^2.0.0"
+ inherits "^2.0.1"
+
+ripemd160@^2.0.0, ripemd160@^2.0.1:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c"
+ integrity sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==
+ dependencies:
+ hash-base "^3.0.0"
+ inherits "^2.0.1"
+
rollup@^4.40.0:
version "4.44.1"
resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.44.1.tgz#641723932894e7acbe6052aea34b8e72ef8b7c8f"
@@ -13046,7 +13499,7 @@ safe-array-concat@^1.1.3:
has-symbols "^1.1.0"
isarray "^2.0.5"
-safe-buffer@5.2.1, safe-buffer@>=5.1.0, safe-buffer@^5.1.0, safe-buffer@~5.2.0:
+safe-buffer@5.2.1, safe-buffer@>=5.1.0, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@^5.2.1, safe-buffer@~5.2.0:
version "5.2.1"
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
@@ -13278,7 +13731,7 @@ set-proto@^1.0.0:
es-errors "^1.3.0"
es-object-atoms "^1.0.0"
-setimmediate@^1.0.5:
+setimmediate@^1.0.4, setimmediate@^1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285"
integrity sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==
@@ -13293,6 +13746,15 @@ setprototypeof@1.2.0:
resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424"
integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==
+sha.js@^2.4.0, sha.js@^2.4.11, sha.js@^2.4.8:
+ version "2.4.12"
+ resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.12.tgz#eb8b568bf383dfd1867a32c3f2b74eb52bdbf23f"
+ integrity sha512-8LzC5+bvI45BjpfXU8V5fdU2mfeKiQe1D1gIMn7XUlF3OTUrpdJpPPH4EMAnF0DsHHdSZqCdSss5qCmJKuiO3w==
+ dependencies:
+ inherits "^2.0.4"
+ safe-buffer "^5.2.1"
+ to-buffer "^1.2.0"
+
shallow-clone@^3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/shallow-clone/-/shallow-clone-3.0.1.tgz#8f2981ad92531f55035b01fb230769a40e02efa3"
@@ -13621,6 +14083,24 @@ storybook@^9.0.12:
semver "^7.6.2"
ws "^8.18.0"
+stream-browserify@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-3.0.0.tgz#22b0a2850cdf6503e73085da1fc7b7d0c2122f2f"
+ integrity sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==
+ dependencies:
+ inherits "~2.0.4"
+ readable-stream "^3.5.0"
+
+stream-http@^3.2.0:
+ version "3.2.0"
+ resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-3.2.0.tgz#1872dfcf24cb15752677e40e5c3f9cc1926028b5"
+ integrity sha512-Oq1bLqisTyK3TSCXpPbT4sdeYNdmyZJv1LxpEm2vu1ZhK89kSE5YXwZc3cWk0MagGaKriBh9mCFbVGtO+vY29A==
+ dependencies:
+ builtin-status-codes "^3.0.0"
+ inherits "^2.0.4"
+ readable-stream "^3.6.0"
+ xtend "^4.0.2"
+
streamx@^2.15.0, streamx@^2.21.0:
version "2.22.1"
resolved "https://registry.yarnpkg.com/streamx/-/streamx-2.22.1.tgz#c97cbb0ce18da4f4db5a971dc9ab68ff5dc7f5a5"
@@ -13756,7 +14236,7 @@ string.prototype.trimstart@^1.0.8:
define-properties "^1.2.1"
es-object-atoms "^1.0.0"
-string_decoder@^1.1.1, string_decoder@^1.3.0:
+string_decoder@^1.0.0, string_decoder@^1.1.1, string_decoder@^1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e"
integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==
@@ -14171,6 +14651,13 @@ thunky@^1.0.2:
resolved "https://registry.yarnpkg.com/thunky/-/thunky-1.1.0.tgz#5abaf714a9405db0504732bbccd2cedd9ef9537d"
integrity sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==
+timers-browserify@^2.0.4:
+ version "2.0.12"
+ resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-2.0.12.tgz#44a45c11fbf407f34f97bccd1577c652361b00ee"
+ integrity sha512-9phl76Cqm6FhSX9Xe1ZUAMLtm1BLkKj2Qd5ApyWkXzsMRaA7dgr81kf4wJmQf/hAvg8EEyJxDo3du/0KlhPiKQ==
+ dependencies:
+ setimmediate "^1.0.4"
+
tiny-invariant@^1.0.6, tiny-invariant@^1.3.3:
version "1.3.3"
resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.3.3.tgz#46680b7a873a0d5d10005995eb90a70d74d60127"
@@ -14224,6 +14711,15 @@ tmpl@1.0.5:
resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.5.tgz#8683e0b902bb9c20c4f726e3c0b69f36518c07cc"
integrity sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==
+to-buffer@^1.2.0:
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/to-buffer/-/to-buffer-1.2.1.tgz#2ce650cdb262e9112a18e65dc29dcb513c8155e0"
+ integrity sha512-tB82LpAIWjhLYbqjx3X4zEeHN6M8CiuOEy2JY8SEQVdYRe3CCHOFaqrBW1doLDrfpWhplcW7BL+bO3/6S3pcDQ==
+ dependencies:
+ isarray "^2.0.5"
+ safe-buffer "^5.2.1"
+ typed-array-buffer "^1.0.3"
+
to-fast-properties@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e"
@@ -14350,6 +14846,11 @@ tslib@^2.6.1, tslib@^2.6.2, tslib@^2.7.0:
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.0.tgz#d124c86c3c05a40a91e6fdea4021bd31d377971b"
integrity sha512-jWVzBLplnCmoaTr13V9dYbiQ99wvZRd0vNWaDRg+aVYRcjDF3nDksxFDE/+fkXnKhpnUUkmx5pK/v8mCtLVqZA==
+tty-browserify@0.0.1:
+ version "0.0.1"
+ resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.1.tgz#3f05251ee17904dfd0677546670db9651682b811"
+ integrity sha512-C3TaO7K81YvjCgQH9Q1S3R3P3BtN3RIM8n+OvX4il1K1zgE8ZhI0op7kClgkxtutIE8hQrcrHBXvIheqKUUCxw==
+
tweetnacl@^0.14.3:
version "0.14.5"
resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64"
@@ -14590,6 +15091,14 @@ url-parse@^1.5.3:
querystringify "^2.1.1"
requires-port "^1.0.0"
+url@^0.11.4:
+ version "0.11.4"
+ resolved "https://registry.yarnpkg.com/url/-/url-0.11.4.tgz#adca77b3562d56b72746e76b330b7f27b6721f3c"
+ integrity sha512-oCwdVC7mTuWiPyjLUz/COz5TLk6wgp0RCsN+wHZ2Ekneac9w8uuV0njcbbie2ME+Vs+d6duwmYuR3HgQXs1fOg==
+ dependencies:
+ punycode "^1.4.1"
+ qs "^6.12.3"
+
use-callback-ref@^1.3.0:
version "1.3.2"
resolved "https://registry.yarnpkg.com/use-callback-ref/-/use-callback-ref-1.3.2.tgz#6134c7f6ff76e2be0b56c809b17a650c942b1693"
@@ -14627,7 +15136,7 @@ util-deprecate@^1.0.1, util-deprecate@^1.0.2, util-deprecate@~1.0.1:
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==
-util@^0.12.5:
+util@^0.12.4, util@^0.12.5:
version "0.12.5"
resolved "https://registry.yarnpkg.com/util/-/util-0.12.5.tgz#5f17a6059b73db61a875668781a1c2b136bd6fbc"
integrity sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==
@@ -14702,6 +15211,14 @@ vaul@^1.0.0:
dependencies:
"@radix-ui/react-dialog" "^1.1.1"
+vite-plugin-node-polyfills@^0.24.0:
+ version "0.24.0"
+ resolved "https://registry.yarnpkg.com/vite-plugin-node-polyfills/-/vite-plugin-node-polyfills-0.24.0.tgz#4a2e984bba134017fc88cace0149cf8afdb50b54"
+ integrity sha512-GA9QKLH+vIM8NPaGA+o2t8PDfFUl32J8rUp1zQfMKVJQiNkOX4unE51tR6ppl6iKw5yOrDAdSH7r/UIFLCVhLw==
+ dependencies:
+ "@rollup/plugin-inject" "^5.0.5"
+ node-stdlib-browser "^1.2.0"
+
vite@^7.0.1:
version "7.0.1"
resolved "https://registry.yarnpkg.com/vite/-/vite-7.0.1.tgz#b7ebb1e8a7d7f0f42867a545561fb72b34b2b13f"
@@ -14716,6 +15233,11 @@ vite@^7.0.1:
optionalDependencies:
fsevents "~2.3.3"
+vm-browserify@^1.0.1:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-1.1.2.tgz#78641c488b8e6ca91a75f511e7a3b32a86e5dda0"
+ integrity sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==
+
vt-pbf@^3.1.3:
version "3.1.3"
resolved "https://registry.yarnpkg.com/vt-pbf/-/vt-pbf-3.1.3.tgz#68fd150756465e2edae1cc5c048e063916dcfaac"
@@ -15209,6 +15731,11 @@ xmlchars@^2.2.0:
resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb"
integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==
+xtend@^4.0.2:
+ version "4.0.2"
+ resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54"
+ integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==
+
xxhashjs@^0.2.2:
version "0.2.2"
resolved "https://registry.yarnpkg.com/xxhashjs/-/xxhashjs-0.2.2.tgz#8a6251567621a1c46a5ae204da0249c7f8caa9d8"