From 2b33da8e20328f6f0a1d4399792a2465835e39e1 Mon Sep 17 00:00:00 2001 From: EthanShoeDev <13422990+EthanShoeDev@users.noreply.github.com> Date: Tue, 7 Oct 2025 00:21:46 -0400 Subject: [PATCH] Better docs --- CONTRIBUTING.md | 70 +++++++- README.md | 79 ++++++++- apps/mobile/README.md | 64 ++----- apps/web/README.md | 57 ++---- .../react-native-uniffi-russh/.release-it.ts | 19 +- .../react-native-uniffi-russh/CONTRIBUTING.md | 162 ------------------ packages/react-native-uniffi-russh/README.md | 42 ++--- .../.release-it.ts | 5 +- .../react-native-xtermjs-webview/README.md | 126 +++++++------- 9 files changed, 251 insertions(+), 373 deletions(-) delete mode 100644 packages/react-native-uniffi-russh/CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 7eb4625..4e661c1 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,3 +1,71 @@ -nix develop .#default +## Contributing +### Monorepo layout + +- `apps/mobile`: Expo app (serves as the example for both packages) +- `apps/web`: Static site (Astro) +- `packages/react-native-uniffi-russh`: React Native native module exposing + russh via UniFFI +- `packages/react-native-xtermjs-webview`: React Native WebView-based xterm.js + renderer + +### Prerequisites + +- Node and pnpm installed +- Optional: Nix for dev shells (recommended) +- For native module work: Rust toolchain (rustup, cargo), Android/iOS build + tools + +With Nix: + +``` +nix develop .#default +``` + +Dev shell with android emulator included: + +``` nix develop .#android-emulator +``` + +### Setup + +1. Clone the repo +2. Install dependencies at the root: + +``` +pnpm install +``` + +3. Run the lint command: + +``` +pnpm exec turbo lint +``` + +### Develop + +- Mobile app: + +``` +cd apps/mobile +pnpm run android +``` + +### Releasing + +Each publishable package uses release-it. From the package directory: + +``` +pnpm run release +``` + +See the package CHANGELOGs for release notes: + +- `packages/react-native-uniffi-russh/CHANGELOG.md` +- `packages/react-native-xtermjs-webview/CHANGELOG.md` + +### CI + +Pull requests run the workflow in `.github/workflows/check.yml`. Please ensure +lint/typecheck/tests pass. diff --git a/README.md b/README.md index 67771c8..744c084 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,74 @@ -Fressh is a mobile SSH client that remains clean and simple while supporting -powerful features: +## Fressh -- Securely storing previous connections -- Configurable preset command buttons -- Configurable theme +[Fressh](https://fressh.dev/) is a mobile SSH client that remains clean and +simple while supporting powerful features. -Coming soon +[![ci](https://github.com/EthanShoeDev/fressh/actions/workflows/check.yml/badge.svg)](https://github.com/EthanShoeDev/fressh/actions/workflows/check.yml) +[![npm: @fressh/react-native-uniffi-russh](https://img.shields.io/npm/v/%40fressh%2Freact-native-uniffi-russh)](https://www.npmjs.com/package/@fressh/react-native-uniffi-russh) +[![npm: @fressh/react-native-xtermjs-webview](https://img.shields.io/npm/v/%40fressh%2Freact-native-xtermjs-webview)](https://www.npmjs.com/package/@fressh/react-native-xtermjs-webview) -- Fully accurate xterm emulation -- On-device LLM for command completion and output summarization +### Features + +- **Secure connection history**: Securely store previous connections +- **Command presets**: Configurable preset command buttons +- **Theming**: Configurable theme + +### Coming soon + +- ~~**xterm fidelity**: Fully accurate xterm emulation~~ Done! +- **On-device AI**: On-device LLM for command completion and output + summarization + +### Architecture + +The app is a monorepo with three main parts: + +- **`apps/mobile`**: The actual React Native Expo app. +- **`packages/react-native-uniffi-russh`**: A + [uniffi react native](https://github.com/jhugman/uniffi-bindgen-react-native) + binding package that exposes a native Rust module for + [russh](https://github.com/Eugeny/russh). +- **`packages/react-native-xtermjs-webview`**: A small library that instantiates + an Expo WebView preloaded with [xterm.js](https://xtermjs.org/). + +Both packages are published on npm if you want to use them in your own project: + +- [`@fressh/react-native-uniffi-russh`](https://www.npmjs.com/package/@fressh/react-native-uniffi-russh) +- [`@fressh/react-native-xtermjs-webview`](https://www.npmjs.com/package/@fressh/react-native-xtermjs-webview) + +### Why + +Mostly to practice with React Native, Expo, and Rust. There are a few more +developed SSH clients on the Google Play and iOS App Stores. + +Some of those try to lock features like one-off commands behind a paywall, so +this aims to be a free alternative. + +Another notable feature of the app is the WebView xterm.js renderer. Using this +as the render layer has a few benefits: + +- **Parity with VS Code**: We match the render behavior of VS Code +- **Consistent visuals**: The render layer visually matches on both iOS and + Android + +With that said, it is probably less performant than a native renderer, so it may +be replaced in the future. Implementing a +[Nitro view](https://nitro.margelo.com/docs/view-components) seems very +promising. + +### Changelogs + +- `apps/mobile`: [`apps/mobile/CHANGELOG.md`](./apps/mobile/CHANGELOG.md) +- `@fressh/react-native-uniffi-russh`: + [`packages/react-native-uniffi-russh/CHANGELOG.md`](./packages/react-native-uniffi-russh/CHANGELOG.md) +- `@fressh/react-native-xtermjs-webview`: + [`packages/react-native-xtermjs-webview/CHANGELOG.md`](./packages/react-native-xtermjs-webview/CHANGELOG.md) + +### Contributing + +We provide a Nix flake devshell to help get a working environment quickly. See +[`CONTRIBUTING.md`](./CONTRIBUTING.md) for details. + +### License + +MIT diff --git a/apps/mobile/README.md b/apps/mobile/README.md index ee7fb2b..587ebbe 100644 --- a/apps/mobile/README.md +++ b/apps/mobile/README.md @@ -1,60 +1,28 @@ -# Welcome to your Expo app 👋 +## Fressh Mobile (Expo) -This is an [Expo](https://expo.dev) project created with -[`create-expo-app`](https://www.npmjs.com/package/create-expo-app). +This is the Fressh mobile app built with Expo. It provides a clean SSH client +experience. packages: -## Get started +- `@fressh/react-native-uniffi-russh` +- `@fressh/react-native-xtermjs-webview` -1. Install dependencies - - ```bash - pnpm install - ``` - -2. Start the app - - ```bash - pnpm exec expo start - ``` - -In the output, you'll find options to open the app in a - -- [development build](https://docs.expo.dev/develop/development-builds/introduction/) -- [Android emulator](https://docs.expo.dev/workflow/android-studio-emulator/) -- [iOS simulator](https://docs.expo.dev/workflow/ios-simulator/) -- [Expo Go](https://expo.dev/go), a limited sandbox for trying out app - development with Expo - -You can start developing by editing the files inside the **app** directory. This -project uses [file-based routing](https://docs.expo.dev/router/introduction). - -## Get a fresh project - -When you're ready, run: +### Setup ```bash -pnpm run reset-project +pnpm install +pnpm exec expo start ``` -This command will move the starter code to the **app-example** directory and -create a blank **app** directory where you can start developing. +Open using Expo Go, an emulator, or a simulator. -## Learn more +For a high-level feature overview, see the root [`README.md`](../../README.md). -To learn more about developing your project with Expo, look at the following -resources: +### Development notes -- [Expo documentation](https://docs.expo.dev/): Learn fundamentals, or go into - advanced topics with our [guides](https://docs.expo.dev/guides). -- [Learn Expo tutorial](https://docs.expo.dev/tutorial/introduction/): Follow a - step-by-step tutorial where you'll create a project that runs on Android, iOS, - and the web. +- Edit files under `app/` (file-based routing) +- Ensure Android/iOS tooling is installed for native builds -## Join the community +### Links -Join our community of developers creating universal apps. - -- [Expo on GitHub](https://github.com/expo/expo): View our open source platform - and contribute. -- [Discord community](https://chat.expo.dev): Chat with Expo users and ask - questions. +- Main README: [`../../README.md`](../../README.md) +- Changelog: [`./CHANGELOG.md`](./CHANGELOG.md) diff --git a/apps/web/README.md b/apps/web/README.md index f12c47c..a15d891 100644 --- a/apps/web/README.md +++ b/apps/web/README.md @@ -1,48 +1,17 @@ -# Astro Starter Kit: Basics +## Fressh Web -```sh -pnpm create astro@latest -- --template basics +This is an Astro site used for the project website/docs. For project details, +see the root README. + +### Commands + +```bash +pnpm install +pnpm dev +pnpm build +pnpm preview ``` -> 🧑‍🚀 **Seasoned astronaut?** Delete this file. Have fun! +### Links -## 🚀 Project Structure - -Inside of your Astro project, you'll see the following folders and files: - -```text -/ -├── public/ -│ └── favicon.svg -├── src -│   ├── assets -│   │   └── astro.svg -│   ├── components -│   │   └── Welcome.astro -│   ├── layouts -│   │   └── Layout.astro -│   └── pages -│   └── index.astro -└── package.json -``` - -To learn more about the folder structure of an Astro project, refer to -[our guide on project structure](https://docs.astro.build/en/basics/project-structure/). - -## 🧞 Commands - -All commands are run from the root of the project, from a terminal: - -| Command | Action | -| :--------------------- | :----------------------------------------------- | -| `pnpm install` | Installs dependencies | -| `pnpm dev` | Starts local dev server at `localhost:4321` | -| `pnpm build` | Build your production site to `./dist/` | -| `pnpm preview` | Preview your build locally, before deploying | -| `pnpm astro ...` | Run CLI commands like `astro add`, `astro check` | -| `pnpm astro -- --help` | Get help using the Astro CLI | - -## 👀 Want to learn more? - -Feel free to check [our documentation](https://docs.astro.build) or jump into -our [Discord server](https://astro.build/chat). +- Main README: [`../../README.md`](../../README.md) diff --git a/packages/react-native-uniffi-russh/.release-it.ts b/packages/react-native-uniffi-russh/.release-it.ts index 20c86a3..3313ffa 100644 --- a/packages/react-native-uniffi-russh/.release-it.ts +++ b/packages/react-native-uniffi-russh/.release-it.ts @@ -1,6 +1,10 @@ -import type { Config } from 'release-it'; +import { type Config } from 'release-it'; export default { + npm: { + publish: true, + publishArgs: ['--access', 'public'], + }, git: { requireCleanWorkingDir: true, tagName: '${npm.name}-v${version}', @@ -10,20 +14,9 @@ export default { push: true, }, - // This one *does* publish to npm - npm: { - publish: true, - // pass flags you’d give to `npm publish` - publishArgs: ['--access', 'public'], - // (optional) skip npm’s own prepublish checks: - // skipChecks: true - }, - github: { release: true, releaseName: '${npm.name} v${version}', - // optional: attach build artifacts - // assets: ['dist/**'] }, plugins: { @@ -36,7 +29,7 @@ export default { hooks: { 'before:init': ['turbo run lint:check'], - 'before:npm:release': 'turbo run build:android build:ios', + 'after:bump': 'turbo run build', 'after:release': 'echo "Published ${npm.name} v${version} to npm"', }, } satisfies Config; diff --git a/packages/react-native-uniffi-russh/CONTRIBUTING.md b/packages/react-native-uniffi-russh/CONTRIBUTING.md deleted file mode 100644 index 759404a..0000000 --- a/packages/react-native-uniffi-russh/CONTRIBUTING.md +++ /dev/null @@ -1,162 +0,0 @@ -# Contributing - -Contributions are always welcome, no matter how large or small! - -We want this community to be friendly and respectful to each other. Please -follow it in all your interactions with the project. Before contributing, please -read the [code of conduct](./CODE_OF_CONDUCT.md). - -## Development workflow - -This project is a monorepo managed using -[Yarn workspaces](https://yarnpkg.com/features/workspaces). It contains the -following packages: - -- The library package in the root directory. -- An example app in the `example/` directory. - -To get started with the project, make sure you have the correct version of -[Node.js](https://nodejs.org/) installed. See the [`.nvmrc`](./.nvmrc) file for -the version used in this project. - -Run `yarn` in the root directory to install the required dependencies for each -package: - -```sh -yarn -``` - -> Since the project relies on Yarn workspaces, you cannot use -> [`npm`](https://github.com/npm/cli) for development without manually -> migrating. - -The [example app](/example/) demonstrates usage of the library. You need to run -it to test any changes you make. - -It is configured to use the local version of the library, so any changes you -make to the library's source code will be reflected in the example app. Changes -to the library's JavaScript code will be reflected in the example app without a -rebuild, but native code changes will require a rebuild of the example app. - -If you want to use Android Studio or XCode to edit the native code, you can open -the `example/android` or `example/ios` directories respectively in those -editors. To edit the Objective-C or Swift files, open -`example/ios/UniffiRusshExample.xcworkspace` in XCode and find the source files -at `Pods > Development Pods > react-native-uniffi-russh`. - -To edit the Java or Kotlin files, open `example/android` in Android studio and -find the source files at `react-native-uniffi-russh` under `Android`. - -You can use various commands from the root directory to work with the project. - -To start the packager: - -```sh -yarn example start -``` - -To run the example app on Android: - -```sh -yarn example android -``` - -To run the example app on iOS: - -```sh -yarn example ios -``` - -To confirm that the app is running with the new architecture, you can check the -Metro logs for a message like this: - -```sh -Running "UniffiRusshExample" with {"fabric":true,"initialProps":{"concurrentRoot":true},"rootTag":1} -``` - -Note the `"fabric":true` and `"concurrentRoot":true` properties. - -Make sure your code passes TypeScript and ESLint. Run the following to verify: - -```sh -yarn typecheck -yarn lint -``` - -To fix formatting errors, run the following: - -```sh -yarn lint --fix -``` - -Remember to add tests for your change if possible. Run the unit tests by: - -```sh -yarn test -``` - -### Commit message convention - -We follow the -[conventional commits specification](https://www.conventionalcommits.org/en) for -our commit messages: - -- `fix`: bug fixes, e.g. fix crash due to deprecated method. -- `feat`: new features, e.g. add new method to the module. -- `refactor`: code refactor, e.g. migrate from class components to hooks. -- `docs`: changes into documentation, e.g. add usage example for the module. -- `test`: adding or updating tests, e.g. add integration tests using detox. -- `chore`: tooling changes, e.g. change CI config. - -Our pre-commit hooks verify that your commit message matches this format when -committing. - -### Linting and tests - -[ESLint](https://eslint.org/), [Prettier](https://prettier.io/), -[TypeScript](https://www.typescriptlang.org/) - -We use [TypeScript](https://www.typescriptlang.org/) for type checking, -[ESLint](https://eslint.org/) with [Prettier](https://prettier.io/) for linting -and formatting the code, and [Jest](https://jestjs.io/) for testing. - -Our pre-commit hooks verify that the linter and tests pass when committing. - -### Publishing to npm - -We use [release-it](https://github.com/release-it/release-it) to make it easier -to publish new versions. It handles common tasks like bumping version based on -semver, creating tags and releases etc. - -To publish new versions, run the following: - -```sh -yarn release -``` - -### Scripts - -The `package.json` file contains various scripts for common tasks: - -- `yarn`: setup project by installing dependencies. -- `yarn typecheck`: type-check files with TypeScript. -- `yarn lint`: lint files with ESLint. -- `yarn test`: run unit tests with Jest. -- `yarn example start`: start the Metro server for the example app. -- `yarn example android`: run the example app on Android. -- `yarn example ios`: run the example app on iOS. - -### Sending a pull request - -> **Working on your first pull request?** You can learn how from this _free_ -> series: -> [How to Contribute to an Open Source Project on GitHub](https://app.egghead.io/playlists/how-to-contribute-to-an-open-source-project-on-github). - -When you're sending a pull request: - -- Prefer small pull requests focused on one change. -- Verify that linters and tests are passing. -- Review the documentation to make sure it looks good. -- Follow the pull request template when opening a pull request. -- For pull requests that change the API or implementation, discuss with - maintainers first by opening an issue. diff --git a/packages/react-native-uniffi-russh/README.md b/packages/react-native-uniffi-russh/README.md index 87b3dd7..cc0b2b0 100644 --- a/packages/react-native-uniffi-russh/README.md +++ b/packages/react-native-uniffi-russh/README.md @@ -1,34 +1,26 @@ -# react-native-uniffi-russh +## @fressh/react-native-uniffi-russh -Uniffi bindings for russh +React Native bindings (via UniFFI) for the Rust SSH library +[russh](https://github.com/Eugeny/russh). -## Installation +[![npm version](https://img.shields.io/npm/v/%40fressh%2Freact-native-uniffi-russh)](https://www.npmjs.com/package/@fressh/react-native-uniffi-russh) -```sh -npm install react-native-uniffi-russh +### Install + +```bash +pnpm add @fressh/react-native-uniffi-russh ``` -## Usage +Peer dependencies (you manage): `react`, `react-native`. -```js -import { multiply } from 'react-native-uniffi-russh'; +### 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`. -const result = multiply(3, 7); -``` +### Links -## Contributing - -- [Development workflow](CONTRIBUTING.md#development-workflow) -- [Sending a pull request](CONTRIBUTING.md#sending-a-pull-request) -- [Code of conduct](CODE_OF_CONDUCT.md) - -## License - -MIT - ---- - -Made with -[create-react-native-library](https://github.com/callstack/react-native-builder-bob) +- Changelog: [`CHANGELOG.md`](./CHANGELOG.md) +- Contributing: see the monorepo guide at + [`../../CONTRIBUTING.md`](../../CONTRIBUTING.md) +- License: MIT diff --git a/packages/react-native-xtermjs-webview/.release-it.ts b/packages/react-native-xtermjs-webview/.release-it.ts index 7bb0549..6b0114a 100644 --- a/packages/react-native-xtermjs-webview/.release-it.ts +++ b/packages/react-native-xtermjs-webview/.release-it.ts @@ -1,7 +1,6 @@ import { type Config } from 'release-it'; export default { - // Avoid double-publish from the built-in npm plugin npm: { publish: true, publishArgs: ['--access', 'public'], @@ -18,8 +17,6 @@ export default { github: { release: true, releaseName: '${npm.name} v${version}', - // optional: attach build artifacts - // assets: ['dist/**'] }, plugins: { @@ -32,7 +29,7 @@ export default { hooks: { 'before:init': ['turbo run lint:check'], - 'before:github:release': 'turbo run build', + 'after:bump': 'turbo run build', 'after:release': 'echo "Published ${npm.name} v${version} to npm"', }, } satisfies Config; diff --git a/packages/react-native-xtermjs-webview/README.md b/packages/react-native-xtermjs-webview/README.md index a03c0c5..220d661 100644 --- a/packages/react-native-xtermjs-webview/README.md +++ b/packages/react-native-xtermjs-webview/README.md @@ -1,77 +1,67 @@ -# React + TypeScript + Vite +## @fressh/react-native-xtermjs-webview -This template provides a minimal setup to get React working in Vite with HMR and -some ESLint rules. +React Native WebView that embeds [xterm.js](https://xtermjs.org/) with sensible +defaults and a bridge for input and output. -Currently, two official plugins are available: +[![npm version](https://img.shields.io/npm/v/%40fressh%2Freact-native-xtermjs-webview)](https://www.npmjs.com/package/@fressh/react-native-xtermjs-webview) -- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) - uses [Babel](https://babeljs.io/) for Fast Refresh -- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) - uses [SWC](https://swc.rs/) for Fast Refresh +### Install -## Expanding the ESLint configuration - -If you are developing a production application, we recommend updating the -configuration to enable type-aware lint rules: - -```js -export default tseslint.config([ - globalIgnores(['dist']), - { - files: ['**/*.{ts,tsx}'], - extends: [ - // Other configs... - - // Remove tseslint.configs.recommended and replace with this - ...tseslint.configs.recommendedTypeChecked, - // Alternatively, use this for stricter rules - ...tseslint.configs.strictTypeChecked, - // Optionally, add this for stylistic rules - ...tseslint.configs.stylisticTypeChecked, - - // Other configs... - ], - languageOptions: { - parserOptions: { - project: ['./tsconfig.node.json', './tsconfig.app.json'], - tsconfigRootDir: import.meta.dirname, - }, - // other options... - }, - }, -]); +```bash +pnpm add @fressh/react-native-xtermjs-webview react-native-webview ``` -You can also install -[eslint-plugin-react-x](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-x) -and -[eslint-plugin-react-dom](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-dom) -for React-specific lint rules: +Peer dependencies: `react`, `react-dom` (for web), `react-native-webview`. -```js -// eslint.config.js -import reactX from 'eslint-plugin-react-x'; -import reactDom from 'eslint-plugin-react-dom'; +### Usage -export default tseslint.config([ - globalIgnores(['dist']), - { - files: ['**/*.{ts,tsx}'], - extends: [ - // Other configs... - // Enable lint rules for React - reactX.configs['recommended-typescript'], - // Enable lint rules for React DOM - reactDom.configs.recommended, - ], - languageOptions: { - parserOptions: { - project: ['./tsconfig.node.json', './tsconfig.app.json'], - tsconfigRootDir: import.meta.dirname, - }, - // other options... - }, - }, -]); +See `apps/mobile` in this monorepo for a complete example. Basic usage: + +```tsx +import React, { useRef } from 'react'; +import { + XtermJsWebView, + type XtermWebViewHandle, +} from '@fressh/react-native-xtermjs-webview'; + +export function Terminal() { + const termRef = useRef(null); + return ( + + termRef.current?.write(new TextEncoder().encode('hello')) + } + onData={(input) => console.log('user input:', input)} + /> + ); +} ``` + +#### Props + +- `webViewOptions`: subset of `react-native-webview` props (sane defaults + applied) +- `xtermOptions`: partial `@xterm/xterm` options (theme, font, scrollback, etc.) +- `onInitialized`: called when the terminal is ready +- `onData(str)`: emits user keystrokes +- `size`: `{ cols, rows }` to set terminal size +- `autoFit`: auto-fit after important changes (default: true) + +#### Ref API + +- `write(bytes)`, `writeMany([bytes...])`, `flush()` +- `clear()`, `focus()`, `fit()`, `resize({ cols, rows })` + +### Publishing contents + +This package intentionally publishes both `src/` and built `dist/` artifacts for +transparency and debugging. + +### Links + +- Changelog: [`CHANGELOG.md`](./CHANGELOG.md) +- Contributing: see the monorepo guide at + [`../../CONTRIBUTING.md`](../../CONTRIBUTING.md) +- Example: `apps/mobile` +- License: MIT