Files
holesail-browser/docs/CONTRIBUTING.md
T
Raven Scott f1e98a7edd
CI / Build & Test (push) Successful in 2m54s
docs: add CONTRIBUTING.md, CHANGELOG.md, and JSDoc to entire codebase
Add docs/CONTRIBUTING.md covering the build system, dev workflow, all
npm scripts, how to add new native host message types, code style, and
debugging guidance.

Add CHANGELOG.md at the project root documenting all features and fixes
across the 1.0.0 release.

Add JSDoc (@param, @returns) to all previously undocumented exported
functions across 35 JS files:
- native-host/holesail-manager/ (index, virtual-hosts, service-tunnels,
  servers, port-allocator)
- native-host top-level managers (startup, connect-proxy, https-proxy,
  certificate-authority, ssh-manager, rdp-manager)
- extension/background/ (logs, native-messaging, proxy, message-router)
- extension/dashboard/core/ (utils, navigation, init)
- extension/dashboard/ui/ (modal, toast, state-tag)
- extension/dashboard/pages/ (all 10 page files)
- extension/dashboard/refresh.js, events.js
- extension/dashboard/data/hostname-validator.js
- scripts/ (build-host, run-install)
2026-03-01 00:40:53 -05:00

209 lines
8.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Contributing
This document covers the development workflow, build system, project structure, and how to extend the codebase.
## Prerequisites
- [Node.js](https://nodejs.org/) v18 or later (for build scripts and dev tooling)
- [Bare](https://github.com/nicolo-ribaudo/bare) runtime — the native host runs under Bare, not Node.js
- A Chromium-based browser or Firefox for testing the extension
Install root-level dev dependencies:
```bash
npm install
```
Install native host dependencies:
```bash
cd native-host && npm install
```
## Repository layout
```
Holesail-Browser/
├── extension/ # Browser extension (MV3, Chrome + Firefox)
│ ├── background.js # Service worker entry point
│ ├── manifest.json # Extension manifest
│ ├── background/ # Background module files
│ └── dashboard/ # Dashboard UI (HTML + JS modules)
├── native-host/ # Native host process (runs under Bare runtime)
│ ├── index.mjs # Entry point
│ ├── host/ # Startup, routing, logging, paths
│ ├── holesail-manager/ # Tunnel lifecycle sub-modules
│ └── ... # Proxy, CA, SSH, RDP, backup managers
├── scripts/ # Build and install scripts (Node.js)
├── docs/ # Documentation
├── releases/ # Build output (generated, not committed)
└── package.json # Root build scripts
```
## Running from source
### 1. Build the native host launcher
```bash
npm run build:host
```
This runs `scripts/build-host.js`, which generates `native-host/holesail-browser-host` — a small shell script that invokes `bare native-host/index.mjs`. The script auto-detects the `bare` binary location.
### 2. Install (register the native messaging host)
```bash
npm run setup
```
This runs `scripts/run-install.js`, which delegates to `scripts/install.sh` (macOS/Linux) or `scripts/install.ps1` (Windows). The installer:
1. Copies the native host files to `~/.holesail-browser/`
2. Writes the native messaging manifest (`com.holesail.browser.json`) to the OS-specific location Chrome/Firefox reads
3. Generates a unique extension ID via `scripts/generate-extension-id.js`
### 3. Load the extension in Chrome
1. Open `chrome://extensions`
2. Enable **Developer mode**
3. Click **Load unpacked** and select the `extension/` directory
### 4. Load the extension in Firefox
1. Open `about:debugging#/runtime/this-firefox`
2. Click **Load Temporary Add-on**
3. Select `extension/manifest.json`
## npm scripts reference
| Script | Command | Description |
|---|---|---|
| `npm run setup` | `node scripts/run-install.js` | Install native host and register native messaging |
| `npm run build:host` | `node scripts/build-host.js` | Generate the `holesail-browser-host` launcher script |
| `npm run build` | alias for `build:host` | Default build |
| `npm run pack` | `node scripts/pack-extension.js` | Pack extension into `.zip` and `.xpi` for distribution |
| `npm run build:dist` | `node scripts/build-distributable.js` | Build standalone binary for the current host platform |
| `npm run build:dist:all` | `...--all` | Build standalone binaries for all 5 platforms |
| `npm run build:dist:mac` | `...--host darwin-arm64 --host darwin-x64` | macOS only |
| `npm run build:dist:linux` | `...--host linux-arm64 --host linux-x64` | Linux only |
| `npm run build:dist:win` | `...--host win32-x64` | Windows only |
| `npm run build:dist:package` | `...--all --package` | All platforms + zip archives |
## Scripts in detail
### `scripts/build-host.js`
Generates `native-host/holesail-browser-host`, a bash launcher that invokes `bare index.mjs`. Searches for the `bare` binary via `which bare`, then common Homebrew paths, then falls back to a sibling of the current `node` binary.
### `scripts/build-distributable.js`
Produces self-contained native host binaries using the `bare-pack` + `bare-build` pipeline:
1. `bare-pack` bundles the entire JS module graph (with optional-dep stubs) into a single `.bundle` file
2. `bare-build` embeds the bundle into a pre-built Bare runtime binary for the target platform
Output goes to `releases/<platform>/holesail-browser-host[.exe]`. Supported targets: `darwin-arm64`, `darwin-x64`, `linux-arm64`, `linux-x64`, `win32-x64`.
### `scripts/pack-extension.js`
Reads the version from `extension/manifest.json` and creates `releases/Holesail-Browser-<version>.zip` (Chrome) and `.xpi` (Firefox) by archiving the `extension/` directory, excluding `.map` files.
### `scripts/generate-extension-id.js`
Generates a unique Chrome extension ID (RSA-2048 public key → SHA-256 → first 16 bytes → base-26 `ap` encoding) and a unique Firefox ID (`holesail-browser-<8 random hex bytes>@example.org`). Updates both `extension/manifest.json` and `com.holesail.browser.json`. Run automatically by the installer so each installation gets its own ID.
### `scripts/run-install.js`
Cross-platform launcher: spawns `install.sh` on Unix or `install.ps1` on Windows via PowerShell with `-ExecutionPolicy Bypass`. Inherits stdio and forwards the exit code.
### `scripts/install.sh` / `scripts/install.ps1`
Full install scripts that:
1. Detect platform and architecture
2. Download or copy the native host binary to `~/.holesail-browser/`
3. Write the native messaging manifest to the correct OS path
4. Optionally download the extension package
## Adding a new native host message type
The extension communicates with the native host via typed JSON messages. To add a new command:
### 1. Add the handler in `native-host/host/message-router.js`
```js
case 'myNewCommand': {
debugLog('myNewCommand: payload=', JSON.stringify(payload));
const result = await someManager.doSomething(payload);
reply(result);
break;
}
```
All handlers receive `payload` (the message payload object) and call `reply(result)` to send the response back to the extension. Async handlers must `await` before calling `reply`.
### 2. Implement the logic in the appropriate manager
- Tunnel operations → `native-host/holesail-manager/`
- SSH sessions → `native-host/ssh-manager.js`
- RDP/VNC sessions → `native-host/rdp-manager.js`
- Certificates → `native-host/certificate-authority.js`
- Backups → `native-host/backup-manager.js`
### 3. Call the command from the extension
In any dashboard JS file, use `sendToNative`:
```js
const result = await sendToNative('myNewCommand', { someParam: 'value' });
if (result && result.ok) {
// handle success
}
```
Or via `chrome.runtime.sendMessage` directly from the background:
```js
chrome.runtime.sendMessage({
target: 'holesail-native',
action: 'send',
payload: { type: 'myNewCommand', payload: { someParam: 'value' } }
}, (response) => { void chrome.runtime.lastError; /* ... */ });
```
### 4. Document the new message type in `docs/NATIVE-HOST.md`
Add an entry under the Commands section with the request payload shape, response shape, and any notes on optional fields.
## Code style
- **No build step for the extension** — the dashboard JS files are loaded directly by the browser in dependency order (see the `<script>` tags at the bottom of `dashboard.html`). There is no bundler or transpiler for the extension.
- **Native host uses CommonJS** (`require`/`module.exports`) with the exception of the entry point `index.mjs` which uses static `import` for Bare compatibility.
- **JSDoc style** — use `/** ... */` blocks with `@param {type} name`, `@returns {type}`, and `@throws {Error}` tags where relevant.
- **Error handling** — all async functions should catch errors and return `{ ok: false, error: e.message }` rather than throwing, so the extension always gets a structured response.
- **Timers and listeners** — always store timer IDs and remove event listeners in cleanup paths to avoid leaks (see `docs/ARCHITECTURE.md` for the resource management patterns used throughout).
## Testing
There is currently no automated test suite. Manual testing workflow:
1. Make changes to the native host source
2. Run `npm run build:host` to regenerate the launcher
3. Reload the extension in the browser (`chrome://extensions` → reload button)
4. The native host process is restarted automatically on the next message from the extension
For distributable builds, run `npm run build:dist` and replace the binary in `~/.holesail-browser/`.
## Debugging
### Native host logs
The native host writes logs to `~/.holesail-browser/holesail-browser.log` (macOS/Linux) or `%APPDATA%\holesail-browser\holesail-browser.log` (Windows). Set `DEBUG_VERBOSE = true` in `extension/background.js` to enable verbose logging from the extension side.
### Extension background logs
Open the service worker DevTools from `chrome://extensions`**Inspect views: service worker**.
### Dashboard logs
The Logs page in the dashboard shows all native host log output in real time.