feat(pwa): experimental — add my.dash.board virtual host for secure PWA install
CI / Build & Test (push) Successful in 2m51s

Serve the dashboard over a local HTTPS virtual host (my.dash.board) so
Chrome treats it as a secure origin and shows the PWA install prompt.

- Add native-host/dashboard-server.js: bare-http1 static file server
  backed by bare-bundle assets in distribution mode, disk fallback in dev
- Add setLocalVirtualHost() to virtual-hosts.js; type:local entries are
  protected from removal and filtered out of saveState persistence
- Export setLocalVirtualHost from holesail-manager/index.js
- Start dashboard server in startup.js after proxies are ready and
  register my.dash.board as a local virtual host
- Stop dashboard server in message-router.js cleanup()
- Update manifest.webmanifest: start_url, id, scope → https://my.dash.board/
- Embed all extension/dashboard/ files as bare-bundle assets in
  build-distributable.js patchBundle() — no installer copy step needed
- Hide checkbox, hs:// URL, Reconnect, and Remove controls for built-in
  my.dash.board row in the virtual hosts table UI
This commit is contained in:
Raven Scott
2026-03-01 02:58:52 -05:00
parent cbc663cacb
commit a838c3a345
8 changed files with 255 additions and 14 deletions
+36
View File
@@ -36,6 +36,7 @@ const ROOT = path.join(__dirname, '..')
const NATIVE_HOST_DIR = path.join(ROOT, 'native-host')
const RELEASES_DIR = path.join(ROOT, 'releases')
const ENTRY = path.join(NATIVE_HOST_DIR, 'index.mjs')
const EXTENSION_DASHBOARD_DIR = path.join(ROOT, 'extension', 'dashboard')
const ALL_HOSTS = [
'darwin-arm64',
@@ -98,6 +99,24 @@ function getPlatformModule(host) {
}
}
/**
* Recursively list all files under a directory.
* @param {string} dir - Absolute path to the directory.
* @returns {string[]} Absolute paths to all files.
*/
function walkDir(dir) {
const results = []
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
const full = path.join(dir, entry.name)
if (entry.isDirectory()) {
results.push(...walkDir(full))
} else {
results.push(full)
}
}
return results
}
/**
* Patch bare-build's apple/sign.js to skip codesign when not on macOS.
* bare-build always calls `codesign --sign -` (ad-hoc) even when sign:false,
@@ -245,6 +264,23 @@ module.exports = EventEmitter;
bundle.write(eventsKey, Buffer.from(eventShim))
console.log(' Patched events module for node-rdpjs-2 compatibility')
}
// ── Embed dashboard static files as bundle assets ───────────────────────────
// The dashboard-server.js reads these via require.bundle().read('/dashboard/<rel>')
// at runtime, so no separate file copy step is needed in the installer.
if (fs.existsSync(EXTENSION_DASHBOARD_DIR)) {
const dashFiles = walkDir(EXTENSION_DASHBOARD_DIR)
let dashCount = 0
for (const file of dashFiles) {
const rel = path.relative(EXTENSION_DASHBOARD_DIR, file).replace(/\\/g, '/')
const key = '/dashboard/' + rel
bundle.write(key, fs.readFileSync(file), { asset: true })
dashCount++
}
console.log(` Embedded ${dashCount} dashboard assets into bundle`)
} else {
console.warn(' WARNING: extension/dashboard not found — dashboard assets not embedded')
}
}
async function build(hosts, doPackage) {