mirror of
https://github.com/EthanShoeDev/fressh.git
synced 2026-01-11 14:22:51 +00:00
commit
This commit is contained in:
@@ -28,11 +28,11 @@
|
|||||||
"@expo/vector-icons": "^15.0.2",
|
"@expo/vector-icons": "^15.0.2",
|
||||||
"@fressh/assets": "workspace:*",
|
"@fressh/assets": "workspace:*",
|
||||||
"@fressh/react-native-uniffi-russh": "workspace:*",
|
"@fressh/react-native-uniffi-russh": "workspace:*",
|
||||||
"@react-native-picker/picker": "2.11.1",
|
|
||||||
"@react-native-segmented-control/segmented-control": "2.5.7",
|
"@react-native-segmented-control/segmented-control": "2.5.7",
|
||||||
"@react-navigation/bottom-tabs": "^7.4.0",
|
"@react-navigation/bottom-tabs": "^7.4.0",
|
||||||
"@react-navigation/elements": "^2.6.4",
|
"@react-navigation/elements": "^2.6.4",
|
||||||
"@react-navigation/native": "^7.1.8",
|
"@react-navigation/native": "^7.1.8",
|
||||||
|
"@shopify/flash-list": "2.0.2",
|
||||||
"@tanstack/react-form": "^1.20.0",
|
"@tanstack/react-form": "^1.20.0",
|
||||||
"@tanstack/react-query": "^5.87.4",
|
"@tanstack/react-query": "^5.87.4",
|
||||||
"expo": "54.0.7",
|
"expo": "54.0.7",
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import React from 'react';
|
|
||||||
import { NativeTabs, Icon, Label } from 'expo-router/unstable-native-tabs';
|
import { NativeTabs, Icon, Label } from 'expo-router/unstable-native-tabs';
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
export default function TabsLayout() {
|
export default function TabsLayout() {
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import {
|
|||||||
SafeAreaView,
|
SafeAreaView,
|
||||||
useSafeAreaInsets,
|
useSafeAreaInsets,
|
||||||
} from 'react-native-safe-area-context';
|
} from 'react-native-safe-area-context';
|
||||||
|
import { KeyList } from '@/components/key-manager/KeyList';
|
||||||
import { AbortSignalTimeout } from '@/lib/utils';
|
import { AbortSignalTimeout } from '@/lib/utils';
|
||||||
import { useAppForm, useFieldContext } from '../components/form-components';
|
import { useAppForm, useFieldContext } from '../components/form-components';
|
||||||
import {
|
import {
|
||||||
@@ -25,8 +26,6 @@ import {
|
|||||||
} from '../lib/secrets-manager';
|
} from '../lib/secrets-manager';
|
||||||
// import { sshConnectionManager } from '../lib/ssh-connection-manager';
|
// import { sshConnectionManager } from '../lib/ssh-connection-manager';
|
||||||
import { useTheme } from '../theme';
|
import { useTheme } from '../theme';
|
||||||
import { useFocusEffect } from '@react-navigation/native';
|
|
||||||
import { KeyList } from '@/components/key-manager/KeyList';
|
|
||||||
|
|
||||||
const defaultValues: ConnectionDetails = {
|
const defaultValues: ConnectionDetails = {
|
||||||
host: 'test.rebex.net',
|
host: 'test.rebex.net',
|
||||||
@@ -260,11 +259,15 @@ function KeyIdPickerField() {
|
|||||||
}, [listPrivateKeysQuery.data]);
|
}, [listPrivateKeysQuery.data]);
|
||||||
const keys = listPrivateKeysQuery.data ?? [];
|
const keys = listPrivateKeysQuery.data ?? [];
|
||||||
|
|
||||||
|
const fieldValue = field.state.value;
|
||||||
|
const defaultPickId = defaultPick?.id;
|
||||||
|
const fieldHandleChange = field.handleChange;
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
if (!field.state.value && defaultPick?.id) {
|
if (!fieldValue && defaultPickId) {
|
||||||
field.handleChange(defaultPick.id);
|
fieldHandleChange(defaultPickId);
|
||||||
}
|
}
|
||||||
}, [field.state.value, defaultPick?.id]);
|
}, [fieldValue, defaultPickId, fieldHandleChange]);
|
||||||
|
|
||||||
const computedSelectedId = field.state.value ?? defaultPick?.id;
|
const computedSelectedId = field.state.value ?? defaultPick?.id;
|
||||||
const selected = keys.find((k) => k.id === computedSelectedId);
|
const selected = keys.find((k) => k.id === computedSelectedId);
|
||||||
|
|||||||
@@ -68,13 +68,6 @@ export default function ShellDetail() {
|
|||||||
};
|
};
|
||||||
}, [connection]);
|
}, [connection]);
|
||||||
|
|
||||||
// Cleanup when leaving screen
|
|
||||||
useEffect(() => {
|
|
||||||
return () => {
|
|
||||||
if (connection) void connection.disconnect().catch(() => {});
|
|
||||||
};
|
|
||||||
}, [connection, shell]);
|
|
||||||
|
|
||||||
const scrollViewRef = useRef<ScrollView | null>(null);
|
const scrollViewRef = useRef<ScrollView | null>(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|||||||
@@ -1,7 +1,40 @@
|
|||||||
|
import {
|
||||||
|
RnRussh,
|
||||||
|
type SshConnection,
|
||||||
|
type SshShellSession,
|
||||||
|
} from '@fressh/react-native-uniffi-russh';
|
||||||
|
import { FlashList } from '@shopify/flash-list';
|
||||||
import { Link } from 'expo-router';
|
import { Link } from 'expo-router';
|
||||||
import { StyleSheet, Text, View } from 'react-native';
|
import { StyleSheet, Text, View } from 'react-native';
|
||||||
|
|
||||||
|
type ShellWithConnection = SshShellSession & { connection: SshConnection };
|
||||||
|
|
||||||
export default function ShellList() {
|
export default function ShellList() {
|
||||||
|
const connectionsWithShells = RnRussh.listSshConnectionsWithShells();
|
||||||
|
const shellsFirstList = connectionsWithShells.reduce<ShellWithConnection[]>(
|
||||||
|
(acc, curr) => {
|
||||||
|
acc.push(...curr.shells.map((shell) => ({ ...shell, connection: curr })));
|
||||||
|
return acc;
|
||||||
|
},
|
||||||
|
[],
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View style={styles.container}>
|
||||||
|
{shellsFirstList.length === 0 ? (
|
||||||
|
<EmptyState />
|
||||||
|
) : (
|
||||||
|
<FlashList
|
||||||
|
data={shellsFirstList}
|
||||||
|
renderItem={({ item }) => <ShellCard shell={item} />}
|
||||||
|
// maintainVisibleContentPosition={{ autoscrollToBottomThreshold: 0.2 }}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function EmptyState() {
|
||||||
return (
|
return (
|
||||||
<View style={styles.container}>
|
<View style={styles.container}>
|
||||||
<Text style={styles.text}>No active shells. Connect from Host tab.</Text>
|
<Text style={styles.text}>No active shells. Connect from Host tab.</Text>
|
||||||
@@ -10,6 +43,24 @@ export default function ShellList() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function ShellCard({ shell }: { shell: ShellWithConnection }) {
|
||||||
|
return (
|
||||||
|
<View style={styles.container}>
|
||||||
|
<Text style={styles.text}>{shell.connectionId}</Text>
|
||||||
|
<Text style={styles.text}>{shell.createdAtMs}</Text>
|
||||||
|
<Text style={styles.text}>{shell.pty}</Text>
|
||||||
|
<Text style={styles.text}>{shell.connection.connectionDetails.host}</Text>
|
||||||
|
<Text style={styles.text}>{shell.connection.connectionDetails.port}</Text>
|
||||||
|
<Text style={styles.text}>
|
||||||
|
{shell.connection.connectionDetails.username}
|
||||||
|
</Text>
|
||||||
|
<Text style={styles.text}>
|
||||||
|
{shell.connection.connectionDetails.security.type}
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
container: { flex: 1, alignItems: 'center', justifyContent: 'center' },
|
container: { flex: 1, alignItems: 'center', justifyContent: 'center' },
|
||||||
text: { color: '#E5E7EB', marginBottom: 8 },
|
text: { color: '#E5E7EB', marginBottom: 8 },
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import { Picker } from '@react-native-picker/picker';
|
|
||||||
import {
|
import {
|
||||||
createFormHook,
|
createFormHook,
|
||||||
createFormHookContexts,
|
createFormHookContexts,
|
||||||
@@ -98,31 +97,6 @@ export function SwitchField(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function PickerField<T>(
|
|
||||||
props: React.ComponentProps<typeof Picker<T>> & {
|
|
||||||
label?: string;
|
|
||||||
},
|
|
||||||
) {
|
|
||||||
const { label, style, ...rest } = props;
|
|
||||||
const field = useFieldContext<T>();
|
|
||||||
return (
|
|
||||||
<View style={styles.inputGroup}>
|
|
||||||
{label ? <Text style={styles.label}>{label}</Text> : null}
|
|
||||||
<View style={[styles.input, styles.pickerContainer]}>
|
|
||||||
<Picker<T>
|
|
||||||
style={styles.picker}
|
|
||||||
selectedValue={field.state.value}
|
|
||||||
onValueChange={(itemValue) => field.handleChange(itemValue)}
|
|
||||||
{...rest}
|
|
||||||
>
|
|
||||||
{props.children}
|
|
||||||
</Picker>
|
|
||||||
</View>
|
|
||||||
<FieldInfo />
|
|
||||||
</View>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function SubmitButton(
|
export function SubmitButton(
|
||||||
props: {
|
props: {
|
||||||
onPress?: () => void;
|
onPress?: () => void;
|
||||||
@@ -162,7 +136,6 @@ export const { useAppForm, withForm, withFieldGroup } = createFormHook({
|
|||||||
fieldComponents: {
|
fieldComponents: {
|
||||||
TextField,
|
TextField,
|
||||||
NumberField,
|
NumberField,
|
||||||
PickerField,
|
|
||||||
SwitchField,
|
SwitchField,
|
||||||
},
|
},
|
||||||
formComponents: {
|
formComponents: {
|
||||||
|
|||||||
@@ -483,6 +483,18 @@ pub fn list_ssh_connections() -> Vec<SshConnectionInfo> {
|
|||||||
out
|
out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[uniffi::export]
|
||||||
|
pub fn list_ssh_shells() -> Vec<ShellSessionInfo> {
|
||||||
|
// Collect shells outside the lock to avoid holding a MutexGuard across await
|
||||||
|
let shells: Vec<Arc<ShellSession>> = SHELLS
|
||||||
|
.lock()
|
||||||
|
.map(|map| map.values().cloned().collect())
|
||||||
|
.unwrap_or_default();
|
||||||
|
let mut out = Vec::with_capacity(shells.len());
|
||||||
|
for shell in shells { out.push(shell.info()); }
|
||||||
|
out
|
||||||
|
}
|
||||||
|
|
||||||
#[uniffi::export]
|
#[uniffi::export]
|
||||||
pub fn get_ssh_connection(id: String) -> Result<Arc<SSHConnection>, SshError> {
|
pub fn get_ssh_connection(id: String) -> Result<Arc<SSHConnection>, SshError> {
|
||||||
if let Ok(map) = CONNECTIONS.lock() { if let Some(conn) = map.get(&id) { return Ok(conn.clone()); } }
|
if let Ok(map) = CONNECTIONS.lock() { if let Some(conn) = map.get(&id) { return Ok(conn.clone()); } }
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ export type SshShellSession = {
|
|||||||
readonly channelId: number;
|
readonly channelId: number;
|
||||||
readonly createdAtMs: number;
|
readonly createdAtMs: number;
|
||||||
readonly pty: GeneratedRussh.PtyType;
|
readonly pty: GeneratedRussh.PtyType;
|
||||||
|
readonly connectionId: string;
|
||||||
sendData: (
|
sendData: (
|
||||||
data: ArrayBuffer,
|
data: ArrayBuffer,
|
||||||
options?: { signal: AbortSignal }
|
options?: { signal: AbortSignal }
|
||||||
@@ -55,8 +56,10 @@ type RusshApi = {
|
|||||||
connect: (options: ConnectOptions) => Promise<SshConnection>;
|
connect: (options: ConnectOptions) => Promise<SshConnection>;
|
||||||
|
|
||||||
getSshConnection: (id: string) => SshConnection | undefined;
|
getSshConnection: (id: string) => SshConnection | undefined;
|
||||||
listSshConnections: () => SshConnection[];
|
|
||||||
getSshShell: (connectionId: string, channelId: number) => SshShellSession | undefined;
|
getSshShell: (connectionId: string, channelId: number) => SshShellSession | undefined;
|
||||||
|
listSshConnections: () => SshConnection[];
|
||||||
|
listSshShells: () => SshShellSession[];
|
||||||
|
listSshConnectionsWithShells: () => (SshConnection & { shells: SshShellSession[] })[];
|
||||||
|
|
||||||
generateKeyPair: (type: PrivateKeyType) => Promise<string>;
|
generateKeyPair: (type: PrivateKeyType) => Promise<string>;
|
||||||
|
|
||||||
@@ -148,6 +151,7 @@ function wrapShellSession(shell: GeneratedRussh.ShellSessionInterface): SshShell
|
|||||||
channelId: info.channelId,
|
channelId: info.channelId,
|
||||||
createdAtMs: info.createdAtMs,
|
createdAtMs: info.createdAtMs,
|
||||||
pty: info.pty,
|
pty: info.pty,
|
||||||
|
connectionId: info.connectionId,
|
||||||
sendData: shell.sendData.bind(shell),
|
sendData: shell.sendData.bind(shell),
|
||||||
close: shell.close.bind(shell)
|
close: shell.close.bind(shell)
|
||||||
};
|
};
|
||||||
@@ -216,6 +220,33 @@ function listSshConnections(): SshConnection[] {
|
|||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function listSshShells(): SshShellSession[] {
|
||||||
|
const infos = GeneratedRussh.listSshShells();
|
||||||
|
const out: SshShellSession[] = [];
|
||||||
|
for (const info of infos) {
|
||||||
|
try {
|
||||||
|
const shell = GeneratedRussh.getSshShell(info.connectionId, info.channelId);
|
||||||
|
out.push(wrapShellSession(shell));
|
||||||
|
} catch {
|
||||||
|
// ignore entries that no longer exist between snapshot and lookup
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO: This feels a bit hacky. It is probably more effecient to do this join in rust and send
|
||||||
|
* the joined result to the app.
|
||||||
|
*/
|
||||||
|
function listSshConnectionsWithShells(): (SshConnection & { shells: SshShellSession[] })[] {
|
||||||
|
const connections = listSshConnections();
|
||||||
|
const shells = listSshShells();
|
||||||
|
return connections.map(connection => ({
|
||||||
|
...connection,
|
||||||
|
shells: shells.filter(shell => shell.connectionId === connection.connectionId),
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
async function generateKeyPair(type: PrivateKeyType) {
|
async function generateKeyPair(type: PrivateKeyType) {
|
||||||
return GeneratedRussh.generateKeyPair(privateKeyTypeLiteralToEnum[type]);
|
return GeneratedRussh.generateKeyPair(privateKeyTypeLiteralToEnum[type]);
|
||||||
@@ -229,5 +260,7 @@ export const RnRussh = {
|
|||||||
generateKeyPair,
|
generateKeyPair,
|
||||||
getSshConnection,
|
getSshConnection,
|
||||||
listSshConnections,
|
listSshConnections,
|
||||||
|
listSshShells,
|
||||||
|
listSshConnectionsWithShells,
|
||||||
getSshShell,
|
getSshShell,
|
||||||
} satisfies RusshApi;
|
} satisfies RusshApi;
|
||||||
|
|||||||
39
pnpm-lock.yaml
generated
39
pnpm-lock.yaml
generated
@@ -49,9 +49,6 @@ importers:
|
|||||||
'@fressh/react-native-uniffi-russh':
|
'@fressh/react-native-uniffi-russh':
|
||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
version: link:../../packages/react-native-uniffi-russh
|
version: link:../../packages/react-native-uniffi-russh
|
||||||
'@react-native-picker/picker':
|
|
||||||
specifier: 2.11.1
|
|
||||||
version: 2.11.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))(react@19.1.0)
|
|
||||||
'@react-native-segmented-control/segmented-control':
|
'@react-native-segmented-control/segmented-control':
|
||||||
specifier: 2.5.7
|
specifier: 2.5.7
|
||||||
version: 2.5.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)
|
version: 2.5.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)
|
||||||
@@ -64,6 +61,9 @@ importers:
|
|||||||
'@react-navigation/native':
|
'@react-navigation/native':
|
||||||
specifier: ^7.1.8
|
specifier: ^7.1.8
|
||||||
version: 7.1.17(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)
|
version: 7.1.17(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)
|
||||||
|
'@shopify/flash-list':
|
||||||
|
specifier: 2.0.2
|
||||||
|
version: 2.0.2(@babel/runtime@7.28.3)(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)
|
||||||
'@tanstack/react-form':
|
'@tanstack/react-form':
|
||||||
specifier: ^1.20.0
|
specifier: ^1.20.0
|
||||||
version: 1.20.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
|
version: 1.20.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
|
||||||
@@ -238,7 +238,7 @@ importers:
|
|||||||
dependencies:
|
dependencies:
|
||||||
uniffi-bindgen-react-native:
|
uniffi-bindgen-react-native:
|
||||||
specifier: github:EthanShoeDev/uniffi-bindgen-react-native#build-ts
|
specifier: github:EthanShoeDev/uniffi-bindgen-react-native#build-ts
|
||||||
version: https://codeload.github.com/EthanShoeDev/uniffi-bindgen-react-native/tar.gz/5933e251a5464a8209e78fd679b72293ef4c68bb(patch_hash=527b712c8fb029b29d9ac7caa72e593fa37a6dcebb63e15a56e21e75ffcb88ec)
|
version: https://codeload.github.com/EthanShoeDev/uniffi-bindgen-react-native/tar.gz/54dd681081a4117ee417f78607a942544636b145(patch_hash=527b712c8fb029b29d9ac7caa72e593fa37a6dcebb63e15a56e21e75ffcb88ec)
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@eslint/compat':
|
'@eslint/compat':
|
||||||
specifier: ^1.3.2
|
specifier: ^1.3.2
|
||||||
@@ -2326,12 +2326,6 @@ packages:
|
|||||||
engines: {node: '>=20.19.4'}
|
engines: {node: '>=20.19.4'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
'@react-native-picker/picker@2.11.1':
|
|
||||||
resolution: {integrity: sha512-ThklnkK4fV3yynnIIRBkxxjxR4IFbdMNJVF6tlLdOJ/zEFUEFUEdXY0KmH0iYzMwY8W4/InWsLiA7AkpAbnexA==}
|
|
||||||
peerDependencies:
|
|
||||||
react: '*'
|
|
||||||
react-native: '*'
|
|
||||||
|
|
||||||
'@react-native-segmented-control/segmented-control@2.5.7':
|
'@react-native-segmented-control/segmented-control@2.5.7':
|
||||||
resolution: {integrity: sha512-l84YeVX8xAU3lvOJSvV4nK/NbGhIm2gBfveYolwaoCbRp+/SLXtc6mYrQmM9ScXNwU14mnzjQTpTHWl5YPnkzQ==}
|
resolution: {integrity: sha512-l84YeVX8xAU3lvOJSvV4nK/NbGhIm2gBfveYolwaoCbRp+/SLXtc6mYrQmM9ScXNwU14mnzjQTpTHWl5YPnkzQ==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@@ -2618,6 +2612,13 @@ packages:
|
|||||||
'@shikijs/vscode-textmate@10.0.2':
|
'@shikijs/vscode-textmate@10.0.2':
|
||||||
resolution: {integrity: sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==}
|
resolution: {integrity: sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==}
|
||||||
|
|
||||||
|
'@shopify/flash-list@2.0.2':
|
||||||
|
resolution: {integrity: sha512-zhlrhA9eiuEzja4wxVvotgXHtqd3qsYbXkQ3rsBfOgbFA9BVeErpDE/yEwtlIviRGEqpuFj/oU5owD6ByaNX+w==}
|
||||||
|
peerDependencies:
|
||||||
|
'@babel/runtime': '*'
|
||||||
|
react: '*'
|
||||||
|
react-native: '*'
|
||||||
|
|
||||||
'@sideway/address@4.1.5':
|
'@sideway/address@4.1.5':
|
||||||
resolution: {integrity: sha512-IqO/DUQHUkPeixNQ8n0JA6102hT9CmaljNTPmQ1u8MEhBo/R4Q8eKLN/vGZxuebwOroDB4cbpjheD4+/sKFK4Q==}
|
resolution: {integrity: sha512-IqO/DUQHUkPeixNQ8n0JA6102hT9CmaljNTPmQ1u8MEhBo/R4Q8eKLN/vGZxuebwOroDB4cbpjheD4+/sKFK4Q==}
|
||||||
|
|
||||||
@@ -8180,8 +8181,8 @@ packages:
|
|||||||
resolution: {integrity: sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==}
|
resolution: {integrity: sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
|
|
||||||
uniffi-bindgen-react-native@https://codeload.github.com/EthanShoeDev/uniffi-bindgen-react-native/tar.gz/5933e251a5464a8209e78fd679b72293ef4c68bb:
|
uniffi-bindgen-react-native@https://codeload.github.com/EthanShoeDev/uniffi-bindgen-react-native/tar.gz/54dd681081a4117ee417f78607a942544636b145:
|
||||||
resolution: {tarball: https://codeload.github.com/EthanShoeDev/uniffi-bindgen-react-native/tar.gz/5933e251a5464a8209e78fd679b72293ef4c68bb}
|
resolution: {tarball: https://codeload.github.com/EthanShoeDev/uniffi-bindgen-react-native/tar.gz/54dd681081a4117ee417f78607a942544636b145}
|
||||||
version: 0.29.3-1
|
version: 0.29.3-1
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
@@ -11282,11 +11283,6 @@ snapshots:
|
|||||||
- typescript
|
- typescript
|
||||||
- utf-8-validate
|
- utf-8-validate
|
||||||
|
|
||||||
'@react-native-picker/picker@2.11.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))(react@19.1.0)':
|
|
||||||
dependencies:
|
|
||||||
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-native-segmented-control/segmented-control@2.5.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-segmented-control/segmented-control@2.5.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:
|
dependencies:
|
||||||
react: 19.1.0
|
react: 19.1.0
|
||||||
@@ -11683,6 +11679,13 @@ snapshots:
|
|||||||
|
|
||||||
'@shikijs/vscode-textmate@10.0.2': {}
|
'@shikijs/vscode-textmate@10.0.2': {}
|
||||||
|
|
||||||
|
'@shopify/flash-list@2.0.2(@babel/runtime@7.28.3)(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
|
||||||
|
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)
|
||||||
|
tslib: 2.8.1
|
||||||
|
|
||||||
'@sideway/address@4.1.5':
|
'@sideway/address@4.1.5':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@hapi/hoek': 9.3.0
|
'@hapi/hoek': 9.3.0
|
||||||
@@ -18502,7 +18505,7 @@ snapshots:
|
|||||||
|
|
||||||
unicorn-magic@0.3.0: {}
|
unicorn-magic@0.3.0: {}
|
||||||
|
|
||||||
uniffi-bindgen-react-native@https://codeload.github.com/EthanShoeDev/uniffi-bindgen-react-native/tar.gz/5933e251a5464a8209e78fd679b72293ef4c68bb(patch_hash=527b712c8fb029b29d9ac7caa72e593fa37a6dcebb63e15a56e21e75ffcb88ec): {}
|
uniffi-bindgen-react-native@https://codeload.github.com/EthanShoeDev/uniffi-bindgen-react-native/tar.gz/54dd681081a4117ee417f78607a942544636b145(patch_hash=527b712c8fb029b29d9ac7caa72e593fa37a6dcebb63e15a56e21e75ffcb88ec): {}
|
||||||
|
|
||||||
unified@11.0.5:
|
unified@11.0.5:
|
||||||
dependencies:
|
dependencies:
|
||||||
|
|||||||
Reference in New Issue
Block a user