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

8.7 KiB
Raw Blame History

Contributing

This document covers the development workflow, build system, project structure, and how to extend the codebase.

Prerequisites

  • Node.js v18 or later (for build scripts and dev tooling)
  • 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:

npm install

Install native host dependencies:

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

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)

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

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:

const result = await sendToNative('myNewCommand', { someParam: 'value' });
if (result && result.ok) {
  // handle success
}

Or via chrome.runtime.sendMessage directly from the background:

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://extensionsInspect views: service worker.

Dashboard logs

The Logs page in the dashboard shows all native host log output in real time.