diff --git a/.changeset/twenty-tools-yell.md b/.changeset/twenty-tools-yell.md
new file mode 100644
index 00000000..36f20344
--- /dev/null
+++ b/.changeset/twenty-tools-yell.md
@@ -0,0 +1,5 @@
+---
+'@stacks/wallet-web': minor
+---
+
+Add a new state that asks users for permission to record application diagnostics
diff --git a/.github/workflows/build-extension.yml b/.github/workflows/build-extension.yml
index 9e1cf189..9d6a2046 100644
--- a/.github/workflows/build-extension.yml
+++ b/.github/workflows/build-extension.yml
@@ -1,6 +1,9 @@
name: Build beta extensions
on: [pull_request, workflow_dispatch]
+env:
+ SENTRY_DSN: ${{ secrets.SENTRY_DSN }}
+
jobs:
pre_run:
runs-on: ubuntu-latest
diff --git a/.github/workflows/publish-extensions.yml b/.github/workflows/publish-extensions.yml
index 52debfaf..c697f1d6 100644
--- a/.github/workflows/publish-extensions.yml
+++ b/.github/workflows/publish-extensions.yml
@@ -5,6 +5,9 @@ on:
- 'v*'
workflow_dispatch:
+env:
+ SENTRY_DSN: ${{ secrets.SENTRY_DSN }}
+
jobs:
pre_run:
runs-on: ubuntu-latest
diff --git a/package.json b/package.json
index f785e933..3c5453a8 100644
--- a/package.json
+++ b/package.json
@@ -44,6 +44,8 @@
"@reach/utils": "0.15.3",
"@reach/visually-hidden": "0.15.2",
"@rehooks/document-title": "1.0.2",
+ "@sentry/react": "6.12.0",
+ "@sentry/tracing": "6.12.0",
"@stacks/auth": "2.0.0-beta.1",
"@stacks/blockchain-api-client": "0.65.0",
"@stacks/common": "2.0.0-beta.0",
diff --git a/scripts/generate-manifest.js b/scripts/generate-manifest.js
index b7e862b1..5e9aba79 100644
--- a/scripts/generate-manifest.js
+++ b/scripts/generate-manifest.js
@@ -60,7 +60,7 @@ const devManifest = {
const prodManifest = {
name: 'Hiro Wallet',
content_security_policy:
- "script-src 'self'; object-src 'none'; frame-src 'none'; frame-ancestors 'none';",
+ "default-src 'none'; connect-src *; style-src 'unsafe-inline'; script-src 'self'; object-src 'none'; frame-src 'none'; frame-ancestors 'none';",
icons: {
128: 'assets/connect-logo/Stacks128w.png',
256: 'assets/connect-logo/Stacks256w.png',
diff --git a/src/background/background.ts b/src/background/background.ts
index 71ac8073..d2d045f0 100755
--- a/src/background/background.ts
+++ b/src/background/background.ts
@@ -5,6 +5,8 @@
needed and unloaded when it goes idle.
https://developer.chrome.com/docs/extensions/mv3/architecture-overview/#background_script
*/
+import * as Sentry from '@sentry/react';
+
import { storePayload, StorageKey } from '@common/storage';
import { ScreenPaths } from '@common/types';
import {
@@ -17,9 +19,12 @@ import type { VaultActions } from '@background/vault-types';
import { popupCenter } from '@background/popup';
import { vaultMessageHandler } from '@background/vault';
import { initContextMenuActions } from '@background/init-context-menus';
+import { initSentry } from '@common/sentry-init';
const IS_TEST_ENV = process.env.TEST_ENV === 'true';
+initSentry();
+
initContextMenuActions();
// Playwright does not currently support Chrome extension popup testing:
@@ -31,68 +36,74 @@ async function openRequestInFullPage(path: string, urlParams: URLSearchParams) {
}
// Listen for install event
-chrome.runtime.onInstalled.addListener(async details => {
- if (details.reason === 'install' && !IS_TEST_ENV) {
- await chrome.tabs.create({
- url: chrome.runtime.getURL(`index.html#${ScreenPaths.INSTALLED}`),
- });
- }
+chrome.runtime.onInstalled.addListener(details => {
+ Sentry.wrap(async () => {
+ if (details.reason === 'install' && !IS_TEST_ENV) {
+ await chrome.tabs.create({
+ url: chrome.runtime.getURL(`index.html#${ScreenPaths.INSTALLED}`),
+ });
+ }
+ });
});
// Listen for connection to the content-script - port for two-way communication
-chrome.runtime.onConnect.addListener(port => {
- // Listen for auth and transaction events
- if (port.name === CONTENT_SCRIPT_PORT) {
- port.onMessage.addListener(async (message: MessageFromContentScript, port) => {
- const { payload } = message;
- switch (message.method) {
- case ExternalMethods.authenticationRequest: {
- void storePayload({
- payload,
- storageKey: StorageKey.authenticationRequests,
- port,
- });
- const path = ScreenPaths.GENERATION;
- const urlParams = new URLSearchParams();
- urlParams.set('authRequest', payload);
- if (IS_TEST_ENV) {
- await openRequestInFullPage(path, urlParams);
- } else {
- popupCenter({ url: `/popup.html#${path}?${urlParams.toString()}` });
+chrome.runtime.onConnect.addListener(port =>
+ Sentry.wrap(() => {
+ // Listen for auth and transaction events
+ if (port.name === CONTENT_SCRIPT_PORT) {
+ port.onMessage.addListener(async (message: MessageFromContentScript, port) => {
+ const { payload } = message;
+ switch (message.method) {
+ case ExternalMethods.authenticationRequest: {
+ void storePayload({
+ payload,
+ storageKey: StorageKey.authenticationRequests,
+ port,
+ });
+ const path = ScreenPaths.GENERATION;
+ const urlParams = new URLSearchParams();
+ urlParams.set('authRequest', payload);
+ if (IS_TEST_ENV) {
+ await openRequestInFullPage(path, urlParams);
+ } else {
+ popupCenter({ url: `/popup.html#${path}?${urlParams.toString()}` });
+ }
+ break;
}
- break;
- }
- case ExternalMethods.transactionRequest: {
- void storePayload({
- payload,
- storageKey: StorageKey.transactionRequests,
- port,
- });
- const path = ScreenPaths.TRANSACTION_POPUP;
- const urlParams = new URLSearchParams();
- urlParams.set('request', payload);
- if (IS_TEST_ENV) {
- await openRequestInFullPage(path, urlParams);
- } else {
- popupCenter({ url: `/popup.html#${path}?${urlParams.toString()}` });
+ case ExternalMethods.transactionRequest: {
+ void storePayload({
+ payload,
+ storageKey: StorageKey.transactionRequests,
+ port,
+ });
+ const path = ScreenPaths.TRANSACTION_POPUP;
+ const urlParams = new URLSearchParams();
+ urlParams.set('request', payload);
+ if (IS_TEST_ENV) {
+ await openRequestInFullPage(path, urlParams);
+ } else {
+ popupCenter({ url: `/popup.html#${path}?${urlParams.toString()}` });
+ }
+ break;
}
- break;
+ default:
+ break;
}
- default:
- break;
- }
- });
- }
-});
+ });
+ }
+ })
+);
// Listen for events triggered by the background memory vault
-chrome.runtime.onMessage.addListener((message: VaultActions, sender, sendResponse) => {
- // Only respond to internal messages from our UI, not content scripts in other applications
- if (!sender.url?.startsWith(chrome.runtime.getURL(''))) return;
- void vaultMessageHandler(message).then(sendResponse).catch(sendResponse);
- // Return true to specify that we are responding async
- return true;
-});
+chrome.runtime.onMessage.addListener((message: VaultActions, sender, sendResponse) =>
+ Sentry.wrap(() => {
+ // Only respond to internal messages from our UI, not content scripts in other applications
+ if (!sender.url?.startsWith(chrome.runtime.getURL(''))) return;
+ void vaultMessageHandler(message).then(sendResponse).catch(sendResponse);
+ // Return true to specify that we are responding async
+ return true;
+ })
+);
if (IS_TEST_ENV) {
// Expose a helper function to open a new tab with the wallet from tests
diff --git a/src/common/hooks/use-diagnostic-permission-prompt.ts b/src/common/hooks/use-diagnostic-permission-prompt.ts
new file mode 100644
index 00000000..e761a9bc
--- /dev/null
+++ b/src/common/hooks/use-diagnostic-permission-prompt.ts
@@ -0,0 +1,17 @@
+import { useEffect } from 'react';
+
+import { ScreenPaths } from '@common/types';
+import { IS_TEST_ENV } from '@common/constants';
+import { userHasAllowedDiagnosticsKey } from '@store/onboarding/onboarding.hooks';
+
+import { useChangeScreen } from './use-change-screen';
+
+export function usePromptUserToSetDiagnosticPermissions() {
+ const changeScreen = useChangeScreen();
+
+ useEffect(() => {
+ if (IS_TEST_ENV) return;
+ const persistedUserDiagnosticDecision = localStorage.getItem(userHasAllowedDiagnosticsKey);
+ if (persistedUserDiagnosticDecision === null) changeScreen(ScreenPaths.REQUEST_DIAGNOSTICS);
+ }, [changeScreen]);
+}
diff --git a/src/common/sentry-init.ts b/src/common/sentry-init.ts
new file mode 100644
index 00000000..0381e651
--- /dev/null
+++ b/src/common/sentry-init.ts
@@ -0,0 +1,21 @@
+import * as Sentry from '@sentry/react';
+import { Integrations } from '@sentry/tracing';
+
+import { userHasAllowedDiagnosticsKey } from '@store/onboarding/onboarding.hooks';
+
+function checkUserHasGrantedPermission() {
+ return localStorage.getItem(userHasAllowedDiagnosticsKey) === 'true';
+}
+
+export function initSentry() {
+ Sentry.init({
+ dsn: process.env.SENTRY_DSN,
+ integrations: [new Integrations.BrowserTracing()],
+ tracesSampleRate: 1.0,
+ enabled: checkUserHasGrantedPermission(),
+ beforeSend(event) {
+ if (!checkUserHasGrantedPermission()) return null;
+ return event;
+ },
+ });
+}
diff --git a/src/common/types.ts b/src/common/types.ts
index fcb57a55..e2487751 100644
--- a/src/common/types.ts
+++ b/src/common/types.ts
@@ -40,6 +40,7 @@ export enum ScreenPaths {
POPUP_SEND = '/send',
POPUP_RECEIVE = '/receive',
ADD_NETWORK = '/add-network',
+ REQUEST_DIAGNOSTICS = '/request-diagnostics',
EDIT_POST_CONDITIONS = '/transaction/post-conditions',
TRANSACTION_POPUP = '/transaction',
}
diff --git a/src/index.tsx b/src/index.tsx
index 37789449..aa109982 100755
--- a/src/index.tsx
+++ b/src/index.tsx
@@ -1,7 +1,11 @@
import React from 'react';
import ReactDOM from 'react-dom';
import App from './app';
+
import { persistAndRenderApp } from '@common/persistence';
+import { initSentry } from '@common/sentry-init';
+
+initSentry();
function renderApp() {
ReactDOM.render(, document.getElementById('actions-root'));
diff --git a/src/pages/allow-diagnostics/allow-diagnostics-layout.tsx b/src/pages/allow-diagnostics/allow-diagnostics-layout.tsx
new file mode 100644
index 00000000..0bd49f15
--- /dev/null
+++ b/src/pages/allow-diagnostics/allow-diagnostics-layout.tsx
@@ -0,0 +1,65 @@
+import React, { FC } from 'react';
+
+import { Body } from '@components/typography';
+import { Box, Button, Flex, color, Stack } from '@stacks/ui';
+import { BaseDrawer } from '@components/drawer';
+import { FiCheck } from 'react-icons/fi';
+
+interface ReasonToAllowDiagnosticsProps {
+ text: string;
+}
+const ReasonToAllowDiagnostics: FC = ({ text }) => {
+ return (
+
+
+
+
+ {text}
+
+ );
+};
+
+interface AllowDiagnosticsLayoutProps {
+ onUserAllowDiagnostics(): void;
+ onUserDenyDiagnosticsPermissions(): void;
+}
+export const AllowDiagnosticsLayout: FC = props => {
+ const { onUserAllowDiagnostics, onUserDenyDiagnosticsPermissions } = props;
+
+ const title = 'Help us improve';
+
+ return (
+ onUserDenyDiagnosticsPermissions()}>
+
+
+ Hiro would like to gather anonymous data to help improve the experience of using Stacks
+ apps and the wallet.
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
diff --git a/src/pages/allow-diagnostics/allow-diagnostics.tsx b/src/pages/allow-diagnostics/allow-diagnostics.tsx
new file mode 100644
index 00000000..698bef92
--- /dev/null
+++ b/src/pages/allow-diagnostics/allow-diagnostics.tsx
@@ -0,0 +1,29 @@
+import React, { useCallback } from 'react';
+
+import { ScreenPaths } from '@common/types';
+import { useChangeScreen } from '@common/hooks/use-change-screen';
+import { useHasAllowedDiagnostics } from '@store/onboarding/onboarding.hooks';
+
+import { AllowDiagnosticsLayout } from './allow-diagnostics-layout';
+import { initSentry } from '@common/sentry-init';
+
+export const AllowDiagnosticsDrawer = () => {
+ const changeScreen = useChangeScreen();
+ const [, setHasAllowedDiagnostics] = useHasAllowedDiagnostics();
+
+ const goHomeAndSetDiagnosticsPermissionTo = useCallback(
+ (areDiagnosticsAllowed: boolean) => {
+ changeScreen(ScreenPaths.HOME);
+ setHasAllowedDiagnostics(areDiagnosticsAllowed);
+ if (areDiagnosticsAllowed) initSentry();
+ },
+ [changeScreen, setHasAllowedDiagnostics]
+ );
+
+ return (
+ goHomeAndSetDiagnosticsPermissionTo(false)}
+ onUserAllowDiagnostics={() => goHomeAndSetDiagnosticsPermissionTo(true)}
+ />
+ );
+};
diff --git a/src/pages/home/home.tsx b/src/pages/home/home.tsx
index 82cd49bb..e5707b19 100644
--- a/src/pages/home/home.tsx
+++ b/src/pages/home/home.tsx
@@ -8,7 +8,11 @@ import { UserAccount } from '@pages/home/components/user-area';
import { HomeActions } from '@pages/home/components/actions';
import { HiroMessages } from '@features/hiro-messages/hiro-messages';
+import { usePromptUserToSetDiagnosticPermissions } from '@common/hooks/use-diagnostic-permission-prompt';
+
export const PopupHome = () => {
+ usePromptUserToSetDiagnosticPermissions();
+
return (
<>
= props => {
const { onUserDeleteWallet, onUserSafelyReturnToHomepage } = props;
diff --git a/src/routes.tsx b/src/routes.tsx
index 68b56b1a..19ba49b0 100644
--- a/src/routes.tsx
+++ b/src/routes.tsx
@@ -27,6 +27,7 @@ import { Unlock } from '@pages/unlock';
import { PopupHome } from '@pages/home/home';
import { useUpdateLastSeenStore } from '@store/wallet/wallet.hooks';
import { SignOutConfirmDrawer } from '@pages/sign-out-confirm/sign-out-confirm';
+import { AllowDiagnosticsDrawer } from '@pages/allow-diagnostics/allow-diagnostics';
interface RouteProps {
path: ScreenPaths;
@@ -90,6 +91,7 @@ export const Routes: React.FC = () => {
} />
+ } />
{/* Installation */}
} />
diff --git a/src/store/onboarding/onboarding.hooks.ts b/src/store/onboarding/onboarding.hooks.ts
index c6a16bbf..32e4bd5b 100644
--- a/src/store/onboarding/onboarding.hooks.ts
+++ b/src/store/onboarding/onboarding.hooks.ts
@@ -3,6 +3,7 @@ import { useAtomValue, useUpdateAtom } from 'jotai/utils';
import {
authRequestState,
currentScreenState,
+ hasAllowedDiagnosticsState,
magicRecoveryCodePasswordState,
magicRecoveryCodeState,
onboardingPathState,
@@ -10,9 +11,12 @@ import {
secretKeyState,
seedInputErrorState,
seedInputState,
+ userHasAllowedDiagnosticsKey,
usernameState,
} from './onboarding';
+export { userHasAllowedDiagnosticsKey };
+
export function useAuthRequest() {
return useAtomValue(authRequestState);
}
@@ -64,3 +68,7 @@ export function useUsernameState() {
export function useOnboardingPathState() {
return useAtomValue(onboardingPathState);
}
+
+export function useHasAllowedDiagnostics() {
+ return useAtom(hasAllowedDiagnosticsState);
+}
diff --git a/src/store/onboarding/onboarding.ts b/src/store/onboarding/onboarding.ts
index 51830954..ecb0d444 100644
--- a/src/store/onboarding/onboarding.ts
+++ b/src/store/onboarding/onboarding.ts
@@ -1,5 +1,5 @@
import { atom } from 'jotai';
-import { atomWithDefault } from 'jotai/utils';
+import { atomWithDefault, atomWithStorage } from 'jotai/utils';
import { ScreenPaths } from '@common/types';
import { DecodedAuthRequest } from '@common/dev/types';
@@ -43,6 +43,10 @@ export const authRequestState = atom({
appURL: undefined,
});
+export const userHasAllowedDiagnosticsKey = 'stacks-wallet-has-allowed-diagnostics';
+
+export const hasAllowedDiagnosticsState = atomWithStorage(userHasAllowedDiagnosticsKey, false);
+
magicRecoveryCodePasswordState.debugLabel = 'magicRecoveryCodePasswordState';
seedInputState.debugLabel = 'seedInputState';
seedInputErrorState.debugLabel = 'seedInputErrorState';
diff --git a/webpack/webpack.config.base.js b/webpack/webpack.config.base.js
index 178b6ce1..0f74686d 100755
--- a/webpack/webpack.config.base.js
+++ b/webpack/webpack.config.base.js
@@ -199,6 +199,11 @@ const config = {
'process.env.USERNAMES_ENABLED': JSON.stringify(process.env.USERNAMES_ENABLED || 'false'),
'process.env.TEST_ENV': JSON.stringify(TEST_ENV ? 'true' : 'false'),
}),
+
+ new webpack.EnvironmentPlugin({
+ SENTRY_DSN: process.env.SENTRY_DSN ?? '',
+ }),
+
new webpack.ProvidePlugin({
process: 'process/browser.js',
Buffer: ['buffer', 'Buffer'],
diff --git a/yarn.lock b/yarn.lock
index 38d11a5f..1998f2a9 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2840,6 +2840,81 @@
resolved "https://registry.yarnpkg.com/@schemastore/web-manifest/-/web-manifest-0.0.5.tgz#97f0b1f14d095189c5672309e4975760278461b2"
integrity sha512-3SF3OwzJ+PIqYDVW0MXoUAyypyx7N5RlYj2zek36qVuDUgoiI65q0ietwuxyVtbTRYJyP64KBGKvKqHzbIxdfA==
+"@sentry/browser@6.12.0":
+ version "6.12.0"
+ resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-6.12.0.tgz#970cd68fa117a1e1336fdb373e3b1fa76cd63e2d"
+ integrity sha512-wsJi1NLOmfwtPNYxEC50dpDcVY7sdYckzwfqz1/zHrede1mtxpqSw+7iP4bHADOJXuF+ObYYTHND0v38GSXznQ==
+ dependencies:
+ "@sentry/core" "6.12.0"
+ "@sentry/types" "6.12.0"
+ "@sentry/utils" "6.12.0"
+ tslib "^1.9.3"
+
+"@sentry/core@6.12.0":
+ version "6.12.0"
+ resolved "https://registry.yarnpkg.com/@sentry/core/-/core-6.12.0.tgz#bc7c5f0785b6a392d9ad47bd9b1fae3f5389996c"
+ integrity sha512-mU/zdjlzFHzdXDZCPZm8OeCw7c9xsbL49Mq0TrY0KJjLt4CJBkiq5SDTGfRsenBLgTedYhe5Z/J8Z+xVVq+MfQ==
+ dependencies:
+ "@sentry/hub" "6.12.0"
+ "@sentry/minimal" "6.12.0"
+ "@sentry/types" "6.12.0"
+ "@sentry/utils" "6.12.0"
+ tslib "^1.9.3"
+
+"@sentry/hub@6.12.0":
+ version "6.12.0"
+ resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-6.12.0.tgz#29e323ab6a95e178fb14fffb684aa0e09707197f"
+ integrity sha512-yR/UQVU+ukr42bSYpeqvb989SowIXlKBanU0cqLFDmv5LPCnaQB8PGeXwJAwWhQgx44PARhmB82S6Xor8gYNxg==
+ dependencies:
+ "@sentry/types" "6.12.0"
+ "@sentry/utils" "6.12.0"
+ tslib "^1.9.3"
+
+"@sentry/minimal@6.12.0":
+ version "6.12.0"
+ resolved "https://registry.yarnpkg.com/@sentry/minimal/-/minimal-6.12.0.tgz#cbe20e95056cedb9709d7d5b2119ef95206a9f8c"
+ integrity sha512-r3C54Q1KN+xIqUvcgX9DlcoWE7ezWvFk2pSu1Ojx9De81hVqR9u5T3sdSAP2Xma+um0zr6coOtDJG4WtYlOtsw==
+ dependencies:
+ "@sentry/hub" "6.12.0"
+ "@sentry/types" "6.12.0"
+ tslib "^1.9.3"
+
+"@sentry/react@6.12.0":
+ version "6.12.0"
+ resolved "https://registry.yarnpkg.com/@sentry/react/-/react-6.12.0.tgz#8ae2680d226fafb0da0f3d8366bb285004ba6c2e"
+ integrity sha512-E8Nw9PPzP/EyMy64ksr9xcyYYlBmUA5ROnkPQp7o5wF0xf5/J+nMS1tQdyPnLQe2KUgHlN4kVs2HHft1m7mSYQ==
+ dependencies:
+ "@sentry/browser" "6.12.0"
+ "@sentry/minimal" "6.12.0"
+ "@sentry/types" "6.12.0"
+ "@sentry/utils" "6.12.0"
+ hoist-non-react-statics "^3.3.2"
+ tslib "^1.9.3"
+
+"@sentry/tracing@6.12.0":
+ version "6.12.0"
+ resolved "https://registry.yarnpkg.com/@sentry/tracing/-/tracing-6.12.0.tgz#a05c8985ee7fed7310b029b147d8f9f14f2a2e67"
+ integrity sha512-u10QHNknPBzbWSUUNMkvuH53sQd5NaBo6YdNPj4p5b7sE7445Sh0PwBpRbY3ZiUUiwyxV59fx9UQ4yVnPGxZQA==
+ dependencies:
+ "@sentry/hub" "6.12.0"
+ "@sentry/minimal" "6.12.0"
+ "@sentry/types" "6.12.0"
+ "@sentry/utils" "6.12.0"
+ tslib "^1.9.3"
+
+"@sentry/types@6.12.0":
+ version "6.12.0"
+ resolved "https://registry.yarnpkg.com/@sentry/types/-/types-6.12.0.tgz#b7395688a79403c6df8d8bb8d81deb8222519853"
+ integrity sha512-urtgLzE4EDMAYQHYdkgC0Ei9QvLajodK1ntg71bGn0Pm84QUpaqpPDfHRU+i6jLeteyC7kWwa5O5W1m/jrjGXA==
+
+"@sentry/utils@6.12.0":
+ version "6.12.0"
+ resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-6.12.0.tgz#3de261e8d11bdfdc7add64a3065d43517802e975"
+ integrity sha512-oRHQ7TH5TSsJqoP9Gqq25Jvn9LKexXfAh/OoKwjMhYCGKGhqpDNUIZVgl9DWsGw5A5N5xnQyLOxDfyRV5RshdA==
+ dependencies:
+ "@sentry/types" "6.12.0"
+ tslib "^1.9.3"
+
"@sideway/address@^4.1.0":
version "4.1.2"
resolved "https://registry.yarnpkg.com/@sideway/address/-/address-4.1.2.tgz#811b84333a335739d3969cfc434736268170cad1"
@@ -9364,7 +9439,7 @@ hmac-drbg@^1.0.1:
minimalistic-assert "^1.0.0"
minimalistic-crypto-utils "^1.0.1"
-hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.1:
+hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.1, 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"
integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==
@@ -15328,7 +15403,7 @@ tsconfig-paths@^3.11.0, tsconfig-paths@^3.9.0:
minimist "^1.2.0"
strip-bom "^3.0.0"
-tslib@^1.10.0, tslib@^1.8.1, tslib@^1.9.0:
+tslib@^1.10.0, tslib@^1.8.1, tslib@^1.9.0, tslib@^1.9.3:
version "1.14.1"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==