CI / Build & Test (push) Successful in 2m54s
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)
209 lines
8.7 KiB
Markdown
209 lines
8.7 KiB
Markdown
# 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 `a–p` 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.
|