From 4cdd8cd4bf80d0f9e05ce58a6481e919832b16e6 Mon Sep 17 00:00:00 2001 From: EthanShoeDev <13422990+EthanShoeDev@users.noreply.github.com> Date: Sun, 14 Sep 2025 00:11:09 -0400 Subject: [PATCH] drop old ssh lib lint passing --- .jscpd.json | 3 +- apps/mobile/app.config.ts | 28 --- apps/mobile/package.json | 3 - apps/mobile/src/app/index.tsx | 67 +++--- apps/mobile/src/app/shell.tsx | 41 ++-- .../src/components/key-manager-modal.tsx | 2 +- apps/mobile/src/lib/secrets-manager.ts | 12 +- apps/mobile/src/lib/ssh-connection-manager.ts | 11 +- apps/mobile/src/lib/test-uniffi-russh.ts | 86 ------- pnpm-lock.yaml | 224 ------------------ 10 files changed, 64 insertions(+), 413 deletions(-) delete mode 100644 apps/mobile/src/lib/test-uniffi-russh.ts diff --git a/.jscpd.json b/.jscpd.json index 9c37b0b..ffee6ca 100644 --- a/.jscpd.json +++ b/.jscpd.json @@ -7,7 +7,8 @@ "**/dist/**", "**/node_modules/**", "**/android/**", - "**/generated/**" + "**/generated/**", + "**/rust/target/**" ], "threshold": 0, "minTokens": 50, diff --git a/apps/mobile/app.config.ts b/apps/mobile/app.config.ts index acd3f15..294a35c 100644 --- a/apps/mobile/app.config.ts +++ b/apps/mobile/app.config.ts @@ -46,34 +46,6 @@ const config: ExpoConfig = { 'expo-secure-store', 'expo-font', 'expo-dev-client', - 'expo-web-browser', - [ - 'expo-build-properties', - { - android: { - // dylankenneally/react-native-ssh-sftp fails to build without this - packagingOptions: { - pickFirst: ['META-INF/versions/9/OSGI-INF/MANIFEST.MF'], - }, - }, - ios: { - // https://github.com/dylankenneally/react-native-ssh-sftp/issues/20#issuecomment-3286693445 - // ../../docs/ios-sim-not-working.md (Update 1) - extraPods: [ - { - name: 'CSSH-Binary', - podspec: - 'https://gist.githubusercontent.com/EthanShoeDev/1ab212949007d7aeabfeb199b7b9e951/raw/8602ec55efdf8c620dbbae93cd54023e2a36a8b9/CSSH-Binary.podspec', - }, - { - name: 'NMSSH', - git: 'https://github.com/EthanShoeDev/NMSSH.git', - branch: 'master', - }, - ], - }, - }, - ], ], experiments: { typedRoutes: true, reactCompiler: true }, }; diff --git a/apps/mobile/package.json b/apps/mobile/package.json index f7c78fc..24c577e 100644 --- a/apps/mobile/package.json +++ b/apps/mobile/package.json @@ -25,7 +25,6 @@ "adb:logs": "while ! adb logcat --pid=$(adb shell pidof -s dev.fressh.app); do sleep 1; done" }, "dependencies": { - "@dylankenneally/react-native-ssh-sftp": "^1.5.20", "@expo/vector-icons": "^15.0.2", "@fressh/assets": "workspace:*", "@fressh/react-native-uniffi-russh": "workspace:*", @@ -37,7 +36,6 @@ "@tanstack/react-form": "^1.19.5", "@tanstack/react-query": "^5.87.1", "expo": "54.0.7", - "expo-build-properties": "~1.0.8", "expo-clipboard": "~8.0.7", "expo-constants": "~18.0.8", "expo-crypto": "~15.0.7", @@ -54,7 +52,6 @@ "expo-status-bar": "~3.0.8", "expo-symbols": "~1.0.7", "expo-system-ui": "~6.0.7", - "expo-web-browser": "~15.0.7", "react": "19.1.0", "react-dom": "19.1.0", "react-native": "0.81.4", diff --git a/apps/mobile/src/app/index.tsx b/apps/mobile/src/app/index.tsx index 74c4847..e22207f 100644 --- a/apps/mobile/src/app/index.tsx +++ b/apps/mobile/src/app/index.tsx @@ -1,4 +1,4 @@ -import SSHClient, { PtyType } from '@dylankenneally/react-native-ssh-sftp'; +import { connect, PtyType, Security } from '@fressh/react-native-uniffi-russh'; import SegmentedControl from '@react-native-segmented-control/segmented-control'; import { useStore } from '@tanstack/react-form'; import { useMutation, useQuery } from '@tanstack/react-query'; @@ -13,7 +13,6 @@ import { secretsManager, } from '../lib/secrets-manager'; import { sshConnectionManager } from '../lib/ssh-connection-manager'; -import '../lib/test-uniffi-russh'; const defaultValues: ConnectionDetails = { host: 'test.rebex.net', port: 22, @@ -28,52 +27,40 @@ const useSshConnMutation = () => { const router = useRouter(); return useMutation({ - mutationFn: async (value: ConnectionDetails) => { + mutationFn: async (connectionDetails: ConnectionDetails) => { try { console.log('Connecting to SSH server...'); - const effective = await (async () => { - if (value.security.type === 'password') return value; - if (value.security.keyId) return value; - const keys = await secretsManager.keys.utils.listEntriesWithValues(); - const def = keys.find((k) => k.metadata?.isDefault); - const pick = def ?? keys[0]; - if (pick) { - return { - ...value, - security: { type: 'key', keyId: pick.id }, - } as ConnectionDetails; - } - return value; - })(); - - const sshClientConnection = await (async () => { - if (effective.security.type === 'password') { - return await SSHClient.connectWithPassword( - effective.host, - effective.port, - effective.username, - effective.security.password, - ); - } - const privateKey = await secretsManager.keys.utils.getPrivateKey( - effective.security.keyId, - ); - return await SSHClient.connectWithKey( - effective.host, - effective.port, - effective.username, - privateKey.value, - ); - })(); + const sshConnection = await connect( + { + host: connectionDetails.host, + port: connectionDetails.port, + username: connectionDetails.username, + security: + connectionDetails.security.type === 'password' + ? new Security.Password({ + password: connectionDetails.security.password, + }) + : new Security.Key({ keyId: connectionDetails.security.keyId }), + }, + { + onStatusChange: (status) => { + console.log('SSH connection status', status); + }, + }, + ); await secretsManager.connections.utils.upsertConnection({ id: 'default', - details: effective, + details: connectionDetails, priority: 0, }); - await sshClientConnection.startShell(PtyType.XTERM); + await sshConnection.startShell(PtyType.Xterm, { + onStatusChange: (status) => { + console.log('SSH shell status', status); + }, + }); const sshConn = sshConnectionManager.addSession({ - client: sshClientConnection, + client: sshConnection, }); console.log('Connected to SSH server', sshConn.sessionId); router.push({ diff --git a/apps/mobile/src/app/shell.tsx b/apps/mobile/src/app/shell.tsx index 5c6b707..0e624f2 100644 --- a/apps/mobile/src/app/shell.tsx +++ b/apps/mobile/src/app/shell.tsx @@ -22,31 +22,34 @@ export default function Shell() { const [shellData, setShellData] = useState(''); useEffect(() => { - sshConn.client.on('Shell', (data) => { - console.log('Received data (on Shell):', data); - setShellData((prev) => prev + data); + // sshConn.client.on('Shell', (data) => { + // console.log('Received data (on Shell):', data); + // setShellData((prev) => prev + data); + // }); + sshConn.client.addChannelListener({ + onData: (data) => { + console.log('Received data (on Shell):', data); + setShellData((prev) => prev + data); + }, }); return () => { - // // Remove the handler by clearing the internal handler map. - // // The library lacks a public `.off()`, but it routes through a single - // // handler map per event name. Deleting the handler prevents updates. - // // eslint-disable-next-line @typescript-eslint/no-explicit-any - // delete (sshConn.client as any)._handlers?.Shell; - - // Set to no-op - sshConn.client.on('Shell', () => {}); + sshConn.client.removeChannelListener({ + onData: () => {}, + }); }; }, [setShellData, sshConn.client]); useEffect(() => { return () => { console.log('Clean up shell screen (immediate disconnect)'); - try { - sshConnectionManager.removeAndDisconnectSession({ sessionId }); - console.log('Disconnected from SSH server'); - } catch (error) { - console.error('Error disconnecting from SSH server', error); - } + void sshConnectionManager + .removeAndDisconnectSession({ sessionId }) + .then(() => { + console.log('Disconnected from SSH server'); + }) + .catch((e: unknown) => { + console.error('Error disconnecting from SSH server', e); + }); }; }, [sessionId]); @@ -74,7 +77,9 @@ export default function Shell() { { console.log('Executing command:', command); - await sshConn.client.writeToShell(command + '\n'); + await sshConn.client.sendData( + Uint8Array.from(new TextEncoder().encode(command + '\n')).buffer, + ); }} /> diff --git a/apps/mobile/src/components/key-manager-modal.tsx b/apps/mobile/src/components/key-manager-modal.tsx index a973d6d..e7c2b25 100644 --- a/apps/mobile/src/components/key-manager-modal.tsx +++ b/apps/mobile/src/components/key-manager-modal.tsx @@ -29,7 +29,7 @@ export function KeyManagerModal(props: { await secretsManager.keys.utils.upsertPrivateKey({ keyId: id, metadata: { priority: 0, label: 'New Key', isDefault: false }, - value: pair.privateKey, + value: pair, }); }, }); diff --git a/apps/mobile/src/lib/secrets-manager.ts b/apps/mobile/src/lib/secrets-manager.ts index 8d1a2f0..5964503 100644 --- a/apps/mobile/src/lib/secrets-manager.ts +++ b/apps/mobile/src/lib/secrets-manager.ts @@ -1,4 +1,4 @@ -import SSHClient from '@dylankenneally/react-native-ssh-sftp'; +import * as Russh from '@fressh/react-native-uniffi-russh'; import { queryOptions } from '@tanstack/react-query'; import * as Crypto from 'expo-crypto'; import * as SecureStore from 'expo-secure-store'; @@ -443,11 +443,11 @@ async function generateKeyPair(params: { keySize?: number; comment?: string; }) { - const keyPair = await SSHClient.generateKeyPair( - params.type, - params.passphrase ?? '', - params.keySize, - params.comment ?? '', + console.log('DEBUG: generating key pair', params); + const keyPair = await Russh.generateKeyPair( + Russh.KeyType.Ed25519, + // params.keySize, + // params.comment ?? '', ); return keyPair; } diff --git a/apps/mobile/src/lib/ssh-connection-manager.ts b/apps/mobile/src/lib/ssh-connection-manager.ts index f73fb79..e71d0cc 100644 --- a/apps/mobile/src/lib/ssh-connection-manager.ts +++ b/apps/mobile/src/lib/ssh-connection-manager.ts @@ -1,15 +1,14 @@ -import type SSHClient from '@dylankenneally/react-native-ssh-sftp'; +import { type SshConnectionInterface } from '@fressh/react-native-uniffi-russh'; import * as Crypto from 'expo-crypto'; - export type SSHConn = { - client: SSHClient; + client: SshConnectionInterface; sessionId: string; createdAt: Date; }; const sshConnections = new Map(); -function addSession(params: { client: SSHClient }) { +function addSession(params: { client: SshConnectionInterface }) { const sessionId = Crypto.randomUUID(); const createdAt = new Date(); const sshConn: SSHConn = { @@ -27,10 +26,10 @@ function getSession(params: { sessionId: string }) { return sshConn; } -function removeAndDisconnectSession(params: { sessionId: string }) { +async function removeAndDisconnectSession(params: { sessionId: string }) { const sshConn = getSession(params); // sshConn.client.closeShell() - sshConn.client.disconnect(); + await sshConn.client.disconnect(); sshConnections.delete(params.sessionId); } diff --git a/apps/mobile/src/lib/test-uniffi-russh.ts b/apps/mobile/src/lib/test-uniffi-russh.ts deleted file mode 100644 index 7d46980..0000000 --- a/apps/mobile/src/lib/test-uniffi-russh.ts +++ /dev/null @@ -1,86 +0,0 @@ -import { - generateKeyPair, - KeyType, - uniffiInitAsync, -} from '@fressh/react-native-uniffi-russh'; - -void uniffiInitAsync().then(() => { - void generateKeyPair(KeyType.Ed25519).then((keyPair) => { - console.log('testKeyPair', keyPair); - }); -}); - -// // https://jhugman.github.io/uniffi-bindgen-react-native/idioms/common-types.html -// // https://jhugman.github.io/uniffi-bindgen-react-native/idioms/callback-interfaces.html -// // https://jhugman.github.io/uniffi-bindgen-react-native/idioms/async-callbacks.html - -// const connectionDetailsSchema = z.object({ -// host: z.string().min(1), -// port: z.number().min(1), -// username: z.string().min(1), -// security: z.discriminatedUnion('type', [ -// z.object({ -// type: z.literal('password'), -// password: z.string().min(1), -// }), -// z.object({ -// type: z.literal('key'), -// keyId: z.string().min(1), -// }), -// ]), -// }); - -// The ideal interface - -// const connectionDetailsSchema = z.object({ -// host: z.string().min(1), -// port: z.number().min(1), -// username: z.string().min(1), -// // There is a section on tagged enums: https://jhugman.github.io/uniffi-bindgen-react-native/idioms/enums.html#enums-with-properties -// security: z.discriminatedUnion('type', [ -// z.object({ -// type: z.literal('password'), -// password: z.string().min(1), -// }), -// z.object({ -// type: z.literal('key'), -// keyId: z.string().min(1), -// }), -// ]), -// }); - -// type ConnectionDetails = z.infer; - -// type SSHConnectionStatus = -// | 'tcp-connecting' -// | 'tcp-connected' -// | 'tcp-disconnected' -// | 'shell-connecting' -// | 'shell-connected' -// | 'shell-disconnected'; - -// type SSHConnection = { -// connectionDetails: ConnectionDetails; -// sessionId: string; -// createdAtMs: number; -// establishedAtMs: number; -// // I am not sure this is the best way to do this within uniffi. -// addListener: (listener: (data: ArrayBuffer) => void) => void; -// removeListener: (listener: (data: ArrayBuffer) => void) => void; - -// // Also not sure if this is the best way -// sendData: (data: ArrayBuffer) => Promise; -// disconnect: () => Promise; -// }; - -// type SSHConnectParams = { -// connectionDetails: ConnectionDetails; -// onStatusChange: (status: SSHConnectionStatus) => void; -// }; - -// type RustInterface = { -// requestSshConnection: (params: SSHConnectParams) => Promise; -// generateKeyPair: ( -// type: 'rsa' | 'ecdsa' | 'ed25519' | 'ed448', -// ) => Promise; -// }; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2a9843b..34edc8d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -40,9 +40,6 @@ importers: apps/mobile: dependencies: - '@dylankenneally/react-native-ssh-sftp': - specifier: ^1.5.20 - version: 1.5.20(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)) '@expo/vector-icons': specifier: ^15.0.2 version: 15.0.2(expo-font@14.0.8(expo@54.0.7)(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) @@ -76,9 +73,6 @@ importers: expo: specifier: 54.0.7 version: 54.0.7(@babel/core@7.28.3)(@expo/metro-runtime@6.1.1)(expo-router@6.0.4)(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) - expo-build-properties: - specifier: ~1.0.8 - version: 1.0.8(expo@54.0.7) expo-clipboard: specifier: ~8.0.7 version: 8.0.7(expo@54.0.7)(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) @@ -127,9 +121,6 @@ importers: expo-system-ui: specifier: ~6.0.7 version: 6.0.7(expo@54.0.7)(react-native-web@0.21.1(react-dom@19.1.0(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)) - expo-web-browser: - specifier: ~15.0.7 - version: 15.0.7(expo@54.0.7)(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: specifier: 19.1.0 version: 19.1.0 @@ -306,9 +297,6 @@ importers: packages: - '-@0.0.1': - resolution: {integrity: sha512-3HfneK3DGAm05fpyj20sT3apkNcvPpCuccOThOPdzz8sY7GgQGe0l93XH9bt+YzibcTIgUAIMoyVJI740RtgyQ==} - '@0no-co/graphql.web@1.2.0': resolution: {integrity: sha512-/1iHy9TTr63gE1YcR5idjx8UREz1s0kFhydf3bBLCXyqjhkIc6igAzTOx3zPifCwFR87tsh/4Pa9cNts6d2otw==} peerDependencies: @@ -1072,12 +1060,6 @@ packages: conventional-commits-parser: optional: true - '@dylankenneally/react-native-ssh-sftp@1.5.20': - resolution: {integrity: sha512-i234V5eNaFlIkUSDX8PbqwMjP7l4rPGjphcMocYHTPs1vJJMCGpWR3pvTwog2za7jZuWAIJTRgLGGuJddDmQSg==} - engines: {node: '>=18.16.0 <21.0.0', npm: '>=9.5.0 <11.0.0'} - peerDependencies: - react-native: '*' - '@egjs/hammerjs@2.0.17': resolution: {integrity: sha512-XQsZgjm2EcVUiZQf11UBJQfmZeEmOW8DpI1gsFeln6w0ae0ii4dMQEQ0kjl6DspdWX1aGY1/loyXnP0JS06e/A==} engines: {node: '>=0.8.0'} @@ -1284,18 +1266,10 @@ packages: resolution: {integrity: sha512-78Md3/Rrxh83gCxoUc0EiciuOHsIITzLy53m3d9UyiW8y9Dj2D29FeETqyKA+BRK76tnTp6RXWb3pCay8Oyomg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/eslintrc@2.1.4': - resolution: {integrity: sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - '@eslint/eslintrc@3.3.1': resolution: {integrity: sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/js@8.57.1': - resolution: {integrity: sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - '@eslint/js@9.35.0': resolution: {integrity: sha512-30iXE9whjlILfWobBkNerJo+TXYsgVM5ERQwMcMKCHckHflCmf7wXDAHlARoWnh0s1U72WqlbeyE7iAcCzuCPw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -1457,19 +1431,10 @@ packages: resolution: {integrity: sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==} engines: {node: '>=18.18.0'} - '@humanwhocodes/config-array@0.13.0': - resolution: {integrity: sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==} - engines: {node: '>=10.10.0'} - deprecated: Use @eslint/config-array instead - '@humanwhocodes/module-importer@1.0.1': resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} engines: {node: '>=12.22'} - '@humanwhocodes/object-schema@2.0.3': - resolution: {integrity: sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==} - deprecated: Use @eslint/object-schema instead - '@humanwhocodes/retry@0.3.1': resolution: {integrity: sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==} engines: {node: '>=18.18'} @@ -3211,10 +3176,6 @@ packages: resolution: {integrity: sha512-cQzWCtO6C8TQiYl1ruKNn2U6Ao4o4WBBcbL61yJl84x+j5sOWWFU9X7DpND8XZG3daDppSsigMdfAIl2upQBRw==} engines: {node: '>=10.0.0'} - D@1.0.0: - resolution: {integrity: sha512-nQvrCBu7K2pSSEtIM0EEF03FVjcczCXInMt3moLNFbjlWx6bZrX72uT6/1uAXDbnzGUAx9gTyDiQ+vrFi663oA==} - deprecated: Package no longer supported. Contact support@npmjs.com for more info. - abbrev@3.0.1: resolution: {integrity: sha512-AO2ac6pjRB3SJmGJo+v5/aK6Omggp6fsLrs6wN9bd35ulu4cCwaAU9+7ZhXjeqHVkaHThLuzH0nZr0YpCDhygg==} engines: {node: ^18.17.0 || >=20.5.0} @@ -3261,9 +3222,6 @@ packages: ajv@6.12.6: resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} - ajv@8.17.1: - resolution: {integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==} - anser@1.4.10: resolution: {integrity: sha512-hCv9AqTQ8ycjpSd3upOJd7vFwW1JaoYQ7tpham03GJ1ca8/65rqn0RpaWpItOAd6ylW9wAw6luXYPJIyPFVOww==} @@ -4219,10 +4177,6 @@ packages: resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} engines: {node: '>=0.10.0'} - doctrine@3.0.0: - resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} - engines: {node: '>=6.0.0'} - doctypes@1.1.0: resolution: {integrity: sha512-LLBi6pEqS6Do3EKQ3J0NqHWV5hhb78Pi8vvESYwyOy2c31ZEZVdtitdzsQsKb7878PEERhzUk0ftqGhG6Mz+pQ==} @@ -4565,10 +4519,6 @@ packages: resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==} engines: {node: '>=8.0.0'} - eslint-scope@7.2.2: - resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - eslint-scope@8.4.0: resolution: {integrity: sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -4585,12 +4535,6 @@ packages: resolution: {integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - eslint@8.57.1: - resolution: {integrity: sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options. - hasBin: true - eslint@9.35.0: resolution: {integrity: sha512-QePbBFMJFjgmlE+cXAlbHZbHpdFVS2E/6vzCy7aKlebddvl1vadiC4JFV5u/wqTkNUwEV8WrQi257jf5f06hrg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -4605,10 +4549,6 @@ packages: resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - espree@9.6.1: - resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - esprima@4.0.1: resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} engines: {node: '>=4'} @@ -4685,11 +4625,6 @@ packages: react: '*' react-native: '*' - expo-build-properties@1.0.8: - resolution: {integrity: sha512-Ram9Jcg2WkbE7bRopWacMnXIhqUP6P13cQoj4rSfXLpJVOyGGvuMiw3rs1vzMbWSHxhvvsX2NvYXXIrZatexuw==} - peerDependencies: - expo: '*' - expo-clipboard@8.0.7: resolution: {integrity: sha512-zvlfFV+wB2QQrQnHWlo0EKHAkdi2tycLtE+EXFUWTPZYkgu1XcH+aiKfd4ul7Z0SDF+1IuwoiW9AA9eO35aj3Q==} peerDependencies: @@ -4863,12 +4798,6 @@ packages: peerDependencies: expo: '*' - expo-web-browser@15.0.7: - resolution: {integrity: sha512-eXnfO3FQ2WthTA8uEPNJ7SDRfPaLIU/P2k082HGEYIHAFZMwh2o9Wo+SDVytO3E95TAv1qwhggUjOrczYzxteQ==} - peerDependencies: - expo: '*' - react-native: '*' - expo@54.0.7: resolution: {integrity: sha512-DftN6nMdpHYUCw5Xnh7+h7wnusjtly4JzQknvuD7MzIvqoyJL9uffQyMQrmZkXrUbgm+cKBm47vtooIz4qj0Qg==} hasBin: true @@ -4915,9 +4844,6 @@ packages: fast-levenshtein@2.0.6: resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} - fast-uri@3.1.0: - resolution: {integrity: sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==} - fast-xml-parser@4.5.3: resolution: {integrity: sha512-RKihhV+SHsIUGXObeVy9AXiBbFwkVk7Syp8XgwN5U3JV416+Gwp/GO9i0JYKmikykgz/UHRrrV4ROuZEo/T0ig==} hasBin: true @@ -4946,10 +4872,6 @@ packages: picomatch: optional: true - file-entry-cache@6.0.1: - resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} - engines: {node: ^10.12.0 || >=12.0.0} - file-entry-cache@8.0.0: resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} engines: {node: '>=16.0.0'} @@ -4981,10 +4903,6 @@ packages: resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} engines: {node: '>=10'} - flat-cache@3.2.0: - resolution: {integrity: sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==} - engines: {node: ^10.12.0 || >=12.0.0} - flat-cache@4.0.1: resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} engines: {node: '>=16'} @@ -5888,9 +5806,6 @@ packages: json-schema-traverse@0.4.1: resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} - json-schema-traverse@1.0.0: - resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} - json-stable-stringify-without-jsonify@1.0.1: resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} @@ -7902,9 +7817,6 @@ packages: resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==} engines: {node: '>=8'} - text-table@0.2.0: - resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} - thenify-all@1.6.0: resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} engines: {node: '>=0.8'} @@ -8681,8 +8593,6 @@ packages: snapshots: - '-@0.0.1': {} - '@0no-co/graphql.web@1.2.0': {} '@ampproject/remapping@2.3.0': @@ -9669,15 +9579,6 @@ snapshots: conventional-commits-filter: 5.0.0 conventional-commits-parser: 6.2.0 - '@dylankenneally/react-native-ssh-sftp@1.5.20(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))': - dependencies: - '-': 0.0.1 - D: 1.0.0 - eslint: 8.57.1 - 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) - transitivePeerDependencies: - - supports-color - '@egjs/hammerjs@2.0.17': dependencies: '@types/hammerjs': 2.0.46 @@ -9820,11 +9721,6 @@ snapshots: '@esbuild/win32-x64@0.25.9': optional: true - '@eslint-community/eslint-utils@4.9.0(eslint@8.57.1)': - dependencies: - eslint: 8.57.1 - eslint-visitor-keys: 3.4.3 - '@eslint-community/eslint-utils@4.9.0(eslint@9.35.0(jiti@2.5.1))': dependencies: eslint: 9.35.0(jiti@2.5.1) @@ -9850,20 +9746,6 @@ snapshots: dependencies: '@types/json-schema': 7.0.15 - '@eslint/eslintrc@2.1.4': - dependencies: - ajv: 6.12.6 - debug: 4.4.1 - espree: 9.6.1 - globals: 13.24.0 - ignore: 5.3.2 - import-fresh: 3.3.1 - js-yaml: 4.1.0 - minimatch: 3.1.2 - strip-json-comments: 3.1.1 - transitivePeerDependencies: - - supports-color - '@eslint/eslintrc@3.3.1': dependencies: ajv: 6.12.6 @@ -9878,8 +9760,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@eslint/js@8.57.1': {} - '@eslint/js@9.35.0': {} '@eslint/object-schema@2.1.6': {} @@ -10259,18 +10139,8 @@ snapshots: '@humanfs/core': 0.19.1 '@humanwhocodes/retry': 0.3.1 - '@humanwhocodes/config-array@0.13.0': - dependencies: - '@humanwhocodes/object-schema': 2.0.3 - debug: 4.4.1 - minimatch: 3.1.2 - transitivePeerDependencies: - - supports-color - '@humanwhocodes/module-importer@1.0.1': {} - '@humanwhocodes/object-schema@2.0.3': {} - '@humanwhocodes/retry@0.3.1': {} '@humanwhocodes/retry@0.4.3': {} @@ -12265,8 +12135,6 @@ snapshots: '@xmldom/xmldom@0.8.11': {} - D@1.0.0: {} - abbrev@3.0.1: {} abort-controller@3.0.0: @@ -12306,13 +12174,6 @@ snapshots: json-schema-traverse: 0.4.1 uri-js: 4.4.1 - ajv@8.17.1: - dependencies: - fast-deep-equal: 3.1.3 - fast-uri: 3.1.0 - json-schema-traverse: 1.0.0 - require-from-string: 2.0.2 - anser@1.4.10: {} ansi-align@3.0.1: @@ -13458,10 +13319,6 @@ snapshots: dependencies: esutils: 2.0.3 - doctrine@3.0.0: - dependencies: - esutils: 2.0.3 - doctypes@1.1.0: {} dot-prop@5.3.0: @@ -13933,11 +13790,6 @@ snapshots: esrecurse: 4.3.0 estraverse: 4.3.0 - eslint-scope@7.2.2: - dependencies: - esrecurse: 4.3.0 - estraverse: 5.3.0 - eslint-scope@8.4.0: dependencies: esrecurse: 4.3.0 @@ -13949,49 +13801,6 @@ snapshots: eslint-visitor-keys@4.2.1: {} - eslint@8.57.1: - dependencies: - '@eslint-community/eslint-utils': 4.9.0(eslint@8.57.1) - '@eslint-community/regexpp': 4.12.1 - '@eslint/eslintrc': 2.1.4 - '@eslint/js': 8.57.1 - '@humanwhocodes/config-array': 0.13.0 - '@humanwhocodes/module-importer': 1.0.1 - '@nodelib/fs.walk': 1.2.8 - '@ungap/structured-clone': 1.3.0 - ajv: 6.12.6 - chalk: 4.1.2 - cross-spawn: 7.0.6 - debug: 4.4.1 - doctrine: 3.0.0 - escape-string-regexp: 4.0.0 - eslint-scope: 7.2.2 - eslint-visitor-keys: 3.4.3 - espree: 9.6.1 - esquery: 1.6.0 - esutils: 2.0.3 - fast-deep-equal: 3.1.3 - file-entry-cache: 6.0.1 - find-up: 5.0.0 - glob-parent: 6.0.2 - globals: 13.24.0 - graphemer: 1.4.0 - ignore: 5.3.2 - imurmurhash: 0.1.4 - is-glob: 4.0.3 - is-path-inside: 3.0.3 - js-yaml: 4.1.0 - json-stable-stringify-without-jsonify: 1.0.1 - levn: 0.4.1 - lodash.merge: 4.6.2 - minimatch: 3.1.2 - natural-compare: 1.4.0 - optionator: 0.9.4 - strip-ansi: 6.0.1 - text-table: 0.2.0 - transitivePeerDependencies: - - supports-color - eslint@9.35.0(jiti@2.5.1): dependencies: '@eslint-community/eslint-utils': 4.9.0(eslint@9.35.0(jiti@2.5.1)) @@ -14040,12 +13849,6 @@ snapshots: acorn-jsx: 5.3.2(acorn@8.15.0) eslint-visitor-keys: 4.2.1 - espree@9.6.1: - dependencies: - acorn: 8.15.0 - acorn-jsx: 5.3.2(acorn@8.15.0) - eslint-visitor-keys: 3.4.3 - esprima@4.0.1: {} esquery@1.6.0: @@ -14134,12 +13937,6 @@ snapshots: transitivePeerDependencies: - supports-color - expo-build-properties@1.0.8(expo@54.0.7): - dependencies: - ajv: 8.17.1 - expo: 54.0.7(@babel/core@7.28.3)(@expo/metro-runtime@6.1.1)(expo-router@6.0.4)(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) - semver: 7.7.2 - expo-clipboard@8.0.7(expo@54.0.7)(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): dependencies: expo: 54.0.7(@babel/core@7.28.3)(@expo/metro-runtime@6.1.1)(expo-router@6.0.4)(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) @@ -14337,11 +14134,6 @@ snapshots: dependencies: expo: 54.0.7(@babel/core@7.28.3)(@expo/metro-runtime@6.1.1)(expo-router@6.0.4)(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) - expo-web-browser@15.0.7(expo@54.0.7)(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)): - dependencies: - expo: 54.0.7(@babel/core@7.28.3)(@expo/metro-runtime@6.1.1)(expo-router@6.0.4)(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) - expo@54.0.7(@babel/core@7.28.3)(@expo/metro-runtime@6.1.1)(expo-router@6.0.4)(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): dependencies: '@babel/runtime': 7.28.3 @@ -14403,8 +14195,6 @@ snapshots: fast-levenshtein@2.0.6: {} - fast-uri@3.1.0: {} - fast-xml-parser@4.5.3: dependencies: strnum: 1.1.2 @@ -14439,10 +14229,6 @@ snapshots: optionalDependencies: picomatch: 4.0.3 - file-entry-cache@6.0.1: - dependencies: - flat-cache: 3.2.0 - file-entry-cache@8.0.0: dependencies: flat-cache: 4.0.1 @@ -14479,12 +14265,6 @@ snapshots: locate-path: 6.0.0 path-exists: 4.0.0 - flat-cache@3.2.0: - dependencies: - flatted: 3.3.3 - keyv: 4.5.4 - rimraf: 3.0.2 - flat-cache@4.0.1: dependencies: flatted: 3.3.3 @@ -15651,8 +15431,6 @@ snapshots: json-schema-traverse@0.4.1: {} - json-schema-traverse@1.0.0: {} - json-stable-stringify-without-jsonify@1.0.1: {} json5@1.0.2: @@ -18211,8 +17989,6 @@ snapshots: glob: 7.2.3 minimatch: 3.1.2 - text-table@0.2.0: {} - thenify-all@1.6.0: dependencies: thenify: 3.3.1