Selaa lähdekoodia

Switch to prettier defaults (#1656)

Manav Rathi 1 vuosi sitten
vanhempi
commit
8b1d33e83d
100 muutettua tiedostoa jossa 1317 lisäystä ja 1265 poistoa
  1. 0 3
      .github/.prettierrc.json
  2. 1 3
      .prettierrc.json
  3. 4 4
      apps/accounts/.eslintrc.js
  4. 1 1
      apps/accounts/next.config.js
  5. 2 2
      apps/accounts/sentry.client.config.ts
  6. 32 30
      apps/accounts/src/pages/_app.tsx
  7. 1 1
      apps/accounts/src/pages/_document.tsx
  8. 13 13
      apps/accounts/src/pages/account-handoff.tsx
  9. 5 5
      apps/accounts/src/pages/credentials/index.tsx
  10. 5 5
      apps/accounts/src/pages/generate/index.tsx
  11. 3 3
      apps/accounts/src/pages/index.tsx
  12. 5 5
      apps/accounts/src/pages/login/index.tsx
  13. 21 18
      apps/accounts/src/pages/passkeys/DeletePasskeyModal.tsx
  14. 24 23
      apps/accounts/src/pages/passkeys/ManagePasskeyDrawer.tsx
  15. 6 6
      apps/accounts/src/pages/passkeys/PasskeyListItem.tsx
  16. 5 5
      apps/accounts/src/pages/passkeys/PasskeysList.tsx
  17. 13 12
      apps/accounts/src/pages/passkeys/RenamePasskeyModal.tsx
  18. 1 1
      apps/accounts/src/pages/passkeys/finish.tsx
  19. 60 53
      apps/accounts/src/pages/passkeys/flow/index.tsx
  20. 35 33
      apps/accounts/src/pages/passkeys/index.tsx
  21. 5 5
      apps/accounts/src/pages/recover/index.tsx
  22. 5 5
      apps/accounts/src/pages/signup/index.tsx
  23. 5 5
      apps/accounts/src/pages/two-factor/recover/index.tsx
  24. 5 5
      apps/accounts/src/pages/two-factor/setup/index.tsx
  25. 5 5
      apps/accounts/src/pages/two-factor/verify/index.tsx
  26. 5 5
      apps/accounts/src/pages/verify/index.tsx
  27. 30 30
      apps/accounts/src/services/passkeysService.ts
  28. 12 12
      apps/accounts/src/styles/global.css
  29. 4 4
      apps/auth/.eslintrc.js
  30. 1 1
      apps/auth/next.config.js
  31. 2 2
      apps/auth/sentry.client.config.ts
  32. 10 9
      apps/auth/src/components/AuthFooter.tsx
  33. 19 17
      apps/auth/src/components/Navbar.tsx
  34. 86 76
      apps/auth/src/components/OTPDisplay.tsx
  35. 4 4
      apps/auth/src/components/TimerProgress.tsx
  36. 5 5
      apps/auth/src/pages/404.tsx
  37. 55 53
      apps/auth/src/pages/_app.tsx
  38. 1 1
      apps/auth/src/pages/_document.tsx
  39. 5 5
      apps/auth/src/pages/_error.tsx
  40. 45 42
      apps/auth/src/pages/auth/index.tsx
  41. 5 5
      apps/auth/src/pages/change-email/index.tsx
  42. 5 5
      apps/auth/src/pages/change-password/index.tsx
  43. 5 5
      apps/auth/src/pages/credentials/index.tsx
  44. 5 5
      apps/auth/src/pages/generate/index.tsx
  45. 3 3
      apps/auth/src/pages/index.tsx
  46. 5 5
      apps/auth/src/pages/login/index.tsx
  47. 5 5
      apps/auth/src/pages/recover/index.tsx
  48. 5 5
      apps/auth/src/pages/signup/index.tsx
  49. 5 5
      apps/auth/src/pages/two-factor/recover/index.tsx
  50. 5 5
      apps/auth/src/pages/two-factor/setup/index.tsx
  51. 5 5
      apps/auth/src/pages/two-factor/verify/index.tsx
  52. 5 5
      apps/auth/src/pages/verify/index.tsx
  53. 24 24
      apps/auth/src/services/index.ts
  54. 50 50
      apps/auth/src/types/code.ts
  55. 4 4
      apps/cast/.eslintrc.js
  56. 1 1
      apps/cast/next.config.js
  57. 2 2
      apps/cast/sentry.client.config.ts
  58. 5 4
      apps/cast/src/components/FilledCircleCheck/index.tsx
  59. 39 35
      apps/cast/src/components/LargeType.tsx
  60. 21 17
      apps/cast/src/components/PairedSuccessfullyOverlay.tsx
  61. 25 23
      apps/cast/src/components/Theatre/PhotoAuditorium.tsx
  62. 14 12
      apps/cast/src/components/Theatre/VideoAuditorium.tsx
  63. 2 2
      apps/cast/src/components/Theatre/index.tsx
  64. 6 6
      apps/cast/src/components/TimerBar.tsx
  65. 11 11
      apps/cast/src/constants/apps.ts
  66. 3 3
      apps/cast/src/constants/cache.ts
  67. 20 20
      apps/cast/src/constants/collection.ts
  68. 3 3
      apps/cast/src/constants/ffmpeg.ts
  69. 25 25
      apps/cast/src/constants/file.ts
  70. 2 2
      apps/cast/src/constants/gallery.ts
  71. 16 16
      apps/cast/src/constants/pages.ts
  72. 54 54
      apps/cast/src/constants/upload.ts
  73. 9 9
      apps/cast/src/constants/urls.ts
  74. 9 8
      apps/cast/src/pages/_app.tsx
  75. 11 9
      apps/cast/src/pages/_document.tsx
  76. 67 60
      apps/cast/src/pages/index.tsx
  77. 24 24
      apps/cast/src/pages/slideshow.tsx
  78. 3 3
      apps/cast/src/services/InMemoryStore.ts
  79. 2 2
      apps/cast/src/services/cache/cacheStorageFactory.ts
  80. 6 6
      apps/cast/src/services/cache/cacheStorageService.ts
  81. 44 44
      apps/cast/src/services/cast/castService.ts
  82. 38 38
      apps/cast/src/services/castDownloadManager.ts
  83. 4 4
      apps/cast/src/services/events.ts
  84. 3 3
      apps/cast/src/services/ffmpeg/ffmpegFactory.ts
  85. 10 10
      apps/cast/src/services/ffmpeg/ffmpegService.ts
  86. 3 3
      apps/cast/src/services/heicConversionService.ts
  87. 12 12
      apps/cast/src/services/livePhotoService.ts
  88. 3 3
      apps/cast/src/services/queueProcessor.ts
  89. 14 14
      apps/cast/src/services/readerService.ts
  90. 19 19
      apps/cast/src/services/typeDetectionService.ts
  91. 26 26
      apps/cast/src/services/wasm/ffmpeg.ts
  92. 3 3
      apps/cast/src/services/wasmHeicConverter/wasmHEICConverterClient.ts
  93. 24 24
      apps/cast/src/services/wasmHeicConverter/wasmHEICConverterService.ts
  94. 14 14
      apps/cast/src/types/collection/index.ts
  95. 7 7
      apps/cast/src/types/file/index.ts
  96. 3 3
      apps/cast/src/types/gallery/index.ts
  97. 9 9
      apps/cast/src/types/upload/index.ts
  98. 1 1
      apps/cast/src/types/upload/ui.ts
  99. 12 12
      apps/cast/src/utils/collection/index.ts
  100. 6 6
      apps/cast/src/utils/comlink/ComlinkConvertWorker.ts

+ 0 - 3
.github/.prettierrc.json

@@ -1,3 +0,0 @@
-{
-    "tabWidth": 4
-}

+ 1 - 3
.prettierrc.json

@@ -1,6 +1,4 @@
 {
     "tabWidth": 4,
-    "trailingComma": "es5",
-    "singleQuote": true,
-    "bracketSameLine": true
+    "plugins": ["prettier-plugin-organize-imports"]
 }

+ 4 - 4
apps/accounts/.eslintrc.js

@@ -3,11 +3,11 @@ module.exports = {
     // This is required here to ensure desktop picks the right eslint config, where this app is
     // packaged as a submodule.
     root: true,
-    extends: ['@ente/eslint-config'],
-    parser: '@typescript-eslint/parser',
+    extends: ["@ente/eslint-config"],
+    parser: "@typescript-eslint/parser",
     parserOptions: {
         tsconfigRootDir: __dirname,
-        project: './tsconfig.json',
+        project: "./tsconfig.json",
     },
-    ignorePatterns: ['.eslintrc.js', 'out'],
+    ignorePatterns: [".eslintrc.js", "out"],
 };

+ 1 - 1
apps/accounts/next.config.js

@@ -1,4 +1,4 @@
-const nextConfigBase = require('@/next/next.config.base.js');
+const nextConfigBase = require("@/next/next.config.base.js");
 
 module.exports = {
     ...nextConfigBase,

+ 2 - 2
apps/accounts/sentry.client.config.ts

@@ -1,3 +1,3 @@
-import { initSentry } from '@ente/shared/sentry/config/sentry.config.base';
+import { initSentry } from "@ente/shared/sentry/config/sentry.config.base";
 
-initSentry('https://0f7214c7feb9b1dd2fed5db09b42fa1b@sentry.ente.io/5');
+initSentry("https://0f7214c7feb9b1dd2fed5db09b42fa1b@sentry.ente.io/5");

+ 32 - 30
apps/accounts/src/pages/_app.tsx

@@ -1,27 +1,27 @@
-import { CacheProvider } from '@emotion/react';
-import { APPS, APP_TITLES } from '@ente/shared/apps/constants';
-import { EnteAppProps } from '@ente/shared/apps/types';
-import { Overlay } from '@ente/shared/components/Container';
-import DialogBoxV2 from '@ente/shared/components/DialogBoxV2';
+import { setupI18n } from "@/ui/i18n";
+import { CacheProvider } from "@emotion/react";
+import { APPS, APP_TITLES } from "@ente/shared/apps/constants";
+import { EnteAppProps } from "@ente/shared/apps/types";
+import { Overlay } from "@ente/shared/components/Container";
+import DialogBoxV2 from "@ente/shared/components/DialogBoxV2";
 import {
     DialogBoxAttributesV2,
     SetDialogBoxAttributesV2,
-} from '@ente/shared/components/DialogBoxV2/types';
-import EnteSpinner from '@ente/shared/components/EnteSpinner';
-import AppNavbar from '@ente/shared/components/Navbar/app';
-import { useLocalState } from '@ente/shared/hooks/useLocalState';
-import { setupI18n } from '@/ui/i18n';
-import HTTPService from '@ente/shared/network/HTTPService';
-import { LS_KEYS, getData } from '@ente/shared/storage/localStorage';
-import { getTheme } from '@ente/shared/themes';
-import { THEME_COLOR } from '@ente/shared/themes/constants';
-import createEmotionCache from '@ente/shared/themes/createEmotionCache';
-import { CssBaseline, useMediaQuery } from '@mui/material';
-import { ThemeProvider } from '@mui/material/styles';
-import Head from 'next/head';
-import { useRouter } from 'next/router';
-import { createContext, useEffect, useState } from 'react';
-import 'styles/global.css';
+} from "@ente/shared/components/DialogBoxV2/types";
+import EnteSpinner from "@ente/shared/components/EnteSpinner";
+import AppNavbar from "@ente/shared/components/Navbar/app";
+import { useLocalState } from "@ente/shared/hooks/useLocalState";
+import HTTPService from "@ente/shared/network/HTTPService";
+import { LS_KEYS, getData } from "@ente/shared/storage/localStorage";
+import { getTheme } from "@ente/shared/themes";
+import { THEME_COLOR } from "@ente/shared/themes/constants";
+import createEmotionCache from "@ente/shared/themes/createEmotionCache";
+import { CssBaseline, useMediaQuery } from "@mui/material";
+import { ThemeProvider } from "@mui/material/styles";
+import Head from "next/head";
+import { useRouter } from "next/router";
+import { createContext, useEffect, useState } from "react";
+import "styles/global.css";
 
 interface AppContextProps {
     isMobile: boolean;
@@ -50,7 +50,7 @@ export default function App(props: EnteAppProps) {
 
     const showNavBar = (show: boolean) => setShowNavBar(show);
 
-    const isMobile = useMediaQuery('(max-width:428px)');
+    const isMobile = useMediaQuery("(max-width:428px)");
 
     const router = useRouter();
 
@@ -70,14 +70,14 @@ export default function App(props: EnteAppProps) {
         const pkg = getData(LS_KEYS.CLIENT_PACKAGE);
         if (!pkg) return;
         HTTPService.setHeaders({
-            'X-Client-Package': pkg.name,
+            "X-Client-Package": pkg.name,
         });
     };
 
     useEffect(() => {
-        router.events.on('routeChangeComplete', setupPackageName);
+        router.events.on("routeChangeComplete", setupPackageName);
         return () => {
-            router.events.off('routeChangeComplete', setupPackageName);
+            router.events.off("routeChangeComplete", setupPackageName);
         };
     }, [router.events]);
 
@@ -111,17 +111,19 @@ export default function App(props: EnteAppProps) {
                         showNavBar,
                         setDialogBoxAttributesV2:
                             setDialogBoxAttributesV2 as any,
-                    }}>
+                    }}
+                >
                     {!isI18nReady && (
                         <Overlay
                             sx={(theme) => ({
-                                display: 'flex',
-                                justifyContent: 'center',
-                                alignItems: 'center',
+                                display: "flex",
+                                justifyContent: "center",
+                                alignItems: "center",
                                 zIndex: 2000,
                                 backgroundColor: (theme as any).colors
                                     .background.base,
-                            })}>
+                            })}
+                        >
                             <EnteSpinner />
                         </Overlay>
                     )}

+ 1 - 1
apps/accounts/src/pages/_document.tsx

@@ -1,6 +1,6 @@
 import DocumentPage, {
     EnteDocumentProps,
-} from '@ente/shared/next/pages/_document';
+} from "@ente/shared/next/pages/_document";
 
 export default function Document(props: EnteDocumentProps) {
     return <DocumentPage {...props} />;

+ 13 - 13
apps/accounts/src/pages/account-handoff.tsx

@@ -1,11 +1,11 @@
-import { VerticallyCentered } from '@ente/shared/components/Container';
-import EnteSpinner from '@ente/shared/components/EnteSpinner';
-import { ACCOUNTS_PAGES } from '@ente/shared/constants/pages';
-import HTTPService from '@ente/shared/network/HTTPService';
-import { logError } from '@ente/shared/sentry';
-import { LS_KEYS, getData, setData } from '@ente/shared/storage/localStorage';
-import { useRouter } from 'next/router';
-import { useEffect } from 'react';
+import { VerticallyCentered } from "@ente/shared/components/Container";
+import EnteSpinner from "@ente/shared/components/EnteSpinner";
+import { ACCOUNTS_PAGES } from "@ente/shared/constants/pages";
+import HTTPService from "@ente/shared/network/HTTPService";
+import { logError } from "@ente/shared/sentry";
+import { LS_KEYS, getData, setData } from "@ente/shared/storage/localStorage";
+import { useRouter } from "next/router";
+import { useEffect } from "react";
 
 const AccountHandoff = () => {
     const router = useRouter();
@@ -16,26 +16,26 @@ const AccountHandoff = () => {
 
             router.push(ACCOUNTS_PAGES.PASSKEYS);
         } catch (e) {
-            logError(e, 'Failed to deserialize and set passed user data');
+            logError(e, "Failed to deserialize and set passed user data");
             router.push(ACCOUNTS_PAGES.LOGIN);
         }
     };
 
     const getClientPackageName = () => {
         const urlParams = new URLSearchParams(window.location.search);
-        const pkg = urlParams.get('package');
+        const pkg = urlParams.get("package");
         if (!pkg) return;
         setData(LS_KEYS.CLIENT_PACKAGE, { name: pkg });
         HTTPService.setHeaders({
-            'X-Client-Package': pkg,
+            "X-Client-Package": pkg,
         });
     };
 
     const extractAccountsToken = () => {
         const urlParams = new URLSearchParams(window.location.search);
-        const token = urlParams.get('token');
+        const token = urlParams.get("token");
         if (!token) {
-            throw new Error('token not found');
+            throw new Error("token not found");
         }
 
         const user = getData(LS_KEYS.USER) || {};

+ 5 - 5
apps/accounts/src/pages/credentials/index.tsx

@@ -1,8 +1,8 @@
-import CredentialPage from '@ente/accounts/pages/credentials';
-import { useRouter } from 'next/router';
-import { AppContext } from '../_app';
-import { useContext } from 'react';
-import { APPS } from '@ente/shared/apps/constants';
+import CredentialPage from "@ente/accounts/pages/credentials";
+import { APPS } from "@ente/shared/apps/constants";
+import { useRouter } from "next/router";
+import { useContext } from "react";
+import { AppContext } from "../_app";
 
 export default function Credential() {
     const appContext = useContext(AppContext);

+ 5 - 5
apps/accounts/src/pages/generate/index.tsx

@@ -1,8 +1,8 @@
-import GeneratePage from '@ente/accounts/pages/generate';
-import { APPS } from '@ente/shared/apps/constants';
-import { useRouter } from 'next/router';
-import { AppContext } from 'pages/_app';
-import { useContext } from 'react';
+import GeneratePage from "@ente/accounts/pages/generate";
+import { APPS } from "@ente/shared/apps/constants";
+import { useRouter } from "next/router";
+import { AppContext } from "pages/_app";
+import { useContext } from "react";
 
 export default function Generate() {
     const appContext = useContext(AppContext);

+ 3 - 3
apps/accounts/src/pages/index.tsx

@@ -1,11 +1,11 @@
-import { useRouter } from 'next/router';
-import { useEffect } from 'react';
+import { useRouter } from "next/router";
+import { useEffect } from "react";
 
 const Index = () => {
     const router = useRouter();
 
     useEffect(() => {
-        router.push('/login');
+        router.push("/login");
     }, []);
     return <></>;
 };

+ 5 - 5
apps/accounts/src/pages/login/index.tsx

@@ -1,8 +1,8 @@
-import LoginPage from '@ente/accounts/pages/login';
-import { useRouter } from 'next/router';
-import { AppContext } from '../_app';
-import { useContext } from 'react';
-import { APPS } from '@ente/shared/apps/constants';
+import LoginPage from "@ente/accounts/pages/login";
+import { APPS } from "@ente/shared/apps/constants";
+import { useRouter } from "next/router";
+import { useContext } from "react";
+import { AppContext } from "../_app";
 
 export default function Login() {
     const appContext = useContext(AppContext);

+ 21 - 18
apps/accounts/src/pages/passkeys/DeletePasskeyModal.tsx

@@ -1,11 +1,11 @@
-import DialogBoxV2 from '@ente/shared/components/DialogBoxV2';
-import EnteButton from '@ente/shared/components/EnteButton';
-import { Button, Stack, Typography } from '@mui/material';
-import { AppContext } from 'pages/_app';
-import { useContext, useState } from 'react';
-import { deletePasskey } from 'services/passkeysService';
-import { PasskeysContext } from '.';
-import { t } from 'i18next';
+import DialogBoxV2 from "@ente/shared/components/DialogBoxV2";
+import EnteButton from "@ente/shared/components/EnteButton";
+import { Button, Stack, Typography } from "@mui/material";
+import { t } from "i18next";
+import { AppContext } from "pages/_app";
+import { useContext, useState } from "react";
+import { deletePasskey } from "services/passkeysService";
+import { PasskeysContext } from ".";
 
 interface IProps {
     open: boolean;
@@ -41,27 +41,30 @@ const DeletePasskeyModal = (props: IProps) => {
             onClose={props.onClose}
             fullScreen={isMobile}
             attributes={{
-                title: t('DELETE_PASSKEY'),
+                title: t("DELETE_PASSKEY"),
                 secondary: {
                     action: props.onClose,
-                    text: t('CANCEL'),
+                    text: t("CANCEL"),
                 },
-            }}>
-            <Stack spacing={'8px'}>
-                <Typography>{t('DELETE_PASSKEY_CONFIRMATION')}</Typography>
+            }}
+        >
+            <Stack spacing={"8px"}>
+                <Typography>{t("DELETE_PASSKEY_CONFIRMATION")}</Typography>
                 <EnteButton
                     type="submit"
                     size="large"
                     color="critical"
                     loading={loading}
-                    onClick={doDelete}>
-                    {t('DELETE')}
+                    onClick={doDelete}
+                >
+                    {t("DELETE")}
                 </EnteButton>
                 <Button
                     size="large"
-                    color={'secondary'}
-                    onClick={props.onClose}>
-                    {t('CANCEL')}
+                    color={"secondary"}
+                    onClick={props.onClose}
+                >
+                    {t("CANCEL")}
                 </Button>
             </Stack>
         </DialogBoxV2>

+ 24 - 23
apps/accounts/src/pages/passkeys/ManagePasskeyDrawer.tsx

@@ -1,19 +1,19 @@
-import { EnteDrawer } from '@ente/shared/components/EnteDrawer';
-import { PasskeysContext } from '.';
-import { Stack } from '@mui/material';
-import Titlebar from '@ente/shared/components/Titlebar';
-import { MenuItemGroup } from '@ente/shared/components/Menu/MenuItemGroup';
-import { EnteMenuItem } from '@ente/shared/components/Menu/EnteMenuItem';
-import { useContext, useState } from 'react';
-import EditIcon from '@mui/icons-material/Edit';
-import DeleteIcon from '@mui/icons-material/Delete';
-import MenuItemDivider from '@ente/shared/components/Menu/MenuItemDivider';
-import DeletePasskeyModal from './DeletePasskeyModal';
-import RenamePasskeyModal from './RenamePasskeyModal';
-import InfoItem from '@ente/shared/components/Info/InfoItem';
-import CalendarTodayIcon from '@mui/icons-material/CalendarToday';
-import { formatDateTimeFull } from '@ente/shared/time/format';
-import { t } from 'i18next';
+import { EnteDrawer } from "@ente/shared/components/EnteDrawer";
+import InfoItem from "@ente/shared/components/Info/InfoItem";
+import { EnteMenuItem } from "@ente/shared/components/Menu/EnteMenuItem";
+import MenuItemDivider from "@ente/shared/components/Menu/MenuItemDivider";
+import { MenuItemGroup } from "@ente/shared/components/Menu/MenuItemGroup";
+import Titlebar from "@ente/shared/components/Titlebar";
+import { formatDateTimeFull } from "@ente/shared/time/format";
+import CalendarTodayIcon from "@mui/icons-material/CalendarToday";
+import DeleteIcon from "@mui/icons-material/Delete";
+import EditIcon from "@mui/icons-material/Edit";
+import { Stack } from "@mui/material";
+import { t } from "i18next";
+import { useContext, useState } from "react";
+import { PasskeysContext } from ".";
+import DeletePasskeyModal from "./DeletePasskeyModal";
+import RenamePasskeyModal from "./RenamePasskeyModal";
 
 interface IProps {
     open: boolean;
@@ -33,10 +33,11 @@ const ManagePasskeyDrawer = (props: IProps) => {
                 open={props.open}
                 onClose={() => {
                     setShowPasskeyDrawer(false);
-                }}>
+                }}
+            >
                 {selectedPasskey && (
                     <>
-                        <Stack spacing={'4px'} py={'12px'}>
+                        <Stack spacing={"4px"} py={"12px"}>
                             <Titlebar
                                 onClose={() => {
                                     setShowPasskeyDrawer(false);
@@ -48,11 +49,11 @@ const ManagePasskeyDrawer = (props: IProps) => {
                             />
                             <InfoItem
                                 icon={<CalendarTodayIcon />}
-                                title={t('CREATED_AT')}
+                                title={t("CREATED_AT")}
                                 caption={
                                     `${formatDateTimeFull(
-                                        selectedPasskey.createdAt / 1000
-                                    )}` || ''
+                                        selectedPasskey.createdAt / 1000,
+                                    )}` || ""
                                 }
                                 loading={!selectedPasskey}
                                 hideEditOption
@@ -63,7 +64,7 @@ const ManagePasskeyDrawer = (props: IProps) => {
                                         setShowRenamePasskeyModal(true);
                                     }}
                                     startIcon={<EditIcon />}
-                                    label={'Rename Passkey'}
+                                    label={"Rename Passkey"}
                                 />
                                 <MenuItemDivider />
                                 <EnteMenuItem
@@ -71,7 +72,7 @@ const ManagePasskeyDrawer = (props: IProps) => {
                                         setShowDeletePasskeyModal(true);
                                     }}
                                     startIcon={<DeleteIcon />}
-                                    label={'Delete Passkey'}
+                                    label={"Delete Passkey"}
                                     color="critical"
                                 />
                             </MenuItemGroup>

+ 6 - 6
apps/accounts/src/pages/passkeys/PasskeyListItem.tsx

@@ -1,9 +1,9 @@
-import { EnteMenuItem } from '@ente/shared/components/Menu/EnteMenuItem';
-import { Passkey } from 'types/passkey';
-import ChevronRightIcon from '@mui/icons-material/ChevronRight';
-import { useContext } from 'react';
-import { PasskeysContext } from '.';
-import KeyIcon from '@mui/icons-material/Key';
+import { EnteMenuItem } from "@ente/shared/components/Menu/EnteMenuItem";
+import ChevronRightIcon from "@mui/icons-material/ChevronRight";
+import KeyIcon from "@mui/icons-material/Key";
+import { useContext } from "react";
+import { Passkey } from "types/passkey";
+import { PasskeysContext } from ".";
 
 interface IProps {
     passkey: Passkey;

+ 5 - 5
apps/accounts/src/pages/passkeys/PasskeysList.tsx

@@ -1,8 +1,8 @@
-import { MenuItemGroup } from '@ente/shared/components/Menu/MenuItemGroup';
-import { Passkey } from 'types/passkey';
-import PasskeyListItem from './PasskeyListItem';
-import MenuItemDivider from '@ente/shared/components/Menu/MenuItemDivider';
-import { Fragment } from 'react';
+import MenuItemDivider from "@ente/shared/components/Menu/MenuItemDivider";
+import { MenuItemGroup } from "@ente/shared/components/Menu/MenuItemGroup";
+import { Fragment } from "react";
+import { Passkey } from "types/passkey";
+import PasskeyListItem from "./PasskeyListItem";
 
 interface IProps {
     passkeys: Passkey[];

+ 13 - 12
apps/accounts/src/pages/passkeys/RenamePasskeyModal.tsx

@@ -1,10 +1,10 @@
-import DialogBoxV2 from '@ente/shared/components/DialogBoxV2';
-import { AppContext } from 'pages/_app';
-import { useContext } from 'react';
-import { PasskeysContext } from '.';
-import SingleInputForm from '@ente/shared/components/SingleInputForm';
-import { t } from 'i18next';
-import { renamePasskey } from 'services/passkeysService';
+import DialogBoxV2 from "@ente/shared/components/DialogBoxV2";
+import SingleInputForm from "@ente/shared/components/SingleInputForm";
+import { t } from "i18next";
+import { AppContext } from "pages/_app";
+import { useContext } from "react";
+import { renamePasskey } from "services/passkeysService";
+import { PasskeysContext } from ".";
 
 interface IProps {
     open: boolean;
@@ -34,17 +34,18 @@ const RenamePasskeyModal = (props: IProps) => {
             onClose={props.onClose}
             fullScreen={isMobile}
             attributes={{
-                title: t('RENAME_PASSKEY'),
+                title: t("RENAME_PASSKEY"),
                 secondary: {
                     action: props.onClose,
-                    text: t('CANCEL'),
+                    text: t("CANCEL"),
                 },
-            }}>
+            }}
+        >
             <SingleInputForm
                 initialValue={selectedPasskey?.friendlyName}
                 callback={onSubmit}
-                placeholder={t('ENTER_PASSKEY_NAME')}
-                buttonText={t('RENAME')}
+                placeholder={t("ENTER_PASSKEY_NAME")}
+                buttonText={t("RENAME")}
                 fieldType="text"
                 secondaryButtonAction={props.onClose}
                 submitButtonProps={{ sx: { mt: 1, mb: 2 } }}

+ 1 - 1
apps/accounts/src/pages/passkeys/finish.tsx

@@ -1,4 +1,4 @@
-import PasskeysFinishPage from '@ente/accounts/pages/passkeys/finish';
+import PasskeysFinishPage from "@ente/accounts/pages/passkeys/finish";
 const PasskeysFinish = () => {
     return <PasskeysFinishPage />;
 };

+ 60 - 53
apps/accounts/src/pages/passkeys/flow/index.tsx

@@ -1,25 +1,25 @@
-import { APPS, CLIENT_PACKAGE_NAMES } from '@ente/shared/apps/constants';
+import { APPS, CLIENT_PACKAGE_NAMES } from "@ente/shared/apps/constants";
 import {
     CenteredFlex,
     VerticallyCentered,
-} from '@ente/shared/components/Container';
-import EnteButton from '@ente/shared/components/EnteButton';
-import EnteSpinner from '@ente/shared/components/EnteSpinner';
-import FormPaper from '@ente/shared/components/Form/FormPaper';
-import HTTPService from '@ente/shared/network/HTTPService';
-import { logError } from '@ente/shared/sentry';
-import { LS_KEYS, setData } from '@ente/shared/storage/localStorage';
-import InfoIcon from '@mui/icons-material/Info';
-import { Box, Typography } from '@mui/material';
-import { t } from 'i18next';
-import _sodium from 'libsodium-wrappers';
-import Image from 'next/image';
-import { useEffect, useState } from 'react';
+} from "@ente/shared/components/Container";
+import EnteButton from "@ente/shared/components/EnteButton";
+import EnteSpinner from "@ente/shared/components/EnteSpinner";
+import FormPaper from "@ente/shared/components/Form/FormPaper";
+import HTTPService from "@ente/shared/network/HTTPService";
+import { logError } from "@ente/shared/sentry";
+import { LS_KEYS, setData } from "@ente/shared/storage/localStorage";
+import InfoIcon from "@mui/icons-material/Info";
+import { Box, Typography } from "@mui/material";
+import { t } from "i18next";
+import _sodium from "libsodium-wrappers";
+import Image from "next/image";
+import { useEffect, useState } from "react";
 import {
     BeginPasskeyAuthenticationResponse,
     beginPasskeyAuthentication,
     finishPasskeyAuthentication,
-} from 'services/passkeysService';
+} from "services/passkeysService";
 
 const PasskeysFlow = () => {
     const [errored, setErrored] = useState(false);
@@ -32,18 +32,18 @@ const PasskeysFlow = () => {
         const searchParams = new URLSearchParams(window.location.search);
 
         // get redirect from the query params
-        const redirect = searchParams.get('redirect') as string;
+        const redirect = searchParams.get("redirect") as string;
 
         const redirectURL = new URL(redirect);
-        if (process.env.NEXT_PUBLIC_DISABLE_REDIRECT_CHECK !== 'true') {
+        if (process.env.NEXT_PUBLIC_DISABLE_REDIRECT_CHECK !== "true") {
             if (
-                redirect !== '' &&
+                redirect !== "" &&
                 !(
-                    redirectURL.host.endsWith('.ente.io') ||
-                    redirectURL.host.endsWith('bada-frame.pages.dev')
+                    redirectURL.host.endsWith(".ente.io") ||
+                    redirectURL.host.endsWith("bada-frame.pages.dev")
                 ) &&
-                redirectURL.protocol !== 'ente:' &&
-                redirectURL.protocol !== 'enteauth:'
+                redirectURL.protocol !== "ente:" &&
+                redirectURL.protocol !== "enteauth:"
             ) {
                 setInvalidInfo(true);
                 setLoading(false);
@@ -52,19 +52,19 @@ const PasskeysFlow = () => {
         }
 
         let pkg = CLIENT_PACKAGE_NAMES.get(APPS.PHOTOS);
-        if (redirectURL.protocol === 'enteauth:') {
+        if (redirectURL.protocol === "enteauth:") {
             pkg = CLIENT_PACKAGE_NAMES.get(APPS.AUTH);
-        } else if (redirectURL.hostname.startsWith('accounts')) {
+        } else if (redirectURL.hostname.startsWith("accounts")) {
             pkg = CLIENT_PACKAGE_NAMES.get(APPS.ACCOUNTS);
         }
 
         setData(LS_KEYS.CLIENT_PACKAGE, { name: pkg });
         HTTPService.setHeaders({
-            'X-Client-Package': pkg,
+            "X-Client-Package": pkg,
         });
 
         // get passkeySessionID from the query params
-        const passkeySessionID = searchParams.get('passkeySessionID') as string;
+        const passkeySessionID = searchParams.get("passkeySessionID") as string;
 
         setLoading(true);
 
@@ -100,7 +100,7 @@ const PasskeysFlow = () => {
 
         if (!credential) {
             if (!isWebAuthnSupported()) {
-                alert('WebAuthn is not supported in this browser');
+                alert("WebAuthn is not supported in this browser");
             }
             setErrored(true);
             return;
@@ -114,7 +114,7 @@ const PasskeysFlow = () => {
             finishData = await finishAuthentication(
                 credential,
                 passkeySessionID,
-                beginData.ceremonySessionID
+                beginData.ceremonySessionID,
             );
         } catch (e) {
             logError(e, "Couldn't finish passkey authentication");
@@ -142,28 +142,28 @@ const PasskeysFlow = () => {
 
     const getCredential = async (
         publicKey: any,
-        timeoutMillis: number = 60000 // Default timeout of 60 seconds
+        timeoutMillis: number = 60000, // Default timeout of 60 seconds
     ): Promise<Credential | null> => {
         publicKey.challenge = _sodium.from_base64(
             publicKey.challenge,
-            _sodium.base64_variants.URLSAFE_NO_PADDING
+            _sodium.base64_variants.URLSAFE_NO_PADDING,
         );
         publicKey.allowCredentials?.forEach(function (listItem: any) {
             listItem.id = _sodium.from_base64(
                 listItem.id,
-                _sodium.base64_variants.URLSAFE_NO_PADDING
+                _sodium.base64_variants.URLSAFE_NO_PADDING,
             );
             // note: we are orverwriting the transports array with all possible values.
             // This is because the browser will only prompt the user for the transport that is available.
             // Warning: In case of invalid transport value, the webauthn will fail on Safari & iOS browsers
-            listItem.transports = ['usb', 'nfc', 'ble', 'internal'];
+            listItem.transports = ["usb", "nfc", "ble", "internal"];
         });
         publicKey.timeout = timeoutMillis;
         const publicKeyCredentialCreationOptions: CredentialRequestOptions = {
             publicKey: publicKey,
         };
         const credential = await navigator.credentials.get(
-            publicKeyCredentialCreationOptions
+            publicKeyCredentialCreationOptions,
         );
         return credential;
     };
@@ -171,12 +171,12 @@ const PasskeysFlow = () => {
     const finishAuthentication = async (
         credential: Credential,
         sessionId: string,
-        ceremonySessionId: string
+        ceremonySessionId: string,
     ) => {
         const data = await finishPasskeyAuthentication(
             credential,
             sessionId,
-            ceremonySessionId
+            ceremonySessionId,
         );
         return data;
     };
@@ -199,18 +199,20 @@ const PasskeysFlow = () => {
                 display="flex"
                 justifyContent="center"
                 alignItems="center"
-                height="100%">
+                height="100%"
+            >
                 <Box maxWidth="30rem">
                     <FormPaper
                         style={{
-                            padding: '1rem',
-                        }}>
+                            padding: "1rem",
+                        }}
+                    >
                         <InfoIcon />
                         <Typography fontWeight="bold" variant="h1">
-                            {t('PASSKEY_LOGIN_FAILED')}
+                            {t("PASSKEY_LOGIN_FAILED")}
                         </Typography>
                         <Typography marginTop="1rem">
-                            {t('PASSKEY_LOGIN_URL_INVALID')}
+                            {t("PASSKEY_LOGIN_URL_INVALID")}
                         </Typography>
                     </FormPaper>
                 </Box>
@@ -224,18 +226,20 @@ const PasskeysFlow = () => {
                 display="flex"
                 justifyContent="center"
                 alignItems="center"
-                height="100%">
+                height="100%"
+            >
                 <Box maxWidth="30rem">
                     <FormPaper
                         style={{
-                            padding: '1rem',
-                        }}>
+                            padding: "1rem",
+                        }}
+                    >
                         <InfoIcon />
                         <Typography fontWeight="bold" variant="h1">
-                            {t('PASSKEY_LOGIN_FAILED')}
+                            {t("PASSKEY_LOGIN_FAILED")}
                         </Typography>
                         <Typography marginTop="1rem">
-                            {t('PASSKEY_LOGIN_ERRORED')}
+                            {t("PASSKEY_LOGIN_ERRORED")}
                         </Typography>
                         <EnteButton
                             onClick={() => {
@@ -244,12 +248,13 @@ const PasskeysFlow = () => {
                             }}
                             fullWidth
                             style={{
-                                marginTop: '1rem',
+                                marginTop: "1rem",
                             }}
                             color="primary"
                             type="button"
-                            variant="contained">
-                            {t('TRY_AGAIN')}
+                            variant="contained"
+                        >
+                            {t("TRY_AGAIN")}
                         </EnteButton>
                     </FormPaper>
                 </Box>
@@ -263,18 +268,20 @@ const PasskeysFlow = () => {
                 display="flex"
                 justifyContent="center"
                 alignItems="center"
-                height="100%">
+                height="100%"
+            >
                 <Box maxWidth="30rem">
                     <FormPaper
                         style={{
-                            padding: '1rem',
-                        }}>
+                            padding: "1rem",
+                        }}
+                    >
                         <InfoIcon />
                         <Typography fontWeight="bold" variant="h1">
-                            {t('LOGIN_WITH_PASSKEY')}
+                            {t("LOGIN_WITH_PASSKEY")}
                         </Typography>
                         <Typography marginTop="1rem">
-                            {t('PASSKEY_FOLLOW_THE_STEPS_FROM_YOUR_BROWSER')}
+                            {t("PASSKEY_FOLLOW_THE_STEPS_FROM_YOUR_BROWSER")}
                         </Typography>
                         <CenteredFlex marginTop="1rem">
                             <Image

+ 35 - 33
apps/accounts/src/pages/passkeys/index.tsx

@@ -1,14 +1,14 @@
-import { CenteredFlex } from '@ente/shared/components/Container';
-import FormPaper from '@ente/shared/components/Form/FormPaper';
-import SingleInputForm from '@ente/shared/components/SingleInputForm';
-import { ACCOUNTS_PAGES } from '@ente/shared/constants/pages';
-import { logError } from '@ente/shared/sentry';
-import { getToken } from '@ente/shared/storage/localStorage/helpers';
-import { Box, Typography } from '@mui/material';
-import { t } from 'i18next';
-import _sodium from 'libsodium-wrappers';
-import { useRouter } from 'next/router';
-import { AppContext } from 'pages/_app';
+import { CenteredFlex } from "@ente/shared/components/Container";
+import FormPaper from "@ente/shared/components/Form/FormPaper";
+import SingleInputForm from "@ente/shared/components/SingleInputForm";
+import { ACCOUNTS_PAGES } from "@ente/shared/constants/pages";
+import { logError } from "@ente/shared/sentry";
+import { getToken } from "@ente/shared/storage/localStorage/helpers";
+import { Box, Typography } from "@mui/material";
+import { t } from "i18next";
+import _sodium from "libsodium-wrappers";
+import { useRouter } from "next/router";
+import { AppContext } from "pages/_app";
 import {
     Dispatch,
     SetStateAction,
@@ -16,15 +16,15 @@ import {
     useContext,
     useEffect,
     useState,
-} from 'react';
-import { Passkey } from 'types/passkey';
+} from "react";
+import { Passkey } from "types/passkey";
 import {
     finishPasskeyRegistration,
     getPasskeyRegistrationOptions,
     getPasskeys,
-} from '../../services/passkeysService';
-import ManagePasskeyDrawer from './ManagePasskeyDrawer';
-import PasskeysList from './PasskeysList';
+} from "../../services/passkeysService";
+import ManagePasskeyDrawer from "./ManagePasskeyDrawer";
+import PasskeysList from "./PasskeysList";
 
 export const PasskeysContext = createContext(
     {} as {
@@ -32,14 +32,14 @@ export const PasskeysContext = createContext(
         setSelectedPasskey: Dispatch<SetStateAction<Passkey | null>>;
         setShowPasskeyDrawer: Dispatch<SetStateAction<boolean>>;
         refreshPasskeys: () => void;
-    }
+    },
 );
 
 const Passkeys = () => {
     const { showNavBar } = useContext(AppContext);
 
     const [selectedPasskey, setSelectedPasskey] = useState<Passkey | null>(
-        null
+        null,
     );
 
     const [showPasskeyDrawer, setShowPasskeyDrawer] = useState(false);
@@ -69,7 +69,7 @@ const Passkeys = () => {
     const handleSubmit = async (
         inputValue: string,
         setFieldError: (errorMessage: string) => void,
-        resetForm: (nextState?: unknown) => void
+        resetForm: (nextState?: unknown) => void,
     ) => {
         let response: {
             options: {
@@ -81,7 +81,7 @@ const Passkeys = () => {
         try {
             response = await getPasskeyRegistrationOptions();
         } catch {
-            setFieldError('Failed to begin registration');
+            setFieldError("Failed to begin registration");
             return;
         }
 
@@ -90,12 +90,12 @@ const Passkeys = () => {
         options.publicKey.challenge = _sodium.from_base64(
             // eslint-disable-next-line @typescript-eslint/ban-ts-comment
             // @ts-ignore
-            options.publicKey.challenge
+            options.publicKey.challenge,
         );
         options.publicKey.user.id = _sodium.from_base64(
             // eslint-disable-next-line @typescript-eslint/ban-ts-comment
             // @ts-ignore
-            options.publicKey.user.id
+            options.publicKey.user.id,
         );
 
         // create new credential
@@ -104,8 +104,8 @@ const Passkeys = () => {
         try {
             newCredential = await navigator.credentials.create(options);
         } catch (e) {
-            logError(e, 'Error creating credential');
-            setFieldError('Failed to create credential');
+            logError(e, "Error creating credential");
+            setFieldError("Failed to create credential");
             return;
         }
 
@@ -113,10 +113,10 @@ const Passkeys = () => {
             await finishPasskeyRegistration(
                 inputValue,
                 newCredential,
-                response.sessionID
+                response.sessionID,
             );
         } catch {
-            setFieldError('Failed to finish registration');
+            setFieldError("Failed to finish registration");
             return;
         }
 
@@ -132,21 +132,23 @@ const Passkeys = () => {
                     setSelectedPasskey,
                     setShowPasskeyDrawer,
                     refreshPasskeys: init,
-                }}>
+                }}
+            >
                 <CenteredFlex>
                     <Box maxWidth="20rem">
                         <Box marginBottom="1rem">
-                            <Typography>{t('PASSKEYS_DESCRIPTION')}</Typography>
+                            <Typography>{t("PASSKEYS_DESCRIPTION")}</Typography>
                         </Box>
                         <FormPaper
                             style={{
-                                padding: '1rem',
-                            }}>
+                                padding: "1rem",
+                            }}
+                        >
                             <SingleInputForm
                                 fieldType="text"
-                                placeholder={t('ENTER_PASSKEY_NAME')}
-                                buttonText={t('ADD_PASSKEY')}
-                                initialValue={''}
+                                placeholder={t("ENTER_PASSKEY_NAME")}
+                                buttonText={t("ADD_PASSKEY")}
+                                initialValue={""}
                                 callback={handleSubmit}
                                 submitButtonProps={{
                                     sx: {

+ 5 - 5
apps/accounts/src/pages/recover/index.tsx

@@ -1,8 +1,8 @@
-import RecoverPage from '@ente/accounts/pages/recover';
-import { useRouter } from 'next/router';
-import { AppContext } from 'pages/_app';
-import { useContext } from 'react';
-import { APPS } from '@ente/shared/apps/constants';
+import RecoverPage from "@ente/accounts/pages/recover";
+import { APPS } from "@ente/shared/apps/constants";
+import { useRouter } from "next/router";
+import { AppContext } from "pages/_app";
+import { useContext } from "react";
 
 export default function Recover() {
     const appContext = useContext(AppContext);

+ 5 - 5
apps/accounts/src/pages/signup/index.tsx

@@ -1,8 +1,8 @@
-import SignupPage from '@ente/accounts/pages/signup';
-import { APPS } from '@ente/shared/apps/constants';
-import { useRouter } from 'next/router';
-import { AppContext } from 'pages/_app';
-import { useContext } from 'react';
+import SignupPage from "@ente/accounts/pages/signup";
+import { APPS } from "@ente/shared/apps/constants";
+import { useRouter } from "next/router";
+import { AppContext } from "pages/_app";
+import { useContext } from "react";
 
 export default function Sigup() {
     const appContext = useContext(AppContext);

+ 5 - 5
apps/accounts/src/pages/two-factor/recover/index.tsx

@@ -1,8 +1,8 @@
-import TwoFactorRecoverPage from '@ente/accounts/pages/two-factor/recover';
-import { useRouter } from 'next/router';
-import { AppContext } from 'pages/_app';
-import { useContext } from 'react';
-import { APPS } from '@ente/shared/apps/constants';
+import TwoFactorRecoverPage from "@ente/accounts/pages/two-factor/recover";
+import { APPS } from "@ente/shared/apps/constants";
+import { useRouter } from "next/router";
+import { AppContext } from "pages/_app";
+import { useContext } from "react";
 
 export default function TwoFactorRecover() {
     const appContext = useContext(AppContext);

+ 5 - 5
apps/accounts/src/pages/two-factor/setup/index.tsx

@@ -1,8 +1,8 @@
-import TwoFactorSetupPage from '@ente/accounts/pages/two-factor/setup';
-import { useRouter } from 'next/router';
-import { AppContext } from 'pages/_app';
-import { useContext } from 'react';
-import { APPS } from '@ente/shared/apps/constants';
+import TwoFactorSetupPage from "@ente/accounts/pages/two-factor/setup";
+import { APPS } from "@ente/shared/apps/constants";
+import { useRouter } from "next/router";
+import { AppContext } from "pages/_app";
+import { useContext } from "react";
 
 export default function TwoFactorSetup() {
     const appContext = useContext(AppContext);

+ 5 - 5
apps/accounts/src/pages/two-factor/verify/index.tsx

@@ -1,8 +1,8 @@
-import TwoFactorVerifyPage from '@ente/accounts/pages/two-factor/verify';
-import { useRouter } from 'next/router';
-import { AppContext } from 'pages/_app';
-import { useContext } from 'react';
-import { APPS } from '@ente/shared/apps/constants';
+import TwoFactorVerifyPage from "@ente/accounts/pages/two-factor/verify";
+import { APPS } from "@ente/shared/apps/constants";
+import { useRouter } from "next/router";
+import { AppContext } from "pages/_app";
+import { useContext } from "react";
 
 export default function TwoFactorVerify() {
     const appContext = useContext(AppContext);

+ 5 - 5
apps/accounts/src/pages/verify/index.tsx

@@ -1,8 +1,8 @@
-import VerifyPage from '@ente/accounts/pages/verify';
-import { useRouter } from 'next/router';
-import { AppContext } from 'pages/_app';
-import { useContext } from 'react';
-import { APPS } from '@ente/shared/apps/constants';
+import VerifyPage from "@ente/accounts/pages/verify";
+import { APPS } from "@ente/shared/apps/constants";
+import { useRouter } from "next/router";
+import { AppContext } from "pages/_app";
+import { useContext } from "react";
 
 export default function Verify() {
     const appContext = useContext(AppContext);

+ 30 - 30
apps/accounts/src/services/passkeysService.ts

@@ -1,8 +1,8 @@
-import HTTPService from '@ente/shared/network/HTTPService';
-import { getEndpoint } from '@ente/shared/network/api';
-import { logError } from '@ente/shared/sentry';
-import { getToken } from '@ente/shared/storage/localStorage/helpers';
-import _sodium from 'libsodium-wrappers';
+import HTTPService from "@ente/shared/network/HTTPService";
+import { getEndpoint } from "@ente/shared/network/api";
+import { logError } from "@ente/shared/sentry";
+import { getToken } from "@ente/shared/storage/localStorage/helpers";
+import _sodium from "libsodium-wrappers";
 const ENDPOINT = getEndpoint();
 
 export const getPasskeys = async () => {
@@ -12,11 +12,11 @@ export const getPasskeys = async () => {
         const response = await HTTPService.get(
             `${ENDPOINT}/passkeys`,
             {},
-            { 'X-Auth-Token': token }
+            { "X-Auth-Token": token },
         );
         return await response.data;
     } catch (e) {
-        logError(e, 'get passkeys failed');
+        logError(e, "get passkeys failed");
         throw e;
     }
 };
@@ -29,11 +29,11 @@ export const renamePasskey = async (id: string, name: string) => {
             `${ENDPOINT}/passkeys/${id}`,
             {},
             { friendlyName: name },
-            { 'X-Auth-Token': token }
+            { "X-Auth-Token": token },
         );
         return await response.data;
     } catch (e) {
-        logError(e, 'rename passkey failed');
+        logError(e, "rename passkey failed");
         throw e;
     }
 };
@@ -46,11 +46,11 @@ export const deletePasskey = async (id: string) => {
             `${ENDPOINT}/passkeys/${id}`,
             {},
             {},
-            { 'X-Auth-Token': token }
+            { "X-Auth-Token": token },
         );
         return await response.data;
     } catch (e) {
-        logError(e, 'delete passkey failed');
+        logError(e, "delete passkey failed");
         throw e;
     }
 };
@@ -63,12 +63,12 @@ export const getPasskeyRegistrationOptions = async () => {
             `${ENDPOINT}/passkeys/registration/begin`,
             {},
             {
-                'X-Auth-Token': token,
-            }
+                "X-Auth-Token": token,
+            },
         );
         return await response.data;
     } catch (e) {
-        logError(e, 'get passkey registration options failed');
+        logError(e, "get passkey registration options failed");
         throw e;
     }
 };
@@ -76,20 +76,20 @@ export const getPasskeyRegistrationOptions = async () => {
 export const finishPasskeyRegistration = async (
     friendlyName: string,
     credential: Credential,
-    sessionId: string
+    sessionId: string,
 ) => {
     try {
         const attestationObjectB64 = _sodium.to_base64(
             // eslint-disable-next-line @typescript-eslint/ban-ts-comment
             // @ts-ignore
             new Uint8Array(credential.response.attestationObject),
-            _sodium.base64_variants.URLSAFE_NO_PADDING
+            _sodium.base64_variants.URLSAFE_NO_PADDING,
         );
         const clientDataJSONB64 = _sodium.to_base64(
             // eslint-disable-next-line @typescript-eslint/ban-ts-comment
             // @ts-ignore
             new Uint8Array(credential.response.clientDataJSON),
-            _sodium.base64_variants.URLSAFE_NO_PADDING
+            _sodium.base64_variants.URLSAFE_NO_PADDING,
         );
 
         const token = getToken();
@@ -111,12 +111,12 @@ export const finishPasskeyRegistration = async (
                 sessionID: sessionId,
             },
             {
-                'X-Auth-Token': token,
-            }
+                "X-Auth-Token": token,
+            },
         );
         return await response.data;
     } catch (e) {
-        logError(e, 'finish passkey registration failed');
+        logError(e, "finish passkey registration failed");
         throw e;
     }
 };
@@ -130,19 +130,19 @@ interface Options {
 }
 
 export const beginPasskeyAuthentication = async (
-    sessionId: string
+    sessionId: string,
 ): Promise<BeginPasskeyAuthenticationResponse> => {
     try {
         const data = await HTTPService.post(
             `${ENDPOINT}/users/two-factor/passkeys/begin`,
             {
                 sessionID: sessionId,
-            }
+            },
         );
 
         return data.data;
     } catch (e) {
-        logError(e, 'begin passkey authentication failed');
+        logError(e, "begin passkey authentication failed");
         throw e;
     }
 };
@@ -150,7 +150,7 @@ export const beginPasskeyAuthentication = async (
 export const finishPasskeyAuthentication = async (
     credential: Credential,
     sessionId: string,
-    ceremonySessionId: string
+    ceremonySessionId: string,
 ) => {
     try {
         const data = await HTTPService.post(
@@ -164,37 +164,37 @@ export const finishPasskeyAuthentication = async (
                         // eslint-disable-next-line @typescript-eslint/ban-ts-comment
                         // @ts-ignore
                         new Uint8Array(credential.response.authenticatorData),
-                        _sodium.base64_variants.URLSAFE_NO_PADDING
+                        _sodium.base64_variants.URLSAFE_NO_PADDING,
                     ),
                     clientDataJSON: _sodium.to_base64(
                         // eslint-disable-next-line @typescript-eslint/ban-ts-comment
                         // @ts-ignore
                         new Uint8Array(credential.response.clientDataJSON),
-                        _sodium.base64_variants.URLSAFE_NO_PADDING
+                        _sodium.base64_variants.URLSAFE_NO_PADDING,
                     ),
                     signature: _sodium.to_base64(
                         // eslint-disable-next-line @typescript-eslint/ban-ts-comment
                         // @ts-ignore
                         new Uint8Array(credential.response.signature),
-                        _sodium.base64_variants.URLSAFE_NO_PADDING
+                        _sodium.base64_variants.URLSAFE_NO_PADDING,
                     ),
                     userHandle: _sodium.to_base64(
                         // eslint-disable-next-line @typescript-eslint/ban-ts-comment
                         // @ts-ignore
                         new Uint8Array(credential.response.userHandle),
-                        _sodium.base64_variants.URLSAFE_NO_PADDING
+                        _sodium.base64_variants.URLSAFE_NO_PADDING,
                     ),
                 },
             },
             {
                 sessionID: sessionId,
                 ceremonySessionID: ceremonySessionId,
-            }
+            },
         );
 
         return data.data;
     } catch (e) {
-        logError(e, 'finish passkey authentication failed');
+        logError(e, "finish passkey authentication failed");
         throw e;
     }
 };

+ 12 - 12
apps/accounts/src/styles/global.css

@@ -1,39 +1,39 @@
 /* inter-regular - latin */
 @font-face {
-    font-family: 'Inter';
+    font-family: "Inter";
     font-style: normal;
     font-weight: 400;
     src:
-        local(''),
-        url('/fonts/inter-v11-latin-500.woff2') format('woff2'),
+        local(""),
+        url("/fonts/inter-v11-latin-500.woff2") format("woff2"),
         /* Chrome 26+, Opera 23+, Firefox 39+ */
-            url('/fonts/inter-v11-latin-500.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
+            url("/fonts/inter-v11-latin-500.woff") format("woff"); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
     font-display: swap; /*https://web.dev/font-display/?utm_source=lighthouse&utm_medium=devtools#how-to-avoid-showing-invisible-text*/
 }
 
 /* inter-600 - latin */
 @font-face {
-    font-family: 'Inter';
+    font-family: "Inter";
     font-style: normal;
     font-weight: 700;
     src:
-        local(''),
-        url('/fonts/inter-v11-latin-600.woff2') format('woff2'),
+        local(""),
+        url("/fonts/inter-v11-latin-600.woff2") format("woff2"),
         /* Chrome 26+, Opera 23+, Firefox 39+ */
-            url('/fonts/inter-v11-latin-600.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
+            url("/fonts/inter-v11-latin-600.woff") format("woff"); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
     font-display: swap;
 }
 
 /* inter-800 - latin */
 @font-face {
-    font-family: 'Inter';
+    font-family: "Inter";
     font-style: normal;
     font-weight: 900;
     src:
-        local(''),
-        url('/fonts/inter-v11-latin-800.woff2') format('woff2'),
+        local(""),
+        url("/fonts/inter-v11-latin-800.woff2") format("woff2"),
         /* Chrome 26+, Opera 23+, Firefox 39+ */
-            url('/fonts/inter-v11-latin-800.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
+            url("/fonts/inter-v11-latin-800.woff") format("woff"); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
     font-display: swap;
 }
 

+ 4 - 4
apps/auth/.eslintrc.js

@@ -3,11 +3,11 @@ module.exports = {
     // This is required here to ensure desktop picks the right eslint config, where this app is
     // packaged as a submodule.
     root: true,
-    extends: ['@ente/eslint-config'],
-    parser: '@typescript-eslint/parser',
+    extends: ["@ente/eslint-config"],
+    parser: "@typescript-eslint/parser",
     parserOptions: {
         tsconfigRootDir: __dirname,
-        project: './tsconfig.json',
+        project: "./tsconfig.json",
     },
-    ignorePatterns: ['.eslintrc.js', 'out'],
+    ignorePatterns: [".eslintrc.js", "out"],
 };

+ 1 - 1
apps/auth/next.config.js

@@ -1,3 +1,3 @@
-const nextConfigBase = require('@/next/next.config.base.js');
+const nextConfigBase = require("@/next/next.config.base.js");
 
 module.exports = nextConfigBase;

+ 2 - 2
apps/auth/sentry.client.config.ts

@@ -1,3 +1,3 @@
-import { initSentry } from '@ente/shared/sentry/config/sentry.config.base';
+import { initSentry } from "@ente/shared/sentry/config/sentry.config.base";
 
-initSentry('https://5d344112b570b1a368b6f5c1d0bb798b@sentry.ente.io/8');
+initSentry("https://5d344112b570b1a368b6f5c1d0bb798b@sentry.ente.io/8");

+ 10 - 9
apps/auth/src/components/AuthFooter.tsx

@@ -1,18 +1,19 @@
-import { Button } from '@mui/material';
-import { t } from 'i18next';
+import { Button } from "@mui/material";
+import { t } from "i18next";
 
 export const AuthFooter = () => {
     return (
         <div
             style={{
-                display: 'flex',
-                flexDirection: 'column',
-                alignItems: 'center',
-                justifyContent: 'center',
-            }}>
-            <p>{t('AUTH_DOWNLOAD_MOBILE_APP')}</p>
+                display: "flex",
+                flexDirection: "column",
+                alignItems: "center",
+                justifyContent: "center",
+            }}
+        >
+            <p>{t("AUTH_DOWNLOAD_MOBILE_APP")}</p>
             <a href="https://github.com/ente-io/auth#-download" download>
-                <Button color="accent">{t('DOWNLOAD')}</Button>
+                <Button color="accent">{t("DOWNLOAD")}</Button>
             </a>
         </div>
     );

+ 19 - 17
apps/auth/src/components/Navbar.tsx

@@ -1,31 +1,33 @@
-import { HorizontalFlex } from '@ente/shared/components/Container';
-import NavbarBase from '@ente/shared/components/Navbar/base';
-import React from 'react';
-import { t } from 'i18next';
-import { logoutUser } from '@ente/accounts/services/user';
-import { EnteLogo } from '@ente/shared/components/EnteLogo';
-import OverflowMenu from '@ente/shared/components/OverflowMenu/menu';
-import { OverflowMenuOption } from '@ente/shared/components/OverflowMenu/option';
-import MoreHoriz from '@mui/icons-material/MoreHoriz';
-import LogoutOutlined from '@mui/icons-material/LogoutOutlined';
-import { AppContext } from 'pages/_app';
+import { logoutUser } from "@ente/accounts/services/user";
+import { HorizontalFlex } from "@ente/shared/components/Container";
+import { EnteLogo } from "@ente/shared/components/EnteLogo";
+import NavbarBase from "@ente/shared/components/Navbar/base";
+import OverflowMenu from "@ente/shared/components/OverflowMenu/menu";
+import { OverflowMenuOption } from "@ente/shared/components/OverflowMenu/option";
+import LogoutOutlined from "@mui/icons-material/LogoutOutlined";
+import MoreHoriz from "@mui/icons-material/MoreHoriz";
+import { t } from "i18next";
+import { AppContext } from "pages/_app";
+import React from "react";
 
 export default function AuthNavbar() {
     const { isMobile } = React.useContext(AppContext);
     return (
         <NavbarBase isMobile={isMobile}>
-            <HorizontalFlex flex={1} justifyContent={'center'}>
+            <HorizontalFlex flex={1} justifyContent={"center"}>
                 <EnteLogo />
             </HorizontalFlex>
-            <HorizontalFlex position={'absolute'} right="24px">
+            <HorizontalFlex position={"absolute"} right="24px">
                 <OverflowMenu
-                    ariaControls={'auth-options'}
-                    triggerButtonIcon={<MoreHoriz />}>
+                    ariaControls={"auth-options"}
+                    triggerButtonIcon={<MoreHoriz />}
+                >
                     <OverflowMenuOption
                         color="critical"
                         startIcon={<LogoutOutlined />}
-                        onClick={logoutUser}>
-                        {t('LOGOUT')}
+                        onClick={logoutUser}
+                    >
+                        {t("LOGOUT")}
                     </OverflowMenuOption>
                 </OverflowMenu>
             </HorizontalFlex>

+ 86 - 76
apps/auth/src/components/OTPDisplay.tsx

@@ -1,98 +1,107 @@
-import React, { useState, useEffect } from 'react';
-import { TOTP, HOTP } from 'otpauth';
-import { Code } from 'types/code';
-import TimerProgress from './TimerProgress';
-import { t } from 'i18next';
-import { ButtonBase, Snackbar } from '@mui/material';
+import { ButtonBase, Snackbar } from "@mui/material";
+import { t } from "i18next";
+import { HOTP, TOTP } from "otpauth";
+import { useEffect, useState } from "react";
+import { Code } from "types/code";
+import TimerProgress from "./TimerProgress";
 
 const TOTPDisplay = ({ issuer, account, code, nextCode, period }) => {
     return (
         <div
             style={{
-                backgroundColor: 'rgba(40, 40, 40, 0.6)',
-                borderRadius: '4px',
-                overflow: 'hidden',
-            }}>
+                backgroundColor: "rgba(40, 40, 40, 0.6)",
+                borderRadius: "4px",
+                overflow: "hidden",
+            }}
+        >
             <TimerProgress period={period ?? Code.defaultPeriod} />
             <div
                 style={{
-                    padding: '12px 20px 0px 20px',
-                    display: 'flex',
-                    alignItems: 'flex-start',
-                    minWidth: '320px',
-                    minHeight: '120px',
-                    justifyContent: 'space-between',
-                }}>
+                    padding: "12px 20px 0px 20px",
+                    display: "flex",
+                    alignItems: "flex-start",
+                    minWidth: "320px",
+                    minHeight: "120px",
+                    justifyContent: "space-between",
+                }}
+            >
                 <div
                     style={{
-                        display: 'flex',
-                        flexDirection: 'column',
-                        alignItems: 'flex-start',
-                        minWidth: '200px',
-                    }}>
+                        display: "flex",
+                        flexDirection: "column",
+                        alignItems: "flex-start",
+                        minWidth: "200px",
+                    }}
+                >
                     <p
                         style={{
-                            fontWeight: 'bold',
-                            margin: '0px',
-                            fontSize: '14px',
-                            textAlign: 'left',
-                        }}>
+                            fontWeight: "bold",
+                            margin: "0px",
+                            fontSize: "14px",
+                            textAlign: "left",
+                        }}
+                    >
                         {issuer}
                     </p>
                     <p
                         style={{
-                            marginTop: '0px',
-                            marginBottom: '8px',
-                            textAlign: 'left',
-                            fontSize: '12px',
-                            maxWidth: '200px',
-                            minHeight: '16px',
-                            color: 'grey',
-                        }}>
+                            marginTop: "0px",
+                            marginBottom: "8px",
+                            textAlign: "left",
+                            fontSize: "12px",
+                            maxWidth: "200px",
+                            minHeight: "16px",
+                            color: "grey",
+                        }}
+                    >
                         {account}
                     </p>
                     <p
                         style={{
-                            margin: '0px',
-                            marginBottom: '1rem',
-                            fontSize: '24px',
-                            fontWeight: 'bold',
-                            textAlign: 'left',
-                        }}>
+                            margin: "0px",
+                            marginBottom: "1rem",
+                            fontSize: "24px",
+                            fontWeight: "bold",
+                            textAlign: "left",
+                        }}
+                    >
                         {code}
                     </p>
                 </div>
                 <div style={{ flex: 1 }} />
                 <div
                     style={{
-                        display: 'flex',
-                        flexDirection: 'column',
-                        alignItems: 'flex-end',
-                        minWidth: '120px',
-                        textAlign: 'right',
-                        marginTop: 'auto',
-                        marginBottom: '1rem',
-                    }}>
+                        display: "flex",
+                        flexDirection: "column",
+                        alignItems: "flex-end",
+                        minWidth: "120px",
+                        textAlign: "right",
+                        marginTop: "auto",
+                        marginBottom: "1rem",
+                    }}
+                >
                     <p
                         style={{
-                            fontWeight: 'bold',
-                            marginBottom: '0px',
-                            fontSize: '10px',
-                            marginTop: 'auto',
-                            textAlign: 'right',
-                            color: 'grey',
-                        }}>
-                        {t('AUTH_NEXT')}
+                            fontWeight: "bold",
+                            marginBottom: "0px",
+                            fontSize: "10px",
+                            marginTop: "auto",
+                            textAlign: "right",
+                            color: "grey",
+                        }}
+                    >
+                        {t("AUTH_NEXT")}
                     </p>
                     <p
                         style={{
-                            fontSize: '14px',
-                            fontWeight: 'bold',
-                            marginBottom: '0px',
-                            marginTop: 'auto',
-                            textAlign: 'right',
-                            color: 'grey',
-                        }}>
+                            fontSize: "14px",
+                            fontWeight: "bold",
+                            marginBottom: "0px",
+                            marginTop: "auto",
+                            textAlign: "right",
+                            color: "grey",
+                        }}
+                    >
                         {nextCode}
                     </p>
                 </div>
@@ -111,7 +120,7 @@ function BadCodeInfo({ codeInfo, codeErr }) {
             <div>
                 {showRawData ? (
                     <div onClick={() => setShowRawData(false)}>
-                        {codeInfo.rawData ?? 'no raw data'}
+                        {codeInfo.rawData ?? "no raw data"}
                     </div>
                 ) : (
                     <div onClick={() => setShowRawData(true)}>Show rawData</div>
@@ -127,15 +136,15 @@ interface OTPDisplayProps {
 
 const OTPDisplay = (props: OTPDisplayProps) => {
     const { codeInfo } = props;
-    const [code, setCode] = useState('');
-    const [nextCode, setNextCode] = useState('');
-    const [codeErr, setCodeErr] = useState('');
+    const [code, setCode] = useState("");
+    const [nextCode, setNextCode] = useState("");
+    const [codeErr, setCodeErr] = useState("");
     const [hasCopied, setHasCopied] = useState(false);
 
     const generateCodes = () => {
         try {
             const currentTime = new Date().getTime();
-            if (codeInfo.type.toLowerCase() === 'totp') {
+            if (codeInfo.type.toLowerCase() === "totp") {
                 const totp = new TOTP({
                     secret: codeInfo.secret,
                     algorithm: codeInfo.algorithm ?? Code.defaultAlgo,
@@ -146,9 +155,9 @@ const OTPDisplay = (props: OTPDisplayProps) => {
                 setNextCode(
                     totp.generate({
                         timestamp: currentTime + codeInfo.period * 1000,
-                    })
+                    }),
                 );
-            } else if (codeInfo.type.toLowerCase() === 'hotp') {
+            } else if (codeInfo.type.toLowerCase() === "hotp") {
                 const hotp = new HOTP({
                     secret: codeInfo.secret,
                     counter: 0,
@@ -184,8 +193,8 @@ const OTPDisplay = (props: OTPDisplayProps) => {
             // we need to call generateCodes() once before the interval loop
             // to set the initial code and nextCode
             generateCodes();
-            codeType.toLowerCase() === 'totp' ||
-            codeType.toLowerCase() === 'hotp'
+            codeType.toLowerCase() === "totp" ||
+            codeType.toLowerCase() === "hotp"
                 ? setInterval(() => {
                       generateCodes();
                   }, codePeriodInMs)
@@ -198,13 +207,14 @@ const OTPDisplay = (props: OTPDisplayProps) => {
     }, [codeInfo]);
 
     return (
-        <div style={{ padding: '8px' }}>
-            {codeErr === '' ? (
+        <div style={{ padding: "8px" }}>
+            {codeErr === "" ? (
                 <ButtonBase
                     component="div"
                     onClick={() => {
                         copyCode();
-                    }}>
+                    }}
+                >
                     <TOTPDisplay
                         period={codeInfo.period}
                         issuer={codeInfo.issuer}

+ 4 - 4
apps/auth/src/components/TimerProgress.tsx

@@ -1,4 +1,4 @@
-import React, { useState, useEffect } from 'react';
+import { useEffect, useState } from "react";
 
 const TimerProgress = ({ period }) => {
     const [progress, setProgress] = useState(0);
@@ -24,14 +24,14 @@ const TimerProgress = ({ period }) => {
         return () => clearInterval(ticker);
     }, []);
 
-    const color = progress > 0.4 ? 'green' : 'orange';
+    const color = progress > 0.4 ? "green" : "orange";
 
     return (
         <div
             style={{
-                borderTopLeftRadius: '3px',
+                borderTopLeftRadius: "3px",
                 width: `${progress * 100}%`,
-                height: '3px',
+                height: "3px",
                 backgroundColor: color,
             }}
         />

+ 5 - 5
apps/auth/src/pages/404.tsx

@@ -1,8 +1,8 @@
-import NotFoundPage from '@ente/shared/next/pages/404';
-import { useRouter } from 'next/router';
-import { AppContext } from 'pages/_app';
-import { useContext } from 'react';
-import { APPS } from '@ente/shared/apps/constants';
+import { APPS } from "@ente/shared/apps/constants";
+import NotFoundPage from "@ente/shared/next/pages/404";
+import { useRouter } from "next/router";
+import { AppContext } from "pages/_app";
+import { useContext } from "react";
 
 export default function NotFound() {
     const appContext = useContext(AppContext);

+ 55 - 53
apps/auth/src/pages/_app.tsx

@@ -1,42 +1,42 @@
-import React, { createContext, useEffect, useRef, useState } from 'react';
-import AppNavbar from '@ente/shared/components/Navbar/app';
-import { t } from 'i18next';
-
-import { useRouter } from 'next/router';
-import { Overlay } from '@ente/shared/components/Container';
-import EnteSpinner from '@ente/shared/components/EnteSpinner';
-import { LS_KEYS } from '@ente/shared/storage/localStorage';
-import HTTPService from '@ente/shared/network/HTTPService';
-import Head from 'next/head';
-import LoadingBar from 'react-top-loading-bar';
-import DialogBoxV2 from '@ente/shared/components/DialogBoxV2';
-import { ThemeProvider } from '@mui/material/styles';
-import { MessageContainer } from '@ente/shared/components/MessageContainer';
-import { CssBaseline, useMediaQuery } from '@mui/material';
+import AppNavbar from "@ente/shared/components/Navbar/app";
+import { t } from "i18next";
+import { createContext, useEffect, useRef, useState } from "react";
+
+import { Overlay } from "@ente/shared/components/Container";
+import DialogBoxV2 from "@ente/shared/components/DialogBoxV2";
 import {
     DialogBoxAttributesV2,
     SetDialogBoxAttributesV2,
-} from '@ente/shared/components/DialogBoxV2/types';
+} from "@ente/shared/components/DialogBoxV2/types";
+import EnteSpinner from "@ente/shared/components/EnteSpinner";
+import { MessageContainer } from "@ente/shared/components/MessageContainer";
 import {
     clearLogsIfLocalStorageLimitExceeded,
     logStartupMessage,
-} from '@ente/shared/logging/web';
-
-import { CacheProvider } from '@emotion/react';
+} from "@ente/shared/logging/web";
+import HTTPService from "@ente/shared/network/HTTPService";
+import { LS_KEYS } from "@ente/shared/storage/localStorage";
+import { CssBaseline, useMediaQuery } from "@mui/material";
+import { ThemeProvider } from "@mui/material/styles";
+import Head from "next/head";
+import { useRouter } from "next/router";
+import LoadingBar from "react-top-loading-bar";
+
+import { setupI18n } from "@/ui/i18n";
+import { CacheProvider } from "@emotion/react";
 import {
     APP_TITLES,
     APPS,
     CLIENT_PACKAGE_NAMES,
-} from '@ente/shared/apps/constants';
-import { EnteAppProps } from '@ente/shared/apps/types';
-import createEmotionCache from '@ente/shared/themes/createEmotionCache';
-import { THEME_COLOR } from '@ente/shared/themes/constants';
-import { SetTheme } from '@ente/shared/themes/types';
-import { setupI18n } from '@/ui/i18n';
-import { useLocalState } from '@ente/shared/hooks/useLocalState';
-import { PHOTOS_PAGES as PAGES } from '@ente/shared/constants/pages';
-import { getTheme } from '@ente/shared/themes';
-import '../../public/css/global.css';
+} from "@ente/shared/apps/constants";
+import { EnteAppProps } from "@ente/shared/apps/types";
+import { PHOTOS_PAGES as PAGES } from "@ente/shared/constants/pages";
+import { useLocalState } from "@ente/shared/hooks/useLocalState";
+import { getTheme } from "@ente/shared/themes";
+import { THEME_COLOR } from "@ente/shared/themes/constants";
+import createEmotionCache from "@ente/shared/themes/createEmotionCache";
+import { SetTheme } from "@ente/shared/themes/types";
+import "../../public/css/global.css";
 
 type AppContextType = {
     showNavBar: (show: boolean) => void;
@@ -64,7 +64,7 @@ export default function App(props: EnteAppProps) {
     const [isI18nReady, setIsI18nReady] = useState<boolean>(false);
     const [loading, setLoading] = useState(false);
     const [offline, setOffline] = useState(
-        typeof window !== 'undefined' && !window.navigator.onLine
+        typeof window !== "undefined" && !window.navigator.onLine,
     );
     const [showNavbar, setShowNavBar] = useState(false);
     const isLoadingBarRunning = useRef(false);
@@ -72,10 +72,10 @@ export default function App(props: EnteAppProps) {
     const [dialogBoxAttributeV2, setDialogBoxAttributesV2] =
         useState<DialogBoxAttributesV2>();
     const [dialogBoxV2View, setDialogBoxV2View] = useState(false);
-    const isMobile = useMediaQuery('(max-width:428px)');
+    const isMobile = useMediaQuery("(max-width:428px)");
     const [themeColor, setThemeColor] = useLocalState(
         LS_KEYS.THEME,
-        THEME_COLOR.DARK
+        THEME_COLOR.DARK,
     );
 
     useEffect(() => {
@@ -83,7 +83,7 @@ export default function App(props: EnteAppProps) {
         setupI18n().finally(() => setIsI18nReady(true));
         // set client package name in headers
         HTTPService.setHeaders({
-            'X-Client-Package': CLIENT_PACKAGE_NAMES.get(APPS.AUTH),
+            "X-Client-Package": CLIENT_PACKAGE_NAMES.get(APPS.AUTH),
         });
         // setup logging
         clearLogsIfLocalStorageLimitExceeded();
@@ -96,31 +96,31 @@ export default function App(props: EnteAppProps) {
     useEffect(() => {
         if (isI18nReady) {
             console.log(
-                `%c${t('CONSOLE_WARNING_STOP')}`,
-                'color: red; font-size: 52px;'
+                `%c${t("CONSOLE_WARNING_STOP")}`,
+                "color: red; font-size: 52px;",
             );
-            console.log(`%c${t('CONSOLE_WARNING_DESC')}`, 'font-size: 20px;');
+            console.log(`%c${t("CONSOLE_WARNING_DESC")}`, "font-size: 20px;");
         }
     }, [isI18nReady]);
 
     useEffect(() => {
-        router.events.on('routeChangeStart', (url: string) => {
-            const newPathname = url.split('?')[0] as PAGES;
+        router.events.on("routeChangeStart", (url: string) => {
+            const newPathname = url.split("?")[0] as PAGES;
             if (window.location.pathname !== newPathname) {
                 setLoading(true);
             }
         });
 
-        router.events.on('routeChangeComplete', () => {
+        router.events.on("routeChangeComplete", () => {
             setLoading(false);
         });
 
-        window.addEventListener('online', setUserOnline);
-        window.addEventListener('offline', setUserOffline);
+        window.addEventListener("online", setUserOnline);
+        window.addEventListener("offline", setUserOffline);
 
         return () => {
-            window.removeEventListener('online', setUserOnline);
-            window.removeEventListener('offline', setUserOffline);
+            window.removeEventListener("online", setUserOnline);
+            window.removeEventListener("offline", setUserOffline);
         };
     }, []);
 
@@ -145,9 +145,9 @@ export default function App(props: EnteAppProps) {
 
     const somethingWentWrong = () =>
         setDialogBoxAttributesV2({
-            title: t('ERROR'),
-            close: { variant: 'critical' },
-            content: t('UNKNOWN_ERROR'),
+            title: t("ERROR"),
+            close: { variant: "critical" },
+            content: t("UNKNOWN_ERROR"),
         });
 
     return (
@@ -155,7 +155,7 @@ export default function App(props: EnteAppProps) {
             <Head>
                 <title>
                     {isI18nReady
-                        ? t('TITLE', { context: APPS.AUTH })
+                        ? t("TITLE", { context: APPS.AUTH })
                         : APP_TITLES.get(APPS.AUTH)}
                 </title>
                 <meta
@@ -168,7 +168,7 @@ export default function App(props: EnteAppProps) {
                 <CssBaseline enableColorScheme />
                 {showNavbar && <AppNavbar isMobile={isMobile} />}
                 <MessageContainer>
-                    {offline && t('OFFLINE_MSG')}
+                    {offline && t("OFFLINE_MSG")}
                 </MessageContainer>
 
                 <LoadingBar color="#51cd7c" ref={loadingBar} />
@@ -190,16 +190,18 @@ export default function App(props: EnteAppProps) {
                         setThemeColor,
                         somethingWentWrong,
                         setDialogBoxAttributesV2,
-                    }}>
+                    }}
+                >
                     {(loading || !isI18nReady) && (
                         <Overlay
                             sx={(theme) => ({
-                                display: 'flex',
-                                justifyContent: 'center',
-                                alignItems: 'center',
+                                display: "flex",
+                                justifyContent: "center",
+                                alignItems: "center",
                                 zIndex: 2000,
                                 backgroundColor: theme.colors.background.base,
-                            })}>
+                            })}
+                        >
                             <EnteSpinner />
                         </Overlay>
                     )}

+ 1 - 1
apps/auth/src/pages/_document.tsx

@@ -1,6 +1,6 @@
 import DocumentPage, {
     EnteDocumentProps,
-} from '@ente/shared/next/pages/_document';
+} from "@ente/shared/next/pages/_document";
 
 export default function Document(props: EnteDocumentProps) {
     return <DocumentPage {...props} />;

+ 5 - 5
apps/auth/src/pages/_error.tsx

@@ -1,8 +1,8 @@
-import ErrorPage from '@ente/shared/next/pages/_error';
-import { useRouter } from 'next/router';
-import { AppContext } from 'pages/_app';
-import { useContext } from 'react';
-import { APPS } from '@ente/shared/apps/constants';
+import { APPS } from "@ente/shared/apps/constants";
+import ErrorPage from "@ente/shared/next/pages/_error";
+import { useRouter } from "next/router";
+import { AppContext } from "pages/_app";
+import { useContext } from "react";
 
 export default function Error() {
     const appContext = useContext(AppContext);

+ 45 - 42
apps/auth/src/pages/auth/index.tsx

@@ -1,24 +1,24 @@
-import React, { useContext, useEffect, useState } from 'react';
-import OTPDisplay from 'components/OTPDisplay';
-import { getAuthCodes } from 'services';
-import { CustomError } from '@ente/shared/error';
-import { AUTH_PAGES as PAGES } from '@ente/shared/constants/pages';
-import { useRouter } from 'next/router';
-import { AuthFooter } from 'components/AuthFooter';
-import { AppContext } from 'pages/_app';
-import { TextField } from '@mui/material';
-import AuthNavbar from 'components/Navbar';
-import { t } from 'i18next';
-import EnteSpinner from '@ente/shared/components/EnteSpinner';
-import { VerticallyCentered } from '@ente/shared/components/Container';
-import InMemoryStore, { MS_KEYS } from '@ente/shared/storage/InMemoryStore';
+import { VerticallyCentered } from "@ente/shared/components/Container";
+import EnteSpinner from "@ente/shared/components/EnteSpinner";
+import { AUTH_PAGES as PAGES } from "@ente/shared/constants/pages";
+import { CustomError } from "@ente/shared/error";
+import InMemoryStore, { MS_KEYS } from "@ente/shared/storage/InMemoryStore";
+import { TextField } from "@mui/material";
+import { AuthFooter } from "components/AuthFooter";
+import AuthNavbar from "components/Navbar";
+import OTPDisplay from "components/OTPDisplay";
+import { t } from "i18next";
+import { useRouter } from "next/router";
+import { AppContext } from "pages/_app";
+import { useContext, useEffect, useState } from "react";
+import { getAuthCodes } from "services";
 
 const AuthenticatorCodesPage = () => {
     const appContext = useContext(AppContext);
     const router = useRouter();
     const [codes, setCodes] = useState([]);
     const [hasFetched, setHasFetched] = useState(false);
-    const [searchTerm, setSearchTerm] = useState('');
+    const [searchTerm, setSearchTerm] = useState("");
 
     useEffect(() => {
         const fetchCodes = async () => {
@@ -41,12 +41,12 @@ const AuthenticatorCodesPage = () => {
 
     const filteredCodes = codes.filter(
         (secret) =>
-            (secret.issuer ?? '')
+            (secret.issuer ?? "")
                 .toLowerCase()
                 .includes(searchTerm.toLowerCase()) ||
-            (secret.account ?? '')
+            (secret.account ?? "")
                 .toLowerCase()
-                .includes(searchTerm.toLowerCase())
+                .includes(searchTerm.toLowerCase()),
     );
 
     if (!hasFetched) {
@@ -64,47 +64,50 @@ const AuthenticatorCodesPage = () => {
             <AuthNavbar />
             <div
                 style={{
-                    maxWidth: '800px',
-                    display: 'flex',
-                    flexDirection: 'column',
-                    alignItems: 'center',
-                    justifyContent: 'center',
-                    margin: '0 auto',
-                }}>
-                <div style={{ marginBottom: '1rem' }} />
+                    maxWidth: "800px",
+                    display: "flex",
+                    flexDirection: "column",
+                    alignItems: "center",
+                    justifyContent: "center",
+                    margin: "0 auto",
+                }}
+            >
+                <div style={{ marginBottom: "1rem" }} />
                 {filteredCodes.length === 0 && searchTerm.length === 0 ? (
                     <></>
                 ) : (
                     <TextField
                         id="search"
                         name="search"
-                        label={t('SEARCH')}
+                        label={t("SEARCH")}
                         onChange={(e) => setSearchTerm(e.target.value)}
                         variant="filled"
-                        style={{ width: '350px' }}
+                        style={{ width: "350px" }}
                         value={searchTerm}
                         autoFocus
                     />
                 )}
 
-                <div style={{ marginBottom: '1rem' }} />
+                <div style={{ marginBottom: "1rem" }} />
                 <div
                     style={{
-                        display: 'flex',
-                        flexDirection: 'row',
-                        flexWrap: 'wrap',
-                        justifyContent: 'center',
-                    }}>
+                        display: "flex",
+                        flexDirection: "row",
+                        flexWrap: "wrap",
+                        justifyContent: "center",
+                    }}
+                >
                     {filteredCodes.length === 0 ? (
                         <div
                             style={{
-                                alignItems: 'center',
-                                display: 'flex',
-                                textAlign: 'center',
-                                marginTop: '32px',
-                            }}>
+                                alignItems: "center",
+                                display: "flex",
+                                textAlign: "center",
+                                marginTop: "32px",
+                            }}
+                        >
                             {searchTerm.length !== 0 ? (
-                                <p>{t('NO_RESULTS')}</p>
+                                <p>{t("NO_RESULTS")}</p>
                             ) : (
                                 <div />
                             )}
@@ -115,9 +118,9 @@ const AuthenticatorCodesPage = () => {
                         ))
                     )}
                 </div>
-                <div style={{ marginBottom: '2rem' }} />
+                <div style={{ marginBottom: "2rem" }} />
                 <AuthFooter />
-                <div style={{ marginBottom: '4rem' }} />
+                <div style={{ marginBottom: "4rem" }} />
             </div>
             <style jsx>{`
                 @media (min-width: 800px) {

+ 5 - 5
apps/auth/src/pages/change-email/index.tsx

@@ -1,8 +1,8 @@
-import ChangeEmailPage from '@ente/accounts/pages/change-email';
-import { useRouter } from 'next/router';
-import { AppContext } from 'pages/_app';
-import { useContext } from 'react';
-import { APPS } from '@ente/shared/apps/constants';
+import ChangeEmailPage from "@ente/accounts/pages/change-email";
+import { APPS } from "@ente/shared/apps/constants";
+import { useRouter } from "next/router";
+import { AppContext } from "pages/_app";
+import { useContext } from "react";
 
 export default function ChangeEmail() {
     const appContext = useContext(AppContext);

+ 5 - 5
apps/auth/src/pages/change-password/index.tsx

@@ -1,8 +1,8 @@
-import ChangePasswordPage from '@ente/accounts/pages/change-password';
-import { useRouter } from 'next/router';
-import { AppContext } from 'pages/_app';
-import { useContext } from 'react';
-import { APPS } from '@ente/shared/apps/constants';
+import ChangePasswordPage from "@ente/accounts/pages/change-password";
+import { APPS } from "@ente/shared/apps/constants";
+import { useRouter } from "next/router";
+import { AppContext } from "pages/_app";
+import { useContext } from "react";
 
 export default function ChangePassword() {
     const appContext = useContext(AppContext);

+ 5 - 5
apps/auth/src/pages/credentials/index.tsx

@@ -1,8 +1,8 @@
-import CredentialPage from '@ente/accounts/pages/credentials';
-import { useRouter } from 'next/router';
-import { AppContext } from 'pages/_app';
-import { useContext } from 'react';
-import { APPS } from '@ente/shared/apps/constants';
+import CredentialPage from "@ente/accounts/pages/credentials";
+import { APPS } from "@ente/shared/apps/constants";
+import { useRouter } from "next/router";
+import { AppContext } from "pages/_app";
+import { useContext } from "react";
 
 export default function Credential() {
     const appContext = useContext(AppContext);

+ 5 - 5
apps/auth/src/pages/generate/index.tsx

@@ -1,8 +1,8 @@
-import GeneratePage from '@ente/accounts/pages/generate';
-import { useRouter } from 'next/router';
-import { AppContext } from 'pages/_app';
-import { useContext } from 'react';
-import { APPS } from '@ente/shared/apps/constants';
+import GeneratePage from "@ente/accounts/pages/generate";
+import { APPS } from "@ente/shared/apps/constants";
+import { useRouter } from "next/router";
+import { AppContext } from "pages/_app";
+import { useContext } from "react";
 
 export default function Generate() {
     const appContext = useContext(AppContext);

+ 3 - 3
apps/auth/src/pages/index.tsx

@@ -1,6 +1,6 @@
-import { PHOTOS_PAGES as PAGES } from '@ente/shared/constants/pages';
-import { useRouter } from 'next/router';
-import { useEffect } from 'react';
+import { PHOTOS_PAGES as PAGES } from "@ente/shared/constants/pages";
+import { useRouter } from "next/router";
+import { useEffect } from "react";
 
 const IndexPage = () => {
     const router = useRouter();

+ 5 - 5
apps/auth/src/pages/login/index.tsx

@@ -1,8 +1,8 @@
-import LoginPage from '@ente/accounts/pages/login';
-import { useRouter } from 'next/router';
-import { AppContext } from 'pages/_app';
-import { useContext } from 'react';
-import { APPS } from '@ente/shared/apps/constants';
+import LoginPage from "@ente/accounts/pages/login";
+import { APPS } from "@ente/shared/apps/constants";
+import { useRouter } from "next/router";
+import { AppContext } from "pages/_app";
+import { useContext } from "react";
 
 export default function Login() {
     const appContext = useContext(AppContext);

+ 5 - 5
apps/auth/src/pages/recover/index.tsx

@@ -1,8 +1,8 @@
-import RecoverPage from '@ente/accounts/pages/recover';
-import { useRouter } from 'next/router';
-import { AppContext } from 'pages/_app';
-import { useContext } from 'react';
-import { APPS } from '@ente/shared/apps/constants';
+import RecoverPage from "@ente/accounts/pages/recover";
+import { APPS } from "@ente/shared/apps/constants";
+import { useRouter } from "next/router";
+import { AppContext } from "pages/_app";
+import { useContext } from "react";
 
 export default function Recover() {
     const appContext = useContext(AppContext);

+ 5 - 5
apps/auth/src/pages/signup/index.tsx

@@ -1,8 +1,8 @@
-import SignupPage from '@ente/accounts/pages/signup';
-import { useRouter } from 'next/router';
-import { AppContext } from 'pages/_app';
-import { useContext } from 'react';
-import { APPS } from '@ente/shared/apps/constants';
+import SignupPage from "@ente/accounts/pages/signup";
+import { APPS } from "@ente/shared/apps/constants";
+import { useRouter } from "next/router";
+import { AppContext } from "pages/_app";
+import { useContext } from "react";
 
 export default function Sigup() {
     const appContext = useContext(AppContext);

+ 5 - 5
apps/auth/src/pages/two-factor/recover/index.tsx

@@ -1,8 +1,8 @@
-import TwoFactorRecoverPage from '@ente/accounts/pages/two-factor/recover';
-import { useRouter } from 'next/router';
-import { AppContext } from 'pages/_app';
-import { useContext } from 'react';
-import { APPS } from '@ente/shared/apps/constants';
+import TwoFactorRecoverPage from "@ente/accounts/pages/two-factor/recover";
+import { APPS } from "@ente/shared/apps/constants";
+import { useRouter } from "next/router";
+import { AppContext } from "pages/_app";
+import { useContext } from "react";
 
 export default function TwoFactorRecover() {
     const appContext = useContext(AppContext);

+ 5 - 5
apps/auth/src/pages/two-factor/setup/index.tsx

@@ -1,8 +1,8 @@
-import TwoFactorSetupPage from '@ente/accounts/pages/two-factor/setup';
-import { useRouter } from 'next/router';
-import { AppContext } from 'pages/_app';
-import { useContext } from 'react';
-import { APPS } from '@ente/shared/apps/constants';
+import TwoFactorSetupPage from "@ente/accounts/pages/two-factor/setup";
+import { APPS } from "@ente/shared/apps/constants";
+import { useRouter } from "next/router";
+import { AppContext } from "pages/_app";
+import { useContext } from "react";
 
 export default function TwoFactorSetup() {
     const appContext = useContext(AppContext);

+ 5 - 5
apps/auth/src/pages/two-factor/verify/index.tsx

@@ -1,8 +1,8 @@
-import TwoFactorVerifyPage from '@ente/accounts/pages/two-factor/verify';
-import { useRouter } from 'next/router';
-import { AppContext } from 'pages/_app';
-import { useContext } from 'react';
-import { APPS } from '@ente/shared/apps/constants';
+import TwoFactorVerifyPage from "@ente/accounts/pages/two-factor/verify";
+import { APPS } from "@ente/shared/apps/constants";
+import { useRouter } from "next/router";
+import { AppContext } from "pages/_app";
+import { useContext } from "react";
 
 export default function TwoFactorVerify() {
     const appContext = useContext(AppContext);

+ 5 - 5
apps/auth/src/pages/verify/index.tsx

@@ -1,8 +1,8 @@
-import VerifyPage from '@ente/accounts/pages/verify';
-import { useRouter } from 'next/router';
-import { AppContext } from 'pages/_app';
-import { useContext } from 'react';
-import { APPS } from '@ente/shared/apps/constants';
+import VerifyPage from "@ente/accounts/pages/verify";
+import { APPS } from "@ente/shared/apps/constants";
+import { useRouter } from "next/router";
+import { AppContext } from "pages/_app";
+import { useContext } from "react";
 
 export default function Verify() {
     const appContext = useContext(AppContext);

+ 24 - 24
apps/auth/src/services/index.ts

@@ -1,13 +1,13 @@
-import { HttpStatusCode } from 'axios';
-import HTTPService from '@ente/shared/network/HTTPService';
-import { AuthEntity, AuthKey } from 'types/api';
-import { Code } from 'types/code';
-import ComlinkCryptoWorker from '@ente/shared/crypto';
-import { getEndpoint } from '@ente/shared/network/api';
-import { getActualKey } from '@ente/shared/user';
-import { getToken } from '@ente/shared/storage/localStorage/helpers';
-import { ApiError, CustomError } from '@ente/shared/error';
-import { logError } from '@ente/shared/sentry';
+import ComlinkCryptoWorker from "@ente/shared/crypto";
+import { ApiError, CustomError } from "@ente/shared/error";
+import HTTPService from "@ente/shared/network/HTTPService";
+import { getEndpoint } from "@ente/shared/network/api";
+import { logError } from "@ente/shared/sentry";
+import { getToken } from "@ente/shared/storage/localStorage/helpers";
+import { getActualKey } from "@ente/shared/user";
+import { HttpStatusCode } from "axios";
+import { AuthEntity, AuthKey } from "types/api";
+import { Code } from "types/code";
 
 const ENDPOINT = getEndpoint();
 export const getAuthCodes = async (): Promise<Code[]> => {
@@ -18,7 +18,7 @@ export const getAuthCodes = async (): Promise<Code[]> => {
         const authenticatorKey = await cryptoWorker.decryptB64(
             authKeyData.encryptedKey,
             authKeyData.header,
-            masterKey
+            masterKey,
         );
         // always fetch all data from server for now
         const authEntity: AuthEntity[] = await getDiff(0);
@@ -31,21 +31,21 @@ export const getAuthCodes = async (): Promise<Code[]> => {
                             await cryptoWorker.decryptMetadata(
                                 entity.encryptedData,
                                 entity.header,
-                                authenticatorKey
+                                authenticatorKey,
                             );
                         return Code.fromRawData(entity.id, decryptedCode);
                     } catch (e) {
                         logError(
-                            Error('failed to parse code'),
-                            'codeId = ' + entity.id
+                            Error("failed to parse code"),
+                            "codeId = " + entity.id,
                         );
                         return null;
                     }
-                })
+                }),
         );
         // Remove null and undefined values
         const filteredAuthCodes = authCodes.filter(
-            (f) => f !== null && f !== undefined
+            (f) => f !== null && f !== undefined,
         );
         filteredAuthCodes.sort((a, b) => {
             if (a.issuer && b.issuer) {
@@ -62,7 +62,7 @@ export const getAuthCodes = async (): Promise<Code[]> => {
         return filteredAuthCodes;
     } catch (e) {
         if (e.message !== CustomError.AUTH_KEY_NOT_FOUND) {
-            logError(e, 'get authenticator entities failed');
+            logError(e, "get authenticator entities failed");
         }
         throw e;
     }
@@ -74,8 +74,8 @@ export const getAuthKey = async (): Promise<AuthKey> => {
             `${ENDPOINT}/authenticator/key`,
             {},
             {
-                'X-Auth-Token': getToken(),
-            }
+                "X-Auth-Token": getToken(),
+            },
         );
         return resp.data;
     } catch (e) {
@@ -85,7 +85,7 @@ export const getAuthKey = async (): Promise<AuthKey> => {
         ) {
             throw Error(CustomError.AUTH_KEY_NOT_FOUND);
         } else {
-            logError(e, 'Get key failed');
+            logError(e, "Get key failed");
             throw e;
         }
     }
@@ -94,7 +94,7 @@ export const getAuthKey = async (): Promise<AuthKey> => {
 // return a promise which resolves to list of AuthEnitity
 export const getDiff = async (
     sinceTime: number,
-    limit = 2500
+    limit = 2500,
 ): Promise<AuthEntity[]> => {
     try {
         const resp = await HTTPService.get(
@@ -104,12 +104,12 @@ export const getDiff = async (
                 limit,
             },
             {
-                'X-Auth-Token': getToken(),
-            }
+                "X-Auth-Token": getToken(),
+            },
         );
         return resp.data.diff;
     } catch (e) {
-        logError(e, 'Get diff failed');
+        logError(e, "Get diff failed");
         throw e;
     }
 };

+ 50 - 50
apps/auth/src/types/code.ts

@@ -1,18 +1,18 @@
-import { URI } from 'vscode-uri';
+import { URI } from "vscode-uri";
 
-type Type = 'totp' | 'TOTP' | 'hotp' | 'HOTP';
+type Type = "totp" | "TOTP" | "hotp" | "HOTP";
 
 type AlgorithmType =
-    | 'sha1'
-    | 'SHA1'
-    | 'sha256'
-    | 'SHA256'
-    | 'sha512'
-    | 'SHA512';
+    | "sha1"
+    | "SHA1"
+    | "sha256"
+    | "SHA256"
+    | "sha512"
+    | "SHA512";
 
 export class Code {
     static readonly defaultDigits = 6;
-    static readonly defaultAlgo = 'sha1';
+    static readonly defaultAlgo = "sha1";
     static readonly defaultPeriod = 30;
 
     // id for the corresponding auth entity
@@ -35,7 +35,7 @@ export class Code {
         algorithm: AlgorithmType,
         type: Type,
         rawData?: string,
-        id?: string
+        id?: string,
     ) {
         this.account = account;
         this.issuer = issuer;
@@ -50,36 +50,36 @@ export class Code {
 
     static fromRawData(id: string, rawData: string): Code {
         let santizedRawData = rawData
-            .replace(/\+/g, '%2B')
-            .replace(/:/g, '%3A')
-            .replaceAll('\r', '');
+            .replace(/\+/g, "%2B")
+            .replace(/:/g, "%3A")
+            .replaceAll("\r", "");
         if (santizedRawData.startsWith('"')) {
             santizedRawData = santizedRawData.substring(1);
         }
         if (santizedRawData.endsWith('"')) {
             santizedRawData = santizedRawData.substring(
                 0,
-                santizedRawData.length - 1
+                santizedRawData.length - 1,
             );
         }
 
         const uriParams = {};
         const searchParamsString =
-            decodeURIComponent(santizedRawData).split('?')[1];
-        searchParamsString.split('&').forEach((pair) => {
-            const [key, value] = pair.split('=');
+            decodeURIComponent(santizedRawData).split("?")[1];
+        searchParamsString.split("&").forEach((pair) => {
+            const [key, value] = pair.split("=");
             uriParams[key] = value;
         });
 
         const uri = URI.parse(santizedRawData);
         let uriPath = decodeURIComponent(uri.path);
         if (
-            uriPath.startsWith('/otpauth://') ||
-            uriPath.startsWith('otpauth://')
+            uriPath.startsWith("/otpauth://") ||
+            uriPath.startsWith("otpauth://")
         ) {
-            uriPath = uriPath.split('otpauth://')[1];
-        } else if (uriPath.startsWith('otpauth%3A//')) {
-            uriPath = uriPath.split('otpauth%3A//')[1];
+            uriPath = uriPath.split("otpauth://")[1];
+        } else if (uriPath.startsWith("otpauth%3A//")) {
+            uriPath = uriPath.split("otpauth%3A//")[1];
         }
 
         return new Code(
@@ -91,54 +91,54 @@ export class Code {
             Code._getAlgorithm(uriParams),
             Code._getType(uriPath),
             rawData,
-            id
+            id,
         );
     }
 
     private static _getAccount(uriPath: string): string {
         try {
             const path = decodeURIComponent(uriPath);
-            if (path.includes(':')) {
-                return path.split(':')[1];
-            } else if (path.includes('/')) {
-                return path.split('/')[1];
+            if (path.includes(":")) {
+                return path.split(":")[1];
+            } else if (path.includes("/")) {
+                return path.split("/")[1];
             }
         } catch (e) {
-            return '';
+            return "";
         }
     }
 
     private static _getIssuer(
         uriPath: string,
-        uriParams: { get?: any }
+        uriParams: { get?: any },
     ): string {
         try {
-            if (uriParams['issuer'] !== undefined) {
-                let issuer = uriParams['issuer'];
+            if (uriParams["issuer"] !== undefined) {
+                let issuer = uriParams["issuer"];
                 // This is to handle bug in the ente auth app
-                if (issuer.endsWith('period')) {
+                if (issuer.endsWith("period")) {
                     issuer = issuer.substring(0, issuer.length - 6);
                 }
                 return issuer;
             }
             let path = decodeURIComponent(uriPath);
-            if (path.startsWith('totp/') || path.startsWith('hotp/')) {
+            if (path.startsWith("totp/") || path.startsWith("hotp/")) {
                 path = path.substring(5);
             }
-            if (path.includes(':')) {
-                return path.split(':')[0];
-            } else if (path.includes('-')) {
-                return path.split('-')[0];
+            if (path.includes(":")) {
+                return path.split(":")[0];
+            } else if (path.includes("-")) {
+                return path.split("-")[0];
             }
             return path;
         } catch (e) {
-            return '';
+            return "";
         }
     }
 
     private static _getDigits(uriParams): number {
         try {
-            return parseInt(uriParams['digits'], 10) || Code.defaultDigits;
+            return parseInt(uriParams["digits"], 10) || Code.defaultDigits;
         } catch (e) {
             return Code.defaultDigits;
         }
@@ -146,7 +146,7 @@ export class Code {
 
     private static _getPeriod(uriParams): number {
         try {
-            return parseInt(uriParams['period'], 10) || Code.defaultPeriod;
+            return parseInt(uriParams["period"], 10) || Code.defaultPeriod;
         } catch (e) {
             return Code.defaultPeriod;
         }
@@ -154,29 +154,29 @@ export class Code {
 
     private static _getAlgorithm(uriParams): AlgorithmType {
         try {
-            const algorithm = uriParams['algorithm'].toLowerCase();
-            if (algorithm === 'sha256') {
+            const algorithm = uriParams["algorithm"].toLowerCase();
+            if (algorithm === "sha256") {
                 return algorithm;
-            } else if (algorithm === 'sha512') {
+            } else if (algorithm === "sha512") {
                 return algorithm;
             }
         } catch (e) {
             // nothing
         }
-        return 'sha1';
+        return "sha1";
     }
 
     private static _getType(uriPath: string): Type {
-        const oauthType = uriPath.split('/')[0].substring(0);
-        if (oauthType.toLowerCase() === 'totp') {
-            return 'totp';
-        } else if (oauthType.toLowerCase() === 'hotp') {
-            return 'hotp';
+        const oauthType = uriPath.split("/")[0].substring(0);
+        if (oauthType.toLowerCase() === "totp") {
+            return "totp";
+        } else if (oauthType.toLowerCase() === "hotp") {
+            return "hotp";
         }
         throw new Error(`Unsupported format with host ${oauthType}`);
     }
 
     static getSanitizedSecret(uriParams): string {
-        return uriParams['secret'].replace(/ /g, '').toUpperCase();
+        return uriParams["secret"].replace(/ /g, "").toUpperCase();
     }
 }

+ 4 - 4
apps/cast/.eslintrc.js

@@ -3,11 +3,11 @@ module.exports = {
     // This is required here to ensure desktop picks the right eslint config, where this app is
     // packaged as a submodule.
     root: true,
-    extends: ['@ente/eslint-config'],
-    parser: '@typescript-eslint/parser',
+    extends: ["@ente/eslint-config"],
+    parser: "@typescript-eslint/parser",
     parserOptions: {
         tsconfigRootDir: __dirname,
-        project: './tsconfig.json',
+        project: "./tsconfig.json",
     },
-    ignorePatterns: ['.eslintrc.js', 'out'],
+    ignorePatterns: [".eslintrc.js", "out"],
 };

+ 1 - 1
apps/cast/next.config.js

@@ -1,3 +1,3 @@
-const nextConfigBase = require('@/next/next.config.base.js');
+const nextConfigBase = require("@/next/next.config.base.js");
 
 module.exports = nextConfigBase;

+ 2 - 2
apps/cast/sentry.client.config.ts

@@ -1,3 +1,3 @@
-import { initSentry } from '@ente/shared/sentry/config/sentry.config.base';
+import { initSentry } from "@ente/shared/sentry/config/sentry.config.base";
 
-initSentry('https://0f7214c7feb9b1dd2fed5db09b42fa1b@sentry.ente.io/5');
+initSentry("https://0f7214c7feb9b1dd2fed5db09b42fa1b@sentry.ente.io/5");

+ 5 - 4
apps/cast/src/components/FilledCircleCheck/index.tsx

@@ -1,5 +1,5 @@
-import { useEffect, useState } from 'react';
-import styles from './FilledCircleCheck.module.scss'; // Import our CSS module
+import { useEffect, useState } from "react";
+import styles from "./FilledCircleCheck.module.scss"; // Import our CSS module
 
 const FilledCircleCheck = () => {
     const [animate, setAnimate] = useState(false);
@@ -9,11 +9,12 @@ const FilledCircleCheck = () => {
     }, []);
 
     return (
-        <div className={`${styles.circle} ${animate ? styles.animate : ''}`}>
+        <div className={`${styles.circle} ${animate ? styles.animate : ""}`}>
             <svg
                 className={styles.checkmark}
                 xmlns="http://www.w3.org/2000/svg"
-                viewBox="0 0 52 52">
+                viewBox="0 0 52 52"
+            >
                 <circle
                     className={styles.checkmark__circle}
                     cx="26"

+ 39 - 35
apps/cast/src/components/LargeType.tsx

@@ -1,58 +1,62 @@
 const colourPool = [
-    '#87CEFA', // Light Blue
-    '#90EE90', // Light Green
-    '#F08080', // Light Coral
-    '#FFFFE0', // Light Yellow
-    '#FFB6C1', // Light Pink
-    '#E0FFFF', // Light Cyan
-    '#FAFAD2', // Light Goldenrod
-    '#87CEFA', // Light Sky Blue
-    '#D3D3D3', // Light Gray
-    '#B0C4DE', // Light Steel Blue
-    '#FFA07A', // Light Salmon
-    '#20B2AA', // Light Sea Green
-    '#778899', // Light Slate Gray
-    '#AFEEEE', // Light Turquoise
-    '#7A58C1', // Light Violet
-    '#FFA500', // Light Orange
-    '#A0522D', // Light Brown
-    '#9370DB', // Light Purple
-    '#008080', // Light Teal
-    '#808000', // Light Olive
+    "#87CEFA", // Light Blue
+    "#90EE90", // Light Green
+    "#F08080", // Light Coral
+    "#FFFFE0", // Light Yellow
+    "#FFB6C1", // Light Pink
+    "#E0FFFF", // Light Cyan
+    "#FAFAD2", // Light Goldenrod
+    "#87CEFA", // Light Sky Blue
+    "#D3D3D3", // Light Gray
+    "#B0C4DE", // Light Steel Blue
+    "#FFA07A", // Light Salmon
+    "#20B2AA", // Light Sea Green
+    "#778899", // Light Slate Gray
+    "#AFEEEE", // Light Turquoise
+    "#7A58C1", // Light Violet
+    "#FFA500", // Light Orange
+    "#A0522D", // Light Brown
+    "#9370DB", // Light Purple
+    "#008080", // Light Teal
+    "#808000", // Light Olive
 ];
 
 export default function LargeType({ chars }: { chars: string[] }) {
     return (
         <table
             style={{
-                fontSize: '4rem',
-                fontWeight: 'bold',
-                fontFamily: 'monospace',
-                display: 'flex',
-                position: 'relative',
-            }}>
+                fontSize: "4rem",
+                fontWeight: "bold",
+                fontFamily: "monospace",
+                display: "flex",
+                position: "relative",
+            }}
+        >
             {chars.map((char, i) => (
                 <tr
                     key={i}
                     style={{
-                        display: 'flex',
-                        flexDirection: 'column',
-                        alignItems: 'center',
-                        padding: '0.5rem',
+                        display: "flex",
+                        flexDirection: "column",
+                        alignItems: "center",
+                        padding: "0.5rem",
                         // alternating background
-                        backgroundColor: i % 2 === 0 ? '#2e2e2e' : '#5e5e5e',
-                    }}>
+                        backgroundColor: i % 2 === 0 ? "#2e2e2e" : "#5e5e5e",
+                    }}
+                >
                     <span
                         style={{
                             color: colourPool[i % colourPool.length],
                             lineHeight: 1.2,
-                        }}>
+                        }}
+                    >
                         {char}
                     </span>
                     <span
                         style={{
-                            fontSize: '1rem',
-                        }}>
+                            fontSize: "1rem",
+                        }}
+                    >
                         {i + 1}
                     </span>
                 </tr>

+ 21 - 17
apps/cast/src/components/PairedSuccessfullyOverlay.tsx

@@ -1,38 +1,42 @@
-import FilledCircleCheck from './FilledCircleCheck';
+import FilledCircleCheck from "./FilledCircleCheck";
 
 export default function PairedSuccessfullyOverlay() {
     return (
         <div
             style={{
-                position: 'fixed',
+                position: "fixed",
                 top: 0,
                 right: 0,
-                height: '100%',
-                width: '100%',
-                display: 'flex',
-                justifyContent: 'center',
-                alignItems: 'center',
+                height: "100%",
+                width: "100%",
+                display: "flex",
+                justifyContent: "center",
+                alignItems: "center",
                 zIndex: 100,
-                backgroundColor: 'black',
-            }}>
+                backgroundColor: "black",
+            }}
+        >
             <div
                 style={{
-                    display: 'flex',
-                    alignItems: 'center',
-                    flexDirection: 'column',
-                    textAlign: 'center',
-                }}>
+                    display: "flex",
+                    alignItems: "center",
+                    flexDirection: "column",
+                    textAlign: "center",
+                }}
+            >
                 <FilledCircleCheck />
                 <h2
                     style={{
                         marginBottom: 0,
-                    }}>
+                    }}
+                >
                     Pairing Complete
                 </h2>
                 <p
                     style={{
-                        lineHeight: '1.5rem',
-                    }}>
+                        lineHeight: "1.5rem",
+                    }}
+                >
                     We're preparing your album.
                     <br /> This should only take a few seconds.
                 </p>

+ 25 - 23
apps/cast/src/components/Theatre/PhotoAuditorium.tsx

@@ -1,5 +1,5 @@
-import { SlideshowContext } from 'pages/slideshow';
-import { useContext, useEffect, useState } from 'react';
+import { SlideshowContext } from "pages/slideshow";
+import { useContext, useEffect, useState } from "react";
 
 export default function PhotoAuditorium({
     url,
@@ -49,38 +49,40 @@ export default function PhotoAuditorium({
     return (
         <div
             style={{
-                width: '100vw',
-                height: '100vh',
+                width: "100vw",
+                height: "100vh",
                 backgroundImage: `url(${url})`,
-                backgroundSize: 'cover',
-                backgroundPosition: 'center',
-                backgroundRepeat: 'no-repeat',
-                backgroundBlendMode: 'multiply',
-                backgroundColor: 'rgba(0, 0, 0, 0.5)',
-            }}>
+                backgroundSize: "cover",
+                backgroundPosition: "center",
+                backgroundRepeat: "no-repeat",
+                backgroundBlendMode: "multiply",
+                backgroundColor: "rgba(0, 0, 0, 0.5)",
+            }}
+        >
             <div
                 style={{
-                    height: '100%',
-                    width: '100%',
-                    display: 'flex',
-                    justifyContent: 'center',
-                    alignItems: 'center',
-                    backdropFilter: 'blur(10px)',
-                }}>
+                    height: "100%",
+                    width: "100%",
+                    display: "flex",
+                    justifyContent: "center",
+                    alignItems: "center",
+                    backdropFilter: "blur(10px)",
+                }}
+            >
                 <img
                     src={url}
                     style={{
-                        maxWidth: '100%',
-                        maxHeight: '100%',
-                        display: showPreloadedNextSlide ? 'none' : 'block',
+                        maxWidth: "100%",
+                        maxHeight: "100%",
+                        display: showPreloadedNextSlide ? "none" : "block",
                     }}
                 />
                 <img
                     src={nextSlideUrl}
                     style={{
-                        maxWidth: '100%',
-                        maxHeight: '100%',
-                        display: showPreloadedNextSlide ? 'block' : 'none',
+                        maxWidth: "100%",
+                        maxHeight: "100%",
+                        display: showPreloadedNextSlide ? "block" : "none",
                     }}
                     onLoad={() => {
                         setNextSlidePrerendered(true);

+ 14 - 12
apps/cast/src/components/Theatre/VideoAuditorium.tsx

@@ -1,6 +1,6 @@
-import mime from 'mime-types';
-import { SlideshowContext } from 'pages/slideshow';
-import { useContext, useEffect, useRef } from 'react';
+import mime from "mime-types";
+import { SlideshowContext } from "pages/slideshow";
+import { useContext, useEffect, useRef } from "react";
 
 export default function VideoAuditorium({
     name,
@@ -30,22 +30,24 @@ export default function VideoAuditorium({
     return (
         <div
             style={{
-                width: '100vw',
-                height: '100vh',
-                display: 'flex',
-                justifyContent: 'center',
-                alignItems: 'center',
-            }}>
+                width: "100vw",
+                height: "100vh",
+                display: "flex",
+                justifyContent: "center",
+                alignItems: "center",
+            }}
+        >
             <video
                 ref={videoRef}
                 autoPlay
                 controls
                 style={{
-                    maxWidth: '100vw',
-                    maxHeight: '100vh',
+                    maxWidth: "100vw",
+                    maxHeight: "100vh",
                 }}
                 onError={showNextSlide}
-                onEnded={showNextSlide}>
+                onEnded={showNextSlide}
+            >
                 <source src={url} type={mime.lookup(name)} />
             </video>
         </div>

+ 2 - 2
apps/cast/src/components/Theatre/index.tsx

@@ -1,5 +1,5 @@
-import { FILE_TYPE } from 'constants/file';
-import PhotoAuditorium from './PhotoAuditorium';
+import { FILE_TYPE } from "constants/file";
+import PhotoAuditorium from "./PhotoAuditorium";
 // import VideoAuditorium from './VideoAuditorium';
 
 interface fileProp {

+ 6 - 6
apps/cast/src/components/TimerBar.tsx

@@ -1,9 +1,9 @@
-import { useEffect, useState } from 'react';
+import { useEffect, useState } from "react";
 
 export default function TimerBar({ percentage }: { percentage: number }) {
-    const okColor = '#75C157';
-    const warningColor = '#FFC000';
-    const lateColor = '#FF0000';
+    const okColor = "#75C157";
+    const warningColor = "#FFC000";
+    const lateColor = "#FF0000";
 
     const [backgroundColor, setBackgroundColor] = useState(okColor);
 
@@ -21,9 +21,9 @@ export default function TimerBar({ percentage }: { percentage: number }) {
         <div
             style={{
                 width: `${percentage}%`, // Set the width based on the time left
-                height: '10px', // Same as the border thickness
+                height: "10px", // Same as the border thickness
                 backgroundColor, // The color of the moving border
-                transition: 'width 1s linear', // Smooth transition for the width change
+                transition: "width 1s linear", // Smooth transition for the width change
             }}
         />
     );

+ 11 - 11
apps/cast/src/constants/apps.ts

@@ -1,11 +1,11 @@
-import { getAlbumsURL } from '@ente/shared/network/api';
-import { runningInBrowser } from '@ente/shared/platform';
-import { PAGES } from 'constants/pages';
+import { getAlbumsURL } from "@ente/shared/network/api";
+import { runningInBrowser } from "@ente/shared/platform";
+import { PAGES } from "constants/pages";
 
 export enum APPS {
-    PHOTOS = 'PHOTOS',
-    AUTH = 'AUTH',
-    ALBUMS = 'ALBUMS',
+    PHOTOS = "PHOTOS",
+    AUTH = "AUTH",
+    ALBUMS = "ALBUMS",
 }
 
 export const ALLOWED_APP_PAGES = new Map([
@@ -29,9 +29,9 @@ export const ALLOWED_APP_PAGES = new Map([
 ]);
 
 export const CLIENT_PACKAGE_NAMES = new Map([
-    [APPS.ALBUMS, 'io.ente.albums.web'],
-    [APPS.PHOTOS, 'io.ente.photos.web'],
-    [APPS.AUTH, 'io.ente.auth.web'],
+    [APPS.ALBUMS, "io.ente.albums.web"],
+    [APPS.PHOTOS, "io.ente.photos.web"],
+    [APPS.AUTH, "io.ente.auth.web"],
 ]);
 
 export const getAppNameAndTitle = () => {
@@ -41,9 +41,9 @@ export const getAppNameAndTitle = () => {
     const currentURL = new URL(window.location.href);
     const albumsURL = new URL(getAlbumsURL());
     if (currentURL.origin === albumsURL.origin) {
-        return { name: APPS.ALBUMS, title: 'ente Photos' };
+        return { name: APPS.ALBUMS, title: "ente Photos" };
     } else {
-        return { name: APPS.PHOTOS, title: 'ente Photos' };
+        return { name: APPS.PHOTOS, title: "ente Photos" };
     }
 };
 

+ 3 - 3
apps/cast/src/constants/cache.ts

@@ -1,5 +1,5 @@
 export enum CACHES {
-    THUMBS = 'thumbs',
-    FACE_CROPS = 'face-crops',
-    FILES = 'files',
+    THUMBS = "thumbs",
+    FACE_CROPS = "face-crops",
+    FILES = "files",
 }

+ 20 - 20
apps/cast/src/constants/collection.ts

@@ -3,31 +3,31 @@ export const TRASH_SECTION = -2;
 export const DUMMY_UNCATEGORIZED_COLLECTION = -3;
 export const HIDDEN_ITEMS_SECTION = -4;
 export const ALL_SECTION = 0;
-export const DEFAULT_HIDDEN_COLLECTION_USER_FACING_NAME = 'Hidden';
+export const DEFAULT_HIDDEN_COLLECTION_USER_FACING_NAME = "Hidden";
 
 export enum CollectionType {
-    folder = 'folder',
-    favorites = 'favorites',
-    album = 'album',
-    uncategorized = 'uncategorized',
+    folder = "folder",
+    favorites = "favorites",
+    album = "album",
+    uncategorized = "uncategorized",
 }
 
 export enum CollectionSummaryType {
-    folder = 'folder',
-    favorites = 'favorites',
-    album = 'album',
-    archive = 'archive',
-    trash = 'trash',
-    uncategorized = 'uncategorized',
-    all = 'all',
-    outgoingShare = 'outgoingShare',
-    incomingShareViewer = 'incomingShareViewer',
-    incomingShareCollaborator = 'incomingShareCollaborator',
-    sharedOnlyViaLink = 'sharedOnlyViaLink',
-    archived = 'archived',
-    defaultHidden = 'defaultHidden',
-    hiddenItems = 'hiddenItems',
-    pinned = 'pinned',
+    folder = "folder",
+    favorites = "favorites",
+    album = "album",
+    archive = "archive",
+    trash = "trash",
+    uncategorized = "uncategorized",
+    all = "all",
+    outgoingShare = "outgoingShare",
+    incomingShareViewer = "incomingShareViewer",
+    incomingShareCollaborator = "incomingShareCollaborator",
+    sharedOnlyViaLink = "sharedOnlyViaLink",
+    archived = "archived",
+    defaultHidden = "defaultHidden",
+    hiddenItems = "hiddenItems",
+    pinned = "pinned",
 }
 export enum COLLECTION_LIST_SORT_BY {
     NAME,

+ 3 - 3
apps/cast/src/constants/ffmpeg.ts

@@ -1,3 +1,3 @@
-export const INPUT_PATH_PLACEHOLDER = 'INPUT';
-export const FFMPEG_PLACEHOLDER = 'FFMPEG';
-export const OUTPUT_PATH_PLACEHOLDER = 'OUTPUT';
+export const INPUT_PATH_PLACEHOLDER = "INPUT";
+export const FFMPEG_PLACEHOLDER = "FFMPEG";
+export const OUTPUT_PATH_PLACEHOLDER = "OUTPUT";

+ 25 - 25
apps/cast/src/constants/file.ts

@@ -4,10 +4,10 @@ export const MAX_EDITED_CREATION_TIME = new Date();
 export const MAX_EDITED_FILE_NAME_LENGTH = 100;
 export const MAX_CAPTION_SIZE = 5000;
 
-export const TYPE_HEIC = 'heic';
-export const TYPE_HEIF = 'heif';
-export const TYPE_JPEG = 'jpeg';
-export const TYPE_JPG = 'jpg';
+export const TYPE_HEIC = "heic";
+export const TYPE_HEIF = "heif";
+export const TYPE_JPEG = "jpeg";
+export const TYPE_JPG = "jpg";
 
 export enum FILE_TYPE {
     IMAGE,
@@ -17,27 +17,27 @@ export enum FILE_TYPE {
 }
 
 export const RAW_FORMATS = [
-    'heic',
-    'rw2',
-    'tiff',
-    'arw',
-    'cr3',
-    'cr2',
-    'raf',
-    'nef',
-    'psd',
-    'dng',
-    'tif',
+    "heic",
+    "rw2",
+    "tiff",
+    "arw",
+    "cr3",
+    "cr2",
+    "raf",
+    "nef",
+    "psd",
+    "dng",
+    "tif",
 ];
 export const SUPPORTED_RAW_FORMATS = [
-    'heic',
-    'rw2',
-    'tiff',
-    'arw',
-    'cr3',
-    'cr2',
-    'nef',
-    'psd',
-    'dng',
-    'tif',
+    "heic",
+    "rw2",
+    "tiff",
+    "arw",
+    "cr3",
+    "cr2",
+    "nef",
+    "psd",
+    "dng",
+    "tif",
 ];

+ 2 - 2
apps/cast/src/constants/gallery.ts

@@ -8,8 +8,8 @@ export const SPACE_BTW_DATES = 44;
 export const SPACE_BTW_DATES_TO_IMAGE_CONTAINER_WIDTH_RATIO = 0.244;
 
 export enum PLAN_PERIOD {
-    MONTH = 'month',
-    YEAR = 'year',
+    MONTH = "month",
+    YEAR = "year",
 }
 
 export const SYNC_INTERVAL_IN_MICROSECONDS = 1000 * 60 * 5; // 5 minutes

+ 16 - 16
apps/cast/src/constants/pages.ts

@@ -1,20 +1,20 @@
 export enum PAGES {
-    CHANGE_EMAIL = '/change-email',
-    CHANGE_PASSWORD = '/change-password',
-    CREDENTIALS = '/credentials',
-    GALLERY = '/gallery',
-    GENERATE = '/generate',
-    LOGIN = '/login',
-    RECOVER = '/recover',
-    SIGNUP = '/signup',
-    TWO_FACTOR_SETUP = '/two-factor/setup',
-    TWO_FACTOR_VERIFY = '/two-factor/verify',
-    TWO_FACTOR_RECOVER = '/two-factor/recover',
-    VERIFY = '/verify',
-    ROOT = '/',
-    SHARED_ALBUMS = '/shared-albums',
+    CHANGE_EMAIL = "/change-email",
+    CHANGE_PASSWORD = "/change-password",
+    CREDENTIALS = "/credentials",
+    GALLERY = "/gallery",
+    GENERATE = "/generate",
+    LOGIN = "/login",
+    RECOVER = "/recover",
+    SIGNUP = "/signup",
+    TWO_FACTOR_SETUP = "/two-factor/setup",
+    TWO_FACTOR_VERIFY = "/two-factor/verify",
+    TWO_FACTOR_RECOVER = "/two-factor/recover",
+    VERIFY = "/verify",
+    ROOT = "/",
+    SHARED_ALBUMS = "/shared-albums",
     // ML_DEBUG = '/ml-debug',
-    DEDUPLICATE = '/deduplicate',
+    DEDUPLICATE = "/deduplicate",
     // AUTH page is used to show (auth)enticator codes
-    AUTH = '/auth',
+    AUTH = "/auth",
 }

+ 54 - 54
apps/cast/src/constants/upload.ts

@@ -1,52 +1,52 @@
-import { ENCRYPTION_CHUNK_SIZE } from '@ente/shared/crypto/constants';
-import { FILE_TYPE } from 'constants/file';
+import { ENCRYPTION_CHUNK_SIZE } from "@ente/shared/crypto/constants";
+import { FILE_TYPE } from "constants/file";
 import {
     FileTypeInfo,
     ImportSuggestion,
     Location,
     ParsedExtractedMetadata,
-} from 'types/upload';
+} from "types/upload";
 
 // list of format that were missed by type-detection for some files.
 export const WHITELISTED_FILE_FORMATS: FileTypeInfo[] = [
-    { fileType: FILE_TYPE.IMAGE, exactType: 'jpeg', mimeType: 'image/jpeg' },
-    { fileType: FILE_TYPE.IMAGE, exactType: 'jpg', mimeType: 'image/jpeg' },
-    { fileType: FILE_TYPE.VIDEO, exactType: 'webm', mimeType: 'video/webm' },
-    { fileType: FILE_TYPE.VIDEO, exactType: 'mod', mimeType: 'video/mpeg' },
-    { fileType: FILE_TYPE.VIDEO, exactType: 'mp4', mimeType: 'video/mp4' },
-    { fileType: FILE_TYPE.IMAGE, exactType: 'gif', mimeType: 'image/gif' },
-    { fileType: FILE_TYPE.VIDEO, exactType: 'dv', mimeType: 'video/x-dv' },
+    { fileType: FILE_TYPE.IMAGE, exactType: "jpeg", mimeType: "image/jpeg" },
+    { fileType: FILE_TYPE.IMAGE, exactType: "jpg", mimeType: "image/jpeg" },
+    { fileType: FILE_TYPE.VIDEO, exactType: "webm", mimeType: "video/webm" },
+    { fileType: FILE_TYPE.VIDEO, exactType: "mod", mimeType: "video/mpeg" },
+    { fileType: FILE_TYPE.VIDEO, exactType: "mp4", mimeType: "video/mp4" },
+    { fileType: FILE_TYPE.IMAGE, exactType: "gif", mimeType: "image/gif" },
+    { fileType: FILE_TYPE.VIDEO, exactType: "dv", mimeType: "video/x-dv" },
     {
         fileType: FILE_TYPE.VIDEO,
-        exactType: 'wmv',
-        mimeType: 'video/x-ms-asf',
+        exactType: "wmv",
+        mimeType: "video/x-ms-asf",
     },
     {
         fileType: FILE_TYPE.VIDEO,
-        exactType: 'hevc',
-        mimeType: 'video/hevc',
+        exactType: "hevc",
+        mimeType: "video/hevc",
     },
     {
         fileType: FILE_TYPE.IMAGE,
-        exactType: 'raf',
-        mimeType: 'image/x-fuji-raf',
+        exactType: "raf",
+        mimeType: "image/x-fuji-raf",
     },
     {
         fileType: FILE_TYPE.IMAGE,
-        exactType: 'orf',
-        mimeType: 'image/x-olympus-orf',
+        exactType: "orf",
+        mimeType: "image/x-olympus-orf",
     },
 
     {
         fileType: FILE_TYPE.IMAGE,
-        exactType: 'crw',
-        mimeType: 'image/x-canon-crw',
+        exactType: "crw",
+        mimeType: "image/x-canon-crw",
     },
 ];
 
-export const KNOWN_NON_MEDIA_FORMATS = ['xmp', 'html', 'txt'];
+export const KNOWN_NON_MEDIA_FORMATS = ["xmp", "html", "txt"];
 
-export const EXIFLESS_FORMATS = ['gif', 'bmp'];
+export const EXIFLESS_FORMATS = ["gif", "bmp"];
 
 // this is the chunk size of the un-encrypted file which is read and encrypted before uploading it as a single part.
 export const MULTIPART_PART_SIZE = 20 * 1024 * 1024;
@@ -54,7 +54,7 @@ export const MULTIPART_PART_SIZE = 20 * 1024 * 1024;
 export const FILE_READER_CHUNK_SIZE = ENCRYPTION_CHUNK_SIZE;
 
 export const FILE_CHUNKS_COMBINED_FOR_A_UPLOAD_PART = Math.floor(
-    MULTIPART_PART_SIZE / FILE_READER_CHUNK_SIZE
+    MULTIPART_PART_SIZE / FILE_READER_CHUNK_SIZE,
 );
 
 export const RANDOM_PERCENTAGE_PROGRESS_FOR_PUT = () => 90 + 10 * Math.random();
@@ -88,9 +88,9 @@ export enum UPLOAD_RESULT {
 }
 
 export enum PICKED_UPLOAD_TYPE {
-    FILES = 'files',
-    FOLDERS = 'folders',
-    ZIPS = 'zips',
+    FILES = "files",
+    FOLDERS = "folders",
+    ZIPS = "zips",
 }
 
 export const MAX_FILE_SIZE_SUPPORTED = 4 * 1024 * 1024 * 1024; // 4 GB
@@ -107,36 +107,36 @@ export const NULL_EXTRACTED_METADATA: ParsedExtractedMetadata = {
 export const A_SEC_IN_MICROSECONDS = 1e6;
 
 export const DEFAULT_IMPORT_SUGGESTION: ImportSuggestion = {
-    rootFolderName: '',
+    rootFolderName: "",
     hasNestedFolders: false,
     hasRootLevelFileWithFolder: false,
 };
 
 export const BLACK_THUMBNAIL_BASE64 =
-    '/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAEBAQEBAQEB' +
-    'AQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH/2wBDAQEBAQEBAQ' +
-    'EBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH/wAARC' +
-    'ACWASwDAREAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUF' +
-    'BAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk' +
-    '6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztL' +
-    'W2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAA' +
-    'AAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVY' +
-    'nLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImK' +
-    'kpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oAD' +
-    'AMBAAIRAxEAPwD/AD/6ACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKA' +
-    'CgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACg' +
-    'AoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKAC' +
-    'gAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAo' +
-    'AKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACg' +
-    'AoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACg' +
-    'AoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKA' +
-    'CgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKA' +
-    'CgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoA' +
-    'KACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACg' +
-    'AoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAo' +
-    'AKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKA' +
-    'CgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAK' +
-    'ACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoA' +
-    'KACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAo' +
-    'AKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAo' +
-    'AKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgD/9k=';
+    "/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAEBAQEBAQEB" +
+    "AQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH/2wBDAQEBAQEBAQ" +
+    "EBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH/wAARC" +
+    "ACWASwDAREAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUF" +
+    "BAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk" +
+    "6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztL" +
+    "W2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAA" +
+    "AAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVY" +
+    "nLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImK" +
+    "kpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oAD" +
+    "AMBAAIRAxEAPwD/AD/6ACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKA" +
+    "CgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACg" +
+    "AoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKAC" +
+    "gAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAo" +
+    "AKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACg" +
+    "AoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACg" +
+    "AoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKA" +
+    "CgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKA" +
+    "CgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoA" +
+    "KACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACg" +
+    "AoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAo" +
+    "AKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKA" +
+    "CgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAK" +
+    "ACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoA" +
+    "KACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAo" +
+    "AKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAo" +
+    "AKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgD/9k=";

+ 9 - 9
apps/cast/src/constants/urls.ts

@@ -1,19 +1,19 @@
-export const ENTE_WEBSITE_LINK = 'https://ente.io';
+export const ENTE_WEBSITE_LINK = "https://ente.io";
 
-export const ML_BLOG_LINK = 'https://ente.io/blog/desktop-ml-beta';
+export const ML_BLOG_LINK = "https://ente.io/blog/desktop-ml-beta";
 
 export const FACE_SEARCH_PRIVACY_POLICY_LINK =
-    'https://ente.io/privacy#8-biometric-information-privacy-policy';
+    "https://ente.io/privacy#8-biometric-information-privacy-policy";
 
-export const SUPPORT_EMAIL = 'support@ente.io';
+export const SUPPORT_EMAIL = "support@ente.io";
 
-export const APP_DOWNLOAD_URL = 'https://ente.io/download/desktop';
+export const APP_DOWNLOAD_URL = "https://ente.io/download/desktop";
 
-export const FEEDBACK_EMAIL = 'feedback@ente.io';
+export const FEEDBACK_EMAIL = "feedback@ente.io";
 
-export const DELETE_ACCOUNT_EMAIL = 'account-deletion@ente.io';
+export const DELETE_ACCOUNT_EMAIL = "account-deletion@ente.io";
 
-export const WEB_ROADMAP_URL = 'https://github.com/ente-io/photos-web/issues';
+export const WEB_ROADMAP_URL = "https://github.com/ente-io/photos-web/issues";
 
 export const DESKTOP_ROADMAP_URL =
-    'https://github.com/ente-io/photos-desktop/issues';
+    "https://github.com/ente-io/photos-desktop/issues";

+ 9 - 8
apps/cast/src/pages/_app.tsx

@@ -1,9 +1,9 @@
-import type { AppProps } from 'next/app';
-import 'styles/global.css';
-import { ThemeProvider, CssBaseline } from '@mui/material';
-import { getTheme } from '@ente/shared/themes';
-import { THEME_COLOR } from '@ente/shared/themes/constants';
-import { APPS } from '@ente/shared/apps/constants';
+import { APPS } from "@ente/shared/apps/constants";
+import { getTheme } from "@ente/shared/themes";
+import { THEME_COLOR } from "@ente/shared/themes/constants";
+import { CssBaseline, ThemeProvider } from "@mui/material";
+import type { AppProps } from "next/app";
+import "styles/global.css";
 
 export default function App({ Component, pageProps }: AppProps) {
     return (
@@ -12,8 +12,9 @@ export default function App({ Component, pageProps }: AppProps) {
 
             <main
                 style={{
-                    display: 'contents',
-                }}>
+                    display: "contents",
+                }}
+            >
                 <Component {...pageProps} />
             </main>
         </ThemeProvider>

+ 11 - 9
apps/cast/src/pages/_document.tsx

@@ -1,22 +1,24 @@
-import { Html, Head, Main, NextScript } from 'next/document';
+import { Head, Html, Main, NextScript } from "next/document";
 
 export default function Document() {
     return (
         <Html
             lang="en"
             style={{
-                height: '100%',
-                width: '100%',
-            }}>
+                height: "100%",
+                width: "100%",
+            }}
+        >
             <Head />
             <body
                 style={{
-                    height: '100%',
-                    width: '100%',
+                    height: "100%",
+                    width: "100%",
                     margin: 0,
-                    backgroundColor: 'black',
-                    color: 'white',
-                }}>
+                    backgroundColor: "black",
+                    color: "white",
+                }}
+            >
                 <Main />
                 <NextScript />
             </body>

+ 67 - 60
apps/cast/src/pages/index.tsx

@@ -1,13 +1,13 @@
-import EnteSpinner from '@ente/shared/components/EnteSpinner';
-import { boxSealOpen, toB64 } from '@ente/shared/crypto/internal/libsodium';
-import { useCastReceiver } from '@ente/shared/hooks/useCastReceiver';
-import { addLogLine } from '@ente/shared/logging';
-import castGateway from '@ente/shared/network/cast';
-import LargeType from 'components/LargeType';
-import _sodium from 'libsodium-wrappers';
-import { useRouter } from 'next/router';
-import { useEffect, useState } from 'react';
-import { storeCastData } from 'services/cast/castService';
+import EnteSpinner from "@ente/shared/components/EnteSpinner";
+import { boxSealOpen, toB64 } from "@ente/shared/crypto/internal/libsodium";
+import { useCastReceiver } from "@ente/shared/hooks/useCastReceiver";
+import { addLogLine } from "@ente/shared/logging";
+import castGateway from "@ente/shared/network/cast";
+import LargeType from "components/LargeType";
+import _sodium from "libsodium-wrappers";
+import { useRouter } from "next/router";
+import { useEffect, useState } from "react";
+import { storeCastData } from "services/cast/castService";
 
 // Function to generate cryptographically secure digits
 const generateSecureData = (length: number): Uint8Array => {
@@ -21,7 +21,7 @@ const generateSecureData = (length: number): Uint8Array => {
 };
 
 const convertDataToDecimalString = (data: Uint8Array): string => {
-    let decimalString = '';
+    let decimalString = "";
     for (let i = 0; i < data.length; i++) {
         decimalString += data[i].toString(); // No need to pad, as each value is a single digit
     }
@@ -30,8 +30,8 @@ const convertDataToDecimalString = (data: Uint8Array): string => {
 
 export default function PairingMode() {
     const [digits, setDigits] = useState<string[]>([]);
-    const [publicKeyB64, setPublicKeyB64] = useState('');
-    const [privateKeyB64, setPrivateKeyB64] = useState('');
+    const [publicKeyB64, setPublicKeyB64] = useState("");
+    const [privateKeyB64, setPrivateKeyB64] = useState("");
     const [codePending, setCodePending] = useState(true);
     const [isCastReady, setIsCastReady] = useState(false);
 
@@ -49,18 +49,18 @@ export default function PairingMode() {
         try {
             const options = new cast.framework.CastReceiverOptions();
             options.customNamespaces = Object.assign({});
-            options.customNamespaces['urn:x-cast:pair-request'] =
+            options.customNamespaces["urn:x-cast:pair-request"] =
                 cast.framework.system.MessageType.JSON;
 
             options.disableIdleTimeout = true;
 
             context.addCustomMessageListener(
-                'urn:x-cast:pair-request',
-                messageReceiveHandler
+                "urn:x-cast:pair-request",
+                messageReceiveHandler,
             );
             context.start(options);
         } catch (e) {
-            addLogLine(e, 'failed to create cast context');
+            addLogLine(e, "failed to create cast context");
         }
         setIsCastReady(true);
         return () => {
@@ -74,17 +74,17 @@ export default function PairingMode() {
         data: any;
     }) => {
         cast.framework.CastReceiverContext.getInstance().sendCustomMessage(
-            'urn:x-cast:pair-request',
+            "urn:x-cast:pair-request",
             message.senderId,
             {
-                code: digits.join(''),
-            }
+                code: digits.join(""),
+            },
         );
     };
 
     const init = async () => {
         const data = generateSecureData(6);
-        setDigits(convertDataToDecimalString(data).split(''));
+        setDigits(convertDataToDecimalString(data).split(""));
         const keypair = await generateKeyPair();
         setPublicKeyB64(await toB64(keypair.publicKey));
         setPrivateKeyB64(await toB64(keypair.privateKey));
@@ -105,10 +105,10 @@ export default function PairingMode() {
         // see if we were acknowledged on the client.
         // the client will send us the encrypted payload using our public key that we advertised.
         // then, we can decrypt this and store all the necessary info locally so we can play the collection slideshow.
-        let devicePayload = '';
+        let devicePayload = "";
         try {
             const encDastData = await castGateway.getCastData(
-                `${digits.join('')}`
+                `${digits.join("")}`,
             );
             if (!encDastData) return;
             devicePayload = encDastData;
@@ -121,7 +121,7 @@ export default function PairingMode() {
         const decryptedPayload = await boxSealOpen(
             devicePayload,
             publicKeyB64,
-            privateKeyB64
+            privateKeyB64,
         );
 
         const decryptedPayloadObj = JSON.parse(atob(decryptedPayload));
@@ -133,8 +133,8 @@ export default function PairingMode() {
         // hey client, we exist!
         try {
             await castGateway.registerDevice(
-                `${digits.join('')}`,
-                publicKeyB64
+                `${digits.join("")}`,
+                publicKeyB64,
             );
             setCodePending(false);
         } catch (e) {
@@ -155,7 +155,7 @@ export default function PairingMode() {
             const data = await pollForCastData();
             if (!data) return;
             storeCastData(data);
-            await router.push('/slideshow');
+            await router.push("/slideshow");
         }, 1000);
 
         return () => {
@@ -172,30 +172,34 @@ export default function PairingMode() {
         <>
             <div
                 style={{
-                    height: '100%',
-                    display: 'flex',
-                    justifyContent: 'center',
-                    alignItems: 'center',
-                }}>
+                    height: "100%",
+                    display: "flex",
+                    justifyContent: "center",
+                    alignItems: "center",
+                }}
+            >
                 <div
                     style={{
-                        textAlign: 'center',
-                        display: 'flex',
-                        flexDirection: 'column',
-                        alignItems: 'center',
-                    }}>
+                        textAlign: "center",
+                        display: "flex",
+                        flexDirection: "column",
+                        alignItems: "center",
+                    }}
+                >
                     <img width={150} src="/images/ente.svg" />
                     <h1
                         style={{
-                            fontWeight: 'normal',
-                        }}>
+                            fontWeight: "normal",
+                        }}
+                    >
                         Enter this code on <b>ente</b> to pair this TV
                     </h1>
                     <div
                         style={{
-                            borderRadius: '10px',
-                            overflow: 'hidden',
-                        }}>
+                            borderRadius: "10px",
+                            overflow: "hidden",
+                        }}
+                    >
                         {codePending ? (
                             <EnteSpinner />
                         ) : (
@@ -206,33 +210,36 @@ export default function PairingMode() {
                     </div>
                     <p
                         style={{
-                            fontSize: '1.2rem',
-                        }}>
-                        Visit{' '}
+                            fontSize: "1.2rem",
+                        }}
+                    >
+                        Visit{" "}
                         <a
                             style={{
-                                textDecoration: 'none',
-                                color: '#87CEFA',
-                                fontWeight: 'bold',
+                                textDecoration: "none",
+                                color: "#87CEFA",
+                                fontWeight: "bold",
                             }}
                             href="https://ente.io/cast"
-                            target="_blank">
+                            target="_blank"
+                        >
                             ente.io/cast
-                        </a>{' '}
+                        </a>{" "}
                         for help
                     </p>
                     <div
                         style={{
-                            position: 'fixed',
-                            bottom: '20px',
-                            right: '20px',
-                            backgroundColor: 'white',
-                            display: 'flex',
-                            justifyContent: 'center',
-                            alignItems: 'center',
-                            padding: '10px',
-                            borderRadius: '10px',
-                        }}>
+                            position: "fixed",
+                            bottom: "20px",
+                            right: "20px",
+                            backgroundColor: "white",
+                            display: "flex",
+                            justifyContent: "center",
+                            alignItems: "center",
+                            padding: "10px",
+                            borderRadius: "10px",
+                        }}
+                    >
                         <img src="/images/help-qrcode.webp" />
                     </div>
                 </div>

+ 24 - 24
apps/cast/src/pages/slideshow.tsx

@@ -1,17 +1,17 @@
-import { logError } from '@ente/shared/sentry';
-import PairedSuccessfullyOverlay from 'components/PairedSuccessfullyOverlay';
-import Theatre from 'components/Theatre';
-import { FILE_TYPE } from 'constants/file';
-import { useRouter } from 'next/router';
-import { createContext, useEffect, useState } from 'react';
+import { logError } from "@ente/shared/sentry";
+import PairedSuccessfullyOverlay from "components/PairedSuccessfullyOverlay";
+import Theatre from "components/Theatre";
+import { FILE_TYPE } from "constants/file";
+import { useRouter } from "next/router";
+import { createContext, useEffect, useState } from "react";
 import {
     getCastCollection,
     getLocalFiles,
     syncPublicFiles,
-} from 'services/cast/castService';
-import { Collection } from 'types/collection';
-import { EnteFile } from 'types/file';
-import { getPreviewableImage, isRawFileFromFileName } from 'utils/file';
+} from "services/cast/castService";
+import { Collection } from "types/collection";
+import { EnteFile } from "types/file";
+import { getPreviewableImage, isRawFileFromFileName } from "utils/file";
 
 export const SlideshowContext = createContext<{
     showNextSlide: () => void;
@@ -23,24 +23,24 @@ export default function Slideshow() {
     const [collectionFiles, setCollectionFiles] = useState<EnteFile[]>([]);
 
     const [currentFile, setCurrentFile] = useState<EnteFile | undefined>(
-        undefined
+        undefined,
     );
     const [nextFile, setNextFile] = useState<EnteFile | undefined>(undefined);
 
     const [loading, setLoading] = useState(true);
-    const [castToken, setCastToken] = useState<string>('');
+    const [castToken, setCastToken] = useState<string>("");
     const [castCollection, setCastCollection] = useState<
         Collection | undefined
     >(undefined);
 
     const syncCastFiles = async (token: string) => {
         try {
-            const castToken = window.localStorage.getItem('castToken');
+            const castToken = window.localStorage.getItem("castToken");
             const requestedCollectionKey =
-                window.localStorage.getItem('collectionKey');
+                window.localStorage.getItem("collectionKey");
             const collection = await getCastCollection(
                 castToken,
-                requestedCollectionKey
+                requestedCollectionKey,
             );
             if (
                 castCollection === undefined ||
@@ -50,22 +50,22 @@ export default function Slideshow() {
                 await syncPublicFiles(token, collection, () => {});
                 const files = await getLocalFiles(String(collection.id));
                 setCollectionFiles(
-                    files.filter((file) => isFileEligibleForCast(file))
+                    files.filter((file) => isFileEligibleForCast(file)),
                 );
             }
         } catch (e) {
-            logError(e, 'error during sync');
-            router.push('/');
+            logError(e, "error during sync");
+            router.push("/");
         }
     };
 
     const init = async () => {
         try {
-            const castToken = window.localStorage.getItem('castToken');
+            const castToken = window.localStorage.getItem("castToken");
             setCastToken(castToken);
         } catch (e) {
-            logError(e, 'error during sync');
-            router.push('/');
+            logError(e, "error during sync");
+            router.push("/");
         }
     };
 
@@ -115,7 +115,7 @@ export default function Slideshow() {
 
     const showNextSlide = () => {
         const currentIndex = collectionFiles.findIndex(
-            (file) => file.id === currentFile?.id
+            (file) => file.id === currentFile?.id,
         );
 
         const nextIndex = (currentIndex + 1) % collectionFiles.length;
@@ -128,7 +128,7 @@ export default function Slideshow() {
         setNextFile(nextNextFile);
     };
 
-    const [renderableFileURL, setRenderableFileURL] = useState<string>('');
+    const [renderableFileURL, setRenderableFileURL] = useState<string>("");
 
     const getRenderableFileURL = async () => {
         if (!currentFile) return;
@@ -143,7 +143,7 @@ export default function Slideshow() {
         try {
             const blob = await getPreviewableImage(
                 currentFile as EnteFile,
-                castToken
+                castToken,
             );
 
             const url = URL.createObjectURL(blob);

+ 3 - 3
apps/cast/src/services/InMemoryStore.ts

@@ -1,7 +1,7 @@
 export enum MS_KEYS {
-    OPT_OUT_OF_CRASH_REPORTS = 'optOutOfCrashReports',
-    SRP_CONFIGURE_IN_PROGRESS = 'srpConfigureInProgress',
-    REDIRECT_URL = 'redirectUrl',
+    OPT_OUT_OF_CRASH_REPORTS = "optOutOfCrashReports",
+    SRP_CONFIGURE_IN_PROGRESS = "srpConfigureInProgress",
+    REDIRECT_URL = "redirectUrl",
 }
 
 type StoreType = Map<Partial<MS_KEYS>, any>;

+ 2 - 2
apps/cast/src/services/cache/cacheStorageFactory.ts

@@ -1,4 +1,4 @@
-import { LimitedCacheStorage } from 'types/cache/index';
+import { LimitedCacheStorage } from "types/cache/index";
 // import { ElectronCacheStorage } from 'services/electron/cache';
 // import { runningInElectron, runningInWorker } from 'utils/common';
 // import { WorkerElectronCacheStorageService } from 'services/workerElectronCache/service';
@@ -25,7 +25,7 @@ class cacheStorageFactory {
 export const CacheStorageFactory = new cacheStorageFactory();
 
 function transformBrowserCacheStorageToLimitedCacheStorage(
-    caches: CacheStorage
+    caches: CacheStorage,
 ): LimitedCacheStorage {
     return {
         async open(cacheName) {

+ 6 - 6
apps/cast/src/services/cache/cacheStorageService.ts

@@ -1,8 +1,8 @@
-import { logError } from '@ente/shared/sentry';
-import { CacheStorageFactory } from './cacheStorageFactory';
+import { logError } from "@ente/shared/sentry";
+import { CacheStorageFactory } from "./cacheStorageFactory";
 
-const SecurityError = 'SecurityError';
-const INSECURE_OPERATION = 'The operation is insecure.';
+const SecurityError = "SecurityError";
+const INSECURE_OPERATION = "The operation is insecure.";
 async function openCache(cacheName: string) {
     try {
         return await CacheStorageFactory.getCacheStorage().open(cacheName);
@@ -12,7 +12,7 @@ async function openCache(cacheName: string) {
             // no-op
         } else {
             // log and ignore, we don't want to break the caller flow, when cache is not available
-            logError(e, 'openCache failed');
+            logError(e, "openCache failed");
         }
     }
 }
@@ -25,7 +25,7 @@ async function deleteCache(cacheName: string) {
             // no-op
         } else {
             // log and ignore, we don't want to break the caller flow, when cache is not available
-            logError(e, 'deleteCache failed');
+            logError(e, "deleteCache failed");
         }
     }
 }

+ 44 - 44
apps/cast/src/services/cast/castService.ts

@@ -1,51 +1,51 @@
-import { getEndpoint } from '@ente/shared/network/api';
-import localForage from '@ente/shared/storage/localForage';
-import HTTPService from '@ente/shared/network/HTTPService';
-import { logError } from '@ente/shared/sentry';
-import { CustomError, parseSharingErrorCodes } from '@ente/shared/error';
-import ComlinkCryptoWorker from '@ente/shared/crypto';
+import ComlinkCryptoWorker from "@ente/shared/crypto";
+import { CustomError, parseSharingErrorCodes } from "@ente/shared/error";
+import HTTPService from "@ente/shared/network/HTTPService";
+import { getEndpoint } from "@ente/shared/network/api";
+import { logError } from "@ente/shared/sentry";
+import localForage from "@ente/shared/storage/localForage";
 
-import { Collection, CollectionPublicMagicMetadata } from 'types/collection';
-import { EncryptedEnteFile, EnteFile } from 'types/file';
-import { decryptFile, mergeMetadata, sortFiles } from 'utils/file';
+import { Collection, CollectionPublicMagicMetadata } from "types/collection";
+import { EncryptedEnteFile, EnteFile } from "types/file";
+import { decryptFile, mergeMetadata, sortFiles } from "utils/file";
 
 export interface SavedCollectionFiles {
     collectionLocalID: string;
     files: EnteFile[];
 }
 const ENDPOINT = getEndpoint();
-const COLLECTION_FILES_TABLE = 'collection-files';
-const COLLECTIONS_TABLE = 'collections';
+const COLLECTION_FILES_TABLE = "collection-files";
+const COLLECTIONS_TABLE = "collections";
 
 const getLastSyncKey = (collectionUID: string) => `${collectionUID}-time`;
 
 export const getLocalFiles = async (
-    collectionUID: string
+    collectionUID: string,
 ): Promise<EnteFile[]> => {
     const localSavedcollectionFiles =
         (await localForage.getItem<SavedCollectionFiles[]>(
-            COLLECTION_FILES_TABLE
+            COLLECTION_FILES_TABLE,
         )) || [];
     const matchedCollection = localSavedcollectionFiles.find(
-        (item) => item.collectionLocalID === collectionUID
+        (item) => item.collectionLocalID === collectionUID,
     );
     return matchedCollection?.files || [];
 };
 
 const savecollectionFiles = async (
     collectionUID: string,
-    files: EnteFile[]
+    files: EnteFile[],
 ) => {
     const collectionFiles =
         (await localForage.getItem<SavedCollectionFiles[]>(
-            COLLECTION_FILES_TABLE
+            COLLECTION_FILES_TABLE,
         )) || [];
     await localForage.setItem(
         COLLECTION_FILES_TABLE,
         dedupeCollectionFiles([
             { collectionLocalID: collectionUID, files },
             ...collectionFiles,
-        ])
+        ]),
     );
 };
 
@@ -55,7 +55,7 @@ export const getLocalCollections = async (collectionKey: string) => {
     const collection =
         localCollections.find(
             (localSavedPublicCollection) =>
-                localSavedPublicCollection.key === collectionKey
+                localSavedPublicCollection.key === collectionKey,
         ) || null;
     return collection;
 };
@@ -65,7 +65,7 @@ const saveCollection = async (collection: Collection) => {
         (await localForage.getItem<Collection[]>(COLLECTIONS_TABLE)) ?? [];
     await localForage.setItem(
         COLLECTIONS_TABLE,
-        dedupeCollections([collection, ...collections])
+        dedupeCollections([collection, ...collections]),
     );
 };
 
@@ -105,7 +105,7 @@ const updateSyncTime = async (collectionUID: string, time: number) =>
 export const syncPublicFiles = async (
     token: string,
     collection: Collection,
-    setPublicFiles: (files: EnteFile[]) => void
+    setPublicFiles: (files: EnteFile[]) => void,
 ) => {
     try {
         let files: EnteFile[] = [];
@@ -123,7 +123,7 @@ export const syncPublicFiles = async (
                 collection,
                 lastSyncTime,
                 files,
-                setPublicFiles
+                setPublicFiles,
             );
 
             files = [...files, ...fetchedFiles];
@@ -150,14 +150,14 @@ export const syncPublicFiles = async (
             setPublicFiles([...sortFiles(mergeMetadata(files), sortAsc)]);
         } catch (e) {
             const parsedError = parseSharingErrorCodes(e);
-            logError(e, 'failed to sync shared collection files');
+            logError(e, "failed to sync shared collection files");
             if (parsedError.message === CustomError.TOKEN_EXPIRED) {
                 throw e;
             }
         }
         return [...sortFiles(mergeMetadata(files), sortAsc)];
     } catch (e) {
-        logError(e, 'failed to get local  or sync shared collection files');
+        logError(e, "failed to get local  or sync shared collection files");
         throw e;
     }
 };
@@ -167,7 +167,7 @@ const fetchFiles = async (
     collection: Collection,
     sinceTime: number,
     files: EnteFile[],
-    setPublicFiles: (files: EnteFile[]) => void
+    setPublicFiles: (files: EnteFile[]) => void,
 ): Promise<EnteFile[]> => {
     try {
         let decryptedFiles: EnteFile[] = [];
@@ -184,9 +184,9 @@ const fetchFiles = async (
                     sinceTime: time,
                 },
                 {
-                    'Cache-Control': 'no-cache',
-                    'X-Cast-Access-Token': castToken,
-                }
+                    "Cache-Control": "no-cache",
+                    "X-Cast-Access-Token": castToken,
+                },
             );
             decryptedFiles = [
                 ...decryptedFiles,
@@ -197,7 +197,7 @@ const fetchFiles = async (
                         } else {
                             return file;
                         }
-                    }) as Promise<EnteFile>[]
+                    }) as Promise<EnteFile>[],
                 )),
             ];
 
@@ -208,28 +208,28 @@ const fetchFiles = async (
                 sortFiles(
                     mergeMetadata(
                         [...(files || []), ...decryptedFiles].filter(
-                            (item) => !item.isDeleted
-                        )
+                            (item) => !item.isDeleted,
+                        ),
                     ),
-                    sortAsc
-                )
+                    sortAsc,
+                ),
             );
         } while (resp.data.hasMore);
         return decryptedFiles;
     } catch (e) {
-        logError(e, 'Get cast files failed');
+        logError(e, "Get cast files failed");
         throw e;
     }
 };
 
 export const getCastCollection = async (
     castToken: string,
-    collectionKey: string
+    collectionKey: string,
 ): Promise<Collection> => {
     try {
         const resp = await HTTPService.get(`${ENDPOINT}/cast/info`, null, {
-            'Cache-Control': 'no-cache',
-            'X-Cast-Access-Token': castToken,
+            "Cache-Control": "no-cache",
+            "X-Cast-Access-Token": castToken,
         });
         const fetchedCollection = resp.data.collection;
 
@@ -240,7 +240,7 @@ export const getCastCollection = async (
             (await cryptoWorker.decryptToUTF8(
                 fetchedCollection.encryptedName,
                 fetchedCollection.nameDecryptionNonce,
-                collectionKey
+                collectionKey,
             )));
 
         let collectionPublicMagicMetadata: CollectionPublicMagicMetadata;
@@ -250,7 +250,7 @@ export const getCastCollection = async (
                 data: await cryptoWorker.decryptMetadata(
                     fetchedCollection.pubMagicMetadata.data,
                     fetchedCollection.pubMagicMetadata.header,
-                    collectionKey
+                    collectionKey,
                 ),
             };
         }
@@ -264,20 +264,20 @@ export const getCastCollection = async (
         await saveCollection(collection);
         return collection;
     } catch (e) {
-        logError(e, 'failed to get cast collection');
+        logError(e, "failed to get cast collection");
         throw e;
     }
 };
 
 export const removeCollection = async (
     collectionUID: string,
-    collectionKey: string
+    collectionKey: string,
 ) => {
     const collections =
         (await localForage.getItem<Collection[]>(COLLECTIONS_TABLE)) || [];
     await localForage.setItem(
         COLLECTIONS_TABLE,
-        collections.filter((collection) => collection.key !== collectionKey)
+        collections.filter((collection) => collection.key !== collectionKey),
     );
     await removeCollectionFiles(collectionUID);
 };
@@ -286,14 +286,14 @@ export const removeCollectionFiles = async (collectionUID: string) => {
     await localForage.removeItem(getLastSyncKey(collectionUID));
     const collectionFiles =
         (await localForage.getItem<SavedCollectionFiles[]>(
-            COLLECTION_FILES_TABLE
+            COLLECTION_FILES_TABLE,
         )) ?? [];
     await localForage.setItem(
         COLLECTION_FILES_TABLE,
         collectionFiles.filter(
             (collectionFiles) =>
-                collectionFiles.collectionLocalID !== collectionUID
-        )
+                collectionFiles.collectionLocalID !== collectionUID,
+        ),
     );
 };
 

+ 38 - 38
apps/cast/src/services/castDownloadManager.ts

@@ -1,19 +1,19 @@
+import { EnteFile } from "types/file";
 import {
+    createTypedObjectURL,
     generateStreamFromArrayBuffer,
     getRenderableFileURL,
-    createTypedObjectURL,
-} from 'utils/file';
-import { EnteFile } from 'types/file';
+} from "utils/file";
 
-import { FILE_TYPE } from 'constants/file';
-import { CustomError } from '@ente/shared/error';
-import ComlinkCryptoWorker from 'utils/comlink/ComlinkCryptoWorker';
-import { CACHES } from 'constants/cache';
-import { CacheStorageService } from './cache/cacheStorageService';
-import { LimitedCache } from 'types/cache';
-import { getCastFileURL, getCastThumbnailURL } from '@ente/shared/network/api';
-import HTTPService from '@ente/shared/network/HTTPService';
-import { logError } from '@ente/shared/sentry';
+import { CustomError } from "@ente/shared/error";
+import HTTPService from "@ente/shared/network/HTTPService";
+import { getCastFileURL, getCastThumbnailURL } from "@ente/shared/network/api";
+import { logError } from "@ente/shared/sentry";
+import { CACHES } from "constants/cache";
+import { FILE_TYPE } from "constants/file";
+import { LimitedCache } from "types/cache";
+import ComlinkCryptoWorker from "utils/comlink/ComlinkCryptoWorker";
+import { CacheStorageService } from "./cache/cacheStorageService";
 
 class CastDownloadManager {
     private fileObjectURLPromise = new Map<
@@ -33,7 +33,7 @@ class CastDownloadManager {
     private async getThumbnailCache() {
         try {
             const thumbnailCache = await CacheStorageService.open(
-                CACHES.THUMBS
+                CACHES.THUMBS,
             );
             return thumbnailCache;
         } catch (e) {
@@ -44,14 +44,14 @@ class CastDownloadManager {
 
     public async getCachedThumbnail(
         file: EnteFile,
-        thumbnailCache?: LimitedCache
+        thumbnailCache?: LimitedCache,
     ) {
         try {
             if (!thumbnailCache) {
                 thumbnailCache = await this.getThumbnailCache();
             }
             const cacheResp: Response = await thumbnailCache?.match(
-                file.id.toString()
+                file.id.toString(),
             );
 
             if (cacheResp) {
@@ -59,7 +59,7 @@ class CastDownloadManager {
             }
             return null;
         } catch (e) {
-            logError(e, 'failed to get cached thumbnail');
+            logError(e, "failed to get cached thumbnail");
             throw e;
         }
     }
@@ -71,7 +71,7 @@ class CastDownloadManager {
                     const thumbnailCache = await this.getThumbnailCache();
                     const cachedThumb = await this.getCachedThumbnail(
                         file,
-                        thumbnailCache
+                        thumbnailCache,
                     );
                     if (cachedThumb) {
                         return cachedThumb;
@@ -82,7 +82,7 @@ class CastDownloadManager {
                     try {
                         await thumbnailCache?.put(
                             file.id.toString(),
-                            new Response(thumbBlob)
+                            new Response(thumbBlob),
                         );
                     } catch (e) {
                         // TODO: handle storage full exception.
@@ -95,7 +95,7 @@ class CastDownloadManager {
             return await this.thumbnailObjectURLPromise.get(file.id);
         } catch (e) {
             this.thumbnailObjectURLPromise.delete(file.id);
-            logError(e, 'get castDownloadManager preview Failed');
+            logError(e, "get castDownloadManager preview Failed");
             throw e;
         }
     }
@@ -105,18 +105,18 @@ class CastDownloadManager {
             getCastThumbnailURL(file.id),
             null,
             {
-                'X-Cast-Access-Token': castToken,
+                "X-Cast-Access-Token": castToken,
             },
-            { responseType: 'arraybuffer' }
+            { responseType: "arraybuffer" },
         );
-        if (typeof resp.data === 'undefined') {
+        if (typeof resp.data === "undefined") {
             throw Error(CustomError.REQUEST_FAILED);
         }
         const cryptoWorker = await ComlinkCryptoWorker.getInstance();
         const decrypted = await cryptoWorker.decryptThumbnail(
             new Uint8Array(resp.data),
             await cryptoWorker.fromB64(file.thumbnail.decryptionHeader),
-            file.key
+            file.key,
         );
         return decrypted;
     };
@@ -132,7 +132,7 @@ class CastDownloadManager {
                 } else {
                     const fileURL = await createTypedObjectURL(
                         fileBlob,
-                        file.metadata.title
+                        file.metadata.title,
                     );
                     return { converted: [fileURL], original: [fileURL] };
                 }
@@ -145,7 +145,7 @@ class CastDownloadManager {
             return fileURLs;
         } catch (e) {
             this.fileObjectURLPromise.delete(fileKey);
-            logError(e, 'castDownloadManager failed to get file');
+            logError(e, "castDownloadManager failed to get file");
             throw e;
         }
     };
@@ -166,40 +166,40 @@ class CastDownloadManager {
                 getCastFileURL(file.id),
                 null,
                 {
-                    'X-Cast-Access-Token': castToken,
+                    "X-Cast-Access-Token": castToken,
                 },
-                { responseType: 'arraybuffer' }
+                { responseType: "arraybuffer" },
             );
-            if (typeof resp.data === 'undefined') {
+            if (typeof resp.data === "undefined") {
                 throw Error(CustomError.REQUEST_FAILED);
             }
             const decrypted = await cryptoWorker.decryptFile(
                 new Uint8Array(resp.data),
                 await cryptoWorker.fromB64(file.file.decryptionHeader),
-                file.key
+                file.key,
             );
             return generateStreamFromArrayBuffer(decrypted);
         }
         const resp = await fetch(getCastFileURL(file.id), {
             headers: {
-                'X-Cast-Access-Token': castToken,
+                "X-Cast-Access-Token": castToken,
             },
         });
         const reader = resp.body.getReader();
 
-        const contentLength = +resp.headers.get('Content-Length');
+        const contentLength = +resp.headers.get("Content-Length");
         let downloadedBytes = 0;
 
         const stream = new ReadableStream({
             async start(controller) {
                 const decryptionHeader = await cryptoWorker.fromB64(
-                    file.file.decryptionHeader
+                    file.file.decryptionHeader,
                 );
                 const fileKey = await cryptoWorker.fromB64(file.key);
                 const { pullState, decryptionChunkSize } =
                     await cryptoWorker.initChunkDecryption(
                         decryptionHeader,
-                        fileKey
+                        fileKey,
                     );
                 let data = new Uint8Array();
                 // The following function handles each data chunk
@@ -214,19 +214,19 @@ class CastDownloadManager {
                                 total: contentLength,
                             });
                             const buffer = new Uint8Array(
-                                data.byteLength + value.byteLength
+                                data.byteLength + value.byteLength,
                             );
                             buffer.set(new Uint8Array(data), 0);
                             buffer.set(new Uint8Array(value), data.byteLength);
                             if (buffer.length > decryptionChunkSize) {
                                 const fileData = buffer.slice(
                                     0,
-                                    decryptionChunkSize
+                                    decryptionChunkSize,
                                 );
                                 const { decryptedData } =
                                     await cryptoWorker.decryptFileChunk(
                                         fileData,
-                                        pullState
+                                        pullState,
                                     );
                                 controller.enqueue(decryptedData);
                                 data = buffer.slice(decryptionChunkSize);
@@ -239,7 +239,7 @@ class CastDownloadManager {
                                 const { decryptedData } =
                                     await cryptoWorker.decryptFileChunk(
                                         data,
-                                        pullState
+                                        pullState,
                                     );
                                 controller.enqueue(decryptedData);
                                 data = null;
@@ -262,7 +262,7 @@ class CastDownloadManager {
             } else {
                 this.fileDownloadProgress.set(
                     fileID,
-                    Math.round((event.loaded * 100) / event.total)
+                    Math.round((event.loaded * 100) / event.total),
                 );
             }
             this.progressUpdater(new Map(this.fileDownloadProgress));

+ 4 - 4
apps/cast/src/services/events.ts

@@ -1,12 +1,12 @@
-import { EventEmitter } from 'eventemitter3';
+import { EventEmitter } from "eventemitter3";
 
 // When registering event handlers,
 // handle errors to avoid unhandled rejection or propagation to emit call
 
 export enum Events {
-    LOGOUT = 'logout',
-    FILE_UPLOADED = 'fileUploaded',
-    LOCAL_FILES_UPDATED = 'localFilesUpdated',
+    LOGOUT = "logout",
+    FILE_UPLOADED = "fileUploaded",
+    LOCAL_FILES_UPDATED = "localFilesUpdated",
 }
 
 export const eventBus = new EventEmitter<Events>();

+ 3 - 3
apps/cast/src/services/ffmpeg/ffmpegFactory.ts

@@ -1,14 +1,14 @@
 // import isElectron from 'is-electron';
 // import { ElectronFFmpeg } from 'services/electron/ffmpeg';
-import { ElectronFile } from 'types/upload';
-import ComlinkFFmpegWorker from 'utils/comlink/ComlinkFFmpegWorker';
+import { ElectronFile } from "types/upload";
+import ComlinkFFmpegWorker from "utils/comlink/ComlinkFFmpegWorker";
 
 export interface IFFmpeg {
     run: (
         cmd: string[],
         inputFile: File | ElectronFile,
         outputFilename: string,
-        dontTimeout?: boolean
+        dontTimeout?: boolean,
     ) => Promise<File | ElectronFile>;
 }
 

+ 10 - 10
apps/cast/src/services/ffmpeg/ffmpegService.ts

@@ -1,11 +1,11 @@
+import { logError } from "@ente/shared/sentry";
 import {
     FFMPEG_PLACEHOLDER,
     INPUT_PATH_PLACEHOLDER,
     OUTPUT_PATH_PLACEHOLDER,
-} from 'constants/ffmpeg';
-import { ElectronFile } from 'types/upload';
-import ffmpegFactory from './ffmpegFactory';
-import { logError } from '@ente/shared/sentry';
+} from "constants/ffmpeg";
+import { ElectronFile } from "types/upload";
+import ffmpegFactory from "./ffmpegFactory";
 
 export async function convertToMP4(file: File | ElectronFile) {
     try {
@@ -13,18 +13,18 @@ export async function convertToMP4(file: File | ElectronFile) {
         return await ffmpegClient.run(
             [
                 FFMPEG_PLACEHOLDER,
-                '-i',
+                "-i",
                 INPUT_PATH_PLACEHOLDER,
-                '-preset',
-                'ultrafast',
+                "-preset",
+                "ultrafast",
                 OUTPUT_PATH_PLACEHOLDER,
             ],
             file,
-            'output.mp4',
-            true
+            "output.mp4",
+            true,
         );
     } catch (e) {
-        logError(e, 'ffmpeg convertToMP4 failed');
+        logError(e, "ffmpeg convertToMP4 failed");
         throw e;
     }
 }

+ 3 - 3
apps/cast/src/services/heicConversionService.ts

@@ -1,12 +1,12 @@
-import { logError } from '@ente/shared/sentry';
-import WasmHEICConverterService from './wasmHeicConverter/wasmHEICConverterService';
+import { logError } from "@ente/shared/sentry";
+import WasmHEICConverterService from "./wasmHeicConverter/wasmHEICConverterService";
 
 class HeicConversionService {
     async convert(heicFileData: Blob): Promise<Blob> {
         try {
             return await WasmHEICConverterService.convert(heicFileData);
         } catch (e) {
-            logError(e, 'failed to convert heic file');
+            logError(e, "failed to convert heic file");
             throw e;
         }
     }

+ 12 - 12
apps/cast/src/services/livePhotoService.ts

@@ -1,9 +1,9 @@
-import JSZip from 'jszip';
-import { EnteFile } from 'types/file';
+import JSZip from "jszip";
+import { EnteFile } from "types/file";
 import {
     getFileExtensionWithDot,
     getFileNameWithoutExtension,
-} from 'utils/file';
+} from "utils/file";
 
 class LivePhoto {
     image: Uint8Array;
@@ -18,14 +18,14 @@ export const decodeLivePhoto = async (file: EnteFile, zipBlob: Blob) => {
 
     const livePhoto = new LivePhoto();
     for (const zipFilename in zip.files) {
-        if (zipFilename.startsWith('image')) {
+        if (zipFilename.startsWith("image")) {
             livePhoto.imageNameTitle =
                 originalName + getFileExtensionWithDot(zipFilename);
-            livePhoto.image = await zip.files[zipFilename].async('uint8array');
-        } else if (zipFilename.startsWith('video')) {
+            livePhoto.image = await zip.files[zipFilename].async("uint8array");
+        } else if (zipFilename.startsWith("video")) {
             livePhoto.videoNameTitle =
                 originalName + getFileExtensionWithDot(zipFilename);
-            livePhoto.video = await zip.files[zipFilename].async('uint8array');
+            livePhoto.video = await zip.files[zipFilename].async("uint8array");
         }
     }
     return livePhoto;
@@ -34,12 +34,12 @@ export const decodeLivePhoto = async (file: EnteFile, zipBlob: Blob) => {
 export const encodeLivePhoto = async (livePhoto: LivePhoto) => {
     const zip = new JSZip();
     zip.file(
-        'image' + getFileExtensionWithDot(livePhoto.imageNameTitle),
-        livePhoto.image
+        "image" + getFileExtensionWithDot(livePhoto.imageNameTitle),
+        livePhoto.image,
     );
     zip.file(
-        'video' + getFileExtensionWithDot(livePhoto.videoNameTitle),
-        livePhoto.video
+        "video" + getFileExtensionWithDot(livePhoto.videoNameTitle),
+        livePhoto.video,
     );
-    return await zip.generateAsync({ type: 'uint8array' });
+    return await zip.generateAsync({ type: "uint8array" });
 };

+ 3 - 3
apps/cast/src/services/queueProcessor.ts

@@ -1,4 +1,4 @@
-import { CustomError } from '@ente/shared/error';
+import { CustomError } from "@ente/shared/error";
 
 interface RequestQueueItem {
     request: (canceller?: RequestCanceller) => Promise<any>;
@@ -28,11 +28,11 @@ export default class QueueProcessor<T> {
 
     constructor(
         private maxParallelProcesses: number,
-        private processingStrategy = PROCESSING_STRATEGY.FIFO
+        private processingStrategy = PROCESSING_STRATEGY.FIFO,
     ) {}
 
     public queueUpRequest(
-        request: (canceller?: RequestCanceller) => Promise<T>
+        request: (canceller?: RequestCanceller) => Promise<T>,
     ) {
         const isCanceled: CancellationStatus = { status: false };
         const canceller: RequestCanceller = {

+ 14 - 14
apps/cast/src/services/readerService.ts

@@ -1,14 +1,14 @@
-import { logError } from '@ente/shared/sentry';
-import { convertBytesToHumanReadable } from '@ente/shared/utils/size';
-import { ElectronFile } from 'types/upload';
+import { logError } from "@ente/shared/sentry";
+import { convertBytesToHumanReadable } from "@ente/shared/utils/size";
+import { ElectronFile } from "types/upload";
 
 export async function getUint8ArrayView(
-    file: Blob | ElectronFile
+    file: Blob | ElectronFile,
 ): Promise<Uint8Array> {
     try {
         return new Uint8Array(await file.arrayBuffer());
     } catch (e) {
-        logError(e, 'reading file blob failed', {
+        logError(e, "reading file blob failed", {
             fileSize: convertBytesToHumanReadable(file.size),
         });
         throw e;
@@ -37,7 +37,7 @@ export function getFileStream(file: File, chunkSize: number) {
 
 export async function getElectronFileStream(
     file: ElectronFile,
-    chunkSize: number
+    chunkSize: number,
 ) {
     const chunkCount = Math.ceil(file.size / chunkSize);
     return {
@@ -61,29 +61,29 @@ async function* fileChunkReaderMaker(file: File, chunkSize: number) {
 // eslint-disable-next-line @typescript-eslint/no-unused-vars
 async function getUint8ArrayViewOld(
     reader: FileReader,
-    file: Blob
+    file: Blob,
 ): Promise<Uint8Array> {
     return await new Promise((resolve, reject) => {
         reader.onabort = () =>
             reject(
                 Error(
                     `file reading was aborted, file size= ${convertBytesToHumanReadable(
-                        file.size
-                    )}`
-                )
+                        file.size,
+                    )}`,
+                ),
             );
         reader.onerror = () =>
             reject(
                 Error(
                     `file reading has failed, file size= ${convertBytesToHumanReadable(
-                        file.size
-                    )} , reason= ${reader.error}`
-                )
+                        file.size,
+                    )} , reason= ${reader.error}`,
+                ),
             );
         reader.onload = () => {
             // Do whatever you want with the file contents
             const result =
-                typeof reader.result === 'string'
+                typeof reader.result === "string"
                     ? new TextEncoder().encode(reader.result)
                     : new Uint8Array(reader.result);
             resolve(result);

+ 19 - 19
apps/cast/src/services/typeDetectionService.ts

@@ -1,26 +1,26 @@
-import { FILE_TYPE } from 'constants/file';
-import { ElectronFile, FileTypeInfo } from 'types/upload';
+import { CustomError } from "@ente/shared/error";
+import { logError } from "@ente/shared/sentry";
+import { convertBytesToHumanReadable } from "@ente/shared/utils/size";
+import { FILE_TYPE } from "constants/file";
 import {
-    WHITELISTED_FILE_FORMATS,
     KNOWN_NON_MEDIA_FORMATS,
-} from 'constants/upload';
-import { CustomError } from '@ente/shared/error';
-import { getFileExtension } from 'utils/file';
-import { logError } from '@ente/shared/sentry';
-import { getUint8ArrayView } from './readerService';
-import FileType, { FileTypeResult } from 'file-type';
-import { convertBytesToHumanReadable } from '@ente/shared/utils/size';
+    WHITELISTED_FILE_FORMATS,
+} from "constants/upload";
+import FileType, { FileTypeResult } from "file-type";
+import { ElectronFile, FileTypeInfo } from "types/upload";
+import { getFileExtension } from "utils/file";
+import { getUint8ArrayView } from "./readerService";
 
 function getFileSize(file: File | ElectronFile) {
     return file.size;
 }
 
-const TYPE_VIDEO = 'video';
-const TYPE_IMAGE = 'image';
+const TYPE_VIDEO = "video";
+const TYPE_IMAGE = "image";
 const CHUNK_SIZE_FOR_TYPE_DETECTION = 4100;
 
 export async function getFileType(
-    receivedFile: File | ElectronFile
+    receivedFile: File | ElectronFile,
 ): Promise<FileTypeInfo> {
     try {
         let fileType: FILE_TYPE;
@@ -32,7 +32,7 @@ export async function getFileType(
             typeResult = await extractElectronFileType(receivedFile);
         }
 
-        const mimTypeParts: string[] = typeResult.mime?.split('/');
+        const mimTypeParts: string[] = typeResult.mime?.split("/");
 
         if (mimTypeParts?.length !== 2) {
             throw Error(CustomError.INVALID_MIME_TYPE(typeResult.mime));
@@ -56,7 +56,7 @@ export async function getFileType(
         const fileFormat = getFileExtension(receivedFile.name);
         const fileSize = convertBytesToHumanReadable(getFileSize(receivedFile));
         const whiteListedFormat = WHITELISTED_FILE_FORMATS.find(
-            (a) => a.exactType === fileFormat
+            (a) => a.exactType === fileFormat,
         );
         if (whiteListedFormat) {
             return whiteListedFormat;
@@ -65,13 +65,13 @@ export async function getFileType(
             throw Error(CustomError.UNSUPPORTED_FILE_FORMAT);
         }
         if (e.message === CustomError.NON_MEDIA_FILE) {
-            logError(e, 'unsupported file format', {
+            logError(e, "unsupported file format", {
                 fileFormat,
                 fileSize,
             });
             throw Error(CustomError.UNSUPPORTED_FILE_FORMAT);
         }
-        logError(e, 'type detection failed', {
+        logError(e, "type detection failed", {
             fileFormat,
             fileSize,
         });
@@ -96,11 +96,11 @@ async function extractElectronFileType(file: ElectronFile) {
 async function getFileTypeFromBuffer(buffer: Uint8Array) {
     const result = await FileType.fromBuffer(buffer);
     if (!result?.mime) {
-        let logableInfo = '';
+        let logableInfo = "";
         try {
             logableInfo = `result: ${JSON.stringify(result)}`;
         } catch (e) {
-            logableInfo = 'failed to stringify result';
+            logableInfo = "failed to stringify result";
         }
         throw Error(`mimetype missing from file type result - ${logableInfo}`);
     }

+ 26 - 26
apps/cast/src/services/wasm/ffmpeg.ts

@@ -1,14 +1,14 @@
-import { promiseWithTimeout } from '@ente/shared/promise';
-import { createFFmpeg, FFmpeg } from 'ffmpeg-wasm';
-import QueueProcessor from 'services/queueProcessor';
-import { getUint8ArrayView } from 'services/readerService';
-import { logError } from '@ente/shared/sentry';
-import { generateTempName } from 'utils/temp';
-import { addLogLine } from '@ente/shared/logging';
+import { addLogLine } from "@ente/shared/logging";
+import { promiseWithTimeout } from "@ente/shared/promise";
+import { logError } from "@ente/shared/sentry";
+import { createFFmpeg, FFmpeg } from "ffmpeg-wasm";
+import QueueProcessor from "services/queueProcessor";
+import { getUint8ArrayView } from "services/readerService";
+import { generateTempName } from "utils/temp";
 
-const INPUT_PATH_PLACEHOLDER = 'INPUT';
-const FFMPEG_PLACEHOLDER = 'FFMPEG';
-const OUTPUT_PATH_PLACEHOLDER = 'OUTPUT';
+const INPUT_PATH_PLACEHOLDER = "INPUT";
+const FFMPEG_PLACEHOLDER = "FFMPEG";
+const OUTPUT_PATH_PLACEHOLDER = "OUTPUT";
 
 const FFMPEG_EXECUTION_WAIT_TIME = 30 * 1000;
 
@@ -19,7 +19,7 @@ export class WasmFFmpeg {
 
     constructor() {
         this.ffmpeg = createFFmpeg({
-            corePath: '/js/ffmpeg/ffmpeg-core.js',
+            corePath: "/js/ffmpeg/ffmpeg-core.js",
             mt: false,
         });
 
@@ -36,7 +36,7 @@ export class WasmFFmpeg {
         cmd: string[],
         inputFile: File,
         outputFileName: string,
-        dontTimeout = false
+        dontTimeout = false,
     ) {
         const response = this.ffmpegTaskQueue.queueUpRequest(() => {
             if (dontTimeout) {
@@ -44,14 +44,14 @@ export class WasmFFmpeg {
             } else {
                 return promiseWithTimeout<File>(
                     this.execute(cmd, inputFile, outputFileName),
-                    FFMPEG_EXECUTION_WAIT_TIME
+                    FFMPEG_EXECUTION_WAIT_TIME,
                 );
             }
         });
         try {
             return await response.promise;
         } catch (e) {
-            logError(e, 'ffmpeg run failed');
+            logError(e, "ffmpeg run failed");
             throw e;
         }
     }
@@ -59,25 +59,25 @@ export class WasmFFmpeg {
     private async execute(
         cmd: string[],
         inputFile: File,
-        outputFileName: string
+        outputFileName: string,
     ) {
         let tempInputFilePath: string;
         let tempOutputFilePath: string;
         try {
             await this.ready;
             const extension = getFileExtension(inputFile.name);
-            const tempNameSuffix = extension ? `input.${extension}` : 'input';
+            const tempNameSuffix = extension ? `input.${extension}` : "input";
             tempInputFilePath = `${generateTempName(10, tempNameSuffix)}`;
             this.ffmpeg.FS(
-                'writeFile',
+                "writeFile",
                 tempInputFilePath,
-                await getUint8ArrayView(inputFile)
+                await getUint8ArrayView(inputFile),
             );
             tempOutputFilePath = `${generateTempName(10, outputFileName)}`;
 
             cmd = cmd.map((cmdPart) => {
                 if (cmdPart === FFMPEG_PLACEHOLDER) {
-                    return '';
+                    return "";
                 } else if (cmdPart === INPUT_PATH_PLACEHOLDER) {
                     return tempInputFilePath;
                 } else if (cmdPart === OUTPUT_PATH_PLACEHOLDER) {
@@ -89,26 +89,26 @@ export class WasmFFmpeg {
             addLogLine(`${cmd}`);
             await this.ffmpeg.run(...cmd);
             return new File(
-                [this.ffmpeg.FS('readFile', tempOutputFilePath)],
-                outputFileName
+                [this.ffmpeg.FS("readFile", tempOutputFilePath)],
+                outputFileName,
             );
         } finally {
             try {
-                this.ffmpeg.FS('unlink', tempInputFilePath);
+                this.ffmpeg.FS("unlink", tempInputFilePath);
             } catch (e) {
-                logError(e, 'unlink input file failed');
+                logError(e, "unlink input file failed");
             }
             try {
-                this.ffmpeg.FS('unlink', tempOutputFilePath);
+                this.ffmpeg.FS("unlink", tempOutputFilePath);
             } catch (e) {
-                logError(e, 'unlink output file failed');
+                logError(e, "unlink output file failed");
             }
         }
     }
 }
 
 function getFileExtension(filename: string) {
-    const lastDotPosition = filename.lastIndexOf('.');
+    const lastDotPosition = filename.lastIndexOf(".");
     if (lastDotPosition === -1) return null;
     else {
         return filename.slice(lastDotPosition + 1);

+ 3 - 3
apps/cast/src/services/wasmHeicConverter/wasmHEICConverterClient.ts

@@ -1,9 +1,9 @@
-import * as HeicConvert from 'heic-convert';
-import { getUint8ArrayView } from 'services/readerService';
+import * as HeicConvert from "heic-convert";
+import { getUint8ArrayView } from "services/readerService";
 
 export async function convertHEIC(
     fileBlob: Blob,
-    format: string
+    format: string,
 ): Promise<Blob> {
     const filedata = await getUint8ArrayView(fileBlob);
     const result = await HeicConvert({ buffer: filedata, format });

+ 24 - 24
apps/cast/src/services/wasmHeicConverter/wasmHEICConverterService.ts

@@ -1,23 +1,23 @@
-import QueueProcessor from 'services/queueProcessor';
-import { retryAsyncFunction } from 'utils/network';
-import { DedicatedConvertWorker } from 'worker/convert.worker';
-import { ComlinkWorker } from 'utils/comlink/comlinkWorker';
-import { getDedicatedConvertWorker } from 'utils/comlink/ComlinkConvertWorker';
-import { logError } from '@ente/shared/sentry';
-import { addLogLine } from '@ente/shared/logging';
-import { convertBytesToHumanReadable } from '@ente/shared/utils/size';
-import { CustomError } from '@ente/shared/error';
+import { CustomError } from "@ente/shared/error";
+import { addLogLine } from "@ente/shared/logging";
+import { logError } from "@ente/shared/sentry";
+import { convertBytesToHumanReadable } from "@ente/shared/utils/size";
+import QueueProcessor from "services/queueProcessor";
+import { getDedicatedConvertWorker } from "utils/comlink/ComlinkConvertWorker";
+import { ComlinkWorker } from "utils/comlink/comlinkWorker";
+import { retryAsyncFunction } from "utils/network";
+import { DedicatedConvertWorker } from "worker/convert.worker";
 
 const WORKER_POOL_SIZE = 2;
 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';
+const CONVERT_FORMAT = "JPEG";
 
 class HEICConverter {
     private convertProcessor = new QueueProcessor<Blob>(
-        MAX_CONVERSION_IN_PARALLEL
+        MAX_CONVERSION_IN_PARALLEL,
     );
     private workerPool: ComlinkWorker<typeof DedicatedConvertWorker>[] = [];
     private ready: Promise<void>;
@@ -43,22 +43,22 @@ class HEICConverter {
                             const main = async () => {
                                 try {
                                     const timeout = setTimeout(() => {
-                                        reject(Error('wait time exceeded'));
+                                        reject(Error("wait time exceeded"));
                                     }, WAIT_TIME_IN_MICROSECONDS);
                                     const startTime = Date.now();
                                     const convertedHEIC =
                                         await worker.convertHEIC(
                                             fileBlob,
-                                            CONVERT_FORMAT
+                                            CONVERT_FORMAT,
                                         );
                                     addLogLine(
                                         `originalFileSize:${convertBytesToHumanReadable(
-                                            fileBlob?.size
+                                            fileBlob?.size,
                                         )},convertedFileSize:${convertBytesToHumanReadable(
-                                            convertedHEIC?.size
+                                            convertedHEIC?.size,
                                         )},  heic conversion time: ${
                                             Date.now() - startTime
-                                        }ms `
+                                        }ms `,
                                     );
                                     clearTimeout(timeout);
                                     resolve(convertedHEIC);
@@ -67,37 +67,37 @@ class HEICConverter {
                                 }
                             };
                             main();
-                        }
+                        },
                     );
                     if (!convertedHEIC || convertedHEIC?.size === 0) {
                         logError(
                             Error(`converted heic fileSize is Zero`),
-                            'converted heic fileSize is Zero',
+                            "converted heic fileSize is Zero",
                             {
                                 originalFileSize: convertBytesToHumanReadable(
-                                    fileBlob?.size ?? 0
+                                    fileBlob?.size ?? 0,
                                 ),
                                 convertedFileSize: convertBytesToHumanReadable(
-                                    convertedHEIC?.size ?? 0
+                                    convertedHEIC?.size ?? 0,
                                 ),
-                            }
+                            },
                         );
                     }
                     await new Promise((resolve) => {
                         setTimeout(
                             () => resolve(null),
-                            BREATH_TIME_IN_MICROSECONDS
+                            BREATH_TIME_IN_MICROSECONDS,
                         );
                     });
                     this.workerPool.push(convertWorker);
                     return convertedHEIC;
                 } catch (e) {
-                    logError(e, 'heic conversion failed');
+                    logError(e, "heic conversion failed");
                     convertWorker.terminate();
                     this.workerPool.push(getDedicatedConvertWorker());
                     throw e;
                 }
-            }, WAIT_TIME_BEFORE_NEXT_ATTEMPT_IN_MICROSECONDS)
+            }, WAIT_TIME_BEFORE_NEXT_ATTEMPT_IN_MICROSECONDS),
         );
         try {
             return await response.promise;

+ 14 - 14
apps/cast/src/types/collection/index.ts

@@ -1,17 +1,17 @@
-import { EnteFile } from 'types/file';
-import { CollectionSummaryType, CollectionType } from 'constants/collection';
+import { CollectionSummaryType, CollectionType } from "constants/collection";
+import { EnteFile } from "types/file";
 import {
     EncryptedMagicMetadata,
     MagicMetadataCore,
     SUB_TYPE,
     VISIBILITY_STATE,
-} from 'types/magicMetadata';
+} from "types/magicMetadata";
 
 export enum COLLECTION_ROLE {
-    VIEWER = 'VIEWER',
-    OWNER = 'OWNER',
-    COLLABORATOR = 'COLLABORATOR',
-    UNKNOWN = 'UNKNOWN',
+    VIEWER = "VIEWER",
+    OWNER = "OWNER",
+    COLLABORATOR = "COLLABORATOR",
+    UNKNOWN = "UNKNOWN",
 }
 
 export interface CollectionUser {
@@ -43,13 +43,13 @@ export interface EncryptedCollection {
 export interface Collection
     extends Omit<
         EncryptedCollection,
-        | 'encryptedKey'
-        | 'keyDecryptionNonce'
-        | 'encryptedName'
-        | 'nameDecryptionNonce'
-        | 'magicMetadata'
-        | 'pubMagicMetadata'
-        | 'sharedMagicMetadata'
+        | "encryptedKey"
+        | "keyDecryptionNonce"
+        | "encryptedName"
+        | "nameDecryptionNonce"
+        | "magicMetadata"
+        | "pubMagicMetadata"
+        | "sharedMagicMetadata"
     > {
     key: string;
     name: string;

+ 7 - 7
apps/cast/src/types/file/index.ts

@@ -2,8 +2,8 @@ import {
     EncryptedMagicMetadata,
     MagicMetadataCore,
     VISIBILITY_STATE,
-} from 'types/magicMetadata';
-import { Metadata } from 'types/upload';
+} from "types/magicMetadata";
+import { Metadata } from "types/upload";
 
 export interface MetadataFileAttributes {
     encryptedData: string;
@@ -38,11 +38,11 @@ export interface EncryptedEnteFile {
 export interface EnteFile
     extends Omit<
         EncryptedEnteFile,
-        | 'metadata'
-        | 'pubMagicMetadata'
-        | 'magicMetadata'
-        | 'encryptedKey'
-        | 'keyDecryptionNonce'
+        | "metadata"
+        | "pubMagicMetadata"
+        | "magicMetadata"
+        | "encryptedKey"
+        | "keyDecryptionNonce"
     > {
     metadata: Metadata;
     magicMetadata: FileMagicMetadata;

+ 3 - 3
apps/cast/src/types/gallery/index.ts

@@ -1,9 +1,9 @@
 // import { CollectionDownloadProgressAttributes } from 'components/Collections/CollectionDownloadProgress';
 // import { CollectionSelectorAttributes } from 'components/Collections/CollectionSelector';
 // import { TimeStampListItem } from 'components/PhotoList';
-import { User } from '@ente/shared/user/types';
-import { Collection } from 'types/collection';
-import { EnteFile } from 'types/file';
+import { User } from "@ente/shared/user/types";
+import { Collection } from "types/collection";
+import { EnteFile } from "types/file";
 
 export type SelectedState = {
     [k: number]: boolean;

+ 9 - 9
apps/cast/src/types/upload/index.ts

@@ -1,16 +1,16 @@
 import {
     B64EncryptionResult,
     LocalFileAttributes,
-} from '@ente/shared/crypto/types';
-import { FILE_TYPE } from 'constants/file';
-import { Collection } from 'types/collection';
+} from "@ente/shared/crypto/types";
+import { FILE_TYPE } from "constants/file";
+import { Collection } from "types/collection";
 import {
-    MetadataFileAttributes,
-    S3FileAttributes,
     FilePublicMagicMetadata,
     FilePublicMagicMetadataProps,
-} from 'types/file';
-import { EncryptedMagicMetadata } from 'types/magicMetadata';
+    MetadataFileAttributes,
+    S3FileAttributes,
+} from "types/file";
+import { EncryptedMagicMetadata } from "types/magicMetadata";
 
 export interface DataStream {
     stream: ReadableStream<Uint8Array>;
@@ -18,7 +18,7 @@ export interface DataStream {
 }
 
 export function isDataStream(object: any): object is DataStream {
-    return 'stream' in object;
+    return "stream" in object;
 }
 
 export type Logger = (message: string) => void;
@@ -114,7 +114,7 @@ export interface FileInMemory {
 }
 
 export interface FileWithMetadata
-    extends Omit<FileInMemory, 'hasStaticThumbnail'> {
+    extends Omit<FileInMemory, "hasStaticThumbnail"> {
     metadata: Metadata;
     localID: number;
     pubMagicMetadata: FilePublicMagicMetadata;

+ 1 - 1
apps/cast/src/types/upload/ui.ts

@@ -1,4 +1,4 @@
-import { UPLOAD_RESULT, UPLOAD_STAGES } from 'constants/upload';
+import { UPLOAD_RESULT, UPLOAD_STAGES } from "constants/upload";
 
 export type FileID = number;
 export type FileName = string;

+ 12 - 12
apps/cast/src/utils/collection/index.ts

@@ -1,13 +1,13 @@
-import { COLLECTION_ROLE, Collection } from 'types/collection';
+import { LS_KEYS, getData } from "@ente/shared/storage/localStorage";
+import { User } from "@ente/shared/user/types";
 import {
     CollectionSummaryType,
     CollectionType,
     HIDE_FROM_COLLECTION_BAR_TYPES,
     OPTIONS_NOT_HAVING_COLLECTION_TYPES,
-} from 'constants/collection';
-import { SUB_TYPE, VISIBILITY_STATE } from 'types/magicMetadata';
-import { User } from '@ente/shared/user/types';
-import { getData, LS_KEYS } from '@ente/shared/storage/localStorage';
+} from "constants/collection";
+import { COLLECTION_ROLE, Collection } from "types/collection";
+import { SUB_TYPE, VISIBILITY_STATE } from "types/magicMetadata";
 
 export enum COLLECTION_OPS_TYPE {
     ADD,
@@ -19,7 +19,7 @@ export enum COLLECTION_OPS_TYPE {
 
 export function getSelectedCollection(
     collectionID: number,
-    collections: Collection[]
+    collections: Collection[],
 ) {
     return collections.find((collection) => collection.id === collectionID);
 }
@@ -64,7 +64,7 @@ export const shouldBeShownOnCollectionBar = (type: CollectionSummaryType) => {
 export const getUserOwnedCollections = (collections: Collection[]) => {
     const user: User = getData(LS_KEYS.USER);
     if (!user?.id) {
-        throw Error('user missing');
+        throw Error("user missing");
     }
     return collections.filter((collection) => collection.owner.id === user.id);
 };
@@ -103,7 +103,7 @@ export function isSharedOnlyViaLink(collection: Collection) {
 export function isValidMoveTarget(
     sourceCollectionID: number,
     targetCollection: Collection,
-    user: User
+    user: User,
 ) {
     return (
         sourceCollectionID !== targetCollection.id &&
@@ -116,7 +116,7 @@ export function isValidMoveTarget(
 export function isValidReplacementAlbum(
     collection: Collection,
     user: User,
-    wantedCollectionName: string
+    wantedCollectionName: string,
 ) {
     return (
         collection.name === wantedCollectionName &&
@@ -129,15 +129,15 @@ export function isValidReplacementAlbum(
 }
 
 export function getCollectionNameMap(
-    collections: Collection[]
+    collections: Collection[],
 ): Map<number, string> {
     return new Map<number, string>(
-        collections.map((collection) => [collection.id, collection.name])
+        collections.map((collection) => [collection.id, collection.name]),
     );
 }
 
 export function getNonHiddenCollections(
-    collections: Collection[]
+    collections: Collection[],
 ): Collection[] {
     return collections.filter((collection) => !isHiddenCollection(collection));
 }

+ 6 - 6
apps/cast/src/utils/comlink/ComlinkConvertWorker.ts

@@ -1,7 +1,7 @@
-import { Remote } from 'comlink';
-import { DedicatedConvertWorker } from 'worker/convert.worker';
-import { ComlinkWorker } from './comlinkWorker';
-import { runningInBrowser } from '@ente/shared/platform';
+import { runningInBrowser } from "@ente/shared/platform";
+import { Remote } from "comlink";
+import { DedicatedConvertWorker } from "worker/convert.worker";
+import { ComlinkWorker } from "./comlinkWorker";
 
 class ComlinkConvertWorker {
     private comlinkWorkerInstance: Remote<DedicatedConvertWorker>;
@@ -20,8 +20,8 @@ export const getDedicatedConvertWorker = () => {
         const cryptoComlinkWorker = new ComlinkWorker<
             typeof DedicatedConvertWorker
         >(
-            'ente-convert-worker',
-            new Worker(new URL('worker/convert.worker.ts', import.meta.url))
+            "ente-convert-worker",
+            new Worker(new URL("worker/convert.worker.ts", import.meta.url)),
         );
         return cryptoComlinkWorker;
     }

Kaikkia tiedostoja ei voida näyttää, sillä liian monta tiedostoa muuttui tässä diffissä