diff --git a/.babelrc b/.babelrc deleted file mode 100644 index 189f09ac0..000000000 --- a/.babelrc +++ /dev/null @@ -1,13 +0,0 @@ -{ - "presets": ["next/babel"], - "plugins": [ - [ - "styled-components", - { - "ssr": true, - "displayName": true, - "preprocess": false - } - ] - ] -} diff --git a/.eslintignore b/.eslintignore deleted file mode 100644 index 7d5c7232d..000000000 --- a/.eslintignore +++ /dev/null @@ -1 +0,0 @@ -thirdparty \ No newline at end of file diff --git a/.eslintrc.json b/.eslintrc.json index 3da5dafd4..519785509 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -1,60 +1,59 @@ { "root": true, - "env": { - "browser": true, - "es2021": true, - "node": true + "parserOptions": { + "project": ["./tsconfig.json"] }, "extends": [ - "plugin:react/recommended", + "next/core-web-vitals", "eslint:recommended", - "plugin:@typescript-eslint/eslint-recommended", - "google", + "plugin:@typescript-eslint/recommended", + "plugin:@typescript-eslint/recommended-requiring-type-checking", "prettier" ], - "parser": "@typescript-eslint/parser", - "parserOptions": { - "ecmaFeatures": { - "jsx": true - }, - "ecmaVersion": 12, - "sourceType": "module" - }, - "plugins": [ - "react", - "@typescript-eslint" - ], + "plugins": ["@typescript-eslint"], + "rules": { - "indent":"off", + "indent": "off", "class-methods-use-this": "off", "react/prop-types": "off", "react/display-name": "off", "react/no-unescaped-entities": "off", "no-unused-vars": "off", - "@typescript-eslint/no-unused-vars": [ - "error" - ], + "@typescript-eslint/no-unused-vars": ["error"], "require-jsdoc": "off", "valid-jsdoc": "off", "max-len": "off", "new-cap": "off", "no-invalid-this": "off", "eqeqeq": "error", - "object-curly-spacing": [ - "error", - "always" - ], + "object-curly-spacing": ["error", "always"], "space-before-function-paren": "off", - "operator-linebreak":["error","after", { "overrides": { "?": "before", ":": "before" } }] - }, - "settings": { - "react": { - "version": "detect" - } - }, - "globals": { - "JSX": "readonly", - "NodeJS": "readonly", - "ReadableStreamDefaultController": "readonly" + "operator-linebreak": [ + "error", + "after", + { "overrides": { "?": "before", ":": "before" } } + ], + "@typescript-eslint/no-unsafe-member-access": "off", + "@typescript-eslint/no-unsafe-return": "off", + "@typescript-eslint/no-unsafe-assignment": "off", + "@typescript-eslint/no-inferrable-types": "off", + "@typescript-eslint/restrict-template-expressions": "off", + "@typescript-eslint/ban-types": "off", + "@typescript-eslint/no-floating-promises": "off", + "@typescript-eslint/no-unsafe-call": "off", + "@typescript-eslint/require-await": "off", + "@typescript-eslint/restrict-plus-operands": "off", + "@typescript-eslint/no-var-requires": "off", + "@typescript-eslint/no-empty-interface": "off", + "@typescript-eslint/no-misused-promises": "off", + "@typescript-eslint/no-empty-function": "off", + "@typescript-eslint/explicit-module-boundary-types": "off", + "@typescript-eslint/no-explicit-any": "off", + "@typescript-eslint/no-unnecessary-type-assertion": "off", + "react-hooks/rules-of-hooks": "off", + "react-hooks/exhaustive-deps": "off", + "@next/next/no-img-element": "off", + "@typescript-eslint/no-unsafe-argument": "off", + "jsx-a11y/alt-text": "off" } } diff --git a/.lintstagedrc.js b/.lintstagedrc.js new file mode 100644 index 000000000..fa55b0807 --- /dev/null +++ b/.lintstagedrc.js @@ -0,0 +1,13 @@ +const path = require('path'); + +const buildEslintCommand = (filenames) => + `next lint --fix --file ${filenames + .map((f) => path.relative(process.cwd(), f)) + .join(' --file ')}`; + +const buildPrettierCommand = (filenames) => + `yarn prettier --write --ignore-unknown ${filenames.join(' ')}`; + +module.exports = { + '*.{js,jsx,ts,tsx}': [buildEslintCommand, buildPrettierCommand], +}; diff --git a/.yarnrc b/.yarnrc new file mode 100644 index 000000000..02b1010b3 --- /dev/null +++ b/.yarnrc @@ -0,0 +1 @@ +network-timeout 500000 diff --git a/configUtil.js b/configUtil.js index 274c3d786..c248fc377 100644 --- a/configUtil.js +++ b/configUtil.js @@ -37,11 +37,6 @@ module.exports = { 'report-to': ' https://csp-reporter.ente.io/local', }, - WORKBOX_CONFIG: { - swSrc: 'src/serviceWorker.js', - exclude: [/manifest\.json$/i], - }, - ALL_ROUTES: '/(.*)', buildCSPHeader: (directives) => ({ diff --git a/next.config.js b/next.config.js index 5b81c9910..2491e4ee0 100644 --- a/next.config.js +++ b/next.config.js @@ -1,7 +1,6 @@ const withBundleAnalyzer = require('@next/bundle-analyzer')({ enabled: process.env.ANALYZE === 'true', }); -const withWorkbox = require('@ente-io/next-with-workbox'); const { withSentryConfig } = require('@sentry/nextjs'); const { PHASE_DEVELOPMENT_SERVER } = require('next/constants'); @@ -19,7 +18,6 @@ const { COOP_COEP_HEADERS, WEB_SECURITY_HEADERS, CSP_DIRECTIVES, - WORKBOX_CONFIG, ALL_ROUTES, getIsSentryEnabled, } = require('./configUtil'); @@ -30,37 +28,39 @@ const IS_SENTRY_ENABLED = getIsSentryEnabled(); module.exports = (phase) => withSentryConfig( - withWorkbox( - withBundleAnalyzer( - withTM({ - env: { - SENTRY_RELEASE: GIT_SHA, - NEXT_PUBLIC_LATEST_COMMIT_HASH: GIT_SHA, + withBundleAnalyzer( + withTM({ + compiler: { + styledComponents: { + ssr: true, + displayName: true, }, - workbox: WORKBOX_CONFIG, + }, + env: { + SENTRY_RELEASE: GIT_SHA, + }, - headers() { - return [ - { - // Apply these headers to all routes in your application.... - source: ALL_ROUTES, - headers: convertToNextHeaderFormat({ - ...COOP_COEP_HEADERS, - ...WEB_SECURITY_HEADERS, - ...buildCSPHeader(CSP_DIRECTIVES), - }), - }, - ]; - }, - // https://dev.to/marcinwosinek/how-to-add-resolve-fallback-to-webpack-5-in-nextjs-10-i6j - webpack: (config, { isServer }) => { - if (!isServer) { - config.resolve.fallback.fs = false; - } - return config; - }, - }) - ) + headers() { + return [ + { + // Apply these headers to all routes in your application.... + source: ALL_ROUTES, + headers: convertToNextHeaderFormat({ + ...COOP_COEP_HEADERS, + ...WEB_SECURITY_HEADERS, + ...buildCSPHeader(CSP_DIRECTIVES), + }), + }, + ]; + }, + // https://dev.to/marcinwosinek/how-to-add-resolve-fallback-to-webpack-5-in-nextjs-10-i6j + webpack: (config, { isServer }) => { + if (!isServer) { + config.resolve.fallback.fs = false; + } + return config; + }, + }) ), { release: GIT_SHA, diff --git a/package.json b/package.json index 86b946949..3a2df5562 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "scripts": { "dev": "next dev", "albums": "next dev -p 3002", - "lint": "eslint \"src/**/*.{js,jsx,ts,tsx}\"", + "lint": "next lint", "prebuild": "yarn lint", "build": "next build", "postbuild": "next export", @@ -15,7 +15,6 @@ }, "dependencies": { "@date-io/date-fns": "^2.14.0", - "@ente-io/next-with-workbox": "^1.0.3", "@mui/icons-material": "^5.6.2", "@mui/material": "^5.6.2", "@mui/styled-engine": "npm:@mui/styled-engine-sc@latest", @@ -39,7 +38,7 @@ "jszip": "3.7.1", "libsodium-wrappers": "^0.7.8", "localforage": "^1.9.0", - "next": "^12.1.0", + "next": "^12.3.1", "next-transpile-modules": "^9.0.0", "photoswipe": "file:./thirdparty/photoswipe", "piexifjs": "^1.0.6", @@ -52,12 +51,8 @@ "react-top-loading-bar": "^2.0.1", "react-virtualized-auto-sizer": "^1.0.2", "react-window": "^1.8.6", + "sanitize-filename": "^1.6.3", "styled-components": "^5.3.5", - "workbox-precaching": "^6.1.5", - "workbox-recipes": "^6.1.5", - "workbox-routing": "^6.1.5", - "workbox-strategies": "^6.1.5", - "workbox-window": "^6.1.5", "xml-js": "^1.6.11", "yup": "^0.29.3" }, @@ -75,17 +70,10 @@ "@types/react-window-infinite-loader": "^1.0.3", "@types/styled-components": "^5.1.25", "@types/yup": "^0.29.7", - "@typescript-eslint/eslint-plugin": "^4.25.0", - "@typescript-eslint/parser": "^4.25.0", - "babel-plugin-styled-components": "^1.11.1", - "eslint": "^7.27.0", - "eslint-config-airbnb": "^18.2.1", - "eslint-config-google": "^0.14.0", - "eslint-config-prettier": "^8.3.0", - "eslint-plugin-import": "^2.23.3", - "eslint-plugin-jsx-a11y": "^6.4.1", - "eslint-plugin-react": "^7.23.2", - "eslint-plugin-react-hooks": "^4.2.0", + "@typescript-eslint/eslint-plugin": "^5.43.0", + "eslint": "^8.28.0", + "eslint-config-next": "^13.0.4", + "eslint-config-prettier": "^8.5.0", "husky": "^7.0.1", "lint-staged": "^11.1.2", "prettier": "2.3.2", @@ -95,12 +83,6 @@ "standard": { "parser": "babel-eslint" }, - "lint-staged": { - "src/**/*.{js,jsx,ts,tsx}": [ - "eslint --fix", - "prettier --write --ignore-unknown" - ] - }, "resolutions": { "@mui/styled-engine": "npm:@mui/styled-engine-sc@latest" } diff --git a/sentry.client.config.js b/sentry.client.config.js index 3eec2c8fc..aeda578d9 100644 --- a/sentry.client.config.js +++ b/sentry.client.config.js @@ -13,7 +13,6 @@ const SENTRY_ENV = getSentryENV(); const SENTRY_RELEASE = getSentryRelease(); const IS_ENABLED = getIsSentryEnabled(); -Sentry.setUser({ id: getSentryUserID() }); Sentry.init({ dsn: SENTRY_DSN, enabled: IS_ENABLED, @@ -39,3 +38,9 @@ Sentry.init({ // `release` value here - use the environment variable `SENTRY_RELEASE`, so // that it will also get attached to your source maps }); + +const main = async () => { + Sentry.setUser({ id: await getSentryUserID() }); +}; + +main(); diff --git a/sentry.properties b/sentry.properties new file mode 100644 index 000000000..c5d0544d7 --- /dev/null +++ b/sentry.properties @@ -0,0 +1,3 @@ +defaults.url=https://sentry.ente.io/ +defaults.org=ente +defaults.project=bada-frame diff --git a/sentry.server.config.js b/sentry.server.config.js index 5d8714c99..79b62e6bd 100644 --- a/sentry.server.config.js +++ b/sentry.server.config.js @@ -6,6 +6,8 @@ import { getIsSentryEnabled, } from 'constants/sentry'; +import { getSentryUserID } from 'utils/user'; + const SENTRY_DSN = getSentryDSN(); const SENTRY_ENV = getSentryENV(); const SENTRY_RELEASE = getSentryRelease(); @@ -18,3 +20,9 @@ Sentry.init({ release: SENTRY_RELEASE, autoSessionTracking: false, }); + +const main = async () => { + Sentry.setUser({ id: await getSentryUserID() }); +}; + +main(); diff --git a/sentryConfigUtil.js b/sentryConfigUtil.js index 1b19f2f6b..84d4a7628 100644 --- a/sentryConfigUtil.js +++ b/sentryConfigUtil.js @@ -1,10 +1,11 @@ +const ENV_DEVELOPMENT = 'development'; + module.exports.getIsSentryEnabled = () => { - if (process.env.NEXT_PUBLIC_IS_SENTRY_ENABLED) { - return process.env.NEXT_PUBLIC_IS_SENTRY_ENABLED === 'yes'; + if (process.env.NEXT_PUBLIC_SENTRY_ENV === ENV_DEVELOPMENT) { + return false; + } else if (process.env.NEXT_PUBLIC_DISABLE_SENTRY === 'true') { + return false; } else { - if (process.env.NEXT_PUBLIC_SENTRY_ENV) { - return process.env.NEXT_PUBLIC_SENTRY_ENV !== 'development'; - } + return true; } - return false; }; diff --git a/src/components/Badge.tsx b/src/components/Badge.tsx index 773729509..c145b2000 100644 --- a/src/components/Badge.tsx +++ b/src/components/Badge.tsx @@ -3,8 +3,9 @@ import { CSSProperties } from '@mui/styled-engine'; export const Badge = styled(Paper)(({ theme }) => ({ padding: '2px 4px', - backgroundColor: theme.palette.glass.main, - color: theme.palette.glass.contrastText, + backgroundColor: theme.palette.backdrop.main, + backdropFilter: `blur(${theme.palette.blur.muted})`, + color: theme.palette.primary.contrastText, textTransform: 'uppercase', ...(theme.typography.mini as CSSProperties), })); diff --git a/src/components/Chip.tsx b/src/components/Chip.tsx new file mode 100644 index 000000000..bce7429e1 --- /dev/null +++ b/src/components/Chip.tsx @@ -0,0 +1,10 @@ +import { Box, styled } from '@mui/material'; +import { CSSProperties } from 'react'; + +export const Chip = styled(Box)(({ theme }) => ({ + ...(theme.typography.body2 as CSSProperties), + padding: '8px 12px', + borderRadius: '4px', + backgroundColor: theme.palette.fill.dark, + fontWeight: 'bold', +})); diff --git a/src/components/CodeBlock/CopyButton.tsx b/src/components/CodeBlock/CopyButton.tsx index 9686c0392..bc8e09f60 100644 --- a/src/components/CodeBlock/CopyButton.tsx +++ b/src/components/CodeBlock/CopyButton.tsx @@ -1,20 +1,43 @@ -import React from 'react'; +import React, { useState } from 'react'; import constants from 'utils/strings/constants'; -import { CopyButtonWrapper } from './styledComponents'; import DoneIcon from '@mui/icons-material/Done'; import ContentCopyIcon from '@mui/icons-material/ContentCopy'; -import { Tooltip } from '@mui/material'; +import { + IconButton, + IconButtonProps, + SvgIconProps, + Tooltip, +} from '@mui/material'; -export default function CopyButton({ code, copied, copyToClipboardHelper }) { +export default function CopyButton({ + code, + color, + size, +}: { + code: string; + color?: IconButtonProps['color']; + size?: SvgIconProps['fontSize']; +}) { + const [copied, setCopied] = useState(false); + + const copyToClipboardHelper = (text: string) => () => { + navigator.clipboard.writeText(text); + setCopied(true); + setTimeout(() => setCopied(false), 1000); + }; return ( - - + + {copied ? ( - + ) : ( - + )} - + ); } diff --git a/src/components/CodeBlock/index.tsx b/src/components/CodeBlock/index.tsx index e3e7aff07..a05c913b2 100644 --- a/src/components/CodeBlock/index.tsx +++ b/src/components/CodeBlock/index.tsx @@ -1,7 +1,7 @@ import { FreeFlowText } from '../Container'; -import React, { useState } from 'react'; +import React from 'react'; import EnteSpinner from '../EnteSpinner'; -import { Wrapper, CodeWrapper } from './styledComponents'; +import { Wrapper, CodeWrapper, CopyButtonWrapper } from './styledComponents'; import CopyButton from './CopyButton'; import { BoxProps } from '@mui/material'; @@ -15,14 +15,6 @@ export default function CodeBlock({ wordBreak, ...props }: BoxProps<'div', Iprops>) { - const [copied, setCopied] = useState(false); - - const copyToClipboardHelper = (text: string) => () => { - navigator.clipboard.writeText(text); - setCopied(true); - setTimeout(() => setCopied(false), 1000); - }; - if (!code) { return ( @@ -37,11 +29,9 @@ export default function CodeBlock({ {code} - + + + ); } diff --git a/src/components/Collections/CollectionInfoWithOptions.tsx b/src/components/Collections/CollectionInfoWithOptions.tsx index e7c85047c..dedd9230f 100644 --- a/src/components/Collections/CollectionInfoWithOptions.tsx +++ b/src/components/Collections/CollectionInfoWithOptions.tsx @@ -8,8 +8,8 @@ import { CollectionInfoBarWrapper } from './styledComponents'; import { shouldShowOptions } from 'utils/collection'; import { CollectionSummaryType } from 'constants/collection'; import Favorite from '@mui/icons-material/FavoriteRounded'; -import VisibilityOff from '@mui/icons-material/VisibilityOff'; import Delete from '@mui/icons-material/Delete'; +import { ArchiveOutlined } from '@mui/icons-material'; interface Iprops { activeCollection: Collection; @@ -43,7 +43,7 @@ export default function CollectionInfoWithOptions({ return ; case CollectionSummaryType.archived: case CollectionSummaryType.archive: - return ; + return ; case CollectionSummaryType.trash: return ; default: diff --git a/src/components/Collections/CollectionListBar/CollectionCard.tsx b/src/components/Collections/CollectionListBar/CollectionCard.tsx index c5bb00df4..3385ed279 100644 --- a/src/components/Collections/CollectionListBar/CollectionCard.tsx +++ b/src/components/Collections/CollectionListBar/CollectionCard.tsx @@ -11,7 +11,7 @@ import TruncateText from 'components/TruncateText'; import { Box } from '@mui/material'; import { CollectionSummaryType } from 'constants/collection'; import Favorite from '@mui/icons-material/FavoriteRounded'; -import VisibilityOff from '@mui/icons-material/VisibilityOff'; +import { ArchiveOutlined } from '@mui/icons-material'; interface Iprops { active: boolean; @@ -50,7 +50,7 @@ function CollectionCardIcon({ collectionType }) { {collectionType === CollectionSummaryType.favorites && } {collectionType === CollectionSummaryType.archived && ( - + )} ); diff --git a/src/components/Collections/CollectionOptions/AlbumCollectionOption.tsx b/src/components/Collections/CollectionOptions/AlbumCollectionOption.tsx index 9d6c4f3c4..24fcdd603 100644 --- a/src/components/Collections/CollectionOptions/AlbumCollectionOption.tsx +++ b/src/components/Collections/CollectionOptions/AlbumCollectionOption.tsx @@ -4,11 +4,10 @@ import React from 'react'; import EditIcon from '@mui/icons-material/Edit'; import IosShareIcon from '@mui/icons-material/IosShare'; import FileDownloadOutlinedIcon from '@mui/icons-material/FileDownloadOutlined'; -import VisibilityOffOutlinedIcon from '@mui/icons-material/VisibilityOffOutlined'; -import VisibilityOnOutlinedIcon from '@mui/icons-material/VisibilityOutlined'; import DeleteOutlinedIcon from '@mui/icons-material/DeleteOutlined'; import constants from 'utils/strings/constants'; import { CollectionActions } from '.'; +import { ArchiveOutlined, Unarchive } from '@mui/icons-material'; interface Iprops { IsArchived: boolean; @@ -53,13 +52,13 @@ export function AlbumCollectionOption({ onClick={handleCollectionAction( CollectionActions.UNARCHIVE )} - startIcon={}> + startIcon={}> {constants.UNARCHIVE} ) : ( }> + startIcon={}> {constants.ARCHIVE} )} diff --git a/src/components/Collections/CollectionShare/emailShare.tsx b/src/components/Collections/CollectionShare/emailShare.tsx index c40fcdcf2..15a65d3a4 100644 --- a/src/components/Collections/CollectionShare/emailShare.tsx +++ b/src/components/Collections/CollectionShare/emailShare.tsx @@ -5,7 +5,7 @@ import { GalleryContext } from 'pages/gallery'; import React, { useContext } from 'react'; import { shareCollection } from 'services/collectionService'; import { User } from 'types/user'; -import { handleSharingErrors } from 'utils/error'; +import { handleSharingErrors } from 'utils/error/ui'; import { getData, LS_KEYS } from 'utils/storage/localStorage'; import constants from 'utils/strings/constants'; import { CollectionShareSharees } from './sharees'; diff --git a/src/components/Collections/CollectionShare/publicShare/control.tsx b/src/components/Collections/CollectionShare/publicShare/control.tsx index bb744d72f..34e51921c 100644 --- a/src/components/Collections/CollectionShare/publicShare/control.tsx +++ b/src/components/Collections/CollectionShare/publicShare/control.tsx @@ -1,6 +1,5 @@ import { Box, Typography } from '@mui/material'; import { FlexWrapper } from 'components/Container'; -import { ButtonVariant } from 'components/pages/gallery/LinkButton'; import { AppContext } from 'pages/_app'; import React, { useContext, useState } from 'react'; import { @@ -8,7 +7,7 @@ import { deleteShareableURL, } from 'services/collectionService'; import { Collection, PublicURL } from 'types/collection'; -import { handleSharingErrors } from 'utils/error'; +import { handleSharingErrors } from 'utils/error/ui'; import constants from 'utils/strings/constants'; import PublicShareSwitch from './switch'; interface Iprops { @@ -60,7 +59,7 @@ export default function PublicShareControl({ proceed: { text: constants.DISABLE, action: disablePublicSharing, - variant: ButtonVariant.danger, + variant: 'danger', }, }); }; diff --git a/src/components/Collections/CollectionShare/publicShare/manage/downloadAccess.tsx b/src/components/Collections/CollectionShare/publicShare/manage/downloadAccess.tsx index daa3d4fcc..ba6d8cc9a 100644 --- a/src/components/Collections/CollectionShare/publicShare/manage/downloadAccess.tsx +++ b/src/components/Collections/CollectionShare/publicShare/manage/downloadAccess.tsx @@ -1,5 +1,4 @@ import { Box, Typography } from '@mui/material'; -import { ButtonVariant } from 'components/pages/gallery/LinkButton'; import { AppContext } from 'pages/_app'; import React, { useContext } from 'react'; import constants from 'utils/strings/constants'; @@ -34,7 +33,7 @@ export function ManageDownloadAccess({ collectionID: collection.id, enableDownload: false, }), - variant: ButtonVariant.danger, + variant: 'danger', }, }); }; diff --git a/src/components/Collections/CollectionShare/publicShare/manage/index.tsx b/src/components/Collections/CollectionShare/publicShare/manage/index.tsx index 5216e4eac..dee0cb8ba 100644 --- a/src/components/Collections/CollectionShare/publicShare/manage/index.tsx +++ b/src/components/Collections/CollectionShare/publicShare/manage/index.tsx @@ -8,13 +8,13 @@ import React, { useContext, useState } from 'react'; import { updateShareableURL } from 'services/collectionService'; import { UpdatePublicURL } from 'types/collection'; import { sleep } from 'utils/common'; -import { handleSharingErrors } from 'utils/error'; import constants from 'utils/strings/constants'; import { ManageSectionLabel, ManageSectionOptions, } from '../../styledComponents'; import { ManageDownloadAccess } from './downloadAccess'; +import { handleSharingErrors } from 'utils/error/ui'; export default function PublicShareManage({ publicShareProp, diff --git a/src/components/Collections/CollectionShare/publicShare/manage/linkExpiry.tsx b/src/components/Collections/CollectionShare/publicShare/manage/linkExpiry.tsx index a7175d206..d3bf4e635 100644 --- a/src/components/Collections/CollectionShare/publicShare/manage/linkExpiry.tsx +++ b/src/components/Collections/CollectionShare/publicShare/manage/linkExpiry.tsx @@ -4,7 +4,7 @@ import Select from 'react-select'; import { linkExpiryStyle } from 'styles/linkExpiry'; import { shareExpiryOptions } from 'utils/collection'; import constants from 'utils/strings/constants'; -import { dateStringWithMMH } from 'utils/time'; +import { formatDateTime } from 'utils/time/format'; import { OptionWithDivider } from './selectComponents/OptionWithDivider'; export function ManageLinkExpiry({ @@ -31,7 +31,7 @@ export function ManageLinkExpiry({ }} placeholder={ publicShareProp?.validTill - ? dateStringWithMMH(publicShareProp?.validTill) + ? formatDateTime(publicShareProp?.validTill / 1000) : 'never' } onChange={(e) => { diff --git a/src/components/Collections/CollectionShare/publicShare/manage/linkPassword.tsx b/src/components/Collections/CollectionShare/publicShare/manage/linkPassword.tsx index 21334f20a..efa25cc37 100644 --- a/src/components/Collections/CollectionShare/publicShare/manage/linkPassword.tsx +++ b/src/components/Collections/CollectionShare/publicShare/manage/linkPassword.tsx @@ -1,5 +1,4 @@ import { Box, Typography } from '@mui/material'; -import { ButtonVariant } from 'components/pages/gallery/LinkButton'; import { AppContext } from 'pages/_app'; import React, { useContext } from 'react'; import constants from 'utils/strings/constants'; @@ -32,7 +31,7 @@ export function ManageLinkPassword({ collectionID: collection.id, disablePassword: true, }), - variant: ButtonVariant.danger, + variant: 'danger', }, }); }; diff --git a/src/components/DeleteBtn.tsx b/src/components/DeleteBtn.tsx deleted file mode 100644 index df4511cdd..000000000 --- a/src/components/DeleteBtn.tsx +++ /dev/null @@ -1,39 +0,0 @@ -import React from 'react'; -import { styled } from '@mui/material'; -import constants from 'utils/strings/constants'; -import { IconWithMessage } from './IconWithMessage'; - -const Wrapper = styled('button')` - border: none; - background-color: #ff6666; - position: fixed; - z-index: 1; - bottom: 30px; - right: 30px; - width: 60px; - height: 60px; - border-radius: 50%; - color: #fff; -`; -export default function DeleteBtn(props) { - return ( - - - - - - - - - ); -} - -DeleteBtn.defaultProps = { - height: 24, - width: 24, - viewBox: '0 0 24 24', -}; diff --git a/src/components/DialogBox/DialogIcon.tsx b/src/components/DialogBox/DialogIcon.tsx new file mode 100644 index 000000000..cebda8d7a --- /dev/null +++ b/src/components/DialogBox/DialogIcon.tsx @@ -0,0 +1,18 @@ +import { Box } from '@mui/material'; +import React from 'react'; + +export default function DialogIcon({ icon }: { icon: React.ReactNode }) { + return ( + + {icon} + + ); +} diff --git a/src/components/DialogBox/base.tsx b/src/components/DialogBox/base.tsx index 395c55cc6..1b4ddf092 100644 --- a/src/components/DialogBox/base.tsx +++ b/src/components/DialogBox/base.tsx @@ -5,6 +5,12 @@ const DialogBoxBase = styled(Dialog)(({ theme }) => ({ padding: theme.spacing(1, 1.5), maxWidth: '346px', }, + + '& .DialogIcon': { + padding: theme.spacing(2), + paddingBottom: theme.spacing(1), + }, + '& .MuiDialogTitle-root': { padding: theme.spacing(2), paddingBottom: theme.spacing(1), @@ -12,6 +18,11 @@ const DialogBoxBase = styled(Dialog)(({ theme }) => ({ '& .MuiDialogContent-root': { padding: theme.spacing(2), }, + + '.DialogIcon + .MuiDialogTitle-root': { + paddingTop: 0, + }, + '.MuiDialogTitle-root + .MuiDialogContent-root': { paddingTop: 0, }, diff --git a/src/components/DialogBox/index.tsx b/src/components/DialogBox/index.tsx index 5f70304c6..fce23fd69 100644 --- a/src/components/DialogBox/index.tsx +++ b/src/components/DialogBox/index.tsx @@ -13,6 +13,7 @@ import DialogTitleWithCloseButton, { } from './TitleWithCloseButton'; import DialogBoxBase from './base'; import { DialogBoxAttributes } from 'types/dialogBox'; +import DialogIcon from './DialogIcon'; type IProps = React.PropsWithChildren< Omit & { @@ -48,6 +49,7 @@ export default function DialogBox({ maxWidth={size} onClose={handleClose} {...props}> + {attributes.icon && } {attributes.title && ( ( - - )} + renderInput={() => <>} /> ); diff --git a/src/components/EnteDrawer.tsx b/src/components/EnteDrawer.tsx new file mode 100644 index 000000000..5c860e9d6 --- /dev/null +++ b/src/components/EnteDrawer.tsx @@ -0,0 +1,11 @@ +import { Drawer } from '@mui/material'; +import styled from 'styled-components'; + +export const EnteDrawer = styled(Drawer)(({ theme }) => ({ + '& .MuiPaper-root': { + maxWidth: '375px', + width: '100%', + scrollbarWidth: 'thin', + padding: theme.spacing(1), + }, +})); diff --git a/src/components/ExportFinished.tsx b/src/components/ExportFinished.tsx index 07701b9f2..175d91248 100644 --- a/src/components/ExportFinished.tsx +++ b/src/components/ExportFinished.tsx @@ -1,8 +1,8 @@ import { Button, DialogActions, DialogContent, Stack } from '@mui/material'; import React from 'react'; import { ExportStats } from 'types/export'; -import { formatDateTime } from 'utils/time'; import constants from 'utils/strings/constants'; +import { formatDateTime } from 'utils/time/format'; import { FlexWrapper, Label, Value } from './Container'; import { ComfySpan } from './ExportInProgress'; diff --git a/src/components/IconWithMessage.tsx b/src/components/IconWithMessage.tsx deleted file mode 100644 index 0f8ea7d58..000000000 --- a/src/components/IconWithMessage.tsx +++ /dev/null @@ -1,19 +0,0 @@ -import { OverlayTrigger, Tooltip } from 'react-bootstrap'; -import React from 'react'; - -interface IconWithMessageProps { - children?: any; - message: string; -} - -export const IconWithMessage = (props: IconWithMessageProps) => ( - - {props.message} - - }> - {props.children} - -); diff --git a/src/components/Notification.tsx b/src/components/Notification.tsx index 4bb83142a..416c8570e 100644 --- a/src/components/Notification.tsx +++ b/src/components/Notification.tsx @@ -31,7 +31,7 @@ export default function Notification({ open, onClose, attributes }: Iprops) { }; const handleClick = () => { - attributes.action?.callback(); + attributes.onClick(); onClose(); }; return ( @@ -40,14 +40,15 @@ export default function Notification({ open, onClose, attributes }: Iprops) { anchorOrigin={{ horizontal: 'right', vertical: 'bottom', - }}> + }} + sx={{ backgroundColor: '#000', width: '320px' }}> theme.spacing(1.5, 2), }}> - - {attributes?.icon ?? } + + {attributes.startIcon ?? } - - - {attributes.message}{' '} - - {attributes?.action && ( - - {attributes?.action.text} + + + {attributes.subtext && ( + + {attributes.subtext} )} - - + {attributes.message && ( + + {attributes.message} + + )} + + + {attributes.endIcon ? ( + onClick={attributes.onClick} + sx={{ fontSize: '36px' }}> + {attributes?.endIcon} + + ) : ( + - + )} diff --git a/src/components/PhotoFrame.tsx b/src/components/PhotoFrame.tsx index 780563cd0..8b2008679 100644 --- a/src/components/PhotoFrame.tsx +++ b/src/components/PhotoFrame.tsx @@ -1,12 +1,12 @@ import { GalleryContext } from 'pages/gallery'; import PreviewCard from './pages/gallery/PreviewCard'; -import React, { useContext, useEffect, useRef, useState } from 'react'; +import React, { useContext, useEffect, useState } from 'react'; import { EnteFile } from 'types/file'; import { styled } from '@mui/material'; import DownloadManager from 'services/downloadManager'; import constants from 'utils/strings/constants'; import AutoSizer from 'react-virtualized-auto-sizer'; -import PhotoSwipe from 'components/PhotoSwipe'; +import PhotoViewer from 'components/PhotoViewer'; import { ALL_SECTION, ARCHIVE_SECTION, @@ -15,7 +15,7 @@ import { import { isSharedFile } from 'utils/file'; import { isPlaybackPossible } from 'utils/photoFrame'; import { PhotoList } from './PhotoList'; -import { SetFiles, SelectedState } from 'types/gallery'; +import { SelectedState } from 'types/gallery'; import { FILE_TYPE } from 'constants/file'; import PublicCollectionDownloadManager from 'services/publicCollectionDownloadManager'; import { PublicCollectionGalleryContext } from 'utils/publicCollectionGallery'; @@ -30,6 +30,8 @@ import { logError } from 'utils/sentry'; import { CustomError } from 'utils/error'; import { User } from 'types/user'; import { getData, LS_KEYS } from 'utils/storage/localStorage'; +import { useMemo } from 'react'; +import { Collection } from 'types/collection'; const Container = styled('div')` display: block; @@ -48,7 +50,7 @@ const PHOTOSWIPE_HASH_SUFFIX = '&opened'; interface Props { files: EnteFile[]; - setFiles: SetFiles; + collections?: Collection[]; syncWithRemote: () => Promise; favItemIds?: Set; archivedCollections?: Set; @@ -60,7 +62,8 @@ interface Props { openUploader?; isInSearchMode?: boolean; search?: Search; - deleted?: number[]; + deletedFileIds?: Set; + setDeletedFileIds?: (value: Set) => void; activeCollection: number; isSharedCollection?: boolean; enableDownload?: boolean; @@ -69,13 +72,15 @@ interface Props { } type SourceURL = { - imageURL?: string; - videoURL?: string; + originalImageURL?: string; + originalVideoURL?: string; + convertedImageURL?: string; + convertedVideoURL?: string; }; const PhotoFrame = ({ files, - setFiles, + collections, syncWithRemote, favItemIds, archivedCollections, @@ -86,7 +91,8 @@ const PhotoFrame = ({ isInSearchMode, search, resetSearch, - deleted, + deletedFileIds, + setDeletedFileIds, activeCollection, isSharedCollection, enableDownload, @@ -104,75 +110,26 @@ const PhotoFrame = ({ const [rangeStart, setRangeStart] = useState(null); const [currentHover, setCurrentHover] = useState(null); const [isShiftKeyPressed, setIsShiftKeyPressed] = useState(false); - const filteredDataRef = useRef([]); - const filteredData = filteredDataRef?.current ?? []; const router = useRouter(); const [isSourceLoaded, setIsSourceLoaded] = useState(false); - useEffect(() => { - const handleKeyDown = (e: KeyboardEvent) => { - if (e.key === 'Shift') { - setIsShiftKeyPressed(true); - } - }; - const handleKeyUp = (e: KeyboardEvent) => { - if (e.key === 'Shift') { - setIsShiftKeyPressed(false); - } - }; - document.addEventListener('keydown', handleKeyDown, false); - document.addEventListener('keyup', handleKeyUp, false); - router.events.on('hashChangeComplete', (url: string) => { - const start = url.indexOf('#'); - const hash = url.slice(start !== -1 ? start : url.length); - const shouldPhotoSwipeBeOpened = hash.endsWith( - PHOTOSWIPE_HASH_SUFFIX - ); - if (shouldPhotoSwipeBeOpened) { - setOpen(true); - } else { - setOpen(false); - } - }); - return () => { - document.addEventListener('keydown', handleKeyDown, false); - document.addEventListener('keyup', handleKeyUp, false); - }; - }, []); - useEffect(() => { - if (!isNaN(search?.file)) { - const filteredDataIdx = filteredData.findIndex((file) => { - return file.id === search.file; - }); - if (!isNaN(filteredDataIdx)) { - onThumbnailClick(filteredDataIdx)(); - } - resetSearch(); - } - }, [search, filteredData]); - - const resetFetching = () => { - setFetching({}); - }; - - useEffect(() => { - if (selected.count === 0) { - setRangeStart(null); - } - }, [selected]); - - useEffect(() => { + const filteredData = useMemo(() => { const idSet = new Set(); const user: User = getData(LS_KEYS.USER); - filteredDataRef.current = files + + return files .map((item, index) => ({ ...item, dataIndex: index, w: window.innerWidth, h: window.innerHeight, + title: item.pubMagicMetadata?.data.caption, })) .filter((item) => { - if (deleted?.includes(item.id)) { + if ( + deletedFileIds?.has(item.id) && + activeCollection !== TRASH_SECTION + ) { return false; } if ( @@ -230,7 +187,31 @@ const PhotoFrame = ({ } return false; }); - }, [files, deleted, search, activeCollection]); + }, [files, deletedFileIds, search, activeCollection]); + + const fileToCollectionsMap = useMemo(() => { + const fileToCollectionsMap = new Map(); + files.forEach((file) => { + if (!fileToCollectionsMap.get(file.id)) { + fileToCollectionsMap.set(file.id, []); + } + fileToCollectionsMap.get(file.id).push(file.collectionID); + }); + return fileToCollectionsMap; + }, [files]); + + const collectionNameMap = useMemo(() => { + if (collections) { + return new Map( + collections.map((collection) => [ + collection.id, + collection.name, + ]) + ); + } else { + return new Map(); + } + }, [collections]); useEffect(() => { const currentURL = new URL(window.location.href); @@ -247,6 +228,59 @@ const PhotoFrame = ({ } }, [open]); + useEffect(() => { + const handleKeyDown = (e: KeyboardEvent) => { + if (e.key === 'Shift') { + setIsShiftKeyPressed(true); + } + }; + const handleKeyUp = (e: KeyboardEvent) => { + if (e.key === 'Shift') { + setIsShiftKeyPressed(false); + } + }; + document.addEventListener('keydown', handleKeyDown, false); + document.addEventListener('keyup', handleKeyUp, false); + router.events.on('hashChangeComplete', (url: string) => { + const start = url.indexOf('#'); + const hash = url.slice(start !== -1 ? start : url.length); + const shouldPhotoSwipeBeOpened = hash.endsWith( + PHOTOSWIPE_HASH_SUFFIX + ); + if (shouldPhotoSwipeBeOpened) { + setOpen(true); + } else { + setOpen(false); + } + }); + return () => { + document.addEventListener('keydown', handleKeyDown, false); + document.addEventListener('keyup', handleKeyUp, false); + }; + }, []); + + useEffect(() => { + if (!isNaN(search?.file)) { + const filteredDataIdx = filteredData.findIndex((file) => { + return file.id === search.file; + }); + if (!isNaN(filteredDataIdx)) { + onThumbnailClick(filteredDataIdx)(); + } + resetSearch(); + } + }, [search, filteredData]); + + const resetFetching = () => { + setFetching({}); + }; + + useEffect(() => { + if (selected.count === 0) { + setRangeStart(null); + } + }, [selected]); + const getFileIndexFromID = (files: EnteFile[], id: number) => { const index = files.findIndex((file) => file.id === id); if (index === -1) { @@ -257,12 +291,10 @@ const PhotoFrame = ({ const updateURL = (id: number) => (url: string) => { const updateFile = (file: EnteFile) => { - file = { - ...file, - msrc: url, - w: window.innerWidth, - h: window.innerHeight, - }; + file.msrc = url; + file.w = window.innerWidth; + file.h = window.innerHeight; + if (file.metadata.fileType === FILE_TYPE.VIDEO && !file.html) { file.html = `
@@ -292,29 +324,30 @@ const PhotoFrame = ({ } return file; }; - setFiles((files) => { - const index = getFileIndexFromID(files, id); - files[index] = updateFile(files[index]); - return files; - }); const index = getFileIndexFromID(files, id); return updateFile(files[index]); }; const updateSrcURL = async (id: number, srcURL: SourceURL) => { - const { videoURL, imageURL } = srcURL; - const isPlayable = videoURL && (await isPlaybackPossible(videoURL)); + const { + originalImageURL, + convertedImageURL, + originalVideoURL, + convertedVideoURL, + } = srcURL; + const isPlayable = + convertedVideoURL && (await isPlaybackPossible(convertedVideoURL)); const updateFile = (file: EnteFile) => { - file = { - ...file, - w: window.innerWidth, - h: window.innerHeight, - }; + file.w = window.innerWidth; + file.h = window.innerHeight; + file.isSourceLoaded = true; + file.originalImageURL = originalImageURL; + file.originalVideoURL = originalVideoURL; if (file.metadata.fileType === FILE_TYPE.VIDEO) { if (isPlayable) { file.html = ` `; @@ -324,7 +357,7 @@ const PhotoFrame = ({
${constants.VIDEO_PLAYBACK_FAILED_DOWNLOAD_INSTEAD} - Download + Download
`; @@ -333,9 +366,9 @@ const PhotoFrame = ({ if (isPlayable) { file.html = `
- +
@@ -352,15 +385,10 @@ const PhotoFrame = ({ `; } } else { - file.src = imageURL; + file.src = convertedImageURL; } return file; }; - setFiles((files) => { - const index = getFileIndexFromID(files, id); - files[index] = updateFile(files[index]); - return files; - }); setIsSourceLoaded(true); const index = getFileIndexFromID(files, id); return updateFile(files[index]); @@ -426,7 +454,11 @@ const PhotoFrame = ({ handleSelect(filteredData[index].id, index)(!checked); } }; - const getThumbnail = (files: EnteFile[], index: number) => + const getThumbnail = ( + files: EnteFile[], + index: number, + isScrolling: boolean + ) => files[index] ? ( = currentHover && index <= rangeStart) } activeCollection={activeCollection} + showPlaceholder={isScrolling} /> ) : ( <> @@ -484,6 +517,9 @@ const PhotoFrame = ({ item.msrc = newFile.msrc; item.html = newFile.html; item.src = newFile.src; + item.isSourceLoaded = newFile.isSourceLoaded; + item.originalImageURL = newFile.originalImageURL; + item.originalVideoURL = newFile.originalVideoURL; item.w = newFile.w; item.h = newFile.h; @@ -506,10 +542,13 @@ const PhotoFrame = ({ if (!fetching[item.id]) { try { fetching[item.id] = true; - let urls: string[]; + let urls: { original: string[]; converted: string[] }; if (galleryContext.files.has(item.id)) { const mergedURL = galleryContext.files.get(item.id); - urls = mergedURL.split(','); + urls = { + original: mergedURL.original.split(','), + converted: mergedURL.converted.split(','), + }; } else { appContext.startLoading(); if ( @@ -525,26 +564,39 @@ const PhotoFrame = ({ urls = await DownloadManager.getFile(item, true); } appContext.finishLoading(); - const mergedURL = urls.join(','); + const mergedURL = { + original: urls.original.join(','), + converted: urls.converted.join(','), + }; galleryContext.files.set(item.id, mergedURL); } - let imageURL; - let videoURL; + let originalImageURL; + let originalVideoURL; + let convertedImageURL; + let convertedVideoURL; + if (item.metadata.fileType === FILE_TYPE.LIVE_PHOTO) { - [imageURL, videoURL] = urls; + [originalImageURL, originalVideoURL] = urls.converted; } else if (item.metadata.fileType === FILE_TYPE.VIDEO) { - [videoURL] = urls; + [originalVideoURL] = urls.original; + [convertedVideoURL] = urls.converted; } else { - [imageURL] = urls; + [originalImageURL] = urls.original; + [convertedImageURL] = urls.converted; } setIsSourceLoaded(false); const newFile = await updateSrcURL(item.id, { - imageURL, - videoURL, + originalImageURL, + originalVideoURL, + convertedImageURL, + convertedVideoURL, }); item.msrc = newFile.msrc; item.html = newFile.html; item.src = newFile.src; + item.isSourceLoaded = newFile.isSourceLoaded; + item.originalImageURL = newFile.originalImageURL; + item.originalVideoURL = newFile.originalVideoURL; item.w = newFile.w; item.h = newFile.h; try { @@ -591,17 +643,21 @@ const PhotoFrame = ({ /> )} - )} diff --git a/src/components/PhotoList.tsx b/src/components/PhotoList.tsx index b2157f12c..05c8e0185 100644 --- a/src/components/PhotoList.tsx +++ b/src/components/PhotoList.tsx @@ -1,6 +1,6 @@ import React, { useRef, useEffect, useContext } from 'react'; import { VariableSizeList as List } from 'react-window'; -import { Box, styled } from '@mui/material'; +import { Box, Link, styled } from '@mui/material'; import { EnteFile } from 'types/file'; import { IMAGE_CONTAINER_MAX_HEIGHT, @@ -15,16 +15,15 @@ import { import constants from 'utils/strings/constants'; import { PublicCollectionGalleryContext } from 'utils/publicCollectionGallery'; import { ENTE_WEBSITE_LINK } from 'constants/urls'; -import { getVariantColor, ButtonVariant } from './pages/gallery/LinkButton'; import { convertBytesToHumanReadable } from 'utils/file/size'; import { DeduplicateContext } from 'pages/deduplicate'; import { FlexWrapper } from './Container'; import { Typography } from '@mui/material'; import { GalleryContext } from 'pages/gallery'; import { SpecialPadding } from 'styles/SpecialPadding'; +import { formatDate } from 'utils/time/format'; const A_DAY = 24 * 60 * 60 * 1000; -const NO_OF_PAGES = 2; const FOOTER_HEIGHT = 90; export enum ITEM_TYPE { @@ -153,7 +152,11 @@ interface Props { width: number; filteredData: EnteFile[]; showAppDownloadBanner: boolean; - getThumbnail: (files: EnteFile[], index: number) => JSX.Element; + getThumbnail: ( + files: EnteFile[], + index: number, + isScrolling?: boolean + ) => JSX.Element; activeCollection: number; resetFetching: () => void; } @@ -244,6 +247,10 @@ export function PhotoList({ filteredData, showAppDownloadBanner, publicCollectionGalleryContext.accessedThroughSharedURL, + galleryContext.photoListHeader, + publicCollectionGalleryContext.photoListHeader, + deduplicateContext.isOnDeduplicatePage, + deduplicateContext.fileSizeMap, ]); const groupByFileSize = (timeStampList: TimeStampListItem[]) => { @@ -298,22 +305,17 @@ export function PhotoList({ ) ) { currentDate = item.metadata.creationTime / 1000; - const dateTimeFormat = new Intl.DateTimeFormat('en-IN', { - weekday: 'short', - year: 'numeric', - month: 'short', - day: 'numeric', - }); + timeStampList.push({ itemType: ITEM_TYPE.TIME, date: isSameDay(new Date(currentDate), new Date()) - ? 'Today' + ? constants.TODAY : isSameDay( new Date(currentDate), new Date(Date.now() - A_DAY) ) - ? 'Yesterday' - : dateTimeFormat.format(currentDate), + ? constants.YESTERDAY + : formatDate(currentDate), id: currentDate.toString(), }); timeStampList.push({ @@ -403,15 +405,9 @@ export function PhotoList({

{constants.PRESERVED_BY}{' '} - + {constants.ENTE_IO} - +

), @@ -453,9 +449,10 @@ export function PhotoList({ date: currItem.date, span: items[index + 1].items.length, }); - newList[newIndex + 1].items = newList[ - newIndex + 1 - ].items.concat(items[index + 1].items); + newList[newIndex + 1].items = [ + ...newList[newIndex + 1].items, + ...items[index + 1].items, + ]; index += 2; } else { // Adding items would exceed the number of columns. @@ -512,10 +509,6 @@ export function PhotoList({ } }; - const extraRowsToRender = Math.ceil( - (NO_OF_PAGES * height) / IMAGE_CONTAINER_MAX_HEIGHT - ); - const generateKey = (index) => { switch (timeStampList[index].itemType) { case ITEM_TYPE.FILE: @@ -527,7 +520,10 @@ export function PhotoList({ } }; - const renderListItem = (listItem: TimeStampListItem) => { + const renderListItem = ( + listItem: TimeStampListItem, + isScrolling: boolean + ) => { switch (listItem.itemType) { case ITEM_TYPE.TIME: return listItem.dates ? ( @@ -556,7 +552,8 @@ export function PhotoList({ const ret = listItem.items.map((item, idx) => getThumbnail( filteredDataCopy, - listItem.itemStartIndex + idx + listItem.itemStartIndex + idx, + isScrolling ) ); if (listItem.groups) { @@ -587,14 +584,15 @@ export function PhotoList({ width={width} itemCount={timeStampList.length} itemKey={generateKey} - overscanCount={extraRowsToRender}> - {({ index, style }) => ( + overscanCount={0} + useIsScrolling> + {({ index, style, isScrolling }) => ( - {renderListItem(timeStampList[index])} + {renderListItem(timeStampList[index], isScrolling)} )} diff --git a/src/components/PhotoSwipe/InfoDialog/ExifData.tsx b/src/components/PhotoSwipe/InfoDialog/ExifData.tsx deleted file mode 100644 index 741ee2086..000000000 --- a/src/components/PhotoSwipe/InfoDialog/ExifData.tsx +++ /dev/null @@ -1,73 +0,0 @@ -import React, { useState } from 'react'; -import constants from 'utils/strings/constants'; - -import { RenderInfoItem } from './RenderInfoItem'; -import { LegendContainer } from '../styledComponents/LegendContainer'; -import { Pre } from '../styledComponents/Pre'; -import { - Checkbox, - FormControlLabel, - FormGroup, - Typography, -} from '@mui/material'; - -export function ExifData(props: { exif: any }) { - const { exif } = props; - const [showAll, setShowAll] = useState(false); - - const changeHandler = (e: React.ChangeEvent) => { - setShowAll(e.target.checked); - }; - - const renderAllValues = () =>
{exif.raw}
; - - const renderSelectedValues = () => ( - <> - {exif?.Make && - exif?.Model && - RenderInfoItem(constants.DEVICE, `${exif.Make} ${exif.Model}`)} - {exif?.ImageWidth && - exif?.ImageHeight && - RenderInfoItem( - constants.IMAGE_SIZE, - `${exif.ImageWidth} x ${exif.ImageHeight}` - )} - {exif?.Flash && RenderInfoItem(constants.FLASH, exif.Flash)} - {exif?.FocalLength && - RenderInfoItem( - constants.FOCAL_LENGTH, - exif.FocalLength.toString() - )} - {exif?.ApertureValue && - RenderInfoItem( - constants.APERTURE, - exif.ApertureValue.toString() - )} - {exif?.ISOSpeedRatings && - RenderInfoItem(constants.ISO, exif.ISOSpeedRatings.toString())} - - ); - - return ( - <> - - - {constants.EXIF} - - - - } - label={constants.SHOW_ALL} - /> - - - {showAll ? renderAllValues() : renderSelectedValues()} - - ); -} diff --git a/src/components/PhotoSwipe/InfoDialog/FileNameEditForm.tsx b/src/components/PhotoSwipe/InfoDialog/FileNameEditForm.tsx deleted file mode 100644 index 5bf96314f..000000000 --- a/src/components/PhotoSwipe/InfoDialog/FileNameEditForm.tsx +++ /dev/null @@ -1,100 +0,0 @@ -import React, { useState } from 'react'; -import constants from 'utils/strings/constants'; -import { Col, Form, FormControl } from 'react-bootstrap'; -import { FlexWrapper, Value } from 'components/Container'; -import CloseIcon from '@mui/icons-material/Close'; -import TickIcon from '@mui/icons-material/Done'; -import { Formik } from 'formik'; -import * as Yup from 'yup'; -import { MAX_EDITED_FILE_NAME_LENGTH } from 'constants/file'; -import { SmallLoadingSpinner } from '../styledComponents/SmallLoadingSpinner'; -import { IconButton } from '@mui/material'; - -export interface formValues { - filename: string; -} - -export const FileNameEditForm = ({ - filename, - saveEdits, - discardEdits, - extension, -}) => { - const [loading, setLoading] = useState(false); - - const onSubmit = async (values: formValues) => { - try { - setLoading(true); - await saveEdits(values.filename); - } finally { - setLoading(false); - } - }; - return ( - - initialValues={{ filename }} - validationSchema={Yup.object().shape({ - filename: Yup.string() - .required(constants.REQUIRED) - .max( - MAX_EDITED_FILE_NAME_LENGTH, - constants.FILE_NAME_CHARACTER_LIMIT - ), - })} - validateOnBlur={false} - onSubmit={onSubmit}> - {({ values, errors, handleChange, handleSubmit }) => ( -
- - - - - {errors.filename} - - - {extension && ( - - - {`.${extension}`} - - - )} - - - - {loading ? ( - - ) : ( - - )} - - - - - - - -
- )} - - ); -}; diff --git a/src/components/PhotoSwipe/InfoDialog/RenderFileName.tsx b/src/components/PhotoSwipe/InfoDialog/RenderFileName.tsx deleted file mode 100644 index ea4df744e..000000000 --- a/src/components/PhotoSwipe/InfoDialog/RenderFileName.tsx +++ /dev/null @@ -1,98 +0,0 @@ -import React, { useState } from 'react'; -import { updateFilePublicMagicMetadata } from 'services/fileService'; -import { EnteFile } from 'types/file'; -import constants from 'utils/strings/constants'; -import { - changeFileName, - splitFilenameAndExtension, - updateExistingFilePubMetadata, -} from 'utils/file'; -import EditIcon from '@mui/icons-material/Edit'; -import { FreeFlowText, Label, Row, Value } from 'components/Container'; -import { logError } from 'utils/sentry'; -import { FileNameEditForm } from './FileNameEditForm'; -import { IconButton } from '@mui/material'; - -export const getFileTitle = (filename, extension) => { - if (extension) { - return filename + '.' + extension; - } else { - return filename; - } -}; - -export function RenderFileName({ - shouldDisableEdits, - file, - scheduleUpdate, -}: { - shouldDisableEdits: boolean; - file: EnteFile; - scheduleUpdate: () => void; -}) { - const originalTitle = file?.metadata.title; - const [isInEditMode, setIsInEditMode] = useState(false); - const [originalFileName, extension] = - splitFilenameAndExtension(originalTitle); - const [filename, setFilename] = useState(originalFileName); - const openEditMode = () => setIsInEditMode(true); - const closeEditMode = () => setIsInEditMode(false); - - const saveEdits = async (newFilename: string) => { - try { - if (file) { - if (filename === newFilename) { - closeEditMode(); - return; - } - setFilename(newFilename); - const newTitle = getFileTitle(newFilename, extension); - let updatedFile = await changeFileName(file, newTitle); - updatedFile = ( - await updateFilePublicMagicMetadata([updatedFile]) - )[0]; - updateExistingFilePubMetadata(file, updatedFile); - scheduleUpdate(); - } - } catch (e) { - logError(e, 'failed to update file name'); - } finally { - closeEditMode(); - } - }; - return ( - <> - - - {!isInEditMode ? ( - <> - - - {getFileTitle(filename, extension)} - - - {!shouldDisableEdits && ( - - - - - - )} - - ) : ( - - )} - - - ); -} diff --git a/src/components/PhotoSwipe/InfoDialog/index.tsx b/src/components/PhotoSwipe/InfoDialog/index.tsx deleted file mode 100644 index 133390b86..000000000 --- a/src/components/PhotoSwipe/InfoDialog/index.tsx +++ /dev/null @@ -1,123 +0,0 @@ -import React, { useContext, useEffect, useState } from 'react'; -import constants from 'utils/strings/constants'; -import { formatDateTime } from 'utils/time'; -import { RenderFileName } from './RenderFileName'; -import { ExifData } from './ExifData'; -import { RenderCreationTime } from './RenderCreationTime'; -import { RenderInfoItem } from './RenderInfoItem'; -import DialogTitleWithCloseButton from 'components/DialogBox/TitleWithCloseButton'; -import { Dialog, DialogContent, Link, styled, Typography } from '@mui/material'; -import { AppContext } from 'pages/_app'; -import { Location, Metadata } from 'types/upload'; -import Photoswipe from 'photoswipe'; -import { getEXIFLocation } from 'services/upload/exifService'; - -const FileInfoDialog = styled(Dialog)(({ theme }) => ({ - zIndex: 1501, - '& .MuiDialog-container': { - alignItems: 'flex-start', - }, - '& .MuiDialog-paper': { - padding: theme.spacing(2), - }, -})); - -interface Iprops { - shouldDisableEdits: boolean; - showInfo: boolean; - handleCloseInfo: () => void; - items: any[]; - photoSwipe: Photoswipe; - metadata: Metadata; - exif: any; - scheduleUpdate: () => void; -} - -export function FileInfo({ - shouldDisableEdits, - showInfo, - handleCloseInfo, - items, - photoSwipe, - metadata, - exif, - scheduleUpdate, -}: Iprops) { - const appContext = useContext(AppContext); - const [location, setLocation] = useState(null); - - useEffect(() => { - if (!location && metadata) { - if (metadata.longitude || metadata.longitude === 0) { - setLocation({ - latitude: metadata.latitude, - longitude: metadata.longitude, - }); - } - } - }, [metadata]); - - useEffect(() => { - if (!location && exif) { - const exifLocation = getEXIFLocation(exif); - if (exifLocation.latitude || exifLocation.latitude === 0) { - setLocation(exifLocation); - } - } - }, [exif]); - - return ( - - - {constants.INFO} - - - - {constants.METADATA} - - - {RenderInfoItem( - constants.FILE_ID, - items[photoSwipe?.getCurrentIndex()]?.id - )} - {metadata?.title && ( - - )} - {metadata?.creationTime && ( - - )} - {metadata?.modificationTime && - RenderInfoItem( - constants.UPDATED_ON, - formatDateTime(metadata.modificationTime / 1000) - )} - {location && - RenderInfoItem( - constants.LOCATION, - - {constants.SHOW_MAP} - - )} - {exif && ( - <> - - - )} - - - ); -} diff --git a/src/components/PhotoViewer/FileInfo/ExifData.tsx b/src/components/PhotoViewer/FileInfo/ExifData.tsx new file mode 100644 index 000000000..411c90790 --- /dev/null +++ b/src/components/PhotoViewer/FileInfo/ExifData.tsx @@ -0,0 +1,92 @@ +import React from 'react'; +import constants from 'utils/strings/constants'; + +import { Stack, styled, Typography } from '@mui/material'; +import { FileInfoSidebar } from '.'; +import Titlebar from 'components/Titlebar'; +import { Box } from '@mui/system'; +import CopyButton from 'components/CodeBlock/CopyButton'; +import { formatDateFull } from 'utils/time/format'; + +const ExifItem = styled(Box)` + padding-left: 8px; + padding-right: 8px; + display: flex; + flex-direction: column; + gap: 4px; +`; + +function parseExifValue(value: any) { + switch (typeof value) { + case 'string': + case 'number': + return value; + default: + if (value instanceof Date) { + return formatDateFull(value); + } + try { + return JSON.stringify(Array.from(value)); + } catch (e) { + return null; + } + } +} +export function ExifData(props: { + exif: any; + open: boolean; + onClose: () => void; + filename: string; + onInfoClose: () => void; +}) { + const { exif, open, onClose, filename, onInfoClose } = props; + + if (!exif) { + return <>; + } + const handleRootClose = () => { + onClose(); + onInfoClose(); + }; + + return ( + + + } + /> + + {[...Object.entries(exif)].map(([key, value]) => + value ? ( + + + {key} + + + {parseExifValue(value)} + + + ) : ( + <> + ) + )} + + + ); +} diff --git a/src/components/PhotoViewer/FileInfo/FileNameEditDialog.tsx b/src/components/PhotoViewer/FileInfo/FileNameEditDialog.tsx new file mode 100644 index 000000000..d4bf98ced --- /dev/null +++ b/src/components/PhotoViewer/FileInfo/FileNameEditDialog.tsx @@ -0,0 +1,51 @@ +import React from 'react'; +import constants from 'utils/strings/constants'; +import { DialogContent, DialogTitle } from '@mui/material'; +import DialogBoxBase from 'components/DialogBox/base'; +import SingleInputForm, { + SingleInputFormProps, +} from 'components/SingleInputForm'; + +export interface formValues { + filename: string; +} + +export const FileNameEditDialog = ({ + isInEditMode, + closeEditMode, + filename, + extension, + saveEdits, +}) => { + const onSubmit: SingleInputFormProps['callback'] = async ( + filename, + setFieldError + ) => { + try { + await saveEdits(filename); + closeEditMode(); + } catch (e) { + setFieldError(constants.UNKNOWN_ERROR); + } + }; + return ( + + {constants.RENAME_FILE} + + + + + ); +}; diff --git a/src/components/PhotoViewer/FileInfo/InfoItem.tsx b/src/components/PhotoViewer/FileInfo/InfoItem.tsx new file mode 100644 index 000000000..566316689 --- /dev/null +++ b/src/components/PhotoViewer/FileInfo/InfoItem.tsx @@ -0,0 +1,61 @@ +import Edit from '@mui/icons-material/Edit'; +import { Box, IconButton, Typography } from '@mui/material'; +import { FlexWrapper } from 'components/Container'; +import React from 'react'; +import { SmallLoadingSpinner } from '../styledComponents/SmallLoadingSpinner'; + +interface Iprops { + icon: JSX.Element; + title?: string; + caption?: string | JSX.Element; + openEditor?: any; + loading?: boolean; + hideEditOption?: any; + customEndButton?: any; + children?: any; +} + +export default function InfoItem({ + icon, + title, + caption, + openEditor, + loading, + hideEditOption, + customEndButton, + children, +}: Iprops): JSX.Element { + return ( + + + + {icon} + + + {children ? ( + children + ) : ( + <> + + {title} + + + {caption} + + + )} + + + {customEndButton + ? customEndButton + : !hideEditOption && ( + + {!loading ? : } + + )} + + ); +} diff --git a/src/components/PhotoViewer/FileInfo/RenderCaption.tsx b/src/components/PhotoViewer/FileInfo/RenderCaption.tsx new file mode 100644 index 000000000..8665aaf29 --- /dev/null +++ b/src/components/PhotoViewer/FileInfo/RenderCaption.tsx @@ -0,0 +1,126 @@ +import React, { useState } from 'react'; +import { updateFilePublicMagicMetadata } from 'services/fileService'; +import { EnteFile } from 'types/file'; +import { changeCaption, updateExistingFilePubMetadata } from 'utils/file'; +import { logError } from 'utils/sentry'; +import { Box, IconButton, TextField } from '@mui/material'; +import { FlexWrapper } from 'components/Container'; +import { MAX_CAPTION_SIZE } from 'constants/file'; +import { Formik } from 'formik'; +import { SmallLoadingSpinner } from '../styledComponents/SmallLoadingSpinner'; +import * as Yup from 'yup'; +import constants from 'utils/strings/constants'; +import Close from '@mui/icons-material/Close'; +import { Done } from '@mui/icons-material'; + +export interface formValues { + caption: string; +} + +export function RenderCaption({ + file, + scheduleUpdate, + refreshPhotoswipe, +}: { + shouldDisableEdits: boolean; + file: EnteFile; + scheduleUpdate: () => void; + refreshPhotoswipe: () => void; +}) { + const [caption, setCaption] = useState( + file?.pubMagicMetadata?.data.caption + ); + + const [loading, setLoading] = useState(false); + + const saveEdits = async (newCaption: string) => { + try { + if (file) { + if (caption === newCaption) { + return; + } + setCaption(newCaption); + + let updatedFile = await changeCaption(file, newCaption); + updatedFile = ( + await updateFilePublicMagicMetadata([updatedFile]) + )[0]; + updateExistingFilePubMetadata(file, updatedFile); + file.title = file.pubMagicMetadata.data.caption; + refreshPhotoswipe(); + scheduleUpdate(); + } + } catch (e) { + logError(e, 'failed to update caption'); + } + }; + + const onSubmit = async (values: formValues) => { + try { + setLoading(true); + await saveEdits(values.caption); + } finally { + setLoading(false); + } + }; + return ( + + + initialValues={{ caption }} + validationSchema={Yup.object().shape({ + caption: Yup.string().max( + MAX_CAPTION_SIZE, + constants.CAPTION_CHARACTER_LIMIT + ), + })} + validateOnBlur={false} + onSubmit={onSubmit}> + {({ + values, + errors, + handleChange, + handleSubmit, + resetForm, + }) => ( +
+ + {values.caption !== caption && ( + + + {loading ? ( + + ) : ( + + )} + + + resetForm({ + values: { caption: caption ?? '' }, + touched: { caption: false }, + }) + } + disabled={loading}> + + + + )} + + )} + +
+ ); +} diff --git a/src/components/PhotoSwipe/InfoDialog/RenderCreationTime.tsx b/src/components/PhotoViewer/FileInfo/RenderCreationTime.tsx similarity index 52% rename from src/components/PhotoSwipe/InfoDialog/RenderCreationTime.tsx rename to src/components/PhotoViewer/FileInfo/RenderCreationTime.tsx index 967b4a14f..5a0c6662b 100644 --- a/src/components/PhotoSwipe/InfoDialog/RenderCreationTime.tsx +++ b/src/components/PhotoViewer/FileInfo/RenderCreationTime.tsx @@ -1,18 +1,16 @@ import React, { useState } from 'react'; import { updateFilePublicMagicMetadata } from 'services/fileService'; import { EnteFile } from 'types/file'; -import constants from 'utils/strings/constants'; +import CalendarTodayIcon from '@mui/icons-material/CalendarToday'; import { changeFileCreationTime, updateExistingFilePubMetadata, } from 'utils/file'; -import { formatDateTime } from 'utils/time'; -import EditIcon from '@mui/icons-material/Edit'; -import { Label, Row, Value } from 'components/Container'; +import { formatDate, formatTime } from 'utils/time/format'; +import { FlexWrapper } from 'components/Container'; import { logError } from 'utils/sentry'; -import { SmallLoadingSpinner } from '../styledComponents/SmallLoadingSpinner'; import EnteDateTimePicker from 'components/EnteDateTimePicker'; -import { IconButton } from '@mui/material'; +import InfoItem from './InfoItem'; export function RenderCreationTime({ shouldDisableEdits, @@ -59,39 +57,24 @@ export function RenderCreationTime({ return ( <> - - - - {isInEditMode ? ( - - ) : ( - formatDateTime(originalCreationTime) - )} - - {!shouldDisableEdits && !isInEditMode && ( - - {loading ? ( - - - - ) : ( - - - - )} - + + } + title={formatDate(originalCreationTime)} + caption={formatTime(originalCreationTime)} + openEditor={openEditMode} + loading={loading} + hideEditOption={shouldDisableEdits || isInEditMode} + /> + {isInEditMode && ( + )} - + ); } diff --git a/src/components/PhotoViewer/FileInfo/RenderFileName.tsx b/src/components/PhotoViewer/FileInfo/RenderFileName.tsx new file mode 100644 index 000000000..e2e31e062 --- /dev/null +++ b/src/components/PhotoViewer/FileInfo/RenderFileName.tsx @@ -0,0 +1,121 @@ +import React, { useEffect, useState } from 'react'; +import { updateFilePublicMagicMetadata } from 'services/fileService'; +import { EnteFile } from 'types/file'; +import { + changeFileName, + splitFilenameAndExtension, + updateExistingFilePubMetadata, +} from 'utils/file'; +import { FlexWrapper } from 'components/Container'; +import { logError } from 'utils/sentry'; +import { FILE_TYPE } from 'constants/file'; +import { PhotoOutlined, VideoFileOutlined } from '@mui/icons-material'; +import InfoItem from './InfoItem'; +import { makeHumanReadableStorage } from 'utils/billing'; +import Box from '@mui/material/Box'; +import { FileNameEditDialog } from './FileNameEditDialog'; + +const getFileTitle = (filename, extension) => { + if (extension) { + return filename + '.' + extension; + } else { + return filename; + } +}; + +const getCaption = (file: EnteFile, parsedExifData) => { + const megaPixels = parsedExifData?.['megaPixels']; + const resolution = parsedExifData?.['resolution']; + const fileSize = file.info?.fileSize; + + const captionParts = []; + if (megaPixels) { + captionParts.push(megaPixels); + } + if (resolution) { + captionParts.push(resolution); + } + if (fileSize) { + captionParts.push(makeHumanReadableStorage(fileSize)); + } + return ( + + {captionParts.map((caption) => ( + {caption} + ))} + + ); +}; + +export function RenderFileName({ + parsedExifData, + shouldDisableEdits, + file, + scheduleUpdate, +}: { + parsedExifData: Record; + shouldDisableEdits: boolean; + file: EnteFile; + scheduleUpdate: () => void; +}) { + const [isInEditMode, setIsInEditMode] = useState(false); + const openEditMode = () => setIsInEditMode(true); + const closeEditMode = () => setIsInEditMode(false); + const [filename, setFilename] = useState(); + const [extension, setExtension] = useState(); + + useEffect(() => { + const [filename, extension] = splitFilenameAndExtension( + file.metadata.title + ); + setFilename(filename); + setExtension(extension); + }, []); + + const saveEdits = async (newFilename: string) => { + try { + if (file) { + if (filename === newFilename) { + closeEditMode(); + return; + } + setFilename(newFilename); + const newTitle = getFileTitle(newFilename, extension); + let updatedFile = await changeFileName(file, newTitle); + updatedFile = ( + await updateFilePublicMagicMetadata([updatedFile]) + )[0]; + updateExistingFilePubMetadata(file, updatedFile); + scheduleUpdate(); + } + } catch (e) { + logError(e, 'failed to update file name'); + throw e; + } + }; + + return ( + <> + + ) : ( + + ) + } + title={getFileTitle(filename, extension)} + caption={getCaption(file, parsedExifData)} + openEditor={openEditMode} + hideEditOption={shouldDisableEdits || isInEditMode} + /> + + + ); +} diff --git a/src/components/PhotoSwipe/InfoDialog/RenderInfoItem.tsx b/src/components/PhotoViewer/FileInfo/RenderInfoItem.tsx similarity index 100% rename from src/components/PhotoSwipe/InfoDialog/RenderInfoItem.tsx rename to src/components/PhotoViewer/FileInfo/RenderInfoItem.tsx diff --git a/src/components/PhotoViewer/FileInfo/index.tsx b/src/components/PhotoViewer/FileInfo/index.tsx new file mode 100644 index 000000000..b237844ec --- /dev/null +++ b/src/components/PhotoViewer/FileInfo/index.tsx @@ -0,0 +1,280 @@ +import React, { useEffect, useState } from 'react'; +import constants from 'utils/strings/constants'; +import { RenderFileName } from './RenderFileName'; +import { RenderCreationTime } from './RenderCreationTime'; +import { Box, DialogProps, Link, Stack, styled } from '@mui/material'; +import { Location } from 'types/upload'; +import { getEXIFLocation } from 'services/upload/exifService'; +import { RenderCaption } from './RenderCaption'; +import { + BackupOutlined, + CameraOutlined, + FolderOutlined, + LocationOnOutlined, + TextSnippetOutlined, +} from '@mui/icons-material'; +import CopyButton from 'components/CodeBlock/CopyButton'; +import { formatDate, formatTime } from 'utils/time/format'; +import Titlebar from 'components/Titlebar'; +import InfoItem from './InfoItem'; +import { FlexWrapper } from 'components/Container'; +import EnteSpinner from 'components/EnteSpinner'; +import { EnteFile } from 'types/file'; +import { Chip } from 'components/Chip'; +import LinkButton from 'components/pages/gallery/LinkButton'; +import { ExifData } from './ExifData'; +import { EnteDrawer } from 'components/EnteDrawer'; + +export const FileInfoSidebar = styled((props: DialogProps) => ( + +))({ + zIndex: 1501, + '& .MuiPaper-root': { + padding: 8, + }, +}); + +interface Iprops { + shouldDisableEdits: boolean; + showInfo: boolean; + handleCloseInfo: () => void; + file: EnteFile; + exif: any; + scheduleUpdate: () => void; + refreshPhotoswipe: () => void; + fileToCollectionsMap: Map; + collectionNameMap: Map; + isTrashCollection: boolean; +} + +function BasicDeviceCamera({ + parsedExifData, +}: { + parsedExifData: Record; +}) { + return ( + + {parsedExifData['fNumber']} + {parsedExifData['exposureTime']} + {parsedExifData['ISO']} + + ); +} + +function getOpenStreetMapLink(location: { + latitude: number; + longitude: number; +}) { + return `https://www.openstreetmap.org/?mlat=${location.latitude}&mlon=${location.longitude}#map=15/${location.latitude}/${location.longitude}`; +} + +export function FileInfo({ + shouldDisableEdits, + showInfo, + handleCloseInfo, + file, + exif, + scheduleUpdate, + refreshPhotoswipe, + fileToCollectionsMap, + collectionNameMap, + isTrashCollection, +}: Iprops) { + const [location, setLocation] = useState(null); + const [parsedExifData, setParsedExifData] = useState>(); + const [showExif, setShowExif] = useState(false); + + const openExif = () => setShowExif(true); + const closeExif = () => setShowExif(false); + + useEffect(() => { + if (!location && file && file.metadata) { + if (file.metadata.longitude || file.metadata.longitude === 0) { + setLocation({ + latitude: file.metadata.latitude, + longitude: file.metadata.longitude, + }); + } + } + }, [file]); + + useEffect(() => { + if (!location && exif) { + const exifLocation = getEXIFLocation(exif); + if (exifLocation.latitude || exifLocation.latitude === 0) { + setLocation(exifLocation); + } + } + }, [exif]); + + useEffect(() => { + if (!exif) { + setParsedExifData({}); + return; + } + const parsedExifData = {}; + if (exif['fNumber']) { + parsedExifData['fNumber'] = `f/${Math.ceil(exif['FNumber'])}`; + } else if (exif['ApertureValue'] && exif['FocalLength']) { + parsedExifData['fNumber'] = `f/${Math.ceil( + exif['FocalLength'] / exif['ApertureValue'] + )}`; + } + const imageWidth = exif['ImageWidth'] ?? exif['ExifImageWidth']; + const imageHeight = exif['ImageHeight'] ?? exif['ExifImageHeight']; + if (imageWidth && imageHeight) { + parsedExifData['resolution'] = `${imageWidth} x ${imageHeight}`; + const megaPixels = Math.round((imageWidth * imageHeight) / 1000000); + if (megaPixels) { + parsedExifData['megaPixels'] = `${Math.round( + (imageWidth * imageHeight) / 1000000 + )}MP`; + } + } + if (exif['Make'] && exif['Model']) { + parsedExifData[ + 'takenOnDevice' + ] = `${exif['Make']} ${exif['Model']}`; + } + if (exif['ExposureTime']) { + parsedExifData['exposureTime'] = `1/${ + 1 / parseFloat(exif['ExposureTime']) + }`; + } + if (exif['ISO']) { + parsedExifData['ISO'] = `ISO${exif['ISO']}`; + } + setParsedExifData(parsedExifData); + }, [exif]); + + if (!file) { + return <>; + } + + return ( + + + + + + + + + {parsedExifData && parsedExifData['takenOnDevice'] && ( + } + title={parsedExifData['takenOnDevice']} + caption={ + + } + hideEditOption + /> + )} + + {location && ( + } + title={constants.LOCATION} + caption={ + + {constants.SHOW_ON_MAP} + + } + customEndButton={ + + } + /> + )} + } + title={constants.DETAILS} + caption={ + typeof exif === 'undefined' ? ( + + ) : exif !== null ? ( + + {constants.VIEW_EXIF} + + ) : ( + constants.NO_EXIF + ) + } + hideEditOption + /> + } + title={formatDate(file.metadata.modificationTime / 1000)} + caption={formatTime(file.metadata.modificationTime / 1000)} + hideEditOption + /> + {!isTrashCollection && ( + } hideEditOption> + + {fileToCollectionsMap + .get(file.id) + ?.filter((collectionID) => + collectionNameMap.has(collectionID) + ) + ?.map((collectionID) => ( + + {collectionNameMap.get(collectionID)} + + ))} + + + )} + + + + ); +} diff --git a/src/components/PhotoSwipe/index.tsx b/src/components/PhotoViewer/index.tsx similarity index 57% rename from src/components/PhotoSwipe/index.tsx rename to src/components/PhotoViewer/index.tsx index 19a6f6bcb..285186fe6 100644 --- a/src/components/PhotoSwipe/index.tsx +++ b/src/components/PhotoViewer/index.tsx @@ -9,26 +9,49 @@ import { import { EnteFile } from 'types/file'; import constants from 'utils/strings/constants'; import exifr from 'exifr'; -import events from './events'; -import { downloadFile } from 'utils/file'; -import { prettyPrintExif } from 'utils/exif'; +import { downloadFile, copyFileToClipboard } from 'utils/file'; import { livePhotoBtnHTML } from 'components/LivePhotoBtn'; import { logError } from 'utils/sentry'; import { FILE_TYPE } from 'constants/file'; -import { sleep } from 'utils/common'; +import { isClipboardItemPresent } from 'utils/common'; import { playVideo, pauseVideo } from 'utils/photoFrame'; import { PublicCollectionGalleryContext } from 'utils/publicCollectionGallery'; import { AppContext } from 'pages/_app'; -import { FileInfo } from './InfoDialog'; -import { defaultLivePhotoDefaultOptions } from 'constants/photoswipe'; +import { FileInfo } from './FileInfo'; +import { + defaultLivePhotoDefaultOptions, + photoSwipeV4Events, +} from 'constants/photoViewer'; import { LivePhotoBtn } from './styledComponents/LivePhotoBtn'; import DownloadIcon from '@mui/icons-material/Download'; import InfoIcon from '@mui/icons-material/InfoOutlined'; import FavoriteIcon from '@mui/icons-material/FavoriteRounded'; import FavoriteBorderIcon from '@mui/icons-material/FavoriteBorderRounded'; import ChevronRight from '@mui/icons-material/ChevronRight'; +import DeleteIcon from '@mui/icons-material/Delete'; +import { trashFiles } from 'services/fileService'; +import { getTrashFileMessage } from 'utils/ui'; +import { ChevronLeft, ContentCopy } from '@mui/icons-material'; +import { styled } from '@mui/material'; +import { addLocalLog } from 'utils/logging'; +interface PhotoswipeFullscreenAPI { + enter: () => void; + exit: () => void; + isFullscreen: () => boolean; +} + +const CaptionContainer = styled('div')(({ theme }) => ({ + padding: theme.spacing(2), + wordBreak: 'break-word', + textAlign: 'right', + maxWidth: '375px', + fontSize: '14px', + lineHeight: '17px', + backgroundColor: theme.palette.backdrop.light, + backdropFilter: `blur(${theme.palette.blur.base})`, +})); interface Iprops { isOpen: boolean; items: any[]; @@ -38,13 +61,17 @@ interface Iprops { id?: string; className?: string; favItemIds: Set; + deletedFileIds: Set; + setDeletedFileIds?: (value: Set) => void; isSharedCollection: boolean; isTrashCollection: boolean; enableDownload: boolean; isSourceLoaded: boolean; + fileToCollectionsMap: Map; + collectionNameMap: Map; } -function PhotoSwipe(props: Iprops) { +function PhotoViewer(props: Iprops) { const pswpElement = useRef(); const [photoSwipe, setPhotoSwipe] = useState>(); @@ -52,8 +79,9 @@ function PhotoSwipe(props: Iprops) { const { isOpen, items, isSourceLoaded } = props; const [isFav, setIsFav] = useState(false); const [showInfo, setShowInfo] = useState(false); - const [metadata, setMetaData] = useState(null); - const [exif, setExif] = useState(null); + const [exif, setExif] = + useState<{ key: string; value: Record }>(); + const exifCopy = useRef(null); const [livePhotoBtnOptions, setLivePhotoBtnOptions] = useState( defaultLivePhotoDefaultOptions ); @@ -63,6 +91,9 @@ function PhotoSwipe(props: Iprops) { ); const appContext = useContext(AppContext); + const exifExtractionInProgress = useRef(null); + const [shouldShowCopyOption] = useState(isClipboardItemPresent()); + useEffect(() => { if (!pswpElement) return; if (isOpen) { @@ -76,6 +107,61 @@ function PhotoSwipe(props: Iprops) { }; }, [isOpen]); + useEffect(() => { + if (!photoSwipe) return; + function handleCopyEvent() { + copyToClipboardHelper(photoSwipe.currItem as EnteFile); + } + + function handleKeyUp(event: KeyboardEvent) { + if (!isOpen) { + return; + } + addLocalLog(() => 'Event: ' + event.key); + if (event.key === 'i' || event.key === 'I') { + if (!showInfo) { + setShowInfo(true); + } else { + setShowInfo(false); + } + } + if (showInfo) { + return; + } + switch (event.key) { + case 'Backspace': + case 'Delete': + confirmTrashFile(photoSwipe?.currItem as EnteFile); + break; + case 'd': + case 'D': + downloadFileHelper(photoSwipe?.currItem as EnteFile); + break; + case 'f': + case 'F': + toggleFullscreen(photoSwipe); + break; + case 'l': + case 'L': + onFavClick(photoSwipe?.currItem as EnteFile); + break; + default: + break; + } + } + + window.addEventListener('keyup', handleKeyUp); + if (shouldShowCopyOption) { + window.addEventListener('copy', handleCopyEvent); + } + return () => { + window.removeEventListener('keyup', handleKeyUp); + if (shouldShowCopyOption) { + window.removeEventListener('copy', handleCopyEvent); + } + }; + }, [isOpen, photoSwipe, showInfo]); + useEffect(() => { updateItems(items); }, [items]); @@ -152,8 +238,12 @@ function PhotoSwipe(props: Iprops) { } }, [photoSwipe?.currItem, isOpen, isSourceLoaded]); - function updateFavButton() { - setIsFav(isInFav(this?.currItem)); + useEffect(() => { + exifCopy.current = exif; + }, [exif]); + + function updateFavButton(file: EnteFile) { + setIsFav(isInFav(file)); } const openPhotoSwipe = () => { @@ -198,7 +288,7 @@ function PhotoSwipe(props: Iprops) { items, options ); - events.forEach((event) => { + photoSwipeV4Events.forEach((event) => { const callback = props[event]; if (callback || event === 'destroy') { photoSwipe.listen(event, function (...args) { @@ -215,11 +305,31 @@ function PhotoSwipe(props: Iprops) { }); } }); - photoSwipe.listen('beforeChange', function () { - updateInfo.call(this); - updateFavButton.call(this); + photoSwipe.listen('beforeChange', () => { + const currItem = photoSwipe?.currItem as EnteFile; + if ( + !currItem || + !exifCopy?.current?.value === null || + exifCopy?.current?.key === currItem.src + ) { + return; + } + setExif({ key: currItem.src, value: undefined }); + checkExifAvailable(currItem); + updateFavButton(currItem); + }); + photoSwipe.listen('resize', () => { + const currItem = photoSwipe?.currItem as EnteFile; + if ( + !currItem || + !exifCopy?.current?.value === null || + exifCopy?.current?.key === currItem.src + ) { + return; + } + setExif({ key: currItem.src, value: undefined }); + checkExifAvailable(currItem); }); - photoSwipe.listen('resize', checkExifAvailable); photoSwipe.init(); needUpdate.current = false; setPhotoSwipe(photoSwipe); @@ -240,7 +350,7 @@ function PhotoSwipe(props: Iprops) { } handleCloseInfo(); }; - const isInFav = (file) => { + const isInFav = (file: EnteFile) => { const { favItemIds } = props; if (favItemIds && file) { return favItemIds.has(file.id); @@ -248,7 +358,7 @@ function PhotoSwipe(props: Iprops) { return false; }; - const onFavClick = async (file) => { + const onFavClick = async (file: EnteFile) => { const { favItemIds } = props; if (!isInFav(file)) { favItemIds.add(file.id); @@ -262,46 +372,78 @@ function PhotoSwipe(props: Iprops) { needUpdate.current = true; }; + const trashFile = async (file: EnteFile) => { + const { deletedFileIds, setDeletedFileIds } = props; + deletedFileIds.add(file.id); + setDeletedFileIds(new Set(deletedFileIds)); + await trashFiles([file]); + needUpdate.current = true; + }; + + const confirmTrashFile = (file: EnteFile) => { + if (props.isSharedCollection || props.isTrashCollection) { + return; + } + appContext.setDialogMessage(getTrashFileMessage(() => trashFile(file))); + }; + const updateItems = (items = []) => { if (photoSwipe) { + if (items.length === 0) { + photoSwipe.close(); + } photoSwipe.items.length = 0; items.forEach((item) => { photoSwipe.items.push(item); }); photoSwipe.invalidateCurrItems(); - // photoSwipe.updateSize(true); + if (isOpen) { + photoSwipe.updateSize(true); + if (photoSwipe.getCurrentIndex() >= photoSwipe.items.length) { + photoSwipe.goTo(0); + } + } } }; - const checkExifAvailable = async () => { - setExif(null); - await sleep(100); + const refreshPhotoswipe = () => { + photoSwipe.invalidateCurrItems(); + if (isOpen) { + photoSwipe.updateSize(true); + } + }; + + const checkExifAvailable = async (file: EnteFile) => { try { - const img: HTMLImageElement = document.querySelector( - '.pswp__img:not(.pswp__img--placeholder)' - ); - if (img) { - const exifData = await exifr.parse(img); - if (!exifData) { - return; + if (exifExtractionInProgress.current === file.src) { + return; + } + try { + if (file.isSourceLoaded) { + exifExtractionInProgress.current = file.src; + const imageBlob = await ( + await fetch(file.originalImageURL) + ).blob(); + const exifData = (await exifr.parse(imageBlob)) as Record< + string, + any + >; + if (exifExtractionInProgress.current === file.src) { + if (exifData) { + setExif({ key: file.src, value: exifData }); + } else { + setExif({ key: file.src, value: null }); + } + } } - exifData.raw = prettyPrintExif(exifData); - setExif(exifData); + } finally { + exifExtractionInProgress.current = null; } } catch (e) { logError(e, 'exifr parsing failed'); } }; - function updateInfo() { - const file: EnteFile = this?.currItem; - if (file?.metadata) { - setMetaData(file.metadata); - setExif(null); - checkExifAvailable(); - } - } - const handleCloseInfo = () => { setShowInfo(false); }; @@ -310,15 +452,37 @@ function PhotoSwipe(props: Iprops) { }; const downloadFileHelper = async (file) => { - appContext.startLoading(); - await downloadFile( - file, - publicCollectionGalleryContext.accessedThroughSharedURL, - publicCollectionGalleryContext.token, - publicCollectionGalleryContext.passwordToken - ); + if (props.enableDownload) { + appContext.startLoading(); + await downloadFile( + file, + publicCollectionGalleryContext.accessedThroughSharedURL, + publicCollectionGalleryContext.token, + publicCollectionGalleryContext.passwordToken + ); + appContext.finishLoading(); + } + }; - appContext.finishLoading(); + const copyToClipboardHelper = async (file: EnteFile) => { + if (props.enableDownload && shouldShowCopyOption) { + appContext.startLoading(); + await copyFileToClipboard(file.src); + appContext.finishLoading(); + } + }; + + const toggleFullscreen = (photoSwipe) => { + const fullScreenApi: PhotoswipeFullscreenAPI = + photoSwipe?.ui?.getFullscreenAPI(); + if (!fullScreenApi) { + return; + } + if (fullScreenApi.isFullscreen()) { + fullScreenApi.exit(); + } else { + fullScreenApi.enter(); + } }; const scheduleUpdate = () => (needUpdate.current = true); const { id } = props; @@ -355,33 +519,74 @@ function PhotoSwipe(props: Iprops) { )} - + )} {!props.isSharedCollection && !props.isTrashCollection && ( + )} + + )} + {!props.isSharedCollection && + !props.isTrashCollection && ( + )} - {!props.isSharedCollection && ( - - )} +
@@ -411,36 +609,34 @@ function PhotoSwipe(props: Iprops) {
-
-
+
+
); } -export default PhotoSwipe; +export default PhotoViewer; diff --git a/src/components/PhotoSwipe/styledComponents/Legend.tsx b/src/components/PhotoViewer/styledComponents/Legend.tsx similarity index 100% rename from src/components/PhotoSwipe/styledComponents/Legend.tsx rename to src/components/PhotoViewer/styledComponents/Legend.tsx diff --git a/src/components/PhotoSwipe/styledComponents/LegendContainer.tsx b/src/components/PhotoViewer/styledComponents/LegendContainer.tsx similarity index 100% rename from src/components/PhotoSwipe/styledComponents/LegendContainer.tsx rename to src/components/PhotoViewer/styledComponents/LegendContainer.tsx diff --git a/src/components/PhotoSwipe/styledComponents/LivePhotoBtn.tsx b/src/components/PhotoViewer/styledComponents/LivePhotoBtn.tsx similarity index 100% rename from src/components/PhotoSwipe/styledComponents/LivePhotoBtn.tsx rename to src/components/PhotoViewer/styledComponents/LivePhotoBtn.tsx diff --git a/src/components/PhotoSwipe/styledComponents/Pre.tsx b/src/components/PhotoViewer/styledComponents/Pre.tsx similarity index 100% rename from src/components/PhotoSwipe/styledComponents/Pre.tsx rename to src/components/PhotoViewer/styledComponents/Pre.tsx diff --git a/src/components/PhotoSwipe/styledComponents/SmallLoadingSpinner.tsx b/src/components/PhotoViewer/styledComponents/SmallLoadingSpinner.tsx similarity index 100% rename from src/components/PhotoSwipe/styledComponents/SmallLoadingSpinner.tsx rename to src/components/PhotoViewer/styledComponents/SmallLoadingSpinner.tsx diff --git a/src/components/Search/SearchBar/searchInput/index.tsx b/src/components/Search/SearchBar/searchInput/index.tsx index a3ec32e9a..71e3ce3ab 100644 --- a/src/components/Search/SearchBar/searchInput/index.tsx +++ b/src/components/Search/SearchBar/searchInput/index.tsx @@ -37,7 +37,9 @@ export default function SearchInput(props: Iprops) { setValue(value); }; - useEffect(() => search(value), [value]); + useEffect(() => { + search(value); + }, [value]); const resetSearch = () => { if (props.isOpen) { diff --git a/src/components/Sidebar/DebugLogs.tsx b/src/components/Sidebar/DebugLogs.tsx deleted file mode 100644 index 2f4283d80..000000000 --- a/src/components/Sidebar/DebugLogs.tsx +++ /dev/null @@ -1,47 +0,0 @@ -import { AppContext } from 'pages/_app'; -import React, { useContext } from 'react'; -import { downloadAsFile } from 'utils/file'; -import constants from 'utils/strings/constants'; -import { addLogLine, getDebugLogs } from 'utils/logging'; -import SidebarButton from './Button'; -import { getData, LS_KEYS } from 'utils/storage/localStorage'; -import { User } from 'types/user'; -import { getSentryUserID } from 'utils/user'; - -export default function DebugLogs() { - const appContext = useContext(AppContext); - const confirmLogDownload = () => - appContext.setDialogMessage({ - title: constants.DOWNLOAD_LOGS, - content: constants.DOWNLOAD_LOGS_MESSAGE(), - proceed: { - text: constants.DOWNLOAD, - variant: 'accent', - action: downloadDebugLogs, - }, - close: { - text: constants.CANCEL, - }, - }); - - const downloadDebugLogs = () => { - addLogLine( - 'latest commit id :' + process.env.NEXT_PUBLIC_LATEST_COMMIT_HASH - ); - addLogLine(`user sentry id ${getSentryUserID()}`); - addLogLine(`ente userID ${(getData(LS_KEYS.USER) as User)?.id}`); - addLogLine('exporting logs'); - const logs = getDebugLogs(); - const logString = logs.join('\n'); - downloadAsFile(`debug_logs_${Date.now()}.txt`, logString); - }; - - return ( - - {constants.DOWNLOAD_UPLOAD_LOGS} - - ); -} diff --git a/src/components/Sidebar/DebugSection.tsx b/src/components/Sidebar/DebugSection.tsx new file mode 100644 index 000000000..3bc52c751 --- /dev/null +++ b/src/components/Sidebar/DebugSection.tsx @@ -0,0 +1,72 @@ +import { AppContext } from 'pages/_app'; +import React, { useContext, useEffect, useState } from 'react'; +import { downloadAsFile } from 'utils/file'; +import constants from 'utils/strings/constants'; +import { addLogLine, getDebugLogs } from 'utils/logging'; +import SidebarButton from './Button'; +import isElectron from 'is-electron'; +import ElectronService from 'services/electron/common'; +import { testUpload } from 'tests/upload.test'; +import Typography from '@mui/material/Typography'; +import { isInternalUser } from 'utils/user'; + +export default function DebugSection() { + const appContext = useContext(AppContext); + const [appVersion, setAppVersion] = useState(null); + + useEffect(() => { + const main = async () => { + if (isElectron()) { + const appVersion = await ElectronService.getAppVersion(); + setAppVersion(appVersion); + } + }; + main(); + }); + + const confirmLogDownload = () => + appContext.setDialogMessage({ + title: constants.DOWNLOAD_LOGS, + content: constants.DOWNLOAD_LOGS_MESSAGE(), + proceed: { + text: constants.DOWNLOAD, + variant: 'accent', + action: downloadDebugLogs, + }, + close: { + text: constants.CANCEL, + }, + }); + + const downloadDebugLogs = () => { + addLogLine('exporting logs'); + if (isElectron()) { + ElectronService.openLogDirectory(); + } else { + const logs = getDebugLogs(); + + downloadAsFile(`debug_logs_${Date.now()}.txt`, logs); + } + }; + + return ( + <> + + {constants.DOWNLOAD_UPLOAD_LOGS} + + {appVersion && ( + + {appVersion} + + )} + {isInternalUser() && ( + + {constants.RUN_TESTS} + + )} + + ); +} diff --git a/src/components/Sidebar/HelpSection.tsx b/src/components/Sidebar/HelpSection.tsx index 6e421c732..ac193b0bb 100644 --- a/src/components/Sidebar/HelpSection.tsx +++ b/src/components/Sidebar/HelpSection.tsx @@ -10,6 +10,7 @@ import { AppContext } from 'pages/_app'; import EnteSpinner from 'components/EnteSpinner'; import { getDownloadAppMessage } from 'utils/ui'; import { NoStyleAnchor } from 'components/pages/sharedAlbum/GoToEnte'; +import { openLink } from 'utils/common'; export default function HelpSection() { const [exportModalView, setExportModalView] = useState(false); @@ -20,8 +21,7 @@ export default function HelpSection() { const feedbackURL: string = `${getEndpoint()}/users/feedback?token=${encodeURIComponent( getToken() )}`; - const win = window.open(feedbackURL, '_blank'); - win.focus(); + openLink(feedbackURL, true); } function exportFiles() { diff --git a/src/components/Sidebar/ShortcutSection.tsx b/src/components/Sidebar/ShortcutSection.tsx index bb0a85cd1..317a610c4 100644 --- a/src/components/Sidebar/ShortcutSection.tsx +++ b/src/components/Sidebar/ShortcutSection.tsx @@ -2,10 +2,9 @@ import React, { useContext } from 'react'; import constants from 'utils/strings/constants'; import { GalleryContext } from 'pages/gallery'; import { ARCHIVE_SECTION, TRASH_SECTION } from 'constants/collection'; -import DeleteIcon from '@mui/icons-material/Delete'; -import VisibilityOffIcon from '@mui/icons-material/VisibilityOff'; import { CollectionSummaries } from 'types/collection'; import ShortcutButton from './ShortcutButton'; +import { ArchiveOutlined, DeleteOutline } from '@mui/icons-material'; interface Iprops { closeSidebar: () => void; collectionSummaries: CollectionSummaries; @@ -30,13 +29,13 @@ export default function ShortcutSection({ return ( <> } + startIcon={} label={constants.TRASH} count={collectionSummaries.get(TRASH_SECTION)?.fileCount} onClick={openTrashSection} /> } + startIcon={} label={constants.ARCHIVE_SECTION_NAME} count={collectionSummaries.get(ARCHIVE_SECTION)?.fileCount} onClick={openArchiveSection} diff --git a/src/components/Sidebar/SubscriptionStatus/index.tsx b/src/components/Sidebar/SubscriptionStatus/index.tsx index d62739a29..4b7206c60 100644 --- a/src/components/Sidebar/SubscriptionStatus/index.tsx +++ b/src/components/Sidebar/SubscriptionStatus/index.tsx @@ -1,5 +1,5 @@ import { GalleryContext } from 'pages/gallery'; -import React, { useContext, useMemo } from 'react'; +import React, { MouseEventHandler, useContext, useMemo } from 'react'; import { hasPaidSubscription, isFamilyAdmin, @@ -43,19 +43,23 @@ export default function SubscriptionStatus({ }, [userDetails]); const handleClick = useMemo(() => { - if (userDetails) { - if (isSubscriptionActive(userDetails.subscription)) { - if (hasExceededStorageQuota(userDetails)) { - return showPlanSelectorModal; - } - } else { - if (hasStripeSubscription(userDetails.subscription)) { - return billingService.redirectToCustomerPortal; + const eventHandler: MouseEventHandler = (e) => { + e.stopPropagation(); + if (userDetails) { + if (isSubscriptionActive(userDetails.subscription)) { + if (hasExceededStorageQuota(userDetails)) { + showPlanSelectorModal(); + } } else { - return showPlanSelectorModal; + if (hasStripeSubscription(userDetails.subscription)) { + billingService.redirectToCustomerPortal(); + } else { + showPlanSelectorModal(); + } } } - } + }; + return eventHandler; }, [userDetails]); if (!hasAMessage) { @@ -80,13 +84,9 @@ export default function SubscriptionStatus({ ) : hasExceededStorageQuota(userDetails) && constants.STORAGE_QUOTA_EXCEEDED_SUBSCRIPTION_INFO( - showPlanSelectorModal + handleClick ) - : constants.SUBSCRIPTION_EXPIRED_MESSAGE( - hasStripeSubscription(userDetails.subscription) - ? billingService.redirectToCustomerPortal - : showPlanSelectorModal - )} + : constants.SUBSCRIPTION_EXPIRED_MESSAGE(handleClick)} ); diff --git a/src/components/Sidebar/index.tsx b/src/components/Sidebar/index.tsx index 5dc8c5110..f58b41557 100644 --- a/src/components/Sidebar/index.tsx +++ b/src/components/Sidebar/index.tsx @@ -4,7 +4,7 @@ import ShortcutSection from './ShortcutSection'; import UtilitySection from './UtilitySection'; import HelpSection from './HelpSection'; import ExitSection from './ExitSection'; -import DebugLogs from './DebugLogs'; +import DebugSection from './DebugSection'; import { DrawerSidebar } from './styledComponents'; import HeaderSection from './Header'; import { CollectionSummaries } from 'types/collection'; @@ -37,7 +37,7 @@ export default function Sidebar({ - + ); diff --git a/src/components/Sidebar/styledComponents.tsx b/src/components/Sidebar/styledComponents.tsx index 433c9ab0a..15c11f83f 100644 --- a/src/components/Sidebar/styledComponents.tsx +++ b/src/components/Sidebar/styledComponents.tsx @@ -1,11 +1,9 @@ -import { Drawer, styled } from '@mui/material'; +import { styled } from '@mui/material'; import CircleIcon from '@mui/icons-material/Circle'; +import { EnteDrawer } from 'components/EnteDrawer'; -export const DrawerSidebar = styled(Drawer)(({ theme }) => ({ +export const DrawerSidebar = styled(EnteDrawer)(({ theme }) => ({ '& .MuiPaper-root': { - maxWidth: '375px', - width: '100%', - scrollbarWidth: 'thin', padding: theme.spacing(1.5), }, })); diff --git a/src/components/SingleInputForm.tsx b/src/components/SingleInputForm.tsx index 81b9be9c9..5c83f19b6 100644 --- a/src/components/SingleInputForm.tsx +++ b/src/components/SingleInputForm.tsx @@ -6,7 +6,7 @@ import SubmitButton from './SubmitButton'; import TextField from '@mui/material/TextField'; import ShowHidePassword from './Form/ShowHidePassword'; import { FlexWrapper } from './Container'; -import { Button } from '@mui/material'; +import { Button, FormHelperText } from '@mui/material'; interface formValues { inputValue: string; @@ -24,6 +24,7 @@ export interface SingleInputFormProps { secondaryButtonAction?: () => void; disableAutoFocus?: boolean; hiddenPreInput?: any; + caption?: any; hiddenPostInput?: any; autoComplete?: string; } @@ -113,6 +114,15 @@ export default function SingleInputForm(props: SingleInputFormProps) { ), }} /> + + {props.caption} + {props.hiddenPostInput} {props.secondaryButtonAction && ( @@ -120,13 +130,15 @@ export default function SingleInputForm(props: SingleInputFormProps) { onClick={props.secondaryButtonAction} size="large" color="secondary" - sx={{ mt: 2, mb: 4, mr: 1, ...buttonSx }} + sx={{ + '&&&': { mt: 2, mb: 4, mr: 1, ...buttonSx }, + }} {...restSubmitButtonProps}> {constants.CANCEL} )} void; + backIsClose?: boolean; + onRootClose?: () => void; + actionButton?: JSX.Element; +} + +export default function Titlebar({ + title, + caption, + onClose, + backIsClose, + actionButton, + onRootClose, +}: Iprops): JSX.Element { + return ( + <> + + + {backIsClose ? : } + + + {actionButton && actionButton} + {!backIsClose && ( + + + + )} + + + + + {title} + + + {caption} + + + + ); +} diff --git a/src/components/Upload/UploadProgress/dialog.tsx b/src/components/Upload/UploadProgress/dialog.tsx index 72667ae1c..f92af350e 100644 --- a/src/components/Upload/UploadProgress/dialog.tsx +++ b/src/components/Upload/UploadProgress/dialog.tsx @@ -7,9 +7,9 @@ import { UploadProgressHeader } from './header'; import { InProgressSection } from './inProgressSection'; import { ResultSection } from './resultSection'; import { NotUploadSectionHeader } from './styledComponents'; -import { getOSSpecificDesktopAppDownloadLink } from 'utils/common'; import UploadProgressContext from 'contexts/uploadProgress'; import { dialogCloseHandler } from 'components/DialogBox/TitleWithCloseButton'; +import { APP_DOWNLOAD_URL } from 'utils/common'; export function UploadProgressDialog() { const { open, onClose, uploadStage, finishedUploads } = useContext( @@ -40,70 +40,78 @@ export function UploadProgressDialog() { {(uploadStage === UPLOAD_STAGES.UPLOADING || - uploadStage === UPLOAD_STAGES.FINISH) && ( + uploadStage === UPLOAD_STAGES.FINISH || + uploadStage === UPLOAD_STAGES.EXTRACTING_METADATA) && ( - {uploadStage === UPLOAD_STAGES.UPLOADING && ( + {(uploadStage === UPLOAD_STAGES.UPLOADING || + uploadStage === UPLOAD_STAGES.EXTRACTING_METADATA) && ( )} + {(uploadStage === UPLOAD_STAGES.UPLOADING || + uploadStage === UPLOAD_STAGES.FINISH) && ( + <> + + - - + {uploadStage === UPLOAD_STAGES.FINISH && + hasUnUploadedFiles && ( + + {constants.FILE_NOT_UPLOADED_LIST} + + )} - {uploadStage === UPLOAD_STAGES.FINISH && - hasUnUploadedFiles && ( - - {constants.FILE_NOT_UPLOADED_LIST} - - )} - - - - - - - + + + + + + + + )} )} {uploadStage === UPLOAD_STAGES.FINISH && } diff --git a/src/components/Upload/UploadProgress/inProgressSection.tsx b/src/components/Upload/UploadProgress/inProgressSection.tsx index 418c2ed69..5266ce738 100644 --- a/src/components/Upload/UploadProgress/inProgressSection.tsx +++ b/src/components/Upload/UploadProgress/inProgressSection.tsx @@ -10,17 +10,19 @@ import { } from './section'; import UploadProgressContext from 'contexts/uploadProgress'; import constants from 'utils/strings/constants'; +import { UPLOAD_STAGES } from 'constants/upload'; export const InProgressSection = () => { - const { inProgressUploads, hasLivePhotos, uploadFileNames } = useContext( - UploadProgressContext - ); + const { inProgressUploads, hasLivePhotos, uploadFileNames, uploadStage } = + useContext(UploadProgressContext); const fileList = inProgressUploads ?? []; return ( - + }> - {constants.INPROGRESS_UPLOADS} + {uploadStage === UPLOAD_STAGES.EXTRACTING_METADATA + ? constants.INPROGRESS_METADATA_EXTRACTION + : constants.INPROGRESS_UPLOADS} {hasLivePhotos && ( @@ -30,8 +32,13 @@ export const InProgressSection = () => { fileList={fileList.map(({ localFileID, progress }) => ( {uploadFileNames.get(localFileID)} - {`-`} - {`${progress}%`} + {uploadStage === UPLOAD_STAGES.UPLOADING && ( + <> + {' '} + {`-`} + {`${progress}%`} + + )} ))} /> diff --git a/src/components/Upload/UploadProgress/title.tsx b/src/components/Upload/UploadProgress/title.tsx index a900ab171..2bdcd2184 100644 --- a/src/components/Upload/UploadProgress/title.tsx +++ b/src/components/Upload/UploadProgress/title.tsx @@ -20,6 +20,8 @@ function UploadProgressSubtitleText() { return ( {uploadStage === UPLOAD_STAGES.UPLOADING + ? constants.UPLOAD_STAGE_MESSAGE[uploadStage](uploadCounter) + : uploadStage === UPLOAD_STAGES.EXTRACTING_METADATA ? constants.UPLOAD_STAGE_MESSAGE[uploadStage](uploadCounter) : constants.UPLOAD_STAGE_MESSAGE[uploadStage]} diff --git a/src/components/Upload/Uploader.tsx b/src/components/Upload/Uploader.tsx index b3190ec89..4e2a0b0fb 100644 --- a/src/components/Upload/Uploader.tsx +++ b/src/components/Upload/Uploader.tsx @@ -49,6 +49,7 @@ import { } from 'utils/upload'; import { getUserOwnedCollections } from 'utils/collection'; import billingService from 'services/billingService'; +import { addLogLine } from 'utils/logging'; const FIRST_ALBUM_NAME = 'My First Album'; @@ -286,7 +287,7 @@ export default function Uploader(props: Props) { ) => { try { await preCollectionCreationAction(); - const filesWithCollectionToUpload: FileWithCollection[] = []; + let filesWithCollectionToUpload: FileWithCollection[] = []; const collections: Collection[] = []; let collectionNameToFilesMap = new Map< string, @@ -320,13 +321,14 @@ export default function Uploader(props: Props) { ...existingCollection, ...collections, ]); - filesWithCollectionToUpload.push( + filesWithCollectionToUpload = [ + ...filesWithCollectionToUpload, ...files.map((file) => ({ localID: index++, collectionID: collection.id, file, - })) - ); + })), + ]; } } catch (e) { closeUploadProgress(); @@ -426,6 +428,7 @@ export default function Uploader(props: Props) { const retryFailed = async () => { try { + addLogLine('user retrying failed upload'); const filesWithCollections = await uploadManager.getFailedFilesWithCollections(); await preUploadAction(); @@ -449,31 +452,28 @@ export default function Uploader(props: Props) { case CustomError.SUBSCRIPTION_EXPIRED: notification = { variant: 'danger', - message: constants.SUBSCRIPTION_EXPIRED, - action: { - text: constants.RENEW_NOW, - callback: billingService.redirectToCustomerPortal, - }, + subtext: constants.SUBSCRIPTION_EXPIRED, + message: constants.RENEW_NOW, + onClick: () => billingService.redirectToCustomerPortal(), }; break; case CustomError.STORAGE_QUOTA_EXCEEDED: notification = { variant: 'danger', - message: constants.STORAGE_QUOTA_EXCEEDED, - action: { - text: constants.UPGRADE_NOW, - callback: galleryContext.showPlanSelectorModal, - }, - icon: , + subtext: constants.STORAGE_QUOTA_EXCEEDED, + message: constants.UPGRADE_NOW, + onClick: () => galleryContext.showPlanSelectorModal(), + startIcon: , }; break; default: notification = { variant: 'danger', message: constants.UNKNOWN_ERROR, + onClick: () => null, }; } - galleryContext.setNotificationAttributes(notification); + appContext.setNotificationAttributes(notification); } const uploadToSingleNewCollection = (collectionName: string) => { diff --git a/src/components/WatchFolder/styledComponents.tsx b/src/components/WatchFolder/styledComponents.tsx index 3e6d595c1..2af051bbe 100644 --- a/src/components/WatchFolder/styledComponents.tsx +++ b/src/components/WatchFolder/styledComponents.tsx @@ -3,15 +3,12 @@ import { Box } from '@mui/material'; import { styled } from '@mui/material/styles'; import VerticallyCentered from 'components/Container'; -export const MappingsContainer = styled(Box)(({ theme }) => ({ +export const MappingsContainer = styled(Box)(() => ({ height: '278px', overflow: 'auto', '&::-webkit-scrollbar': { width: '4px', }, - '&::-webkit-scrollbar-thumb': { - backgroundColor: theme.palette.secondary.main, - }, })); export const NoMappingsContainer = styled(VerticallyCentered)({ diff --git a/src/components/pages/dedupe/SelectedFileOptions.tsx b/src/components/pages/dedupe/SelectedFileOptions.tsx index 030077d4c..c6a4c80ac 100644 --- a/src/components/pages/dedupe/SelectedFileOptions.tsx +++ b/src/components/pages/dedupe/SelectedFileOptions.tsx @@ -2,9 +2,8 @@ import { FluidContainer } from 'components/Container'; import { SelectionBar } from '../../Navbar/SelectionBar'; import constants from 'utils/strings/constants'; import React, { useContext } from 'react'; -import { Box, IconButton, styled } from '@mui/material'; +import { Box, IconButton, styled, Tooltip } from '@mui/material'; import { DeduplicateContext } from 'pages/deduplicate'; -import { IconWithMessage } from 'components/IconWithMessage'; import { AppContext } from 'pages/_app'; import CloseIcon from '@mui/icons-material/Close'; import BackButton from '@mui/icons-material/ArrowBackOutlined'; @@ -78,11 +77,11 @@ export default function DeduplicateOptions({
- + - + ); } diff --git a/src/components/pages/gallery/LinkButton.tsx b/src/components/pages/gallery/LinkButton.tsx index 113566245..4c26433e3 100644 --- a/src/components/pages/gallery/LinkButton.tsx +++ b/src/components/pages/gallery/LinkButton.tsx @@ -1,34 +1,12 @@ -import { Link, LinkProps } from '@mui/material'; +import { ButtonProps, Link, LinkProps } from '@mui/material'; import React, { FC } from 'react'; -import { ButtonProps } from 'react-bootstrap'; -export enum ButtonVariant { - success = 'success', - danger = 'danger', - secondary = 'secondary', - warning = 'warning', -} export type LinkButtonProps = React.PropsWithChildren<{ onClick: () => void; variant?: string; style?: React.CSSProperties; }>; -export function getVariantColor(variant: string) { - switch (variant) { - case ButtonVariant.success: - return '#51cd7c'; - case ButtonVariant.danger: - return '#c93f3f'; - case ButtonVariant.secondary: - return '#858585'; - case ButtonVariant.warning: - return '#D7BB63'; - default: - return '#d1d1d1'; - } -} - const LinkButton: FC> = ({ children, sx, @@ -41,6 +19,7 @@ const LinkButton: FC> = ({ sx={{ color: 'text.primary', textDecoration: 'underline rgba(255, 255, 255, 0.4)', + paddingBottom: 0.5, '&:hover': { color: `${color}.main`, textDecoration: `underline `, diff --git a/src/components/pages/gallery/PlanSelector/card/index.tsx b/src/components/pages/gallery/PlanSelector/card/index.tsx index 4af88bbed..2d8ed195a 100644 --- a/src/components/pages/gallery/PlanSelector/card/index.tsx +++ b/src/components/pages/gallery/PlanSelector/card/index.tsx @@ -13,6 +13,7 @@ import { hasPaidSubscription, getTotalFamilyUsage, isPartOfFamily, + isSubscriptionActive, } from 'utils/billing'; import { reverseString } from 'utils/common'; import { GalleryContext } from 'pages/gallery'; @@ -68,18 +69,19 @@ function PlanSelectorCard(props: Props) { const main = async () => { try { props.setLoading(true); - let plans = await billingService.getPlans(); - - const planNotListed = - plans.filter((plan) => - isUserSubscribedPlan(plan, subscription) - ).length === 0; - if ( - subscription && - !isOnFreePlan(subscription) && - planNotListed - ) { - plans = [planForSubscription(subscription), ...plans]; + const plans = await billingService.getPlans(); + if (isSubscriptionActive(subscription)) { + const planNotListed = + plans.filter((plan) => + isUserSubscribedPlan(plan, subscription) + ).length === 0; + if ( + subscription && + !isOnFreePlan(subscription) && + planNotListed + ) { + plans.push(planForSubscription(subscription)); + } } setPlans(plans); } catch (e) { diff --git a/src/components/pages/gallery/PreviewCard.tsx b/src/components/pages/gallery/PreviewCard.tsx index 71344c7e2..f3915396a 100644 --- a/src/components/pages/gallery/PreviewCard.tsx +++ b/src/components/pages/gallery/PreviewCard.tsx @@ -1,4 +1,4 @@ -import React, { useContext, useLayoutEffect, useRef, useState } from 'react'; +import React, { useContext, useLayoutEffect, useState } from 'react'; import { EnteFile } from 'types/file'; import { styled } from '@mui/material'; import PlayCircleOutlineOutlinedIcon from '@mui/icons-material/PlayCircleOutlineOutlined'; @@ -14,22 +14,22 @@ import { DeduplicateContext } from 'pages/deduplicate'; import { logError } from 'utils/sentry'; import { Overlay } from 'components/Container'; import { TRASH_SECTION } from 'constants/collection'; -import { formatDateRelative } from 'utils/time'; +import { formatDateRelative } from 'utils/time/format'; interface IProps { file: EnteFile; - updateURL?: (url: string) => EnteFile; - onClick?: () => void; - forcedEnable?: boolean; - selectable?: boolean; - selected?: boolean; - onSelect?: (checked: boolean) => void; - onHover?: () => void; - onRangeSelect?: () => void; - isRangeSelectActive?: boolean; - selectOnClick?: boolean; - isInsSelectRange?: boolean; - activeCollection?: number; + updateURL: (url: string) => EnteFile; + onClick: () => void; + selectable: boolean; + selected: boolean; + onSelect: (checked: boolean) => void; + onHover: () => void; + onRangeSelect: () => void; + isRangeSelectActive: boolean; + selectOnClick: boolean; + isInsSelectRange: boolean; + activeCollection: number; + showPlaceholder: boolean; } const Check = styled('input')<{ active: boolean }>` @@ -203,7 +203,6 @@ export default function PreviewCard(props: IProps) { file, onClick, updateURL, - forcedEnable, selectable, selected, onSelect, @@ -213,14 +212,13 @@ export default function PreviewCard(props: IProps) { isRangeSelectActive, isInsSelectRange, } = props; - const isMounted = useRef(true); const publicCollectionGalleryContext = useContext( PublicCollectionGalleryContext ); const deduplicateContext = useContext(DeduplicateContext); useLayoutEffect(() => { - if (file && !file.msrc) { + if (file && !file.msrc && !props.showPlaceholder) { const main = async () => { try { let url; @@ -236,18 +234,14 @@ export default function PreviewCard(props: IProps) { } else { url = await DownloadManager.getThumbnail(file); } - if (isMounted.current) { - setImgSrc(url); - thumbs.set(file.id, url); - if (updateURL) { - const newFile = updateURL(url); - file.msrc = newFile.msrc; - file.html = newFile.html; - file.src = newFile.src; - file.w = newFile.w; - file.h = newFile.h; - } - } + setImgSrc(url); + thumbs.set(file.id, url); + const newFile = updateURL(url); + file.msrc = newFile.msrc; + file.html = newFile.html; + file.src = newFile.src; + file.w = newFile.w; + file.h = newFile.h; } catch (e) { logError(e, 'preview card useEffect failed'); // no-op @@ -257,17 +251,17 @@ export default function PreviewCard(props: IProps) { if (thumbs.has(file.id)) { const thumbImgSrc = thumbs.get(file.id); setImgSrc(thumbImgSrc); - file.msrc = thumbImgSrc; + const newFile = updateURL(thumbImgSrc); + file.msrc = newFile.msrc; + file.html = newFile.html; + file.src = newFile.src; + file.w = newFile.w; + file.h = newFile.h; } else { main(); } } - - return () => { - // cool cool cool - isMounted.current = false; - }; - }, [file]); + }, [file, props.showPlaceholder]); const handleClick = () => { if (selectOnClick) { @@ -300,10 +294,10 @@ export default function PreviewCard(props: IProps) { return ( {selectable && ( + `${getPaymentsURL()}/desktop-redirect`; diff --git a/src/constants/ffmpeg/index.ts b/src/constants/ffmpeg/index.ts new file mode 100644 index 000000000..008b09784 --- /dev/null +++ b/src/constants/ffmpeg/index.ts @@ -0,0 +1,3 @@ +export const INPUT_PATH_PLACEHOLDER = 'INPUT'; +export const FFMPEG_PLACEHOLDER = 'FFMPEG'; +export const OUTPUT_PATH_PLACEHOLDER = 'OUTPUT'; diff --git a/src/constants/file/index.ts b/src/constants/file/index.ts index 93f8eb81b..306b2a4fb 100644 --- a/src/constants/file/index.ts +++ b/src/constants/file/index.ts @@ -2,6 +2,7 @@ export const MIN_EDITED_CREATION_TIME = new Date(1800, 0, 1); export const MAX_EDITED_CREATION_TIME = new Date(); export const MAX_EDITED_FILE_NAME_LENGTH = 100; +export const MAX_CAPTION_SIZE = 280; export const MAX_TRASH_BATCH_SIZE = 1000; export const TYPE_HEIC = 'heic'; diff --git a/src/components/PhotoSwipe/events.ts b/src/constants/photoViewer/index.ts similarity index 65% rename from src/components/PhotoSwipe/events.ts rename to src/constants/photoViewer/index.ts index b634d17c5..1a22dfeae 100644 --- a/src/components/PhotoSwipe/events.ts +++ b/src/constants/photoViewer/index.ts @@ -1,4 +1,12 @@ -export default [ +export const defaultLivePhotoDefaultOptions = { + click: () => {}, + hide: () => {}, + show: () => {}, + loading: false, + visible: false, +}; + +export const photoSwipeV4Events = [ 'beforeChange', 'afterChange', 'imageLoadComplete', diff --git a/src/constants/photoswipe/index.ts b/src/constants/photoswipe/index.ts deleted file mode 100644 index 7c1d44886..000000000 --- a/src/constants/photoswipe/index.ts +++ /dev/null @@ -1,7 +0,0 @@ -export const defaultLivePhotoDefaultOptions = { - click: () => {}, - hide: () => {}, - show: () => {}, - loading: false, - visible: false, -}; diff --git a/src/constants/sentry/index.ts b/src/constants/sentry/index.ts index 4e10419f4..abce60083 100644 --- a/src/constants/sentry/index.ts +++ b/src/constants/sentry/index.ts @@ -1,10 +1,15 @@ +export const ENV_DEVELOPMENT = 'development'; +export const ENV_PRODUCTION = 'production'; + export const getSentryDSN = () => process.env.NEXT_PUBLIC_SENTRY_DSN ?? 'https://60abb33b597c42f6a3fb27cd82c55101@sentry.ente.io/2'; export const getSentryENV = () => - process.env.NEXT_PUBLIC_SENTRY_ENV ?? 'development'; + process.env.NEXT_PUBLIC_SENTRY_ENV ?? ENV_PRODUCTION; export const getSentryRelease = () => process.env.SENTRY_RELEASE; export { getIsSentryEnabled } from '../../../sentryConfigUtil'; + +export const isDEVSentryENV = () => getSentryENV() === ENV_DEVELOPMENT; diff --git a/src/pages/_app.tsx b/src/pages/_app.tsx index ed219cfd2..47a46e7f4 100644 --- a/src/pages/_app.tsx +++ b/src/pages/_app.tsx @@ -8,12 +8,10 @@ import 'photoswipe/dist/photoswipe.css'; import 'styles/global.css'; import EnteSpinner from 'components/EnteSpinner'; import { logError } from '../utils/sentry'; -// import { Workbox } from 'workbox-window'; import { getData, LS_KEYS } from 'utils/storage/localStorage'; import HTTPService from 'services/HTTPService'; import FlashMessageBar from 'components/FlashMessageBar'; import Head from 'next/head'; -import { addLogLine } from 'utils/logging'; import LoadingBar from 'react-top-loading-bar'; import DialogBox from 'components/DialogBox'; import { styled, ThemeProvider } from '@mui/material/styles'; @@ -27,6 +25,25 @@ import { getRoadmapRedirectURL, } from 'services/userService'; import { CustomError } from 'utils/error'; +import { + addLogLine, + clearLogsIfLocalStorageLimitExceeded, +} from 'utils/logging'; +import isElectron from 'is-electron'; +import ElectronUpdateService from 'services/electron/update'; +import { + getUpdateAvailableForDownloadMessage, + getUpdateReadyToInstallMessage, +} from 'utils/ui'; +import Notification from 'components/Notification'; +import { + NotificationAttributes, + SetNotificationAttributes, +} from 'types/Notification'; +import ArrowForward from '@mui/icons-material/ArrowForward'; +import { AppUpdateInfo } from 'types/electron'; +import { getSentryUserID } from 'utils/user'; +import { User } from 'types/user'; export const MessageContainer = styled('div')` background-color: #111; @@ -52,6 +69,7 @@ type AppContextType = { finishLoading: () => void; closeMessageDialog: () => void; setDialogMessage: SetDialogBoxAttributes; + setNotificationAttributes: SetNotificationAttributes; isFolderSyncRunning: boolean; setIsFolderSyncRunning: (isRunning: boolean) => void; watchFolderView: boolean; @@ -97,34 +115,12 @@ export default function App({ Component, err }) { const [watchFolderView, setWatchFolderView] = useState(false); const [watchFolderFiles, setWatchFolderFiles] = useState(null); const isMobile = useMediaQuery('(max-width:428px)'); + const [notificationView, setNotificationView] = useState(false); + const closeNotification = () => setNotificationView(false); + const [notificationAttributes, setNotificationAttributes] = + useState(null); useEffect(() => { - if ( - !('serviceWorker' in navigator) || - process.env.NODE_ENV !== 'production' - ) { - console.warn('Progressive Web App support is disabled'); - return; - } - // const wb = new Workbox('sw.js', { scope: '/' }); - // wb.register(); - - if ('serviceWorker' in navigator) { - navigator.serviceWorker.onmessage = (event) => { - if (event.data.action === 'upload-files') { - const files = event.data.files; - setSharedFiles(files); - } - }; - navigator.serviceWorker - .getRegistrations() - .then(function (registrations) { - for (const registration of registrations) { - registration.unregister(); - } - }); - } - HTTPService.getInterceptors().response.use( (resp) => resp, (error) => { @@ -132,6 +128,34 @@ export default function App({ Component, err }) { return Promise.reject(error); } ); + clearLogsIfLocalStorageLimitExceeded(); + const main = async () => { + addLogLine(`userID: ${(getData(LS_KEYS.USER) as User)?.id}`); + addLogLine(`sentryID: ${await getSentryUserID()}`); + addLogLine(`sentry release ID: ${process.env.SENTRY_RELEASE}`); + }; + main(); + }, []); + + useEffect(() => { + if (isElectron()) { + const showUpdateDialog = (updateInfo: AppUpdateInfo) => { + if (updateInfo.autoUpdatable) { + setDialogMessage(getUpdateReadyToInstallMessage()); + } else { + setNotificationAttributes({ + endIcon: , + variant: 'secondary', + message: constants.UPDATE_AVAILABLE, + onClick: () => + setDialogMessage( + getUpdateAvailableForDownloadMessage(updateInfo) + ), + }); + } + }; + ElectronUpdateService.registerUpdateEventListener(showUpdateDialog); + } }, []); const setUserOnline = () => setOffline(false); @@ -206,10 +230,12 @@ export default function App({ Component, err }) { }, [redirectName]); useEffect(() => { - addLogLine(`app started`); - }, []); + setMessageDialogView(true); + }, [dialogMessage]); - useEffect(() => setMessageDialogView(true), [dialogMessage]); + useEffect(() => { + setNotificationView(true); + }, [notificationAttributes]); const showNavBar = (show: boolean) => setShowNavBar(show); const setDisappearingFlashMessage = (flashMessages: FlashMessage) => { @@ -239,7 +265,7 @@ export default function App({ Component, err }) { - + {showNavbar && } {offline && constants.OFFLINE_MSG} @@ -265,11 +291,17 @@ export default function App({ Component, err }) { + {loading ? ( diff --git a/src/pages/deduplicate/index.tsx b/src/pages/deduplicate/index.tsx index 2836bb4f0..856b20041 100644 --- a/src/pages/deduplicate/index.tsx +++ b/src/pages/deduplicate/index.tsx @@ -24,6 +24,9 @@ import router from 'next/router'; import { getKey, SESSION_KEYS } from 'utils/storage/sessionStorage'; import { styled } from '@mui/material'; import { syncCollections } from 'services/collectionService'; +import EnteSpinner from 'components/EnteSpinner'; +import VerticallyCentered from 'components/Container'; +import { Collection } from 'types/collection'; export const DeduplicateContext = createContext( DefaultDeduplicateContext @@ -42,6 +45,7 @@ export default function Deduplicate() { setRedirectURL, } = useContext(AppContext); const [duplicateFiles, setDuplicateFiles] = useState(null); + const [collections, setCollection] = useState([]); const [clubSameTimeFilesOnly, setClubSameTimeFilesOnly] = useState(false); const [fileSizeMap, setFileSizeMap] = useState(new Map()); const [collectionNameMap, setCollectionNameMap] = useState( @@ -72,6 +76,7 @@ export default function Deduplicate() { const syncWithRemote = async () => { startLoading(); const collections = await syncCollections(); + setCollection(collections); const collectionNameMap = new Map(); for (const collection of collections) { collectionNameMap.set(collection.id, collection.name); @@ -87,11 +92,12 @@ export default function Deduplicate() { let toSelectFileIDs: number[] = []; let count = 0; for (const dupe of duplicates) { - allDuplicateFiles = allDuplicateFiles.concat(dupe.files); + allDuplicateFiles = [...allDuplicateFiles, ...dupe.files]; // select all except first file - toSelectFileIDs = toSelectFileIDs.concat( - dupe.files.slice(1).map((f) => f.id) - ); + toSelectFileIDs = [ + ...toSelectFileIDs, + ...dupe.files.slice(1).map((f) => f.id), + ]; count += dupe.files.length - 1; for (const file of dupe.files) { @@ -143,7 +149,13 @@ export default function Deduplicate() { }; if (!duplicateFiles) { - return <>; + return ( + + + Loading... + + + ); } return ( @@ -165,7 +177,7 @@ export default function Deduplicate() { )} null, setActiveCollection: () => null, syncWithRemote: () => null, - setNotificationAttributes: () => null, setBlockingLoad: () => null, photoListHeader: null, }; @@ -180,7 +178,9 @@ export default function Gallery() { useState(null); const syncInProgress = useRef(true); const resync = useRef(false); - const [deleted, setDeleted] = useState([]); + const [deletedFileIds, setDeletedFileIds] = useState>( + new Set() + ); const { startLoading, finishLoading, setDialogMessage, ...appContext } = useContext(AppContext); const [collectionSummaries, setCollectionSummaries] = @@ -190,13 +190,6 @@ export default function Gallery() { const [fixCreationTimeAttributes, setFixCreationTimeAttributes] = useState(null); - const [notificationView, setNotificationView] = useState(false); - - const closeNotification = () => setNotificationView(false); - - const [notificationAttributes, setNotificationAttributes] = - useState(null); - const [archivedCollections, setArchivedCollections] = useState>(); @@ -233,6 +226,10 @@ export default function Gallery() { return; } const main = async () => { + const valid = await validateKey(); + if (!valid) { + return; + } setActiveCollection(ALL_SECTION); setIsFirstLoad(isFirstLogin()); setIsFirstFetch(true); @@ -241,10 +238,10 @@ export default function Gallery() { } setIsFirstLogin(false); const user = getData(LS_KEYS.USER); - const files = mergeMetadata(await getLocalFiles()); + let files = mergeMetadata(await getLocalFiles()); const collections = await getLocalCollections(); const trash = await getLocalTrash(); - files.push(...getTrashedFiles(trash)); + files = [...files, ...getTrashedFiles(trash)]; setUser(user); setFiles(sortFiles(files)); setCollections(collections); @@ -264,24 +261,16 @@ export default function Gallery() { setDerivativeState(user, collections, files); }, [collections, files]); - useEffect( - () => collectionSelectorAttributes && setCollectionSelectorView(true), - [collectionSelectorAttributes] - ); + useEffect(() => { + collectionSelectorAttributes && setCollectionSelectorView(true); + }, [collectionSelectorAttributes]); - useEffect( - () => collectionNamerAttributes && setCollectionNamerView(true), - [collectionNamerAttributes] - ); - useEffect( - () => fixCreationTimeAttributes && setFixCreationTimeView(true), - [fixCreationTimeAttributes] - ); - - useEffect( - () => notificationAttributes && setNotificationView(true), - [notificationAttributes] - ); + useEffect(() => { + collectionNamerAttributes && setCollectionNamerView(true); + }, [collectionNamerAttributes]); + useEffect(() => { + fixCreationTimeAttributes && setFixCreationTimeView(true); + }, [fixCreationTimeAttributes]); useEffect(() => { if (typeof activeCollection === 'undefined') { @@ -341,9 +330,9 @@ export default function Gallery() { !silent && startLoading(); const collections = await syncCollections(); setCollections(collections); - const files = await syncFiles(collections, setFiles); + let files = await syncFiles(collections, setFiles); const trash = await syncTrash(collections, setFiles, files); - files.push(...getTrashedFiles(trash)); + files = [...files, ...getTrashedFiles(trash)]; } catch (e) { logError(e, 'syncWithRemote failed'); switch (e.message) { @@ -490,12 +479,12 @@ export default function Gallery() { startLoading(); try { const selectedFiles = getSelectedFiles(selected, files); + setDeletedFileIds((deletedFileIds) => { + selectedFiles.forEach((file) => deletedFileIds.add(file.id)); + return new Set(deletedFileIds); + }); if (permanent) { await deleteFromTrash(selectedFiles.map((file) => file.id)); - setDeleted([ - ...deleted, - ...selectedFiles.map((file) => file.id), - ]); } else { await trashFiles(selectedFiles); } @@ -574,7 +563,6 @@ export default function Gallery() { showPlanSelectorModal, setActiveCollection, syncWithRemote, - setNotificationAttributes, setBlockingLoad, photoListHeader: photoListHeader, }}> @@ -602,11 +590,6 @@ export default function Gallery() { closeModal={() => setPlanModalView(false)} setLoading={setBlockingLoad} /> - - { try { + recoveryKey = recoveryKey + .trim() + .split(' ') + .map((part) => part.trim()) + .filter((part) => !!part) + .join(' '); // check if user is entering mnemonic recovery key - if (recoveryKey.trim().indexOf(' ') > 0) { - if (recoveryKey.trim().split(' ').length !== 24) { + if (recoveryKey.indexOf(' ') > 0) { + if (recoveryKey.split(' ').length !== 24) { throw new Error('recovery code should have 24 words'); } recoveryKey = bip39.mnemonicToEntropy(recoveryKey); @@ -102,12 +108,12 @@ export default function Recover() { buttonText={constants.RECOVER} /> - - + diff --git a/src/pages/shared-albums/index.tsx b/src/pages/shared-albums/index.tsx index a557764a2..e6a66dd24 100644 --- a/src/pages/shared-albums/index.tsx +++ b/src/pages/shared-albums/index.tsx @@ -58,7 +58,7 @@ export default function PublicCollectionGallery() { const url = useRef(null); const [publicFiles, setPublicFiles] = useState(null); const [publicCollection, setPublicCollection] = useState(null); - const [errorMessage, setErrorMessage] = useState(null); + const [errorMessage, setErrorMessage] = useState(null); const appContext = useContext(AppContext); const [abuseReportFormView, setAbuseReportFormView] = useState(false); const [loading, setLoading] = useState(true); @@ -128,9 +128,8 @@ export default function PublicCollectionGallery() { main(); }, []); - useEffect( - () => - publicCollection && + useEffect(() => { + publicCollection && publicFiles && setPhotoListHeader({ item: ( @@ -143,9 +142,8 @@ export default function PublicCollectionGallery() { ), itemType: ITEM_TYPE.OTHER, height: 68, - }), - [publicCollection, publicFiles] - ); + }); + }, [publicCollection, publicFiles]); const syncWithRemote = async () => { const collectionUID = getPublicCollectionUID(token.current); @@ -309,16 +307,10 @@ export default function PublicCollectionGallery() { null} selected={{ count: 0, collectionID: null }} isFirstLoad={true} - openUploader={() => null} - isInSearchMode={false} - search={{}} - deleted={[]} activeCollection={ALL_SECTION} isSharedCollection enableDownload={ diff --git a/src/pages/two-factor/recover/index.tsx b/src/pages/two-factor/recover/index.tsx index a090e33cb..3c55e1fd4 100644 --- a/src/pages/two-factor/recover/index.tsx +++ b/src/pages/two-factor/recover/index.tsx @@ -7,7 +7,6 @@ import SingleInputForm, { SingleInputFormProps, } from 'components/SingleInputForm'; import VerticallyCentered from 'components/Container'; -import { Button } from 'react-bootstrap'; import { logError } from 'utils/sentry'; import { recoverTwoFactor, removeTwoFactor } from 'services/userService'; import { AppContext } from 'pages/_app'; @@ -15,6 +14,7 @@ import { PAGES } from 'constants/pages'; import FormPaper from 'components/Form/FormPaper'; import FormPaperTitle from 'components/Form/FormPaper/Title'; import FormPaperFooter from 'components/Form/FormPaper/Footer'; +import LinkButton from 'components/pages/gallery/LinkButton'; const bip39 = require('bip39'); // mobile client library only supports english. bip39.setDefaultWordlist('english'); @@ -52,9 +52,15 @@ export default function Recover() { setFieldError ) => { try { + recoveryKey = recoveryKey + .trim() + .split(' ') + .map((part) => part.trim()) + .filter((part) => !!part) + .join(' '); // check if user is entering mnemonic recovery key - if (recoveryKey.trim().indexOf(' ') > 0) { - if (recoveryKey.trim().split(' ').length !== 24) { + if (recoveryKey.indexOf(' ') > 0) { + if (recoveryKey.split(' ').length !== 24) { throw new Error('recovery code should have 24 words'); } recoveryKey = bip39.mnemonicToEntropy(recoveryKey); @@ -101,12 +107,12 @@ export default function Recover() { buttonText={constants.RECOVER} /> - - + diff --git a/src/serviceWorker.js b/src/serviceWorker.js deleted file mode 100644 index aed91c3fa..000000000 --- a/src/serviceWorker.js +++ /dev/null @@ -1,34 +0,0 @@ -import { precacheAndRoute, cleanupOutdatedCaches } from 'workbox-precaching'; -import { registerRoute, setDefaultHandler } from 'workbox-routing'; -import { NetworkOnly } from 'workbox-strategies'; -import { pageCache, offlineFallback } from 'workbox-recipes'; - -pageCache(); - -precacheAndRoute(self.__WB_MANIFEST); -cleanupOutdatedCaches(); - -registerRoute( - '/share-target', - async ({ event }) => { - event.waitUntil( - (async function () { - const data = await event.request.formData(); - const client = await self.clients.get( - event.resultingClientId || event.clientId - ); - const files = data.getAll('files'); - setTimeout(() => { - client.postMessage({ files, action: 'upload-files' }); - }, 1000); - })() - ); - return Response.redirect('./'); - }, - 'POST' -); - -// Use a stale-while-revalidate strategy for all other requests. -setDefaultHandler(new NetworkOnly()); - -offlineFallback(); diff --git a/src/services/billingService.ts b/src/services/billingService.ts index 5d95e345a..19807bd16 100644 --- a/src/services/billingService.ts +++ b/src/services/billingService.ts @@ -6,7 +6,7 @@ import { logError } from 'utils/sentry'; import { getPaymentToken } from './userService'; import { Plan, Subscription } from 'types/billing'; import isElectron from 'is-electron'; -import { DESKTOP_REDIRECT_URL } from 'constants/billing'; +import { getDesktopRedirectURL } from 'constants/billing'; const ENDPOINT = getEndpoint(); @@ -170,12 +170,7 @@ class billingService { action: string ) { try { - let redirectURL; - if (isElectron()) { - redirectURL = DESKTOP_REDIRECT_URL; - } else { - redirectURL = `${window.location.origin}/gallery`; - } + const redirectURL = this.getRedirectURL(); window.location.href = `${getPaymentsURL()}?productID=${productID}&paymentToken=${paymentToken}&action=${action}&redirectURL=${redirectURL}`; } catch (e) { logError(e, 'unable to get payments url'); @@ -185,9 +180,10 @@ class billingService { public async redirectToCustomerPortal() { try { + const redirectURL = this.getRedirectURL(); const response = await HTTPService.get( `${ENDPOINT}/billing/stripe/customer-portal`, - { redirectURL: `${window.location.origin}/gallery` }, + { redirectURL }, { 'X-Auth-Token': getToken(), } @@ -198,6 +194,14 @@ class billingService { throw e; } } + + public getRedirectURL() { + if (isElectron()) { + return getDesktopRedirectURL(); + } else { + return `${window.location.origin}/gallery`; + } + } } export default new billingService(); diff --git a/src/services/collectionService.ts b/src/services/collectionService.ts index 1d2fa20a5..62982b008 100644 --- a/src/services/collectionService.ts +++ b/src/services/collectionService.ts @@ -42,6 +42,7 @@ import { EncryptionResult } from 'types/upload'; import constants from 'utils/strings/constants'; import { IsArchived } from 'utils/magicMetadata'; import { User } from 'types/user'; +import { getNonHiddenCollections } from 'utils/collection'; const ENDPOINT = getEndpoint(); const COLLECTION_TABLE = 'collections'; @@ -143,7 +144,7 @@ const getCollections = async ( export const getLocalCollections = async (): Promise => { const collections: Collection[] = (await localForage.getItem(COLLECTION_TABLE)) ?? []; - return collections; + return getNonHiddenCollections(collections); }; export const getCollectionUpdationTime = async (): Promise => @@ -188,7 +189,7 @@ export const syncCollections = async () => { await localForage.setItem(COLLECTION_TABLE, collections); await localForage.setItem(COLLECTION_UPDATION_TIME, updationTime); - return collections; + return getNonHiddenCollections(collections); }; export const getCollection = async ( diff --git a/src/services/deduplicationService.ts b/src/services/deduplicationService.ts index 9ab0e0b12..50d2bd7a9 100644 --- a/src/services/deduplicationService.ts +++ b/src/services/deduplicationService.ts @@ -33,7 +33,7 @@ export async function getDuplicateFiles( fileMap.set(file.id, file); } - const result: DuplicateFiles[] = []; + let result: DuplicateFiles[] = []; for (const dupe of dupes) { let duplicateFiles: EnteFile[] = []; @@ -48,12 +48,13 @@ export async function getDuplicateFiles( ); if (duplicateFiles.length > 1) { - result.push( + result = [ + ...result, ...getDupesGroupedBySameFileHashes( duplicateFiles, dupe.size - ) - ); + ), + ]; } } diff --git a/src/services/downloadManager.ts b/src/services/downloadManager.ts index ca45c22ae..c747037e3 100644 --- a/src/services/downloadManager.ts +++ b/src/services/downloadManager.ts @@ -13,11 +13,22 @@ import { logError } from 'utils/sentry'; import { FILE_TYPE } from 'constants/file'; import { CustomError } from 'utils/error'; import { openThumbnailCache } from './cacheService'; +import QueueProcessor, { PROCESSING_STRATEGY } from './queueProcessor'; + +const MAX_PARALLEL_DOWNLOADS = 10; class DownloadManager { - private fileObjectURLPromise = new Map>(); + private fileObjectURLPromise = new Map< + string, + Promise<{ original: string[]; converted: string[] }> + >(); private thumbnailObjectURLPromise = new Map>(); + private thumbnailDownloadRequestsProcessor = new QueueProcessor( + MAX_PARALLEL_DOWNLOADS, + PROCESSING_STRATEGY.LIFO + ); + public async getThumbnail(file: EnteFile) { try { const token = getToken(); @@ -34,7 +45,10 @@ class DownloadManager { if (cacheResp) { return URL.createObjectURL(await cacheResp.blob()); } - const thumb = await this.downloadThumb(token, file); + const thumb = + await this.thumbnailDownloadRequestsProcessor.queueUpRequest( + () => this.downloadThumb(token, file) + ).promise; const thumbBlob = new Blob([thumb]); thumbnailCache @@ -84,12 +98,11 @@ class DownloadManager { if (forPreview) { return await getRenderableFileURL(file, fileBlob); } else { - return [ - await createTypedObjectURL( - fileBlob, - file.metadata.title - ), - ]; + const fileURL = await createTypedObjectURL( + fileBlob, + file.metadata.title + ); + return { converted: [fileURL], original: [fileURL] }; } }; if (!this.fileObjectURLPromise.get(fileKey)) { diff --git a/src/services/electron/common.ts b/src/services/electron/common.ts index b01c85e36..baf27f33f 100644 --- a/src/services/electron/common.ts +++ b/src/services/electron/common.ts @@ -1,18 +1,38 @@ import isElectron from 'is-electron'; import { ElectronAPIs } from 'types/electron'; -import { runningInBrowser } from 'utils/common'; class ElectronService { private electronAPIs: ElectronAPIs; - private isBundledApp: boolean = false; constructor() { - this.electronAPIs = runningInBrowser() && window['ElectronAPIs']; - this.isBundledApp = !!this.electronAPIs?.openDiskCache; + this.electronAPIs = globalThis['ElectronAPIs']; } checkIsBundledApp() { - return isElectron() && this.isBundledApp; + return isElectron() && !!this.electronAPIs?.openDiskCache; + } + + logToDisk(msg: string) { + if (this.electronAPIs?.logToDisk) { + this.electronAPIs.logToDisk(msg); + } + } + + openLogDirectory() { + if (this.electronAPIs?.openLogDirectory) { + this.electronAPIs.openLogDirectory(); + } + } + + getSentryUserID() { + if (this.electronAPIs?.getSentryUserID) { + return this.electronAPIs.getSentryUserID(); + } + } + getAppVersion() { + if (this.electronAPIs?.getAppVersion) { + return this.electronAPIs.getAppVersion(); + } } } diff --git a/src/services/electron/ffmpeg.ts b/src/services/electron/ffmpeg.ts new file mode 100644 index 000000000..b16133d24 --- /dev/null +++ b/src/services/electron/ffmpeg.ts @@ -0,0 +1,26 @@ +import { IFFmpeg } from 'services/ffmpeg/ffmpegFactory'; +import { ElectronAPIs } from 'types/electron'; +import { ElectronFile } from 'types/upload'; +import { runningInBrowser } from 'utils/common'; + +export class ElectronFFmpeg implements IFFmpeg { + private electronAPIs: ElectronAPIs; + + constructor() { + this.electronAPIs = runningInBrowser() && globalThis['ElectronAPIs']; + } + + async run( + cmd: string[], + inputFile: ElectronFile | File, + outputFilename: string + ) { + if (this.electronAPIs?.runFFmpegCmd) { + return this.electronAPIs.runFFmpegCmd( + cmd, + inputFile, + outputFilename + ); + } + } +} diff --git a/src/services/electron/heicConvertor.ts b/src/services/electron/heicConvertor.ts new file mode 100644 index 000000000..cec59fcd3 --- /dev/null +++ b/src/services/electron/heicConvertor.ts @@ -0,0 +1,46 @@ +import { ElectronAPIs } from 'types/electron'; +import { makeHumanReadableStorage } from 'utils/billing'; +import { addLogLine } from 'utils/logging'; +import { logError } from 'utils/sentry'; + +class ElectronHEICConverter { + private electronAPIs: ElectronAPIs; + private allElectronAPIExists: boolean; + constructor() { + this.electronAPIs = globalThis['ElectronAPIs']; + this.allElectronAPIExists = !!this.electronAPIs?.convertHEIC; + } + + apiExists() { + return this.allElectronAPIExists; + } + + async convert(fileBlob: Blob): Promise { + try { + if (this.allElectronAPIExists) { + const startTime = Date.now(); + const inputFileData = new Uint8Array( + await fileBlob.arrayBuffer() + ); + const convertedFileData = await this.electronAPIs.convertHEIC( + inputFileData + ); + addLogLine( + `originalFileSize:${makeHumanReadableStorage( + fileBlob?.size + )},convertedFileSize:${makeHumanReadableStorage( + convertedFileData?.length + )}, native heic conversion time: ${ + Date.now() - startTime + }ms ` + ); + return new Blob([convertedFileData]); + } + } catch (e) { + logError(e, 'failed to convert heic natively'); + throw e; + } + } +} + +export default new ElectronHEICConverter(); diff --git a/src/services/electron/update.ts b/src/services/electron/update.ts new file mode 100644 index 000000000..121facfd1 --- /dev/null +++ b/src/services/electron/update.ts @@ -0,0 +1,31 @@ +import { AppUpdateInfo, ElectronAPIs } from 'types/electron'; + +class ElectronUpdateService { + private electronAPIs: ElectronAPIs; + + constructor() { + this.electronAPIs = globalThis['ElectronAPIs']; + } + + registerUpdateEventListener( + showUpdateDialog: (updateInfo: AppUpdateInfo) => void + ) { + if (this.electronAPIs?.registerUpdateEventListener) { + this.electronAPIs.registerUpdateEventListener(showUpdateDialog); + } + } + + updateAndRestart() { + if (this.electronAPIs?.updateAndRestart) { + this.electronAPIs.updateAndRestart(); + } + } + + skipAppVersion(version: string) { + if (this.electronAPIs?.skipAppVersion) { + this.electronAPIs.skipAppVersion(version); + } + } +} + +export default new ElectronUpdateService(); diff --git a/src/services/exportService.ts b/src/services/exportService.ts index 90e730d60..87a438fb6 100644 --- a/src/services/exportService.ts +++ b/src/services/exportService.ts @@ -39,7 +39,6 @@ import { } from 'utils/file'; import { updateFileCreationDateInEXIF } from './upload/exifService'; -import { Metadata } from 'types/upload'; import QueueProcessor from './queueProcessor'; import { Collection } from 'types/collection'; import { @@ -245,10 +244,7 @@ class ExportService { file, RecordType.FAILED ); - console.log( - `export failed for fileID:${file.id}, reason:`, - e - ); + logError( e, 'download and save failed for file during export' @@ -460,11 +456,7 @@ class ExportService { await this.exportMotionPhoto(fileStream, file, collectionPath); } else { this.saveMediaFile(collectionPath, fileSaveName, fileStream); - await this.saveMetadataFile( - collectionPath, - fileSaveName, - file.metadata - ); + await this.saveMetadataFile(collectionPath, fileSaveName, file); } } @@ -483,11 +475,7 @@ class ExportService { file.id ); this.saveMediaFile(collectionPath, imageSaveName, imageStream); - await this.saveMetadataFile( - collectionPath, - imageSaveName, - file.metadata - ); + await this.saveMetadataFile(collectionPath, imageSaveName, file); const videoStream = generateStreamFromArrayBuffer(motionPhoto.video); const videoSaveName = getUniqueFileSaveName( @@ -496,11 +484,7 @@ class ExportService { file.id ); this.saveMediaFile(collectionPath, videoSaveName, videoStream); - await this.saveMetadataFile( - collectionPath, - videoSaveName, - file.metadata - ); + await this.saveMetadataFile(collectionPath, videoSaveName, file); } private saveMediaFile( @@ -516,11 +500,11 @@ class ExportService { private async saveMetadataFile( collectionFolderPath: string, fileSaveName: string, - metadata: Metadata + file: EnteFile ) { await this.electronAPIs.saveFileToDisk( getFileMetadataSavePath(collectionFolderPath, fileSaveName), - getGoogleLikeMetadataFile(fileSaveName, metadata) + getGoogleLikeMetadataFile(fileSaveName, file) ); } @@ -637,7 +621,6 @@ class ExportService { oldFileSavePath, newFileSavePath ); - console.log(oldFileMetadataSavePath, newFileMetadataSavePath); await this.electronAPIs.checkExistsAndRename( oldFileMetadataSavePath, newFileMetadataSavePath diff --git a/src/services/ffmpeg/ffmpegClient.ts b/src/services/ffmpeg/ffmpegClient.ts deleted file mode 100644 index cd4848744..000000000 --- a/src/services/ffmpeg/ffmpegClient.ts +++ /dev/null @@ -1,114 +0,0 @@ -import { createFFmpeg, FFmpeg } from 'ffmpeg-wasm'; -import { getUint8ArrayView } from 'services/readerService'; -import { - parseFFmpegExtractedMetadata, - splitFilenameAndExtension, -} from 'utils/ffmpeg'; - -class FFmpegClient { - private ffmpeg: FFmpeg; - private ready: Promise = null; - constructor() { - this.ffmpeg = createFFmpeg({ - corePath: '/js/ffmpeg/ffmpeg-core.js', - mt: false, - }); - - this.ready = this.init(); - } - - private async init() { - if (!this.ffmpeg.isLoaded()) { - await this.ffmpeg.load(); - } - } - - async generateThumbnail(file: File) { - await this.ready; - // eslint-disable-next-line @typescript-eslint/no-unused-vars - const [_, ext] = splitFilenameAndExtension(file.name); - const inputFileName = `${Date.now().toString()}-input.${ext}`; - const thumbFileName = `${Date.now().toString()}-thumb.jpeg`; - this.ffmpeg.FS( - 'writeFile', - inputFileName, - await getUint8ArrayView(file) - ); - let seekTime = 1.0; - let thumb = null; - while (seekTime > 0) { - try { - await this.ffmpeg.run( - '-i', - inputFileName, - '-ss', - `00:00:0${seekTime.toFixed(3)}`, - '-vframes', - '1', - '-vf', - 'scale=-1:720', - thumbFileName - ); - thumb = this.ffmpeg.FS('readFile', thumbFileName); - this.ffmpeg.FS('unlink', thumbFileName); - break; - } catch (e) { - seekTime = Number((seekTime / 10).toFixed(3)); - } - } - this.ffmpeg.FS('unlink', inputFileName); - return thumb; - } - - async extractVideoMetadata(file: File) { - await this.ready; - // eslint-disable-next-line @typescript-eslint/no-unused-vars - const [_, ext] = splitFilenameAndExtension(file.name); - const inputFileName = `${Date.now().toString()}-input.${ext}`; - const outFileName = `${Date.now().toString()}-metadata.txt`; - this.ffmpeg.FS( - 'writeFile', - inputFileName, - await getUint8ArrayView(file) - ); - let metadata = null; - - // https://stackoverflow.com/questions/9464617/retrieving-and-saving-media-metadata-using-ffmpeg - // -c [short for codex] copy[(stream_specifier)[ffmpeg.org/ffmpeg.html#Stream-specifiers]] => copies all the stream without re-encoding - // -map_metadata [http://ffmpeg.org/ffmpeg.html#Advanced-options search for map_metadata] => copies all stream metadata to the out - // -f ffmetadata [https://ffmpeg.org/ffmpeg-formats.html#Metadata-1] => dump metadata from media files into a simple UTF-8-encoded INI-like text file - await this.ffmpeg.run( - '-i', - inputFileName, - '-c', - 'copy', - '-map_metadata', - '0', - '-f', - 'ffmetadata', - outFileName - ); - metadata = this.ffmpeg.FS('readFile', outFileName); - this.ffmpeg.FS('unlink', outFileName); - this.ffmpeg.FS('unlink', inputFileName); - return parseFFmpegExtractedMetadata(metadata); - } - - async convertToMP4(file: Uint8Array, inputFileName: string) { - await this.ready; - this.ffmpeg.FS('writeFile', inputFileName, file); - await this.ffmpeg.run( - '-i', - inputFileName, - '-preset', - 'ultrafast', - 'output.mp4' - ); - const convertedFile = this.ffmpeg.FS('readFile', 'output.mp4'); - this.ffmpeg.FS('unlink', inputFileName); - this.ffmpeg.FS('unlink', 'output.mp4'); - return convertedFile; - } -} - -export default FFmpegClient; diff --git a/src/services/ffmpeg/ffmpegFactory.ts b/src/services/ffmpeg/ffmpegFactory.ts new file mode 100644 index 000000000..93d1a2749 --- /dev/null +++ b/src/services/ffmpeg/ffmpegFactory.ts @@ -0,0 +1,28 @@ +import isElectron from 'is-electron'; +import { ElectronFFmpeg } from 'services/electron/ffmpeg'; +import { ElectronFile } from 'types/upload'; +import { FFmpegWorker } from 'utils/comlink'; + +export interface IFFmpeg { + run: ( + cmd: string[], + inputFile: File | ElectronFile, + outputFilename: string + ) => Promise; +} + +class FFmpegFactory { + private client: IFFmpeg; + + async getFFmpegClient() { + if (!this.client) { + if (isElectron()) { + this.client = new ElectronFFmpeg(); + } else { + this.client = await new FFmpegWorker(); + } + } + return this.client; + } +} +export default new FFmpegFactory(); diff --git a/src/services/ffmpeg/ffmpegService.ts b/src/services/ffmpeg/ffmpegService.ts index 889eabda1..8464d027b 100644 --- a/src/services/ffmpeg/ffmpegService.ts +++ b/src/services/ffmpeg/ffmpegService.ts @@ -1,93 +1,99 @@ -import { CustomError } from 'utils/error'; +import { + FFMPEG_PLACEHOLDER, + INPUT_PATH_PLACEHOLDER, + OUTPUT_PATH_PLACEHOLDER, +} from 'constants/ffmpeg'; +import { ElectronFile } from 'types/upload'; +import { parseFFmpegExtractedMetadata } from 'utils/ffmpeg'; import { logError } from 'utils/sentry'; -import QueueProcessor from 'services/queueProcessor'; -import { ParsedExtractedMetadata } from 'types/upload'; +import ffmpegFactory from './ffmpegFactory'; -import { FFmpegWorker } from 'utils/comlink'; -import { promiseWithTimeout } from 'utils/common'; - -const FFMPEG_EXECUTION_WAIT_TIME = 30 * 1000; - -class FFmpegService { - private ffmpegWorker = null; - private ffmpegTaskQueue = new QueueProcessor(1); - - async init() { - this.ffmpegWorker = await new FFmpegWorker(); - } - - async generateThumbnail(file: File): Promise { - if (!this.ffmpegWorker) { - await this.init(); - } - - const response = this.ffmpegTaskQueue.queueUpRequest(() => - promiseWithTimeout( - this.ffmpegWorker.generateThumbnail(file), - FFMPEG_EXECUTION_WAIT_TIME - ) - ); - try { - return await response.promise; - } catch (e) { - if (e.message === CustomError.REQUEST_CANCELLED) { - // ignore - return null; - } else { - logError(e, 'ffmpeg thumbnail generation failed'); - throw e; - } - } - } - - async extractMetadata(file: File): Promise { - if (!this.ffmpegWorker) { - await this.init(); - } - - const response = this.ffmpegTaskQueue.queueUpRequest(() => - promiseWithTimeout( - this.ffmpegWorker.extractVideoMetadata(file), - FFMPEG_EXECUTION_WAIT_TIME - ) - ); - try { - return await response.promise; - } catch (e) { - if (e.message === CustomError.REQUEST_CANCELLED) { - // ignore - return null; - } else { - logError(e, 'ffmpeg metadata extraction failed'); - throw e; - } - } - } - - async convertToMP4( - file: Uint8Array, - fileName: string - ): Promise { - if (!this.ffmpegWorker) { - await this.init(); - } - - const response = this.ffmpegTaskQueue.queueUpRequest( - async () => await this.ffmpegWorker.convertToMP4(file, fileName) - ); - - try { - return await response.promise; - } catch (e) { - if (e.message === CustomError.REQUEST_CANCELLED) { - // ignore - return null; - } else { - logError(e, 'ffmpeg MP4 conversion failed'); - throw e; +export async function generateVideoThumbnail( + file: File | ElectronFile +): Promise { + try { + let seekTime = 1.0; + const ffmpegClient = await ffmpegFactory.getFFmpegClient(); + while (seekTime > 0) { + try { + return await ffmpegClient.run( + [ + FFMPEG_PLACEHOLDER, + '-i', + INPUT_PATH_PLACEHOLDER, + '-ss', + `00:00:0${seekTime.toFixed(3)}`, + '-vframes', + '1', + '-vf', + 'scale=-1:720', + OUTPUT_PATH_PLACEHOLDER, + ], + file, + 'thumb.jpeg' + ); + } catch (e) { + if (seekTime <= 0) { + throw e; + } } + seekTime = Number((seekTime / 10).toFixed(3)); } + } catch (e) { + logError(e, 'ffmpeg generateVideoThumbnail failed'); + throw e; } } -export default new FFmpegService(); +export async function extractVideoMetadata(file: File | ElectronFile) { + try { + const ffmpegClient = await ffmpegFactory.getFFmpegClient(); + // https://stackoverflow.com/questions/9464617/retrieving-and-saving-media-metadata-using-ffmpeg + // -c [short for codex] copy[(stream_specifier)[ffmpeg.org/ffmpeg.html#Stream-specifiers]] => copies all the stream without re-encoding + // -map_metadata [http://ffmpeg.org/ffmpeg.html#Advanced-options search for map_metadata] => copies all stream metadata to the out + // -f ffmetadata [https://ffmpeg.org/ffmpeg-formats.html#Metadata-1] => dump metadata from media files into a simple UTF-8-encoded INI-like text file + const metadata = await ffmpegClient.run( + [ + FFMPEG_PLACEHOLDER, + '-i', + INPUT_PATH_PLACEHOLDER, + '-c', + 'copy', + '-map_metadata', + '0', + '-f', + 'ffmetadata', + OUTPUT_PATH_PLACEHOLDER, + ], + file, + `metadata.txt` + ); + return parseFFmpegExtractedMetadata( + new Uint8Array(await metadata.arrayBuffer()) + ); + } catch (e) { + logError(e, 'ffmpeg extractVideoMetadata failed'); + throw e; + } +} + +export async function convertToMP4(file: File | ElectronFile) { + try { + const ffmpegClient = await ffmpegFactory.getFFmpegClient(); + return await ffmpegClient.run( + [ + FFMPEG_PLACEHOLDER, + '-i', + INPUT_PATH_PLACEHOLDER, + '-preset', + 'ultrafast', + OUTPUT_PATH_PLACEHOLDER, + ], + file, + 'output.mp4' + ); + } catch (e) { + logError(e, 'ffmpeg convertToMP4 failed'); + throw e; + } +} diff --git a/src/services/fileService.ts b/src/services/fileService.ts index f2935ce04..f7c66e113 100644 --- a/src/services/fileService.ts +++ b/src/services/fileService.ts @@ -18,6 +18,8 @@ import { SetFiles } from 'types/gallery'; import { MAX_TRASH_BATCH_SIZE } from 'constants/file'; import { BulkUpdateMagicMetadataRequest } from 'types/magicMetadata'; import { addLogLine } from 'utils/logging'; +import { isCollectionHidden } from 'utils/collection'; +import { CustomError } from 'utils/error'; const ENDPOINT = getEndpoint(); const FILES_TABLE = 'files'; @@ -63,13 +65,16 @@ export const syncFiles = async ( if (!getToken()) { continue; } + if (isCollectionHidden(collection)) { + throw Error(CustomError.HIDDEN_COLLECTION_SYNC_FILE_ATTEMPTED); + } const lastSyncTime = await getCollectionLastSyncTime(collection); if (collection.updationTime === lastSyncTime) { continue; } const fetchedFiles = (await getFiles(collection, lastSyncTime, files, setFiles)) ?? []; - files.push(...fetchedFiles); + files = [...files, ...fetchedFiles]; const latestVersionFiles = new Map(); files.forEach((file) => { const uid = `${file.collectionID}-${file.id}`; @@ -105,7 +110,7 @@ export const getFiles = async ( setFiles: SetFiles ): Promise => { try { - const decryptedFiles: EnteFile[] = []; + let decryptedFiles: EnteFile[] = []; let time = sinceTime; let resp; do { @@ -124,7 +129,8 @@ export const getFiles = async ( } ); - decryptedFiles.push( + decryptedFiles = [ + ...decryptedFiles, ...(await Promise.all( resp.data.diff.map(async (file: EnteFile) => { if (!file.isDeleted) { @@ -132,8 +138,8 @@ export const getFiles = async ( } return file; }) as Promise[] - )) - ); + )), + ]; if (resp.data.diff.length) { time = resp.data.diff.slice(-1)[0].updationTime; diff --git a/src/services/heicConversionService.ts b/src/services/heicConversionService.ts new file mode 100644 index 000000000..aa5b8fba3 --- /dev/null +++ b/src/services/heicConversionService.ts @@ -0,0 +1,24 @@ +import isElectron from 'is-electron'; +import { logError } from 'utils/sentry'; +import WasmHEICConverterService from './wasmHeicConverter/wasmHEICConverterService'; +import ElectronHEICConvertor from 'services/electron/heicConvertor'; + +class HeicConversionService { + async convert(heicFileData: Blob): Promise { + try { + if (isElectron() && ElectronHEICConvertor.apiExists()) { + try { + return await ElectronHEICConvertor.convert(heicFileData); + } catch (e) { + return await WasmHEICConverterService.convert(heicFileData); + } + } else { + return await WasmHEICConverterService.convert(heicFileData); + } + } catch (e) { + logError(e, 'failed to convert heic file'); + throw e; + } + } +} +export default new HeicConversionService(); diff --git a/src/services/publicCollectionDownloadManager.ts b/src/services/publicCollectionDownloadManager.ts index d649fced6..4733f7adc 100644 --- a/src/services/publicCollectionDownloadManager.ts +++ b/src/services/publicCollectionDownloadManager.ts @@ -14,11 +14,17 @@ import { EnteFile } from 'types/file'; import { logError } from 'utils/sentry'; import { FILE_TYPE } from 'constants/file'; import { CustomError } from 'utils/error'; +import QueueProcessor from './queueProcessor'; class PublicCollectionDownloadManager { - private fileObjectURLPromise = new Map>(); + private fileObjectURLPromise = new Map< + string, + Promise<{ original: string[]; converted: string[] }> + >(); private thumbnailObjectURLPromise = new Map>(); + private thumbnailDownloadRequestsProcessor = new QueueProcessor(5); + public async getThumbnail( file: EnteFile, token: string, @@ -46,11 +52,10 @@ class PublicCollectionDownloadManager { if (cacheResp) { return URL.createObjectURL(await cacheResp.blob()); } - const thumb = await this.downloadThumb( - token, - passwordToken, - file - ); + const thumb = + await this.thumbnailDownloadRequestsProcessor.queueUpRequest( + () => this.downloadThumb(token, passwordToken, file) + ).promise; const thumbBlob = new Blob([thumb]); try { await thumbnailCache?.put( @@ -119,12 +124,11 @@ class PublicCollectionDownloadManager { if (forPreview) { return await getRenderableFileURL(file, fileBlob); } else { - return [ - await createTypedObjectURL( - fileBlob, - file.metadata.title - ), - ]; + const fileURL = await createTypedObjectURL( + fileBlob, + file.metadata.title + ); + return { converted: [fileURL], original: [fileURL] }; } }; if (!this.fileObjectURLPromise.get(fileKey)) { diff --git a/src/services/publicCollectionService.ts b/src/services/publicCollectionService.ts index 43554af69..5b4f9c265 100644 --- a/src/services/publicCollectionService.ts +++ b/src/services/publicCollectionService.ts @@ -151,7 +151,7 @@ export const syncPublicFiles = async ( let files: EnteFile[] = []; const collectionUID = getPublicCollectionUID(token); const localFiles = await getLocalPublicFiles(collectionUID); - files.push(...localFiles); + files = [...files, ...localFiles]; try { if (!token) { return files; @@ -171,7 +171,7 @@ export const syncPublicFiles = async ( setPublicFiles ); - files.push(...fetchedFiles); + files = [...files, ...fetchedFiles]; const latestVersionFiles = new Map(); files.forEach((file) => { const uid = `${file.collectionID}-${file.id}`; @@ -200,7 +200,6 @@ export const syncPublicFiles = async ( const parsedError = parseSharingErrorCodes(e); logError(e, 'failed to sync shared collection files'); if (parsedError.message === CustomError.TOKEN_EXPIRED) { - console.log('invalid token or password'); throw e; } } @@ -220,7 +219,7 @@ const getPublicFiles = async ( setPublicFiles: (files: EnteFile[]) => void ): Promise => { try { - const decryptedFiles: EnteFile[] = []; + let decryptedFiles: EnteFile[] = []; let time = sinceTime; let resp; do { @@ -240,7 +239,8 @@ const getPublicFiles = async ( }), } ); - decryptedFiles.push( + decryptedFiles = [ + ...decryptedFiles, ...(await Promise.all( resp.data.diff.map(async (file: EnteFile) => { if (!file.isDeleted) { @@ -248,8 +248,8 @@ const getPublicFiles = async ( } return file; }) as Promise[] - )) - ); + )), + ]; if (resp.data.diff.length) { time = resp.data.diff.slice(-1)[0].updationTime; diff --git a/src/services/queueProcessor.ts b/src/services/queueProcessor.ts index 5f5e939c6..ad63d3227 100644 --- a/src/services/queueProcessor.ts +++ b/src/services/queueProcessor.ts @@ -8,6 +8,11 @@ interface RequestQueueItem { canceller: { exec: () => void }; } +export enum PROCESSING_STRATEGY { + FIFO, + LIFO, +} + export interface RequestCanceller { exec: () => void; } @@ -17,7 +22,10 @@ export default class QueueProcessor { private requestInProcessing = 0; - constructor(private maxParallelProcesses: number) {} + constructor( + private maxParallelProcesses: number, + private processingStrategy = PROCESSING_STRATEGY.FIFO + ) {} public queueUpRequest( request: (canceller?: RequestCanceller) => Promise @@ -52,7 +60,10 @@ export default class QueueProcessor { private async processQueue() { while (this.requestQueue.length > 0) { - const queueItem = this.requestQueue.shift(); + const queueItem = + this.processingStrategy === PROCESSING_STRATEGY.LIFO + ? this.requestQueue.pop() + : this.requestQueue.shift(); let response = null; if (queueItem.isCanceled.status) { diff --git a/src/services/searchService.ts b/src/services/searchService.ts index 45ef3345f..e14a0b7de 100644 --- a/src/services/searchService.ts +++ b/src/services/searchService.ts @@ -35,7 +35,6 @@ export const getAutoCompleteSuggestions = ...getDateSuggestion(searchPhrase), ...getCollectionSuggestion(searchPhrase, collections), ...getFileSuggestion(searchPhrase, files), - ...(await getLocationSuggestions(searchPhrase)), ]; const previewImageAppendedOptions: SearchOption[] = suggestions @@ -166,6 +165,7 @@ function getFileSuggestion( })); } +// eslint-disable-next-line @typescript-eslint/no-unused-vars async function getLocationSuggestions(searchPhrase: string) { const locationResults = await searchLocation(searchPhrase); diff --git a/src/services/typeDetectionService.ts b/src/services/typeDetectionService.ts index 7d25b82c4..97ccd53e5 100644 --- a/src/services/typeDetectionService.ts +++ b/src/services/typeDetectionService.ts @@ -73,6 +73,7 @@ async function extractElectronFileType(file: ElectronFile) { const stream = await file.stream(); const reader = stream.getReader(); const { value: fileDataChunk } = await reader.read(); + await reader.cancel(); return getFileTypeFromBuffer(fileDataChunk); } diff --git a/src/services/updateCreationTimeWithExif.ts b/src/services/updateCreationTimeWithExif.ts index fc6dd54fc..6d17a3674 100644 --- a/src/services/updateCreationTimeWithExif.ts +++ b/src/services/updateCreationTimeWithExif.ts @@ -36,7 +36,8 @@ export async function updateCreationTimeWithExif( if (file.metadata.fileType !== FILE_TYPE.IMAGE) { continue; } - const fileURL = await downloadManager.getFile(file)[0]; + const fileURL = (await downloadManager.getFile(file)) + .original[0]; const fileObject = await getFileFromURL(fileURL); const fileTypeInfo = await getFileType(fileObject); const exifData = await getRawExif(fileObject, fileTypeInfo); diff --git a/src/services/upload/exifService.ts b/src/services/upload/exifService.ts index ee6a3c906..9cbb11fac 100644 --- a/src/services/upload/exifService.ts +++ b/src/services/upload/exifService.ts @@ -62,8 +62,7 @@ export async function updateFileCreationDateInEXIF( updatedDate: Date ) { try { - const fileURL = URL.createObjectURL(fileBlob); - let imageDataURL = await convertImageToDataURL(reader, fileURL); + let imageDataURL = await convertImageToDataURL(reader, fileBlob); imageDataURL = 'data:image/jpeg;base64' + imageDataURL.slice(imageDataURL.indexOf(',')); @@ -83,8 +82,7 @@ export async function updateFileCreationDateInEXIF( } } -async function convertImageToDataURL(reader: FileReader, url: string) { - const blob = await fetch(url).then((r) => r.blob()); +async function convertImageToDataURL(reader: FileReader, blob: Blob) { const dataURL = await new Promise((resolve) => { reader.onload = () => resolve(reader.result as string); reader.readAsDataURL(blob); diff --git a/src/services/upload/thumbnailService.ts b/src/services/upload/thumbnailService.ts index d5b13046a..057ae7fa0 100644 --- a/src/services/upload/thumbnailService.ts +++ b/src/services/upload/thumbnailService.ts @@ -2,13 +2,13 @@ import { FILE_TYPE } from 'constants/file'; import { CustomError, errorWithContext } from 'utils/error'; import { logError } from 'utils/sentry'; import { BLACK_THUMBNAIL_BASE64 } from 'constants/upload'; -import FFmpegService from 'services/ffmpeg/ffmpegService'; +import * as FFmpegService from 'services/ffmpeg/ffmpegService'; import { convertBytesToHumanReadable } from 'utils/file/size'; import { isExactTypeHEIC } from 'utils/file'; import { ElectronFile, FileTypeInfo } from 'types/upload'; import { getUint8ArrayView } from '../readerService'; -import HEICConverter from 'services/heicConverter/heicConverterService'; import { getFileNameSize, addLogLine } from 'utils/logging'; +import HeicConversionService from 'services/heicConversionService'; const MAX_THUMBNAIL_DIMENSION = 720; const MIN_COMPRESSION_PERCENTAGE_SIZE_DIFF = 10; @@ -33,9 +33,6 @@ export async function generateThumbnail( let canvas = document.createElement('canvas'); let thumbnail: Uint8Array; try { - if (!(file instanceof File)) { - file = new File([await file.blob()], file.name); - } if (fileTypeInfo.fileType === FILE_TYPE.IMAGE) { const isHEIC = isExactTypeHEIC(fileTypeInfo.exactType); canvas = await generateImageThumbnail(file, isHEIC); @@ -47,17 +44,14 @@ export async function generateThumbnail( )}` ); - const thumb = await FFmpegService.generateThumbnail(file); + const thumbFile = + await FFmpegService.generateVideoThumbnail(file); addLogLine( `ffmpeg thumbnail successfully generated ${getFileNameSize( file )}` ); - const dummyImageFile = new File([thumb], file.name); - canvas = await generateImageThumbnail( - dummyImageFile, - false - ); + canvas = await generateImageThumbnail(thumbFile, false); } catch (e) { addLogLine( `ffmpeg thumbnail generated failed ${getFileNameSize( @@ -99,7 +93,10 @@ export async function generateThumbnail( } } -export async function generateImageThumbnail(file: File, isHEIC: boolean) { +export async function generateImageThumbnail( + file: File | ElectronFile, + isHEIC: boolean +) { const canvas = document.createElement('canvas'); const canvasCTX = canvas.getContext('2d'); @@ -108,15 +105,19 @@ export async function generateImageThumbnail(file: File, isHEIC: boolean) { if (isHEIC) { addLogLine(`HEICConverter called for ${getFileNameSize(file)}`); - file = new File([await HEICConverter.convert(file)], file.name); + const convertedBlob = await HeicConversionService.convert( + new Blob([await file.arrayBuffer()]) + ); + file = new File([convertedBlob], file.name); addLogLine(`${getFileNameSize(file)} successfully converted`); } let image = new Image(); - imageURL = URL.createObjectURL(file); - image.setAttribute('src', imageURL); + imageURL = URL.createObjectURL(new Blob([await file.arrayBuffer()])); await new Promise((resolve, reject) => { + image.setAttribute('src', imageURL); image.onload = () => { try { + URL.revokeObjectURL(imageURL); const imageDimension = { width: image.width, height: image.height, @@ -153,18 +154,21 @@ export async function generateImageThumbnail(file: File, isHEIC: boolean) { return canvas; } -export async function generateVideoThumbnail(file: File) { +export async function generateVideoThumbnail(file: File | ElectronFile) { const canvas = document.createElement('canvas'); const canvasCTX = canvas.getContext('2d'); - let videoURL = null; let timeout = null; + let videoURL = null; + let video = document.createElement('video'); + videoURL = URL.createObjectURL(new Blob([await file.arrayBuffer()])); await new Promise((resolve, reject) => { - let video = document.createElement('video'); - videoURL = URL.createObjectURL(file); + video.preload = 'metadata'; + video.src = videoURL; video.addEventListener('loadeddata', function () { try { + URL.revokeObjectURL(videoURL); if (!video) { throw Error('video load failed'); } @@ -196,8 +200,6 @@ export async function generateVideoThumbnail(file: File) { reject(err); } }); - video.preload = 'metadata'; - video.src = videoURL; timeout = setTimeout( () => reject(Error(CustomError.WAIT_TIME_EXCEEDED)), WAIT_TIME_THUMBNAIL_GENERATION diff --git a/src/services/upload/uiService.ts b/src/services/upload/uiService.ts index 70c0b036e..31be1f7c8 100644 --- a/src/services/upload/uiService.ts +++ b/src/services/upload/uiService.ts @@ -70,6 +70,10 @@ class UIService { this.updateProgressBarUI(); } + removeFromInProgressList(key: number) { + this.inProgressUploads.delete(key); + } + moveFileToResultList(key: number, uploadResult: UPLOAD_RESULT) { this.finishedUploads.set(key, uploadResult); this.inProgressUploads.delete(key); diff --git a/src/services/upload/uploadHttpClient.ts b/src/services/upload/uploadHttpClient.ts index ecf3d81e8..351031ae8 100644 --- a/src/services/upload/uploadHttpClient.ts +++ b/src/services/upload/uploadHttpClient.ts @@ -51,7 +51,9 @@ class UploadHttpClient { { 'X-Auth-Token': token } ); const response = await this.uploadURLFetchInProgress; - urlStore.push(...response.data['urls']); + for (const url of response.data['urls']) { + urlStore.push(url); + } } finally { this.uploadURLFetchInProgress = null; } diff --git a/src/services/upload/uploadManager.ts b/src/services/upload/uploadManager.ts index dea6abcf7..83337d1d5 100644 --- a/src/services/upload/uploadManager.ts +++ b/src/services/upload/uploadManager.ts @@ -115,6 +115,14 @@ class UploadManager { addLogLine( `received ${filesWithCollectionToUploadIn.length} files to upload` ); + uiService.setFilenames( + new Map( + filesWithCollectionToUploadIn.map((mediaFile) => [ + mediaFile.localID, + UploadService.getAssetName(mediaFile), + ]) + ) + ); const { metadataJSONFiles, mediaFiles } = segregateMetadataAndMediaFiles(filesWithCollectionToUploadIn); addLogLine(`has ${metadataJSONFiles.length} metadata json files`); @@ -137,8 +145,6 @@ class UploadManager { this.metadataAndFileTypeInfoMap ); - addLogLine(`clusterLivePhotoFiles called`); - // filter out files whose metadata detection failed or those that have been skipped because the files are too large, // as they will be rejected during upload and are not valid upload files which we need to clustering const rejectedFileLocalIDs = new Set( @@ -163,11 +169,16 @@ class UploadManager { } }); + addLogLine(`clusterLivePhotoFiles started`); + const analysedMediaFiles = UploadService.clusterLivePhotoFiles(filesWithMetadata); + addLogLine(`clusterLivePhotoFiles ended`); const allFiles = [...rejectedFiles, ...analysedMediaFiles]; - + addLogLine( + `got live photos: ${mediaFiles.length !== allFiles.length}` + ); uiService.setFilenames( new Map( allFiles.map((mediaFile) => [ @@ -180,9 +191,6 @@ class UploadManager { UIService.setHasLivePhoto( mediaFiles.length !== allFiles.length ); - addLogLine( - `got live photos: ${mediaFiles.length !== allFiles.length}` - ); await this.uploadMediaFiles(allFiles); } @@ -193,10 +201,6 @@ class UploadManager { } } else { logError(e, 'uploading failed with error'); - addLogLine( - `uploading failed with error -> ${e.message} - ${(e as Error).stack}` - ); throw e; } } finally { @@ -257,12 +261,12 @@ class UploadManager { } else { // and don't break for subsequent files just log and move on logError(e, 'parsing failed for a file'); + addLogLine( + `failed to parse metadata json file ${getFileNameSize( + file + )} error: ${e.message}` + ); } - addLogLine( - `failed to parse metadata json file ${getFileNameSize( - file - )} error: ${e.message}` - ); } } } catch (e) { @@ -278,6 +282,7 @@ class UploadManager { addLogLine(`extractMetadataFromFiles executed`); UIService.reset(mediaFiles.length); for (const { file, localID, collectionID } of mediaFiles) { + UIService.setFileProgress(localID, 0); if (uploadCancelService.isUploadCancelationRequested()) { throw Error(CustomError.UPLOAD_CANCELLED); } @@ -306,18 +311,19 @@ class UploadManager { } else { // and don't break for subsequent files just log and move on logError(e, 'extractFileTypeAndMetadata failed'); + addLogLine( + `metadata extraction failed ${getFileNameSize( + file + )} error: ${e.message}` + ); } - addLogLine( - `metadata extraction failed ${getFileNameSize( - file - )} error: ${e.message}` - ); } this.metadataAndFileTypeInfoMap.set(localID, { fileTypeInfo: fileTypeInfo && { ...fileTypeInfo }, metadata: metadata && { ...metadata }, filePath: filePath, }); + UIService.removeFromInProgressList(localID); UIService.increaseFileUploaded(); } } catch (e) { @@ -366,10 +372,10 @@ class UploadManager { private async uploadMediaFiles(mediaFiles: FileWithCollection[]) { addLogLine(`uploadMediaFiles called`); - this.filesToBeUploaded.push(...mediaFiles); + this.filesToBeUploaded = [...this.filesToBeUploaded, ...mediaFiles]; if (isElectron()) { - this.remainingFiles.push(...mediaFiles); + this.remainingFiles = [...this.remainingFiles, ...mediaFiles]; } UIService.reset(mediaFiles.length); @@ -434,7 +440,9 @@ class UploadManager { ) { try { let decryptedFile: EnteFile; - addLogLine(`uploadedFile ${JSON.stringify(uploadedFile)}`); + addLogLine( + `post upload action -> fileUploadResult: ${fileUploadResult} uploadedFile present ${!!uploadedFile}` + ); this.updateElectronRemainingFiles(fileWithCollection); switch (fileUploadResult) { case UPLOAD_RESULT.FAILED: @@ -480,10 +488,6 @@ class UploadManager { return fileUploadResult; } catch (e) { logError(e, 'failed to do post file upload action'); - addLogLine( - `failed to do post file upload action -> ${e.message} - ${(e as Error).stack}` - ); return UPLOAD_RESULT.FAILED; } } @@ -503,6 +507,7 @@ class UploadManager { } public cancelRunningUpload() { + addLogLine('user cancelled running upload'); UIService.setUploadStage(UPLOAD_STAGES.CANCELLING); uploadCancelService.requestUploadCancelation(); } diff --git a/src/services/upload/uploader.ts b/src/services/upload/uploader.ts index 6ff02dd76..13869a7ed 100644 --- a/src/services/upload/uploader.ts +++ b/src/services/upload/uploader.ts @@ -133,7 +133,6 @@ export default async function uploader( backupedFile, encryptedFile.fileKey ); - addLogLine(`uploadFile ${fileNameSize}`); const uploadedFile = await UploadHttpClient.uploadFile(uploadFile); diff --git a/src/services/upload/videoMetadataService.ts b/src/services/upload/videoMetadataService.ts index 76505d356..a7c2e2e34 100644 --- a/src/services/upload/videoMetadataService.ts +++ b/src/services/upload/videoMetadataService.ts @@ -1,5 +1,5 @@ import { NULL_EXTRACTED_METADATA } from 'constants/upload'; -import ffmpegService from 'services/ffmpeg/ffmpegService'; +import * as ffmpegService from 'services/ffmpeg/ffmpegService'; import { ElectronFile } from 'types/upload'; import { logError } from 'utils/sentry'; import { getFileNameSize, addLogLine } from 'utils/logging'; @@ -8,16 +8,7 @@ export async function getVideoMetadata(file: File | ElectronFile) { let videoMetadata = NULL_EXTRACTED_METADATA; try { addLogLine(`getVideoMetadata called for ${getFileNameSize(file)}`); - if (!(file instanceof File)) { - addLogLine('get file blob for video metadata extraction'); - file = new File([await file.blob()], file.name, { - lastModified: file.lastModified, - }); - addLogLine( - 'get file blob for video metadata extraction successfully' - ); - } - videoMetadata = await ffmpegService.extractMetadata(file); + videoMetadata = await ffmpegService.extractVideoMetadata(file); addLogLine( `videoMetadata successfully extracted ${getFileNameSize(file)}` ); diff --git a/src/services/userService.ts b/src/services/userService.ts index 5f3cd631e..1d4a092cc 100644 --- a/src/services/userService.ts +++ b/src/services/userService.ts @@ -6,7 +6,7 @@ import { clearData, getData, LS_KEYS } from 'utils/storage/localStorage'; import localForage from 'utils/storage/localForage'; import { getToken } from 'utils/common/key'; import HTTPService from './HTTPService'; -import { B64EncryptionResult } from 'utils/crypto'; +import { B64EncryptionResult, getRecoveryKey } from 'utils/crypto'; import { logError } from 'utils/sentry'; import { KeyAttributes, @@ -364,3 +364,13 @@ export const deleteAccount = async (challenge: string) => { throw e; } }; + +export const validateKey = async () => { + try { + await getRecoveryKey(); + return true; + } catch (e) { + await logoutUser(); + return false; + } +}; diff --git a/src/services/wasm/ffmpeg.ts b/src/services/wasm/ffmpeg.ts new file mode 100644 index 000000000..f27cf99cd --- /dev/null +++ b/src/services/wasm/ffmpeg.ts @@ -0,0 +1,97 @@ +import { createFFmpeg, FFmpeg } from 'ffmpeg-wasm'; +import QueueProcessor from 'services/queueProcessor'; +import { getUint8ArrayView } from 'services/readerService'; +import { promiseWithTimeout } from 'utils/common'; +import { addLogLine } from 'utils/logging'; +import { logError } from 'utils/sentry'; +import { generateTempName } from 'utils/temp'; + +const INPUT_PATH_PLACEHOLDER = 'INPUT'; +const FFMPEG_PLACEHOLDER = 'FFMPEG'; +const OUTPUT_PATH_PLACEHOLDER = 'OUTPUT'; + +const FFMPEG_EXECUTION_WAIT_TIME = 30 * 1000; + +export class WasmFFmpeg { + private ffmpeg: FFmpeg; + private ready: Promise = null; + private ffmpegTaskQueue = new QueueProcessor(1); + + constructor() { + this.ffmpeg = createFFmpeg({ + corePath: '/js/ffmpeg/ffmpeg-core.js', + mt: false, + }); + + this.ready = this.init(); + } + + private async init() { + if (!this.ffmpeg.isLoaded()) { + await this.ffmpeg.load(); + } + } + + async run(cmd: string[], inputFile: File, outputFileName: string) { + const response = this.ffmpegTaskQueue.queueUpRequest(() => + promiseWithTimeout( + this.execute(cmd, inputFile, outputFileName), + FFMPEG_EXECUTION_WAIT_TIME + ) + ); + try { + return await response.promise; + } catch (e) { + logError(e, 'ffmpeg run failed'); + throw e; + } + } + + private async execute( + cmd: string[], + inputFile: File, + outputFileName: string + ) { + let tempInputFilePath: string; + let tempOutputFilePath: string; + try { + await this.ready; + tempInputFilePath = `${generateTempName(10)}- ${inputFile.name}`; + this.ffmpeg.FS( + 'writeFile', + tempInputFilePath, + await getUint8ArrayView(inputFile) + ); + tempOutputFilePath = `${generateTempName(10)}-${outputFileName}`; + + cmd = cmd.map((cmdPart) => { + if (cmdPart === FFMPEG_PLACEHOLDER) { + return ''; + } else if (cmdPart === INPUT_PATH_PLACEHOLDER) { + return tempInputFilePath; + } else if (cmdPart === OUTPUT_PATH_PLACEHOLDER) { + return tempOutputFilePath; + } else { + return cmdPart; + } + }); + addLogLine(`${cmd}`); + await this.ffmpeg.run(...cmd); + return new File( + [this.ffmpeg.FS('readFile', tempOutputFilePath)], + outputFileName + ); + } finally { + try { + this.ffmpeg.FS('unlink', tempInputFilePath); + } catch (e) { + logError(e, 'unlink input file failed'); + } + try { + this.ffmpeg.FS('unlink', tempOutputFilePath); + } catch (e) { + logError(e, 'unlink output file failed'); + } + } + } +} diff --git a/src/services/heicConverter/heicConverterClient.ts b/src/services/wasmHeicConverter/wasmHEICConverterClient.ts similarity index 100% rename from src/services/heicConverter/heicConverterClient.ts rename to src/services/wasmHeicConverter/wasmHEICConverterClient.ts diff --git a/src/services/heicConverter/heicConverterService.ts b/src/services/wasmHeicConverter/wasmHEICConverterService.ts similarity index 95% rename from src/services/heicConverter/heicConverterService.ts rename to src/services/wasmHeicConverter/wasmHEICConverterService.ts index 5013089f5..5d28be7e2 100644 --- a/src/services/heicConverter/heicConverterService.ts +++ b/src/services/wasmHeicConverter/wasmHEICConverterService.ts @@ -13,6 +13,7 @@ const MAX_CONVERSION_IN_PARALLEL = 1; const WAIT_TIME_BEFORE_NEXT_ATTEMPT_IN_MICROSECONDS = [100, 100]; const WAIT_TIME_IN_MICROSECONDS = 30 * 1000; const BREATH_TIME_IN_MICROSECONDS = 1000; +const CONVERT_FORMAT = 'JPEG'; class HEICConverter { private convertProcessor = new QueueProcessor( @@ -24,13 +25,13 @@ class HEICConverter { constructor() { this.ready = this.init(); } - async init() { + private async init() { this.workerPool = []; for (let i = 0; i < WORKER_POOL_SIZE; i++) { this.workerPool.push(getDedicatedConvertWorker()); } } - async convert(fileBlob: Blob, format = 'JPEG'): Promise { + async convert(fileBlob: Blob): Promise { await this.ready; const response = this.convertProcessor.queueUpRequest(() => retryAsyncFunction(async () => { @@ -48,7 +49,7 @@ class HEICConverter { const convertedHEIC: Blob = await worker.convertHEIC( fileBlob, - format + CONVERT_FORMAT ); addLogLine( `originalFileSize:${makeHumanReadableStorage( @@ -91,7 +92,6 @@ class HEICConverter { this.workerPool.push(convertWorker); return convertedHEIC; } catch (e) { - addLogLine('heic conversion failed-' + e.message); logError(e, 'heic conversion failed'); convertWorker.terminate(); this.workerPool.push(getDedicatedConvertWorker()); diff --git a/src/services/watchFolder/watchFolderEventHandlers.ts b/src/services/watchFolder/watchFolderEventHandlers.ts index 93896ea38..bfc462c83 100644 --- a/src/services/watchFolder/watchFolderEventHandlers.ts +++ b/src/services/watchFolder/watchFolderEventHandlers.ts @@ -22,7 +22,9 @@ export async function diskFileAddedCallback(file: ElectronFile) { files: [file], }; watchFolderService.pushEvent(event); - addLogLine(`added (upload) to event queue, ${JSON.stringify(event)}`); + addLogLine( + `added (upload) to event queue, collectionName:${event.collectionName} folderPath:${event.folderPath}, filesCount: ${event.files.length}` + ); } catch (e) { logError(e, 'error while calling diskFileAddedCallback'); } @@ -46,7 +48,9 @@ export async function diskFileRemovedCallback(filePath: string) { paths: [filePath], }; watchFolderService.pushEvent(event); - addLogLine(`added (trash) to event queue, ${JSON.stringify(event)}`); + addLogLine( + `added (trash) to event queue collectionName:${event.collectionName} folderPath:${event.folderPath} , pathsCount: ${event.paths.length}` + ); } catch (e) { logError(e, 'error while calling diskFileRemovedCallback'); } diff --git a/src/services/watchFolder/watchFolderService.ts b/src/services/watchFolder/watchFolderService.ts index 4ded8cf6d..714536e53 100644 --- a/src/services/watchFolder/watchFolderService.ts +++ b/src/services/watchFolder/watchFolderService.ts @@ -80,8 +80,6 @@ class watchFolderService { try { let mappings = this.getWatchMappings(); - addLogLine(`mappings, ${mappings.map((m) => JSON.stringify(m))}`); - if (!mappings?.length) { return; } @@ -238,11 +236,6 @@ class watchFolderService { private async runNextEvent() { try { - addLogLine( - `mappings, - ${this.getWatchMappings().map((m) => JSON.stringify(m))}` - ); - if ( this.eventQueue.length === 0 || this.isEventRunning || @@ -252,6 +245,9 @@ class watchFolderService { } const event = this.clubSameCollectionEvents(); + addLogLine( + `running event type:${event.type} collectionName:${event.collectionName} folderPath:${event.folderPath} , fileCount:${event.files?.length} pathsCount: ${event.paths?.length}` + ); const mappings = this.getWatchMappings(); const mapping = mappings.find( (mapping) => mapping.folderPath === event.folderPath @@ -259,15 +255,19 @@ class watchFolderService { if (!mapping) { throw Error('no Mapping found for event'); } + addLogLine( + `mapping for event rootFolder: ${mapping.rootFolderName} folderPath: ${mapping.folderPath} uploadStrategy: ${mapping.uploadStrategy} syncedFilesCount: ${mapping.syncedFiles.length} ignoredFilesCount ${mapping.ignoredFiles.length}` + ); if (event.type === 'upload') { event.files = getValidFilesToUpload(event.files, mapping); + addLogLine(`valid files count: ${event.files?.length}`); if (event.files.length === 0) { return; } } this.currentEvent = event; this.currentlySyncedMapping = mapping; - addLogLine(`running event', ${JSON.stringify(event)}`); + this.setIsEventRunning(true); if (event.type === 'upload') { this.processUploadEvent(); diff --git a/src/styles/global.css b/src/styles/global.css index f2d2e6271..ba9e35bab 100644 --- a/src/styles/global.css +++ b/src/styles/global.css @@ -121,6 +121,18 @@ html, body { } +.pswp-custom-caption-container { + width: 100%; + display: flex; + justify-content: flex-end; + bottom: 56px; + background-color: transparent !important; +} + +.pswp__caption--empty{ + display: none; +} + .bg-upload-progress-bar { background-color: #51cd7c; } diff --git a/src/tests/upload.test.ts b/src/tests/upload.test.ts new file mode 100644 index 000000000..1796b92bd --- /dev/null +++ b/src/tests/upload.test.ts @@ -0,0 +1,254 @@ +import { getLocalFiles } from 'services/fileService'; +import { getLocalCollections } from 'services/collectionService'; +import { getUserDetailsV2 } from 'services/userService'; +import { groupFilesBasedOnCollectionID } from 'utils/file'; +import { FILE_TYPE } from 'constants/file'; + +export async function testUpload() { + if (!process.env.NEXT_PUBLIC_EXPECTED_JSON_PATH) { + throw Error( + 'upload test failed NEXT_PUBLIC_EXPECTED_JSON_PATH missing' + ); + } + const expectedState = await import( + process.env.NEXT_PUBLIC_EXPECTED_JSON_PATH + ); + if (!expectedState) { + throw Error('upload test failed expectedState missing'); + } + + try { + await totalCollectionCountCheck(expectedState); + await collectionWiseFileCount(expectedState); + await thumbnailGenerationFailedFilesCheck(expectedState); + await livePhotoClubbingCheck(expectedState); + await exifDataParsingCheck(expectedState); + await googleMetadataReadingCheck(expectedState); + await totalFileCountCheck(expectedState); + } catch (e) { + console.log(e); + } +} + +async function totalFileCountCheck(expectedState) { + const userDetails = await getUserDetailsV2(); + if (expectedState['total_file_count'] === userDetails.fileCount) { + console.log('file count check passed ✅'); + } else { + throw Error( + `total file count check failed ❌, expected: ${expectedState['total_file_count']}, got: ${userDetails.fileCount}` + ); + } +} + +async function totalCollectionCountCheck(expectedState) { + const collections = await getLocalCollections(); + const files = await getLocalFiles(); + const nonEmptyCollectionIds = new Set( + files.map((file) => file.collectionID) + ); + const nonEmptyCollections = collections.filter((collection) => + nonEmptyCollectionIds.has(collection.id) + ); + if (expectedState['collection_count'] === nonEmptyCollections.length) { + console.log('collection count check passed ✅'); + } else { + throw Error( + `total Collection count check failed ❌ + expected : ${expectedState['collection_count']}, got: ${collections.length}` + ); + } +} + +async function collectionWiseFileCount(expectedState) { + const files = await getLocalFiles(); + const collections = await getLocalCollections(); + const collectionToFilesMap = groupFilesBasedOnCollectionID(files); + const collectionIDToNameMap = new Map( + collections.map((collection) => [collection.id, collection.name]) + ); + const collectionNameToFileCount = new Map( + [...collectionToFilesMap.entries()].map(([collectionID, files]) => [ + collectionIDToNameMap.get(collectionID), + files.length, + ]) + ); + Object.entries(expectedState['collection_files_count']).forEach( + ([collectionName, fileCount]) => { + if (fileCount !== collectionNameToFileCount.get(collectionName)) { + throw Error( + `collectionWiseFileCount check failed ❌ + for collection ${collectionName} + expected File count : ${fileCount} , got: ${collectionNameToFileCount.get( + collectionName + )}` + ); + } + } + ); + console.log('collection wise file count check passed ✅'); +} + +async function thumbnailGenerationFailedFilesCheck(expectedState) { + const files = await getLocalFiles(); + const filesWithStaticThumbnail = files.filter( + (file) => file.metadata.hasStaticThumbnail + ); + + const fileIDSet = new Set(); + const uniqueFilesWithStaticThumbnail = filesWithStaticThumbnail.filter( + (file) => { + if (fileIDSet.has(file.id)) { + return false; + } else { + fileIDSet.add(file.id); + return true; + } + } + ); + const fileNamesWithStaticThumbnail = uniqueFilesWithStaticThumbnail.map( + (file) => file.metadata.title + ); + + if ( + expectedState['thumbnail_generation_failure']['count'] !== + uniqueFilesWithStaticThumbnail.length + ) { + throw Error( + `thumbnailGenerationFailedFiles Count Check failed ❌ + expected: ${expectedState['thumbnail_generation_failure']['count']}, got: ${uniqueFilesWithStaticThumbnail.length}` + ); + } + expectedState['thumbnail_generation_failure']['files'].forEach( + (fileName) => { + if (!fileNamesWithStaticThumbnail.includes(fileName)) { + throw Error( + `thumbnailGenerationFailedFiles Check failed ❌ + expected: ${expectedState['thumbnail_generation_failure']['files']}, got: ${fileNamesWithStaticThumbnail}` + ); + } + } + ); + console.log('thumbnail generation failure check passed ✅'); +} + +async function livePhotoClubbingCheck(expectedState) { + const files = await getLocalFiles(); + const livePhotos = files.filter( + (file) => file.metadata.fileType === FILE_TYPE.LIVE_PHOTO + ); + + const fileIDSet = new Set(); + const uniqueLivePhotos = livePhotos.filter((file) => { + if (fileIDSet.has(file.id)) { + return false; + } else { + fileIDSet.add(file.id); + return true; + } + }); + + const livePhotoFileNames = uniqueLivePhotos.map( + (file) => file.metadata.title + ); + + if (expectedState['live_photo']['count'] !== livePhotoFileNames.length) { + throw Error( + `livePhotoClubbing Check failed ❌ + expected: ${expectedState['live_photo']['count']}, got: ${livePhotoFileNames.length}` + ); + } + expectedState['live_photo']['files'].forEach((fileName) => { + if (!livePhotoFileNames.includes(fileName)) { + throw Error( + `livePhotoClubbing Check failed ❌ + expected: ${expectedState['live_photo']['files']}, got: ${livePhotoFileNames}` + ); + } + }); + console.log('live-photo clubbing check passed ✅'); +} + +async function exifDataParsingCheck(expectedState) { + const files = await getLocalFiles(); + Object.entries(expectedState['exif']).map(([fileName, exifValues]) => { + const matchingFile = files.find( + (file) => file.metadata.title === fileName + ); + if (!matchingFile) { + throw Error(`exifDataParsingCheck failed , ${fileName} missing`); + } + if ( + exifValues['creation_time'] && + exifValues['creation_time'] !== matchingFile.metadata.creationTime + ) { + throw Error(`exifDataParsingCheck failed ❌ , + for ${fileName} + expected: ${exifValues['creation_time']} got: ${matchingFile.metadata.creationTime}`); + } + if ( + exifValues['location'] && + (Math.abs( + exifValues['location']['latitude'] - + matchingFile.metadata.latitude + ) > 1 || + Math.abs( + exifValues['location']['longitude'] - + matchingFile.metadata.longitude + ) > 1) + ) { + throw Error(`exifDataParsingCheck failed ❌ , + for ${fileName} + expected: ${JSON.stringify(exifValues['location'])} + got: [${matchingFile.metadata.latitude},${ + matchingFile.metadata.longitude + }]`); + } + }); + console.log('exif data parsing check passed ✅'); +} + +async function googleMetadataReadingCheck(expectedState) { + const files = await getLocalFiles(); + Object.entries(expectedState['google_import']).map( + ([fileName, metadata]) => { + const matchingFile = files.find( + (file) => file.metadata.title === fileName + ); + if (!matchingFile) { + throw Error( + `exifDataParsingCheck failed , ${fileName} missing` + ); + } + if ( + metadata['creation_time'] && + metadata['creation_time'] !== matchingFile.metadata.creationTime + ) { + throw Error(`googleMetadataJSON reading check failed ❌ , + for ${fileName} + expected: ${metadata['creation_time']} got: ${matchingFile.metadata.creationTime}`); + } + if ( + metadata['location'] && + (Math.abs( + metadata['location']['latitude'] - + matchingFile.metadata.latitude + ) > 1 || + Math.abs( + metadata['location']['longitude'] - + matchingFile.metadata.longitude + ) > 1) + ) { + throw Error(`googleMetadataJSON reading check failed ❌ , + for ${fileName} + expected: ${JSON.stringify( + metadata['location'] + )} + got: [${matchingFile.metadata.latitude},${ + matchingFile.metadata.longitude + }]`); + } + } + ); + console.log('googleMetadataJSON reading check passed ✅'); +} diff --git a/src/themes/darkThemeOptions.tsx b/src/themes/darkThemeOptions.tsx index 2688f5812..d99d36a62 100644 --- a/src/themes/darkThemeOptions.tsx +++ b/src/themes/darkThemeOptions.tsx @@ -9,10 +9,22 @@ declare module '@mui/material/styles' { interface TypeBackground { overPaper?: string; } + + interface BlurStrength { + base: string; + muted: string; + faint: string; + } + interface BlurStrengthOptions { + base?: string; + muted?: string; + faint?: string; + } interface Palette { accent: PaletteColor; fill: PaletteColor; - glass: PaletteColor; + backdrop: PaletteColor; + blur: BlurStrength; danger: PaletteColor; stroke: TypeText; } @@ -20,7 +32,8 @@ declare module '@mui/material/styles' { accent?: PaletteColorOptions; danger?: PaletteColorOptions; fill?: PaletteColorOptions; - glass?: PaletteColorOptions; + backdrop?: PaletteColorOptions; + blur?: BlurStrengthOptions; stroke?: Partial; } @@ -74,6 +87,12 @@ declare module '@mui/material/Alert' { } } +declare module '@mui/material/CircularProgress' { + export interface CircularProgressPropsColorOverrides { + accent: true; + } +} + // Create a theme instance. const darkThemeOptions = createTheme({ components: { @@ -243,6 +262,13 @@ const darkThemeOptions = createTheme({ }, }, }, + MuiSnackbar: { + styleOverrides: { + root: { + borderRadius: '8px', + }, + }, + }, }, palette: { @@ -265,11 +291,15 @@ const darkThemeOptions = createTheme({ dark: 'rgba(256, 256, 256, 0.12)', light: 'rgba(256, 256, 256)', }, - glass: { - main: 'rgba(256, 256, 256, 0.7)', - dark: 'rgba(256, 256, 256, 0.9)', - light: 'rgba(256, 256, 256,0.3)', - contrastText: '#000', + backdrop: { + main: 'rgba(256, 256, 256, 0.65)', + light: 'rgba(0, 0, 0,0.2)', + }, + + blur: { + base: '96px', + muted: '48px', + faint: '24px', }, text: { primary: '#fff', @@ -304,7 +334,7 @@ const darkThemeOptions = createTheme({ typography: { body1: { fontSize: '16px', - lineHeight: '19px', + lineHeight: '20px', }, body2: { fontSize: '14px', @@ -316,7 +346,7 @@ const darkThemeOptions = createTheme({ }, button: { fontSize: '16px', - lineHeight: '19px', + lineHeight: '20px', fontWeight: 'bold', textTransform: 'none', }, diff --git a/src/types/Notification/index.tsx b/src/types/Notification/index.tsx index 22ce43982..553ab20d4 100644 --- a/src/types/Notification/index.tsx +++ b/src/types/Notification/index.tsx @@ -2,11 +2,14 @@ import { ButtonProps } from '@mui/material/Button'; import { ReactNode } from 'react'; export interface NotificationAttributes { - icon?: ReactNode; + startIcon?: ReactNode; variant: ButtonProps['color']; message: JSX.Element | string; - action?: { - text: string; - callback: () => void; - }; + subtext?: JSX.Element | string; + onClick: () => void; + endIcon?: ReactNode; } + +export type SetNotificationAttributes = React.Dispatch< + React.SetStateAction +>; diff --git a/src/types/collection/index.ts b/src/types/collection/index.ts index 73925bbfe..39980d566 100644 --- a/src/types/collection/index.ts +++ b/src/types/collection/index.ts @@ -1,7 +1,11 @@ import { User } from 'types/user'; import { EnteFile } from 'types/file'; import { CollectionSummaryType, CollectionType } from 'constants/collection'; -import { MagicMetadataCore, VISIBILITY_STATE } from 'types/magicMetadata'; +import { + MagicMetadataCore, + SUB_TYPE, + VISIBILITY_STATE, +} from 'types/magicMetadata'; export interface Collection { id: number; @@ -82,6 +86,7 @@ export interface RemoveFromCollectionRequest { export interface CollectionMagicMetadataProps { visibility?: VISIBILITY_STATE; + subType?: SUB_TYPE; } export interface CollectionMagicMetadata diff --git a/src/types/dialogBox/index.ts b/src/types/dialogBox/index.ts index 7bf155dda..4350c3388 100644 --- a/src/types/dialogBox/index.ts +++ b/src/types/dialogBox/index.ts @@ -1,6 +1,7 @@ import { ButtonProps } from '@mui/material'; export interface DialogBoxAttributes { + icon?: React.ReactNode; title?: string; staticBackdrop?: boolean; nonClosable?: boolean; diff --git a/src/types/electron/index.ts b/src/types/electron/index.ts index 3bb4f59bc..e881667cb 100644 --- a/src/types/electron/index.ts +++ b/src/types/electron/index.ts @@ -1,6 +1,11 @@ import { ElectronFile } from 'types/upload'; import { WatchMapping } from 'types/watchFolder'; +export interface AppUpdateInfo { + autoUpdatable: boolean; + version: string; +} + export interface ElectronAPIs { exists: (path: string) => boolean; checkExistsAndCreateCollectionDir: (dirPath: string) => Promise; @@ -62,4 +67,19 @@ export interface ElectronAPIs { getEncryptionKey: () => Promise; openDiskCache: (cacheName: string) => Promise; deleteDiskCache: (cacheName: string) => Promise; + logToDisk: (msg: string) => void; + convertHEIC(fileData: Uint8Array): Promise; + openLogDirectory: () => void; + registerUpdateEventListener: ( + showUpdateDialog: (updateInfo: AppUpdateInfo) => void + ) => void; + updateAndRestart: () => void; + skipAppVersion: (version: string) => void; + getSentryUserID: () => Promise; + getAppVersion: () => Promise; + runFFmpegCmd: ( + cmd: string[], + inputFile: File | ElectronFile, + outputFileName: string + ) => Promise; } diff --git a/src/types/file/index.ts b/src/types/file/index.ts index bad26b122..73c7631bf 100644 --- a/src/types/file/index.ts +++ b/src/types/file/index.ts @@ -19,6 +19,7 @@ export interface FileMagicMetadata extends Omit { export interface FilePublicMagicMetadataProps { editedTime?: number; editedName?: string; + caption?: string; } export interface FilePublicMagicMetadata @@ -26,6 +27,11 @@ export interface FilePublicMagicMetadata data: FilePublicMagicMetadataProps; } +export interface EnteFileInfo { + fileSize: number; + thumbSize: number; +} + export interface EnteFile { id: number; collectionID: number; @@ -33,6 +39,7 @@ export interface EnteFile { file: fileAttribute; thumbnail: fileAttribute; metadata: Metadata; + info: EnteFileInfo; magicMetadata: FileMagicMetadata; pubMagicMetadata: FilePublicMagicMetadata; encryptedKey: string; @@ -43,9 +50,13 @@ export interface EnteFile { html: string; w: number; h: number; + title: string; isDeleted: boolean; isTrashed?: boolean; deleteBy?: number; + isSourceLoaded?: boolean; + originalVideoURL?: string; + originalImageURL?: string; dataIndex: number; updationTime: number; } diff --git a/src/types/gallery/index.ts b/src/types/gallery/index.ts index c4d27ef6e..36542de6f 100644 --- a/src/types/gallery/index.ts +++ b/src/types/gallery/index.ts @@ -2,7 +2,6 @@ import { CollectionSelectorAttributes } from 'components/Collections/CollectionS import { TimeStampListItem } from 'components/PhotoList'; import { Collection } from 'types/collection'; import { EnteFile } from 'types/file'; -import { NotificationAttributes } from 'types/Notification'; export type SelectedState = { [k: number]: boolean; @@ -18,11 +17,10 @@ export type SetCollectionSelectorAttributes = React.Dispatch< export type GalleryContextType = { thumbs: Map; - files: Map; + files: Map; showPlanSelectorModal: () => void; setActiveCollection: (collection: number) => void; syncWithRemote: (force?: boolean, silent?: boolean) => Promise; - setNotificationAttributes: (attributes: NotificationAttributes) => void; setBlockingLoad: (value: boolean) => void; photoListHeader: TimeStampListItem; }; diff --git a/src/types/magicMetadata/index.ts b/src/types/magicMetadata/index.ts index f16d54b9c..f642501ea 100644 --- a/src/types/magicMetadata/index.ts +++ b/src/types/magicMetadata/index.ts @@ -11,8 +11,13 @@ export interface EncryptedMagicMetadataCore } export enum VISIBILITY_STATE { - VISIBLE, - ARCHIVED, + VISIBLE = 0, + ARCHIVED = 1, + HIDDEN = 2, +} + +export enum SUB_TYPE { + DEFAULT_HIDDEN = 1, } export const NEW_FILE_MAGIC_METADATA: MagicMetadataCore = { diff --git a/src/utils/billing/index.ts b/src/utils/billing/index.ts index 2394eb487..84308a074 100644 --- a/src/utils/billing/index.ts +++ b/src/utils/billing/index.ts @@ -153,7 +153,6 @@ export function isUserSubscribedPlan(plan: Plan, subscription: Subscription) { } export function hasStripeSubscription(subscription: Subscription) { return ( - hasPaidSubscription(subscription) && subscription.paymentProvider.length > 0 && subscription.paymentProvider === PAYMENT_PROVIDER_STRIPE ); diff --git a/src/utils/collection/index.ts b/src/utils/collection/index.ts index 1743e2c91..33ed973e8 100644 --- a/src/utils/collection/index.ts +++ b/src/utils/collection/index.ts @@ -30,9 +30,11 @@ import { getAlbumSiteHost } from 'constants/pages'; import { getUnixTimeInMicroSecondsWithDelta } from 'utils/time'; import { NEW_COLLECTION_MAGIC_METADATA, + SUB_TYPE, VISIBILITY_STATE, } from 'types/magicMetadata'; import { IsArchived, updateMagicMetadataProps } from 'utils/magicMetadata'; +import { ENV_DEVELOPMENT } from 'constants/sentry'; export enum COLLECTION_OPS_TYPE { ADD, @@ -121,7 +123,7 @@ export function appendCollectionKeyToShareURL( } const bs58 = require('bs58'); const sharableURL = new URL(url); - if (process.env.NODE_ENV === 'development') { + if (process.env.NODE_ENV === ENV_DEVELOPMENT) { sharableURL.host = getAlbumSiteHost(); sharableURL.protocol = 'http'; } @@ -226,3 +228,11 @@ export const getUserOwnedCollections = (collections: Collection[]) => { } return collections.filter((collection) => collection.owner.id === user.id); }; + +export const getNonHiddenCollections = (collections: Collection[]) => { + return collections.filter((collection) => !isCollectionHidden(collection)); +}; + +export const isCollectionHidden = (collection: Collection) => + collection.magicMetadata?.data.visibility === VISIBILITY_STATE.HIDDEN || + collection.magicMetadata?.data.subType === SUB_TYPE.DEFAULT_HIDDEN; diff --git a/src/utils/common/index.ts b/src/utils/common/index.ts index b8eb8fef3..35a8b4df8 100644 --- a/src/utils/common/index.ts +++ b/src/utils/common/index.ts @@ -1,18 +1,6 @@ -import constants from 'utils/strings/constants'; import { CustomError } from 'utils/error'; -import GetDeviceOS, { OS } from './deviceDetection'; -const DESKTOP_APP_GITHUB_DOWNLOAD_URL = - 'https://github.com/ente-io/bhari-frame/releases/latest'; - -const APP_DOWNLOAD_ENTE_URL_PREFIX = 'https://ente.io/download'; - -export function checkConnectivity() { - if (navigator.onLine) { - return true; - } - throw new Error(constants.NO_INTERNET_CONNECTION); -} +export const APP_DOWNLOAD_URL = 'https://ente.io/download/desktop'; export function runningInBrowser() { return typeof window !== 'undefined'; @@ -24,22 +12,8 @@ export async function sleep(time: number) { }); } -export function getOSSpecificDesktopAppDownloadLink() { - const os = GetDeviceOS(); - let url = ''; - if (os === OS.WINDOWS) { - url = `${APP_DOWNLOAD_ENTE_URL_PREFIX}/exe`; - } else if (os === OS.MAC) { - url = `${APP_DOWNLOAD_ENTE_URL_PREFIX}/dmg`; - } else { - url = DESKTOP_APP_GITHUB_DOWNLOAD_URL; - } - return url; -} export function downloadApp() { - const link = getOSSpecificDesktopAppDownloadLink(); - const win = window.open(link, '_blank'); - win.focus(); + openLink(APP_DOWNLOAD_URL, true); } export function reverseString(title: string) { @@ -54,12 +28,12 @@ export function initiateEmail(email: string) { a.rel = 'noreferrer noopener'; a.click(); } -export const promiseWithTimeout = async ( - request: Promise, +export const promiseWithTimeout = async ( + request: Promise, timeout: number -) => { +): Promise => { const timeoutRef = { current: null }; - const rejectOnTimeout = new Promise((_, reject) => { + const rejectOnTimeout = new Promise((_, reject) => { timeoutRef.current = setTimeout( () => reject(Error(CustomError.WAIT_TIME_EXCEEDED)), timeout @@ -110,3 +84,7 @@ function isPromise(p: any) { return false; } + +export function isClipboardItemPresent() { + return typeof ClipboardItem !== 'undefined'; +} diff --git a/src/utils/error/index.ts b/src/utils/error/index.ts index 9d08e0ca7..4aa6a3c48 100644 --- a/src/utils/error/index.ts +++ b/src/utils/error/index.ts @@ -1,5 +1,3 @@ -import constants from 'utils/strings/constants'; - export const ServerErrorCodes = { SESSION_EXPIRED: '401', NO_ACTIVE_SUBSCRIPTION: '402', @@ -14,7 +12,6 @@ export const ServerErrorCodes = { }; export enum CustomError { - UNKNOWN_ERROR = 'unknown error', SUBSCRIPTION_VERIFICATION_ERROR = 'Subscription verification failed', THUMBNAIL_GENERATION_FAILED = 'thumbnail generation failed', VIDEO_PLAYBACK_FAILED = 'video playback failed', @@ -47,6 +44,8 @@ export enum CustomError { INCORRECT_PASSWORD = 'incorrect password', UPLOAD_CANCELLED = 'upload cancelled', REQUEST_TIMEOUT = 'request taking too long', + HIDDEN_COLLECTION_SYNC_FILE_ATTEMPTED = 'hidden collection sync file attempted', + UNKNOWN_ERROR = 'Something went wrong, please try again', } function parseUploadErrorCodes(error) { @@ -67,7 +66,7 @@ function parseUploadErrorCodes(error) { parsedMessage = CustomError.FILE_TOO_LARGE; break; default: - parsedMessage = `${constants.UNKNOWN_ERROR} statusCode:${errorCode}`; + parsedMessage = `${CustomError.UNKNOWN_ERROR} statusCode:${errorCode}`; } } else { parsedMessage = error.message; @@ -120,29 +119,10 @@ export const parseSharingErrorCodes = (error) => { parsedMessage = CustomError.TOO_MANY_REQUESTS; break; default: - parsedMessage = `${constants.UNKNOWN_ERROR} statusCode:${errorCode}`; + parsedMessage = `${CustomError.UNKNOWN_ERROR} statusCode:${errorCode}`; } } else { parsedMessage = error.message; } return new Error(parsedMessage); }; - -export const handleSharingErrors = (error) => { - const parsedError = parseSharingErrorCodes(error); - let errorMessage = ''; - switch (parsedError.message) { - case CustomError.BAD_REQUEST: - errorMessage = constants.SHARING_BAD_REQUEST_ERROR; - break; - case CustomError.SUBSCRIPTION_NEEDED: - errorMessage = constants.SHARING_DISABLED_FOR_FREE_ACCOUNTS; - break; - case CustomError.NOT_FOUND: - errorMessage = constants.USER_DOES_NOT_EXIST; - break; - default: - errorMessage = parsedError.message; - } - return errorMessage; -}; diff --git a/src/utils/error/ui.ts b/src/utils/error/ui.ts new file mode 100644 index 000000000..fdf695dff --- /dev/null +++ b/src/utils/error/ui.ts @@ -0,0 +1,28 @@ +import constants from 'utils/strings/constants'; +import { parseSharingErrorCodes, CustomError } from '.'; + +export const handleSharingErrors = (error) => { + const parsedError = parseSharingErrorCodes(error); + let errorMessage = ''; + switch (parsedError.message) { + case CustomError.BAD_REQUEST: + errorMessage = constants.SHARING_BAD_REQUEST_ERROR; + break; + case CustomError.SUBSCRIPTION_NEEDED: + errorMessage = constants.SHARING_DISABLED_FOR_FREE_ACCOUNTS; + break; + case CustomError.NOT_FOUND: + errorMessage = constants.USER_DOES_NOT_EXIST; + break; + default: + errorMessage = parsedError.message; + } + return errorMessage; +}; + +export function checkConnectivity() { + if (navigator.onLine) { + return true; + } + throw new Error(constants.NO_INTERNET_CONNECTION); +} diff --git a/src/utils/exif/index.ts b/src/utils/exif/index.ts deleted file mode 100644 index 83e1a6695..000000000 --- a/src/utils/exif/index.ts +++ /dev/null @@ -1,13 +0,0 @@ -export function prettyPrintExif(exifData: Object) { - let strPretty = ''; - for (const [tagName, tagValue] of Object.entries(exifData)) { - if (tagValue instanceof Uint8Array) { - strPretty += tagName + ' : ' + '[' + tagValue + ']' + '\r\n'; - } else if (tagValue instanceof Date) { - strPretty += tagName + ' : ' + tagValue.toDateString() + '\r\n'; - } else { - strPretty += tagName + ' : ' + tagValue + '\r\n'; - } - } - return strPretty; -} diff --git a/src/utils/export/index.ts b/src/utils/export/index.ts index 7b40b2ce1..1d2010f3c 100644 --- a/src/utils/export/index.ts +++ b/src/utils/export/index.ts @@ -5,8 +5,10 @@ import { CollectionIDPathMap, ExportRecord } from 'types/export'; import { EnteFile } from 'types/file'; import { Metadata } from 'types/upload'; -import { formatDate, splitFilenameAndExtension } from 'utils/file'; +import { splitFilenameAndExtension } from 'utils/file'; import { ENTE_METADATA_FOLDER } from 'constants/export'; +import sanitize from 'sanitize-filename'; +import { formatDateTimeShort } from 'utils/time/format'; export const getExportRecordFileUID = (file: EnteFile) => `${file.id}_${file.collectionID}_${file.updationTime}`; @@ -127,22 +129,25 @@ export const dedupe = (files: any[]) => { export const getGoogleLikeMetadataFile = ( fileSaveName: string, - metadata: Metadata + file: EnteFile ) => { + const metadata: Metadata = file.metadata; const creationTime = Math.floor(metadata.creationTime / 1000000); const modificationTime = Math.floor( (metadata.modificationTime ?? metadata.creationTime) / 1000000 ); + const captionValue: string = file?.pubMagicMetadata?.data?.caption; return JSON.stringify( { title: fileSaveName, + caption: captionValue, creationTime: { timestamp: creationTime, - formatted: formatDate(creationTime * 1000), + formatted: formatDateTimeShort(creationTime * 1000), }, modificationTime: { timestamp: modificationTime, - formatted: formatDate(modificationTime * 1000), + formatted: formatDateTimeShort(modificationTime * 1000), }, geoData: { latitude: metadata.latitude, @@ -158,7 +163,7 @@ export const oldSanitizeName = (name: string) => name.replaceAll('/', '_').replaceAll(' ', '_'); export const sanitizeName = (name: string) => - name.replace(/[^a-z0-9.]/gi, '_').toLowerCase(); + sanitize(name, { replacement: '_' }); export const getUniqueCollectionFolderPath = ( dir: string, diff --git a/src/utils/file/index.ts b/src/utils/file/index.ts index e1f035702..63d5165c1 100644 --- a/src/utils/file/index.ts +++ b/src/utils/file/index.ts @@ -21,27 +21,23 @@ import { FILE_TYPE, } from 'constants/file'; import PublicCollectionDownloadManager from 'services/publicCollectionDownloadManager'; -import HEICConverter from 'services/heicConverter/heicConverterService'; -import ffmpegService from 'services/ffmpeg/ffmpegService'; +import heicConversionService from 'services/heicConversionService'; +import * as ffmpegService from 'services/ffmpeg/ffmpegService'; import { NEW_FILE_MAGIC_METADATA, VISIBILITY_STATE } from 'types/magicMetadata'; import { IsArchived, updateMagicMetadataProps } from 'utils/magicMetadata'; import { addLogLine } from 'utils/logging'; import { makeHumanReadableStorage } from 'utils/billing'; +import { CustomError } from 'utils/error'; + +const WAIT_TIME_IMAGE_CONVERSION = 30 * 1000; + export function downloadAsFile(filename: string, content: string) { const file = new Blob([content], { type: 'text/plain', }); - const a = document.createElement('a'); - a.href = URL.createObjectURL(file); - a.download = filename; - - a.style.display = 'none'; - document.body.appendChild(a); - - a.click(); - - a.remove(); + const fileURL = URL.createObjectURL(file); + downloadUsingAnchor(fileURL, filename); } export async function downloadFile( @@ -116,10 +112,6 @@ export async function downloadFile( tempURL = URL.createObjectURL(fileBlob); downloadUsingAnchor(tempURL, file.metadata.title); } - - tempURL && URL.revokeObjectURL(tempURL); - tempImageURL && URL.revokeObjectURL(tempImageURL); - tempVideoURL && URL.revokeObjectURL(tempVideoURL); } function downloadUsingAnchor(link: string, name: string) { @@ -129,6 +121,7 @@ function downloadUsingAnchor(link: string, name: string) { a.download = name; document.body.appendChild(a); a.click(); + URL.revokeObjectURL(link); a.remove(); } @@ -170,16 +163,6 @@ export function getSelectedFiles( return selectedFiles; } -export function formatDate(date: number | Date) { - const dateTimeFormat = new Intl.DateTimeFormat('en-IN', { - weekday: 'short', - year: 'numeric', - month: 'long', - day: 'numeric', - }); - return dateTimeFormat.format(date); -} - export function sortFiles(files: EnteFile[]) { // sort according to modification time first files = files.sort((a, b) => { @@ -304,14 +287,25 @@ export async function getRenderableFileURL(file: EnteFile, fileBlob: Blob) { file.metadata.title, fileBlob ); - return [URL.createObjectURL(convertedBlob)]; + return { + converted: [URL.createObjectURL(convertedBlob)], + original: [URL.createObjectURL(fileBlob)], + }; } case FILE_TYPE.LIVE_PHOTO: { const livePhoto = await getRenderableLivePhoto(file, fileBlob); - return livePhoto.map((asset) => URL.createObjectURL(asset)); + return { + converted: livePhoto.map((asset) => URL.createObjectURL(asset)), + original: [URL.createObjectURL(fileBlob)], + }; + } + default: { + const previewURL = URL.createObjectURL(fileBlob); + return { + converted: [previewURL], + original: [previewURL], + }; } - default: - return [URL.createObjectURL(fileBlob)]; } } @@ -330,10 +324,9 @@ async function getRenderableLivePhoto( async function getPlayableVideo(videoNameTitle: string, video: Uint8Array) { const mp4ConvertedVideo = await ffmpegService.convertToMP4( - video, - videoNameTitle + new File([video], videoNameTitle) ); - return new Blob([mp4ConvertedVideo]); + return new Blob([await mp4ConvertedVideo.arrayBuffer()]); } async function getRenderableImage(fileName: string, imageBlob: Blob) { @@ -343,7 +336,10 @@ async function getRenderableImage(fileName: string, imageBlob: Blob) { imageBlob.size )}` ); - const convertedImageBlob = await HEICConverter.convert(imageBlob); + const convertedImageBlob = await heicConversionService.convert( + imageBlob + ); + addLogLine(`${fileName} successfully converted`); return convertedImageBlob; } else { @@ -416,6 +412,19 @@ export async function changeFileName(file: EnteFile, editedName: string) { return file; } +export async function changeCaption(file: EnteFile, caption: string) { + const updatedPublicMagicMetadataProps: FilePublicMagicMetadataProps = { + caption, + }; + + file.pubMagicMetadata = await updateMagicMetadataProps( + file.pubMagicMetadata ?? NEW_FILE_MAGIC_METADATA, + file.key, + updatedPublicMagicMetadataProps + ); + return file; +} + export function isSharedFile(user: User, file: EnteFile) { if (!user?.id || !file?.ownerID) { return false; @@ -522,3 +531,46 @@ export const getUserOwnedNonTrashedFiles = (files: EnteFile[]) => { } return files.filter((file) => file.isTrashed || file.ownerID === user.id); }; + +// doesn't work on firefox +export const copyFileToClipboard = async (fileUrl: string) => { + const canvas = document.createElement('canvas'); + const canvasCTX = canvas.getContext('2d'); + const image = new Image(); + + const blobPromise = new Promise((resolve, reject) => { + let timeout: NodeJS.Timeout = null; + try { + image.setAttribute('src', fileUrl); + image.onload = () => { + canvas.width = image.width; + canvas.height = image.height; + canvasCTX.drawImage(image, 0, 0, image.width, image.height); + canvas.toBlob( + (blob) => { + resolve(blob); + }, + 'image/png', + 1 + ); + + clearTimeout(timeout); + }; + } catch (e) { + void logError(e, 'failed to copy to clipboard'); + reject(e); + } finally { + clearTimeout(timeout); + } + timeout = setTimeout( + () => reject(Error(CustomError.WAIT_TIME_EXCEEDED)), + WAIT_TIME_IMAGE_CONVERSION + ); + }); + + const { ClipboardItem } = window; + + await navigator.clipboard + .write([new ClipboardItem({ 'image/png': blobPromise })]) + .catch((e) => logError(e, 'failed to copy to clipboard')); +}; diff --git a/src/utils/logging/index.ts b/src/utils/logging/index.ts index 9e12d6e12..19646b046 100644 --- a/src/utils/logging/index.ts +++ b/src/utils/logging/index.ts @@ -1,30 +1,111 @@ import { ElectronFile } from 'types/upload'; import { convertBytesToHumanReadable } from 'utils/file/size'; -import { formatDateTime } from 'utils/time'; -import { saveLogLine, getLogs } from 'utils/storage'; +import { formatDateTimeShort } from 'utils/time/format'; +import { isDEVSentryENV } from 'constants/sentry'; +import isElectron from 'is-electron'; +import ElectronService from 'services/electron/common'; +import { logError } from 'utils/sentry'; +import { + getData, + LS_KEYS, + removeData, + setData, +} from 'utils/storage/localStorage'; + +export const MAX_LOG_SIZE = 5 * 1024 * 1024; // 5MB +export const MAX_LOG_LINES = 1000; + +export interface Log { + timestamp: number; + logLine: string; +} export function addLogLine(log: string) { - if (!process.env.NEXT_PUBLIC_SENTRY_ENV) { - console.log(log); + try { + if (isDEVSentryENV()) { + console.log(log); + } + if (isElectron()) { + ElectronService.logToDisk(log); + } else { + saveLogLine({ + timestamp: Date.now(), + logLine: log, + }); + } + } catch (e) { + if (e.name === 'QuotaExceededError') { + deleteLogs(); + addLogLine('logs cleared'); + } + logError(e, 'failed to addLogLine', undefined, true); + // ignore } - saveLogLine({ - timestamp: Date.now(), - logLine: log, - }); } export const addLocalLog = (getLog: () => string) => { - if (!process.env.NEXT_PUBLIC_SENTRY_ENV) { + if (isDEVSentryENV()) { console.log(getLog()); } }; export function getDebugLogs() { - return getLogs().map( - (log) => `[${formatDateTime(log.timestamp)}] ${log.logLine}` - ); + return combineLogLines(getLogs()); } export function getFileNameSize(file: File | ElectronFile) { return `${file.name}_${convertBytesToHumanReadable(file.size)}`; } + +export const clearLogsIfLocalStorageLimitExceeded = () => { + try { + const logs = getDebugLogs(); + const logSize = getStringSize(logs); + if (logSize > MAX_LOG_SIZE) { + deleteLogs(); + addLogLine('Logs cleared due to size limit exceeded'); + } else { + try { + addLogLine(`app started`); + } catch (e) { + deleteLogs(); + } + } + addLogLine(`logs size: ${convertBytesToHumanReadable(logSize)}`); + } catch (e) { + logError(e, 'failed to clearLogsIfLocalStorageLimitExceeded'); + } +}; + +function saveLogLine(log: Log) { + const logs = getLogs(); + if (logs.length > MAX_LOG_LINES) { + logs.slice(logs.length - MAX_LOG_LINES); + } + logs.push(log); + setLogs(logs); +} + +function getLogs(): Log[] { + return getData(LS_KEYS.LOGS)?.logs ?? []; +} + +function setLogs(logs: Log[]) { + setData(LS_KEYS.LOGS, { logs }); +} + +function deleteLogs() { + removeData(LS_KEYS.LOGS); +} + +function getStringSize(str: string) { + return new Blob([str]).size; +} + +function formatLog(log: Log) { + return `[${formatDateTimeShort(log.timestamp)}] ${log.logLine}`; +} + +function combineLogLines(logs: Log[]) { + return logs.map(formatLog).join('\n'); +} diff --git a/src/utils/sentry/index.ts b/src/utils/sentry/index.ts index 35a4d873b..116d35909 100644 --- a/src/utils/sentry/index.ts +++ b/src/utils/sentry/index.ts @@ -1,27 +1,31 @@ import * as Sentry from '@sentry/nextjs'; +import { isDEVSentryENV } from 'constants/sentry'; import { addLogLine } from 'utils/logging'; import { getSentryUserID } from 'utils/user'; -export const logError = ( +export const logError = async ( error: any, msg: string, - info?: Record + info?: Record, + skipAddLogLine = false ) => { if (isErrorUnnecessaryForSentry(error)) { return; } const err = errorWithContext(error, msg); - addLogLine( - `error: ${error?.name} ${error?.message} ${ - error?.stack - } msg: ${msg} info: ${JSON.stringify(info)}` - ); - if (!process.env.NEXT_PUBLIC_SENTRY_ENV) { + if (!skipAddLogLine) { + addLogLine( + `error: ${error?.name} ${error?.message} ${ + error?.stack + } msg: ${msg} info: ${JSON.stringify(info)}` + ); + } + if (isDEVSentryENV()) { console.log(error, { msg, info }); } Sentry.captureException(err, { level: Sentry.Severity.Info, - user: { id: getSentryUserID() }, + user: { id: await getSentryUserID() }, contexts: { ...(info && { info: info, diff --git a/src/utils/storage/index.ts b/src/utils/storage/index.ts index 853518cb3..0b35736cd 100644 --- a/src/utils/storage/index.ts +++ b/src/utils/storage/index.ts @@ -1,12 +1,5 @@ import { getData, LS_KEYS, setData } from './localStorage'; -export interface Log { - timestamp: number; - logLine: string; -} - -const MAX_LOG_LINES = 1000; - export const isFirstLogin = () => getData(LS_KEYS.IS_FIRST_LOGIN)?.status ?? false; @@ -28,13 +21,3 @@ export function getLivePhotoInfoShownCount() { export function setLivePhotoInfoShownCount(count) { setData(LS_KEYS.LIVE_PHOTO_INFO_SHOWN_COUNT, { count }); } - -export function saveLogLine(log: Log) { - setData(LS_KEYS.LOGS, { - logs: [...getLogs(), log].slice(-1 * MAX_LOG_LINES), - }); -} - -export function getLogs(): Log[] { - return getData(LS_KEYS.LOGS)?.logs ?? []; -} diff --git a/src/utils/storage/localStorage.ts b/src/utils/storage/localStorage.ts index 7674e4822..04443b1db 100644 --- a/src/utils/storage/localStorage.ts +++ b/src/utils/storage/localStorage.ts @@ -40,7 +40,8 @@ export const getData = (key: LS_KEYS) => { if ( typeof localStorage === 'undefined' || typeof key === 'undefined' || - typeof localStorage.getItem(key) === 'undefined' + typeof localStorage.getItem(key) === 'undefined' || + localStorage.getItem(key) === 'undefined' ) { return null; } diff --git a/src/utils/strings/englishConstants.tsx b/src/utils/strings/englishConstants.tsx index 27f83056b..8acbbef7a 100644 --- a/src/utils/strings/englishConstants.tsx +++ b/src/utils/strings/englishConstants.tsx @@ -71,8 +71,8 @@ const englishConstants = { UNKNOWN_ERROR: 'Something went wrong, please try again', INVALID_CODE: 'Invalid verification code', EXPIRED_CODE: 'Your verification code has expired', - SENDING: 'sending...', - SENT: 'sent!', + SENDING: 'Sending...', + SENT: 'Sent!', PASSWORD: 'Password', LINK_PASSWORD: 'Enter password to unlock the album', ENTER_PASSPHRASE: 'Enter your password', @@ -99,6 +99,8 @@ const englishConstants = { SELECT_COLLECTION: 'Select an album to upload to', CREATE_COLLECTION: 'New album', ENTER_ALBUM_NAME: 'Album name', + CLOSE_OPTION: 'Close (Esc)', + ENTER_FILE_NAME: 'File name', CLOSE: 'Close', NO: 'No', NOTHING_HERE: 'Nothing to see here yet 👀', @@ -107,7 +109,8 @@ const englishConstants = { UPLOAD_STAGE_MESSAGE: { 0: 'Preparing to upload', 1: 'Reading google metadata files', - 2: 'Reading file metadata', + 2: (fileCounter) => + `${fileCounter.finished} / ${fileCounter.total} files metadata extracted`, 3: (fileCounter) => `${fileCounter.finished} / ${fileCounter.total} files backed up`, 4: 'Cancelling remaining uploads', @@ -131,10 +134,12 @@ const englishConstants = { ALBUM_NAME: 'Album name', CREATE: 'Create', DOWNLOAD: 'Download', - TOGGLE_FULLSCREEN: 'Toggle fullscreen', + DOWNLOAD_OPTION: 'Download (D)', + COPY_OPTION: 'Copy as PNG (Ctrl/Cmd - C)', + TOGGLE_FULLSCREEN: 'Toggle fullscreen (F)', ZOOM_IN_OUT: 'Zoom in/out', - PREVIOUS: 'Previous (arrow left)', - NEXT: 'Next (arrow right)', + PREVIOUS: 'Previous (←)', + NEXT: 'Next (→)', NO_INTERNET_CONNECTION: 'Please check your internet connection and try again', TITLE: 'ente.io | encrypted photo storage', @@ -146,14 +151,18 @@ const englishConstants = { UPLOAD_FIRST_PHOTO: 'Preserve', UPLOAD_DROPZONE_MESSAGE: 'Drop to backup your files', WATCH_FOLDER_DROPZONE_MESSAGE: 'Drop to add watched folder', - CONFIRM_DELETE: 'Confirm deletion', - DELETE_MESSAGE: `The selected files will be permanently deleted and can't be restored `, TRASH_FILES_TITLE: 'Delete files?', + TRASH_FILE_TITLE: 'Delete file?', DELETE_FILES_TITLE: 'Delete immediately?', DELETE_FILES_MESSAGE: 'Selected files will be permanently deleted from your ente account.', DELETE_FILE: 'Delete files', DELETE: 'Delete', + DELETE_OPTION: 'Delete (DEL)', + FAVORITE: 'Favorite', + FAVORITE_OPTION: 'Favorite (L)', + UNFAVORITE_OPTION: 'Unfavorite (L)', + UNFAVORITE: 'Unfavorite', MULTI_FOLDER_UPLOAD: 'Multiple folders detected', UPLOAD_STRATEGY_CHOICE: 'Would you like to upload them into', UPLOAD_STRATEGY_SINGLE_COLLECTION: 'A single album', @@ -348,6 +357,7 @@ const englishConstants = { ), RENAME: 'Rename', + RENAME_FILE: 'Rename file', RENAME_COLLECTION: 'Rename album', DELETE_COLLECTION_TITLE: 'Delete album?', DELETE_COLLECTION: 'Delete album', @@ -371,7 +381,6 @@ const englishConstants = {

All files will be queued for download sequentially

), - ARCHIVED_ALBUM: 'Archived album', DOWNLOAD_COLLECTION_FAILED: 'Album downloading failed, please try again', CREATE_ALBUM_FAILED: 'Failed to create album , please try again', @@ -431,14 +440,20 @@ const englishConstants = { VIDEO_PLAYBACK_FAILED_DOWNLOAD_INSTEAD: 'This video cannot be played on your browser', METADATA: 'Metadata', - INFO: 'Info', - FILE_ID: 'File id', + INFO: 'Info ', + INFO_OPTION: 'Info (I)', + FILE_ID: 'File ID', FILE_NAME: 'File name', + CAPTION: 'Description', + CAPTION_PLACEHOLDER: 'Add a description', CREATION_TIME: 'Creation time', UPDATED_ON: 'Updated on', LOCATION: 'Location', - SHOW_MAP: 'show on map', - EXIF: 'Exif', + SHOW_ON_MAP: 'View on OpenStreetMap', + DETAILS: 'Details', + VIEW_EXIF: 'View all EXIF data', + NO_EXIF: 'No EXIF data', + EXIF: 'EXIF', DEVICE: 'Device', IMAGE_SIZE: 'Image size', FLASH: 'Flash', @@ -509,7 +524,7 @@ const englishConstants = { EMAIl_ALREADY_OWNED: 'Email already taken', EMAIL_UDPATE_SUCCESSFUL: 'Your email has been udpated successfully', UPLOAD_FAILED: 'Upload failed', - ETAGS_BLOCKED: (url: string) => ( + ETAGS_BLOCKED: (link: string) => ( <> We were unable to upload the following files because of your @@ -518,13 +533,9 @@ const englishConstants = { Please disable any addons that might be preventing ente from using eTags to upload large files, or use our{' '} - + desktop app - {' '} + {' '} for a more reliable import experience. @@ -543,6 +554,7 @@ const englishConstants = { 'Skipped these as there are files with matching names in the same album', UNSUPPORTED_INFO: 'ente does not support these file formats yet', BLOCKED_UPLOADS: 'Blocked uploads', + INPROGRESS_METADATA_EXTRACTION: 'In progress', INPROGRESS_UPLOADS: 'Uploads in progress', TOO_LARGE_UPLOADS: 'Large files', LARGER_THAN_AVAILABLE_STORAGE_UPLOADS: 'Insufficient storage', @@ -553,11 +565,11 @@ const englishConstants = { THUMBNAIL_GENERATION_FAILED_INFO: 'These files were uploaded, but unfortunately we could not generate the thumbnails for them.', UPLOAD_TO_COLLECTION: 'Upload to album', - ARCHIVE: 'Hide', - ARCHIVE_SECTION_NAME: 'Hidden', + ARCHIVE: 'Archive', + ARCHIVE_SECTION_NAME: 'Archive', ALL_SECTION_NAME: 'All', MOVE_TO_COLLECTION: 'Move to album', - UNARCHIVE: 'Unhide', + UNARCHIVE: 'Unarchive', MOVE: 'Move', ADD: 'Add', SORT: 'Sort', @@ -567,6 +579,8 @@ const englishConstants = { MOVE_TO_TRASH: 'Move to trash', TRASH_FILES_MESSAGE: 'Selected files will be removed from all albums and moved to trash.', + TRASH_FILE_MESSAGE: + 'The file will be removed from all albums and moved to trash.', DELETE_PERMANENTLY: 'Delete permanently', RESTORE: 'Restore', CONFIRM_RESTORE: 'Confirm restoration', @@ -622,6 +636,7 @@ const englishConstants = { <>File time updation failed for some files, please retry ), FILE_NAME_CHARACTER_LIMIT: '100 characters max', + CAPTION_CHARACTER_LIMIT: '280 characters max', DATE_TIME_ORIGINAL: 'EXIF:DateTimeOriginal', DATE_TIME_DIGITIZED: 'EXIF:DateTimeDigitized', @@ -692,7 +707,7 @@ const englishConstants = { TERM_1: 'I hereby state that I have a good faith belief that the sharing of copyrighted material at the location above is not authorized by the copyright owner, its agent, or the law (e.g., as a fair use). ', TERM_2: 'I hereby state that the information in this Notice is accurate and, under penalty of perjury, that I am the owner, or authorized to act on behalf of, the owner, of the copyright or of an exclusive right under the copyright that is allegedly infringed. ', TERM_3: 'I acknowledge that any person who knowingly materially misrepresents that material or activity is infringing may be subject to liability for damages. ', - PRESERVED_BY: 'preserved by', + PRESERVED_BY: 'Preserved by', ENTE_IO: 'ente.io', LIVE: 'LIVE', DISABLE_PASSWORD: 'Disable password lock', @@ -820,6 +835,19 @@ const englishConstants = { UPLOADED_TO_SINGLE_COLLECTION: 'Uploaded to single collection', UPLOADED_TO_SEPARATE_COLLECTIONS: 'Uploaded to separate collections', NEVERMIND: 'Nevermind', + UPDATE_AVAILABLE: 'Update available', + UPDATE_INSTALLABLE_MESSAGE: + 'A new version of ente is ready to be installed.', + INSTALL_NOW: `Install now`, + INSTALL_ON_NEXT_LAUNCH: 'Install on next launch', + UPDATE_AVAILABLE_MESSAGE: + 'A new version of ente has been released, but it cannot be automatically downloaded and installed.', + DOWNLOAD_AND_INSTALL: 'Download and install', + IGNORE_THIS_VERSION: 'Ignore this version', + RUN_TESTS: 'Run tests', + TODAY: 'Today', + YESTERDAY: 'Yesterday', + AT: 'at', }; export default englishConstants; diff --git a/src/utils/temp/index.ts b/src/utils/temp/index.ts new file mode 100644 index 000000000..75319fdb8 --- /dev/null +++ b/src/utils/temp/index.ts @@ -0,0 +1,14 @@ +const CHARACTERS = + 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; + +export function generateTempName(length: number) { + let result = ''; + + const charactersLength = CHARACTERS.length; + for (let i = 0; i < length; i++) { + result += CHARACTERS.charAt( + Math.floor(Math.random() * charactersLength) + ); + } + return result; +} diff --git a/src/utils/time/format.ts b/src/utils/time/format.ts new file mode 100644 index 000000000..aa0502525 --- /dev/null +++ b/src/utils/time/format.ts @@ -0,0 +1,85 @@ +export function formatDateFull(date: number | Date) { + const dateTimeFormat1 = new Intl.DateTimeFormat('en-US', { + weekday: 'short', + month: 'short', + day: 'numeric', + }); + + const dateTimeFormat2 = new Intl.DateTimeFormat('en-US', { + year: 'numeric', + }); + + return [dateTimeFormat1, dateTimeFormat2] + .map((f) => f.format(date)) + .join(' '); +} + +export function formatDate(date: number | Date) { + const dateTimeFormat1 = new Intl.DateTimeFormat('en-US', { + weekday: 'short', + month: 'short', + day: 'numeric', + }); + const withinYear = + new Date().getFullYear() === new Date(date).getFullYear(); + const dateTimeFormat2 = !withinYear + ? new Intl.DateTimeFormat('en-US', { + year: 'numeric', + }) + : null; + return [dateTimeFormat1, dateTimeFormat2] + .filter((f) => !!f) + .map((f) => f.format(date)) + .join(' '); +} + +export function formatDateTimeShort(date: number | Date) { + const dateTimeFormat = new Intl.DateTimeFormat('en-US', { + month: 'short', + day: 'numeric', + year: 'numeric', + hour: '2-digit', + minute: '2-digit', + }); + + return dateTimeFormat.format(date); +} + +export function formatTime(date: number | Date) { + const timeFormat = new Intl.DateTimeFormat('en-IN', { + timeStyle: 'short', + }); + return timeFormat.format(date).toUpperCase(); +} + +export function formatDateTimeFull(dateTime: number | Date): string { + return [formatDateFull(dateTime), 'at', formatTime(dateTime)].join(' '); +} + +export function formatDateTime(dateTime: number | Date): string { + return [formatDate(dateTime), 'at', formatTime(dateTime)].join(' '); +} + +export function formatDateRelative(date: number) { + const units = { + year: 24 * 60 * 60 * 1000 * 365, + month: (24 * 60 * 60 * 1000 * 365) / 12, + day: 24 * 60 * 60 * 1000, + hour: 60 * 60 * 1000, + minute: 60 * 1000, + second: 1000, + }; + const relativeDateFormat = new Intl.RelativeTimeFormat('en-IN', { + localeMatcher: 'best fit', + numeric: 'always', + style: 'long', + }); + const elapsed = date - Date.now(); // "Math.abs" accounts for both "past" & "future" scenarios + + for (const u in units) + if (Math.abs(elapsed) > units[u] || u === 'second') + return relativeDateFormat.format( + Math.round(elapsed / units[u]), + u as Intl.RelativeTimeFormatUnit + ); +} diff --git a/src/utils/time/index.ts b/src/utils/time/index.ts index 56fa78d78..1af5853ed 100644 --- a/src/utils/time/index.ts +++ b/src/utils/time/index.ts @@ -14,25 +14,6 @@ interface DateComponent { second: T; } -export function dateStringWithMMH(unixTimeInMicroSeconds: number): string { - return new Date(unixTimeInMicroSeconds / 1000).toLocaleDateString('en-US', { - year: 'numeric', - month: 'long', - day: 'numeric', - hour: '2-digit', - minute: '2-digit', - }); -} - -export function formatDateShort(date: number | Date) { - const dateTimeFormat = new Intl.DateTimeFormat('en-IN', { - year: '2-digit', - month: 'short', - day: 'numeric', - }); - return dateTimeFormat.format(date); -} - export function getUnixTimeInMicroSecondsWithDelta(delta: TimeDelta): number { let currentDate = new Date(); if (delta?.hours) { @@ -55,7 +36,8 @@ export function getUnixTimeInMicroSeconds(dateTime: Date) { return null; } const unixTime = dateTime.getTime() * 1000; - if (unixTime <= 0) { + //ignoring dateTimeString = "0000:00:00 00:00:00"; + if (unixTime === Date.UTC(0, 0, 0, 0, 0, 0, 0)) { return null; } else { return unixTime; @@ -163,39 +145,3 @@ function getDateFromComponents(dateComponent: DateComponent) { ? new Date(year, month, day, hour, minute, second) : new Date(year, month, day); } - -export function formatDateTime(date: number | Date) { - const dateTimeFormat = new Intl.DateTimeFormat('en-IN', { - weekday: 'short', - year: 'numeric', - month: 'long', - day: 'numeric', - }); - const timeFormat = new Intl.DateTimeFormat('en-IN', { - timeStyle: 'short', - }); - return `${dateTimeFormat.format(date)} ${timeFormat.format(date)}`; -} -export function formatDateRelative(date: number) { - const units = { - year: 24 * 60 * 60 * 1000 * 365, - month: (24 * 60 * 60 * 1000 * 365) / 12, - day: 24 * 60 * 60 * 1000, - hour: 60 * 60 * 1000, - minute: 60 * 1000, - second: 1000, - }; - const relativeDateFormat = new Intl.RelativeTimeFormat('en-IN', { - localeMatcher: 'best fit', - numeric: 'always', - style: 'long', - }); - const elapsed = date - Date.now(); // "Math.abs" accounts for both "past" & "future" scenarios - - for (const u in units) - if (Math.abs(elapsed) > units[u] || u === 'second') - return relativeDateFormat.format( - Math.round(elapsed / units[u]), - u as Intl.RelativeTimeFormatUnit - ); -} diff --git a/src/utils/ui/index.tsx b/src/utils/ui/index.tsx index 63668ad83..a0fd26619 100644 --- a/src/utils/ui/index.tsx +++ b/src/utils/ui/index.tsx @@ -1,7 +1,10 @@ +import React from 'react'; +import AutoAwesomeOutlinedIcon from '@mui/icons-material/AutoAwesomeOutlined'; import { DialogBoxAttributes } from 'types/dialogBox'; import { downloadApp } from 'utils/common'; import constants from 'utils/strings/constants'; - +import ElectronUpdateService from 'services/electron/update'; +import { AppUpdateInfo } from 'types/electron'; export const getDownloadAppMessage = (): DialogBoxAttributes => { return { title: constants.DOWNLOAD_APP, @@ -30,3 +33,47 @@ export const getTrashFilesMessage = ( }, close: { text: constants.CANCEL }, }); + +export const getTrashFileMessage = (deleteFileHelper): DialogBoxAttributes => ({ + title: constants.TRASH_FILE_TITLE, + content: constants.TRASH_FILE_MESSAGE, + proceed: { + action: deleteFileHelper, + text: constants.MOVE_TO_TRASH, + variant: 'danger', + }, + close: { text: constants.CANCEL }, +}); + +export const getUpdateReadyToInstallMessage = (): DialogBoxAttributes => ({ + icon: , + title: constants.UPDATE_AVAILABLE, + content: constants.UPDATE_INSTALLABLE_MESSAGE, + close: { + text: constants.INSTALL_ON_NEXT_LAUNCH, + variant: 'secondary', + }, + proceed: { + action: () => ElectronUpdateService.updateAndRestart(), + text: constants.INSTALL_NOW, + variant: 'accent', + }, +}); + +export const getUpdateAvailableForDownloadMessage = ( + updateInfo: AppUpdateInfo +): DialogBoxAttributes => ({ + icon: , + title: constants.UPDATE_AVAILABLE, + content: constants.UPDATE_AVAILABLE_MESSAGE, + close: { + text: constants.IGNORE_THIS_VERSION, + variant: 'secondary', + action: () => ElectronUpdateService.skipAppVersion(updateInfo.version), + }, + proceed: { + action: downloadApp, + text: constants.DOWNLOAD_AND_INSTALL, + variant: 'accent', + }, +}); diff --git a/src/utils/user/index.ts b/src/utils/user/index.ts index cfafd92a7..f1914cbf4 100644 --- a/src/utils/user/index.ts +++ b/src/utils/user/index.ts @@ -1,5 +1,7 @@ -import { UserDetails } from 'types/user'; +import isElectron from 'is-electron'; +import { User, UserDetails } from 'types/user'; import { getData, LS_KEYS, setData } from 'utils/storage/localStorage'; +import ElectronService from 'services/electron/common'; export function makeID(length) { let result = ''; @@ -14,15 +16,22 @@ export function makeID(length) { return result; } -export function getSentryUserID() { - let anonymizeUserID = getData(LS_KEYS.AnonymizedUserID)?.id; - if (!anonymizeUserID) { - anonymizeUserID = makeID(6); - setData(LS_KEYS.AnonymizedUserID, { id: anonymizeUserID }); +export async function getSentryUserID() { + if (isElectron()) { + return await ElectronService.getSentryUserID(); + } else { + let anonymizeUserID = getData(LS_KEYS.AnonymizedUserID)?.id; + if (!anonymizeUserID) { + anonymizeUserID = makeID(6); + setData(LS_KEYS.AnonymizedUserID, { id: anonymizeUserID }); + } + return anonymizeUserID; } - return anonymizeUserID; } export function getLocalUserDetails(): UserDetails { return getData(LS_KEYS.USER_DETAILS)?.value; } + +export const isInternalUser = () => + (getData(LS_KEYS.USER) as User)?.email.endsWith('@ente.io'); diff --git a/src/worker/convert.worker.ts b/src/worker/convert.worker.ts index 3b330834c..1fa41231d 100644 --- a/src/worker/convert.worker.ts +++ b/src/worker/convert.worker.ts @@ -1,5 +1,5 @@ import * as Comlink from 'comlink'; -import { convertHEIC } from 'services/heicConverter/heicConverterClient'; +import { convertHEIC } from 'services/wasmHeicConverter/wasmHEICConverterClient.ts'; export class DedicatedConvertWorker { async convertHEIC(fileBlob: Blob, format: string) { diff --git a/src/worker/ffmpeg.worker.ts b/src/worker/ffmpeg.worker.ts index cf372c5df..6a3ff52c3 100644 --- a/src/worker/ffmpeg.worker.ts +++ b/src/worker/ffmpeg.worker.ts @@ -1,20 +1,14 @@ import * as Comlink from 'comlink'; -import FFmpegClient from 'services/ffmpeg/ffmpegClient'; +import { WasmFFmpeg } from 'services/wasm/ffmpeg'; export class DedicatedFFmpegWorker { - ffmpegClient: FFmpegClient; + wasmFFmpeg: WasmFFmpeg; constructor() { - this.ffmpegClient = new FFmpegClient(); - } - async generateThumbnail(file: File) { - return this.ffmpegClient.generateThumbnail(file); - } - async extractVideoMetadata(file: File) { - return this.ffmpegClient.extractVideoMetadata(file); + this.wasmFFmpeg = new WasmFFmpeg(); } - async convertToMP4(file: Uint8Array, inputFileName: string) { - return this.ffmpegClient.convertToMP4(file, inputFileName); + run(cmd, inputFile, outputFileName) { + return this.wasmFFmpeg.run(cmd, inputFile, outputFileName); } } diff --git a/tsconfig.json b/tsconfig.json index dce11bcd5..737c70f6e 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -20,12 +20,6 @@ "downlevelIteration": true, "incremental": true }, - "include": [ - "next-env.d.ts", - "**/*.ts", - "**/*.tsx", - "src/pages/index.tsx", - "configUtil.js" - ], - "exclude": ["node_modules"] + "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", "**/*.js"], + "exclude": ["node_modules", "out", ".next", "thirdparty"] } diff --git a/yarn.lock b/yarn.lock index d8b0a2aab..ae3e2e40f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,46 +2,13 @@ # yarn lockfile v1 -"@babel/code-frame@7.12.11": - version "7.12.11" - resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz" - integrity sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw== - dependencies: - "@babel/highlight" "^7.10.4" - -"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.14.5", "@babel/code-frame@^7.5.5": +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.14.5": version "7.14.5" resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.14.5.tgz" integrity sha512-9pzDqyc6OLDaqe+zbACgFkb6fKMNG6CObKpnYXChRsvYGyEdc7CA2BaqeOM+vOtCS5ndmJicPJhKAwYRI6UfFw== dependencies: "@babel/highlight" "^7.14.5" -"@babel/compat-data@^7.13.11", "@babel/compat-data@^7.15.0": - version "7.15.0" - resolved "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.15.0.tgz" - integrity sha512-0NqAC1IJE0S0+lL1SWFMxMkz1pKCNCjI4tr2Zx4LJSXxCLAdr6KyArnY+sno5m3yH9g737ygOyPABDsnXkpxiA== - -"@babel/core@^7.8.4": - version "7.15.5" - resolved "https://registry.npmjs.org/@babel/core/-/core-7.15.5.tgz" - integrity sha512-pYgXxiwAgQpgM1bNkZsDEq85f0ggXMA5L7c+o3tskGMh2BunCI9QUwB9Z4jpvXUOuMdyGKiGKQiRe11VS6Jzvg== - dependencies: - "@babel/code-frame" "^7.14.5" - "@babel/generator" "^7.15.4" - "@babel/helper-compilation-targets" "^7.15.4" - "@babel/helper-module-transforms" "^7.15.4" - "@babel/helpers" "^7.15.4" - "@babel/parser" "^7.15.5" - "@babel/template" "^7.15.4" - "@babel/traverse" "^7.15.4" - "@babel/types" "^7.15.4" - convert-source-map "^1.7.0" - debug "^4.1.0" - gensync "^1.0.0-beta.2" - json5 "^2.1.2" - semver "^6.3.0" - source-map "^0.5.0" - "@babel/generator@^7.15.4": version "7.15.4" resolved "https://registry.npmjs.org/@babel/generator/-/generator-7.15.4.tgz" @@ -51,73 +18,14 @@ jsesc "^2.5.1" source-map "^0.5.0" -"@babel/helper-annotate-as-pure@^7.0.0", "@babel/helper-annotate-as-pure@^7.14.5", "@babel/helper-annotate-as-pure@^7.15.4": +"@babel/helper-annotate-as-pure@^7.0.0": version "7.15.4" resolved "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.15.4.tgz" integrity sha512-QwrtdNvUNsPCj2lfNQacsGSQvGX8ee1ttrBrcozUP2Sv/jylewBP/8QFe6ZkBsC8T/GYWonNAWJV4aRR9AL2DA== dependencies: "@babel/types" "^7.15.4" -"@babel/helper-builder-binary-assignment-operator-visitor@^7.14.5": - version "7.15.4" - resolved "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.15.4.tgz" - integrity sha512-P8o7JP2Mzi0SdC6eWr1zF+AEYvrsZa7GSY1lTayjF5XJhVH0kjLYUZPvTMflP7tBgZoe9gIhTa60QwFpqh/E0Q== - dependencies: - "@babel/helper-explode-assignable-expression" "^7.15.4" - "@babel/types" "^7.15.4" - -"@babel/helper-compilation-targets@^7.13.0", "@babel/helper-compilation-targets@^7.15.4": - version "7.15.4" - resolved "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.15.4.tgz" - integrity sha512-rMWPCirulnPSe4d+gwdWXLfAXTTBj8M3guAf5xFQJ0nvFY7tfNAFnWdqaHegHlgDZOCT4qvhF3BYlSJag8yhqQ== - dependencies: - "@babel/compat-data" "^7.15.0" - "@babel/helper-validator-option" "^7.14.5" - browserslist "^4.16.6" - semver "^6.3.0" - -"@babel/helper-create-class-features-plugin@^7.14.5", "@babel/helper-create-class-features-plugin@^7.15.4": - version "7.15.4" - resolved "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.15.4.tgz" - integrity sha512-7ZmzFi+DwJx6A7mHRwbuucEYpyBwmh2Ca0RvI6z2+WLZYCqV0JOaLb+u0zbtmDicebgKBZgqbYfLaKNqSgv5Pw== - dependencies: - "@babel/helper-annotate-as-pure" "^7.15.4" - "@babel/helper-function-name" "^7.15.4" - "@babel/helper-member-expression-to-functions" "^7.15.4" - "@babel/helper-optimise-call-expression" "^7.15.4" - "@babel/helper-replace-supers" "^7.15.4" - "@babel/helper-split-export-declaration" "^7.15.4" - -"@babel/helper-create-regexp-features-plugin@^7.14.5": - version "7.14.5" - resolved "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.14.5.tgz" - integrity sha512-TLawwqpOErY2HhWbGJ2nZT5wSkR192QpN+nBg1THfBfftrlvOh+WbhrxXCH4q4xJ9Gl16BGPR/48JA+Ryiho/A== - dependencies: - "@babel/helper-annotate-as-pure" "^7.14.5" - regexpu-core "^4.7.1" - -"@babel/helper-define-polyfill-provider@^0.2.2": - version "0.2.3" - resolved "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.2.3.tgz" - integrity sha512-RH3QDAfRMzj7+0Nqu5oqgO5q9mFtQEVvCRsi8qCEfzLR9p2BHfn5FzhSB2oj1fF7I2+DcTORkYaQ6aTR9Cofew== - dependencies: - "@babel/helper-compilation-targets" "^7.13.0" - "@babel/helper-module-imports" "^7.12.13" - "@babel/helper-plugin-utils" "^7.13.0" - "@babel/traverse" "^7.13.0" - debug "^4.1.1" - lodash.debounce "^4.0.8" - resolve "^1.14.2" - semver "^6.1.2" - -"@babel/helper-explode-assignable-expression@^7.15.4": - version "7.15.4" - resolved "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.15.4.tgz" - integrity sha512-J14f/vq8+hdC2KoWLIQSsGrC9EFBKE4NFts8pfMpymfApds+fPqR30AOUWc4tyr56h9l/GA1Sxv2q3dLZWbQ/g== - dependencies: - "@babel/types" "^7.15.4" - -"@babel/helper-function-name@^7.14.5", "@babel/helper-function-name@^7.15.4": +"@babel/helper-function-name@^7.15.4": version "7.15.4" resolved "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.15.4.tgz" integrity sha512-Z91cOMM4DseLIGOnog+Z8OI6YseR9bua+HpvLAQ2XayUGU+neTtX+97caALaLdyu53I/fjhbeCnWnRH1O3jFOw== @@ -140,84 +48,13 @@ dependencies: "@babel/types" "^7.15.4" -"@babel/helper-member-expression-to-functions@^7.15.4": - version "7.15.4" - resolved "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.15.4.tgz" - integrity sha512-cokOMkxC/BTyNP1AlY25HuBWM32iCEsLPI4BHDpJCHHm1FU2E7dKWWIXJgQgSFiu4lp8q3bL1BIKwqkSUviqtA== - dependencies: - "@babel/types" "^7.15.4" - -"@babel/helper-module-imports@^7.0.0", "@babel/helper-module-imports@^7.12.13", "@babel/helper-module-imports@^7.14.5", "@babel/helper-module-imports@^7.15.4": +"@babel/helper-module-imports@^7.0.0": version "7.15.4" resolved "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.15.4.tgz" integrity sha512-jeAHZbzUwdW/xHgHQ3QmWR4Jg6j15q4w/gCfwZvtqOxoo5DKtLHk8Bsf4c5RZRC7NmLEs+ohkdq8jFefuvIxAA== dependencies: "@babel/types" "^7.15.4" -"@babel/helper-module-transforms@^7.14.5", "@babel/helper-module-transforms@^7.15.4": - version "7.15.4" - resolved "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.15.4.tgz" - integrity sha512-9fHHSGE9zTC++KuXLZcB5FKgvlV83Ox+NLUmQTawovwlJ85+QMhk1CnVk406CQVj97LaWod6KVjl2Sfgw9Aktw== - dependencies: - "@babel/helper-module-imports" "^7.15.4" - "@babel/helper-replace-supers" "^7.15.4" - "@babel/helper-simple-access" "^7.15.4" - "@babel/helper-split-export-declaration" "^7.15.4" - "@babel/helper-validator-identifier" "^7.14.9" - "@babel/template" "^7.15.4" - "@babel/traverse" "^7.15.4" - "@babel/types" "^7.15.4" - -"@babel/helper-optimise-call-expression@^7.15.4": - version "7.15.4" - resolved "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.15.4.tgz" - integrity sha512-E/z9rfbAOt1vDW1DR7k4SzhzotVV5+qMciWV6LaG1g4jeFrkDlJedjtV4h0i4Q/ITnUu+Pk08M7fczsB9GXBDw== - dependencies: - "@babel/types" "^7.15.4" - -"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.13.0", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3": - version "7.14.5" - resolved "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.14.5.tgz" - integrity sha512-/37qQCE3K0vvZKwoK4XU/irIJQdIfCJuhU5eKnNxpFDsOkgFaUAwbv+RYw6eYgsC0E4hS7r5KqGULUogqui0fQ== - -"@babel/helper-plugin-utils@^7.14.5": - version "7.16.7" - resolved "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.16.7.tgz" - integrity sha512-Qg3Nk7ZxpgMrsox6HreY1ZNKdBq7K72tDSliA6dCl5f007jR4ne8iD5UzuNnCJH2xBf2BEEVGr+/OL6Gdp7RxA== - -"@babel/helper-remap-async-to-generator@^7.14.5", "@babel/helper-remap-async-to-generator@^7.15.4": - version "7.15.4" - resolved "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.15.4.tgz" - integrity sha512-v53MxgvMK/HCwckJ1bZrq6dNKlmwlyRNYM6ypaRTdXWGOE2c1/SCa6dL/HimhPulGhZKw9W0QhREM583F/t0vQ== - dependencies: - "@babel/helper-annotate-as-pure" "^7.15.4" - "@babel/helper-wrap-function" "^7.15.4" - "@babel/types" "^7.15.4" - -"@babel/helper-replace-supers@^7.14.5", "@babel/helper-replace-supers@^7.15.4": - version "7.15.4" - resolved "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.15.4.tgz" - integrity sha512-/ztT6khaXF37MS47fufrKvIsiQkx1LBRvSJNzRqmbyeZnTwU9qBxXYLaaT/6KaxfKhjs2Wy8kG8ZdsFUuWBjzw== - dependencies: - "@babel/helper-member-expression-to-functions" "^7.15.4" - "@babel/helper-optimise-call-expression" "^7.15.4" - "@babel/traverse" "^7.15.4" - "@babel/types" "^7.15.4" - -"@babel/helper-simple-access@^7.15.4": - version "7.15.4" - resolved "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.15.4.tgz" - integrity sha512-UzazrDoIVOZZcTeHHEPYrr1MvTR/K+wgLg6MY6e1CJyaRhbibftF6fR2KU2sFRtI/nERUZR9fBd6aKgBlIBaPg== - dependencies: - "@babel/types" "^7.15.4" - -"@babel/helper-skip-transparent-expression-wrappers@^7.14.5", "@babel/helper-skip-transparent-expression-wrappers@^7.15.4": - version "7.15.4" - resolved "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.15.4.tgz" - integrity sha512-BMRLsdh+D1/aap19TycS4eD1qELGrCBJwzaY9IE8LrpJtJb+H7rQkPIdsfgnMtLBA6DJls7X9z93Z4U8h7xw0A== - dependencies: - "@babel/types" "^7.15.4" - "@babel/helper-split-export-declaration@^7.15.4": version "7.15.4" resolved "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.15.4.tgz" @@ -225,44 +62,11 @@ dependencies: "@babel/types" "^7.15.4" -"@babel/helper-validator-identifier@^7.14.5", "@babel/helper-validator-identifier@^7.14.9", "@babel/helper-validator-identifier@^7.16.7": +"@babel/helper-validator-identifier@^7.14.5", "@babel/helper-validator-identifier@^7.14.9": version "7.16.7" resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz" integrity sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw== -"@babel/helper-validator-option@^7.14.5": - version "7.14.5" - resolved "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.14.5.tgz" - integrity sha512-OX8D5eeX4XwcroVW45NMvoYaIuFI+GQpA2a8Gi+X/U/cDUIRsV37qQfF905F0htTRCREQIB4KqPeaveRJUl3Ow== - -"@babel/helper-wrap-function@^7.15.4": - version "7.15.4" - resolved "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.15.4.tgz" - integrity sha512-Y2o+H/hRV5W8QhIfTpRIBwl57y8PrZt6JM3V8FOo5qarjshHItyH5lXlpMfBfmBefOqSCpKZs/6Dxqp0E/U+uw== - dependencies: - "@babel/helper-function-name" "^7.15.4" - "@babel/template" "^7.15.4" - "@babel/traverse" "^7.15.4" - "@babel/types" "^7.15.4" - -"@babel/helpers@^7.15.4": - version "7.15.4" - resolved "https://registry.npmjs.org/@babel/helpers/-/helpers-7.15.4.tgz" - integrity sha512-V45u6dqEJ3w2rlryYYXf6i9rQ5YMNu4FLS6ngs8ikblhu2VdR1AqAd6aJjBzmf2Qzh6KOLqKHxEN9+TFbAkAVQ== - dependencies: - "@babel/template" "^7.15.4" - "@babel/traverse" "^7.15.4" - "@babel/types" "^7.15.4" - -"@babel/highlight@^7.10.4": - version "7.16.10" - resolved "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.10.tgz" - integrity sha512-5FnTQLSLswEj6IkgVw5KusNUUFY9ZGqe/TRFnP/BKYHYgfh7tc+C7mwiy95/yNP7Dh9x580Vv8r7u7ZfTBFxdw== - dependencies: - "@babel/helper-validator-identifier" "^7.16.7" - chalk "^2.0.0" - js-tokens "^4.0.0" - "@babel/highlight@^7.14.5": version "7.14.5" resolved "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz" @@ -272,584 +76,11 @@ chalk "^2.0.0" js-tokens "^4.0.0" -"@babel/parser@^7.15.4", "@babel/parser@^7.15.5": +"@babel/parser@^7.15.4": version "7.15.6" resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.15.6.tgz" integrity sha512-S/TSCcsRuCkmpUuoWijua0Snt+f3ewU/8spLo+4AXJCZfT0bVCzLD5MuOKdrx0mlAptbKzn5AdgEIIKXxXkz9Q== -"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.15.4": - version "7.15.4" - resolved "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.15.4.tgz" - integrity sha512-eBnpsl9tlhPhpI10kU06JHnrYXwg3+V6CaP2idsCXNef0aeslpqyITXQ74Vfk5uHgY7IG7XP0yIH8b42KSzHog== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - "@babel/helper-skip-transparent-expression-wrappers" "^7.15.4" - "@babel/plugin-proposal-optional-chaining" "^7.14.5" - -"@babel/plugin-proposal-async-generator-functions@^7.15.4": - version "7.15.4" - resolved "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.15.4.tgz" - integrity sha512-2zt2g5vTXpMC3OmK6uyjvdXptbhBXfA77XGrd3gh93zwG8lZYBLOBImiGBEG0RANu3JqKEACCz5CGk73OJROBw== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - "@babel/helper-remap-async-to-generator" "^7.15.4" - "@babel/plugin-syntax-async-generators" "^7.8.4" - -"@babel/plugin-proposal-class-properties@^7.14.5": - version "7.14.5" - resolved "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.14.5.tgz" - integrity sha512-q/PLpv5Ko4dVc1LYMpCY7RVAAO4uk55qPwrIuJ5QJ8c6cVuAmhu7I/49JOppXL6gXf7ZHzpRVEUZdYoPLM04Gg== - dependencies: - "@babel/helper-create-class-features-plugin" "^7.14.5" - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-proposal-class-static-block@^7.15.4": - version "7.15.4" - resolved "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.15.4.tgz" - integrity sha512-M682XWrrLNk3chXCjoPUQWOyYsB93B9z3mRyjtqqYJWDf2mfCdIYgDrA11cgNVhAQieaq6F2fn2f3wI0U4aTjA== - dependencies: - "@babel/helper-create-class-features-plugin" "^7.15.4" - "@babel/helper-plugin-utils" "^7.14.5" - "@babel/plugin-syntax-class-static-block" "^7.14.5" - -"@babel/plugin-proposal-dynamic-import@^7.14.5": - version "7.14.5" - resolved "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.14.5.tgz" - integrity sha512-ExjiNYc3HDN5PXJx+bwC50GIx/KKanX2HiggnIUAYedbARdImiCU4RhhHfdf0Kd7JNXGpsBBBCOm+bBVy3Gb0g== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - "@babel/plugin-syntax-dynamic-import" "^7.8.3" - -"@babel/plugin-proposal-export-namespace-from@^7.14.5": - version "7.14.5" - resolved "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.14.5.tgz" - integrity sha512-g5POA32bXPMmSBu5Dx/iZGLGnKmKPc5AiY7qfZgurzrCYgIztDlHFbznSNCoQuv57YQLnQfaDi7dxCtLDIdXdA== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - "@babel/plugin-syntax-export-namespace-from" "^7.8.3" - -"@babel/plugin-proposal-json-strings@^7.14.5": - version "7.14.5" - resolved "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.14.5.tgz" - integrity sha512-NSq2fczJYKVRIsUJyNxrVUMhB27zb7N7pOFGQOhBKJrChbGcgEAqyZrmZswkPk18VMurEeJAaICbfm57vUeTbQ== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - "@babel/plugin-syntax-json-strings" "^7.8.3" - -"@babel/plugin-proposal-logical-assignment-operators@^7.14.5": - version "7.14.5" - resolved "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.14.5.tgz" - integrity sha512-YGn2AvZAo9TwyhlLvCCWxD90Xq8xJ4aSgaX3G5D/8DW94L8aaT+dS5cSP+Z06+rCJERGSr9GxMBZ601xoc2taw== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" - -"@babel/plugin-proposal-nullish-coalescing-operator@^7.14.5": - version "7.14.5" - resolved "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.14.5.tgz" - integrity sha512-gun/SOnMqjSb98Nkaq2rTKMwervfdAoz6NphdY0vTfuzMfryj+tDGb2n6UkDKwez+Y8PZDhE3D143v6Gepp4Hg== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" - -"@babel/plugin-proposal-numeric-separator@^7.14.5": - version "7.14.5" - resolved "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.14.5.tgz" - integrity sha512-yiclALKe0vyZRZE0pS6RXgjUOt87GWv6FYa5zqj15PvhOGFO69R5DusPlgK/1K5dVnCtegTiWu9UaBSrLLJJBg== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - "@babel/plugin-syntax-numeric-separator" "^7.10.4" - -"@babel/plugin-proposal-object-rest-spread@^7.15.6": - version "7.15.6" - resolved "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.15.6.tgz" - integrity sha512-qtOHo7A1Vt+O23qEAX+GdBpqaIuD3i9VRrWgCJeq7WO6H2d14EK3q11urj5Te2MAeK97nMiIdRpwd/ST4JFbNg== - dependencies: - "@babel/compat-data" "^7.15.0" - "@babel/helper-compilation-targets" "^7.15.4" - "@babel/helper-plugin-utils" "^7.14.5" - "@babel/plugin-syntax-object-rest-spread" "^7.8.3" - "@babel/plugin-transform-parameters" "^7.15.4" - -"@babel/plugin-proposal-optional-catch-binding@^7.14.5": - version "7.14.5" - resolved "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.14.5.tgz" - integrity sha512-3Oyiixm0ur7bzO5ybNcZFlmVsygSIQgdOa7cTfOYCMY+wEPAYhZAJxi3mixKFCTCKUhQXuCTtQ1MzrpL3WT8ZQ== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" - -"@babel/plugin-proposal-optional-chaining@^7.14.5": - version "7.14.5" - resolved "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.14.5.tgz" - integrity sha512-ycz+VOzo2UbWNI1rQXxIuMOzrDdHGrI23fRiz/Si2R4kv2XZQ1BK8ccdHwehMKBlcH/joGW/tzrUmo67gbJHlQ== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - "@babel/helper-skip-transparent-expression-wrappers" "^7.14.5" - "@babel/plugin-syntax-optional-chaining" "^7.8.3" - -"@babel/plugin-proposal-private-methods@^7.14.5": - version "7.14.5" - resolved "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.14.5.tgz" - integrity sha512-838DkdUA1u+QTCplatfq4B7+1lnDa/+QMI89x5WZHBcnNv+47N8QEj2k9I2MUU9xIv8XJ4XvPCviM/Dj7Uwt9g== - dependencies: - "@babel/helper-create-class-features-plugin" "^7.14.5" - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-proposal-private-property-in-object@^7.15.4": - version "7.15.4" - resolved "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.15.4.tgz" - integrity sha512-X0UTixkLf0PCCffxgu5/1RQyGGbgZuKoI+vXP4iSbJSYwPb7hu06omsFGBvQ9lJEvwgrxHdS8B5nbfcd8GyUNA== - dependencies: - "@babel/helper-annotate-as-pure" "^7.15.4" - "@babel/helper-create-class-features-plugin" "^7.15.4" - "@babel/helper-plugin-utils" "^7.14.5" - "@babel/plugin-syntax-private-property-in-object" "^7.14.5" - -"@babel/plugin-proposal-unicode-property-regex@^7.14.5", "@babel/plugin-proposal-unicode-property-regex@^7.4.4": - version "7.14.5" - resolved "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.14.5.tgz" - integrity sha512-6axIeOU5LnY471KenAB9vI8I5j7NQ2d652hIYwVyRfgaZT5UpiqFKCuVXCDMSrU+3VFafnu2c5m3lrWIlr6A5Q== - dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.14.5" - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-syntax-async-generators@^7.8.4": - version "7.8.4" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz" - integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-class-properties@^7.12.13": - version "7.12.13" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz" - integrity sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA== - dependencies: - "@babel/helper-plugin-utils" "^7.12.13" - -"@babel/plugin-syntax-class-static-block@^7.14.5": - version "7.14.5" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz" - integrity sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-syntax-dynamic-import@^7.8.3": - version "7.8.3" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz" - integrity sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-export-namespace-from@^7.8.3": - version "7.8.3" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz" - integrity sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - -"@babel/plugin-syntax-json-strings@^7.8.3": - version "7.8.3" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz" - integrity sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-logical-assignment-operators@^7.10.4": - version "7.10.4" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz" - integrity sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig== - dependencies: - "@babel/helper-plugin-utils" "^7.10.4" - -"@babel/plugin-syntax-nullish-coalescing-operator@^7.8.3": - version "7.8.3" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz" - integrity sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-numeric-separator@^7.10.4": - version "7.10.4" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz" - integrity sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug== - dependencies: - "@babel/helper-plugin-utils" "^7.10.4" - -"@babel/plugin-syntax-object-rest-spread@^7.8.3": - version "7.8.3" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz" - integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-optional-catch-binding@^7.8.3": - version "7.8.3" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz" - integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-optional-chaining@^7.8.3": - version "7.8.3" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz" - integrity sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-private-property-in-object@^7.14.5": - version "7.14.5" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz" - integrity sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-syntax-top-level-await@^7.14.5": - version "7.14.5" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz" - integrity sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-transform-arrow-functions@^7.14.5": - version "7.14.5" - resolved "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.14.5.tgz" - integrity sha512-KOnO0l4+tD5IfOdi4x8C1XmEIRWUjNRV8wc6K2vz/3e8yAOoZZvsRXRRIF/yo/MAOFb4QjtAw9xSxMXbSMRy8A== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-transform-async-to-generator@^7.14.5": - version "7.14.5" - resolved "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.14.5.tgz" - integrity sha512-szkbzQ0mNk0rpu76fzDdqSyPu0MuvpXgC+6rz5rpMb5OIRxdmHfQxrktL8CYolL2d8luMCZTR0DpIMIdL27IjA== - dependencies: - "@babel/helper-module-imports" "^7.14.5" - "@babel/helper-plugin-utils" "^7.14.5" - "@babel/helper-remap-async-to-generator" "^7.14.5" - -"@babel/plugin-transform-block-scoped-functions@^7.14.5": - version "7.14.5" - resolved "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.14.5.tgz" - integrity sha512-dtqWqdWZ5NqBX3KzsVCWfQI3A53Ft5pWFCT2eCVUftWZgjc5DpDponbIF1+c+7cSGk2wN0YK7HGL/ezfRbpKBQ== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-transform-block-scoping@^7.15.3": - version "7.15.3" - resolved "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.15.3.tgz" - integrity sha512-nBAzfZwZb4DkaGtOes1Up1nOAp9TDRRFw4XBzBBSG9QK7KVFmYzgj9o9sbPv7TX5ofL4Auq4wZnxCoPnI/lz2Q== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-transform-classes@^7.15.4": - version "7.15.4" - resolved "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.15.4.tgz" - integrity sha512-Yjvhex8GzBmmPQUvpXRPWQ9WnxXgAFuZSrqOK/eJlOGIXwvv8H3UEdUigl1gb/bnjTrln+e8bkZUYCBt/xYlBg== - dependencies: - "@babel/helper-annotate-as-pure" "^7.15.4" - "@babel/helper-function-name" "^7.15.4" - "@babel/helper-optimise-call-expression" "^7.15.4" - "@babel/helper-plugin-utils" "^7.14.5" - "@babel/helper-replace-supers" "^7.15.4" - "@babel/helper-split-export-declaration" "^7.15.4" - globals "^11.1.0" - -"@babel/plugin-transform-computed-properties@^7.14.5": - version "7.14.5" - resolved "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.14.5.tgz" - integrity sha512-pWM+E4283UxaVzLb8UBXv4EIxMovU4zxT1OPnpHJcmnvyY9QbPPTKZfEj31EUvG3/EQRbYAGaYEUZ4yWOBC2xg== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-transform-destructuring@^7.14.7": - version "7.14.7" - resolved "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.14.7.tgz" - integrity sha512-0mDE99nK+kVh3xlc5vKwB6wnP9ecuSj+zQCa/n0voENtP/zymdT4HH6QEb65wjjcbqr1Jb/7z9Qp7TF5FtwYGw== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-transform-dotall-regex@^7.14.5", "@babel/plugin-transform-dotall-regex@^7.4.4": - version "7.14.5" - resolved "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.14.5.tgz" - integrity sha512-loGlnBdj02MDsFaHhAIJzh7euK89lBrGIdM9EAtHFo6xKygCUGuuWe07o1oZVk287amtW1n0808sQM99aZt3gw== - dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.14.5" - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-transform-duplicate-keys@^7.14.5": - version "7.14.5" - resolved "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.14.5.tgz" - integrity sha512-iJjbI53huKbPDAsJ8EmVmvCKeeq21bAze4fu9GBQtSLqfvzj2oRuHVx4ZkDwEhg1htQ+5OBZh/Ab0XDf5iBZ7A== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-transform-exponentiation-operator@^7.14.5": - version "7.14.5" - resolved "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.14.5.tgz" - integrity sha512-jFazJhMBc9D27o9jDnIE5ZErI0R0m7PbKXVq77FFvqFbzvTMuv8jaAwLZ5PviOLSFttqKIW0/wxNSDbjLk0tYA== - dependencies: - "@babel/helper-builder-binary-assignment-operator-visitor" "^7.14.5" - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-transform-for-of@^7.15.4": - version "7.15.4" - resolved "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.15.4.tgz" - integrity sha512-DRTY9fA751AFBDh2oxydvVm4SYevs5ILTWLs6xKXps4Re/KG5nfUkr+TdHCrRWB8C69TlzVgA9b3RmGWmgN9LA== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-transform-function-name@^7.14.5": - version "7.14.5" - resolved "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.14.5.tgz" - integrity sha512-vbO6kv0fIzZ1GpmGQuvbwwm+O4Cbm2NrPzwlup9+/3fdkuzo1YqOZcXw26+YUJB84Ja7j9yURWposEHLYwxUfQ== - dependencies: - "@babel/helper-function-name" "^7.14.5" - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-transform-literals@^7.14.5": - version "7.14.5" - resolved "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.14.5.tgz" - integrity sha512-ql33+epql2F49bi8aHXxvLURHkxJbSmMKl9J5yHqg4PLtdE6Uc48CH1GS6TQvZ86eoB/ApZXwm7jlA+B3kra7A== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-transform-member-expression-literals@^7.14.5": - version "7.14.5" - resolved "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.14.5.tgz" - integrity sha512-WkNXxH1VXVTKarWFqmso83xl+2V3Eo28YY5utIkbsmXoItO8Q3aZxN4BTS2k0hz9dGUloHK26mJMyQEYfkn/+Q== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-transform-modules-amd@^7.14.5": - version "7.14.5" - resolved "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.14.5.tgz" - integrity sha512-3lpOU8Vxmp3roC4vzFpSdEpGUWSMsHFreTWOMMLzel2gNGfHE5UWIh/LN6ghHs2xurUp4jRFYMUIZhuFbody1g== - dependencies: - "@babel/helper-module-transforms" "^7.14.5" - "@babel/helper-plugin-utils" "^7.14.5" - babel-plugin-dynamic-import-node "^2.3.3" - -"@babel/plugin-transform-modules-commonjs@^7.15.4": - version "7.15.4" - resolved "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.15.4.tgz" - integrity sha512-qg4DPhwG8hKp4BbVDvX1s8cohM8a6Bvptu4l6Iingq5rW+yRUAhe/YRup/YcW2zCOlrysEWVhftIcKzrEZv3sA== - dependencies: - "@babel/helper-module-transforms" "^7.15.4" - "@babel/helper-plugin-utils" "^7.14.5" - "@babel/helper-simple-access" "^7.15.4" - babel-plugin-dynamic-import-node "^2.3.3" - -"@babel/plugin-transform-modules-systemjs@^7.15.4": - version "7.15.4" - resolved "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.15.4.tgz" - integrity sha512-fJUnlQrl/mezMneR72CKCgtOoahqGJNVKpompKwzv3BrEXdlPspTcyxrZ1XmDTIr9PpULrgEQo3qNKp6dW7ssw== - dependencies: - "@babel/helper-hoist-variables" "^7.15.4" - "@babel/helper-module-transforms" "^7.15.4" - "@babel/helper-plugin-utils" "^7.14.5" - "@babel/helper-validator-identifier" "^7.14.9" - babel-plugin-dynamic-import-node "^2.3.3" - -"@babel/plugin-transform-modules-umd@^7.14.5": - version "7.14.5" - resolved "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.14.5.tgz" - integrity sha512-RfPGoagSngC06LsGUYyM9QWSXZ8MysEjDJTAea1lqRjNECE3y0qIJF/qbvJxc4oA4s99HumIMdXOrd+TdKaAAA== - dependencies: - "@babel/helper-module-transforms" "^7.14.5" - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-transform-named-capturing-groups-regex@^7.14.9": - version "7.14.9" - resolved "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.14.9.tgz" - integrity sha512-l666wCVYO75mlAtGFfyFwnWmIXQm3kSH0C3IRnJqWcZbWkoihyAdDhFm2ZWaxWTqvBvhVFfJjMRQ0ez4oN1yYA== - dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.14.5" - -"@babel/plugin-transform-new-target@^7.14.5": - version "7.14.5" - resolved "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.14.5.tgz" - integrity sha512-Nx054zovz6IIRWEB49RDRuXGI4Gy0GMgqG0cII9L3MxqgXz/+rgII+RU58qpo4g7tNEx1jG7rRVH4ihZoP4esQ== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-transform-object-super@^7.14.5": - version "7.14.5" - resolved "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.14.5.tgz" - integrity sha512-MKfOBWzK0pZIrav9z/hkRqIk/2bTv9qvxHzPQc12RcVkMOzpIKnFCNYJip00ssKWYkd8Sf5g0Wr7pqJ+cmtuFg== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - "@babel/helper-replace-supers" "^7.14.5" - -"@babel/plugin-transform-parameters@^7.15.4": - version "7.15.4" - resolved "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.15.4.tgz" - integrity sha512-9WB/GUTO6lvJU3XQsSr6J/WKvBC2hcs4Pew8YxZagi6GkTdniyqp8On5kqdK8MN0LMeu0mGbhPN+O049NV/9FQ== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-transform-property-literals@^7.14.5": - version "7.14.5" - resolved "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.14.5.tgz" - integrity sha512-r1uilDthkgXW8Z1vJz2dKYLV1tuw2xsbrp3MrZmD99Wh9vsfKoob+JTgri5VUb/JqyKRXotlOtwgu4stIYCmnw== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-transform-regenerator@^7.14.5": - version "7.14.5" - resolved "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.14.5.tgz" - integrity sha512-NVIY1W3ITDP5xQl50NgTKlZ0GrotKtLna08/uGY6ErQt6VEQZXla86x/CTddm5gZdcr+5GSsvMeTmWA5Ii6pkg== - dependencies: - regenerator-transform "^0.14.2" - -"@babel/plugin-transform-reserved-words@^7.14.5": - version "7.14.5" - resolved "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.14.5.tgz" - integrity sha512-cv4F2rv1nD4qdexOGsRQXJrOcyb5CrgjUH9PKrrtyhSDBNWGxd0UIitjyJiWagS+EbUGjG++22mGH1Pub8D6Vg== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-transform-shorthand-properties@^7.14.5": - version "7.14.5" - resolved "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.14.5.tgz" - integrity sha512-xLucks6T1VmGsTB+GWK5Pl9Jl5+nRXD1uoFdA5TSO6xtiNjtXTjKkmPdFXVLGlK5A2/or/wQMKfmQ2Y0XJfn5g== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-transform-spread@^7.14.6": - version "7.14.6" - resolved "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.14.6.tgz" - integrity sha512-Zr0x0YroFJku7n7+/HH3A2eIrGMjbmAIbJSVv0IZ+t3U2WUQUA64S/oeied2e+MaGSjmt4alzBCsK9E8gh+fag== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - "@babel/helper-skip-transparent-expression-wrappers" "^7.14.5" - -"@babel/plugin-transform-sticky-regex@^7.14.5": - version "7.14.5" - resolved "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.14.5.tgz" - integrity sha512-Z7F7GyvEMzIIbwnziAZmnSNpdijdr4dWt+FJNBnBLz5mwDFkqIXU9wmBcWWad3QeJF5hMTkRe4dAq2sUZiG+8A== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-transform-template-literals@^7.14.5": - version "7.14.5" - resolved "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.14.5.tgz" - integrity sha512-22btZeURqiepOfuy/VkFr+zStqlujWaarpMErvay7goJS6BWwdd6BY9zQyDLDa4x2S3VugxFb162IZ4m/S/+Gg== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-transform-typeof-symbol@^7.14.5": - version "7.14.5" - resolved "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.14.5.tgz" - integrity sha512-lXzLD30ffCWseTbMQzrvDWqljvZlHkXU+CnseMhkMNqU1sASnCsz3tSzAaH3vCUXb9PHeUb90ZT1BdFTm1xxJw== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-transform-unicode-escapes@^7.14.5": - version "7.14.5" - resolved "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.14.5.tgz" - integrity sha512-crTo4jATEOjxj7bt9lbYXcBAM3LZaUrbP2uUdxb6WIorLmjNKSpHfIybgY4B8SRpbf8tEVIWH3Vtm7ayCrKocA== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-transform-unicode-regex@^7.14.5": - version "7.14.5" - resolved "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.14.5.tgz" - integrity sha512-UygduJpC5kHeCiRw/xDVzC+wj8VaYSoKl5JNVmbP7MadpNinAm3SvZCxZ42H37KZBKztz46YC73i9yV34d0Tzw== - dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.14.5" - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/preset-env@^7.8.4": - version "7.15.6" - resolved "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.15.6.tgz" - integrity sha512-L+6jcGn7EWu7zqaO2uoTDjjMBW+88FXzV8KvrBl2z6MtRNxlsmUNRlZPaNNPUTgqhyC5DHNFk/2Jmra+ublZWw== - dependencies: - "@babel/compat-data" "^7.15.0" - "@babel/helper-compilation-targets" "^7.15.4" - "@babel/helper-plugin-utils" "^7.14.5" - "@babel/helper-validator-option" "^7.14.5" - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining" "^7.15.4" - "@babel/plugin-proposal-async-generator-functions" "^7.15.4" - "@babel/plugin-proposal-class-properties" "^7.14.5" - "@babel/plugin-proposal-class-static-block" "^7.15.4" - "@babel/plugin-proposal-dynamic-import" "^7.14.5" - "@babel/plugin-proposal-export-namespace-from" "^7.14.5" - "@babel/plugin-proposal-json-strings" "^7.14.5" - "@babel/plugin-proposal-logical-assignment-operators" "^7.14.5" - "@babel/plugin-proposal-nullish-coalescing-operator" "^7.14.5" - "@babel/plugin-proposal-numeric-separator" "^7.14.5" - "@babel/plugin-proposal-object-rest-spread" "^7.15.6" - "@babel/plugin-proposal-optional-catch-binding" "^7.14.5" - "@babel/plugin-proposal-optional-chaining" "^7.14.5" - "@babel/plugin-proposal-private-methods" "^7.14.5" - "@babel/plugin-proposal-private-property-in-object" "^7.15.4" - "@babel/plugin-proposal-unicode-property-regex" "^7.14.5" - "@babel/plugin-syntax-async-generators" "^7.8.4" - "@babel/plugin-syntax-class-properties" "^7.12.13" - "@babel/plugin-syntax-class-static-block" "^7.14.5" - "@babel/plugin-syntax-dynamic-import" "^7.8.3" - "@babel/plugin-syntax-export-namespace-from" "^7.8.3" - "@babel/plugin-syntax-json-strings" "^7.8.3" - "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" - "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" - "@babel/plugin-syntax-numeric-separator" "^7.10.4" - "@babel/plugin-syntax-object-rest-spread" "^7.8.3" - "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" - "@babel/plugin-syntax-optional-chaining" "^7.8.3" - "@babel/plugin-syntax-private-property-in-object" "^7.14.5" - "@babel/plugin-syntax-top-level-await" "^7.14.5" - "@babel/plugin-transform-arrow-functions" "^7.14.5" - "@babel/plugin-transform-async-to-generator" "^7.14.5" - "@babel/plugin-transform-block-scoped-functions" "^7.14.5" - "@babel/plugin-transform-block-scoping" "^7.15.3" - "@babel/plugin-transform-classes" "^7.15.4" - "@babel/plugin-transform-computed-properties" "^7.14.5" - "@babel/plugin-transform-destructuring" "^7.14.7" - "@babel/plugin-transform-dotall-regex" "^7.14.5" - "@babel/plugin-transform-duplicate-keys" "^7.14.5" - "@babel/plugin-transform-exponentiation-operator" "^7.14.5" - "@babel/plugin-transform-for-of" "^7.15.4" - "@babel/plugin-transform-function-name" "^7.14.5" - "@babel/plugin-transform-literals" "^7.14.5" - "@babel/plugin-transform-member-expression-literals" "^7.14.5" - "@babel/plugin-transform-modules-amd" "^7.14.5" - "@babel/plugin-transform-modules-commonjs" "^7.15.4" - "@babel/plugin-transform-modules-systemjs" "^7.15.4" - "@babel/plugin-transform-modules-umd" "^7.14.5" - "@babel/plugin-transform-named-capturing-groups-regex" "^7.14.9" - "@babel/plugin-transform-new-target" "^7.14.5" - "@babel/plugin-transform-object-super" "^7.14.5" - "@babel/plugin-transform-parameters" "^7.15.4" - "@babel/plugin-transform-property-literals" "^7.14.5" - "@babel/plugin-transform-regenerator" "^7.14.5" - "@babel/plugin-transform-reserved-words" "^7.14.5" - "@babel/plugin-transform-shorthand-properties" "^7.14.5" - "@babel/plugin-transform-spread" "^7.14.6" - "@babel/plugin-transform-sticky-regex" "^7.14.5" - "@babel/plugin-transform-template-literals" "^7.14.5" - "@babel/plugin-transform-typeof-symbol" "^7.14.5" - "@babel/plugin-transform-unicode-escapes" "^7.14.5" - "@babel/plugin-transform-unicode-regex" "^7.14.5" - "@babel/preset-modules" "^0.1.4" - "@babel/types" "^7.15.6" - babel-plugin-polyfill-corejs2 "^0.2.2" - babel-plugin-polyfill-corejs3 "^0.2.2" - babel-plugin-polyfill-regenerator "^0.2.2" - core-js-compat "^3.16.0" - semver "^6.3.0" - -"@babel/preset-modules@^0.1.4": - version "0.1.4" - resolved "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.4.tgz" - integrity sha512-J36NhwnfdzpmH41M1DrnkkgAqhZaqr/NBdPfQ677mLzlaXo+oDiv1deyCDtgAhz8p328otdob0Du7+xgHGZbKg== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-proposal-unicode-property-regex" "^7.4.4" - "@babel/plugin-transform-dotall-regex" "^7.4.4" - "@babel/types" "^7.4.4" - esutils "^2.0.2" - "@babel/runtime-corejs3@^7.10.2": version "7.15.4" resolved "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.15.4.tgz" @@ -858,7 +89,7 @@ core-js-pure "^3.16.0" regenerator-runtime "^0.13.4" -"@babel/runtime@^7.0.0", "@babel/runtime@^7.10.2", "@babel/runtime@^7.10.5", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.0", "@babel/runtime@^7.13.10", "@babel/runtime@^7.13.8", "@babel/runtime@^7.14.0", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.3", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7": +"@babel/runtime@^7.0.0", "@babel/runtime@^7.10.2", "@babel/runtime@^7.10.5", "@babel/runtime@^7.12.0", "@babel/runtime@^7.13.10", "@babel/runtime@^7.13.8", "@babel/runtime@^7.14.0", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.3", "@babel/runtime@^7.8.7": version "7.15.4" resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.15.4.tgz" integrity sha512-99catp6bHCaxr4sJ/DbTGgHS4+Rs2RVd2g7iOap6SLGPDknRK9ztKNsE/Fg6QhSeh1FGE5f6gHGQmvvn3I3xhw== @@ -872,6 +103,13 @@ dependencies: regenerator-runtime "^0.13.4" +"@babel/runtime@^7.18.9": + version "7.20.1" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.20.1.tgz#1148bb33ab252b165a06698fde7576092a78b4a9" + integrity sha512-mrzLkl6U9YLF8qpqI7TB82PESyEGjm/0Ly91jG575eVxMMlb8fYfOXFZIJ8XfLrJZQbm7dlKry2bJmXBUEkdFg== + dependencies: + regenerator-runtime "^0.13.10" + "@babel/template@^7.15.4": version "7.15.4" resolved "https://registry.npmjs.org/@babel/template/-/template-7.15.4.tgz" @@ -881,7 +119,7 @@ "@babel/parser" "^7.15.4" "@babel/types" "^7.15.4" -"@babel/traverse@^7.13.0", "@babel/traverse@^7.15.4", "@babel/traverse@^7.4.5": +"@babel/traverse@^7.4.5": version "7.15.4" resolved "https://registry.npmjs.org/@babel/traverse/-/traverse-7.15.4.tgz" integrity sha512-W6lQD8l4rUbQR/vYgSuCAE75ADyyQvOpFVsvPPdkhf6lATXAsQIG9YdtOcu8BB1dZ0LKu+Zo3c1wEcbKeuhdlA== @@ -896,7 +134,7 @@ debug "^4.1.0" globals "^11.1.0" -"@babel/types@^7.15.4", "@babel/types@^7.15.6", "@babel/types@^7.4.4": +"@babel/types@^7.15.4": version "7.15.6" resolved "https://registry.npmjs.org/@babel/types/-/types-7.15.6.tgz" integrity sha512-BPU+7QhqNjmWyDO0/vitH/CuhpV8ZmK1wpKva8nuyNF5MJfuRNWMc+hc14+u9xT93kvykMdncrJT19h74uB1Ig== @@ -1014,75 +252,39 @@ resolved "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.2.5.tgz" integrity sha512-6U71C2Wp7r5XtFtQzYrW5iKFT67OixrSxjI4MptCHzdSVlgabczzqLe0ZSgnub/5Kp4hSbpDB1tMytZY9pwxxA== -"@ente-io/next-with-workbox@^1.0.3": - version "1.0.3" - resolved "https://registry.npmjs.org/@ente-io/next-with-workbox/-/next-with-workbox-1.0.3.tgz" - integrity sha512-+OAiY75RWj+15MqE64JVRUP7UZGONhTsNIx16p9NIAIvatn5ds4132o69mB3uj5eQQGs1eU2EIlpCi+3nfOJcQ== - dependencies: - clean-webpack-plugin "^3.0.0" - glob "^7.1.6" - workbox-webpack-plugin "^5.1.4" - -"@eslint/eslintrc@^0.4.3": - version "0.4.3" - resolved "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz" - integrity sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw== +"@eslint/eslintrc@^1.3.3": + version "1.3.3" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-1.3.3.tgz#2b044ab39fdfa75b4688184f9e573ce3c5b0ff95" + integrity sha512-uj3pT6Mg+3t39fvLrj8iuCIJ38zKO9FpGtJ4BBJebJhEwjoT+KLVNCcHT5QC9NGRIEi7fZ0ZR8YRb884auB4Lg== dependencies: ajv "^6.12.4" - debug "^4.1.1" - espree "^7.3.0" - globals "^13.9.0" - ignore "^4.0.6" + debug "^4.3.2" + espree "^9.4.0" + globals "^13.15.0" + ignore "^5.2.0" import-fresh "^3.2.1" - js-yaml "^3.13.1" - minimatch "^3.0.4" + js-yaml "^4.1.0" + minimatch "^3.1.2" strip-json-comments "^3.1.1" -"@hapi/address@2.x.x": - version "2.1.4" - resolved "https://registry.npmjs.org/@hapi/address/-/address-2.1.4.tgz" - integrity sha512-QD1PhQk+s31P1ixsX0H0Suoupp3VMXzIVMSwobR3F3MSUO2YCV0B7xqLcUw/Bh8yuvd3LhpyqLQWTNcRmp6IdQ== - -"@hapi/bourne@1.x.x": - version "1.3.2" - resolved "https://registry.npmjs.org/@hapi/bourne/-/bourne-1.3.2.tgz" - integrity sha512-1dVNHT76Uu5N3eJNTYcvxee+jzX4Z9lfciqRRHCU27ihbUcYi+iSc2iml5Ke1LXe1SyJCLA0+14Jh4tXJgOppA== - -"@hapi/hoek@8.x.x", "@hapi/hoek@^8.3.0": - version "8.5.1" - resolved "https://registry.npmjs.org/@hapi/hoek/-/hoek-8.5.1.tgz" - integrity sha512-yN7kbciD87WzLGc5539Tn0sApjyiGHAJgKvG9W8C7O+6c7qmoQMfVs0W4bX17eqz6C78QJqqFrtgdK5EWf6Qow== - -"@hapi/joi@^15.1.0": - version "15.1.1" - resolved "https://registry.npmjs.org/@hapi/joi/-/joi-15.1.1.tgz" - integrity sha512-entf8ZMOK8sc+8YfeOlM8pCfg3b5+WZIKBfUaaJT8UsjAAPjartzxIYm3TIbjvA4u+u++KbcXD38k682nVHDAQ== +"@humanwhocodes/config-array@^0.11.6": + version "0.11.7" + resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.7.tgz#38aec044c6c828f6ed51d5d7ae3d9b9faf6dbb0f" + integrity sha512-kBbPWzN8oVMLb0hOUYXhmxggL/1cJE6ydvjDIGi9EnAGUyA7cLVKQg+d/Dsm+KZwx2czGHrCmMVLiyg8s5JPKw== dependencies: - "@hapi/address" "2.x.x" - "@hapi/bourne" "1.x.x" - "@hapi/hoek" "8.x.x" - "@hapi/topo" "3.x.x" - -"@hapi/topo@3.x.x": - version "3.1.6" - resolved "https://registry.npmjs.org/@hapi/topo/-/topo-3.1.6.tgz" - integrity sha512-tAag0jEcjwH+P2quUfipd7liWCNX2F8NvYjQp2wtInsZxnMlypdw0FtAOLxtvvkO+GSRRbmNi8m/5y42PQJYCQ== - dependencies: - "@hapi/hoek" "^8.3.0" - -"@humanwhocodes/config-array@^0.5.0": - version "0.5.0" - resolved "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz" - integrity sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg== - dependencies: - "@humanwhocodes/object-schema" "^1.2.0" + "@humanwhocodes/object-schema" "^1.2.1" debug "^4.1.1" - minimatch "^3.0.4" + minimatch "^3.0.5" -"@humanwhocodes/object-schema@^1.2.0": - version "1.2.0" - resolved "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.0.tgz" - integrity sha512-wdppn25U8z/2yiaT6YGquE6X8sSv7hNMWSXYSSU1jGv/yd6XqjXgTDJ8KP4NgjTXfJ3GbRjeeb8RTV7a/VpM+w== +"@humanwhocodes/module-importer@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c" + integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA== + +"@humanwhocodes/object-schema@^1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45" + integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== "@mui/base@5.0.0-alpha.77": version "5.0.0-alpha.77" @@ -1204,65 +406,82 @@ dependencies: webpack-bundle-analyzer "3.6.1" -"@next/env@12.1.0": - version "12.1.0" - resolved "https://registry.npmjs.org/@next/env/-/env-12.1.0.tgz" - integrity sha512-nrIgY6t17FQ9xxwH3jj0a6EOiQ/WDHUos35Hghtr+SWN/ntHIQ7UpuvSi0vaLzZVHQWaDupKI+liO5vANcDeTQ== +"@next/env@12.3.1": + version "12.3.1" + resolved "https://registry.yarnpkg.com/@next/env/-/env-12.3.1.tgz#18266bd92de3b4aa4037b1927aa59e6f11879260" + integrity sha512-9P9THmRFVKGKt9DYqeC2aKIxm8rlvkK38V1P1sRE7qyoPBIs8l9oo79QoSdPtOWfzkbDAVUqvbQGgTMsb8BtJg== -"@next/swc-android-arm64@12.1.0": - version "12.1.0" - resolved "https://registry.yarnpkg.com/@next/swc-android-arm64/-/swc-android-arm64-12.1.0.tgz#865ba3a9afc204ff2bdeea49dd64d58705007a39" - integrity sha512-/280MLdZe0W03stA69iL+v6I+J1ascrQ6FrXBlXGCsGzrfMaGr7fskMa0T5AhQIVQD4nA/46QQWxG//DYuFBcA== +"@next/eslint-plugin-next@13.0.4": + version "13.0.4" + resolved "https://registry.yarnpkg.com/@next/eslint-plugin-next/-/eslint-plugin-next-13.0.4.tgz#46800f48d9f81e8bb460319a15a00bf2f4016e91" + integrity sha512-jZ4urKT+aO9QHm3ttihrIQscQISDSKK8isAom750+EySn9o3LCSkTdPGBtvBqY7Yku+NqhfQempR5J58DqTaVg== + dependencies: + glob "7.1.7" -"@next/swc-darwin-arm64@12.1.0": - version "12.1.0" - resolved "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-12.1.0.tgz" - integrity sha512-R8vcXE2/iONJ1Unf5Ptqjk6LRW3bggH+8drNkkzH4FLEQkHtELhvcmJwkXcuipyQCsIakldAXhRbZmm3YN1vXg== +"@next/swc-android-arm-eabi@12.3.1": + version "12.3.1" + resolved "https://registry.yarnpkg.com/@next/swc-android-arm-eabi/-/swc-android-arm-eabi-12.3.1.tgz#b15ce8ad376102a3b8c0f3c017dde050a22bb1a3" + integrity sha512-i+BvKA8tB//srVPPQxIQN5lvfROcfv4OB23/L1nXznP+N/TyKL8lql3l7oo2LNhnH66zWhfoemg3Q4VJZSruzQ== -"@next/swc-darwin-x64@12.1.0": - version "12.1.0" - resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-12.1.0.tgz#fcd684497a76e8feaca88db3c394480ff0b007cd" - integrity sha512-ieAz0/J0PhmbZBB8+EA/JGdhRHBogF8BWaeqR7hwveb6SYEIJaDNQy0I+ZN8gF8hLj63bEDxJAs/cEhdnTq+ug== +"@next/swc-android-arm64@12.3.1": + version "12.3.1" + resolved "https://registry.yarnpkg.com/@next/swc-android-arm64/-/swc-android-arm64-12.3.1.tgz#85d205f568a790a137cb3c3f720d961a2436ac9c" + integrity sha512-CmgU2ZNyBP0rkugOOqLnjl3+eRpXBzB/I2sjwcGZ7/Z6RcUJXK5Evz+N0ucOxqE4cZ3gkTeXtSzRrMK2mGYV8Q== -"@next/swc-linux-arm-gnueabihf@12.1.0": - version "12.1.0" - resolved "https://registry.yarnpkg.com/@next/swc-linux-arm-gnueabihf/-/swc-linux-arm-gnueabihf-12.1.0.tgz#9ec6380a27938a5799aaa6035c205b3c478468a7" - integrity sha512-njUd9hpl6o6A5d08dC0cKAgXKCzm5fFtgGe6i0eko8IAdtAPbtHxtpre3VeSxdZvuGFh+hb0REySQP9T1ttkog== +"@next/swc-darwin-arm64@12.3.1": + version "12.3.1" + resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-12.3.1.tgz#b105457d6760a7916b27e46c97cb1a40547114ae" + integrity sha512-hT/EBGNcu0ITiuWDYU9ur57Oa4LybD5DOQp4f22T6zLfpoBMfBibPtR8XktXmOyFHrL/6FC2p9ojdLZhWhvBHg== -"@next/swc-linux-arm64-gnu@12.1.0": - version "12.1.0" - resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-12.1.0.tgz#7f4196dff1049cea479607c75b81033ae2dbd093" - integrity sha512-OqangJLkRxVxMhDtcb7Qn1xjzFA3s50EIxY7mljbSCLybU+sByPaWAHY4px97ieOlr2y4S0xdPKkQ3BCAwyo6Q== +"@next/swc-darwin-x64@12.3.1": + version "12.3.1" + resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-12.3.1.tgz#6947b39082271378896b095b6696a7791c6e32b1" + integrity sha512-9S6EVueCVCyGf2vuiLiGEHZCJcPAxglyckTZcEwLdJwozLqN0gtS0Eq0bQlGS3dH49Py/rQYpZ3KVWZ9BUf/WA== -"@next/swc-linux-arm64-musl@12.1.0": - version "12.1.0" - resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-12.1.0.tgz#b445f767569cdc2dddee785ca495e1a88c025566" - integrity sha512-hB8cLSt4GdmOpcwRe2UzI5UWn6HHO/vLkr5OTuNvCJ5xGDwpPXelVkYW/0+C3g5axbDW2Tym4S+MQCkkH9QfWA== +"@next/swc-freebsd-x64@12.3.1": + version "12.3.1" + resolved "https://registry.yarnpkg.com/@next/swc-freebsd-x64/-/swc-freebsd-x64-12.3.1.tgz#2b6c36a4d84aae8b0ea0e0da9bafc696ae27085a" + integrity sha512-qcuUQkaBZWqzM0F1N4AkAh88lLzzpfE6ImOcI1P6YeyJSsBmpBIV8o70zV+Wxpc26yV9vpzb+e5gCyxNjKJg5Q== -"@next/swc-linux-x64-gnu@12.1.0": - version "12.1.0" - resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-12.1.0.tgz#67610e9be4fbc987de7535f1bcb17e45fe12f90e" - integrity sha512-OKO4R/digvrVuweSw/uBM4nSdyzsBV5EwkUeeG4KVpkIZEe64ZwRpnFB65bC6hGwxIBnTv5NMSnJ+0K/WmG78A== +"@next/swc-linux-arm-gnueabihf@12.3.1": + version "12.3.1" + resolved "https://registry.yarnpkg.com/@next/swc-linux-arm-gnueabihf/-/swc-linux-arm-gnueabihf-12.3.1.tgz#6e421c44285cfedac1f4631d5de330dd60b86298" + integrity sha512-diL9MSYrEI5nY2wc/h/DBewEDUzr/DqBjIgHJ3RUNtETAOB3spMNHvJk2XKUDjnQuluLmFMloet9tpEqU2TT9w== -"@next/swc-linux-x64-musl@12.1.0": - version "12.1.0" - resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-12.1.0.tgz#ea19a23db08a9f2e34ac30401f774cf7d1669d31" - integrity sha512-JohhgAHZvOD3rQY7tlp7NlmvtvYHBYgY0x5ZCecUT6eCCcl9lv6iV3nfu82ErkxNk1H893fqH0FUpznZ/H3pSw== +"@next/swc-linux-arm64-gnu@12.3.1": + version "12.3.1" + resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-12.3.1.tgz#8863f08a81f422f910af126159d2cbb9552ef717" + integrity sha512-o/xB2nztoaC7jnXU3Q36vGgOolJpsGG8ETNjxM1VAPxRwM7FyGCPHOMk1XavG88QZSQf+1r+POBW0tLxQOJ9DQ== -"@next/swc-win32-arm64-msvc@12.1.0": - version "12.1.0" - resolved "https://registry.yarnpkg.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-12.1.0.tgz#eadf054fc412085659b98e145435bbba200b5283" - integrity sha512-T/3gIE6QEfKIJ4dmJk75v9hhNiYZhQYAoYm4iVo1TgcsuaKLFa+zMPh4056AHiG6n9tn2UQ1CFE8EoybEsqsSw== +"@next/swc-linux-arm64-musl@12.3.1": + version "12.3.1" + resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-12.3.1.tgz#0038f07cf0b259d70ae0c80890d826dfc775d9f3" + integrity sha512-2WEasRxJzgAmP43glFNhADpe8zB7kJofhEAVNbDJZANp+H4+wq+/cW1CdDi8DqjkShPEA6/ejJw+xnEyDID2jg== -"@next/swc-win32-ia32-msvc@12.1.0": - version "12.1.0" - resolved "https://registry.yarnpkg.com/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-12.1.0.tgz#68faeae10c89f698bf9d28759172b74c9c21bda1" - integrity sha512-iwnKgHJdqhIW19H9PRPM9j55V6RdcOo6rX+5imx832BCWzkDbyomWnlzBfr6ByUYfhohb8QuH4hSGEikpPqI0Q== +"@next/swc-linux-x64-gnu@12.3.1": + version "12.3.1" + resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-12.3.1.tgz#c66468f5e8181ffb096c537f0dbfb589baa6a9c1" + integrity sha512-JWEaMyvNrXuM3dyy9Pp5cFPuSSvG82+yABqsWugjWlvfmnlnx9HOQZY23bFq3cNghy5V/t0iPb6cffzRWylgsA== -"@next/swc-win32-x64-msvc@12.1.0": - version "12.1.0" - resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-12.1.0.tgz#d27e7e76c87a460a4da99c5bfdb1618dcd6cd064" - integrity sha512-aBvcbMwuanDH4EMrL2TthNJy+4nP59Bimn8egqv6GHMVj0a44cU6Au4PjOhLNqEh9l+IpRGBqMTzec94UdC5xg== +"@next/swc-linux-x64-musl@12.3.1": + version "12.3.1" + resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-12.3.1.tgz#c6269f3e96ac0395bc722ad97ce410ea5101d305" + integrity sha512-xoEWQQ71waWc4BZcOjmatuvPUXKTv6MbIFzpm4LFeCHsg2iwai0ILmNXf81rJR+L1Wb9ifEke2sQpZSPNz1Iyg== + +"@next/swc-win32-arm64-msvc@12.3.1": + version "12.3.1" + resolved "https://registry.yarnpkg.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-12.3.1.tgz#83c639ee969cee36ce247c3abd1d9df97b5ecade" + integrity sha512-hswVFYQYIeGHE2JYaBVtvqmBQ1CppplQbZJS/JgrVI3x2CurNhEkmds/yqvDONfwfbttTtH4+q9Dzf/WVl3Opw== + +"@next/swc-win32-ia32-msvc@12.3.1": + version "12.3.1" + resolved "https://registry.yarnpkg.com/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-12.3.1.tgz#52995748b92aa8ad053440301bc2c0d9fbcf27c2" + integrity sha512-Kny5JBehkTbKPmqulr5i+iKntO5YMP+bVM8Hf8UAmjSMVo3wehyLVc9IZkNmcbxi+vwETnQvJaT5ynYBkJ9dWA== + +"@next/swc-win32-x64-msvc@12.3.1": + version "12.3.1" + resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-12.3.1.tgz#27d71a95247a9eaee03d47adee7e3bd594514136" + integrity sha512-W1ijvzzg+kPEX6LAc+50EYYSEo0FVu7dmTE+t+DM4iOLqgGHoW9uYSz9wCVdkXOEEMP9xhXfGpcSxsfDucyPkA== "@nodelib/fs.scandir@2.1.5": version "2.1.5" @@ -1277,7 +496,7 @@ resolved "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz" integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== -"@nodelib/fs.walk@^1.2.3": +"@nodelib/fs.walk@^1.2.3", "@nodelib/fs.walk@^1.2.8": version "1.2.8" resolved "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz" integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== @@ -1285,6 +504,18 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" +"@pkgr/utils@^2.3.1": + version "2.3.1" + resolved "https://registry.yarnpkg.com/@pkgr/utils/-/utils-2.3.1.tgz#0a9b06ffddee364d6642b3cd562ca76f55b34a03" + integrity sha512-wfzX8kc1PMyUILA+1Z/EqoE4UCXGy0iRGMhPwdfae1+f0OXlLqCk+By+aMzgJBzR9AzS4CDizioG6Ss1gvAFJw== + dependencies: + cross-spawn "^7.0.3" + is-glob "^4.0.3" + open "^8.4.0" + picocolors "^1.0.0" + tiny-glob "^0.2.9" + tslib "^2.4.0" + "@popperjs/core@^2.11.5": version "2.11.5" resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.5.tgz#db5a11bf66bdab39569719555b0f76e138d7bd64" @@ -1312,33 +543,10 @@ dependencies: dequal "^2.0.2" -"@rollup/plugin-node-resolve@^7.1.1": - version "7.1.3" - resolved "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-7.1.3.tgz" - integrity sha512-RxtSL3XmdTAE2byxekYLnx+98kEUOrPHF/KRVjLH+DEIHy6kjIw7YINQzn+NXiH/NTrQLAwYs0GWB+csWygA9Q== - dependencies: - "@rollup/pluginutils" "^3.0.8" - "@types/resolve" "0.0.8" - builtin-modules "^3.1.0" - is-module "^1.0.0" - resolve "^1.14.2" - -"@rollup/plugin-replace@^2.3.1": - version "2.4.2" - resolved "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-2.4.2.tgz" - integrity sha512-IGcu+cydlUMZ5En85jxHH4qj2hta/11BHq95iHEyb2sbgiN0eCdzvUcHw5gt9pBL5lTi4JDYJ1acCoMGpTvEZg== - dependencies: - "@rollup/pluginutils" "^3.1.0" - magic-string "^0.25.7" - -"@rollup/pluginutils@^3.0.8", "@rollup/pluginutils@^3.1.0": - version "3.1.0" - resolved "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz" - integrity sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg== - dependencies: - "@types/estree" "0.0.39" - estree-walker "^1.0.1" - picomatch "^2.2.2" +"@rushstack/eslint-patch@^1.1.3": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@rushstack/eslint-patch/-/eslint-patch-1.2.0.tgz#8be36a1f66f3265389e90b5f9c9962146758f728" + integrity sha512-sXo/qW2/pAcmT43VoRKOJbDOfV3cYpq3szSVfIThQXNt+E4DfKj361vaAt3c88U5tPUxzEswam7GW48PJqtKAg== "@sentry/browser@6.12.0": version "6.12.0" @@ -1478,13 +686,12 @@ resolved "https://registry.npmjs.org/@stripe/stripe-js/-/stripe-js-1.17.1.tgz" integrity sha512-c9MyDvdi5Xou0j0JPNy86NebtTDfh9o62Ifuzx6GSm2YO0oedBpy51WSyOue2L8Fb+mqESS5gd6mGVEIPUnXsA== -"@surma/rollup-plugin-off-main-thread@^1.1.1": - version "1.4.2" - resolved "https://registry.npmjs.org/@surma/rollup-plugin-off-main-thread/-/rollup-plugin-off-main-thread-1.4.2.tgz" - integrity sha512-yBMPqmd1yEJo/280PAMkychuaALyQ9Lkb5q1ck3mjJrFuEobIfhnQ4J3mbvBoISmR3SWMWV+cGB/I0lCQee79A== +"@swc/helpers@0.4.11": + version "0.4.11" + resolved "https://registry.yarnpkg.com/@swc/helpers/-/helpers-0.4.11.tgz#db23a376761b3d31c26502122f349a21b592c8de" + integrity sha512-rEUrBSGIoSFuYxwBYtlUFMlE2CwGhmW+w9355/5oduSw8e5h2+Tj4UrAGNNgP9915++wj5vkQo0UuOBqOAq4nw== dependencies: - ejs "^2.6.1" - magic-string "^0.25.0" + tslib "^2.4.0" "@tokenizer/token@^0.3.0": version "0.3.0" @@ -1496,24 +703,6 @@ resolved "https://registry.npmjs.org/@types/debounce-promise/-/debounce-promise-3.1.4.tgz" integrity sha512-9SEVY3nsz+uMN2DwDocftB5TAgZe7D0cOzxxRhpotWs6T4QFqRaTXpXbOSzbk31/7iYcfCkJJPwWGzTxyuGhCg== -"@types/estree@*": - version "0.0.50" - resolved "https://registry.npmjs.org/@types/estree/-/estree-0.0.50.tgz" - integrity sha512-C6N5s2ZFtuZRj54k2/zyRhNDjJwwcViAM3Nbm8zjBpbqAdZ00mr0CFxvSKeO8Y/e03WVFLpQMdHYVfUd6SB+Hw== - -"@types/estree@0.0.39": - version "0.0.39" - resolved "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz" - integrity sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw== - -"@types/glob@^7.1.1": - version "7.1.4" - resolved "https://registry.npmjs.org/@types/glob/-/glob-7.1.4.tgz" - integrity sha512-w+LsMxKyYQm347Otw+IfBXOv9UWVjpHpCDdbBMt8Kz/xbvCYNjP+0qPh91Km3iKfSRLBB0P7fAMf0KHrPu+MyA== - dependencies: - "@types/minimatch" "*" - "@types/node" "*" - "@types/hoist-non-react-statics@*": version "3.3.1" resolved "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz" @@ -1527,10 +716,10 @@ resolved "https://registry.npmjs.org/@types/invariant/-/invariant-2.2.35.tgz" integrity sha512-DxX1V9P8zdJPYQat1gHyY0xj3efl8gnMVjiM9iCY6y27lj+PoQWkgjt8jDqmovPqULkKVpKRg8J36iQiA+EtEg== -"@types/json-schema@^7.0.7": - version "7.0.9" - resolved "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz" - integrity sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ== +"@types/json-schema@^7.0.9": + version "7.0.11" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.11.tgz#d421b6c527a3037f7c84433fd2c4229e016863d3" + integrity sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ== "@types/json5@^0.0.29": version "0.0.29" @@ -1542,16 +731,6 @@ resolved "https://registry.npmjs.org/@types/libsodium-wrappers/-/libsodium-wrappers-0.7.9.tgz" integrity sha512-LisgKLlYQk19baQwjkBZZXdJL0KbeTpdEnrAfz5hQACbklCY0gVFnsKUyjfNWF1UQsCSjw93Sj5jSbiO8RPfdw== -"@types/minimatch@*": - version "3.0.5" - resolved "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.5.tgz" - integrity sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ== - -"@types/node@*": - version "17.0.18" - resolved "https://registry.npmjs.org/@types/node/-/node-17.0.18.tgz" - integrity sha512-eKj4f/BsN/qcculZiRSujogjvp5O/k4lOW5m35NopjZM/QwLOR075a8pJW5hD+Rtdm2DaCVPENS6KtSQnUD6BA== - "@types/node@11.11.6": version "11.11.6" resolved "https://registry.npmjs.org/@types/node/-/node-11.11.6.tgz" @@ -1670,22 +849,15 @@ "@types/scheduler" "*" csstype "^3.0.2" -"@types/resolve@0.0.8": - version "0.0.8" - resolved "https://registry.npmjs.org/@types/resolve/-/resolve-0.0.8.tgz" - integrity sha512-auApPaJf3NPfe18hSoJkp8EbZzer2ISk7o8mCC3M9he/a04+gbMF97NkpD2S8riMGvm4BMRI59/SZQSaLTKpsQ== - dependencies: - "@types/node" "*" - "@types/scheduler@*": version "0.16.2" resolved "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz" integrity sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew== -"@types/source-list-map@*": - version "0.1.2" - resolved "https://registry.npmjs.org/@types/source-list-map/-/source-list-map-0.1.2.tgz" - integrity sha512-K5K+yml8LTo9bWJI/rECfIPrGgxdpeNbj+d53lwN4QjW1MCwlkhUms+gtdzigTeUyBr09+u8BwOIY3MXvHdcsA== +"@types/semver@^7.3.12": + version "7.3.13" + resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.3.13.tgz#da4bfd73f49bd541d28920ab0e2bf0ee80f71c91" + integrity sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw== "@types/styled-components@^5.1.25": version "5.1.25" @@ -1696,122 +868,98 @@ "@types/react" "*" csstype "^3.0.2" -"@types/tapable@^1": - version "1.0.8" - resolved "https://registry.npmjs.org/@types/tapable/-/tapable-1.0.8.tgz" - integrity sha512-ipixuVrh2OdNmauvtT51o3d8z12p6LtFW9in7U79der/kwejjdNchQC5UMn5u/KxNoM7VHHOs/l8KS8uHxhODQ== - -"@types/trusted-types@^2.0.2": - version "2.0.2" - resolved "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.2.tgz" - integrity sha512-F5DIZ36YVLE+PN+Zwws4kJogq47hNgX3Nx6WyDJ3kcplxyke3XIzB8uK5n/Lpm1HBsbGzd6nmGehL8cPekP+Tg== - -"@types/uglify-js@*": - version "3.13.1" - resolved "https://registry.npmjs.org/@types/uglify-js/-/uglify-js-3.13.1.tgz" - integrity sha512-O3MmRAk6ZuAKa9CHgg0Pr0+lUOqoMLpc9AS4R8ano2auvsg7IE8syF3Xh/NPr26TWklxYcqoEEFdzLLs1fV9PQ== - dependencies: - source-map "^0.6.1" - "@types/warning@^3.0.0": version "3.0.0" resolved "https://registry.npmjs.org/@types/warning/-/warning-3.0.0.tgz" integrity sha1-DSUBJorY+ZYrdA04fEZU9fjiPlI= -"@types/webpack-sources@*": - version "3.2.0" - resolved "https://registry.npmjs.org/@types/webpack-sources/-/webpack-sources-3.2.0.tgz" - integrity sha512-Ft7YH3lEVRQ6ls8k4Ff1oB4jN6oy/XmU6tQISKdhfh+1mR+viZFphS6WL0IrtDOzvefmJg5a0s7ZQoRXwqTEFg== - dependencies: - "@types/node" "*" - "@types/source-list-map" "*" - source-map "^0.7.3" - -"@types/webpack@^4.4.31": - version "4.41.30" - resolved "https://registry.npmjs.org/@types/webpack/-/webpack-4.41.30.tgz" - integrity sha512-GUHyY+pfuQ6haAfzu4S14F+R5iGRwN6b2FRNJY7U0NilmFAqbsOfK6j1HwuLBAqwRIT+pVdNDJGJ6e8rpp0KHA== - dependencies: - "@types/node" "*" - "@types/tapable" "^1" - "@types/uglify-js" "*" - "@types/webpack-sources" "*" - anymatch "^3.0.0" - source-map "^0.6.0" - "@types/yup@^0.29.7": version "0.29.13" resolved "https://registry.npmjs.org/@types/yup/-/yup-0.29.13.tgz" integrity sha512-qRyuv+P/1t1JK1rA+elmK1MmCL1BapEzKKfbEhDBV/LMMse4lmhZ/XbgETI39JveDJRpLjmToOI6uFtMW/WR2g== -"@typescript-eslint/eslint-plugin@^4.25.0": - version "4.31.0" - resolved "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.31.0.tgz" - integrity sha512-iPKZTZNavAlOhfF4gymiSuUkgLne/nh5Oz2/mdiUmuZVD42m9PapnCnzjxuDsnpnbH3wT5s2D8bw6S39TC6GNw== +"@typescript-eslint/eslint-plugin@^5.43.0": + version "5.43.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.43.0.tgz#4a5248eb31b454715ddfbf8cfbf497529a0a78bc" + integrity sha512-wNPzG+eDR6+hhW4yobEmpR36jrqqQv1vxBq5LJO3fBAktjkvekfr4BRl+3Fn1CM/A+s8/EiGUbOMDoYqWdbtXA== dependencies: - "@typescript-eslint/experimental-utils" "4.31.0" - "@typescript-eslint/scope-manager" "4.31.0" - debug "^4.3.1" - functional-red-black-tree "^1.0.1" - regexpp "^3.1.0" - semver "^7.3.5" + "@typescript-eslint/scope-manager" "5.43.0" + "@typescript-eslint/type-utils" "5.43.0" + "@typescript-eslint/utils" "5.43.0" + debug "^4.3.4" + ignore "^5.2.0" + natural-compare-lite "^1.4.0" + regexpp "^3.2.0" + semver "^7.3.7" tsutils "^3.21.0" -"@typescript-eslint/experimental-utils@4.31.0": - version "4.31.0" - resolved "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.31.0.tgz" - integrity sha512-Hld+EQiKLMppgKKkdUsLeVIeEOrwKc2G983NmznY/r5/ZtZCDvIOXnXtwqJIgYz/ymsy7n7RGvMyrzf1WaSQrw== +"@typescript-eslint/parser@^5.42.0": + version "5.43.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.43.0.tgz#9c86581234b88f2ba406f0b99a274a91c11630fd" + integrity sha512-2iHUK2Lh7PwNUlhFxxLI2haSDNyXvebBO9izhjhMoDC+S3XI9qt2DGFUsiJ89m2k7gGYch2aEpYqV5F/+nwZug== dependencies: - "@types/json-schema" "^7.0.7" - "@typescript-eslint/scope-manager" "4.31.0" - "@typescript-eslint/types" "4.31.0" - "@typescript-eslint/typescript-estree" "4.31.0" + "@typescript-eslint/scope-manager" "5.43.0" + "@typescript-eslint/types" "5.43.0" + "@typescript-eslint/typescript-estree" "5.43.0" + debug "^4.3.4" + +"@typescript-eslint/scope-manager@5.43.0": + version "5.43.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.43.0.tgz#566e46303392014d5d163704724872e1f2dd3c15" + integrity sha512-XNWnGaqAtTJsUiZaoiGIrdJYHsUOd3BZ3Qj5zKp9w6km6HsrjPk/TGZv0qMTWyWj0+1QOqpHQ2gZOLXaGA9Ekw== + dependencies: + "@typescript-eslint/types" "5.43.0" + "@typescript-eslint/visitor-keys" "5.43.0" + +"@typescript-eslint/type-utils@5.43.0": + version "5.43.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.43.0.tgz#91110fb827df5161209ecca06f70d19a96030be6" + integrity sha512-K21f+KY2/VvYggLf5Pk4tgBOPs2otTaIHy2zjclo7UZGLyFH86VfUOm5iq+OtDtxq/Zwu2I3ujDBykVW4Xtmtg== + dependencies: + "@typescript-eslint/typescript-estree" "5.43.0" + "@typescript-eslint/utils" "5.43.0" + debug "^4.3.4" + tsutils "^3.21.0" + +"@typescript-eslint/types@5.43.0": + version "5.43.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.43.0.tgz#e4ddd7846fcbc074325293515fa98e844d8d2578" + integrity sha512-jpsbcD0x6AUvV7tyOlyvon0aUsQpF8W+7TpJntfCUWU1qaIKu2K34pMwQKSzQH8ORgUrGYY6pVIh1Pi8TNeteg== + +"@typescript-eslint/typescript-estree@5.43.0": + version "5.43.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.43.0.tgz#b6883e58ba236a602c334be116bfc00b58b3b9f2" + integrity sha512-BZ1WVe+QQ+igWal2tDbNg1j2HWUkAa+CVqdU79L4HP9izQY6CNhXfkNwd1SS4+sSZAP/EthI1uiCSY/+H0pROg== + dependencies: + "@typescript-eslint/types" "5.43.0" + "@typescript-eslint/visitor-keys" "5.43.0" + debug "^4.3.4" + globby "^11.1.0" + is-glob "^4.0.3" + semver "^7.3.7" + tsutils "^3.21.0" + +"@typescript-eslint/utils@5.43.0": + version "5.43.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.43.0.tgz#00fdeea07811dbdf68774a6f6eacfee17fcc669f" + integrity sha512-8nVpA6yX0sCjf7v/NDfeaOlyaIIqL7OaIGOWSPFqUKK59Gnumd3Wa+2l8oAaYO2lk0sO+SbWFWRSvhu8gLGv4A== + dependencies: + "@types/json-schema" "^7.0.9" + "@types/semver" "^7.3.12" + "@typescript-eslint/scope-manager" "5.43.0" + "@typescript-eslint/types" "5.43.0" + "@typescript-eslint/typescript-estree" "5.43.0" eslint-scope "^5.1.1" eslint-utils "^3.0.0" + semver "^7.3.7" -"@typescript-eslint/parser@^4.25.0": - version "4.31.0" - resolved "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.31.0.tgz" - integrity sha512-oWbzvPh5amMuTmKaf1wp0ySxPt2ZXHnFQBN2Szu1O//7LmOvgaKTCIDNLK2NvzpmVd5A2M/1j/rujBqO37hj3w== +"@typescript-eslint/visitor-keys@5.43.0": + version "5.43.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.43.0.tgz#cbbdadfdfea385310a20a962afda728ea106befa" + integrity sha512-icl1jNH/d18OVHLfcwdL3bWUKsBeIiKYTGxMJCoGe7xFht+E4QgzOqoWYrU8XSLJWhVw8nTacbm03v23J/hFTg== dependencies: - "@typescript-eslint/scope-manager" "4.31.0" - "@typescript-eslint/types" "4.31.0" - "@typescript-eslint/typescript-estree" "4.31.0" - debug "^4.3.1" - -"@typescript-eslint/scope-manager@4.31.0": - version "4.31.0" - resolved "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.31.0.tgz" - integrity sha512-LJ+xtl34W76JMRLjbaQorhR0hfRAlp3Lscdiz9NeI/8i+q0hdBZ7BsiYieLoYWqy+AnRigaD3hUwPFugSzdocg== - dependencies: - "@typescript-eslint/types" "4.31.0" - "@typescript-eslint/visitor-keys" "4.31.0" - -"@typescript-eslint/types@4.31.0": - version "4.31.0" - resolved "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.31.0.tgz" - integrity sha512-9XR5q9mk7DCXgXLS7REIVs+BaAswfdHhx91XqlJklmqWpTALGjygWVIb/UnLh4NWhfwhR5wNe1yTyCInxVhLqQ== - -"@typescript-eslint/typescript-estree@4.31.0": - version "4.31.0" - resolved "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.31.0.tgz" - integrity sha512-QHl2014t3ptg+xpmOSSPn5hm4mY8D4s97ftzyk9BZ8RxYQ3j73XcwuijnJ9cMa6DO4aLXeo8XS3z1omT9LA/Eg== - dependencies: - "@typescript-eslint/types" "4.31.0" - "@typescript-eslint/visitor-keys" "4.31.0" - debug "^4.3.1" - globby "^11.0.3" - is-glob "^4.0.1" - semver "^7.3.5" - tsutils "^3.21.0" - -"@typescript-eslint/visitor-keys@4.31.0": - version "4.31.0" - resolved "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.31.0.tgz" - integrity sha512-HUcRp2a9I+P21+O21yu3ezv3GEPGjyGiXoEUQwZXjR8UxRApGeLyWH4ZIIUSalE28aG4YsV6GjtaAVB3QKOu0w== - dependencies: - "@typescript-eslint/types" "4.31.0" - eslint-visitor-keys "^2.0.0" + "@typescript-eslint/types" "5.43.0" + eslint-visitor-keys "^3.3.0" accepts@~1.3.7: version "1.3.7" @@ -1821,9 +969,9 @@ accepts@~1.3.7: mime-types "~2.1.24" negotiator "0.6.2" -acorn-jsx@^5.3.1: +acorn-jsx@^5.3.2: version "5.3.2" - resolved "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== acorn-walk@^7.1.1: @@ -1831,11 +979,16 @@ acorn-walk@^7.1.1: resolved "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz" integrity sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA== -acorn@^7.1.0, acorn@^7.1.1, acorn@^7.4.0: +acorn@^7.1.1: version "7.4.1" resolved "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz" integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== +acorn@^8.8.0: + version "8.8.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.1.tgz#0a3f9cbecc4ec3bea6f0a80b66ae8dd2da250b73" + integrity sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA== + agent-base@6: version "6.0.2" resolved "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz" @@ -1861,16 +1014,6 @@ ajv@^6.10.0, ajv@^6.12.4: json-schema-traverse "^0.4.1" uri-js "^4.2.2" -ajv@^8.0.1: - version "8.6.2" - resolved "https://registry.npmjs.org/ajv/-/ajv-8.6.2.tgz" - integrity sha512-9807RlWAgT564wT+DjeyU5OFMPjmzxVobvDFmNAhY+5zD6A2ly3jDp6sgnfyDtlIQ+7H97oc/DGCzzfu9rjw9w== - dependencies: - fast-deep-equal "^3.1.1" - json-schema-traverse "^1.0.0" - require-from-string "^2.0.2" - uri-js "^4.2.2" - ansi-colors@^4.1.1: version "4.1.1" resolved "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz" @@ -1893,7 +1036,7 @@ ansi-regex@^3.0.0: resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz" integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= -ansi-regex@^5.0.0: +ansi-regex@^5.0.0, ansi-regex@^5.0.1: version "5.0.1" resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz" integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== @@ -1912,14 +1055,6 @@ ansi-styles@^4.0.0, ansi-styles@^4.1.0: dependencies: color-convert "^2.0.1" -anymatch@^3.0.0: - version "3.1.2" - resolved "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz" - integrity sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg== - dependencies: - normalize-path "^3.0.0" - picomatch "^2.0.4" - aproba@^1.0.3: version "1.2.0" resolved "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz" @@ -1933,12 +1068,10 @@ are-we-there-yet@~1.1.2: delegates "^1.0.0" readable-stream "^2.0.6" -argparse@^1.0.7: - version "1.0.10" - resolved "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz" - integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== - dependencies: - sprintf-js "~1.0.2" +argparse@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" + integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== aria-query@^4.2.2: version "4.2.2" @@ -1953,7 +1086,7 @@ array-flatten@1.1.1: resolved "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz" integrity sha1-ml9pkFGx5wczKPKgCJaLZOopVdI= -array-includes@^3.1.1, array-includes@^3.1.2, array-includes@^3.1.3: +array-includes@^3.1.2: version "3.1.3" resolved "https://registry.npmjs.org/array-includes/-/array-includes-3.1.3.tgz" integrity sha512-gcem1KlBU7c9rB+Rq8/3PPKsK2kjqeEBa3bD5kkQo4nYlOHQCJqIJFqBXDEfwaRuYTT4E+FxA9xez7Gf/e3Q7A== @@ -1964,41 +1097,52 @@ array-includes@^3.1.1, array-includes@^3.1.2, array-includes@^3.1.3: get-intrinsic "^1.1.1" is-string "^1.0.5" -array-union@^1.0.1: - version "1.0.2" - resolved "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz" - integrity sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk= +array-includes@^3.1.4, array-includes@^3.1.5, array-includes@^3.1.6: + version "3.1.6" + resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.6.tgz#9e9e720e194f198266ba9e18c29e6a9b0e4b225f" + integrity sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw== dependencies: - array-uniq "^1.0.1" + call-bind "^1.0.2" + define-properties "^1.1.4" + es-abstract "^1.20.4" + get-intrinsic "^1.1.3" + is-string "^1.0.7" array-union@^2.1.0: version "2.1.0" resolved "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz" integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== -array-uniq@^1.0.1: - version "1.0.3" - resolved "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz" - integrity sha1-r2rId6Jcx/dOBYiUdThY39sk/bY= - -array.prototype.flat@^1.2.4: - version "1.2.4" - resolved "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.4.tgz" - integrity sha512-4470Xi3GAPAjZqFcljX2xzckv1qeKPizoNkiS0+O4IoPR2ZNpcjE0pkhdihlDouK+x6QOast26B4Q/O9DJnwSg== +array.prototype.flat@^1.2.5: + version "1.3.1" + resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.3.1.tgz#ffc6576a7ca3efc2f46a143b9d1dda9b4b3cf5e2" + integrity sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA== dependencies: - call-bind "^1.0.0" - define-properties "^1.1.3" - es-abstract "^1.18.0-next.1" + call-bind "^1.0.2" + define-properties "^1.1.4" + es-abstract "^1.20.4" + es-shim-unscopables "^1.0.0" -array.prototype.flatmap@^1.2.4: - version "1.2.4" - resolved "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.2.4.tgz" - integrity sha512-r9Z0zYoxqHz60vvQbWEdXIEtCwHF0yxaWfno9qzXeNHvfyl3BZqygmGzb84dsubyaXLH4husF+NFgMSdpZhk2Q== +array.prototype.flatmap@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.3.1.tgz#1aae7903c2100433cb8261cd4ed310aab5c4a183" + integrity sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ== dependencies: - call-bind "^1.0.0" - define-properties "^1.1.3" - es-abstract "^1.18.0-next.1" - function-bind "^1.1.1" + call-bind "^1.0.2" + define-properties "^1.1.4" + es-abstract "^1.20.4" + es-shim-unscopables "^1.0.0" + +array.prototype.tosorted@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/array.prototype.tosorted/-/array.prototype.tosorted-1.1.1.tgz#ccf44738aa2b5ac56578ffda97c03fd3e23dd532" + integrity sha512-pZYPXPRl2PqWcsUs6LOMn+1f1532nEoPTYowBtqLwAW+W8vSVhkIGnmOX1t/UQjD6YGI0vcD2B1U7ZFGQH9jnQ== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + es-abstract "^1.20.4" + es-shim-unscopables "^1.0.0" + get-intrinsic "^1.1.3" ast-types-flow@^0.0.7: version "0.0.7" @@ -2020,10 +1164,10 @@ attr-accept@^2.2.1: resolved "https://registry.npmjs.org/attr-accept/-/attr-accept-2.2.2.tgz" integrity sha512-7prDjvt9HmqiZ0cl5CRjtS84sEyhsHP2coDkaZKRKVfCDo9s7iw7ChVmar78Gu9pC4SoR/28wFu/G5JJhTnqEg== -axe-core@^4.0.2: - version "4.3.3" - resolved "https://registry.npmjs.org/axe-core/-/axe-core-4.3.3.tgz" - integrity sha512-/lqqLAmuIPi79WYfRpy2i8z+x+vxU3zX2uAm0gs1q52qTuKwolOj1P8XbufpXcsydrpKx2yGn2wzAnxCMV86QA== +axe-core@^4.4.3: + version "4.5.2" + resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.5.2.tgz#823fdf491ff717ac3c58a52631d4206930c1d9f7" + integrity sha512-u2MVsXfew5HBvjsczCv+xlwdNnB1oQR9HlAcsejZttNjKKSkeDNVwB1vMThIUIFI9GoT57Vtk8iQLwqOfAkboA== axios@^0.21.3: version "0.21.4" @@ -2037,45 +1181,7 @@ axobject-query@^2.2.0: resolved "https://registry.npmjs.org/axobject-query/-/axobject-query-2.2.0.tgz" integrity sha512-Td525n+iPOOyUQIeBfcASuG6uJsDOITl7Mds5gFyerkWiX7qhUTdYUBlSgNMyVqtSJqwpt1kXGLdUt6SykLMRA== -babel-extract-comments@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/babel-extract-comments/-/babel-extract-comments-1.0.0.tgz" - integrity sha512-qWWzi4TlddohA91bFwgt6zO/J0X+io7Qp184Fw0m2JYRSTZnJbFR8+07KmzudHCZgOiKRCrjhylwv9Xd8gfhVQ== - dependencies: - babylon "^6.18.0" - -babel-plugin-dynamic-import-node@^2.3.3: - version "2.3.3" - resolved "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz" - integrity sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ== - dependencies: - object.assign "^4.1.0" - -babel-plugin-polyfill-corejs2@^0.2.2: - version "0.2.2" - resolved "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.2.2.tgz" - integrity sha512-kISrENsJ0z5dNPq5eRvcctITNHYXWOA4DUZRFYCz3jYCcvTb/A546LIddmoGNMVYg2U38OyFeNosQwI9ENTqIQ== - dependencies: - "@babel/compat-data" "^7.13.11" - "@babel/helper-define-polyfill-provider" "^0.2.2" - semver "^6.1.1" - -babel-plugin-polyfill-corejs3@^0.2.2: - version "0.2.4" - resolved "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.2.4.tgz" - integrity sha512-z3HnJE5TY/j4EFEa/qpQMSbcUJZ5JQi+3UFjXzn6pQCmIKc5Ug5j98SuYyH+m4xQnvKlMDIW4plLfgyVnd0IcQ== - dependencies: - "@babel/helper-define-polyfill-provider" "^0.2.2" - core-js-compat "^3.14.0" - -babel-plugin-polyfill-regenerator@^0.2.2: - version "0.2.2" - resolved "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.2.2.tgz" - integrity sha512-Goy5ghsc21HgPDFtzRkSirpZVW35meGoTmTOb2bxqdl60ghub4xOidgNTHaZfQ2FaxQsKmwvXtOAkcIS4SMBWg== - dependencies: - "@babel/helper-define-polyfill-provider" "^0.2.2" - -"babel-plugin-styled-components@>= 1.12.0", babel-plugin-styled-components@^1.11.1: +"babel-plugin-styled-components@>= 1.12.0": version "1.13.2" resolved "https://registry.npmjs.org/babel-plugin-styled-components/-/babel-plugin-styled-components-1.13.2.tgz" integrity sha512-Vb1R3d4g+MUfPQPVDMCGjm3cDocJEUTR7Xq7QS95JWWeksN1wdFRYpD2kulDgI3Huuaf1CZd+NK4KQmqUFh5dA== @@ -2090,32 +1196,6 @@ babel-plugin-syntax-jsx@^6.18.0: resolved "https://registry.npmjs.org/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz" integrity sha1-CvMqmm4Tyno/1QaeYtew9Y0NiUY= -babel-plugin-syntax-object-rest-spread@^6.8.0: - version "6.13.0" - resolved "https://registry.npmjs.org/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz" - integrity sha1-/WU28rzhODb/o6VFjEkDpZe7O/U= - -babel-plugin-transform-object-rest-spread@^6.26.0: - version "6.26.0" - resolved "https://registry.npmjs.org/babel-plugin-transform-object-rest-spread/-/babel-plugin-transform-object-rest-spread-6.26.0.tgz" - integrity sha1-DzZpLVD+9rfi1LOsFHgTepY7ewY= - dependencies: - babel-plugin-syntax-object-rest-spread "^6.8.0" - babel-runtime "^6.26.0" - -babel-runtime@^6.26.0: - version "6.26.0" - resolved "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz" - integrity sha1-llxwWGaOgrVde/4E/yM3vItWR/4= - dependencies: - core-js "^2.4.0" - regenerator-runtime "^0.11.0" - -babylon@^6.18.0: - version "6.18.0" - resolved "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz" - integrity sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ== - balanced-match@^1.0.0: version "1.0.2" resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz" @@ -2189,17 +1269,6 @@ braces@^3.0.1: dependencies: fill-range "^7.0.1" -browserslist@^4.16.6, browserslist@^4.17.0: - version "4.17.0" - resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.17.0.tgz" - integrity sha512-g2BJ2a0nEYvEFQC208q8mVAhfNwpZ5Mu8BwgtCdZKO3qx98HChmeg448fPdUzld8aFmfLgVh7yymqV+q1lJZ5g== - dependencies: - caniuse-lite "^1.0.30001254" - colorette "^1.3.0" - electron-to-chromium "^1.3.830" - escalade "^3.1.1" - node-releases "^1.1.75" - bs58@^4.0.1: version "4.0.1" resolved "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz" @@ -2207,16 +1276,6 @@ bs58@^4.0.1: dependencies: base-x "^3.0.2" -buffer-from@^1.0.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" - integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== - -builtin-modules@^3.1.0: - version "3.2.0" - resolved "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.2.0.tgz" - integrity sha512-lGzLKcioL90C7wMczpkY0n/oART3MbBa8R9OFGE1rJxoVI86u4WAGfEk8Wjv10eKSyTHVGkSo3bvBylCEtk7LA== - bytes@3.1.0: version "3.1.0" resolved "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz" @@ -2240,15 +1299,10 @@ camelize@^1.0.0: resolved "https://registry.npmjs.org/camelize/-/camelize-1.0.0.tgz" integrity sha1-FkpUg+Yw+kMh5a8HAg5TGDGyYJs= -caniuse-lite@^1.0.30001254: - version "1.0.30001255" - resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001255.tgz" - integrity sha512-F+A3N9jTZL882f/fg/WWVnKSu6IOo3ueLz4zwaOPbPYHNmM/ZaDUyzyJwS1mZhX7Ex5jqTyW599Gdelh5PDYLQ== - -caniuse-lite@^1.0.30001283: - version "1.0.30001312" - resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001312.tgz" - integrity sha512-Wiz1Psk2MEK0pX3rUzWaunLTZzqS2JYZFzNKqAiJGiuxIjRPLgV6+VDPOg6lQOUxmDwhTlh198JsTTi8Hzw6aQ== +caniuse-lite@^1.0.30001406: + version "1.0.30001423" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001423.tgz#57176d460aa8cd85ee1a72016b961eb9aca55d91" + integrity sha512-09iwWGOlifvE1XuHokFMP7eR38a0JnajoyL3/i87c8ZjRWRrdKo1fqjNfugfBD0UDBIOz0U+jtNhJ0EPm1VleQ== chalk@^2.0.0, chalk@^2.4.1: version "2.4.2" @@ -2297,14 +1351,6 @@ clean-stack@^2.0.0: resolved "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz" integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A== -clean-webpack-plugin@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/clean-webpack-plugin/-/clean-webpack-plugin-3.0.0.tgz" - integrity sha512-MciirUH5r+cYLGCOL5JX/ZLzOZbVr1ot3Fw+KcvbhUb6PM+yycqd9ZhIlcigQ5gl+XhppNmw3bEFuaaMNyLj3A== - dependencies: - "@types/webpack" "^4.4.31" - del "^4.1.1" - cli-cursor@^3.1.0: version "3.1.0" resolved "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz" @@ -2354,7 +1400,7 @@ color-name@~1.1.4: resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== -colorette@^1.2.2, colorette@^1.3.0: +colorette@^1.2.2: version "1.4.0" resolved "https://registry.npmjs.org/colorette/-/colorette-1.4.0.tgz" integrity sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g== @@ -2364,7 +1410,7 @@ comlink@^4.3.0: resolved "https://registry.npmjs.org/comlink/-/comlink-4.3.1.tgz" integrity sha512-+YbhUdNrpBZggBAHWcgQMLPLH1KDF3wJpeqrCKieWQ8RL7atmgsgTQko1XEBK6PsecfopWNntopJ+ByYG1lRaA== -commander@^2.18.0, commander@^2.20.0: +commander@^2.18.0: version "2.20.3" resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== @@ -2374,21 +1420,11 @@ commander@^7.2.0: resolved "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz" integrity sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw== -common-tags@^1.8.0: - version "1.8.0" - resolved "https://registry.npmjs.org/common-tags/-/common-tags-1.8.0.tgz" - integrity sha512-6P6g0uetGpW/sdyUy/iQQCbFF0kWVMSIVSyYz7Zgjcgh8mgw8PQzDNZeyZ5DQ2gM7LBoZPHmnjz8rUthkBG5tw== - concat-map@0.0.1: version "0.0.1" resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz" integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= -confusing-browser-globals@^1.0.10: - version "1.0.10" - resolved "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.10.tgz" - integrity sha512-gNld/3lySHwuhaVluJUKLePYirM3QNCKzVxqAdhJII9/WXKVX5PURzMVJspS1jTslSqjeuG4KMVTSouit5YPHA== - console-control-strings@^1.0.0, console-control-strings@~1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz" @@ -2406,13 +1442,6 @@ content-type@~1.0.4: resolved "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz" integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== -convert-source-map@^1.7.0: - version "1.8.0" - resolved "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz" - integrity sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA== - dependencies: - safe-buffer "~5.1.1" - cookie-signature@1.0.6: version "1.0.6" resolved "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz" @@ -2428,24 +1457,11 @@ cookie@^0.4.1: resolved "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz" integrity sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA== -core-js-compat@^3.14.0, core-js-compat@^3.16.0: - version "3.17.3" - resolved "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.17.3.tgz" - integrity sha512-+in61CKYs4hQERiADCJsdgewpdl/X0GhEX77pjKgbeibXviIt2oxEjTc8O2fqHX8mDdBrDvX8MYD/RYsBv4OiA== - dependencies: - browserslist "^4.17.0" - semver "7.0.0" - core-js-pure@^3.16.0: version "3.17.3" resolved "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.17.3.tgz" integrity sha512-YusrqwiOTTn8058JDa0cv9unbXdIiIgcgI9gXso0ey4WgkFLd3lYlV9rp9n7nDCsYxXsMDTjA4m1h3T348mdlQ== -core-js@^2.4.0: - version "2.6.12" - resolved "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz" - integrity sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ== - core-util-is@~1.0.0: version "1.0.3" resolved "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz" @@ -2494,11 +1510,6 @@ cross-spawn@^7.0.2, cross-spawn@^7.0.3: shebang-command "^2.0.0" which "^2.0.1" -crypto-random-string@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-1.0.0.tgz" - integrity sha1-ojD2T1aDEOFJgAmUB5DsmVRbyn4= - css-color-keywords@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/css-color-keywords/-/css-color-keywords-1.0.0.tgz" @@ -2523,10 +1534,10 @@ csstype@^3.0.2: resolved "https://registry.npmjs.org/csstype/-/csstype-3.0.8.tgz" integrity sha512-jXKhWqXPmlUeoQnF/EhTtTl4C9SnrxSH/jZUih3jmO6lBKr99rP3/+FmrMj4EFpOXzMtXHAZkd3x0E6h6Fgflw== -damerau-levenshtein@^1.0.6: - version "1.0.7" - resolved "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.7.tgz" - integrity sha512-VvdQIPGdWP0SqFXghj79Wf/5LArmreyMsGLa6FG6iC4t3j7j5s71TrwWmT/4akbDQIqjfACkLZmjXhA7g2oUZw== +damerau-levenshtein@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz#b43d286ccbd36bc5b2f7ed41caf2d0aba1f8a6e7" + integrity sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA== date-fns@^2.0.1: version "2.25.0" @@ -2550,7 +1561,7 @@ debug@2.6.9, debug@^2.6.9: dependencies: ms "2.0.0" -debug@4, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1: +debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1: version "4.3.2" resolved "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz" integrity sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw== @@ -2564,6 +1575,13 @@ debug@^3.2.7: dependencies: ms "^2.1.1" +debug@^4.3.2, debug@^4.3.4: + version "4.3.4" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== + dependencies: + ms "2.1.2" + deep-is@^0.1.3: version "0.1.4" resolved "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz" @@ -2574,6 +1592,11 @@ deepmerge@^2.1.1: resolved "https://registry.npmjs.org/deepmerge/-/deepmerge-2.2.1.tgz" integrity sha512-R9hc1Xa/NOBi9WRVUWg19rl1UB7Tt4kuPd+thNJgFZoxXsTz7ncaPaeIm+40oSGuP33DfMb4sZt1QIGiJzC4EA== +define-lazy-prop@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz#3f7ae421129bcaaac9bc74905c98a0009ec9ee7f" + integrity sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og== + define-properties@^1.1.3: version "1.1.3" resolved "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz" @@ -2581,18 +1604,13 @@ define-properties@^1.1.3: dependencies: object-keys "^1.0.12" -del@^4.1.1: - version "4.1.1" - resolved "https://registry.npmjs.org/del/-/del-4.1.1.tgz" - integrity sha512-QwGuEUouP2kVwQenAsOof5Fv8K9t3D8Ca8NxcXKrIpEHjTXK5J2nXLdP+ALI1cgv8wj7KuwBhTwBkOZSJKM5XQ== +define-properties@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.4.tgz#0b14d7bd7fbeb2f3572c3a7eda80ea5d57fb05b1" + integrity sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA== dependencies: - "@types/glob" "^7.1.1" - globby "^6.1.0" - is-path-cwd "^2.0.0" - is-path-in-cwd "^2.0.0" - p-map "^2.0.0" - pify "^4.0.1" - rimraf "^2.6.3" + has-property-descriptors "^1.0.0" + object-keys "^1.1.1" delegates@^1.0.0: version "1.0.0" @@ -2658,19 +1676,14 @@ ejs@^2.6.1: resolved "https://registry.npmjs.org/ejs/-/ejs-2.7.4.tgz" integrity sha512-7vmuyh5+kuUyJKePhQfRQBhXV5Ce+RnaeeQArKu1EAMpL3WbgMt5WG6uQZpEVvYSSsxMXRKOewtDk9RaTKXRlA== -electron-to-chromium@^1.3.830: - version "1.3.835" - resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.835.tgz" - integrity sha512-rHQszGg2KLMqOWPNTpwCnlp7Kb85haJa8j089DJCreZueykoSN/in+EMlay3SSDMNKR4VGPvfskxofHV18xVJg== - emoji-regex@^8.0.0: version "8.0.0" resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz" integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== -emoji-regex@^9.0.0: +emoji-regex@^9.2.2: version "9.2.2" - resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72" integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg== encodeurl@~1.0.2: @@ -2678,6 +1691,14 @@ encodeurl@~1.0.2: resolved "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz" integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k= +enhanced-resolve@^5.10.0: + version "5.10.0" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.10.0.tgz#0dc579c3bb2a1032e357ac45b8f3a6f3ad4fb1e6" + integrity sha512-T0yTFjdpldGY8PmuXXR0PyQ1ufZpEGiHVrp7zHKB7jdR4qlmZHhONVM5AQOAWXuF/w3dnHbEQVrNptJgt7F+cQ== + dependencies: + graceful-fs "^4.2.4" + tapable "^2.2.0" + enhanced-resolve@^5.7.0: version "5.9.3" resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.9.3.tgz#44a342c012cbc473254af5cc6ae20ebd0aae5d88" @@ -2686,7 +1707,7 @@ enhanced-resolve@^5.7.0: graceful-fs "^4.2.4" tapable "^2.2.0" -enquirer@^2.3.5, enquirer@^2.3.6: +enquirer@^2.3.6: version "2.3.6" resolved "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz" integrity sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg== @@ -2700,7 +1721,7 @@ error-ex@^1.3.1: dependencies: is-arrayish "^0.2.1" -es-abstract@^1.18.0-next.1, es-abstract@^1.18.0-next.2, es-abstract@^1.18.2: +es-abstract@^1.18.0-next.2: version "1.19.1" resolved "https://registry.npmjs.org/es-abstract/-/es-abstract-1.19.1.tgz" integrity sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w== @@ -2726,6 +1747,43 @@ es-abstract@^1.18.0-next.1, es-abstract@^1.18.0-next.2, es-abstract@^1.18.2: string.prototype.trimstart "^1.0.4" unbox-primitive "^1.0.1" +es-abstract@^1.19.0, es-abstract@^1.20.4: + version "1.20.4" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.20.4.tgz#1d103f9f8d78d4cf0713edcd6d0ed1a46eed5861" + integrity sha512-0UtvRN79eMe2L+UNEF1BwRe364sj/DXhQ/k5FmivgoSdpM90b8Jc0mDzKMGo7QS0BVbOP/bTwBKNnDc9rNzaPA== + dependencies: + call-bind "^1.0.2" + es-to-primitive "^1.2.1" + function-bind "^1.1.1" + function.prototype.name "^1.1.5" + get-intrinsic "^1.1.3" + get-symbol-description "^1.0.0" + has "^1.0.3" + has-property-descriptors "^1.0.0" + has-symbols "^1.0.3" + internal-slot "^1.0.3" + is-callable "^1.2.7" + is-negative-zero "^2.0.2" + is-regex "^1.1.4" + is-shared-array-buffer "^1.0.2" + is-string "^1.0.7" + is-weakref "^1.0.2" + object-inspect "^1.12.2" + object-keys "^1.1.1" + object.assign "^4.1.4" + regexp.prototype.flags "^1.4.3" + safe-regex-test "^1.0.0" + string.prototype.trimend "^1.0.5" + string.prototype.trimstart "^1.0.5" + unbox-primitive "^1.0.2" + +es-shim-unscopables@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz#702e632193201e3edf8713635d083d378e510241" + integrity sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w== + dependencies: + has "^1.0.3" + es-to-primitive@^1.2.1: version "1.2.1" resolved "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz" @@ -2755,33 +1813,25 @@ escape-string-regexp@^4.0.0: resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz" integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== -eslint-config-airbnb-base@^14.2.1: - version "14.2.1" - resolved "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-14.2.1.tgz" - integrity sha512-GOrQyDtVEc1Xy20U7vsB2yAoB4nBlfH5HZJeatRXHleO+OS5Ot+MWij4Dpltw4/DyIkqUfqz1epfhVR5XWWQPA== +eslint-config-next@^13.0.4: + version "13.0.4" + resolved "https://registry.yarnpkg.com/eslint-config-next/-/eslint-config-next-13.0.4.tgz#78954caf26b3aa718bed077bce90c1f505db0005" + integrity sha512-moEC7BW2TK7JKq3QfnaauqRjWzVcEf71gp5DbClpFPHM6QXE0u0uVvSTiHlmOgtCe1vyWAO+AhF87ZITd8mIDw== dependencies: - confusing-browser-globals "^1.0.10" - object.assign "^4.1.2" - object.entries "^1.1.2" + "@next/eslint-plugin-next" "13.0.4" + "@rushstack/eslint-patch" "^1.1.3" + "@typescript-eslint/parser" "^5.42.0" + eslint-import-resolver-node "^0.3.6" + eslint-import-resolver-typescript "^3.5.2" + eslint-plugin-import "^2.26.0" + eslint-plugin-jsx-a11y "^6.5.1" + eslint-plugin-react "^7.31.7" + eslint-plugin-react-hooks "^4.5.0" -eslint-config-airbnb@^18.2.1: - version "18.2.1" - resolved "https://registry.npmjs.org/eslint-config-airbnb/-/eslint-config-airbnb-18.2.1.tgz" - integrity sha512-glZNDEZ36VdlZWoxn/bUR1r/sdFKPd1mHPbqUtkctgNG4yT2DLLtJ3D+yCV+jzZCc2V1nBVkmdknOJBZ5Hc0fg== - dependencies: - eslint-config-airbnb-base "^14.2.1" - object.assign "^4.1.2" - object.entries "^1.1.2" - -eslint-config-google@^0.14.0: - version "0.14.0" - resolved "https://registry.npmjs.org/eslint-config-google/-/eslint-config-google-0.14.0.tgz" - integrity sha512-WsbX4WbjuMvTdeVL6+J3rK1RGhCTqjsFjX7UMSMgZiyxxaNLkoJENbrGExzERFeoTpGw3F3FypTiWAP9ZXzkEw== - -eslint-config-prettier@^8.3.0: - version "8.3.0" - resolved "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.3.0.tgz" - integrity sha512-BgZuLUSeKzvlL/VUjx/Yb787VQ26RU3gGjA3iiFvdsp/2bMfVIWUVP7tjxtjS0e+HP409cPlPvNkQloz8C91ew== +eslint-config-prettier@^8.5.0: + version "8.5.0" + resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-8.5.0.tgz#5a81680ec934beca02c7b1a61cf8ca34b66feab1" + integrity sha512-obmWKLUNCnhtQRKc+tmnYuQl0pFU1ibYJQ5BGhTVB08bHe9wC8qUeG7c08dj9XX+AuPj1YSGSQIHl1pnDHZR0Q== eslint-import-resolver-node@^0.3.6: version "0.3.6" @@ -2791,75 +1841,89 @@ eslint-import-resolver-node@^0.3.6: debug "^3.2.7" resolve "^1.20.0" -eslint-module-utils@^2.6.2: - version "2.6.2" - resolved "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.6.2.tgz" - integrity sha512-QG8pcgThYOuqxupd06oYTZoNOGaUdTY1PqK+oS6ElF6vs4pBdk/aYxFVQQXzcrAqp9m7cl7lb2ubazX+g16k2Q== +eslint-import-resolver-typescript@^3.5.2: + version "3.5.2" + resolved "https://registry.yarnpkg.com/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.5.2.tgz#9431acded7d898fd94591a08ea9eec3514c7de91" + integrity sha512-zX4ebnnyXiykjhcBvKIf5TNvt8K7yX6bllTRZ14MiurKPjDpCAZujlszTdB8pcNXhZcOf+god4s9SjQa5GnytQ== + dependencies: + debug "^4.3.4" + enhanced-resolve "^5.10.0" + get-tsconfig "^4.2.0" + globby "^13.1.2" + is-core-module "^2.10.0" + is-glob "^4.0.3" + synckit "^0.8.4" + +eslint-module-utils@^2.7.3: + version "2.7.4" + resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.7.4.tgz#4f3e41116aaf13a20792261e61d3a2e7e0583974" + integrity sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA== dependencies: debug "^3.2.7" - pkg-dir "^2.0.0" -eslint-plugin-import@^2.23.3: - version "2.24.2" - resolved "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.24.2.tgz" - integrity sha512-hNVtyhiEtZmpsabL4neEj+6M5DCLgpYyG9nzJY8lZQeQXEn5UPW1DpUdsMHMXsq98dbNm7nt1w9ZMSVpfJdi8Q== +eslint-plugin-import@^2.26.0: + version "2.26.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.26.0.tgz#f812dc47be4f2b72b478a021605a59fc6fe8b88b" + integrity sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA== dependencies: - array-includes "^3.1.3" - array.prototype.flat "^1.2.4" + array-includes "^3.1.4" + array.prototype.flat "^1.2.5" debug "^2.6.9" doctrine "^2.1.0" eslint-import-resolver-node "^0.3.6" - eslint-module-utils "^2.6.2" - find-up "^2.0.0" + eslint-module-utils "^2.7.3" has "^1.0.3" - is-core-module "^2.6.0" - minimatch "^3.0.4" - object.values "^1.1.4" - pkg-up "^2.0.0" - read-pkg-up "^3.0.0" - resolve "^1.20.0" - tsconfig-paths "^3.11.0" + is-core-module "^2.8.1" + is-glob "^4.0.3" + minimatch "^3.1.2" + object.values "^1.1.5" + resolve "^1.22.0" + tsconfig-paths "^3.14.1" -eslint-plugin-jsx-a11y@^6.4.1: - version "6.4.1" - resolved "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.4.1.tgz" - integrity sha512-0rGPJBbwHoGNPU73/QCLP/vveMlM1b1Z9PponxO87jfr6tuH5ligXbDT6nHSSzBC8ovX2Z+BQu7Bk5D/Xgq9zg== +eslint-plugin-jsx-a11y@^6.5.1: + version "6.6.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.6.1.tgz#93736fc91b83fdc38cc8d115deedfc3091aef1ff" + integrity sha512-sXgFVNHiWffBq23uiS/JaP6eVR622DqwB4yTzKvGZGcPq6/yZ3WmOZfuBks/vHWo9GaFOqC2ZK4i6+C35knx7Q== dependencies: - "@babel/runtime" "^7.11.2" + "@babel/runtime" "^7.18.9" aria-query "^4.2.2" - array-includes "^3.1.1" + array-includes "^3.1.5" ast-types-flow "^0.0.7" - axe-core "^4.0.2" + axe-core "^4.4.3" axobject-query "^2.2.0" - damerau-levenshtein "^1.0.6" - emoji-regex "^9.0.0" + damerau-levenshtein "^1.0.8" + emoji-regex "^9.2.2" has "^1.0.3" - jsx-ast-utils "^3.1.0" + jsx-ast-utils "^3.3.2" language-tags "^1.0.5" + minimatch "^3.1.2" + semver "^6.3.0" -eslint-plugin-react-hooks@^4.2.0: - version "4.2.0" - resolved "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.2.0.tgz" - integrity sha512-623WEiZJqxR7VdxFCKLI6d6LLpwJkGPYKODnkH3D7WpOG5KM8yWueBd8TLsNAetEJNF5iJmolaAKO3F8yzyVBQ== +eslint-plugin-react-hooks@^4.5.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz#4c3e697ad95b77e93f8646aaa1630c1ba607edd3" + integrity sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g== -eslint-plugin-react@^7.23.2: - version "7.25.1" - resolved "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.25.1.tgz" - integrity sha512-P4j9K1dHoFXxDNP05AtixcJEvIT6ht8FhYKsrkY0MPCPaUMYijhpWwNiRDZVtA8KFuZOkGSeft6QwH8KuVpJug== +eslint-plugin-react@^7.31.7: + version "7.31.11" + resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.31.11.tgz#011521d2b16dcf95795df688a4770b4eaab364c8" + integrity sha512-TTvq5JsT5v56wPa9OYHzsrOlHzKZKjV+aLgS+55NJP/cuzdiQPC7PfYoUjMoxlffKtvijpk7vA/jmuqRb9nohw== dependencies: - array-includes "^3.1.3" - array.prototype.flatmap "^1.2.4" + array-includes "^3.1.6" + array.prototype.flatmap "^1.3.1" + array.prototype.tosorted "^1.1.1" doctrine "^2.1.0" - estraverse "^5.2.0" - has "^1.0.3" + estraverse "^5.3.0" jsx-ast-utils "^2.4.1 || ^3.0.0" - minimatch "^3.0.4" - object.entries "^1.1.4" - object.fromentries "^2.0.4" - object.values "^1.1.4" - prop-types "^15.7.2" + minimatch "^3.1.2" + object.entries "^1.1.6" + object.fromentries "^2.0.6" + object.hasown "^1.1.2" + object.values "^1.1.6" + prop-types "^15.8.1" resolve "^2.0.0-next.3" - string.prototype.matchall "^4.0.5" + semver "^6.3.0" + string.prototype.matchall "^4.0.8" eslint-scope@^5.1.1: version "5.1.1" @@ -2869,12 +1933,13 @@ eslint-scope@^5.1.1: esrecurse "^4.3.0" estraverse "^4.1.1" -eslint-utils@^2.1.0: - version "2.1.0" - resolved "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz" - integrity sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg== +eslint-scope@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.1.1.tgz#fff34894c2f65e5226d3041ac480b4513a163642" + integrity sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw== dependencies: - eslint-visitor-keys "^1.1.0" + esrecurse "^4.3.0" + estraverse "^5.2.0" eslint-utils@^3.0.0: version "3.0.0" @@ -2883,75 +1948,69 @@ eslint-utils@^3.0.0: dependencies: eslint-visitor-keys "^2.0.0" -eslint-visitor-keys@^1.1.0, eslint-visitor-keys@^1.3.0: - version "1.3.0" - resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz" - integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ== - eslint-visitor-keys@^2.0.0: version "2.1.0" resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz" integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw== -eslint@^7.27.0: - version "7.32.0" - resolved "https://registry.npmjs.org/eslint/-/eslint-7.32.0.tgz" - integrity sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA== +eslint-visitor-keys@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz#f6480fa6b1f30efe2d1968aa8ac745b862469826" + integrity sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA== + +eslint@^8.28.0: + version "8.28.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.28.0.tgz#81a680732634677cc890134bcdd9fdfea8e63d6e" + integrity sha512-S27Di+EVyMxcHiwDrFzk8dJYAaD+/5SoWKxL1ri/71CRHsnJnRDPNt2Kzj24+MT9FDupf4aqqyqPrvI8MvQ4VQ== dependencies: - "@babel/code-frame" "7.12.11" - "@eslint/eslintrc" "^0.4.3" - "@humanwhocodes/config-array" "^0.5.0" + "@eslint/eslintrc" "^1.3.3" + "@humanwhocodes/config-array" "^0.11.6" + "@humanwhocodes/module-importer" "^1.0.1" + "@nodelib/fs.walk" "^1.2.8" ajv "^6.10.0" chalk "^4.0.0" cross-spawn "^7.0.2" - debug "^4.0.1" + debug "^4.3.2" doctrine "^3.0.0" - enquirer "^2.3.5" escape-string-regexp "^4.0.0" - eslint-scope "^5.1.1" - eslint-utils "^2.1.0" - eslint-visitor-keys "^2.0.0" - espree "^7.3.1" + eslint-scope "^7.1.1" + eslint-utils "^3.0.0" + eslint-visitor-keys "^3.3.0" + espree "^9.4.0" esquery "^1.4.0" esutils "^2.0.2" fast-deep-equal "^3.1.3" file-entry-cache "^6.0.1" - functional-red-black-tree "^1.0.1" - glob-parent "^5.1.2" - globals "^13.6.0" - ignore "^4.0.6" + find-up "^5.0.0" + glob-parent "^6.0.2" + globals "^13.15.0" + grapheme-splitter "^1.0.4" + ignore "^5.2.0" import-fresh "^3.0.0" imurmurhash "^0.1.4" is-glob "^4.0.0" - js-yaml "^3.13.1" + is-path-inside "^3.0.3" + js-sdsl "^4.1.4" + js-yaml "^4.1.0" json-stable-stringify-without-jsonify "^1.0.1" levn "^0.4.1" lodash.merge "^4.6.2" - minimatch "^3.0.4" + minimatch "^3.1.2" natural-compare "^1.4.0" optionator "^0.9.1" - progress "^2.0.0" - regexpp "^3.1.0" - semver "^7.2.1" - strip-ansi "^6.0.0" + regexpp "^3.2.0" + strip-ansi "^6.0.1" strip-json-comments "^3.1.0" - table "^6.0.9" text-table "^0.2.0" - v8-compile-cache "^2.0.3" -espree@^7.3.0, espree@^7.3.1: - version "7.3.1" - resolved "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz" - integrity sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g== +espree@^9.4.0: + version "9.4.1" + resolved "https://registry.yarnpkg.com/espree/-/espree-9.4.1.tgz#51d6092615567a2c2cff7833445e37c28c0065bd" + integrity sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg== dependencies: - acorn "^7.4.0" - acorn-jsx "^5.3.1" - eslint-visitor-keys "^1.3.0" - -esprima@^4.0.0: - version "4.0.1" - resolved "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz" - integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== + acorn "^8.8.0" + acorn-jsx "^5.3.2" + eslint-visitor-keys "^3.3.0" esquery@^1.4.0: version "1.4.0" @@ -2977,15 +2036,10 @@ estraverse@^5.1.0, estraverse@^5.2.0: resolved "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz" integrity sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ== -estree-walker@^0.6.1: - version "0.6.1" - resolved "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.1.tgz" - integrity sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w== - -estree-walker@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz" - integrity sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg== +estraverse@^5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" + integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== esutils@^2.0.2: version "2.0.3" @@ -3058,10 +2112,10 @@ fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: resolved "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz" integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== -fast-glob@^3.1.1: - version "3.2.7" - resolved "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.7.tgz" - integrity sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q== +fast-glob@^3.2.11, fast-glob@^3.2.9: + version "3.2.12" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.12.tgz#7f39ec99c2e6ab030337142da9e0c18f37afae80" + integrity sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w== dependencies: "@nodelib/fs.stat" "^2.0.2" "@nodelib/fs.walk" "^1.2.3" @@ -3069,7 +2123,7 @@ fast-glob@^3.1.1: merge2 "^1.3.0" micromatch "^4.0.4" -fast-json-stable-stringify@^2.0.0, fast-json-stable-stringify@^2.1.0: +fast-json-stable-stringify@^2.0.0: version "2.1.0" resolved "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz" integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== @@ -3141,12 +2195,13 @@ finalhandler@~1.1.2: statuses "~1.5.0" unpipe "~1.0.0" -find-up@^2.0.0, find-up@^2.1.0: - version "2.1.0" - resolved "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz" - integrity sha1-RdG35QbHF93UgndaK3eSCjwMV6c= +find-up@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" + integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== dependencies: - locate-path "^2.0.0" + locate-path "^6.0.0" + path-exists "^4.0.0" flat-cache@^3.0.4: version "3.0.4" @@ -3194,15 +2249,6 @@ fresh@0.5.2: resolved "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz" integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac= -fs-extra@^8.1.0: - version "8.1.0" - resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz" - integrity sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g== - dependencies: - graceful-fs "^4.2.0" - jsonfile "^4.0.0" - universalify "^0.1.0" - fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz" @@ -3213,10 +2259,20 @@ function-bind@^1.1.1: resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz" integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== -functional-red-black-tree@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz" - integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= +function.prototype.name@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.5.tgz#cce0505fe1ffb80503e6f9e46cc64e46a12a9621" + integrity sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + es-abstract "^1.19.0" + functions-have-names "^1.2.2" + +functions-have-names@^1.2.2: + version "1.2.3" + resolved "https://registry.yarnpkg.com/functions-have-names/-/functions-have-names-1.2.3.tgz#0404fe4ee2ba2f607f0e0ec3c80bae994133b834" + integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ== gauge@~2.7.3: version "2.7.4" @@ -3232,11 +2288,6 @@ gauge@~2.7.3: strip-ansi "^3.0.1" wide-align "^1.1.0" -gensync@^1.0.0-beta.2: - version "1.0.0-beta.2" - resolved "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz" - integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== - get-intrinsic@^1.0.2, get-intrinsic@^1.1.0, get-intrinsic@^1.1.1: version "1.1.1" resolved "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz" @@ -3246,6 +2297,15 @@ get-intrinsic@^1.0.2, get-intrinsic@^1.1.0, get-intrinsic@^1.1.1: has "^1.0.3" has-symbols "^1.0.1" +get-intrinsic@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.3.tgz#063c84329ad93e83893c7f4f243ef63ffa351385" + integrity sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A== + dependencies: + function-bind "^1.1.1" + has "^1.0.3" + has-symbols "^1.0.3" + get-own-enumerable-property-symbols@^3.0.0: version "3.0.2" resolved "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz" @@ -3264,6 +2324,11 @@ get-symbol-description@^1.0.0: call-bind "^1.0.2" get-intrinsic "^1.1.1" +get-tsconfig@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/get-tsconfig/-/get-tsconfig-4.2.0.tgz#ff368dd7104dab47bf923404eb93838245c66543" + integrity sha512-X8u8fREiYOE6S8hLbq99PeykTDoLVnxvF4DjWKJmz9xy2nNRdUcV8ZN9tniJFeKyTU3qnC9lL8n4Chd6LmVKHg== + glob-parent@^5.1.2: version "5.1.2" resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz" @@ -3271,7 +2336,14 @@ glob-parent@^5.1.2: dependencies: is-glob "^4.0.1" -glob@^7.0.3, glob@^7.1.3, glob@^7.1.6: +glob-parent@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3" + integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== + dependencies: + is-glob "^4.0.3" + +glob@7.1.7, glob@^7.1.3: version "7.1.7" resolved "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz" integrity sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ== @@ -3288,46 +2360,56 @@ globals@^11.1.0: resolved "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz" integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== -globals@^13.6.0, globals@^13.9.0: - version "13.11.0" - resolved "https://registry.npmjs.org/globals/-/globals-13.11.0.tgz" - integrity sha512-08/xrJ7wQjK9kkkRoI3OFUBbLx4f+6x3SGwcPvQ0QH6goFDrOU2oyAWrmh3dJezu65buo+HBMzAMQy6rovVC3g== +globals@^13.15.0: + version "13.18.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-13.18.0.tgz#fb224daeeb2bb7d254cd2c640f003528b8d0c1dc" + integrity sha512-/mR4KI8Ps2spmoc0Ulu9L7agOF0du1CZNQ3dke8yItYlyKNmGrkONemBbd6V8UTc1Wgcqn21t3WYB7dbRmh6/A== dependencies: type-fest "^0.20.2" -globby@^11.0.3: - version "11.0.4" - resolved "https://registry.npmjs.org/globby/-/globby-11.0.4.tgz" - integrity sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg== +globalyzer@0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/globalyzer/-/globalyzer-0.1.0.tgz#cb76da79555669a1519d5a8edf093afaa0bf1465" + integrity sha512-40oNTM9UfG6aBmuKxk/giHn5nQ8RVz/SS4Ir6zgzOv9/qC3kKZ9v4etGTcJbEl/NyVQH7FGU7d+X1egr57Md2Q== + +globby@^11.1.0: + version "11.1.0" + resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" + integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== dependencies: array-union "^2.1.0" dir-glob "^3.0.1" - fast-glob "^3.1.1" - ignore "^5.1.4" - merge2 "^1.3.0" + fast-glob "^3.2.9" + ignore "^5.2.0" + merge2 "^1.4.1" slash "^3.0.0" -globby@^6.1.0: - version "6.1.0" - resolved "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz" - integrity sha1-9abXDoOV4hyFj7BInWTfAkJNUGw= +globby@^13.1.2: + version "13.1.2" + resolved "https://registry.yarnpkg.com/globby/-/globby-13.1.2.tgz#29047105582427ab6eca4f905200667b056da515" + integrity sha512-LKSDZXToac40u8Q1PQtZihbNdTYSNMuWe+K5l+oa6KgDzSvVrHXlJy40hUP522RjAIoNLJYBJi7ow+rbFpIhHQ== dependencies: - array-union "^1.0.1" - glob "^7.0.3" - object-assign "^4.0.1" - pify "^2.0.0" - pinkie-promise "^2.0.0" + dir-glob "^3.0.1" + fast-glob "^3.2.11" + ignore "^5.2.0" + merge2 "^1.4.1" + slash "^4.0.0" -graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0: - version "4.2.8" - resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz" - integrity sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg== +globrex@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/globrex/-/globrex-0.1.2.tgz#dd5d9ec826232730cd6793a5e33a9302985e6098" + integrity sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg== graceful-fs@^4.2.4: version "4.2.10" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c" integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA== +grapheme-splitter@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz#9cf3a665c6247479896834af35cf1dbb4400767e" + integrity sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ== + gzip-size@^5.0.0: version "5.1.1" resolved "https://registry.npmjs.org/gzip-size/-/gzip-size-5.1.1.tgz" @@ -3341,6 +2423,11 @@ has-bigints@^1.0.1: resolved "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz" integrity sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA== +has-bigints@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.2.tgz#0871bd3e3d51626f6ca0966668ba35d5602d6eaa" + integrity sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ== + has-flag@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz" @@ -3351,11 +2438,23 @@ has-flag@^4.0.0: resolved "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz" integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== +has-property-descriptors@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz#610708600606d36961ed04c196193b6a607fa861" + integrity sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ== + dependencies: + get-intrinsic "^1.1.1" + has-symbols@^1.0.1, has-symbols@^1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz" integrity sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw== +has-symbols@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" + integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== + has-tostringtag@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz" @@ -3412,11 +2511,6 @@ hoopy@^0.1.4: resolved "https://registry.npmjs.org/hoopy/-/hoopy-0.1.4.tgz" integrity sha512-HRcs+2mr52W0K+x8RzcLzuPPmVIKMSv97RGHy0Ea9y/mpcaK+xTrjICA04KAHi4GRzxliNqNJEFYWHghy3rSfQ== -hosted-git-info@^2.1.4: - version "2.8.9" - resolved "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz" - integrity sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw== - http-errors@1.7.2: version "1.7.2" resolved "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz" @@ -3464,25 +2558,15 @@ iconv-lite@0.4.24: dependencies: safer-buffer ">= 2.1.2 < 3" -idb@^6.0.0: - version "6.1.3" - resolved "https://registry.npmjs.org/idb/-/idb-6.1.3.tgz" - integrity sha512-oIRDpVcs5KXpI1hRnTJUwkY63RB/7iqu9nSNuzXN8TLHjs7oO20IoPFbBTsqxIL5IjzIUDi+FXlVcK4zm26J8A== - ieee754@^1.2.1: version "1.2.1" resolved "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz" integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== -ignore@^4.0.6: - version "4.0.6" - resolved "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz" - integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== - -ignore@^5.1.4: - version "5.1.8" - resolved "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz" - integrity sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw== +ignore@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.0.tgz#6d3bac8fa7fe0d45d9f9be7bac2fc279577e345a" + integrity sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ== immediate@~3.0.5: version "3.0.6" @@ -3571,7 +2655,19 @@ is-callable@^1.1.4, is-callable@^1.2.4: resolved "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz" integrity sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w== -is-core-module@^2.2.0, is-core-module@^2.6.0: +is-callable@^1.2.7: + version "1.2.7" + resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055" + integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA== + +is-core-module@^2.10.0, is-core-module@^2.8.1, is-core-module@^2.9.0: + version "2.11.0" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.11.0.tgz#ad4cb3e3863e814523c96f3f58d26cc570ff0144" + integrity sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw== + dependencies: + has "^1.0.3" + +is-core-module@^2.2.0: version "2.6.0" resolved "https://registry.npmjs.org/is-core-module/-/is-core-module-2.6.0.tgz" integrity sha512-wShG8vs60jKfPWpF2KZRaAtvt3a20OAn7+IJ6hLPECpSABLcKtFKTTI4ZtH5QcBruBHlq+WsdHWyz0BCZW7svQ== @@ -3585,6 +2681,11 @@ is-date-object@^1.0.1: dependencies: has-tostringtag "^1.0.0" +is-docker@^2.0.0, is-docker@^2.1.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa" + integrity sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ== + is-electron@^2.2.0: version "2.2.0" resolved "https://registry.npmjs.org/is-electron/-/is-electron-2.2.0.tgz" @@ -3619,19 +2720,14 @@ is-glob@^4.0.0: dependencies: is-extglob "^2.1.1" -is-glob@^4.0.1: +is-glob@^4.0.1, is-glob@^4.0.3: version "4.0.3" resolved "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz" integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== dependencies: is-extglob "^2.1.1" -is-module@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz" - integrity sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE= - -is-negative-zero@^2.0.1: +is-negative-zero@^2.0.1, is-negative-zero@^2.0.2: version "2.0.2" resolved "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz" integrity sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA== @@ -3653,24 +2749,10 @@ is-obj@^1.0.1: resolved "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz" integrity sha1-PkcprB9f3gJc19g6iW2rn09n2w8= -is-path-cwd@^2.0.0: - version "2.2.0" - resolved "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz" - integrity sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ== - -is-path-in-cwd@^2.0.0: - version "2.1.0" - resolved "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-2.1.0.tgz" - integrity sha512-rNocXHgipO+rvnP6dk3zI20RpOtrAM/kzbB258Uw5BWr3TpXi861yzjo16Dn4hUox07iw5AyeMLHWsujkjzvRQ== - dependencies: - is-path-inside "^2.1.0" - -is-path-inside@^2.1.0: - version "2.1.0" - resolved "https://registry.npmjs.org/is-path-inside/-/is-path-inside-2.1.0.tgz" - integrity sha512-wiyhTzfDWsvwAW53OBWF5zuvaOGlZ6PwYxAbPVDhpm+gM09xKQGjBq/8uYN12aDvMxnAnq3dxTyoSoRNmg5YFg== - dependencies: - path-is-inside "^1.0.2" +is-path-inside@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" + integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== is-regex@^1.1.4: version "1.1.4" @@ -3690,6 +2772,13 @@ is-shared-array-buffer@^1.0.1: resolved "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz" integrity sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA== +is-shared-array-buffer@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz#8f259c573b60b6a32d4058a1a07430c0a7344c79" + integrity sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA== + dependencies: + call-bind "^1.0.2" + is-stream@^2.0.0: version "2.0.1" resolved "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz" @@ -3719,13 +2808,20 @@ is-url@^1.2.4: resolved "https://registry.yarnpkg.com/is-url/-/is-url-1.2.4.tgz#04a4df46d28c4cff3d73d01ff06abeb318a1aa52" integrity sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww== -is-weakref@^1.0.1: +is-weakref@^1.0.1, is-weakref@^1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz" integrity sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ== dependencies: call-bind "^1.0.2" +is-wsl@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271" + integrity sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww== + dependencies: + is-docker "^2.0.0" + isarray@~1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz" @@ -3736,47 +2832,33 @@ isexe@^2.0.0: resolved "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz" integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= -jest-worker@^24.9.0: - version "24.9.0" - resolved "https://registry.npmjs.org/jest-worker/-/jest-worker-24.9.0.tgz" - integrity sha512-51PE4haMSXcHohnSMdM42anbvZANYTqMrr52tVKPqqsPJMzoP6FYYDVqahX/HrAoKEKz3uUPzSvKs9A3qR4iVw== - dependencies: - merge-stream "^2.0.0" - supports-color "^6.1.0" - jpeg-js@^0.4.1: version "0.4.4" resolved "https://registry.yarnpkg.com/jpeg-js/-/jpeg-js-0.4.4.tgz#a9f1c6f1f9f0fa80cdb3484ed9635054d28936aa" integrity sha512-WZzeDOEtTOBK4Mdsar0IqEU5sMr3vSV2RqkAIzUEV2BHnUfKGyswWFPFwK5EeDo93K3FohSHbLAjj0s1Wzd+dg== +js-sdsl@^4.1.4: + version "4.1.5" + resolved "https://registry.yarnpkg.com/js-sdsl/-/js-sdsl-4.1.5.tgz#1ff1645e6b4d1b028cd3f862db88c9d887f26e2a" + integrity sha512-08bOAKweV2NUC1wqTtf3qZlnpOX/R2DU9ikpjOHs0H+ibQv3zpncVQg6um4uYtRtrwIX8M4Nh3ytK4HGlYAq7Q== + "js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz" integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== -js-yaml@^3.13.1: - version "3.14.1" - resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz" - integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== +js-yaml@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" + integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== dependencies: - argparse "^1.0.7" - esprima "^4.0.0" + argparse "^2.0.1" jsesc@^2.5.1: version "2.5.2" resolved "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz" integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== -jsesc@~0.5.0: - version "0.5.0" - resolved "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz" - integrity sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0= - -json-parse-better-errors@^1.0.1: - version "1.0.2" - resolved "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz" - integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw== - json-parse-even-better-errors@^2.3.0: version "2.3.1" resolved "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz" @@ -3787,11 +2869,6 @@ json-schema-traverse@^0.4.1: resolved "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz" integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== -json-schema-traverse@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz" - integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== - json-stable-stringify-without-jsonify@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz" @@ -3804,21 +2881,7 @@ json5@^1.0.1: dependencies: minimist "^1.2.0" -json5@^2.1.2: - version "2.2.0" - resolved "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz" - integrity sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA== - dependencies: - minimist "^1.2.5" - -jsonfile@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz" - integrity sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss= - optionalDependencies: - graceful-fs "^4.1.6" - -"jsx-ast-utils@^2.4.1 || ^3.0.0", jsx-ast-utils@^3.1.0: +"jsx-ast-utils@^2.4.1 || ^3.0.0": version "3.2.0" resolved "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.2.0.tgz" integrity sha512-EIsmt3O3ljsU6sot/J4E1zDRxfBNrhjyf/OKjlydwgEimQuznlM4Wv7U+ueONJMyEn1WRE0K8dhi3dVAXYT24Q== @@ -3826,6 +2889,14 @@ jsonfile@^4.0.0: array-includes "^3.1.2" object.assign "^4.1.2" +jsx-ast-utils@^3.3.2: + version "3.3.3" + resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-3.3.3.tgz#76b3e6e6cece5c69d49a5792c3d01bd1a0cdc7ea" + integrity sha512-fYQHZTZ8jSfmWZ0iyzfwiU4WDX4HpHbMCZ3gPlWYiCl3BoeOTsqKBqnTVfH2rYT7eP5c3sVbeSPHnnJOaTrWiw== + dependencies: + array-includes "^3.1.5" + object.assign "^4.1.3" + jszip@3.7.1: version "3.7.1" resolved "https://registry.npmjs.org/jszip/-/jszip-3.7.1.tgz" @@ -3925,16 +2996,6 @@ listr2@^3.8.2: through "^2.3.8" wrap-ansi "^7.0.0" -load-json-file@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz" - integrity sha1-L19Fq5HjMhYjT9U62rZo607AmTs= - dependencies: - graceful-fs "^4.1.2" - parse-json "^4.0.0" - pify "^3.0.0" - strip-bom "^3.0.0" - localforage@^1.8.1, localforage@^1.9.0: version "1.10.0" resolved "https://registry.npmjs.org/localforage/-/localforage-1.10.0.tgz" @@ -3942,59 +3003,23 @@ localforage@^1.8.1, localforage@^1.9.0: dependencies: lie "3.1.1" -locate-path@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz" - integrity sha1-K1aLJl7slExtnA3pw9u7ygNUzY4= +locate-path@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" + integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== dependencies: - p-locate "^2.0.0" - path-exists "^3.0.0" + p-locate "^5.0.0" lodash-es@^4.17.11, lodash-es@^4.17.21: version "4.17.21" resolved "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz" integrity sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw== -lodash._reinterpolate@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz" - integrity sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0= - -lodash.clonedeep@^4.5.0: - version "4.5.0" - resolved "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz" - integrity sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8= - -lodash.debounce@^4.0.8: - version "4.0.8" - resolved "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz" - integrity sha1-gteb/zCmfEAF/9XiUVMArZyk168= - lodash.merge@^4.6.2: version "4.6.2" resolved "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz" integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== -lodash.template@^4.5.0: - version "4.5.0" - resolved "https://registry.npmjs.org/lodash.template/-/lodash.template-4.5.0.tgz" - integrity sha512-84vYFxIkmidUiFxidA/KjjH9pAycqW+h980j7Fuz5qxRtO9pgB7MDFTdys1N7A5mcucRiDyEq4fusljItR1T/A== - dependencies: - lodash._reinterpolate "^3.0.0" - lodash.templatesettings "^4.0.0" - -lodash.templatesettings@^4.0.0: - version "4.2.0" - resolved "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-4.2.0.tgz" - integrity sha512-stgLz+i3Aa9mZgnjr/O+v9ruKZsPsndy7qPZOchbqk2cnTU1ZaldKK+v7m54WoKIyxiuMZTKT2H81F8BeAc3ZQ== - dependencies: - lodash._reinterpolate "^3.0.0" - -lodash.truncate@^4.4.2: - version "4.4.2" - resolved "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz" - integrity sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM= - lodash@^4.17.11, lodash@^4.17.15, lodash@^4.17.21: version "4.17.21" resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz" @@ -4037,13 +3062,6 @@ lru_map@^0.3.3: resolved "https://registry.npmjs.org/lru_map/-/lru_map-0.3.3.tgz" integrity sha1-tcg1G5Rky9dQM1p5ZQoOwOVhGN0= -magic-string@^0.25.0, magic-string@^0.25.7: - version "0.25.7" - resolved "https://registry.npmjs.org/magic-string/-/magic-string-0.25.7.tgz" - integrity sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA== - dependencies: - sourcemap-codec "^1.4.4" - md5.js@^1.3.4: version "1.3.5" resolved "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz" @@ -4073,7 +3091,7 @@ merge-stream@^2.0.0: resolved "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz" integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== -merge2@^1.3.0: +merge2@^1.3.0, merge2@^1.4.1: version "1.4.1" resolved "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz" integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== @@ -4120,11 +3138,23 @@ minimatch@^3.0.4: dependencies: brace-expansion "^1.1.7" +minimatch@^3.0.5, minimatch@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + minimist@^1.2.0, minimist@^1.2.5: version "1.2.6" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44" integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q== +minimist@^1.2.6: + version "1.2.7" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.7.tgz#daa1c4d91f507390437c6a8bc01078e7000c4d18" + integrity sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g== + mkdirp@^0.5.1, mkdirp@^0.5.5: version "0.5.5" resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz" @@ -4147,10 +3177,15 @@ ms@2.1.2, ms@^2.1.1: resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== -nanoid@^3.1.30: - version "3.3.1" - resolved "https://registry.npmjs.org/nanoid/-/nanoid-3.3.1.tgz" - integrity sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw== +nanoid@^3.3.4: + version "3.3.4" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.4.tgz#730b67e3cd09e2deacf03c027c81c9d9dbc5e8ab" + integrity sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw== + +natural-compare-lite@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz#17b09581988979fddafe0201e931ba933c96cbb4" + integrity sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g== natural-compare@^1.4.0: version "1.4.0" @@ -4170,28 +3205,31 @@ next-transpile-modules@^9.0.0: enhanced-resolve "^5.7.0" escalade "^3.1.1" -next@^12.1.0: - version "12.1.0" - resolved "https://registry.npmjs.org/next/-/next-12.1.0.tgz" - integrity sha512-s885kWvnIlxsUFHq9UGyIyLiuD0G3BUC/xrH0CEnH5lHEWkwQcHOORgbDF0hbrW9vr/7am4ETfX4A7M6DjrE7Q== +next@^12.3.1: + version "12.3.1" + resolved "https://registry.yarnpkg.com/next/-/next-12.3.1.tgz#127b825ad2207faf869b33393ec8c75fe61e50f1" + integrity sha512-l7bvmSeIwX5lp07WtIiP9u2ytZMv7jIeB8iacR28PuUEFG5j0HGAPnMqyG5kbZNBG2H7tRsrQ4HCjuMOPnANZw== dependencies: - "@next/env" "12.1.0" - caniuse-lite "^1.0.30001283" - postcss "8.4.5" - styled-jsx "5.0.0" - use-subscription "1.5.1" + "@next/env" "12.3.1" + "@swc/helpers" "0.4.11" + caniuse-lite "^1.0.30001406" + postcss "8.4.14" + styled-jsx "5.0.7" + use-sync-external-store "1.2.0" optionalDependencies: - "@next/swc-android-arm64" "12.1.0" - "@next/swc-darwin-arm64" "12.1.0" - "@next/swc-darwin-x64" "12.1.0" - "@next/swc-linux-arm-gnueabihf" "12.1.0" - "@next/swc-linux-arm64-gnu" "12.1.0" - "@next/swc-linux-arm64-musl" "12.1.0" - "@next/swc-linux-x64-gnu" "12.1.0" - "@next/swc-linux-x64-musl" "12.1.0" - "@next/swc-win32-arm64-msvc" "12.1.0" - "@next/swc-win32-ia32-msvc" "12.1.0" - "@next/swc-win32-x64-msvc" "12.1.0" + "@next/swc-android-arm-eabi" "12.3.1" + "@next/swc-android-arm64" "12.3.1" + "@next/swc-darwin-arm64" "12.3.1" + "@next/swc-darwin-x64" "12.3.1" + "@next/swc-freebsd-x64" "12.3.1" + "@next/swc-linux-arm-gnueabihf" "12.3.1" + "@next/swc-linux-arm64-gnu" "12.3.1" + "@next/swc-linux-arm64-musl" "12.3.1" + "@next/swc-linux-x64-gnu" "12.3.1" + "@next/swc-linux-x64-musl" "12.3.1" + "@next/swc-win32-arm64-msvc" "12.3.1" + "@next/swc-win32-ia32-msvc" "12.3.1" + "@next/swc-win32-x64-msvc" "12.3.1" node-fetch@^2.6.0: version "2.6.2" @@ -4205,21 +3243,6 @@ node-fetch@^2.6.1: dependencies: whatwg-url "^5.0.0" -node-releases@^1.1.75: - version "1.1.75" - resolved "https://registry.npmjs.org/node-releases/-/node-releases-1.1.75.tgz" - integrity sha512-Qe5OUajvqrqDSy6wrWFmMwfJ0jVgwiw4T3KqmbTcZ62qW0gQkheXYhcFM1+lOVcGUoRxcEcfyvFMAnDgaF1VWw== - -normalize-package-data@^2.3.2: - version "2.5.0" - resolved "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz" - integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA== - dependencies: - hosted-git-info "^2.1.4" - resolve "^1.10.0" - semver "2 || 3 || 4 || 5" - validate-npm-package-license "^3.0.1" - normalize-path@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz" @@ -4247,7 +3270,7 @@ number-is-nan@^1.0.0: resolved "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz" integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0= -object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1: +object-assign@^4.1.0, object-assign@^4.1.1: version "4.1.1" resolved "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz" integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= @@ -4257,12 +3280,17 @@ object-inspect@^1.11.0, object-inspect@^1.9.0: resolved "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.0.tgz" integrity sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g== +object-inspect@^1.12.2: + version "1.12.2" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.2.tgz#c0641f26394532f28ab8d796ab954e43c009a8ea" + integrity sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ== + object-keys@^1.0.12, object-keys@^1.1.1: version "1.1.1" resolved "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz" integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== -object.assign@^4.1.0, object.assign@^4.1.2: +object.assign@^4.1.2: version "4.1.2" resolved "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz" integrity sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ== @@ -4272,33 +3300,50 @@ object.assign@^4.1.0, object.assign@^4.1.2: has-symbols "^1.0.1" object-keys "^1.1.1" -object.entries@^1.1.2, object.entries@^1.1.4: - version "1.1.4" - resolved "https://registry.npmjs.org/object.entries/-/object.entries-1.1.4.tgz" - integrity sha512-h4LWKWE+wKQGhtMjZEBud7uLGhqyLwj8fpHOarZhD2uY3C9cRtk57VQ89ke3moByLXMedqs3XCHzyb4AmA2DjA== +object.assign@^4.1.3, object.assign@^4.1.4: + version "4.1.4" + resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.4.tgz#9673c7c7c351ab8c4d0b516f4343ebf4dfb7799f" + integrity sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ== dependencies: call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.18.2" + define-properties "^1.1.4" + has-symbols "^1.0.3" + object-keys "^1.1.1" -object.fromentries@^2.0.4: - version "2.0.4" - resolved "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.4.tgz" - integrity sha512-EsFBshs5RUUpQEY1D4q/m59kMfz4YJvxuNCJcv/jWwOJr34EaVnG11ZrZa0UHB3wnzV1wx8m58T4hQL8IuNXlQ== +object.entries@^1.1.6: + version "1.1.6" + resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.6.tgz#9737d0e5b8291edd340a3e3264bb8a3b00d5fa23" + integrity sha512-leTPzo4Zvg3pmbQ3rDK69Rl8GQvIqMWubrkxONG9/ojtFE2rD9fjMKfSI5BxW3osRH1m6VdzmqK8oAY9aT4x5w== dependencies: call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.18.0-next.2" - has "^1.0.3" + define-properties "^1.1.4" + es-abstract "^1.20.4" -object.values@^1.1.4: - version "1.1.4" - resolved "https://registry.npmjs.org/object.values/-/object.values-1.1.4.tgz" - integrity sha512-TnGo7j4XSnKQoK3MfvkzqKCi0nVe/D9I9IjwTNYdb/fxYHpjrluHVOgw0AF6jrRFGMPHdfuidR09tIDiIvnaSg== +object.fromentries@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.6.tgz#cdb04da08c539cffa912dcd368b886e0904bfa73" + integrity sha512-VciD13dswC4j1Xt5394WR4MzmAQmlgN72phd/riNp9vtD7tp4QQWJ0R4wvclXcafgcYK8veHRed2W6XeGBvcfg== dependencies: call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.18.2" + define-properties "^1.1.4" + es-abstract "^1.20.4" + +object.hasown@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/object.hasown/-/object.hasown-1.1.2.tgz#f919e21fad4eb38a57bc6345b3afd496515c3f92" + integrity sha512-B5UIT3J1W+WuWIU55h0mjlwaqxiE5vYENJXIXZ4VFe05pNYrkKuK0U/6aFcb0pKywYJh7IhfoqUfKVmrJJHZHw== + dependencies: + define-properties "^1.1.4" + es-abstract "^1.20.4" + +object.values@^1.1.5, object.values@^1.1.6: + version "1.1.6" + resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.6.tgz#4abbaa71eba47d63589d402856f908243eea9b1d" + integrity sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + es-abstract "^1.20.4" on-finished@~2.3.0: version "2.3.0" @@ -4321,6 +3366,15 @@ onetime@^5.1.0, onetime@^5.1.2: dependencies: mimic-fn "^2.1.0" +open@^8.4.0: + version "8.4.0" + resolved "https://registry.yarnpkg.com/open/-/open-8.4.0.tgz#345321ae18f8138f82565a910fdc6b39e8c244f8" + integrity sha512-XgFPPM+B28FtCCgSb9I+s9szOC1vZRSwgWsRUA5ylIxRTgKozqjOCrVOqGsYABPYK5qnfqClxZTFBa8PKt2v6Q== + dependencies: + define-lazy-prop "^2.0.0" + is-docker "^2.1.1" + is-wsl "^2.2.0" + opener@^1.5.1: version "1.5.2" resolved "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz" @@ -4338,24 +3392,19 @@ optionator@^0.9.1: type-check "^0.4.0" word-wrap "^1.2.3" -p-limit@^1.1.0: - version "1.3.0" - resolved "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz" - integrity sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q== +p-limit@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" + integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== dependencies: - p-try "^1.0.0" + yocto-queue "^0.1.0" -p-locate@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz" - integrity sha1-IKAQOyIqcMj9OcwuWAaA893l7EM= +p-locate@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" + integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== dependencies: - p-limit "^1.1.0" - -p-map@^2.0.0: - version "2.1.0" - resolved "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz" - integrity sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw== + p-limit "^3.0.2" p-map@^4.0.0: version "4.0.0" @@ -4364,11 +3413,6 @@ p-map@^4.0.0: dependencies: aggregate-error "^3.0.0" -p-try@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz" - integrity sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M= - pako@~1.0.2: version "1.0.11" resolved "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz" @@ -4381,14 +3425,6 @@ parent-module@^1.0.0: dependencies: callsites "^3.0.0" -parse-json@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz" - integrity sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA= - dependencies: - error-ex "^1.3.1" - json-parse-better-errors "^1.0.1" - parse-json@^5.0.0: version "5.2.0" resolved "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz" @@ -4404,27 +3440,22 @@ parseurl@~1.3.3: resolved "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz" integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== -path-exists@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz" - integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU= +path-exists@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" + integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== path-is-absolute@^1.0.0: version "1.0.1" resolved "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz" integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= -path-is-inside@^1.0.2: - version "1.0.2" - resolved "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz" - integrity sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM= - path-key@^3.0.0, path-key@^3.1.0: version "3.1.1" resolved "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz" integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== -path-parse@^1.0.6: +path-parse@^1.0.6, path-parse@^1.0.7: version "1.0.7" resolved "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz" integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== @@ -4434,13 +3465,6 @@ path-to-regexp@0.1.7: resolved "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz" integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w= -path-type@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz" - integrity sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg== - dependencies: - pify "^3.0.0" - path-type@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz" @@ -4470,12 +3494,7 @@ picocolors@^1.0.0: resolved "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz" integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== -picomatch@^2.0.4: - version "2.3.1" - resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz" - integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== - -picomatch@^2.2.2, picomatch@^2.2.3: +picomatch@^2.2.3: version "2.3.0" resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz" integrity sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw== @@ -4485,47 +3504,11 @@ piexifjs@^1.0.6: resolved "https://registry.npmjs.org/piexifjs/-/piexifjs-1.0.6.tgz" integrity sha512-0wVyH0cKohzBQ5Gi2V1BuxYpxWfxF3cSqfFXfPIpl5tl9XLS5z4ogqhUCD20AbHi0h9aJkqXNJnkVev6gwh2ag== -pify@^2.0.0: - version "2.3.0" - resolved "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz" - integrity sha1-7RQaasBDqEnqWISY59yosVMw6Qw= - -pify@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz" - integrity sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY= - pify@^4.0.1: version "4.0.1" resolved "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz" integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g== -pinkie-promise@^2.0.0: - version "2.0.1" - resolved "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz" - integrity sha1-ITXW36ejWMBprJsXh3YogihFD/o= - dependencies: - pinkie "^2.0.0" - -pinkie@^2.0.0: - version "2.0.4" - resolved "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz" - integrity sha1-clVrgM+g1IqXToDnckjoDtT3+HA= - -pkg-dir@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz" - integrity sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s= - dependencies: - find-up "^2.1.0" - -pkg-up@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/pkg-up/-/pkg-up-2.0.0.tgz" - integrity sha1-yBmscoBZpGHKscOImivjxJoATX8= - dependencies: - find-up "^2.1.0" - please-upgrade-node@^3.2.0: version "3.2.0" resolved "https://registry.npmjs.org/please-upgrade-node/-/please-upgrade-node-3.2.0.tgz" @@ -4543,14 +3526,14 @@ postcss-value-parser@^4.0.2: resolved "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz" integrity sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ== -postcss@8.4.5: - version "8.4.5" - resolved "https://registry.npmjs.org/postcss/-/postcss-8.4.5.tgz" - integrity sha512-jBDboWM8qpaqwkMwItqTQTiFikhs/67OYVvblFFTM7MrZjt6yMKd6r2kgXizEbTTljacm4NldIlZnhbjr84QYg== +postcss@8.4.14: + version "8.4.14" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.14.tgz#ee9274d5622b4858c1007a74d76e42e56fd21caf" + integrity sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig== dependencies: - nanoid "^3.1.30" + nanoid "^3.3.4" picocolors "^1.0.0" - source-map-js "^1.0.1" + source-map-js "^1.0.2" prelude-ls@^1.2.1: version "1.2.1" @@ -4562,17 +3545,12 @@ prettier@2.3.2: resolved "https://registry.npmjs.org/prettier/-/prettier-2.3.2.tgz" integrity sha512-lnJzDfJ66zkMy58OL5/NY5zp70S7Nz6KqcKkXYzn2tMVrNxvbqaBpg7H3qHaLxCJ5lNMsGuM8+ohS7cZrthdLQ== -pretty-bytes@^5.3.0: - version "5.6.0" - resolved "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz" - integrity sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg== - process-nextick-args@~2.0.0: version "2.0.1" resolved "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz" integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== -progress@^2.0.0, progress@^2.0.3: +progress@^2.0.3: version "2.0.3" resolved "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz" integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== @@ -4636,7 +3614,7 @@ queue-microtask@^1.2.2: resolved "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz" integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== -randombytes@^2.0.1, randombytes@^2.1.0: +randombytes@^2.0.1: version "2.1.0" resolved "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz" integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== @@ -4812,23 +3790,6 @@ react@^17.0.2: loose-envify "^1.1.0" object-assign "^4.1.1" -read-pkg-up@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-3.0.0.tgz" - integrity sha1-PtSWaF26D4/hGNBpHcUfSh/5bwc= - dependencies: - find-up "^2.0.0" - read-pkg "^3.0.0" - -read-pkg@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz" - integrity sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k= - dependencies: - load-json-file "^4.0.0" - normalize-package-data "^2.3.2" - path-type "^3.0.0" - readable-stream@^2.0.6, readable-stream@~2.3.6: version "2.3.7" resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz" @@ -4858,83 +3819,36 @@ readable-web-to-node-stream@^3.0.0: dependencies: readable-stream "^3.6.0" -regenerate-unicode-properties@^8.2.0: - version "8.2.0" - resolved "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-8.2.0.tgz" - integrity sha512-F9DjY1vKLo/tPePDycuH3dn9H1OTPIkVD9Kz4LODu+F2C75mgjAJ7x/gwy6ZcSNRAAkhNlJSOHRe8k3p+K9WhA== - dependencies: - regenerate "^1.4.0" - -regenerate@^1.4.0: - version "1.4.2" - resolved "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz" - integrity sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A== - -regenerator-runtime@^0.11.0: - version "0.11.1" - resolved "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz" - integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg== +regenerator-runtime@^0.13.10: + version "0.13.11" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz#f6dca3e7ceec20590d07ada785636a90cdca17f9" + integrity sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg== regenerator-runtime@^0.13.4, regenerator-runtime@^0.13.7: version "0.13.9" resolved "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz" integrity sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA== -regenerator-transform@^0.14.2: - version "0.14.5" - resolved "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.14.5.tgz" - integrity sha512-eOf6vka5IO151Jfsw2NO9WpGX58W6wWmefK3I1zEGr0lOD0u8rwPaNqQL1aRxUaxLeKO3ArNh3VYg1KbaD+FFw== - dependencies: - "@babel/runtime" "^7.8.4" - -regexp.prototype.flags@^1.3.1: - version "1.3.1" - resolved "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.3.1.tgz" - integrity sha512-JiBdRBq91WlY7uRJ0ds7R+dU02i6LKi8r3BuQhNXn+kmeLN+EfHhfjqMRis1zJxnlu88hq/4dx0P2OP3APRTOA== +regexp.prototype.flags@^1.4.3: + version "1.4.3" + resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz#87cab30f80f66660181a3bb7bf5981a872b367ac" + integrity sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA== dependencies: call-bind "^1.0.2" define-properties "^1.1.3" + functions-have-names "^1.2.2" -regexpp@^3.1.0: +regexpp@^3.2.0: version "3.2.0" resolved "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz" integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg== -regexpu-core@^4.7.1: - version "4.7.1" - resolved "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.7.1.tgz" - integrity sha512-ywH2VUraA44DZQuRKzARmw6S66mr48pQVva4LBeRhcOltJ6hExvWly5ZjFLYo67xbIxb6W1q4bAGtgfEl20zfQ== - dependencies: - regenerate "^1.4.0" - regenerate-unicode-properties "^8.2.0" - regjsgen "^0.5.1" - regjsparser "^0.6.4" - unicode-match-property-ecmascript "^1.0.4" - unicode-match-property-value-ecmascript "^1.2.0" - -regjsgen@^0.5.1: - version "0.5.2" - resolved "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.2.tgz" - integrity sha512-OFFT3MfrH90xIW8OOSyUrk6QHD5E9JOTeGodiJeBS3J6IwlgzJMNE/1bZklWz5oTg+9dCMyEetclvCVXOPoN3A== - -regjsparser@^0.6.4: - version "0.6.9" - resolved "https://registry.npmjs.org/regjsparser/-/regjsparser-0.6.9.tgz" - integrity sha512-ZqbNRz1SNjLAiYuwY0zoXW8Ne675IX5q+YHioAGbCw4X96Mjl2+dcX9B2ciaeyYjViDAfvIjFpQjJgLttTEERQ== - dependencies: - jsesc "~0.5.0" - -require-from-string@^2.0.2: - version "2.0.2" - resolved "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz" - integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== - resolve-from@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz" integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== -resolve@^1.10.0, resolve@^1.14.2, resolve@^1.20.0: +resolve@^1.20.0: version "1.20.0" resolved "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz" integrity sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A== @@ -4942,6 +3856,15 @@ resolve@^1.10.0, resolve@^1.14.2, resolve@^1.20.0: is-core-module "^2.2.0" path-parse "^1.0.6" +resolve@^1.22.0: + version "1.22.1" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.1.tgz#27cb2ebb53f91abb49470a928bba7558066ac177" + integrity sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw== + dependencies: + is-core-module "^2.9.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + resolve@^2.0.0-next.3: version "2.0.0-next.3" resolved "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.3.tgz" @@ -4968,13 +3891,6 @@ rifm@^0.12.1: resolved "https://registry.yarnpkg.com/rifm/-/rifm-0.12.1.tgz#8fa77f45b7f1cda2a0068787ac821f0593967ac4" integrity sha512-OGA1Bitg/dSJtI/c4dh90svzaUPt228kzFsUkJbtA2c964IqEAwWXeL9ZJi86xWv3j5SMqRvGULl7bA6cK0Bvg== -rimraf@^2.6.3: - version "2.7.1" - resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz" - integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== - dependencies: - glob "^7.1.3" - rimraf@^3.0.2: version "3.0.2" resolved "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz" @@ -4990,41 +3906,6 @@ ripemd160@^2.0.0, ripemd160@^2.0.1: hash-base "^3.0.0" inherits "^2.0.1" -rollup-plugin-babel@^4.3.3: - version "4.4.0" - resolved "https://registry.npmjs.org/rollup-plugin-babel/-/rollup-plugin-babel-4.4.0.tgz" - integrity sha512-Lek/TYp1+7g7I+uMfJnnSJ7YWoD58ajo6Oarhlex7lvUce+RCKRuGRSgztDO3/MF/PuGKmUL5iTHKf208UNszw== - dependencies: - "@babel/helper-module-imports" "^7.0.0" - rollup-pluginutils "^2.8.1" - -rollup-plugin-terser@^5.3.1: - version "5.3.1" - resolved "https://registry.npmjs.org/rollup-plugin-terser/-/rollup-plugin-terser-5.3.1.tgz" - integrity sha512-1pkwkervMJQGFYvM9nscrUoncPwiKR/K+bHdjv6PFgRo3cgPHoRT83y2Aa3GvINj4539S15t/tpFPb775TDs6w== - dependencies: - "@babel/code-frame" "^7.5.5" - jest-worker "^24.9.0" - rollup-pluginutils "^2.8.2" - serialize-javascript "^4.0.0" - terser "^4.6.2" - -rollup-pluginutils@^2.8.1, rollup-pluginutils@^2.8.2: - version "2.8.2" - resolved "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz" - integrity sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ== - dependencies: - estree-walker "^0.6.1" - -rollup@^1.31.1: - version "1.32.1" - resolved "https://registry.npmjs.org/rollup/-/rollup-1.32.1.tgz" - integrity sha512-/2HA0Ec70TvQnXdzynFffkjA6XN+1e2pEv/uKS5Ulca40g2L7KuOE3riasHoNVHOsFD5KKZgDsMk1CP3Tw9s+A== - dependencies: - "@types/estree" "*" - "@types/node" "*" - acorn "^7.1.0" - run-parallel@^1.1.9: version "1.2.0" resolved "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz" @@ -5049,11 +3930,27 @@ safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.2, safe-buffer@^5.2.0, resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== +safe-regex-test@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/safe-regex-test/-/safe-regex-test-1.0.0.tgz#793b874d524eb3640d1873aad03596db2d4f2295" + integrity sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.1.3" + is-regex "^1.1.4" + "safer-buffer@>= 2.1.2 < 3": version "2.1.2" resolved "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== +sanitize-filename@^1.6.3: + version "1.6.3" + resolved "https://registry.yarnpkg.com/sanitize-filename/-/sanitize-filename-1.6.3.tgz#755ebd752045931977e30b2025d340d7c9090378" + integrity sha512-y/52Mcy7aw3gRm7IrcGDFx/bCk4AhRh2eI9luHOQM86nZsqwiRkkq2GekHXBBD+SmPidc8i2PqtYZl+pWJ8Oeg== + dependencies: + truncate-utf8-bytes "^1.0.0" + sax@^1.2.4: version "1.2.4" resolved "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz" @@ -5072,25 +3969,15 @@ semver-compare@^1.0.0: resolved "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz" integrity sha1-De4hahyUGrN+nvsXiPavxf9VN/w= -"semver@2 || 3 || 4 || 5": - version "5.7.1" - resolved "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz" - integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== - -semver@7.0.0: - version "7.0.0" - resolved "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz" - integrity sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A== - -semver@^6.1.1, semver@^6.1.2, semver@^6.3.0: +semver@^6.3.0: version "6.3.0" - resolved "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== -semver@^7.2.1, semver@^7.3.5: - version "7.3.5" - resolved "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz" - integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ== +semver@^7.3.7: + version "7.3.8" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.8.tgz#07a78feafb3f7b32347d725e33de7e2a2df67798" + integrity sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A== dependencies: lru-cache "^6.0.0" @@ -5113,13 +4000,6 @@ send@0.17.1: range-parser "~1.2.1" statuses "~1.5.0" -serialize-javascript@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz" - integrity sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw== - dependencies: - randombytes "^2.1.0" - serve-static@1.14.1: version "1.14.1" resolved "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz" @@ -5189,6 +4069,11 @@ slash@^3.0.0: resolved "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz" integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== +slash@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-4.0.0.tgz#2422372176c4c6c5addb5e2ada885af984b396a7" + integrity sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew== + slice-ansi@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/slice-ansi/-/slice-ansi-3.0.0.tgz" @@ -5207,80 +4092,16 @@ slice-ansi@^4.0.0: astral-regex "^2.0.0" is-fullwidth-code-point "^3.0.0" -source-list-map@^2.0.0: - version "2.0.1" - resolved "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz" - integrity sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw== - -source-map-js@^1.0.1: +source-map-js@^1.0.2: version "1.0.2" - resolved "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz" + resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c" integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw== -source-map-support@~0.5.12: - version "0.5.21" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" - integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== - dependencies: - buffer-from "^1.0.0" - source-map "^0.6.0" - -source-map-url@^0.4.0: - version "0.4.1" - resolved "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.1.tgz" - integrity sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw== - source-map@^0.5.0: version "0.5.7" resolved "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz" integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= -source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" - integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== - -source-map@^0.7.3: - version "0.7.3" - resolved "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz" - integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ== - -sourcemap-codec@^1.4.4: - version "1.4.8" - resolved "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz" - integrity sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA== - -spdx-correct@^3.0.0: - version "3.1.1" - resolved "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz" - integrity sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w== - dependencies: - spdx-expression-parse "^3.0.0" - spdx-license-ids "^3.0.0" - -spdx-exceptions@^2.1.0: - version "2.3.0" - resolved "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz" - integrity sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A== - -spdx-expression-parse@^3.0.0: - version "3.0.1" - resolved "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz" - integrity sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q== - dependencies: - spdx-exceptions "^2.1.0" - spdx-license-ids "^3.0.0" - -spdx-license-ids@^3.0.0: - version "3.0.10" - resolved "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.10.tgz" - integrity sha512-oie3/+gKf7QtpitB0LYLETe+k8SifzsX4KixvpOsbI6S0kRiRQ5MKOio8eMSAKQ17N06+wdEOXRiId+zOxo0hA== - -sprintf-js@~1.0.2: - version "1.0.3" - resolved "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz" - integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= - "statuses@>= 1.5.0 < 2", statuses@~1.5.0: version "1.5.0" resolved "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz" @@ -5317,18 +4138,18 @@ string-width@^4.1.0, string-width@^4.2.0: is-fullwidth-code-point "^3.0.0" strip-ansi "^6.0.0" -string.prototype.matchall@^4.0.5: - version "4.0.5" - resolved "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.5.tgz" - integrity sha512-Z5ZaXO0svs0M2xd/6By3qpeKpLKd9mO4v4q3oMEQrk8Ck4xOD5d5XeBOOjGrmVZZ/AHB1S0CgG4N5r1G9N3E2Q== +string.prototype.matchall@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-4.0.8.tgz#3bf85722021816dcd1bf38bb714915887ca79fd3" + integrity sha512-6zOCOcJ+RJAQshcTvXPHoxoQGONa3e/Lqx90wUA+wEzX78sg5Bo+1tQo4N0pohS0erG9qtCqJDjNCQBjeWVxyg== dependencies: call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.18.2" - get-intrinsic "^1.1.1" - has-symbols "^1.0.2" + define-properties "^1.1.4" + es-abstract "^1.20.4" + get-intrinsic "^1.1.3" + has-symbols "^1.0.3" internal-slot "^1.0.3" - regexp.prototype.flags "^1.3.1" + regexp.prototype.flags "^1.4.3" side-channel "^1.0.4" string.prototype.trimend@^1.0.4: @@ -5339,6 +4160,15 @@ string.prototype.trimend@^1.0.4: call-bind "^1.0.2" define-properties "^1.1.3" +string.prototype.trimend@^1.0.5: + version "1.0.6" + resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz#c4a27fa026d979d79c04f17397f250a462944533" + integrity sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + es-abstract "^1.20.4" + string.prototype.trimstart@^1.0.4: version "1.0.4" resolved "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz" @@ -5347,6 +4177,15 @@ string.prototype.trimstart@^1.0.4: call-bind "^1.0.2" define-properties "^1.1.3" +string.prototype.trimstart@^1.0.5: + version "1.0.6" + resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz#e90ab66aa8e4007d92ef591bbf3cd422c56bdcf4" + integrity sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + es-abstract "^1.20.4" + string_decoder@^1.1.1: version "1.3.0" resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz" @@ -5391,19 +4230,18 @@ strip-ansi@^6.0.0: dependencies: ansi-regex "^5.0.0" +strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + strip-bom@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz" integrity sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM= -strip-comments@^1.0.2: - version "1.0.2" - resolved "https://registry.npmjs.org/strip-comments/-/strip-comments-1.0.2.tgz" - integrity sha512-kL97alc47hoyIQSV165tTt9rG5dn4w1dNnBhOQ3bOU1Nc1hel09jnXANaHJ7vzHLd4Ju8kseDGzlev96pghLFw== - dependencies: - babel-extract-comments "^1.0.0" - babel-plugin-transform-object-rest-spread "^6.26.0" - strip-final-newline@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz" @@ -5438,10 +4276,10 @@ styled-components@^5.3.5: shallowequal "^1.1.0" supports-color "^5.5.0" -styled-jsx@5.0.0: - version "5.0.0" - resolved "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.0.0.tgz" - integrity sha512-qUqsWoBquEdERe10EW8vLp3jT25s/ssG1/qX5gZ4wu15OZpmSMFI2v+fWlRhLfykA5rFtlJ1ME8A8pm/peV4WA== +styled-jsx@5.0.7: + version "5.0.7" + resolved "https://registry.yarnpkg.com/styled-jsx/-/styled-jsx-5.0.7.tgz#be44afc53771b983769ac654d355ca8d019dff48" + integrity sha512-b3sUzamS086YLRuvnaDigdAewz1/EFYlHpYBP5mZovKEdQQOIIYq8lApylub3HHZ6xFjV051kkGU7cudJmrXEA== stylis@^4.0.3: version "4.0.10" @@ -5455,13 +4293,6 @@ supports-color@^5.3.0, supports-color@^5.5.0: dependencies: has-flag "^3.0.0" -supports-color@^6.1.0: - version "6.1.0" - resolved "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz" - integrity sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ== - dependencies: - has-flag "^3.0.0" - supports-color@^7.1.0: version "7.2.0" resolved "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz" @@ -5469,51 +4300,29 @@ supports-color@^7.1.0: dependencies: has-flag "^4.0.0" +supports-preserve-symlinks-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" + integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== + synchronous-promise@^2.0.13: version "2.0.15" resolved "https://registry.npmjs.org/synchronous-promise/-/synchronous-promise-2.0.15.tgz" integrity sha512-k8uzYIkIVwmT+TcglpdN50pS2y1BDcUnBPK9iJeGu0Pl1lOI8pD6wtzgw91Pjpe+RxtTncw32tLxs/R0yNL2Mg== -table@^6.0.9: - version "6.7.1" - resolved "https://registry.npmjs.org/table/-/table-6.7.1.tgz" - integrity sha512-ZGum47Yi6KOOFDE8m223td53ath2enHcYLgOCjGr5ngu8bdIARQk6mN/wRMv4yMRcHnCSnHbCEha4sobQx5yWg== +synckit@^0.8.4: + version "0.8.4" + resolved "https://registry.yarnpkg.com/synckit/-/synckit-0.8.4.tgz#0e6b392b73fafdafcde56692e3352500261d64ec" + integrity sha512-Dn2ZkzMdSX827QbowGbU/4yjWuvNaCoScLLoMo/yKbu+P4GBR6cRGKZH27k6a9bRzdqcyd1DE96pQtQ6uNkmyw== dependencies: - ajv "^8.0.1" - lodash.clonedeep "^4.5.0" - lodash.truncate "^4.4.2" - slice-ansi "^4.0.0" - string-width "^4.2.0" - strip-ansi "^6.0.0" + "@pkgr/utils" "^2.3.1" + tslib "^2.4.0" tapable@^2.2.0: version "2.2.1" resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0" integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ== -temp-dir@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/temp-dir/-/temp-dir-1.0.0.tgz" - integrity sha1-CnwOom06Oa+n4OvqnB/AvE2qAR0= - -tempy@^0.3.0: - version "0.3.0" - resolved "https://registry.npmjs.org/tempy/-/tempy-0.3.0.tgz" - integrity sha512-WrH/pui8YCwmeiAoxV+lpRH9HpRtgBhSR2ViBPgpGb/wnYDzp21R4MN45fsCGvLROvY67o3byhJRYRONJyImVQ== - dependencies: - temp-dir "^1.0.0" - type-fest "^0.3.1" - unique-string "^1.0.0" - -terser@^4.6.2: - version "4.8.1" - resolved "https://registry.yarnpkg.com/terser/-/terser-4.8.1.tgz#a00e5634562de2239fd404c649051bf6fc21144f" - integrity sha512-4GnLC0x667eJG0ewJTa6z/yXrbLGv80D9Ru6HIpCQmO+Q4PfEtBFi0ObSckqwL6VyQv/7ENJieXHo2ANmdQwgw== - dependencies: - commander "^2.20.0" - source-map "~0.6.1" - source-map-support "~0.5.12" - text-table@^0.2.0: version "0.2.0" resolved "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz" @@ -5524,6 +4333,14 @@ through@^2.3.8: resolved "https://registry.npmjs.org/through/-/through-2.3.8.tgz" integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= +tiny-glob@^0.2.9: + version "0.2.9" + resolved "https://registry.yarnpkg.com/tiny-glob/-/tiny-glob-0.2.9.tgz#2212d441ac17928033b110f8b3640683129d31e2" + integrity sha512-g/55ssRPUjShh+xkfx9UPDXqhckHEsHr4Vd9zX55oSdGZc/MD0m3sferOkwWtp98bv+kcVfEHtRJgBVJzelrzg== + dependencies: + globalyzer "0.1.0" + globrex "^0.1.2" + tiny-warning@^1.0.2: version "1.0.3" resolved "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz" @@ -5564,19 +4381,26 @@ tr46@~0.0.3: resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" integrity sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o= +truncate-utf8-bytes@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/truncate-utf8-bytes/-/truncate-utf8-bytes-1.0.2.tgz#405923909592d56f78a5818434b0b78489ca5f2b" + integrity sha512-95Pu1QXQvruGEhv62XCMO3Mm90GscOCClvrIUwCM0PYOXK3kaF3l3sIHxx71ThJfcbM2O5Au6SO3AWCSEfW4mQ== + dependencies: + utf8-byte-length "^1.0.1" + tryer@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/tryer/-/tryer-1.0.1.tgz" integrity sha512-c3zayb8/kWWpycWYg87P71E1S1ZL6b6IJxfb5fvsUgsf0S2MVGaDhDXXjDMpdCpfWXqptc+4mXwmiy1ypXqRAA== -tsconfig-paths@^3.11.0: - version "3.11.0" - resolved "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.11.0.tgz" - integrity sha512-7ecdYDnIdmv639mmDwslG6KQg1Z9STTz1j7Gcz0xa+nshh/gKDAHcPxRbWOsA3SPp0tXP2leTcY9Kw+NAkfZzA== +tsconfig-paths@^3.14.1: + version "3.14.1" + resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz#ba0734599e8ea36c862798e920bcf163277b137a" + integrity sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ== dependencies: "@types/json5" "^0.0.29" json5 "^1.0.1" - minimist "^1.2.0" + minimist "^1.2.6" strip-bom "^3.0.0" tslib@^1.10.0, tslib@^1.8.1, tslib@^1.9.0, tslib@^1.9.3: @@ -5589,6 +4413,11 @@ tslib@^2.0.3: resolved "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz" integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw== +tslib@^2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.0.tgz#7cecaa7f073ce680a05847aa77be941098f36dc3" + integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ== + tsutils@^3.21.0: version "3.21.0" resolved "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz" @@ -5613,11 +4442,6 @@ type-fest@^0.21.3: resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz" integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== -type-fest@^0.3.1: - version "0.3.1" - resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.3.1.tgz" - integrity sha512-cUGJnCdr4STbePCgqNFbpVNCepa+kAVohJs1sLhxzdH+gnEoOd8VhbYa7pD3zZYGiURWM2xzEII3fQcRizDkYQ== - type-is@~1.6.17, type-is@~1.6.18: version "1.6.18" resolved "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz" @@ -5641,6 +4465,16 @@ unbox-primitive@^1.0.1: has-symbols "^1.0.2" which-boxed-primitive "^1.0.2" +unbox-primitive@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.2.tgz#29032021057d5e6cdbd08c5129c226dff8ed6f9e" + integrity sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw== + dependencies: + call-bind "^1.0.2" + has-bigints "^1.0.2" + has-symbols "^1.0.3" + which-boxed-primitive "^1.0.2" + uncontrollable@^7.2.1: version "7.2.1" resolved "https://registry.npmjs.org/uncontrollable/-/uncontrollable-7.2.1.tgz" @@ -5651,51 +4485,11 @@ uncontrollable@^7.2.1: invariant "^2.2.4" react-lifecycles-compat "^3.0.4" -unicode-canonical-property-names-ecmascript@^1.0.4: - version "1.0.4" - resolved "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz" - integrity sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ== - -unicode-match-property-ecmascript@^1.0.4: - version "1.0.4" - resolved "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz" - integrity sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg== - dependencies: - unicode-canonical-property-names-ecmascript "^1.0.4" - unicode-property-aliases-ecmascript "^1.0.4" - -unicode-match-property-value-ecmascript@^1.2.0: - version "1.2.0" - resolved "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.2.0.tgz" - integrity sha512-wjuQHGQVofmSJv1uVISKLE5zO2rNGzM/KCYZch/QQvez7C1hUhBIuZ701fYXExuufJFMPhv2SyL8CyoIfMLbIQ== - -unicode-property-aliases-ecmascript@^1.0.4: - version "1.1.0" - resolved "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.1.0.tgz" - integrity sha512-PqSoPh/pWetQ2phoj5RLiaqIk4kCNwoV3CI+LfGmWLKI3rE3kl1h59XpX2BjgDrmbxD9ARtQobPGU1SguCYuQg== - -unique-string@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/unique-string/-/unique-string-1.0.0.tgz" - integrity sha1-nhBXzKhRq7kzmPizOuGHuZyuwRo= - dependencies: - crypto-random-string "^1.0.0" - -universalify@^0.1.0: - version "0.1.2" - resolved "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz" - integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== - unpipe@1.0.0, unpipe@~1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz" integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw= -upath@^1.1.2, upath@^1.2.0: - version "1.2.0" - resolved "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz" - integrity sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg== - uri-js@^4.2.2: version "4.4.1" resolved "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz" @@ -5703,12 +4497,15 @@ uri-js@^4.2.2: dependencies: punycode "^2.1.0" -use-subscription@1.5.1: - version "1.5.1" - resolved "https://registry.npmjs.org/use-subscription/-/use-subscription-1.5.1.tgz" - integrity sha512-Xv2a1P/yReAjAbhylMfFplFKj9GssgTwN7RlcTxBujFQcloStWNDQdc4g4NRWH9xS4i/FDk04vQBptAXoF3VcA== - dependencies: - object-assign "^4.1.1" +use-sync-external-store@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz#7dbefd6ef3fe4e767a0cf5d7287aacfb5846928a" + integrity sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA== + +utf8-byte-length@^1.0.1: + version "1.0.4" + resolved "https://registry.yarnpkg.com/utf8-byte-length/-/utf8-byte-length-1.0.4.tgz#f45f150c4c66eee968186505ab93fcbb8ad6bf61" + integrity sha512-4+wkEYLBbWxqTahEsWrhxepcoVOJ+1z5PGIjPZxRkytcdSUaNjIjBM7Xn8E+pdSuV7SzvWovBFA54FO0JSoqhA== util-deprecate@^1.0.1, util-deprecate@~1.0.1: version "1.0.2" @@ -5720,19 +4517,6 @@ utils-merge@1.0.1: resolved "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz" integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= -v8-compile-cache@^2.0.3: - version "2.3.0" - resolved "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz" - integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA== - -validate-npm-package-license@^3.0.1: - version "3.0.4" - resolved "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz" - integrity sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew== - dependencies: - spdx-correct "^3.0.0" - spdx-expression-parse "^3.0.0" - vary@~1.1.2: version "1.1.2" resolved "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz" @@ -5769,14 +4553,6 @@ webpack-bundle-analyzer@3.6.1: opener "^1.5.1" ws "^6.0.0" -webpack-sources@^1.3.0: - version "1.4.3" - resolved "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz" - integrity sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ== - dependencies: - source-list-map "^2.0.0" - source-map "~0.6.1" - whatwg-url@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" @@ -5815,222 +4591,6 @@ word-wrap@^1.2.3: resolved "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz" integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== -workbox-background-sync@^5.1.4: - version "5.1.4" - resolved "https://registry.npmjs.org/workbox-background-sync/-/workbox-background-sync-5.1.4.tgz" - integrity sha512-AH6x5pYq4vwQvfRDWH+vfOePfPIYQ00nCEB7dJRU1e0n9+9HMRyvI63FlDvtFT2AvXVRsXvUt7DNMEToyJLpSA== - dependencies: - workbox-core "^5.1.4" - -workbox-broadcast-update@^5.1.4: - version "5.1.4" - resolved "https://registry.npmjs.org/workbox-broadcast-update/-/workbox-broadcast-update-5.1.4.tgz" - integrity sha512-HTyTWkqXvHRuqY73XrwvXPud/FN6x3ROzkfFPsRjtw/kGZuZkPzfeH531qdUGfhtwjmtO/ZzXcWErqVzJNdXaA== - dependencies: - workbox-core "^5.1.4" - -workbox-build@^5.1.4: - version "5.1.4" - resolved "https://registry.npmjs.org/workbox-build/-/workbox-build-5.1.4.tgz" - integrity sha512-xUcZn6SYU8usjOlfLb9Y2/f86Gdo+fy1fXgH8tJHjxgpo53VVsqRX0lUDw8/JuyzNmXuo8vXX14pXX2oIm9Bow== - dependencies: - "@babel/core" "^7.8.4" - "@babel/preset-env" "^7.8.4" - "@babel/runtime" "^7.8.4" - "@hapi/joi" "^15.1.0" - "@rollup/plugin-node-resolve" "^7.1.1" - "@rollup/plugin-replace" "^2.3.1" - "@surma/rollup-plugin-off-main-thread" "^1.1.1" - common-tags "^1.8.0" - fast-json-stable-stringify "^2.1.0" - fs-extra "^8.1.0" - glob "^7.1.6" - lodash.template "^4.5.0" - pretty-bytes "^5.3.0" - rollup "^1.31.1" - rollup-plugin-babel "^4.3.3" - rollup-plugin-terser "^5.3.1" - source-map "^0.7.3" - source-map-url "^0.4.0" - stringify-object "^3.3.0" - strip-comments "^1.0.2" - tempy "^0.3.0" - upath "^1.2.0" - workbox-background-sync "^5.1.4" - workbox-broadcast-update "^5.1.4" - workbox-cacheable-response "^5.1.4" - workbox-core "^5.1.4" - workbox-expiration "^5.1.4" - workbox-google-analytics "^5.1.4" - workbox-navigation-preload "^5.1.4" - workbox-precaching "^5.1.4" - workbox-range-requests "^5.1.4" - workbox-routing "^5.1.4" - workbox-strategies "^5.1.4" - workbox-streams "^5.1.4" - workbox-sw "^5.1.4" - workbox-window "^5.1.4" - -workbox-cacheable-response@6.3.0: - version "6.3.0" - resolved "https://registry.npmjs.org/workbox-cacheable-response/-/workbox-cacheable-response-6.3.0.tgz" - integrity sha512-oYCRGF6PFEmJJkktdxYw/tcrU8N5u/2ihxVSHd+9sNqjNMDiXLqsewcEG544f1yx7gq5/u6VcvUA5N62KzN1GQ== - dependencies: - workbox-core "6.3.0" - -workbox-cacheable-response@^5.1.4: - version "5.1.4" - resolved "https://registry.npmjs.org/workbox-cacheable-response/-/workbox-cacheable-response-5.1.4.tgz" - integrity sha512-0bfvMZs0Of1S5cdswfQK0BXt6ulU5kVD4lwer2CeI+03czHprXR3V4Y8lPTooamn7eHP8Iywi5QjyAMjw0qauA== - dependencies: - workbox-core "^5.1.4" - -workbox-core@6.3.0: - version "6.3.0" - resolved "https://registry.npmjs.org/workbox-core/-/workbox-core-6.3.0.tgz" - integrity sha512-SufToEV3SOLwwz3j+P4pgkfpzLRUlR17sX3p/LrMHP/brYKvJQqjTwtSvaCkkAX0RPHX2TFHmN8xhPP1bpmomg== - -workbox-core@^5.1.4: - version "5.1.4" - resolved "https://registry.npmjs.org/workbox-core/-/workbox-core-5.1.4.tgz" - integrity sha512-+4iRQan/1D8I81nR2L5vcbaaFskZC2CL17TLbvWVzQ4qiF/ytOGF6XeV54pVxAvKUtkLANhk8TyIUMtiMw2oDg== - -workbox-expiration@6.3.0: - version "6.3.0" - resolved "https://registry.npmjs.org/workbox-expiration/-/workbox-expiration-6.3.0.tgz" - integrity sha512-teYuYfM3HFbwAD/nlZDw/dCMOrCKjsAiMRhz0uOy9IkfBb7vBynO3xf118lY62X6BfqjZdeahiHh10N0/aYICg== - dependencies: - idb "^6.0.0" - workbox-core "6.3.0" - -workbox-expiration@^5.1.4: - version "5.1.4" - resolved "https://registry.npmjs.org/workbox-expiration/-/workbox-expiration-5.1.4.tgz" - integrity sha512-oDO/5iC65h2Eq7jctAv858W2+CeRW5e0jZBMNRXpzp0ZPvuT6GblUiHnAsC5W5lANs1QS9atVOm4ifrBiYY7AQ== - dependencies: - workbox-core "^5.1.4" - -workbox-google-analytics@^5.1.4: - version "5.1.4" - resolved "https://registry.npmjs.org/workbox-google-analytics/-/workbox-google-analytics-5.1.4.tgz" - integrity sha512-0IFhKoEVrreHpKgcOoddV+oIaVXBFKXUzJVBI+nb0bxmcwYuZMdteBTp8AEDJacENtc9xbR0wa9RDCnYsCDLjA== - dependencies: - workbox-background-sync "^5.1.4" - workbox-core "^5.1.4" - workbox-routing "^5.1.4" - workbox-strategies "^5.1.4" - -workbox-navigation-preload@^5.1.4: - version "5.1.4" - resolved "https://registry.npmjs.org/workbox-navigation-preload/-/workbox-navigation-preload-5.1.4.tgz" - integrity sha512-Wf03osvK0wTflAfKXba//QmWC5BIaIZARU03JIhAEO2wSB2BDROWI8Q/zmianf54kdV7e1eLaIEZhth4K4MyfQ== - dependencies: - workbox-core "^5.1.4" - -workbox-precaching@6.3.0, workbox-precaching@^6.1.5: - version "6.3.0" - resolved "https://registry.npmjs.org/workbox-precaching/-/workbox-precaching-6.3.0.tgz" - integrity sha512-bND3rUxiuzFmDfeKywdvOqK0LQ5LLbOPk0eX22PlMQNOOduHRxzglMpgHo/MR6h+8cPJ3GpxT8hZ895/7bHMqQ== - dependencies: - workbox-core "6.3.0" - workbox-routing "6.3.0" - workbox-strategies "6.3.0" - -workbox-precaching@^5.1.4: - version "5.1.4" - resolved "https://registry.npmjs.org/workbox-precaching/-/workbox-precaching-5.1.4.tgz" - integrity sha512-gCIFrBXmVQLFwvAzuGLCmkUYGVhBb7D1k/IL7pUJUO5xacjLcFUaLnnsoVepBGAiKw34HU1y/YuqvTKim9qAZA== - dependencies: - workbox-core "^5.1.4" - -workbox-range-requests@^5.1.4: - version "5.1.4" - resolved "https://registry.npmjs.org/workbox-range-requests/-/workbox-range-requests-5.1.4.tgz" - integrity sha512-1HSujLjgTeoxHrMR2muDW2dKdxqCGMc1KbeyGcmjZZAizJTFwu7CWLDmLv6O1ceWYrhfuLFJO+umYMddk2XMhw== - dependencies: - workbox-core "^5.1.4" - -workbox-recipes@^6.1.5: - version "6.3.0" - resolved "https://registry.npmjs.org/workbox-recipes/-/workbox-recipes-6.3.0.tgz" - integrity sha512-f0AZyxd48E4t+PV+ifgIf8WodfJqRj8/E0t+PwppDIdTPyD59cIh0HZBtgPKFdIMVnltodpMz4zioxym1H3GjQ== - dependencies: - workbox-cacheable-response "6.3.0" - workbox-core "6.3.0" - workbox-expiration "6.3.0" - workbox-precaching "6.3.0" - workbox-routing "6.3.0" - workbox-strategies "6.3.0" - -workbox-routing@6.3.0, workbox-routing@^6.1.5: - version "6.3.0" - resolved "https://registry.npmjs.org/workbox-routing/-/workbox-routing-6.3.0.tgz" - integrity sha512-asajX5UPkaoU4PB9pEpxKWKkcpA+KJQUEeYU6NlK0rXTCpdWQ6iieMRDoBTZBjTzUdL3j3s1Zo2qCOSvtXSYGg== - dependencies: - workbox-core "6.3.0" - -workbox-routing@^5.1.4: - version "5.1.4" - resolved "https://registry.npmjs.org/workbox-routing/-/workbox-routing-5.1.4.tgz" - integrity sha512-8ljknRfqE1vEQtnMtzfksL+UXO822jJlHTIR7+BtJuxQ17+WPZfsHqvk1ynR/v0EHik4x2+826Hkwpgh4GKDCw== - dependencies: - workbox-core "^5.1.4" - -workbox-strategies@6.3.0, workbox-strategies@^6.1.5: - version "6.3.0" - resolved "https://registry.npmjs.org/workbox-strategies/-/workbox-strategies-6.3.0.tgz" - integrity sha512-SYZt40y+Iu5nA+UEPQOrAuAMMNTxtUBPLCIaMMb4lcADpBYrNP1CD+/s2QsrxzS651a8hfi06REKt+uTp1tqfw== - dependencies: - workbox-core "6.3.0" - -workbox-strategies@^5.1.4: - version "5.1.4" - resolved "https://registry.npmjs.org/workbox-strategies/-/workbox-strategies-5.1.4.tgz" - integrity sha512-VVS57LpaJTdjW3RgZvPwX0NlhNmscR7OQ9bP+N/34cYMDzXLyA6kqWffP6QKXSkca1OFo/v6v7hW7zrrguo6EA== - dependencies: - workbox-core "^5.1.4" - workbox-routing "^5.1.4" - -workbox-streams@^5.1.4: - version "5.1.4" - resolved "https://registry.npmjs.org/workbox-streams/-/workbox-streams-5.1.4.tgz" - integrity sha512-xU8yuF1hI/XcVhJUAfbQLa1guQUhdLMPQJkdT0kn6HP5CwiPOGiXnSFq80rAG4b1kJUChQQIGPrq439FQUNVrw== - dependencies: - workbox-core "^5.1.4" - workbox-routing "^5.1.4" - -workbox-sw@^5.1.4: - version "5.1.4" - resolved "https://registry.npmjs.org/workbox-sw/-/workbox-sw-5.1.4.tgz" - integrity sha512-9xKnKw95aXwSNc8kk8gki4HU0g0W6KXu+xks7wFuC7h0sembFnTrKtckqZxbSod41TDaGh+gWUA5IRXrL0ECRA== - -workbox-webpack-plugin@^5.1.4: - version "5.1.4" - resolved "https://registry.npmjs.org/workbox-webpack-plugin/-/workbox-webpack-plugin-5.1.4.tgz" - integrity sha512-PZafF4HpugZndqISi3rZ4ZK4A4DxO8rAqt2FwRptgsDx7NF8TVKP86/huHquUsRjMGQllsNdn4FNl8CD/UvKmQ== - dependencies: - "@babel/runtime" "^7.5.5" - fast-json-stable-stringify "^2.0.0" - source-map-url "^0.4.0" - upath "^1.1.2" - webpack-sources "^1.3.0" - workbox-build "^5.1.4" - -workbox-window@^5.1.4: - version "5.1.4" - resolved "https://registry.yarnpkg.com/workbox-window/-/workbox-window-5.1.4.tgz#2740f7dea7f93b99326179a62f1cc0ca2c93c863" - integrity sha512-vXQtgTeMCUq/4pBWMfQX8Ee7N2wVC4Q7XYFqLnfbXJ2hqew/cU1uMTD2KqGEgEpE4/30luxIxgE+LkIa8glBYw== - dependencies: - workbox-core "^5.1.4" - -workbox-window@^6.1.5: - version "6.3.0" - resolved "https://registry.npmjs.org/workbox-window/-/workbox-window-6.3.0.tgz" - integrity sha512-CFP84assX9srH/TOx4OD8z4EBPO/Cq4WKdV2YLcJIFJmVTS/cB63XKeidKl2KJk8qOOLVIKnaO7BLmb0MxGFtA== - dependencies: - "@types/trusted-types" "^2.0.2" - workbox-core "6.3.0" - wrap-ansi@^6.2.0: version "6.2.0" resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz" @@ -6078,6 +4638,11 @@ yaml@^1.10.0: resolved "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz" integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== +yocto-queue@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" + integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== + yup@^0.29.3: version "0.29.3" resolved "https://registry.npmjs.org/yup/-/yup-0.29.3.tgz"