From 8cb3a7528a7c5d5481f0a38eee2ae223360aec33 Mon Sep 17 00:00:00 2001 From: EthanShoeDev <13422990+EthanShoeDev@users.noreply.github.com> Date: Thu, 18 Sep 2025 01:43:40 -0400 Subject: [PATCH] new eslint --- apps/mobile/eslint.config.js | 112 +++- apps/mobile/package.json | 13 +- apps/mobile/scripts/script-lib.ts | 8 +- apps/mobile/scripts/signed-build.ts | 5 +- apps/mobile/src/app/(modals)/key-manager.tsx | 10 +- apps/mobile/src/app/(tabs)/index.tsx | 18 +- apps/mobile/src/app/(tabs)/settings/index.tsx | 8 +- apps/mobile/src/app/(tabs)/shell/detail.tsx | 239 ++++--- apps/mobile/src/app/(tabs)/shell/index.tsx | 45 +- .../mobile/src/components/form-components.tsx | 19 +- .../src/components/key-manager/KeyList.tsx | 28 +- apps/mobile/src/lib/preferences.tsx | 9 +- apps/mobile/src/lib/query-fns.ts | 44 +- apps/mobile/src/lib/secrets-manager.ts | 10 +- apps/mobile/src/lib/ssh-registry.ts | 108 --- apps/mobile/src/lib/ssh-store.ts | 86 +++ apps/mobile/src/lib/theme.tsx | 18 +- apps/mobile/src/lib/utils.ts | 4 +- .../react-native-xtermjs-webview/index.html | 4 +- pnpm-lock.yaml | 614 +++++++++++++++--- 20 files changed, 1014 insertions(+), 388 deletions(-) delete mode 100644 apps/mobile/src/lib/ssh-registry.ts create mode 100644 apps/mobile/src/lib/ssh-store.ts diff --git a/apps/mobile/eslint.config.js b/apps/mobile/eslint.config.js index 27667b0..cc0d34f 100644 --- a/apps/mobile/eslint.config.js +++ b/apps/mobile/eslint.config.js @@ -1,27 +1,115 @@ // https://docs.expo.dev/guides/using-eslint/ import { createRequire } from 'node:module'; import { config as epicConfig } from '@epic-web/config/eslint'; +import eslint from '@eslint/js'; +import comments from '@eslint-community/eslint-plugin-eslint-comments/configs'; +import react from '@eslint-react/eslint-plugin'; +import pluginQuery from '@tanstack/eslint-plugin-query'; +import * as tsParser from '@typescript-eslint/parser'; import { defineConfig } from 'eslint/config'; +import eslintReact from 'eslint-plugin-react'; +import pluginReactCompiler from 'eslint-plugin-react-compiler'; +import hooksPlugin from 'eslint-plugin-react-hooks'; +import globals from 'globals'; +import tseslint from 'typescript-eslint'; const require = createRequire(import.meta.url); const expoConfig = require('eslint-config-expo/flat'); -// // Both epic and expo define a 'import' plugin (though not the same package) -// // We need to pick one or they will conflict. -const stripImportPlugin = (config) => { - if (!config?.plugins?.['import']) return config; - const { import: _removed, ...rest } = config.plugins; - return { - ...config, - plugins: rest, - }; +// Several presets define the same plugin keys which causes conflicts in ESLint flat config +// (e.g. 'import' from different packages, and '@typescript-eslint'). +// Remove conflicting plugins from upstream presets so we can control which wins. +const stripPlugins = (config, names) => { + if (!config?.plugins) return config; + const plugins = { ...config.plugins }; + let changed = false; + for (const name of names) { + if (plugins[name]) { + delete plugins[name]; + changed = true; + } + } + return changed ? { ...config, plugins } : config; }; export default defineConfig([ - ...expoConfig, - ...epicConfig.map(stripImportPlugin), + // Expo (strip conflicting plugins defined elsewhere) + ...expoConfig.map((c) => stripPlugins(c, ['@typescript-eslint'])), + // Epic (strip conflicting plugins defined elsewhere) + ...epicConfig.map((c) => stripPlugins(c, ['import', '@typescript-eslint'])), + + // ts-eslint + eslint.configs.recommended, + ...tseslint.configs.strictTypeChecked, + ...tseslint.configs.stylisticTypeChecked, { - ignores: ['dist'], + languageOptions: { + parserOptions: { + projectService: true, + tsconfigRootDir: import.meta.dirname, + }, + }, + }, + + // tanstack query + ...pluginQuery.configs['flat/recommended'], + + // @eslint-react/eslint-plugin (smaller version of eslint-plugin-react) + { + files: ['**/*.{ts,tsx}'], + ...react.configs['recommended-type-checked'], + languageOptions: { + parser: tsParser, + }, + }, + + // Lint eslint disable comments + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access -- no types + comments.recommended, + + // eslint-plugin-react + // Terrible flat config support + { + ...eslintReact.configs.flat.recommended, + files: ['**/*.{ts,tsx}'], + settings: { react: { version: 'detect' } }, + languageOptions: { + ...eslintReact.configs.flat.recommended?.languageOptions, + globals: { + ...globals.serviceworker, + ...globals.browser, + }, + }, + plugins: { + ...eslintReact.configs.flat.recommended?.plugins, + 'react-hooks': hooksPlugin, + 'react-compiler': pluginReactCompiler, + }, + rules: { + ...hooksPlugin.configs.recommended.rules, + 'react/display-name': 'off', + 'react/prop-types': 'off', + 'react/jsx-uses-react': 'off', + 'react/react-in-jsx-scope': 'off', + 'react-compiler/react-compiler': 'error', + }, + }, + + // Custom + { + ignores: [ + 'dist', + '**/*.d.ts', + '**/.expo/**', + 'prettier.config.mjs', + 'eslint.config.js', + ], + }, + { + rules: { + '@typescript-eslint/no-explicit-any': 'error', + '@typescript-eslint/restrict-template-expressions': 'off', + }, }, ]); diff --git a/apps/mobile/package.json b/apps/mobile/package.json index f849ef2..8a77d37 100644 --- a/apps/mobile/package.json +++ b/apps/mobile/package.json @@ -55,7 +55,6 @@ "expo-status-bar": "~3.0.8", "expo-symbols": "~1.0.7", "expo-system-ui": "~6.0.7", - "p-queue": "^8.1.1", "react": "19.1.0", "react-dom": "19.1.0", "react-native": "0.81.4", @@ -76,6 +75,18 @@ "@types/react": "~19.1.12", "cmd-ts": "^0.14.1", "eslint": "^9.35.0", + "@eslint/js": "^9.35.0", + "@eslint-community/eslint-plugin-eslint-comments": "^4.5.0", + "@eslint-react/eslint-plugin": "^1.53.0", + "@tanstack/eslint-plugin-query": "^5.86.0", + "@typescript-eslint/parser": "^8.44.0", + "@typescript-eslint/utils": "^8.43.0", + "eslint-plugin-react": "^7.37.5", + "eslint-plugin-react-compiler": "19.1.0-rc.2", + "eslint-plugin-react-hooks": "^5.2.0", + "globals": "^16.4.0", + "eslint-plugin-react-refresh": "^0.4.20", + "typescript-eslint": "^8.44.0", "eslint-config-expo": "~10.0.0", "jiti": "^2.5.1", "npm-run-all": "^4.1.5", diff --git a/apps/mobile/scripts/script-lib.ts b/apps/mobile/scripts/script-lib.ts index 6431d07..a97cd31 100644 --- a/apps/mobile/scripts/script-lib.ts +++ b/apps/mobile/scripts/script-lib.ts @@ -19,11 +19,11 @@ export const cmd = ( let stdout = ''; let stderr = ''; - proc.stdout?.on('data', (data) => { - stdout += data; + proc.stdout?.on('data', (data: unknown) => { + stdout += String(data); }); - proc.stderr?.on('data', (data) => { - stderr += data; + proc.stderr?.on('data', (data: unknown) => { + stderr += String(data); }); process.once('SIGTERM', () => { diff --git a/apps/mobile/scripts/signed-build.ts b/apps/mobile/scripts/signed-build.ts index 99e9861..636c6b3 100644 --- a/apps/mobile/scripts/signed-build.ts +++ b/apps/mobile/scripts/signed-build.ts @@ -19,7 +19,6 @@ async function getSecrets(): Promise<{ stdio: 'pipe', }, ); - const rawBwItem = JSON.parse(rawBwItemString); const bwItemSchema = z.looseObject({ login: z.looseObject({ username: z.string(), @@ -32,7 +31,7 @@ async function getSecrets(): Promise<{ }), ), }); - const bwItem = bwItemSchema.parse(rawBwItem, { + const bwItem = bwItemSchema.parse(JSON.parse(rawBwItemString) as unknown, { reportInput: true, }); const keystoreBase64 = bwItem.fields.find( @@ -138,7 +137,7 @@ const signedBuildCommand = command({ .replace( /signingConfigs \{([\s\S]*?)\}/, // Modify existing signingConfigs without removing debug (match) => { - if (/release \{/.test(match)) { + if (match.includes('release {')) { return match.replace( /release \{([\s\S]*?)\}/, releaseSigningConfig, diff --git a/apps/mobile/src/app/(modals)/key-manager.tsx b/apps/mobile/src/app/(modals)/key-manager.tsx index 8e8f264..ffbdd5b 100644 --- a/apps/mobile/src/app/(modals)/key-manager.tsx +++ b/apps/mobile/src/app/(modals)/key-manager.tsx @@ -15,7 +15,11 @@ export default function KeyManagerModalRoute() { options={{ title: selectMode ? 'Select Key' : 'Manage Keys', headerRight: () => ( - router.back()}> + { + router.back(); + }} + > Close ), @@ -23,7 +27,9 @@ export default function KeyManagerModalRoute() { /> router.back()} + onSelect={() => { + router.back(); + }} /> ); diff --git a/apps/mobile/src/app/(tabs)/index.tsx b/apps/mobile/src/app/(tabs)/index.tsx index 298763b..f1b2262 100644 --- a/apps/mobile/src/app/(tabs)/index.tsx +++ b/apps/mobile/src/app/(tabs)/index.tsx @@ -237,7 +237,7 @@ function KeyIdPickerField() { const listPrivateKeysQuery = useQuery(secretsManager.keys.query.list); const defaultPick = React.useMemo(() => { const keys = listPrivateKeysQuery.data ?? []; - const def = keys.find((k) => k.metadata?.isDefault); + const def = keys.find((k) => k.metadata.isDefault); return def ?? keys[0]; }, [listPrivateKeysQuery.data]); const keys = listPrivateKeysQuery.data ?? []; @@ -252,9 +252,9 @@ function KeyIdPickerField() { } }, [fieldValue, defaultPickId, fieldHandleChange]); - const computedSelectedId = field.state.value ?? defaultPick?.id; + const computedSelectedId = field.state.value; const selected = keys.find((k) => k.id === computedSelectedId); - const display = selected ? (selected.metadata?.label ?? selected.id) : 'None'; + const display = selected ? (selected.metadata.label ?? selected.id) : 'None'; return ( <> @@ -298,7 +298,9 @@ function KeyIdPickerField() { visible={open} transparent animationType="slide" - onRequestClose={() => setOpen(false)} + onRequestClose={() => { + setOpen(false); + }} > setOpen(false)} + onPress={() => { + setOpen(false); + }} > { + onSelect={(id) => { field.handleChange(id); setOpen(false); }} @@ -399,7 +403,7 @@ function PreviousConnectionsSection(props: { ) : listConnectionsQuery.data?.length ? ( - {listConnectionsQuery.data?.map((conn) => ( + {listConnectionsQuery.data.map((conn) => ( setThemeName('dark')} + onPress={() => { + setThemeName('dark'); + }} /> setThemeName('light')} + onPress={() => { + setThemeName('light'); + }} /> diff --git a/apps/mobile/src/app/(tabs)/shell/detail.tsx b/apps/mobile/src/app/(tabs)/shell/detail.tsx index a28a0e8..e5ffb4d 100644 --- a/apps/mobile/src/app/(tabs)/shell/detail.tsx +++ b/apps/mobile/src/app/(tabs)/shell/detail.tsx @@ -1,8 +1,5 @@ import { Ionicons } from '@expo/vector-icons'; -import { - type ListenerEvent, - type TerminalChunk, -} from '@fressh/react-native-uniffi-russh'; +import { type ListenerEvent } from '@fressh/react-native-uniffi-russh'; import { XtermJsWebView, type XtermWebViewHandle, @@ -16,11 +13,14 @@ import { useFocusEffect, } from 'expo-router'; import React, { startTransition, useEffect, useRef, useState } from 'react'; -import { Pressable, View, Text } from 'react-native'; +import { Dimensions, Platform, Pressable, Text, View } from 'react-native'; -import { SafeAreaView } from 'react-native-safe-area-context'; +import { + SafeAreaView, + useSafeAreaInsets, +} from 'react-native-safe-area-context'; import { disconnectSshConnectionAndInvalidateQuery } from '@/lib/query-fns'; -import { getSession } from '@/lib/ssh-registry'; +import { useSshStore, makeSessionKey } from '@/lib/ssh-store'; import { useTheme } from '@/lib/theme'; export default function TabsShellDetail() { @@ -28,9 +28,13 @@ export default function TabsShellDetail() { useFocusEffect( React.useCallback(() => { - startTransition(() => setReady(true)); // React 19: non-urgent + startTransition(() => { + setReady(true); + }); // React 19: non-urgent - return () => setReady(false); + return () => { + setReady(false); + }; }, []), ); @@ -60,10 +64,11 @@ function ShellDetail() { const theme = useTheme(); const channelIdNum = Number(channelId); - const sess = + const sess = useSshStore((s) => connectionId && channelId - ? getSession(String(connectionId), channelIdNum) - : undefined; + ? s.getByKey(makeSessionKey(connectionId, channelIdNum)) + : undefined, + ); const connection = sess?.connection; const shell = sess?.shell; @@ -74,14 +79,41 @@ function ShellDetail() { if (shell && listenerIdRef.current != null) shell.removeListener(listenerIdRef.current); listenerIdRef.current = null; - xterm?.flush?.(); + if (xterm) xterm.flush(); }; }, [shell]); const queryClient = useQueryClient(); + const insets = useSafeAreaInsets(); + const estimatedTabBarHeight = Platform.select({ + ios: 49, + android: 80, + default: 56, + }); + const windowH = Dimensions.get('window').height; + const computeBottomExtra = (y: number, height: number) => { + const extra = windowH - (y + height); + return extra > 0 ? extra : 0; + }; + + // Measure any bottom overlap (e.g., native tab bar) and add padding to avoid it + const [bottomExtra, setBottomExtra] = useState(0); return ( - + { + const { y, height } = e.nativeEvent.layout; + const extra = computeBottomExtra(y, height); + if (extra !== bottomExtra) setBottomExtra(extra); + }} + style={{ + flex: 1, + backgroundColor: theme.colors.background, + padding: 12, + paddingBottom: + 12 + insets.bottom + (bottomExtra || estimatedTabBarHeight), + }} + > - - { - console.log('WebView render process gone -> clear()'); - xtermRef.current?.clear?.(); - }} - onContentProcessDidTerminate={() => { - console.log('WKWebView content process terminated -> clear()'); - xtermRef.current?.clear?.(); - }} - onLoadEnd={() => { - console.log('WebView onLoadEnd'); - }} - onMessage={(m) => { - console.log('received msg', m); - if (m.type === 'initialized') { - if (terminalReadyRef.current) return; - terminalReadyRef.current = true; + { + console.log('WebView render process gone -> clear()'); + const xr = xtermRef.current; + if (xr) xr.clear(); + }} + onContentProcessDidTerminate={() => { + console.log('WKWebView content process terminated -> clear()'); + const xr = xtermRef.current; + if (xr) xr.clear(); + }} + onLoadEnd={() => { + console.log('WebView onLoadEnd'); + }} + onMessage={(m) => { + console.log('received msg', m); + if (m.type === 'initialized') { + if (terminalReadyRef.current) return; + terminalReadyRef.current = true; - // Replay from head, then attach live listener - if (shell) { - void (async () => { - const res = await shell.readBuffer({ mode: 'head' }); - console.log('readBuffer(head)', { - chunks: res.chunks.length, - nextSeq: res.nextSeq, - dropped: res.dropped, - }); - if (res.chunks.length) { - const chunks = res.chunks.map((c) => c.bytes); - xtermRef.current?.writeMany?.(chunks); - xtermRef.current?.flush?.(); + // Replay from head, then attach live listener + if (shell) { + void (async () => { + const res = await shell.readBuffer({ mode: 'head' }); + console.log('readBuffer(head)', { + chunks: res.chunks.length, + nextSeq: res.nextSeq, + dropped: res.dropped, + }); + if (res.chunks.length) { + const chunks = res.chunks.map((c) => c.bytes); + const xr = xtermRef.current; + if (xr) { + xr.writeMany(chunks); + xr.flush(); } - const id = shell.addListener( - (ev: ListenerEvent) => { - if ('kind' in ev && ev.kind === 'dropped') { - console.log('listener.dropped', ev); - return; - } - const chunk = ev as TerminalChunk; - xtermRef.current?.write(chunk.bytes); - }, - { cursor: { mode: 'seq', seq: res.nextSeq } }, - ); - console.log('shell listener attached', id.toString()); - listenerIdRef.current = id; - })(); - } + } + const id = shell.addListener( + (ev: ListenerEvent) => { + if ('kind' in ev) { + console.log('listener.dropped', ev); + return; + } + const chunk = ev; + const xr3 = xtermRef.current; + if (xr3) xr3.write(chunk.bytes); + }, + { cursor: { mode: 'seq', seq: res.nextSeq } }, + ); + console.log('shell listener attached', id.toString()); + listenerIdRef.current = id; + })(); + } - // Focus to pop the keyboard (iOS needs the prop we set) - xtermRef.current?.focus?.(); - return; + // Focus to pop the keyboard (iOS needs the prop we set) + const xr2 = xtermRef.current; + if (xr2) xr2.focus(); + return; + } + if (m.type === 'data') { + console.log('xterm->SSH', { len: m.data.length }); + const { buffer, byteOffset, byteLength } = m.data; + const ab = buffer.slice(byteOffset, byteOffset + byteLength); + if (shell) { + shell.sendData(ab as ArrayBuffer).catch((e: unknown) => { + console.warn('sendData failed', e); + router.back(); + }); } - if (m.type === 'data') { - console.log('xterm->SSH', { len: m.data.length }); - // Ensure we send the exact slice; send CR only for Enter. - const { buffer, byteOffset, byteLength } = m.data; - const ab = buffer.slice(byteOffset, byteOffset + byteLength); - void shell?.sendData(ab as ArrayBuffer); - return; - } - if (m.type === 'debug') { - console.log('xterm.debug', m.message); - } - }} - /> - + return; + } else { + console.log('xterm.debug', m.message); + } + }} + /> ); } diff --git a/apps/mobile/src/app/(tabs)/shell/index.tsx b/apps/mobile/src/app/(tabs)/shell/index.tsx index 20ca6d3..25e33e0 100644 --- a/apps/mobile/src/app/(tabs)/shell/index.tsx +++ b/apps/mobile/src/app/(tabs)/shell/index.tsx @@ -1,5 +1,8 @@ import { Ionicons } from '@expo/vector-icons'; -import { type SshConnection } from '@fressh/react-native-uniffi-russh'; +import { + type SshShell, + type SshConnection, +} from '@fressh/react-native-uniffi-russh'; import { FlashList } from '@shopify/flash-list'; import { useQuery, useQueryClient } from '@tanstack/react-query'; import { formatDistanceToNow } from 'date-fns'; @@ -21,7 +24,6 @@ import { listSshShellsQueryOptions, type ShellWithConnection, } from '@/lib/query-fns'; -import { type listConnectionsWithShells as registryList } from '@/lib/ssh-registry'; import { useTheme } from '@/lib/theme'; export default function TabsShellList() { @@ -78,7 +80,7 @@ type ActionTarget = connection: SshConnection; }; -type ConnectionsList = ReturnType; +type ConnectionsList = (SshConnection & { shells: SshShell[] })[]; function LoadedState({ connections }: { connections: ConnectionsList }) { const [actionTarget, setActionTarget] = React.useState( @@ -103,7 +105,9 @@ function LoadedState({ connections }: { connections: ConnectionsList }) { )} setActionTarget(null)} + onClose={() => { + setActionTarget(null); + }} onCloseShell={() => { if (!actionTarget) return; if (!('shell' in actionTarget)) return; @@ -138,7 +142,12 @@ function FlatView({ }) { const flatShells = React.useMemo(() => { return connectionsWithShells.reduce((acc, curr) => { - acc.push(...curr.shells.map((shell) => ({ ...shell, connection: curr }))); + acc.push( + ...curr.shells.map((shell) => ({ + ...shell, + connection: curr, + })), + ); return acc; }, []); }, [connectionsWithShells]); @@ -149,11 +158,11 @@ function FlatView({ renderItem={({ item }) => ( + onLongPress={() => { setActionTarget({ shell: item, - }) - } + }); + }} /> )} ItemSeparatorComponent={() => } @@ -194,12 +203,12 @@ function GroupedView({ alignItems: 'center', justifyContent: 'space-between', }} - onPress={() => + onPress={() => { setExpanded((prev) => ({ ...prev, [item.connectionId]: !prev[item.connectionId], - })) - } + })); + }} > + onLongPress={() => { setActionTarget({ shell: shellWithConnection, - }) - } + }); + }} /> ); })} @@ -299,15 +308,15 @@ function ShellCard({ paddingHorizontal: 12, paddingVertical: 12, }} - onPress={() => + onPress={() => { router.push({ pathname: '/shell/detail', params: { - connectionId: String(shell.connectionId), + connectionId: shell.connectionId, channelId: String(shell.channelId), }, - }) - } + }); + }} onLongPress={onLongPress} > diff --git a/apps/mobile/src/components/form-components.tsx b/apps/mobile/src/components/form-components.tsx index 080e01d..391409c 100644 --- a/apps/mobile/src/components/form-components.tsx +++ b/apps/mobile/src/components/form-components.tsx @@ -14,15 +14,14 @@ import { function FieldInfo() { const field = useFieldContext(); - const meta = field.state.meta; - const errorMessage = meta?.errors?.[0]; // TODO: typesafe errors + const meta = field.state.meta as { errors?: unknown[] }; + const errs = meta.errors; + const errorMessage = errs && errs.length > 0 ? String(errs[0]) : null; return ( {errorMessage ? ( - - {String(errorMessage)} - + {errorMessage} ) : null} ); @@ -103,7 +102,9 @@ export function NumberField( ]} placeholderTextColor="#9AA0A6" value={field.state.value.toString()} - onChangeText={(text) => field.handleChange(Number(text))} + onChangeText={(text) => { + field.handleChange(Number(text)); + }} onBlur={field.handleBlur} {...rest} /> @@ -145,7 +146,9 @@ export function SwitchField( style, ]} value={field.state.value} - onChange={(event) => field.handleChange(event.nativeEvent.value)} + onChange={(event) => { + field.handleChange(event.nativeEvent.value); + }} onBlur={field.handleBlur} {...rest} /> @@ -179,7 +182,7 @@ export function SubmitButton( disabled ? { backgroundColor: '#3B82F6', opacity: 0.6 } : undefined, ]} onPress={onPress} - disabled={disabled || isSubmitting} + disabled={disabled === true ? true : isSubmitting} > {isSubmitting ? 'Connecting...' : title} diff --git a/apps/mobile/src/components/key-manager/KeyList.tsx b/apps/mobile/src/components/key-manager/KeyList.tsx index d5554dd..0f20b6c 100644 --- a/apps/mobile/src/components/key-manager/KeyList.tsx +++ b/apps/mobile/src/components/key-manager/KeyList.tsx @@ -41,7 +41,9 @@ export function KeyList(props: { generateMutation.isPending && { opacity: 0.7 }, ]} disabled={generateMutation.isPending} - onPress={() => generateMutation.mutate()} + onPress={() => { + generateMutation.mutate(); + }} > {generateMutation.isPending @@ -80,7 +82,7 @@ function KeyRow(props: { const entryQuery = useQuery(secretsManager.keys.query.get(props.entryId)); const entry = entryQuery.data; const [label, setLabel] = React.useState( - entry?.manifestEntry.metadata?.label ?? '', + entry?.manifestEntry.metadata.label ?? '', ); const renameMutation = useMutation({ @@ -150,8 +152,8 @@ function KeyRow(props: { > - {entry.manifestEntry.metadata?.label ?? entry.manifestEntry.id} - {entry.manifestEntry.metadata?.isDefault ? ' • Default' : ''} + {entry.manifestEntry.metadata.label ?? entry.manifestEntry.id} + {entry.manifestEntry.metadata.isDefault ? ' • Default' : ''} ID: {entry.manifestEntry.id} @@ -179,7 +181,9 @@ function KeyRow(props: { {props.mode === 'select' ? ( setDefaultMutation.mutate()} + onPress={() => { + setDefaultMutation.mutate(); + }} style={{ backgroundColor: '#2563EB', borderRadius: 10, @@ -207,7 +211,9 @@ function KeyRow(props: { }, renameMutation.isPending && { opacity: 0.6 }, ]} - onPress={() => renameMutation.mutate(label)} + onPress={() => { + renameMutation.mutate(label); + }} disabled={renameMutation.isPending} > @@ -215,7 +221,7 @@ function KeyRow(props: { ) : null} - {!entry.manifestEntry.metadata?.isDefault ? ( + {!entry.manifestEntry.metadata.isDefault ? ( setDefaultMutation.mutate()} + onPress={() => { + setDefaultMutation.mutate(); + }} > Set Default @@ -243,7 +251,9 @@ function KeyRow(props: { paddingHorizontal: 10, alignItems: 'center', }} - onPress={() => deleteMutation.mutate()} + onPress={() => { + deleteMutation.mutate(); + }} > Delete diff --git a/apps/mobile/src/lib/preferences.tsx b/apps/mobile/src/lib/preferences.tsx index 3d47e99..f1ebcfe 100644 --- a/apps/mobile/src/lib/preferences.tsx +++ b/apps/mobile/src/lib/preferences.tsx @@ -12,7 +12,9 @@ export const preferences = { rawTheme === 'light' ? 'light' : 'dark', get: (): ThemeName => preferences.theme._resolve(storage.getString(preferences.theme._key)), - set: (name: ThemeName) => storage.set(preferences.theme._key, name), + set: (name: ThemeName) => { + storage.set(preferences.theme._key, name); + }, useThemePref: (): [ThemeName, (name: ThemeName) => void] => { const [theme, setTheme] = useMMKVString(preferences.theme._key); return [ @@ -31,8 +33,9 @@ export const preferences = { preferences.shellListViewMode._resolve( storage.getString(preferences.shellListViewMode._key), ), - set: (mode: ShellListViewMode) => - storage.set(preferences.shellListViewMode._key, mode), + set: (mode: ShellListViewMode) => { + storage.set(preferences.shellListViewMode._key, mode); + }, useShellListViewModePref: (): [ ShellListViewMode, diff --git a/apps/mobile/src/lib/query-fns.ts b/apps/mobile/src/lib/query-fns.ts index 76c164d..3378e7d 100644 --- a/apps/mobile/src/lib/query-fns.ts +++ b/apps/mobile/src/lib/query-fns.ts @@ -7,11 +7,7 @@ import { } from '@tanstack/react-query'; import { useRouter } from 'expo-router'; import { secretsManager, type InputConnectionDetails } from './secrets-manager'; -import { - listConnectionsWithShells as registryList, - registerSession, - type ShellWithConnection, -} from './ssh-registry'; +import { useSshStore, toSessionStatus, type SessionKey } from './ssh-store'; import { AbortSignalTimeout } from './utils'; export const useSshConnMutation = () => { @@ -44,22 +40,26 @@ export const useSshConnMutation = () => { details: connectionDetails, priority: 0, }); + // Capture status events to Zustand after session is known. + let keyRef: SessionKey | null = null; const shellInterface = await sshConnection.startShell({ pty: 'Xterm', onStatusChange: (status) => { + if (keyRef) + useSshStore.getState().setStatus(keyRef, toSessionStatus(status)); console.log('SSH shell status', status); }, abortSignal: AbortSignalTimeout(5_000), }); - const channelId = shellInterface.channelId as number; - const connectionId = - sshConnection.connectionId ?? - `${sshConnection.connectionDetails.username}@${sshConnection.connectionDetails.host}:${sshConnection.connectionDetails.port}|${Math.floor(sshConnection.createdAtMs)}`; + const channelId = shellInterface.channelId; + const connectionId = `${sshConnection.connectionDetails.username}@${sshConnection.connectionDetails.host}:${sshConnection.connectionDetails.port}|${Math.floor(sshConnection.createdAtMs)}`; console.log('Connected to SSH server', connectionId, channelId); - // Track in registry for app use - registerSession(sshConnection, shellInterface); + // Track in Zustand store + keyRef = useSshStore + .getState() + .addSession(sshConnection, shellInterface); await queryClient.invalidateQueries({ queryKey: listSshShellsQueryOptions.queryKey, @@ -81,17 +81,29 @@ export const useSshConnMutation = () => { export const listSshShellsQueryOptions = queryOptions({ queryKey: ['ssh-shells'], - queryFn: () => registryList(), + queryFn: () => useSshStore.getState().listConnectionsWithShells(), }); -export type { ShellWithConnection }; +export type ShellWithConnection = (ReturnType< + typeof useSshStore.getState +>['listConnectionsWithShells'] extends () => infer R + ? R + : never)[number]['shells'][number] & { + connection: (ReturnType< + typeof useSshStore.getState + >['listConnectionsWithShells'] extends () => infer R + ? R + : never)[number]; +}; export const closeSshShellAndInvalidateQuery = async (params: { channelId: number; connectionId: string; queryClient: QueryClient; }) => { - const currentActiveShells = registryList(); + const currentActiveShells = useSshStore + .getState() + .listConnectionsWithShells(); const connection = currentActiveShells.find( (c) => c.connectionId === params.connectionId, ); @@ -108,7 +120,9 @@ export const disconnectSshConnectionAndInvalidateQuery = async (params: { connectionId: string; queryClient: QueryClient; }) => { - const currentActiveShells = registryList(); + const currentActiveShells = useSshStore + .getState() + .listConnectionsWithShells(); const connection = currentActiveShells.find( (c) => c.connectionId === params.connectionId, ); diff --git a/apps/mobile/src/lib/secrets-manager.ts b/apps/mobile/src/lib/secrets-manager.ts index 0fd766f..bf7091d 100644 --- a/apps/mobile/src/lib/secrets-manager.ts +++ b/apps/mobile/src/lib/secrets-manager.ts @@ -79,7 +79,7 @@ function makeBetterSecureStore< log( `Root manifest for ${rootManifestKey} is ${rawRootManifestString?.length ?? 0} bytes`, ); - const unsafedRootManifest = rawRootManifestString + const unsafedRootManifest: unknown = rawRootManifestString ? JSON.parse(rawRootManifestString) : { manifestVersion: rootManifestVersion, @@ -95,9 +95,11 @@ function makeBetterSecureStore< if (!rawManifestChunkString) throw new Error('Manifest chunk not found'); log( - `Manifest chunk for ${manifestChunkKeyString} is ${rawManifestChunkString?.length} bytes`, + `Manifest chunk for ${manifestChunkKeyString} is ${rawManifestChunkString.length} bytes`, + ); + const unsafedManifestChunk: unknown = JSON.parse( + rawManifestChunkString, ); - const unsafedManifestChunk = JSON.parse(rawManifestChunkString); return { manifestChunk: manifestChunkSchema.parse(unsafedManifestChunk), manifestChunkId, @@ -316,7 +318,7 @@ const keyMetadataSchema = z.object({ }); export type KeyMetadata = z.infer; -const betterKeyStorage = makeBetterSecureStore({ +const betterKeyStorage = makeBetterSecureStore({ storagePrefix: 'privateKey', extraManifestFieldsSchema: keyMetadataSchema, parseValue: (value) => value, diff --git a/apps/mobile/src/lib/ssh-registry.ts b/apps/mobile/src/lib/ssh-registry.ts deleted file mode 100644 index ec3f6b2..0000000 --- a/apps/mobile/src/lib/ssh-registry.ts +++ /dev/null @@ -1,108 +0,0 @@ -import { - RnRussh, - type SshConnection, - type SshShell, -} from '@fressh/react-native-uniffi-russh'; - -// Simple in-memory registry owned by JS to track active handles. -// Keyed by `${connectionId}:${channelId}`. - -export type SessionKey = string; - -export type StoredSession = { - connection: SshConnection; - shell: SshShell; -}; - -const sessions = new Map(); - -export function makeSessionKey( - connectionId: string, - channelId: number, -): SessionKey { - return `${connectionId}:${channelId}`; -} - -export function registerSession( - connection: SshConnection, - shell: SshShell, -): SessionKey { - const key = makeSessionKey(connection.connectionId, shell.channelId); - sessions.set(key, { connection, shell }); - return key; -} - -export function getSession( - connectionId: string, - channelId: number, -): StoredSession | undefined { - return sessions.get(makeSessionKey(connectionId, channelId)); -} - -export function removeSession(connectionId: string, channelId: number): void { - sessions.delete(makeSessionKey(connectionId, channelId)); -} - -export function listSessions(): StoredSession[] { - return Array.from(sessions.values()); -} - -// Legacy list view expected shape -export type ShellWithConnection = StoredSession['shell'] & { - connection: SshConnection; -}; - -export function listConnectionsWithShells(): (SshConnection & { - shells: StoredSession['shell'][]; -})[] { - // Group shells by connection - const byConn = new Map(); - for (const { connection, shell } of sessions.values()) { - const g = byConn.get(connection.connectionId) ?? { - conn: connection, - shells: [], - }; - g.shells.push(shell); - byConn.set(connection.connectionId, g); - } - return Array.from(byConn.values()).map(({ conn, shells }) => ({ - ...conn, - shells, - })); -} - -// Convenience helpers for flows -export async function connectAndStart( - details: Parameters[0], -) { - const conn = await RnRussh.connect(details); - const shell = await conn.startShell({ pty: 'Xterm' }); - registerSession(conn, shell); - return { conn, shell }; -} - -export async function closeShell(connectionId: string, channelId: number) { - const sess = getSession(connectionId, channelId); - if (!sess) return; - await sess.shell.close(); - removeSession(connectionId, channelId); -} - -export async function disconnectConnection(connectionId: string) { - const remaining = Array.from(sessions.entries()).filter( - ([, v]) => v.connection.connectionId === connectionId, - ); - for (const [key, sess] of remaining) { - try { - await sess.shell.close(); - } catch {} - sessions.delete(key); - } - // Find one connection handle for this id to disconnect - const conn = remaining[0]?.[1].connection; - if (conn) { - try { - await conn.disconnect(); - } catch {} - } -} diff --git a/apps/mobile/src/lib/ssh-store.ts b/apps/mobile/src/lib/ssh-store.ts new file mode 100644 index 0000000..2c55e35 --- /dev/null +++ b/apps/mobile/src/lib/ssh-store.ts @@ -0,0 +1,86 @@ +import { + type SshConnection, + type SshShell, + type SshConnectionStatus, +} from '@fressh/react-native-uniffi-russh'; +import { create } from 'zustand'; + +export type SessionKey = string; +export const makeSessionKey = (connectionId: string, channelId: number) => + `${connectionId}:${channelId}` as const; + +export type SessionStatus = 'connecting' | 'connected' | 'disconnected'; + +export interface StoredSession { + connection: SshConnection; + shell: SshShell; + status: SessionStatus; +} + +interface SshStoreState { + sessions: Record; + addSession: (conn: SshConnection, shell: SshShell) => SessionKey; + removeSession: (key: SessionKey) => void; + setStatus: (key: SessionKey, status: SessionStatus) => void; + getByKey: (key: SessionKey) => StoredSession | undefined; + listConnectionsWithShells: () => (SshConnection & { shells: SshShell[] })[]; +} + +export const useSshStore = create((set, get) => ({ + sessions: {}, + addSession: (conn, shell) => { + const key = makeSessionKey(conn.connectionId, shell.channelId); + set((s) => ({ + sessions: { + ...s.sessions, + [key]: { connection: conn, shell, status: 'connected' }, + }, + })); + return key; + }, + removeSession: (key) => { + set((s) => { + const { [key]: _omit, ...rest } = s.sessions; + return { sessions: rest }; + }); + }, + setStatus: (key, status) => { + set((s) => + s.sessions[key] + ? { sessions: { ...s.sessions, [key]: { ...s.sessions[key], status } } } + : s, + ); + }, + getByKey: (key) => get().sessions[key], + listConnectionsWithShells: () => { + const byConn = new Map< + string, + { conn: SshConnection; shells: SshShell[] } + >(); + for (const { connection, shell } of Object.values(get().sessions)) { + const g = byConn.get(connection.connectionId) ?? { + conn: connection, + shells: [], + }; + g.shells.push(shell); + byConn.set(connection.connectionId, g); + } + return Array.from(byConn.values()).map(({ conn, shells }) => ({ + ...conn, + shells, + })); + }, +})); + +export function toSessionStatus(status: SshConnectionStatus): SessionStatus { + switch (status) { + case 'shellConnecting': + return 'connecting'; + case 'shellConnected': + return 'connected'; + case 'shellDisconnected': + return 'disconnected'; + default: + return 'connected'; + } +} diff --git a/apps/mobile/src/lib/theme.tsx b/apps/mobile/src/lib/theme.tsx index 68a381c..6183ea9 100644 --- a/apps/mobile/src/lib/theme.tsx +++ b/apps/mobile/src/lib/theme.tsx @@ -1,7 +1,7 @@ import React from 'react'; import { preferences } from './preferences'; -export type AppTheme = { +export interface AppTheme { colors: { background: string; surface: string; @@ -20,7 +20,7 @@ export type AppTheme = { shadow: string; primaryDisabled: string; }; -}; +} export const darkTheme: AppTheme = { colors: { @@ -70,11 +70,11 @@ export const themes: Record = { light: lightTheme, }; -type ThemeContextValue = { +interface ThemeContextValue { theme: AppTheme; themeName: ThemeName; setThemeName: (name: ThemeName) => void; -}; +} const ThemeContext = React.createContext( undefined, @@ -93,21 +93,17 @@ export function ThemeProvider(props: { children: React.ReactNode }) { [theme, themeName, setThemeName], ); - return ( - - {props.children} - - ); + return {props.children}; } export function useTheme() { - const ctx = React.useContext(ThemeContext); + const ctx = React.use(ThemeContext); if (!ctx) throw new Error('useTheme must be used within ThemeProvider'); return ctx.theme; } export function useThemeControls() { - const ctx = React.useContext(ThemeContext); + const ctx = React.use(ThemeContext); if (!ctx) throw new Error('useThemeControls must be used within ThemeProvider'); const { themeName, setThemeName } = ctx; diff --git a/apps/mobile/src/lib/utils.ts b/apps/mobile/src/lib/utils.ts index 0523bd4..f7c4af6 100644 --- a/apps/mobile/src/lib/utils.ts +++ b/apps/mobile/src/lib/utils.ts @@ -8,6 +8,8 @@ export const AbortSignalTimeout = (timeout: number) => { // AbortSignal.timeout is not available as of expo 54 // TypeError: AbortSignal.timeout is not a function (it is undefined) const controller = new AbortController(); - setTimeout(() => controller.abort(), timeout); + setTimeout(() => { + controller.abort(); + }, timeout); return controller.signal; }; diff --git a/packages/react-native-xtermjs-webview/index.html b/packages/react-native-xtermjs-webview/index.html index 3cfee5a..b809e5c 100644 --- a/packages/react-native-xtermjs-webview/index.html +++ b/packages/react-native-xtermjs-webview/index.html @@ -1,5 +1,5 @@ - + - +
=6.9.0'} + deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-private-methods instead. + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2': resolution: {integrity: sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==} engines: {node: '>=6.9.0'} @@ -1348,6 +1388,12 @@ packages: cpu: [x64] os: [win32] + '@eslint-community/eslint-plugin-eslint-comments@4.5.0': + resolution: {integrity: sha512-MAhuTKlr4y/CE3WYX26raZjy+I/kS2PLKSzvfmDCGrBLTFHOYwqROZdr4XwPgXwX3K9rjzMr4pSmUWGnzsUyMg==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0 + '@eslint-community/eslint-utils@4.9.0': resolution: {integrity: sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -1358,6 +1404,40 @@ packages: resolution: {integrity: sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + '@eslint-react/ast@1.53.1': + resolution: {integrity: sha512-qvUC99ewtriJp9quVEOvZ6+RHcsMLfVQ0OhZ4/LupZUDhjW7GiX1dxJsFaxHdJ9rLNLhQyLSPmbAToeqUrSruQ==} + engines: {node: '>=18.18.0'} + + '@eslint-react/core@1.53.1': + resolution: {integrity: sha512-8prroos5/Uvvh8Tjl1HHCpq4HWD3hV9tYkm7uXgKA6kqj0jHlgRcQzuO6ZPP7feBcK3uOeug7xrq03BuG8QKCA==} + engines: {node: '>=18.18.0'} + + '@eslint-react/eff@1.53.1': + resolution: {integrity: sha512-uq20lPRAmsWRjIZm+mAV/2kZsU2nDqn5IJslxGWe3Vfdw23hoyhEw3S1KKlxbftwbTvsZjKvVP0iw3bZo/NUpg==} + engines: {node: '>=18.18.0'} + + '@eslint-react/eslint-plugin@1.53.1': + resolution: {integrity: sha512-JZ2ciXNCC9CtBBAqYtwWH+Jy/7ZzLw+whei8atP4Fxsbh+Scs30MfEwBzuiEbNw6uF9eZFfPidchpr5RaEhqxg==} + engines: {node: '>=18.18.0'} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: ^4.9.5 || ^5.3.3 + peerDependenciesMeta: + typescript: + optional: true + + '@eslint-react/kit@1.53.1': + resolution: {integrity: sha512-zOi2le9V4rMrJvQV4OeedGvMGvDT46OyFPOwXKs7m0tQu5vXVJ8qwIPaVQT1n/WIuvOg49OfmAVaHpGxK++xLQ==} + engines: {node: '>=18.18.0'} + + '@eslint-react/shared@1.53.1': + resolution: {integrity: sha512-gomJQmFqQgQVI3Ra4vTMG/s6a4bx3JqeNiTBjxBJt4C9iGaBj458GkP4LJHX7TM6xUzX+fMSKOPX7eV3C/+UCw==} + engines: {node: '>=18.18.0'} + + '@eslint-react/var@1.53.1': + resolution: {integrity: sha512-yzwopvPntcHU7mmDvWzRo1fb8QhjD8eDRRohD11rTV1u7nWO4QbJi0pOyugQakvte1/W11Y0Vr8Of0Ojk/A6zg==} + engines: {node: '>=18.18.0'} + '@eslint/compat@1.3.2': resolution: {integrity: sha512-jRNwzTbd6p2Rw4sZ1CgWRS8YMtqG15YyZf7zvb6gY2rB2u6n+2Z+ELW0GtL0fQgyl0pr4Y/BzBfng/BdsereRA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -2904,6 +2984,11 @@ packages: peerDependencies: vite: ^5.2.0 || ^6 + '@tanstack/eslint-plugin-query@5.89.0': + resolution: {integrity: sha512-vz8TEuw9GO0xXIdreMpcofvOY17T3cjgob9bSFln8yQsKsbsUvtpvV3F8pVC3tZEDq0IwO++3/e0/+7YKEarNA==} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + '@tanstack/form-core@1.20.0': resolution: {integrity: sha512-FGlKvcsusOf4756vtN1EoDI4h50r4/11eTcpF3NcnE04N/bSn2gP7cdhG6tYA0lJWzM9H1pNIzZ86uZ4MHB9eA==} @@ -3127,12 +3212,6 @@ packages: peerDependencies: typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/tsconfig-utils@8.43.0': - resolution: {integrity: sha512-ALC2prjZcj2YqqL5X/bwWQmHA2em6/94GcbB/KKu5SX3EBDOsqztmmX1kMkvAJHzxk7TazKzJfFiEIagNV3qEA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/tsconfig-utils@8.44.0': resolution: {integrity: sha512-x5Y0+AuEPqAInc6yd0n5DAcvtoQ/vyaGwuX5HE9n6qAefk1GaedqrLQF8kQGylLUb9pnZyLf+iEiL9fr8APDtQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -3840,6 +3919,9 @@ packages: bindings@1.5.0: resolution: {integrity: sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==} + birecord@0.1.1: + resolution: {integrity: sha512-VUpsf/qykW0heRlC8LooCq28Kxn3mAqKohhDG/49rrsQ1dT1CXyj/pgXS+5BSRzFTR/3DyIBOqQOrGyZOh71Aw==} + bl@4.1.0: resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} @@ -4848,12 +4930,58 @@ packages: peerDependencies: eslint: '>=8.40.0' + eslint-plugin-react-compiler@19.1.0-rc.2: + resolution: {integrity: sha512-oKalwDGcD+RX9mf3NEO4zOoUMeLvjSvcbbEOpquzmzqEEM2MQdp7/FY/Hx9NzmUwFzH1W9SKTz5fihfMldpEYw==} + engines: {node: ^14.17.0 || ^16.0.0 || >= 18.0.0} + peerDependencies: + eslint: '>=7' + + eslint-plugin-react-debug@1.53.1: + resolution: {integrity: sha512-WNOiQ6jhodJE88VjBU/IVDM+2Zr9gKHlBFDUSA3fQ0dMB5RiBVj5wMtxbxRuipK/GqNJbteqHcZoYEod7nfddg==} + engines: {node: '>=18.18.0'} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: ^4.9.5 || ^5.3.3 + peerDependenciesMeta: + typescript: + optional: true + + eslint-plugin-react-dom@1.53.1: + resolution: {integrity: sha512-UYrWJ2cS4HpJ1A5XBuf1HfMpPoLdfGil+27g/ldXfGemb4IXqlxHt4ANLyC8l2CWcE3SXGJW7mTslL34MG0qTQ==} + engines: {node: '>=18.18.0'} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: ^4.9.5 || ^5.3.3 + peerDependenciesMeta: + typescript: + optional: true + + eslint-plugin-react-hooks-extra@1.53.1: + resolution: {integrity: sha512-fshTnMWNn9NjFLIuy7HzkRgGK29vKv4ZBO9UMr+kltVAfKLMeXXP6021qVKk66i/XhQjbktiS+vQsu1Rd3ZKvg==} + engines: {node: '>=18.18.0'} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: ^4.9.5 || ^5.3.3 + peerDependenciesMeta: + typescript: + optional: true + eslint-plugin-react-hooks@5.2.0: resolution: {integrity: sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg==} engines: {node: '>=10'} peerDependencies: eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 + eslint-plugin-react-naming-convention@1.53.1: + resolution: {integrity: sha512-rvZ/B/CSVF8d34HQ4qIt90LRuxotVx+KUf3i1OMXAyhsagEFMRe4gAlPJiRufZ+h9lnuu279bEdd+NINsXOteA==} + engines: {node: '>=18.18.0'} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: ^4.9.5 || ^5.3.3 + peerDependenciesMeta: + typescript: + optional: true + eslint-plugin-react-native-globals@0.1.2: resolution: {integrity: sha512-9aEPf1JEpiTjcFAmmyw8eiIXmcNZOqaZyHO77wgm0/dWfT/oxC1SrIq8ET38pMxHYrcB6Uew+TzUVsBeczF88g==} @@ -4867,6 +4995,29 @@ packages: peerDependencies: eslint: '>=8.40' + eslint-plugin-react-web-api@1.53.1: + resolution: {integrity: sha512-INVZ3Cbl9/b+sizyb43ChzEPXXYuDsBGU9BIg7OVTNPyDPloCXdI+dQFAcSlDocZhPrLxhPV3eT6+gXbygzYXg==} + engines: {node: '>=18.18.0'} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: ^4.9.5 || ^5.3.3 + peerDependenciesMeta: + typescript: + optional: true + + eslint-plugin-react-x@1.53.1: + resolution: {integrity: sha512-MwMNnVwiPem0U6SlejDF/ddA4h/lmP6imL1RDZ2m3pUBrcdcOwOx0gyiRVTA3ENnhRlWfHljHf5y7m8qDSxMEg==} + engines: {node: '>=18.18.0'} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + ts-api-utils: ^2.1.0 + typescript: ^4.9.5 || ^5.3.3 + peerDependenciesMeta: + ts-api-utils: + optional: true + typescript: + optional: true + eslint-plugin-react@7.37.5: resolution: {integrity: sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==} engines: {node: '>=4'} @@ -5570,12 +5721,18 @@ packages: resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} hasBin: true + hermes-estree@0.25.1: + resolution: {integrity: sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==} + hermes-estree@0.28.1: resolution: {integrity: sha512-w3nxl/RGM7LBae0v8LH2o36+8VqwOZGv9rX1wyoWT6YaKZLqpJZ0YQ5P0LVr3tuRpf7vCx0iIG4i/VmBJejxTQ==} hermes-estree@0.29.1: resolution: {integrity: sha512-jl+x31n4/w+wEqm0I2r4CMimukLbLQEYpisys5oCre611CI5fc9TxhqkBBCJ1edDG4Kza0f7CgNz8xVMLZQOmQ==} + hermes-parser@0.25.1: + resolution: {integrity: sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==} + hermes-parser@0.28.1: resolution: {integrity: sha512-nf8o+hE8g7UJWParnccljHumE9Vlq8F7MqIdeahl+4x0tvCUJYRrT0L7h0MMg/X9YJmkNwsfbaNNrzPtFXOscg==} @@ -5824,6 +5981,12 @@ packages: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} engines: {node: '>=0.10.0'} + is-immutable-type@5.0.1: + resolution: {integrity: sha512-LkHEOGVZZXxGl8vDs+10k3DvP++SEoYEAJLRk6buTFi6kD7QekThV7xHS0j6gpnUCQ0zpud/gMDGiV4dQneLTg==} + peerDependencies: + eslint: '*' + typescript: '>=4.7.4' + is-inside-container@1.0.0: resolution: {integrity: sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==} engines: {node: '>=14.16'} @@ -8158,6 +8321,9 @@ packages: string-natural-compare@3.0.1: resolution: {integrity: sha512-n3sPwynL1nwKi3WJ6AIsClwBMa0zTi54fn2oLU6ndfTSIO05xaznjSf15PcBZU6FNWbmN5Q6cxT4V5hGvB4taw==} + string-ts@2.2.1: + resolution: {integrity: sha512-Q2u0gko67PLLhbte5HmPfdOjNvUKbKQM+mCNQae6jE91DmoFHY6HH9GcdqCeNx87DZ2KKjiFxmA0R/42OneGWw==} + string-width@4.2.3: resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} engines: {node: '>=8'} @@ -8386,9 +8552,17 @@ packages: peerDependencies: typescript: '>=4.8.4' + ts-declaration-location@1.0.7: + resolution: {integrity: sha512-EDyGAwH1gO0Ausm9gV6T2nUvBgXT5kGoCMJPllOaooZ+4VvJiKBdZE7wK18N1deEowhcUptS+5GXZK8U/fvpwA==} + peerDependencies: + typescript: '>=4.0.0' + ts-interface-checker@0.1.13: resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} + ts-pattern@5.8.0: + resolution: {integrity: sha512-kIjN2qmWiHnhgr5DAkAafF9fwb0T5OhMVSWrm8XEdTFnX6+wfXwYOFjeF86UZ54vduqiR7BfqScFmXSzSaH8oA==} + ts-toolbelt@9.6.0: resolution: {integrity: sha512-nsZd8ZeNUzukXPlJmTBwUAuABDe/9qtVDelJeT/qW0ow3ZS3BsQJtNkan1802aM9Uf68/Y8ljw86Hu0h5IUW3w==} @@ -9207,7 +9381,7 @@ snapshots: '@astrojs/telemetry@3.3.0': dependencies: ci-info: 4.3.0 - debug: 4.4.1 + debug: 4.4.3 dlv: 1.1.3 dset: 3.1.4 is-docker: 3.0.0 @@ -9259,12 +9433,12 @@ snapshots: '@babel/helper-compilation-targets': 7.27.2 '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.3) '@babel/helpers': 7.28.3 - '@babel/parser': 7.28.3 + '@babel/parser': 7.28.4 '@babel/template': 7.27.2 - '@babel/traverse': 7.28.3 - '@babel/types': 7.28.2 + '@babel/traverse': 7.28.4 + '@babel/types': 7.28.4 convert-source-map: 2.0.0 - debug: 4.4.1 + debug: 4.4.3 gensync: 1.0.0-beta.2 json5: 2.2.3 semver: 6.3.1 @@ -9281,7 +9455,7 @@ snapshots: '@babel/generator@7.28.3': dependencies: - '@babel/parser': 7.28.3 + '@babel/parser': 7.28.4 '@babel/types': 7.28.2 '@jridgewell/gen-mapping': 0.3.13 '@jridgewell/trace-mapping': 0.3.30 @@ -9334,8 +9508,8 @@ snapshots: '@babel/helper-member-expression-to-functions@7.27.1': dependencies: - '@babel/traverse': 7.28.3 - '@babel/types': 7.28.2 + '@babel/traverse': 7.28.4 + '@babel/types': 7.28.4 transitivePeerDependencies: - supports-color @@ -9357,7 +9531,7 @@ snapshots: '@babel/helper-optimise-call-expression@7.27.1': dependencies: - '@babel/types': 7.28.2 + '@babel/types': 7.28.4 '@babel/helper-plugin-utils@7.27.1': {} @@ -9395,7 +9569,7 @@ snapshots: '@babel/helper-wrap-function@7.28.3': dependencies: '@babel/template': 7.27.2 - '@babel/traverse': 7.28.3 + '@babel/traverse': 7.28.4 '@babel/types': 7.28.4 transitivePeerDependencies: - supports-color @@ -9403,7 +9577,7 @@ snapshots: '@babel/helpers@7.28.3': dependencies: '@babel/template': 7.27.2 - '@babel/types': 7.28.2 + '@babel/types': 7.28.4 '@babel/highlight@7.25.9': dependencies: @@ -9424,7 +9598,7 @@ snapshots: dependencies: '@babel/core': 7.28.3 '@babel/helper-plugin-utils': 7.27.1 - '@babel/traverse': 7.28.3 + '@babel/traverse': 7.28.4 transitivePeerDependencies: - supports-color @@ -9451,7 +9625,7 @@ snapshots: dependencies: '@babel/core': 7.28.3 '@babel/helper-plugin-utils': 7.27.1 - '@babel/traverse': 7.28.3 + '@babel/traverse': 7.28.4 transitivePeerDependencies: - supports-color @@ -9469,6 +9643,14 @@ snapshots: '@babel/core': 7.28.3 '@babel/helper-plugin-utils': 7.27.1 + '@babel/plugin-proposal-private-methods@7.18.6(@babel/core@7.28.3)': + dependencies: + '@babel/core': 7.28.3 + '@babel/helper-create-class-features-plugin': 7.28.3(@babel/core@7.28.3) + '@babel/helper-plugin-utils': 7.27.1 + transitivePeerDependencies: + - supports-color + '@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2(@babel/core@7.28.3)': dependencies: '@babel/core': 7.28.3 @@ -9769,7 +9951,7 @@ snapshots: '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.3) '@babel/helper-plugin-utils': 7.27.1 '@babel/helper-validator-identifier': 7.27.1 - '@babel/traverse': 7.28.3 + '@babel/traverse': 7.28.4 transitivePeerDependencies: - supports-color @@ -10075,7 +10257,7 @@ snapshots: dependencies: '@babel/core': 7.28.3 '@babel/helper-plugin-utils': 7.27.1 - '@babel/types': 7.28.2 + '@babel/types': 7.28.4 esutils: 2.0.3 '@babel/preset-react@7.27.1(@babel/core@7.28.3)': @@ -10106,7 +10288,7 @@ snapshots: '@babel/template@7.27.2': dependencies: '@babel/code-frame': 7.27.1 - '@babel/parser': 7.28.3 + '@babel/parser': 7.28.4 '@babel/types': 7.28.2 '@babel/traverse@7.28.3': @@ -10114,10 +10296,10 @@ snapshots: '@babel/code-frame': 7.27.1 '@babel/generator': 7.28.3 '@babel/helper-globals': 7.28.0 - '@babel/parser': 7.28.3 + '@babel/parser': 7.28.4 '@babel/template': 7.27.2 '@babel/types': 7.28.2 - debug: 4.4.1 + debug: 4.4.3 transitivePeerDependencies: - supports-color @@ -10306,6 +10488,12 @@ snapshots: '@esbuild/win32-x64@0.25.9': optional: true + '@eslint-community/eslint-plugin-eslint-comments@4.5.0(eslint@9.35.0(jiti@2.5.1))': + dependencies: + escape-string-regexp: 4.0.0 + eslint: 9.35.0(jiti@2.5.1) + ignore: 5.3.2 + '@eslint-community/eslint-utils@4.9.0(eslint@9.35.0(jiti@2.5.1))': dependencies: eslint: 9.35.0(jiti@2.5.1) @@ -10313,6 +10501,98 @@ snapshots: '@eslint-community/regexpp@4.12.1': {} + '@eslint-react/ast@1.53.1(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2)': + dependencies: + '@eslint-react/eff': 1.53.1 + '@typescript-eslint/types': 8.44.0 + '@typescript-eslint/typescript-estree': 8.44.0(typescript@5.9.2) + '@typescript-eslint/utils': 8.44.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2) + string-ts: 2.2.1 + ts-pattern: 5.8.0 + transitivePeerDependencies: + - eslint + - supports-color + - typescript + + '@eslint-react/core@1.53.1(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2)': + dependencies: + '@eslint-react/ast': 1.53.1(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2) + '@eslint-react/eff': 1.53.1 + '@eslint-react/kit': 1.53.1(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2) + '@eslint-react/shared': 1.53.1(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2) + '@eslint-react/var': 1.53.1(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2) + '@typescript-eslint/scope-manager': 8.44.0 + '@typescript-eslint/type-utils': 8.44.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2) + '@typescript-eslint/types': 8.44.0 + '@typescript-eslint/utils': 8.44.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2) + birecord: 0.1.1 + ts-pattern: 5.8.0 + transitivePeerDependencies: + - eslint + - supports-color + - typescript + + '@eslint-react/eff@1.53.1': {} + + '@eslint-react/eslint-plugin@1.53.1(eslint@9.35.0(jiti@2.5.1))(ts-api-utils@2.1.0(typescript@5.9.2))(typescript@5.9.2)': + dependencies: + '@eslint-react/eff': 1.53.1 + '@eslint-react/kit': 1.53.1(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2) + '@eslint-react/shared': 1.53.1(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2) + '@typescript-eslint/scope-manager': 8.44.0 + '@typescript-eslint/type-utils': 8.44.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2) + '@typescript-eslint/types': 8.44.0 + '@typescript-eslint/utils': 8.44.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2) + eslint: 9.35.0(jiti@2.5.1) + eslint-plugin-react-debug: 1.53.1(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2) + eslint-plugin-react-dom: 1.53.1(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2) + eslint-plugin-react-hooks-extra: 1.53.1(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2) + eslint-plugin-react-naming-convention: 1.53.1(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2) + eslint-plugin-react-web-api: 1.53.1(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2) + eslint-plugin-react-x: 1.53.1(eslint@9.35.0(jiti@2.5.1))(ts-api-utils@2.1.0(typescript@5.9.2))(typescript@5.9.2) + optionalDependencies: + typescript: 5.9.2 + transitivePeerDependencies: + - supports-color + - ts-api-utils + + '@eslint-react/kit@1.53.1(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2)': + dependencies: + '@eslint-react/eff': 1.53.1 + '@typescript-eslint/utils': 8.44.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2) + ts-pattern: 5.8.0 + zod: 4.1.9 + transitivePeerDependencies: + - eslint + - supports-color + - typescript + + '@eslint-react/shared@1.53.1(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2)': + dependencies: + '@eslint-react/eff': 1.53.1 + '@eslint-react/kit': 1.53.1(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2) + '@typescript-eslint/utils': 8.44.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2) + ts-pattern: 5.8.0 + zod: 4.1.9 + transitivePeerDependencies: + - eslint + - supports-color + - typescript + + '@eslint-react/var@1.53.1(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2)': + dependencies: + '@eslint-react/ast': 1.53.1(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2) + '@eslint-react/eff': 1.53.1 + '@typescript-eslint/scope-manager': 8.44.0 + '@typescript-eslint/types': 8.44.0 + '@typescript-eslint/utils': 8.44.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2) + string-ts: 2.2.1 + ts-pattern: 5.8.0 + transitivePeerDependencies: + - eslint + - supports-color + - typescript + '@eslint/compat@1.3.2(eslint@9.35.0(jiti@2.5.1))': optionalDependencies: eslint: 9.35.0(jiti@2.5.1) @@ -10682,7 +10962,7 @@ snapshots: '@expo/image-utils': 0.8.7 '@expo/json-file': 10.0.7 '@react-native/normalize-colors': 0.81.4 - debug: 4.4.1 + debug: 4.4.3 expo: 54.0.8(@babel/core@7.28.3)(@expo/metro-runtime@6.1.1)(expo-router@6.0.6)(react-native-webview@13.15.0(react-native@0.81.4(@babel/core@7.28.3)(@react-native-community/cli@20.0.2(typescript@5.9.2))(@types/react@19.1.12)(react@19.1.0))(react@19.1.0))(react-native@0.81.4(@babel/core@7.28.3)(@react-native-community/cli@20.0.2(typescript@5.9.2))(@types/react@19.1.12)(react@19.1.0))(react@19.1.0) resolve-from: 5.0.0 semver: 7.7.2 @@ -10697,7 +10977,7 @@ snapshots: '@expo/server@0.7.4': dependencies: abort-controller: 3.0.0 - debug: 4.4.1 + debug: 4.4.3 transitivePeerDependencies: - supports-color @@ -11830,7 +12110,7 @@ snapshots: '@react-native/babel-plugin-codegen@0.81.4(@babel/core@7.28.3)': dependencies: - '@babel/traverse': 7.28.3 + '@babel/traverse': 7.28.4 '@react-native/codegen': 0.81.4(@babel/core@7.28.3) transitivePeerDependencies: - '@babel/core' @@ -11939,7 +12219,7 @@ snapshots: '@react-native/codegen@0.81.1(@babel/core@7.28.3)': dependencies: '@babel/core': 7.28.3 - '@babel/parser': 7.28.3 + '@babel/parser': 7.28.4 glob: 7.2.3 hermes-parser: 0.29.1 invariant: 2.2.4 @@ -11959,7 +12239,7 @@ snapshots: '@react-native/community-cli-plugin@0.81.4(@react-native-community/cli@20.0.2(typescript@5.9.2))': dependencies: '@react-native/dev-middleware': 0.81.4 - debug: 4.4.1 + debug: 4.4.3 invariant: 2.2.4 metro: 0.83.1 metro-config: 0.83.1 @@ -11981,7 +12261,7 @@ snapshots: chrome-launcher: 0.15.2 chromium-edge-launcher: 0.2.0 connect: 3.7.0 - debug: 4.4.1 + debug: 4.4.3 invariant: 2.2.4 nullthrows: 1.1.1 open: 7.4.2 @@ -12355,6 +12635,14 @@ snapshots: tailwindcss: 4.1.9 vite: 6.3.6(@types/node@24.3.0)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(tsx@4.20.5)(yaml@2.8.1) + '@tanstack/eslint-plugin-query@5.89.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2)': + dependencies: + '@typescript-eslint/utils': 8.44.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2) + eslint: 9.35.0(jiti@2.5.1) + transitivePeerDependencies: + - supports-color + - typescript + '@tanstack/form-core@1.20.0': dependencies: '@tanstack/store': 0.7.4 @@ -12398,7 +12686,7 @@ snapshots: '@types/babel__core@7.20.5': dependencies: - '@babel/parser': 7.28.3 + '@babel/parser': 7.28.4 '@babel/types': 7.28.2 '@types/babel__generator': 7.27.0 '@types/babel__template': 7.4.4 @@ -12406,16 +12694,16 @@ snapshots: '@types/babel__generator@7.27.0': dependencies: - '@babel/types': 7.28.2 + '@babel/types': 7.28.4 '@types/babel__template@7.4.4': dependencies: - '@babel/parser': 7.28.3 - '@babel/types': 7.28.2 + '@babel/parser': 7.28.4 + '@babel/types': 7.28.4 '@types/babel__traverse@7.28.0': dependencies: - '@babel/types': 7.28.2 + '@babel/types': 7.28.4 '@types/debug@4.1.12': dependencies: @@ -12533,6 +12821,23 @@ snapshots: transitivePeerDependencies: - supports-color + '@typescript-eslint/eslint-plugin@8.41.0(@typescript-eslint/parser@8.44.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2)': + dependencies: + '@eslint-community/regexpp': 4.12.1 + '@typescript-eslint/parser': 8.44.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2) + '@typescript-eslint/scope-manager': 8.41.0 + '@typescript-eslint/type-utils': 8.41.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2) + '@typescript-eslint/utils': 8.41.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2) + '@typescript-eslint/visitor-keys': 8.41.0 + eslint: 9.35.0(jiti@2.5.1) + graphemer: 1.4.0 + ignore: 7.0.5 + natural-compare: 1.4.0 + ts-api-utils: 2.1.0(typescript@5.9.2) + typescript: 5.9.2 + transitivePeerDependencies: + - supports-color + '@typescript-eslint/eslint-plugin@8.44.0(@typescript-eslint/parser@8.44.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2)': dependencies: '@eslint-community/regexpp': 4.12.1 @@ -12556,7 +12861,7 @@ snapshots: '@typescript-eslint/types': 7.18.0 '@typescript-eslint/typescript-estree': 7.18.0(typescript@5.9.2) '@typescript-eslint/visitor-keys': 7.18.0 - debug: 4.4.1 + debug: 4.4.3 eslint: 9.35.0(jiti@2.5.1) optionalDependencies: typescript: 5.9.2 @@ -12569,7 +12874,7 @@ snapshots: '@typescript-eslint/types': 8.41.0 '@typescript-eslint/typescript-estree': 8.41.0(typescript@5.9.2) '@typescript-eslint/visitor-keys': 8.41.0 - debug: 4.4.1 + debug: 4.4.3 eslint: 9.35.0(jiti@2.5.1) typescript: 5.9.2 transitivePeerDependencies: @@ -12581,7 +12886,7 @@ snapshots: '@typescript-eslint/types': 8.44.0 '@typescript-eslint/typescript-estree': 8.44.0(typescript@5.9.2) '@typescript-eslint/visitor-keys': 8.44.0 - debug: 4.4.1 + debug: 4.4.3 eslint: 9.35.0(jiti@2.5.1) typescript: 5.9.2 transitivePeerDependencies: @@ -12589,8 +12894,8 @@ snapshots: '@typescript-eslint/project-service@8.41.0(typescript@5.9.2)': dependencies: - '@typescript-eslint/tsconfig-utils': 8.43.0(typescript@5.9.2) - '@typescript-eslint/types': 8.43.0 + '@typescript-eslint/tsconfig-utils': 8.44.0(typescript@5.9.2) + '@typescript-eslint/types': 8.44.0 debug: 4.4.3 typescript: 5.9.2 transitivePeerDependencies: @@ -12634,10 +12939,6 @@ snapshots: dependencies: typescript: 5.9.2 - '@typescript-eslint/tsconfig-utils@8.43.0(typescript@5.9.2)': - dependencies: - typescript: 5.9.2 - '@typescript-eslint/tsconfig-utils@8.44.0(typescript@5.9.2)': dependencies: typescript: 5.9.2 @@ -12723,7 +13024,7 @@ snapshots: '@typescript-eslint/tsconfig-utils': 8.41.0(typescript@5.9.2) '@typescript-eslint/types': 8.41.0 '@typescript-eslint/visitor-keys': 8.41.0 - debug: 4.4.1 + debug: 4.4.3 fast-glob: 3.3.3 is-glob: 4.0.3 minimatch: 9.0.5 @@ -12739,7 +13040,7 @@ snapshots: '@typescript-eslint/tsconfig-utils': 8.44.0(typescript@5.9.2) '@typescript-eslint/types': 8.44.0 '@typescript-eslint/visitor-keys': 8.44.0 - debug: 4.4.1 + debug: 4.4.3 fast-glob: 3.3.3 is-glob: 4.0.3 minimatch: 9.0.5 @@ -12949,7 +13250,7 @@ snapshots: '@vitest/eslint-plugin@1.3.6(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2)': dependencies: '@typescript-eslint/scope-manager': 8.43.0 - '@typescript-eslint/utils': 8.41.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2) + '@typescript-eslint/utils': 8.44.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2) eslint: 9.35.0(jiti@2.5.1) optionalDependencies: typescript: 5.9.2 @@ -13226,10 +13527,10 @@ snapshots: astro-eslint-parser@1.2.2: dependencies: '@astrojs/compiler': 2.12.2 - '@typescript-eslint/scope-manager': 8.41.0 - '@typescript-eslint/types': 8.41.0 + '@typescript-eslint/scope-manager': 8.44.0 + '@typescript-eslint/types': 8.44.0 astrojs-compiler-sync: 1.1.1(@astrojs/compiler@2.12.2) - debug: 4.4.1 + debug: 4.4.3 entities: 6.0.1 eslint-scope: 8.4.0 eslint-visitor-keys: 4.2.1 @@ -13414,7 +13715,7 @@ snapshots: babel-plugin-jest-hoist@29.6.3: dependencies: '@babel/template': 7.27.2 - '@babel/types': 7.28.2 + '@babel/types': 7.28.4 '@types/babel__core': 7.20.5 '@types/babel__traverse': 7.28.0 @@ -13557,6 +13858,8 @@ snapshots: dependencies: file-uri-to-path: 1.0.0 + birecord@0.1.1: {} + bl@4.1.0: dependencies: buffer: 5.7.1 @@ -14490,15 +14793,15 @@ snapshots: eslint-config-expo@10.0.0(eslint-plugin-import-x@4.16.1(@typescript-eslint/utils@8.44.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint@9.35.0(jiti@2.5.1)))(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2): dependencies: - '@typescript-eslint/eslint-plugin': 8.41.0(@typescript-eslint/parser@8.41.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2) - '@typescript-eslint/parser': 8.41.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2) + '@typescript-eslint/eslint-plugin': 8.41.0(@typescript-eslint/parser@8.44.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2) + '@typescript-eslint/parser': 8.44.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2) eslint: 9.35.0(jiti@2.5.1) - eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import-x@4.16.1(@typescript-eslint/utils@8.44.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint@9.35.0(jiti@2.5.1)))(eslint-plugin-import@2.32.0)(eslint@9.35.0(jiti@2.5.1)) + eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import-x@4.16.1(@typescript-eslint/utils@8.44.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint@9.35.0(jiti@2.5.1)))(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.44.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.35.0(jiti@2.5.1)))(eslint@9.35.0(jiti@2.5.1)) eslint-plugin-expo: 1.0.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2) - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.41.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1)(eslint@9.35.0(jiti@2.5.1)) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.44.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1)(eslint@9.35.0(jiti@2.5.1)) eslint-plugin-react: 7.37.5(eslint@9.35.0(jiti@2.5.1)) eslint-plugin-react-hooks: 5.2.0(eslint@9.35.0(jiti@2.5.1)) - globals: 16.3.0 + globals: 16.4.0 transitivePeerDependencies: - eslint-import-resolver-webpack - eslint-plugin-import-x @@ -14524,7 +14827,7 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-import-resolver-typescript@3.10.1(eslint-plugin-import-x@4.16.1(@typescript-eslint/utils@8.44.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint@9.35.0(jiti@2.5.1)))(eslint-plugin-import@2.32.0)(eslint@9.35.0(jiti@2.5.1)): + eslint-import-resolver-typescript@3.10.1(eslint-plugin-import-x@4.16.1(@typescript-eslint/utils@8.44.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint@9.35.0(jiti@2.5.1)))(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.44.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.35.0(jiti@2.5.1)))(eslint@9.35.0(jiti@2.5.1)): dependencies: '@nolyfill/is-core-module': 1.0.39 debug: 4.4.1 @@ -14535,19 +14838,19 @@ snapshots: tinyglobby: 0.2.14 unrs-resolver: 1.11.1 optionalDependencies: - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.41.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1)(eslint@9.35.0(jiti@2.5.1)) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.44.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1)(eslint@9.35.0(jiti@2.5.1)) eslint-plugin-import-x: 4.16.1(@typescript-eslint/utils@8.44.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint@9.35.0(jiti@2.5.1)) transitivePeerDependencies: - supports-color - eslint-module-utils@2.12.1(@typescript-eslint/parser@8.41.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.35.0(jiti@2.5.1)): + eslint-module-utils@2.12.1(@typescript-eslint/parser@8.44.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.35.0(jiti@2.5.1)): dependencies: debug: 3.2.7 optionalDependencies: - '@typescript-eslint/parser': 8.41.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2) + '@typescript-eslint/parser': 8.44.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2) eslint: 9.35.0(jiti@2.5.1) eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import-x@4.16.1(@typescript-eslint/utils@8.44.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint@9.35.0(jiti@2.5.1)))(eslint-plugin-import@2.32.0)(eslint@9.35.0(jiti@2.5.1)) + eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import-x@4.16.1(@typescript-eslint/utils@8.44.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint@9.35.0(jiti@2.5.1)))(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.44.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.35.0(jiti@2.5.1)))(eslint@9.35.0(jiti@2.5.1)) transitivePeerDependencies: - supports-color @@ -14574,7 +14877,7 @@ snapshots: eslint-plugin-expo@1.0.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2): dependencies: '@typescript-eslint/types': 8.41.0 - '@typescript-eslint/utils': 8.41.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2) + '@typescript-eslint/utils': 8.44.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2) eslint: 9.35.0(jiti@2.5.1) transitivePeerDependencies: - supports-color @@ -14605,7 +14908,7 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.41.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1)(eslint@9.35.0(jiti@2.5.1)): + eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.44.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1)(eslint@9.35.0(jiti@2.5.1)): dependencies: '@rtsao/scc': 1.1.0 array-includes: 3.1.9 @@ -14616,7 +14919,7 @@ snapshots: doctrine: 2.1.0 eslint: 9.35.0(jiti@2.5.1) eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.41.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.35.0(jiti@2.5.1)) + eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.44.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.35.0(jiti@2.5.1)) hasown: 2.0.2 is-core-module: 2.16.1 is-glob: 4.0.3 @@ -14628,7 +14931,7 @@ snapshots: string.prototype.trimend: 1.0.9 tsconfig-paths: 3.15.0 optionalDependencies: - '@typescript-eslint/parser': 8.41.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2) + '@typescript-eslint/parser': 8.44.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2) transitivePeerDependencies: - eslint-import-resolver-typescript - eslint-import-resolver-webpack @@ -14675,10 +14978,102 @@ snapshots: eslint: 9.35.0(jiti@2.5.1) globals: 13.24.0 + eslint-plugin-react-compiler@19.1.0-rc.2(eslint@9.35.0(jiti@2.5.1)): + dependencies: + '@babel/core': 7.28.3 + '@babel/parser': 7.28.4 + '@babel/plugin-proposal-private-methods': 7.18.6(@babel/core@7.28.3) + eslint: 9.35.0(jiti@2.5.1) + hermes-parser: 0.25.1 + zod: 3.25.76 + zod-validation-error: 3.5.3(zod@3.25.76) + transitivePeerDependencies: + - supports-color + + eslint-plugin-react-debug@1.53.1(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2): + dependencies: + '@eslint-react/ast': 1.53.1(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2) + '@eslint-react/core': 1.53.1(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2) + '@eslint-react/eff': 1.53.1 + '@eslint-react/kit': 1.53.1(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2) + '@eslint-react/shared': 1.53.1(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2) + '@eslint-react/var': 1.53.1(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2) + '@typescript-eslint/scope-manager': 8.44.0 + '@typescript-eslint/type-utils': 8.44.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2) + '@typescript-eslint/types': 8.44.0 + '@typescript-eslint/utils': 8.44.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2) + eslint: 9.35.0(jiti@2.5.1) + string-ts: 2.2.1 + ts-pattern: 5.8.0 + optionalDependencies: + typescript: 5.9.2 + transitivePeerDependencies: + - supports-color + + eslint-plugin-react-dom@1.53.1(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2): + dependencies: + '@eslint-react/ast': 1.53.1(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2) + '@eslint-react/core': 1.53.1(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2) + '@eslint-react/eff': 1.53.1 + '@eslint-react/kit': 1.53.1(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2) + '@eslint-react/shared': 1.53.1(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2) + '@eslint-react/var': 1.53.1(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2) + '@typescript-eslint/scope-manager': 8.44.0 + '@typescript-eslint/types': 8.44.0 + '@typescript-eslint/utils': 8.44.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2) + compare-versions: 6.1.1 + eslint: 9.35.0(jiti@2.5.1) + string-ts: 2.2.1 + ts-pattern: 5.8.0 + optionalDependencies: + typescript: 5.9.2 + transitivePeerDependencies: + - supports-color + + eslint-plugin-react-hooks-extra@1.53.1(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2): + dependencies: + '@eslint-react/ast': 1.53.1(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2) + '@eslint-react/core': 1.53.1(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2) + '@eslint-react/eff': 1.53.1 + '@eslint-react/kit': 1.53.1(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2) + '@eslint-react/shared': 1.53.1(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2) + '@eslint-react/var': 1.53.1(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2) + '@typescript-eslint/scope-manager': 8.44.0 + '@typescript-eslint/type-utils': 8.44.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2) + '@typescript-eslint/types': 8.44.0 + '@typescript-eslint/utils': 8.44.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2) + eslint: 9.35.0(jiti@2.5.1) + string-ts: 2.2.1 + ts-pattern: 5.8.0 + optionalDependencies: + typescript: 5.9.2 + transitivePeerDependencies: + - supports-color + eslint-plugin-react-hooks@5.2.0(eslint@9.35.0(jiti@2.5.1)): dependencies: eslint: 9.35.0(jiti@2.5.1) + eslint-plugin-react-naming-convention@1.53.1(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2): + dependencies: + '@eslint-react/ast': 1.53.1(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2) + '@eslint-react/core': 1.53.1(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2) + '@eslint-react/eff': 1.53.1 + '@eslint-react/kit': 1.53.1(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2) + '@eslint-react/shared': 1.53.1(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2) + '@eslint-react/var': 1.53.1(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2) + '@typescript-eslint/scope-manager': 8.44.0 + '@typescript-eslint/type-utils': 8.44.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2) + '@typescript-eslint/types': 8.44.0 + '@typescript-eslint/utils': 8.44.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2) + eslint: 9.35.0(jiti@2.5.1) + string-ts: 2.2.1 + ts-pattern: 5.8.0 + optionalDependencies: + typescript: 5.9.2 + transitivePeerDependencies: + - supports-color + eslint-plugin-react-native-globals@0.1.2: {} eslint-plugin-react-native@4.1.0(eslint@9.35.0(jiti@2.5.1)): @@ -14690,6 +15085,48 @@ snapshots: dependencies: eslint: 9.35.0(jiti@2.5.1) + eslint-plugin-react-web-api@1.53.1(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2): + dependencies: + '@eslint-react/ast': 1.53.1(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2) + '@eslint-react/core': 1.53.1(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2) + '@eslint-react/eff': 1.53.1 + '@eslint-react/kit': 1.53.1(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2) + '@eslint-react/shared': 1.53.1(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2) + '@eslint-react/var': 1.53.1(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2) + '@typescript-eslint/scope-manager': 8.44.0 + '@typescript-eslint/types': 8.44.0 + '@typescript-eslint/utils': 8.44.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2) + eslint: 9.35.0(jiti@2.5.1) + string-ts: 2.2.1 + ts-pattern: 5.8.0 + optionalDependencies: + typescript: 5.9.2 + transitivePeerDependencies: + - supports-color + + eslint-plugin-react-x@1.53.1(eslint@9.35.0(jiti@2.5.1))(ts-api-utils@2.1.0(typescript@5.9.2))(typescript@5.9.2): + dependencies: + '@eslint-react/ast': 1.53.1(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2) + '@eslint-react/core': 1.53.1(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2) + '@eslint-react/eff': 1.53.1 + '@eslint-react/kit': 1.53.1(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2) + '@eslint-react/shared': 1.53.1(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2) + '@eslint-react/var': 1.53.1(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2) + '@typescript-eslint/scope-manager': 8.44.0 + '@typescript-eslint/type-utils': 8.44.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2) + '@typescript-eslint/types': 8.44.0 + '@typescript-eslint/utils': 8.44.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2) + compare-versions: 6.1.1 + eslint: 9.35.0(jiti@2.5.1) + is-immutable-type: 5.0.1(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2) + string-ts: 2.2.1 + ts-pattern: 5.8.0 + optionalDependencies: + ts-api-utils: 2.1.0(typescript@5.9.2) + typescript: 5.9.2 + transitivePeerDependencies: + - supports-color + eslint-plugin-react@7.37.5(eslint@9.35.0(jiti@2.5.1)): dependencies: array-includes: 3.1.9 @@ -14715,7 +15152,7 @@ snapshots: eslint-plugin-testing-library@7.6.6(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2): dependencies: '@typescript-eslint/scope-manager': 8.43.0 - '@typescript-eslint/utils': 8.41.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2) + '@typescript-eslint/utils': 8.44.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2) eslint: 9.35.0(jiti@2.5.1) transitivePeerDependencies: - supports-color @@ -15600,10 +16037,16 @@ snapshots: he@1.2.0: {} + hermes-estree@0.25.1: {} + hermes-estree@0.28.1: {} hermes-estree@0.29.1: {} + hermes-parser@0.25.1: + dependencies: + hermes-estree: 0.25.1 + hermes-parser@0.28.1: dependencies: hermes-estree: 0.28.1 @@ -15843,6 +16286,16 @@ snapshots: dependencies: is-extglob: 2.1.1 + is-immutable-type@5.0.1(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2): + dependencies: + '@typescript-eslint/type-utils': 8.44.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2) + eslint: 9.35.0(jiti@2.5.1) + ts-api-utils: 2.1.0(typescript@5.9.2) + ts-declaration-location: 1.0.7(typescript@5.9.2) + typescript: 5.9.2 + transitivePeerDependencies: + - supports-color + is-inside-container@1.0.0: dependencies: is-docker: 3.0.0 @@ -15966,7 +16419,7 @@ snapshots: istanbul-lib-instrument@5.2.1: dependencies: '@babel/core': 7.28.3 - '@babel/parser': 7.28.3 + '@babel/parser': 7.28.4 '@istanbuljs/schema': 0.1.3 istanbul-lib-coverage: 3.2.2 semver: 6.3.1 @@ -16305,7 +16758,7 @@ snapshots: '@babel/generator': 7.28.3 '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.28.3) '@babel/plugin-syntax-typescript': 7.27.1(@babel/core@7.28.3) - '@babel/types': 7.28.2 + '@babel/types': 7.28.4 '@jest/expect-utils': 30.1.2 '@jest/get-type': 30.1.0 '@jest/snapshot-utils': 30.1.2 @@ -16885,7 +17338,7 @@ snapshots: metro-file-map@0.83.1: dependencies: - debug: 4.4.1 + debug: 4.4.3 fb-watchman: 2.0.2 flow-enums-runtime: 0.0.6 graceful-fs: 4.2.11 @@ -16952,7 +17405,7 @@ snapshots: dependencies: '@babel/core': 7.28.3 '@babel/generator': 7.28.3 - '@babel/parser': 7.28.3 + '@babel/parser': 7.28.4 '@babel/types': 7.28.2 flow-enums-runtime: 0.0.6 metro: 0.83.1 @@ -16973,7 +17426,7 @@ snapshots: '@babel/code-frame': 7.27.1 '@babel/core': 7.28.3 '@babel/generator': 7.28.3 - '@babel/parser': 7.28.3 + '@babel/parser': 7.28.4 '@babel/template': 7.27.2 '@babel/traverse': 7.28.3 '@babel/types': 7.28.2 @@ -16981,7 +17434,7 @@ snapshots: chalk: 4.1.2 ci-info: 2.0.0 connect: 3.7.0 - debug: 4.4.1 + debug: 4.4.3 error-stack-parser: 2.1.4 flow-enums-runtime: 0.0.6 graceful-fs: 4.2.11 @@ -17868,7 +18321,7 @@ snapshots: proxy-agent@6.5.0: dependencies: agent-base: 7.1.4 - debug: 4.4.1 + debug: 4.4.3 http-proxy-agent: 7.0.2 https-proxy-agent: 7.0.6 lru-cache: 7.18.3 @@ -18885,6 +19338,8 @@ snapshots: string-natural-compare@3.0.1: {} + string-ts@2.2.1: {} + string-width@4.2.3: dependencies: emoji-regex: 8.0.0 @@ -19147,8 +19602,15 @@ snapshots: dependencies: typescript: 5.9.2 + ts-declaration-location@1.0.7(typescript@5.9.2): + dependencies: + picomatch: 4.0.3 + typescript: 5.9.2 + ts-interface-checker@0.1.13: {} + ts-pattern@5.8.0: {} + ts-toolbelt@9.6.0: {} tsconfck@3.1.6(typescript@5.9.2):