diff --git a/app/.eslintrc.cjs b/app/.eslintrc.cjs index 273f008f2..8dcc7c5c1 100644 --- a/app/.eslintrc.cjs +++ b/app/.eslintrc.cjs @@ -174,6 +174,8 @@ module.exports = { files: ['docs/examples/**/*.ts'], rules: { '@typescript-eslint/no-unused-vars': 'off', + '@typescript-eslint/no-explicit-any': 'off', + 'no-console': 'off', 'no-unused-vars': 'off', 'import/no-unresolved': 'off', }, @@ -194,11 +196,14 @@ module.exports = { }, { files: ['tests/**/*.{ts,tsx}'], + env: { + jest: true, + }, parserOptions: { project: './tsconfig.test.json', }, rules: { - // Allow console logging in tests + // Allow console logging and relaxed typing in tests 'no-console': 'off', // Allow require() imports in tests for mocking '@typescript-eslint/no-require-imports': 'off', @@ -220,6 +225,13 @@ module.exports = { '@typescript-eslint/no-require-imports': 'off', }, }, + { + // Allow require imports for conditional loading in navigation + files: ['src/navigation/index.tsx'], + rules: { + '@typescript-eslint/no-require-imports': 'off', + }, + }, { files: ['*.cjs', '*.js'], env: { @@ -232,6 +244,10 @@ module.exports = { sourceType: 'script', }, rules: { + 'no-console': 'off', + 'no-unused-vars': 'off', + '@typescript-eslint/no-unused-vars': 'off', + '@typescript-eslint/no-explicit-any': 'off', '@typescript-eslint/no-var-requires': 'off', '@typescript-eslint/no-require-imports': 'off', 'no-undef': 'off', diff --git a/app/docs/examples/tree-shaking/level2-optimal-example.ts b/app/docs/examples/tree-shaking/level2-optimal-example.ts index 5aa1f0716..b3994bb2a 100644 --- a/app/docs/examples/tree-shaking/level2-optimal-example.ts +++ b/app/docs/examples/tree-shaking/level2-optimal-example.ts @@ -16,14 +16,12 @@ import { hash } from '@selfxyz/common/utils/hash'; export function optimalLevel2Example(data: PassportData) { // This will result in the smallest possible bundle // Only the specific functions and constants we use are included - - // eslint-disable-next-line no-console console.log('Using API:', API_URL); - // eslint-disable-next-line no-console + console.log('Attestation ID:', PASSPORT_ATTESTATION_ID); const hashedData = hash(JSON.stringify(data)); - // eslint-disable-next-line no-console + console.log('Hashed passport data:', hashedData); return { diff --git a/app/docs/examples/tree-shaking/level3-optimal-example.ts b/app/docs/examples/tree-shaking/level3-optimal-example.ts index 04e13c33e..e24db0ce0 100644 --- a/app/docs/examples/tree-shaking/level3-optimal-example.ts +++ b/app/docs/examples/tree-shaking/level3-optimal-example.ts @@ -26,20 +26,18 @@ export function optimalLevel3Example(data: PassportData, secret: string) { // This will result in the smallest possible bundle // Only the specific individual functions we use are included // Bundle size reduction: ~75-90% compared to broad imports! - - // eslint-disable-next-line no-console console.log('Using API:', API_URL); - // eslint-disable-next-line no-console + console.log('Attestation ID:', PASSPORT_ATTESTATION_ID); // Use specific hash function from SHA module const hashedData = hash([1, 2, 3, 4], 'hex'); - // eslint-disable-next-line no-console + console.log('SHA hashed data:', hashedData); // Use specific Poseidon function for commitment const poseidonHash = flexiblePoseidon([BigInt(1), BigInt(2)]); - // eslint-disable-next-line no-console + console.log('Poseidon hash:', poseidonHash); // Use specific passport functions diff --git a/app/scripts/mobile-deploy-confirm.cjs b/app/scripts/mobile-deploy-confirm.cjs index ff19a32e7..58c87c3dd 100755 --- a/app/scripts/mobile-deploy-confirm.cjs +++ b/app/scripts/mobile-deploy-confirm.cjs @@ -62,7 +62,7 @@ const REGEX_PATTERNS = { function safeReadFile(filePath, description) { try { return fs.readFileSync(filePath, 'utf8'); - } catch (_error) { + } catch { console.warn(`Warning: Could not read ${description} at ${filePath}`); return null; } @@ -91,7 +91,7 @@ function safeExecSync(command, description) { try { return execSync(command, { encoding: 'utf8' }).trim(); - } catch (_error) { + } catch { console.warn(`Warning: Could not ${description}`); return null; } diff --git a/app/src/components/typography/Additional.tsx b/app/src/components/typography/Additional.tsx index b3c25b657..250acb777 100644 --- a/app/src/components/typography/Additional.tsx +++ b/app/src/components/typography/Additional.tsx @@ -8,7 +8,7 @@ import { shouldShowAesopRedesign } from '@/hooks/useAesopRedesign'; import { slate400 } from '@/utils/colors'; import { dinot } from '@/utils/fonts'; -interface AdditionalProps extends TextProps {} +type AdditionalProps = TextProps; const Additional = ({ children, style, ...props }: AdditionalProps) => { return ( diff --git a/app/src/components/typography/Caution.tsx b/app/src/components/typography/Caution.tsx index 2573e4b85..e6c1f5d82 100644 --- a/app/src/components/typography/Caution.tsx +++ b/app/src/components/typography/Caution.tsx @@ -7,7 +7,7 @@ import { StyleSheet, Text } from 'react-native'; import { slate700 } from '@/utils/colors'; import { dinot } from '@/utils/fonts'; -interface CautionProps extends TextProps {} +type CautionProps = TextProps; const Caution = ({ children, style, ...props }: CautionProps) => { return ( diff --git a/app/src/components/typography/Description.tsx b/app/src/components/typography/Description.tsx index 253de3109..283dcf5b1 100644 --- a/app/src/components/typography/Description.tsx +++ b/app/src/components/typography/Description.tsx @@ -9,7 +9,7 @@ import { shouldShowAesopRedesign } from '@/hooks/useAesopRedesign'; import { slate500 } from '@/utils/colors'; import { dinot } from '@/utils/fonts'; -interface DescriptionProps extends TextProps {} +type DescriptionProps = TextProps; const Description = ({ children, style, ...props }: DescriptionProps) => { return ( diff --git a/app/src/hooks/useRecoveryPrompts.ts b/app/src/hooks/useRecoveryPrompts.ts index 5da503196..37fc9d947 100644 --- a/app/src/hooks/useRecoveryPrompts.ts +++ b/app/src/hooks/useRecoveryPrompts.ts @@ -43,7 +43,7 @@ export default function useRecoveryPrompts() { if (shouldPrompt) { showModal(); } - } catch (_error) { + } catch { // Silently fail to avoid breaking the hook // If we can't get documents, we shouldn't show the prompt return; diff --git a/app/src/layouts/AppLayout.tsx b/app/src/layouts/AppLayout.tsx index 5a60bfb26..098f94e2b 100644 --- a/app/src/layouts/AppLayout.tsx +++ b/app/src/layouts/AppLayout.tsx @@ -4,7 +4,7 @@ import type { PropsWithChildren } from 'react'; import React from 'react'; import { SafeAreaProvider } from 'react-native-safe-area-context'; -interface ConnectedAppLayoutProps extends PropsWithChildren {} +type ConnectedAppLayoutProps = PropsWithChildren; export default function ConnectedAppLayout({ children, diff --git a/app/src/layouts/ExpandableBottomLayout.tsx b/app/src/layouts/ExpandableBottomLayout.tsx index 72ef1b1fa..57ab6be30 100644 --- a/app/src/layouts/ExpandableBottomLayout.tsx +++ b/app/src/layouts/ExpandableBottomLayout.tsx @@ -72,7 +72,7 @@ const TopSection: React.FC = ({ ); }; -interface FullSectionProps extends ViewProps {} +type FullSectionProps = ViewProps; /* * Rather than using a top and bottom section, this component is te entire thing. * It leave space for the safe area insets and provides basic padding diff --git a/app/src/layouts/SimpleScrolledTitleLayout.tsx b/app/src/layouts/SimpleScrolledTitleLayout.tsx index 9e1c87ed4..adfc8363c 100644 --- a/app/src/layouts/SimpleScrolledTitleLayout.tsx +++ b/app/src/layouts/SimpleScrolledTitleLayout.tsx @@ -11,15 +11,14 @@ import { Title } from '@/components/typography/Title'; import { ExpandableBottomLayout } from '@/layouts/ExpandableBottomLayout'; import { white } from '@/utils/colors'; -interface DetailListProps - extends PropsWithChildren<{ - title: string; - onDismiss: () => void; - secondaryButtonText?: string; - onSecondaryButtonPress?: () => void; - header?: React.ReactNode; - footer?: React.ReactNode; - }> {} +type DetailListProps = PropsWithChildren<{ + title: string; + onDismiss: () => void; + secondaryButtonText?: string; + onSecondaryButtonPress?: () => void; + header?: React.ReactNode; + footer?: React.ReactNode; +}>; export default function SimpleScrolledTitleLayout({ title, diff --git a/app/src/navigation/dev.ts b/app/src/navigation/dev.ts index 6da109438..ab5365b5b 100644 --- a/app/src/navigation/dev.ts +++ b/app/src/navigation/dev.ts @@ -3,7 +3,7 @@ import { lazy } from 'react'; import type { NativeStackNavigationOptions } from '@react-navigation/native-stack'; -import DevPrivateKeyScreen from '@/screens/dev/DevPrivateKeyScreen'; +// DevPrivateKeyScreen is loaded lazily to avoid bundling in production import { black, white } from '@/utils/colors'; const DevFeatureFlagsScreen = lazy( @@ -17,6 +17,9 @@ const MockDataScreen = lazy(() => import('@/screens/dev/MockDataScreen')); const MockDataScreenDeepLink = lazy( () => import('@/screens/dev/MockDataScreenDeepLink'), ); +const DevPrivateKeyScreen = lazy( + () => import('@/screens/dev/DevPrivateKeyScreen'), +); const devScreens = { CreateMock: { diff --git a/app/src/navigation/index.tsx b/app/src/navigation/index.tsx index b03432711..08cab2297 100644 --- a/app/src/navigation/index.tsx +++ b/app/src/navigation/index.tsx @@ -14,7 +14,9 @@ import { createNativeStackNavigator } from '@react-navigation/native-stack'; import { DefaultNavBar } from '@/components/NavBar'; import AppLayout from '@/layouts/AppLayout'; import { getAesopScreens } from '@/navigation/aesop'; -import devScreens from '@/navigation/dev'; +// Import dev screens type for conditional inclusion +import type devScreensType from '@/navigation/dev'; +// Dev screens are conditionally loaded to avoid bundling in production import homeScreens from '@/navigation/home'; import miscScreens from '@/navigation/misc'; import passportScreens from '@/navigation/passport'; @@ -25,6 +27,11 @@ import analytics from '@/utils/analytics'; import { white } from '@/utils/colors'; import { setupUniversalLinkListenerInNavigation } from '@/utils/deeplinks'; +// Conditionally load dev screens only in development +const devScreens: typeof devScreensType = __DEV__ + ? require('@/navigation/dev').default + : ({} as typeof devScreensType); + export const navigationScreens = { ...miscScreens, ...passportScreens, @@ -36,9 +43,6 @@ export const navigationScreens = { // add last to override other screens ...getAesopScreens(), }; - -export type RootStackParamList = StaticParamList; - const AppNavigation = createNativeStackNavigator({ id: undefined, initialRouteName: Platform.OS === 'web' ? 'Home' : 'Splash', @@ -50,11 +54,14 @@ const AppNavigation = createNativeStackNavigator({ screens: navigationScreens, }); +export type RootStackParamList = StaticParamList; + // Create a ref that we can use to access the navigation state -export const navigationRef = createNavigationContainerRef(); +export const navigationRef = createNavigationContainerRef(); declare global { namespace ReactNavigation { + // eslint-disable-next-line @typescript-eslint/no-empty-object-type interface RootParamList extends RootStackParamList {} } } diff --git a/app/src/providers/passportDataProvider.tsx b/app/src/providers/passportDataProvider.tsx index 973b4518e..3b8cbba8e 100644 --- a/app/src/providers/passportDataProvider.tsx +++ b/app/src/providers/passportDataProvider.tsx @@ -278,7 +278,7 @@ export async function clearDocumentCatalogForMigrationTesting() { try { await Keychain.resetGenericPassword({ service: `document-${doc.id}` }); console.log(`Cleared document: ${doc.id}`); - } catch (_error) { + } catch { console.log(`Document ${doc.id} not found or already cleared`); } } @@ -287,7 +287,7 @@ export async function clearDocumentCatalogForMigrationTesting() { try { await Keychain.resetGenericPassword({ service: 'documentCatalog' }); console.log('Cleared document catalog'); - } catch (_error) { + } catch { console.log('Document catalog not found or already cleared'); } @@ -305,7 +305,7 @@ export async function clearPassportData() { for (const doc of catalog.documents) { try { await Keychain.resetGenericPassword({ service: `document-${doc.id}` }); - } catch (_error) { + } catch { console.log(`Document ${doc.id} not found or already cleared`); } } @@ -345,7 +345,7 @@ export async function deleteDocument(documentId: string): Promise { // Delete the actual document try { await Keychain.resetGenericPassword({ service: `document-${documentId}` }); - } catch (_error) { + } catch { console.log(`Document ${documentId} not found or already cleared`); } } diff --git a/app/src/screens/aesop/PassportOnboardingScreen.tsx b/app/src/screens/aesop/PassportOnboardingScreen.tsx index f11d88942..3d8fabdd2 100644 --- a/app/src/screens/aesop/PassportOnboardingScreen.tsx +++ b/app/src/screens/aesop/PassportOnboardingScreen.tsx @@ -20,11 +20,7 @@ import { ExpandableBottomLayout } from '@/layouts/ExpandableBottomLayout'; import { black, slate100, white } from '@/utils/colors'; import { hasAnyValidRegisteredDocument } from '@/utils/proving/validateDocument'; -interface PassportOnboardingScreenProps {} - -const PassportOnboardingScreen: React.FC< - PassportOnboardingScreenProps -> = ({}) => { +const PassportOnboardingScreen: React.FC = () => { const handleCameraPress = useHapticNavigation('PassportCamera'); const navigateToLaunch = useHapticNavigation('Launch', { action: 'cancel', diff --git a/app/src/screens/dev/DevPrivateKeyScreen.tsx b/app/src/screens/dev/DevPrivateKeyScreen.tsx index 1aa06ba37..bbced1c4c 100644 --- a/app/src/screens/dev/DevPrivateKeyScreen.tsx +++ b/app/src/screens/dev/DevPrivateKeyScreen.tsx @@ -8,9 +8,7 @@ import { unsafe_getPrivateKey } from '@/providers/authProvider'; import { black, slate50, slate200, teal500, white } from '@/utils/colors'; import { confirmTap } from '@/utils/haptic'; -interface DevPrivateKeyScreen {} - -const DevPrivateKeyScreen: React.FC = ({}) => { +const DevPrivateKeyScreen: React.FC = () => { const [privateKey, setPrivateKey] = useState( 'Loading private key…', ); diff --git a/app/src/screens/dev/DevSettingsScreen.tsx b/app/src/screens/dev/DevSettingsScreen.tsx index 19824562b..4fa010a0e 100644 --- a/app/src/screens/dev/DevSettingsScreen.tsx +++ b/app/src/screens/dev/DevSettingsScreen.tsx @@ -347,11 +347,16 @@ const DevSettingsScreen: React.FC = ({}) => { darkMode={true} > {[ - { - label: 'Display your private key', - onPress: () => navigation.navigate('DevPrivateKey'), - dangerTheme: false, - }, + // Only show private key button in development + ...(__DEV__ + ? [ + { + label: 'Display your private key', + onPress: () => navigation.navigate('DevPrivateKey'), + dangerTheme: false, + }, + ] + : []), { label: 'Delete your private key', onPress: handleClearSecretsPress, diff --git a/app/src/screens/dev/MockDataScreen.tsx b/app/src/screens/dev/MockDataScreen.tsx index e53336246..f8fadfe3e 100644 --- a/app/src/screens/dev/MockDataScreen.tsx +++ b/app/src/screens/dev/MockDataScreen.tsx @@ -56,8 +56,6 @@ import { buttonTap, selectionChange } from '@/utils/haptic'; const { trackEvent } = analytics(); -interface MockDataScreenProps {} - const documentTypes = { mock_passport: 'Passport', mock_id_card: 'ID Card', @@ -244,7 +242,7 @@ const FormSection: React.FC = ({ ); }; -const MockDataScreen: React.FC = ({}) => { +const MockDataScreen: React.FC = () => { const navigation = useNavigation(); const [age, setAge] = useState(21); const [expiryYears, setExpiryYears] = useState(5); diff --git a/app/src/screens/misc/ModalScreen.tsx b/app/src/screens/misc/ModalScreen.tsx index 403102222..ffa9b249e 100644 --- a/app/src/screens/misc/ModalScreen.tsx +++ b/app/src/screens/misc/ModalScreen.tsx @@ -45,7 +45,7 @@ export interface ModalParams extends Record { preventDismiss?: boolean; } -interface ModalScreenProps extends StaticScreenProps {} +type ModalScreenProps = StaticScreenProps; const ModalScreen: React.FC = ({ route: { params } }) => { const navigation = useNavigation(); diff --git a/app/src/screens/passport/PassportCameraScreen.tsx b/app/src/screens/passport/PassportCameraScreen.tsx index e5e21104d..e754d24a7 100644 --- a/app/src/screens/passport/PassportCameraScreen.tsx +++ b/app/src/screens/passport/PassportCameraScreen.tsx @@ -26,11 +26,9 @@ import { dinot } from '@/utils/fonts'; import { hasAnyValidRegisteredDocument } from '@/utils/proving/validateDocument'; import { checkScannedInfo } from '@/utils/utils'; -interface PassportNFCScanScreen {} - const { trackEvent } = analytics(); -const PassportCameraScreen: React.FC = ({}) => { +const PassportCameraScreen: React.FC = () => { const navigation = useNavigation(); const isFocused = useIsFocused(); const store = useUserStore(); diff --git a/app/src/screens/passport/PassportNFCScanScreen.tsx b/app/src/screens/passport/PassportNFCScanScreen.tsx index 6ebb20c0c..fbc322fb8 100644 --- a/app/src/screens/passport/PassportNFCScanScreen.tsx +++ b/app/src/screens/passport/PassportNFCScanScreen.tsx @@ -52,8 +52,6 @@ import { hasAnyValidRegisteredDocument } from '@/utils/proving/validateDocument' const { trackEvent } = analytics(); -interface PassportNFCScanScreenProps {} - const emitter = Platform.OS === 'android' ? new NativeEventEmitter(NativeModules.nativeModule) @@ -73,7 +71,7 @@ type PassportNFCScanRoute = RouteProp< string >; -const PassportNFCScanScreen: React.FC = ({}) => { +const PassportNFCScanScreen: React.FC = () => { const navigation = useNavigation(); const route = useRoute(); const { diff --git a/app/src/screens/passport/PassportNFCScanScreen.web.tsx b/app/src/screens/passport/PassportNFCScanScreen.web.tsx index 00414c57f..e511145ce 100644 --- a/app/src/screens/passport/PassportNFCScanScreen.web.tsx +++ b/app/src/screens/passport/PassportNFCScanScreen.web.tsx @@ -15,9 +15,7 @@ import { ExpandableBottomLayout } from '@/layouts/ExpandableBottomLayout'; import { black, slate100, white } from '@/utils/colors'; import { hasAnyValidRegisteredDocument } from '@/utils/proving/validateDocument'; -interface PassportNFCScanScreenProps {} - -const PassportNFCScanScreen: React.FC = ({}) => { +const PassportNFCScanScreen: React.FC = () => { const navigateToLaunch = useHapticNavigation('Launch', { action: 'cancel', }); diff --git a/app/src/screens/passport/PassportOnboardingScreen.tsx b/app/src/screens/passport/PassportOnboardingScreen.tsx index 404382d1e..1028c86a4 100644 --- a/app/src/screens/passport/PassportOnboardingScreen.tsx +++ b/app/src/screens/passport/PassportOnboardingScreen.tsx @@ -20,11 +20,7 @@ import { ExpandableBottomLayout } from '@/layouts/ExpandableBottomLayout'; import { black, slate100, white } from '@/utils/colors'; import { impactLight } from '@/utils/haptic'; -interface PassportOnboardingScreenProps {} - -const PassportOnboardingScreen: React.FC< - PassportOnboardingScreenProps -> = ({}) => { +const PassportOnboardingScreen: React.FC = () => { const navigation = useNavigation(); const handleCameraPress = useHapticNavigation('PassportCamera'); const animationRef = useRef(null); diff --git a/app/src/screens/prove/ConfirmBelongingScreen.tsx b/app/src/screens/prove/ConfirmBelongingScreen.tsx index fdd5ddbed..0dab5f525 100644 --- a/app/src/screens/prove/ConfirmBelongingScreen.tsx +++ b/app/src/screens/prove/ConfirmBelongingScreen.tsx @@ -23,11 +23,11 @@ import { } from '@/utils/notifications/notificationService'; import { useProvingStore } from '@/utils/proving/provingMachine'; -type ConfirmBelongingScreenProps = StaticScreenProps<{}>; +type ConfirmBelongingScreenProps = StaticScreenProps>; const { trackEvent } = analytics(); -const ConfirmBelongingScreen: React.FC = ({}) => { +const ConfirmBelongingScreen: React.FC = () => { const navigate = useHapticNavigation('LoadingScreen', { params: {}, }); diff --git a/app/src/screens/prove/ProofRequestStatusScreen.tsx b/app/src/screens/prove/ProofRequestStatusScreen.tsx index f422cbe6a..9cf275ef8 100644 --- a/app/src/screens/prove/ProofRequestStatusScreen.tsx +++ b/app/src/screens/prove/ProofRequestStatusScreen.tsx @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BUSL-1.1; Copyright (c) 2025 Social Connect Labs, Inc.; Licensed under BUSL-1.1 (see LICENSE); Apache-2.0 from 2029-06-11 import LottieView from 'lottie-react-native'; -import React, { useEffect, useRef, useState } from 'react'; +import React, { useCallback, useEffect, useRef, useState } from 'react'; import { Linking, StyleSheet, View } from 'react-native'; import { SystemBars } from 'react-native-edge-to-edge'; import { ScrollView, Spinner } from 'tamagui'; @@ -51,13 +51,13 @@ const SuccessScreen: React.FC = () => { const [countdownStarted, setCountdownStarted] = useState(false); const timerRef = useRef(null); - function onOkPress() { + const onOkPress = useCallback(() => { buttonTap(); goHome(); setTimeout(() => { cleanSelfApp(); }, 2000); // Wait 2 seconds to user coming back to the home screen. If we don't wait the appname will change and user will see it. - } + }, [goHome, cleanSelfApp]); function cancelDeeplinkCallbackRedirect() { setCountdown(null); @@ -91,7 +91,7 @@ const SuccessScreen: React.FC = () => { setCountdown(5); setCountdownStarted(true); } - } catch (_error) { + } catch { console.warn( 'Invalid deep link URL provided:', selfApp.deeplinkCallback, diff --git a/app/src/screens/prove/ViewFinderScreen.tsx b/app/src/screens/prove/ViewFinderScreen.tsx index 4e58d33c2..1afa7490b 100644 --- a/app/src/screens/prove/ViewFinderScreen.tsx +++ b/app/src/screens/prove/ViewFinderScreen.tsx @@ -27,11 +27,9 @@ import analytics from '@/utils/analytics'; import { black, slate800, white } from '@/utils/colors'; import { parseAndValidateUrlParams } from '@/utils/deeplinks'; -interface QRCodeViewFinderScreenProps {} - const { trackEvent } = analytics(); -const QRCodeViewFinderScreen: React.FC = ({}) => { +const QRCodeViewFinderScreen: React.FC = () => { const { visible: connectionModalVisible } = useConnectionModal(); const navigation = useNavigation(); const isFocused = useIsFocused(); diff --git a/app/src/screens/recovery/AccountRecoveryChoiceScreen.tsx b/app/src/screens/recovery/AccountRecoveryChoiceScreen.tsx index bb043d412..9b23c5e1a 100644 --- a/app/src/screens/recovery/AccountRecoveryChoiceScreen.tsx +++ b/app/src/screens/recovery/AccountRecoveryChoiceScreen.tsx @@ -27,11 +27,7 @@ import { isUserRegisteredWithAlternativeCSCA } from '@/utils/proving/validateDoc const { trackEvent } = analytics(); -interface AccountRecoveryChoiceScreenProps {} - -const AccountRecoveryChoiceScreen: React.FC< - AccountRecoveryChoiceScreenProps -> = ({}) => { +const AccountRecoveryChoiceScreen: React.FC = () => { const { restoreAccountFromMnemonic } = useAuth(); const [restoring, setRestoring] = useState(false); const { cloudBackupEnabled, toggleCloudBackupEnabled, biometricsAvailable } = diff --git a/app/src/screens/recovery/AccountRecoveryScreen.tsx b/app/src/screens/recovery/AccountRecoveryScreen.tsx index 972194e92..7e0be8ae4 100644 --- a/app/src/screens/recovery/AccountRecoveryScreen.tsx +++ b/app/src/screens/recovery/AccountRecoveryScreen.tsx @@ -13,9 +13,7 @@ import RestoreAccountSvg from '@/images/icons/restore_account.svg'; import { ExpandableBottomLayout } from '@/layouts/ExpandableBottomLayout'; import { black, slate600, white } from '@/utils/colors'; -interface AccountRecoveryScreenProps {} - -const AccountRecoveryScreen: React.FC = ({}) => { +const AccountRecoveryScreen: React.FC = () => { const onRestoreAccountPress = useHapticNavigation('AccountRecoveryChoice'); const onCreateAccountPress = useHapticNavigation('CloudBackupSettings', { params: { diff --git a/app/src/screens/recovery/RecoverWithPhraseScreen.tsx b/app/src/screens/recovery/RecoverWithPhraseScreen.tsx index 8dafdea0a..aa4f510cf 100644 --- a/app/src/screens/recovery/RecoverWithPhraseScreen.tsx +++ b/app/src/screens/recovery/RecoverWithPhraseScreen.tsx @@ -27,11 +27,7 @@ import { } from '@/utils/colors'; import { isUserRegisteredWithAlternativeCSCA } from '@/utils/proving/validateDocument'; -interface RecoverWithPhraseScreenProps {} - -const RecoverWithPhraseScreen: React.FC< - RecoverWithPhraseScreenProps -> = ({}) => { +const RecoverWithPhraseScreen: React.FC = () => { const navigation = useNavigation(); const { restoreAccountFromMnemonic } = useAuth(); const { trackEvent } = analytics(); diff --git a/app/src/screens/recovery/SaveRecoveryPhraseScreen.tsx b/app/src/screens/recovery/SaveRecoveryPhraseScreen.tsx index 23ba67ea8..451da23f6 100644 --- a/app/src/screens/recovery/SaveRecoveryPhraseScreen.tsx +++ b/app/src/screens/recovery/SaveRecoveryPhraseScreen.tsx @@ -15,11 +15,7 @@ import { useSettingStore } from '@/stores/settingStore'; import { STORAGE_NAME } from '@/utils/cloudBackup'; import { black, slate400, white } from '@/utils/colors'; -interface SaveRecoveryPhraseScreenProps {} - -const SaveRecoveryPhraseScreen: React.FC< - SaveRecoveryPhraseScreenProps -> = ({}) => { +const SaveRecoveryPhraseScreen: React.FC = () => { const [userHasSeenMnemonic, setUserHasSeenMnemonic] = useState(false); const { mnemonic, loadMnemonic } = useMnemonic(); const { cloudBackupEnabled } = useSettingStore(); diff --git a/app/src/screens/settings/CloudBackupScreen.tsx b/app/src/screens/settings/CloudBackupScreen.tsx index 4c0547d99..86a03139f 100644 --- a/app/src/screens/settings/CloudBackupScreen.tsx +++ b/app/src/screens/settings/CloudBackupScreen.tsx @@ -27,13 +27,12 @@ const { trackEvent } = analytics(); type NextScreen = keyof Pick; -interface CloudBackupScreenProps - extends StaticScreenProps< - | { - nextScreen?: NextScreen; - } - | undefined - > {} +type CloudBackupScreenProps = StaticScreenProps< + | { + nextScreen?: NextScreen; + } + | undefined +>; const CloudBackupScreen: React.FC = ({ route: { params }, diff --git a/app/src/screens/settings/ManageDocumentsScreen.tsx b/app/src/screens/settings/ManageDocumentsScreen.tsx index 517da884d..bfb902b2a 100644 --- a/app/src/screens/settings/ManageDocumentsScreen.tsx +++ b/app/src/screens/settings/ManageDocumentsScreen.tsx @@ -25,8 +25,6 @@ import { impactLight } from '@/utils/haptic'; const { trackEvent } = analytics(); -interface ManageDocumentsScreenProps {} - const PassportDataSelector = () => { const { loadDocumentCatalog, @@ -140,7 +138,7 @@ const PassportDataSelector = () => { return 'IND'; } return null; - } catch (_error) { + } catch { return null; } }; @@ -265,7 +263,7 @@ const PassportDataSelector = () => { ); }; -const ManageDocumentsScreen: React.FC = ({}) => { +const ManageDocumentsScreen: React.FC = () => { const navigation = useNavigation>(); const { bottom } = useSafeAreaInsets(); @@ -281,6 +279,7 @@ const ManageDocumentsScreen: React.FC = ({}) => { }; const handleGenerateMock = () => { + if (!__DEV__) return; impactLight(); trackEvent(DocumentEvents.ADD_NEW_MOCK_SELECTED); navigation.navigate('CreateMock'); @@ -313,9 +312,11 @@ const ManageDocumentsScreen: React.FC = ({}) => { Scan New ID Document - - Generate Mock Document - + {__DEV__ && ( + + Generate Mock Document + + )} diff --git a/app/src/screens/settings/PassportDataInfoScreen.tsx b/app/src/screens/settings/PassportDataInfoScreen.tsx index b474bccdc..346058f71 100644 --- a/app/src/screens/settings/PassportDataInfoScreen.tsx +++ b/app/src/screens/settings/PassportDataInfoScreen.tsx @@ -59,9 +59,7 @@ const InfoRow: React.FC<{ ); -interface PassportDataInfoScreenProps {} - -const PassportDataInfoScreen: React.FC = ({}) => { +const PassportDataInfoScreen: React.FC = () => { const { getData } = usePassport(); const [metadata, setMetadata] = useState(null); const { bottom } = useSafeAreaInsets(); diff --git a/app/src/screens/settings/SettingsScreen.tsx b/app/src/screens/settings/SettingsScreen.tsx index fbfc51d22..d05f3d2f5 100644 --- a/app/src/screens/settings/SettingsScreen.tsx +++ b/app/src/screens/settings/SettingsScreen.tsx @@ -40,7 +40,6 @@ import { getCountry, getLocales, getTimeZone } from '@/utils/locale'; import { version } from '../../../package.json'; -interface SettingsScreenProps {} interface MenuButtonProps extends PropsWithChildren { Icon: React.FC; onPress: () => void; @@ -140,9 +139,8 @@ const SocialButton: React.FC = ({ Icon, href }) => { ); }; -const SettingsScreen: React.FC = ({}) => { +const SettingsScreen: React.FC = () => { const { isDevMode, setDevModeOn } = useSettingStore(); - useSettingStore(); const navigation = useNavigation>(); diff --git a/app/src/screens/settings/ShowRecoveryPhraseScreen.tsx b/app/src/screens/settings/ShowRecoveryPhraseScreen.tsx index d40c30aec..3337a8fa8 100644 --- a/app/src/screens/settings/ShowRecoveryPhraseScreen.tsx +++ b/app/src/screens/settings/ShowRecoveryPhraseScreen.tsx @@ -7,11 +7,7 @@ import Description from '@/components/typography/Description'; import useMnemonic from '@/hooks/useMnemonic'; import { ExpandableBottomLayout } from '@/layouts/ExpandableBottomLayout'; -interface ShowRecoveryPhraseScreenProps {} - -const ShowRecoveryPhraseScreen: React.FC< - ShowRecoveryPhraseScreenProps -> = ({}) => { +const ShowRecoveryPhraseScreen: React.FC = () => { const { mnemonic, loadMnemonic } = useMnemonic(); const onRevealWords = useCallback(async () => { diff --git a/app/src/utils/cloudBackup/helpers.ts b/app/src/utils/cloudBackup/helpers.ts index 5995572b1..d89972921 100644 --- a/app/src/utils/cloudBackup/helpers.ts +++ b/app/src/utils/cloudBackup/helpers.ts @@ -38,7 +38,7 @@ export function parseMnemonic(mnemonicString: string): Mnemonic { try { parsed = JSON.parse(mnemonicString); - } catch (_e) { + } catch { throw new Error('Invalid JSON format in mnemonic backup'); } diff --git a/app/src/utils/logger/nativeLoggerBridge.ts b/app/src/utils/logger/nativeLoggerBridge.ts index 464a08c52..c13247aa6 100644 --- a/app/src/utils/logger/nativeLoggerBridge.ts +++ b/app/src/utils/logger/nativeLoggerBridge.ts @@ -51,7 +51,7 @@ const setupEventListeners = () => { try { const parsedEvent = JSON.parse(event); handleNativeLogEvent(parsedEvent); - } catch (_e) { + } catch { console.warn('Failed to parse logEvent string:', event); } } else { diff --git a/app/src/utils/proving/provingMachine.ts b/app/src/utils/proving/provingMachine.ts index eb875a594..ae48a516a 100644 --- a/app/src/utils/proving/provingMachine.ts +++ b/app/src/utils/proving/provingMachine.ts @@ -422,7 +422,7 @@ export const useProvingStore = create((set, get) => { navigationRef.navigate('Launch'); } } - } catch (_error) { + } catch { if (navigationRef.isReady()) { navigationRef.navigate('Launch'); } diff --git a/app/src/utils/testingUtils.ts b/app/src/utils/testingUtils.ts index 1ae8aec00..f90b55cc4 100644 --- a/app/src/utils/testingUtils.ts +++ b/app/src/utils/testingUtils.ts @@ -26,7 +26,7 @@ export async function clearDocumentCatalogForMigrationTesting(): Promise { try { await Keychain.resetGenericPassword({ service: `document-${doc.id}` }); console.log(`Cleared document: ${doc.id}`); - } catch (_error) { + } catch { console.log(`Document ${doc.id} not found or already cleared`); } } @@ -35,7 +35,7 @@ export async function clearDocumentCatalogForMigrationTesting(): Promise { try { await Keychain.resetGenericPassword({ service: 'documentCatalog' }); console.log('Cleared document catalog'); - } catch (_error) { + } catch { console.log('Document catalog not found or already cleared'); } diff --git a/app/src/vite-env.d.ts b/app/src/vite-env.d.ts index 4490e0c53..d8550b1da 100644 --- a/app/src/vite-env.d.ts +++ b/app/src/vite-env.d.ts @@ -1,11 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1; Copyright (c) 2025 Social Connect Labs, Inc.; Licensed under BUSL-1.1 (see LICENSE); Apache-2.0 from 2029-06-11 -interface ViteTypeOptions { - // By adding this line, you can make the type of ImportMetaEnv strict - // to disallow unknown keys. - // strictImportMetaEnv: unknown -} - interface ImportMetaEnv { readonly VITE_APP_TITLE: string; readonly VITE_DEV_PRIVATE_SECRET_FOR_TESTING: string; diff --git a/app/tamagui.config.ts b/app/tamagui.config.ts index d9aece3e4..131fa0f75 100644 --- a/app/tamagui.config.ts +++ b/app/tamagui.config.ts @@ -73,6 +73,8 @@ declare module 'tamagui' { // or '@tamagui/core' // overrides TamaguiCustomConfig so your custom types // work everywhere you import `tamagui` + + // eslint-disable-next-line @typescript-eslint/no-empty-object-type interface TamaguiCustomConfig extends AppConfig {} } diff --git a/app/tests/src/providers/passportDataProvider.test.tsx b/app/tests/src/providers/passportDataProvider.test.tsx index b1821edf9..07db9eaf1 100644 --- a/app/tests/src/providers/passportDataProvider.test.tsx +++ b/app/tests/src/providers/passportDataProvider.test.tsx @@ -90,7 +90,7 @@ const ErrorBoundaryTest = () => { try { // This would normally call a context function return 'success'; - } catch (_error) { + } catch { return 'error'; } }; @@ -446,9 +446,10 @@ describe('PassportDataProvider', () => { // Re-import the module after mocking to ensure mock is applied const passportModule = require('@/providers/passportDataProvider'); - const loadDocumentCatalogLocal = passportModule.loadDocumentCatalog; + const loadDocumentCatalogLocalUndefined = + passportModule.loadDocumentCatalog; - const result = await loadDocumentCatalogLocal(); + const result = await loadDocumentCatalogLocalUndefined(); expect(result).toEqual({ documents: [] }); }); diff --git a/sdk/qrcode/package.json b/sdk/qrcode/package.json index 9c4a113a9..f8e58c2ed 100644 --- a/sdk/qrcode/package.json +++ b/sdk/qrcode/package.json @@ -17,34 +17,34 @@ "type": "module", "exports": { ".": { + "types": "./dist/esm/index.d.ts", "import": "./dist/esm/index.js", - "require": "./dist/cjs/index.cjs", - "types": "./dist/esm/index.d.ts" + "require": "./dist/cjs/index.cjs" }, "./components/LED": { + "types": "./dist/esm/components/LED.d.ts", "import": "./dist/esm/components/LED.js", - "require": "./dist/cjs/components/LED.cjs", - "types": "./dist/esm/components/LED.d.ts" + "require": "./dist/cjs/components/LED.cjs" }, "./components/SelfQRcode": { + "types": "./dist/esm/components/SelfQRcode.d.ts", "import": "./dist/esm/components/SelfQRcode.js", - "require": "./dist/cjs/components/SelfQRcode.cjs", - "types": "./dist/esm/components/SelfQRcode.d.ts" + "require": "./dist/cjs/components/SelfQRcode.cjs" }, "./utils/utils": { + "types": "./dist/esm/utils/utils.d.ts", "import": "./dist/esm/utils/utils.js", - "require": "./dist/cjs/utils/utils.cjs", - "types": "./dist/esm/utils/utils.d.ts" + "require": "./dist/cjs/utils/utils.cjs" }, "./utils/styles": { + "types": "./dist/esm/utils/styles.d.ts", "import": "./dist/esm/utils/styles.js", - "require": "./dist/cjs/utils/styles.cjs", - "types": "./dist/esm/utils/styles.d.ts" + "require": "./dist/cjs/utils/styles.cjs" }, "./utils/websocket": { + "types": "./dist/esm/utils/websocket.d.ts", "import": "./dist/esm/utils/websocket.js", - "require": "./dist/cjs/utils/websocket.cjs", - "types": "./dist/esm/utils/websocket.d.ts" + "require": "./dist/cjs/utils/websocket.cjs" } }, "main": "dist/cjs/index.cjs",