aboutsummaryrefslogtreecommitdiffstats
path: root/packaging
diff options
context:
space:
mode:
Diffstat (limited to 'packaging')
-rw-r--r--packaging/win/README.md4
-rw-r--r--packaging/win/build-node-runtime.ps16
-rw-r--r--packaging/win/electron-builder.msix.yml82
-rw-r--r--packaging/win/meshbay-node.spec25
-rw-r--r--packaging/win/node-entry.py17
5 files changed, 79 insertions, 55 deletions
diff --git a/packaging/win/README.md b/packaging/win/README.md
index b84ba98..eda728e 100644
--- a/packaging/win/README.md
+++ b/packaging/win/README.md
@@ -15,7 +15,9 @@ Linux). `meshbay-common` rides along inside the node runtime.
│ ├─ service.ps1 install/remove/status/run/end the boot-time task
│ ├─ service-mode.ps1 elevated helper: service.ps1 + firewall.ps1 in one UAC prompt
│ └─ node-runtime\
-│ ├─ meshbay-node.exe frozen daemon (PyInstaller onedir)
+│ ├─ meshbay-node.exe frozen daemon and CLI (PyInstaller onedir)
+│ ├─ meshbay-nodew.exe the same daemon without a console (the Store
+│ │ package's startup task runs it)
│ ├─ _internal\ … its Python + deps (aiortc, av, aioquic, …)
│ ├─ ffmpeg.exe, ffprobe.exe bundled by default, see Video (ffmpeg) below
│ ├─ av*.dll, swscale/swresample*.dll what those two link against
diff --git a/packaging/win/build-node-runtime.ps1 b/packaging/win/build-node-runtime.ps1
index 42d1faa..aa5e759 100644
--- a/packaging/win/build-node-runtime.ps1
+++ b/packaging/win/build-node-runtime.ps1
@@ -105,8 +105,10 @@ finally {
}
$frozen = Join-Path $pyiDist "meshbay-node"
-if (-not (Test-Path (Join-Path $frozen "meshbay-node.exe"))) {
- throw "PyInstaller did not produce meshbay-node.exe at $frozen"
+foreach ($name in "meshbay-node.exe", "meshbay-nodew.exe") {
+ if (-not (Test-Path (Join-Path $frozen $name))) {
+ throw "PyInstaller did not produce $name at $frozen"
+ }
}
# --- 3b. licences ----------------------------------------------------
diff --git a/packaging/win/electron-builder.msix.yml b/packaging/win/electron-builder.msix.yml
index d3adad6..577e039 100644
--- a/packaging/win/electron-builder.msix.yml
+++ b/packaging/win/electron-builder.msix.yml
@@ -1,8 +1,22 @@
-# Standalone electron-builder config for the "MSIX" Windows target: same
-# feature set as Full (bundled node + ffmpeg), packaged for Microsoft Store
-# submission instead of NSIS. The package carries none of installer.nsh's
-# elevation logic: an AppX/MSIX install never elevates, by design. What is
-# still unverified here is called out at each declaration below.
+# Standalone electron-builder config for the "MSIX" Windows target: the
+# bundled node + ffmpeg, packaged for Microsoft Store submission instead of
+# NSIS.
+#
+# What the NSIS build does with scripts -- firewall rules, a Startup-folder
+# launcher, a boot task, a PATH entry -- this package DECLARES in its manifest,
+# and Windows creates it at install, carries it across updates and removes it
+# with the package, all without an administrator prompt. Scripts could not do
+# that job here: everything they write names the install folder, and a Store
+# install lives in C:\Program Files\WindowsApps\MeshBay.MeshBay_<version>_...,
+# which each update deletes. Measured on a real install (2026-10-08):
+# - firewall: build/appx-manifest.xml declares the node's rules;
+# - at sign-in: build/appx-extensions.xml declares a startup task, off by
+# default, that the node's CLI switches (`meshbay-node autostart`),
+# for the app's Node page and a terminal alike;
+# - `meshbay-node` in a terminal: an execution alias, also in that file;
+# - at boot, before anyone signs in: not offered. It needs a boot task,
+# created elevated and left behind on uninstall; that is the .exe
+# installer's job.
#
# Deliberately NOT layered onto package.json's `build` field, same reasoning
# as electron-builder.light.yml: --config reads ONLY this file, so nothing
@@ -42,33 +56,15 @@ win:
icon: build/icon.ico
artifactName: "MeshBay-${version}.${ext}"
extraResources:
- # Same bundle as Full (package.json's own build.win.extraResources) --
- # this target drops NSIS, not the node/ffmpeg runtime or the two service
- # scripts. service-mode.ps1 in particular still works unmodified: it is
- # invoked from main.js's winElevateServiceMode() on demand, from the
- # running (unelevated) app, not from an installer step -- that path
- # already existed before this target did (see "the other door" comment
- # in src/main.js) and needs nothing new here beyond the file being
- # present to find.
+ # The node runtime as Full ships it, both executables: meshbay-node.exe
+ # (CLI, and what the app starts) and meshbay-nodew.exe (no console, for
+ # the startup task). No scripts: firewall.ps1, the service scripts and
+ # ensure-node-path.ps1 are the manifest's job here (see the top of this
+ # file), and main.js offers no service mode without service-mode.ps1.
- from: node-runtime
to: node-runtime
filter:
- "**/*"
- - from: ../../packaging/win/firewall.ps1
- to: firewall.ps1
- - from: ../../packaging/win/service.ps1
- to: service.ps1
- - from: ../../packaging/win/service-mode.ps1
- to: service-mode.ps1
- # Full's own installer adds node-runtime\ to the per-user PATH at install
- # time (build/installer.nsh's customInstall) -- an unelevated HKCU write,
- # never blocked by the no-elevation rule this target is built around, but
- # MSIX has no install-time hook at all to run it from. main.js's
- # winEnsureNodeOnPath() calls this itself on first launch instead
- # (found missing by actually sideloading a build and checking, not
- # anticipated in the original plan).
- - from: ../../packaging/win/ensure-node-path.ps1
- to: ensure-node-path.ps1
# The application's own licence, beside the app (Electron's LICENSE and
# LICENSES.chromium.html are put next to the exe by electron-builder).
- from: ../../LICENSE
@@ -99,26 +95,14 @@ appx:
- it-IT
- nl-NL
- pl-PL
- # Both are the "common" (general, non-restricted) capability group per
- # app-builder-lib's AppxCapabilities.js -- no special Store justification
- # needed, unlike the `rescap`-namespaced restricted ones. Matches
- # firewall.ps1's own rules, which are `-Profile Any` (private AND public
- # network). Whether Windows Firewall actually auto-exempts a full-trust
- # packaged app on the strength of these declarations -- eliminating the
- # elevation firewall.ps1 exists for entirely -- is an open item: verify
- # live before relying on it, the declaration alone only proves the
- # manifest is well-formed.
- capabilities:
- - internetClientServer
- - privateNetworkClientServer
- # windows.startupTask, the MSIX-native equivalent of the NSIS "at sign in"
- # mode's Startup-folder .vbs (main.js's WIN_STARTUP_VBS) -- but pointed at
- # the node daemon, not the Electron shell, which is what `addAutoLaunchExtension:
- # true` would do instead (it always targets the package's own main
- # executable, per AppxTarget.js's `executable` macro -- there is no config
- # switch to point it at a different bundled exe). build/appx-extensions.xml
- # declares that extension by hand for exactly this reason. Whether
- # Windows actually launches a *non-primary* bundled exe through this
- # mechanism is the other open item -- untested until sideloaded.
+ # Execution aliases need Windows 10 1709; 1809 is the oldest still
+ # serviced. electron-builder's default (10.0.14316.0, for both) predates both.
+ minVersion: 10.0.17763.0
+ maxVersionTested: 10.0.26100.0
+ # The stock template plus the package-level firewall rules.
+ customManifestPath: build/appx-manifest.xml
+ # The startup task and the execution alias. Not addAutoLaunchExtension:
+ # that one always starts the package's main executable, the Electron shell,
+ # where "at sign-in" means the node.
customExtensionsPath: build/appx-extensions.xml
showNameOnTiles: false
diff --git a/packaging/win/meshbay-node.spec b/packaging/win/meshbay-node.spec
index 3261778..a1173a2 100644
--- a/packaging/win/meshbay-node.spec
+++ b/packaging/win/meshbay-node.spec
@@ -153,8 +153,33 @@ exe = EXE(
icon="../../packages/meshbay-client/build/icon.ico",
version=_version_info,
)
+# The same daemon without a console, for what starts it with nobody watching:
+# the Store package's startup task runs its executable as is, and a console
+# executable opened a window whose close button killed the node. The CLI stays
+# meshbay-node.exe, which has to print. Same entry point and archive, same
+# _internal\ beside both (pythonw.exe beside python.exe).
+exe_windowless = EXE(
+ pyz,
+ a.scripts,
+ [],
+ exclude_binaries=True,
+ name="meshbay-nodew",
+ debug=False,
+ bootloader_ignore_signals=False,
+ strip=False,
+ upx=False,
+ console=False,
+ disable_windowed_traceback=False,
+ argv_emulation=False,
+ target_arch=None,
+ codesign_identity=None,
+ entitlements_file=None,
+ icon="../../packages/meshbay-client/build/icon.ico",
+ version=_version_info,
+)
coll = COLLECT(
exe,
+ exe_windowless,
a.binaries,
a.datas,
strip=False,
diff --git a/packaging/win/node-entry.py b/packaging/win/node-entry.py
index 6fadad7..a502a37 100644
--- a/packaging/win/node-entry.py
+++ b/packaging/win/node-entry.py
@@ -1,12 +1,23 @@
"""PyInstaller entry point for the bundled Windows node daemon.
`meshbay_node.daemon:main` is a module function; PyInstaller freezes a script.
-This is that script — nothing more. The frozen binary is `meshbay-node.exe`,
+This is that script. The frozen binary is `meshbay-node.exe`,
relocatable, and is what the desktop client spawns and what the W3 autostart
-launcher points at (`meshbay_node.platform._node_exe`).
+launcher points at (`meshbay_node.platform._node_exe`). `meshbay-nodew.exe` is
+the same script built without a console (meshbay-node.spec).
"""
-from meshbay_node.daemon import main
+import os
+import sys
+
+# meshbay-nodew.exe, the build without a console, starts with no stdio at all
+# (sys.stdout and sys.stderr are None), and a library that writes to either or
+# asks whether it is a terminal would raise. The daemon logs to node.log.
+for _name in ("stdout", "stderr"):
+ if getattr(sys, _name) is None:
+ setattr(sys, _name, open(os.devnull, "w", encoding="utf-8"))
+
+from meshbay_node.daemon import main # noqa: E402
if __name__ == "__main__":
main()