Compare commits

...

14 Commits

Author SHA1 Message Date
EthanShoeDev
ec3876ac3a chore(@fressh/react-native-uniffi-russh): release v0.0.3 2025-10-07 20:54:33 -04:00
EthanShoeDev
64d385038c chore(@fressh/react-native-xtermjs-webview): release v0.0.7 2025-10-07 20:52:01 -04:00
EthanShoeDev
57765da5e8 publish configs 2025-10-07 20:48:24 -04:00
EthanShoeDev
26c5bb8332 chore(@fressh/react-native-xtermjs-webview): release v0.0.6 2025-10-07 17:07:08 -04:00
EthanShoeDev
3a1893e08c chore(@fressh/react-native-uniffi-russh): release v0.0.2 2025-10-07 15:53:18 -04:00
EthanShoeDev
49d4a667b9 small change 2025-10-07 15:40:00 -04:00
EthanShoeDev
fffc3b103c flake fmt 2025-10-07 14:51:08 -04:00
EthanShoeDev
a3c2b67513 flake change 2025-10-07 14:46:28 -04:00
EthanShoeDev
3acde79485 config 2025-10-07 13:46:19 -04:00
EthanShoeDev
711335367e add src 2025-10-07 13:10:04 -04:00
EthanShoeDev
e4139c6f7b small tweaks 2025-10-07 10:19:45 -04:00
EthanShoeDev
8e7ec01e28 small bug fix 2025-10-07 01:24:15 -04:00
EthanShoeDev
0fc4481e82 chore(@fressh/react-native-xtermjs-webview): release v0.0.5 2025-10-07 00:46:30 -04:00
EthanShoeDev
fa2ad2708e changelog 2025-10-07 00:45:42 -04:00
15 changed files with 188 additions and 54 deletions

View File

@@ -9,6 +9,7 @@
"yoavbls.pretty-ts-errors",
"ctf0.duplicated-code-new",
"github.vscode-github-actions",
"mkhl.direnv"
"mkhl.direnv",
"jnoortheen.nix-ide"
]
}

View File

@@ -50,7 +50,7 @@
"expo-font": "~14.0.8",
"expo-glass-effect": "^0.1.4",
"expo-haptics": "~15.0.7",
"expo-image": "~3.0.8",
"expo-image": "~3.0.9",
"expo-linking": "~8.0.8",
"expo-router": "6.0.10",
"expo-secure-store": "~15.0.7",

View File

@@ -467,6 +467,9 @@ type KeyboardToolbarButtonProps =
| KeyboardToolbarModifierButtonProps
| KeyboardToolbarInstantButtonProps;
const propsToKey = (props: KeyboardToolbarButtonProps) =>
'label' in props ? props.label : props.iconName;
function KeyboardToolbarButton({
style,
...props
@@ -487,7 +490,8 @@ function KeyboardToolbarButton({
);
const modifierActive =
props.type === 'modifier' && modifierKeysActive.includes(props);
props.type === 'modifier' &&
!!modifierKeysActive.find((m) => propsToKey(m) === propsToKey(props));
return (
<Pressable
@@ -505,8 +509,10 @@ function KeyboardToolbarButton({
onPress={() => {
if (props.type === 'modifier') {
setModifierKeysActive((modifierKeysActive) =>
modifierKeysActive.includes(props)
? modifierKeysActive.filter((m) => m !== props)
modifierKeysActive.find((m) => propsToKey(m) === propsToKey(props))
? modifierKeysActive.filter(
(m) => propsToKey(m) !== propsToKey(props),
)
: [...modifierKeysActive, props],
);
return;

View File

@@ -63,6 +63,8 @@
fen.targets.armv7-linux-androideabi.stable.rust-std
fen.targets.x86_64-linux-android.stable.rust-std
fen.targets.i686-linux-android.stable.rust-std
fen.targets.aarch64-apple-ios.stable.rust-std
fen.targets.aarch64-apple-ios-sim.stable.rust-std
];
defaultPkgs = with pkgs; [
@@ -93,6 +95,11 @@
clang-tools
];
mkShellFn =
if pkgs.stdenv.isDarwin
then pkgs.mkShellNoCC
else pkgs.mkShell;
ndkId = "27-1-12297006"; # nix flake show github:tadfisher/android-nixpkgs | grep ndk
ndkAttr = "ndk-${ndkId}";
ndkVer = builtins.replaceStrings ["-"] ["."] ndkId;
@@ -218,13 +225,13 @@
export PROMPT_COMMAND=". \"$FRESSH_STARSHIP_PREINIT\""
'';
in {
default = pkgs.mkShell {
default = mkShellFn {
packages = defaultPkgs ++ [remoteAndroidSdk.androidSdk];
shellHook =
commonAndroidInit remoteAndroidSdk.sdkRoot;
};
android-emulator = pkgs.mkShell {
android-emulator = mkShellFn {
packages = defaultPkgs ++ [fullAndroidSdk.androidSdk];
shellHook =
commonAndroidInit fullAndroidSdk.sdkRoot;

View File

@@ -0,0 +1,31 @@
# Workspace caches
.turbo/
# Node modules (npm excludes by default)
node_modules/
# OS junk
**/.DS_Store
# Platform build outputs and local config
ios/build/
android/build/
android/gradle/
android/gradlew
android/gradlew.bat
android/local.properties
# Tests and mocks
**/__tests__/
**/__fixtures__/
**/__mocks__/
# Dotfiles and editors
**/.*
.vscode/
.idea/
# Coverage and logs
coverage/
*.log
*.local

View File

@@ -29,7 +29,7 @@ export default {
hooks: {
'before:init': ['turbo run lint:check'],
'after:bump': ['turbo run build:android', 'turbo run build:ios'],
'after:bump': ['turbo run build:android build:ios'],
'after:release': 'echo "Published ${npm.name} v${version} to npm"',
},
} satisfies Config;

View File

@@ -0,0 +1,7 @@
# Changelog
## [0.0.3](https://github.com/EthanShoeDev/fressh/compare/@fressh/react-native-uniffi-russh-v0.0.2...${npm.name}-v0.0.3) (2025-10-08)
## 0.0.2 (2025-10-07)
## [0.0.1](https://github.com/EthanShoeDev/fressh/compare/@fressh/react-native-xtermjs-webview-v0.0.1...@fressh/react-native-xtermjs-webview-v0.0.4) (2025-10-07)

View File

@@ -16,11 +16,42 @@ Peer dependencies (you manage): `react`, `react-native`.
### Usage
This package exposes a native Rust module for SSH transport. For a complete,
working integration, see the example app in this monorepo at `apps/mobile`.
working integration, see the example app:
- https://github.com/EthanShoeDev/fressh/tree/main/apps/mobile
### API overview
High-level API surface (see code for full types):
```ts
import { RnRussh } from '@fressh/react-native-uniffi-russh';
await RnRussh.uniffiInitAsync();
const conn = await RnRussh.connect({
host: 'example.com',
port: 22,
username: 'me',
security: { type: 'password', password: '...' },
onServerKey: async () => true,
});
const shell = await conn.startShell({ term: 'Xterm' });
shell.addListener(
(ev) => {
// handle TerminalChunk or DropNotice
},
{ cursor: { mode: 'live' } },
);
```
### Links
- Changelog: [`CHANGELOG.md`](./CHANGELOG.md)
- Contributing: see the monorepo guide at
[`../../CONTRIBUTING.md`](../../CONTRIBUTING.md)
- Changelog:
[`CHANGELOG.md`](https://github.com/EthanShoeDev/fressh/blob/main/packages/react-native-uniffi-russh/CHANGELOG.md)
- Contributing:
[`CONTRIBUTING.md`](https://github.com/EthanShoeDev/fressh/blob/main/CONTRIBUTING.md)
- API source:
[`src/api.ts`](https://github.com/EthanShoeDev/fressh/blob/main/packages/react-native-uniffi-russh/src/api.ts)
- License: MIT

View File

@@ -1,9 +1,9 @@
{
"name": "@fressh/react-native-uniffi-russh",
"homepage": "https://github.com/EthanShoeDev/fressh",
"homepage": "https://github.com/EthanShoeDev/fressh#readme",
"license": "MIT",
"description": "Uniffi bindings for russh",
"version": "0.0.1",
"version": "0.0.3",
"type": "module",
"main": "./lib/module/api.js",
"types": "./lib/typescript/src/api.d.ts",
@@ -18,20 +18,11 @@
"lib",
"android",
"ios",
"src",
"cpp",
"*.podspec",
"react-native.config.js",
"LICENSE",
"!ios/build",
"!android/build",
"!android/gradle",
"!android/gradlew",
"!android/gradlew.bat",
"!android/local.properties",
"!**/__tests__",
"!**/__fixtures__",
"!**/__mocks__",
"!**/.*"
"LICENSE"
],
"scripts": {
"fmt": "cross-env SORT_IMPORTS=true prettier --write .",
@@ -52,15 +43,23 @@
"release": "GITHUB_TOKEN=$(gh auth token) release-it",
"release:dry": "release-it --dry-run"
},
"keywords": [
"react-native",
"ios",
"android"
],
"repository": {
"type": "git",
"url": "git+https://github.com/EthanShoeDev/fressh.git"
},
"bugs": {
"url": "https://github.com/EthanShoeDev/fressh/issues"
},
"keywords": [
"react-native",
"ssh",
"russh",
"uniffi",
"rust",
"expo",
"android",
"ios"
],
"author": "EthanShoeDev <13422990+EthanShoeDev@users.noreply.github.com> (https://github.com/EthanShoeDev)",
"publishConfig": {
"registry": "https://registry.npmjs.org/"

View File

@@ -24,7 +24,7 @@
"dependsOn": ["build:bob"],
},
"typecheck": {
"dependsOn": ["build:native"],
"dependsOn": ["build:native", "build:bob"],
},
// Special tasks

View File

@@ -0,0 +1,20 @@
# Exclude build and workspace caches not meant for publication
.turbo/
# Node modules should never be packed (npm ignores it by default, but explicit is fine)
node_modules/
# OS cruft
**/.DS_Store
# Keep dist outputs and sources; do not exclude them here
# dist/
# dist-internal/
# src/
# Common ignores that shouldn't ship
coverage/
.vscode/
.idea/
*.log
*.local

View File

@@ -1,5 +1,11 @@
# Changelog
## [0.0.7](https://github.com/EthanShoeDev/fressh/compare/@fressh/react-native-xtermjs-webview-v0.0.6...${npm.name}-v0.0.7) (2025-10-08)
## [0.0.6](https://github.com/EthanShoeDev/fressh/compare/@fressh/react-native-xtermjs-webview-v0.0.5...${npm.name}-v0.0.6) (2025-10-07)
## [0.0.5](https://github.com/EthanShoeDev/fressh/compare/@fressh/react-native-xtermjs-webview-v0.0.4...${npm.name}-v0.0.5) (2025-10-07)
## [0.0.4](https://github.com/EthanShoeDev/fressh/compare/@fressh/react-native-xtermjs-webview-v0.0.1...${npm.name}-v0.0.4) (2025-10-07)
## 0.0.1 (2025-10-07)

View File

@@ -11,28 +11,33 @@ defaults and a bridge for input and output.
pnpm add @fressh/react-native-xtermjs-webview react-native-webview
```
Peer dependencies: `react`, `react-dom` (for web), `react-native-webview`.
Peer dependencies: `react`, `react-native-webview`.
### Usage
See `apps/mobile` in this monorepo for a complete example. Basic usage:
For a complete production example, see the mobile app:
https://github.com/EthanShoeDev/fressh/tree/main/apps/mobile
Basic usage:
```tsx
import React, { useRef } from 'react';
import {
XtermJsWebView,
type XtermWebViewHandle,
} from '@fressh/react-native-xtermjs-webview';
import type { XtermWebViewHandle } from '@fressh/react-native-xtermjs-webview';
import { XtermJsWebView } from '@fressh/react-native-xtermjs-webview';
export function Terminal() {
const termRef = useRef<XtermWebViewHandle | null>(null);
return (
<XtermJsWebView
ref={termRef}
onInitialized={() =>
termRef.current?.write(new TextEncoder().encode('hello'))
}
onData={(input) => console.log('user input:', input)}
onInitialized={() => {
const hello = new TextEncoder().encode('hello');
termRef.current?.write(hello);
}}
onData={(input) => {
console.log('user input:', input);
}}
/>
);
}
@@ -60,8 +65,14 @@ transparency and debugging.
### Links
- Changelog: [`CHANGELOG.md`](./CHANGELOG.md)
- Contributing: see the monorepo guide at
[`../../CONTRIBUTING.md`](../../CONTRIBUTING.md)
- Example: `apps/mobile`
- Changelog:
[`CHANGELOG.md`](https://github.com/EthanShoeDev/fressh/blob/main/packages/react-native-xtermjs-webview/CHANGELOG.md)
- Contributing:
[`CONTRIBUTING.md`](https://github.com/EthanShoeDev/fressh/blob/main/CONTRIBUTING.md)
- Example app:
[`apps/mobile`](https://github.com/EthanShoeDev/fressh/tree/main/apps/mobile)
and source usage:
[`apps/mobile/src/app/(tabs)/shell/detail.tsx`](<https://github.com/EthanShoeDev/fressh/blob/main/apps/mobile/src/app/(tabs)/shell/detail.tsx>)
- API source:
[`src/index.tsx`](https://github.com/EthanShoeDev/fressh/blob/main/packages/react-native-xtermjs-webview/src/index.tsx)
- License: MIT

View File

@@ -1,20 +1,36 @@
{
"name": "@fressh/react-native-xtermjs-webview",
"private": false,
"version": "0.0.4",
"version": "0.0.7",
"license": "MIT",
"type": "module",
"files": [
"src",
"dist",
"dist-internal",
"!node_modules",
"!.turbo",
"*"
],
"exports": {
".": "./dist/index.js"
},
"repository": {
"type": "git",
"url": "git+https://github.com/EthanShoeDev/fressh.git"
},
"bugs": {
"url": "https://github.com/EthanShoeDev/fressh/issues"
},
"homepage": "https://github.com/EthanShoeDev/fressh#readme",
"keywords": [
"react-native",
"xterm",
"webview",
"terminal",
"ssh",
"expo",
"android",
"ios"
],
"scripts": {
"fmt": "cross-env SORT_IMPORTS=true prettier --write .",
"fmt:check": "cross-env SORT_IMPORTS=true prettier --check .",
@@ -33,7 +49,6 @@
},
"peerDependencies": {
"react": "19.1.0",
"react-dom": "19.1.0",
"react-native-webview": "13.15.0"
},
"devDependencies": {

10
pnpm-lock.yaml generated
View File

@@ -113,8 +113,8 @@ importers:
specifier: ~15.0.7
version: 15.0.7(expo@54.0.12)
expo-image:
specifier: ~3.0.8
version: 3.0.8(expo@54.0.12)(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))(react@19.1.0)
specifier: ~3.0.9
version: 3.0.9(expo@54.0.12)(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))(react@19.1.0)
expo-linking:
specifier: ~8.0.8
version: 8.0.8(expo@54.0.12)(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)
@@ -5336,8 +5336,8 @@ packages:
peerDependencies:
expo: '*'
expo-image@3.0.8:
resolution: {integrity: sha512-L83fTHVjvE5hACxUXPk3dpABteI/IypeqxKMeOAAcT2eB/jbqT53ddsYKEvKAP86eoByQ7+TCtw9AOUizEtaTQ==}
expo-image@3.0.9:
resolution: {integrity: sha512-GkPIjeqrODMBdpbRWOzbwiq8ztxjgq1rdZrnqwt/pzQavgXPlr4rW/7aigue9Jm5t5vebhMNAuc1A/XIXXqpcA==}
peerDependencies:
expo: '*'
react: '*'
@@ -15754,7 +15754,7 @@ snapshots:
dependencies:
expo: 54.0.12(@babel/core@7.28.3)(@expo/metro-runtime@6.1.1)(expo-router@6.0.10)(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)
expo-image@3.0.8(expo@54.0.12)(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))(react@19.1.0):
expo-image@3.0.9(expo@54.0.12)(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))(react@19.1.0):
dependencies:
expo: 54.0.12(@babel/core@7.28.3)(@expo/metro-runtime@6.1.1)(expo-router@6.0.10)(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)
react: 19.1.0