aboutsummaryrefslogtreecommitdiffstats
path: root/packaging/win/electron-builder.msix.yml
diff options
context:
space:
mode:
authorChristophe Besson <cbesson@gmail.com>2026-09-11 17:47:42 +0200
committerChristophe Besson <cbesson@gmail.com>2026-09-11 17:51:51 +0200
commitedbff1768054afa80efda721cd1011b29c7fe355 (patch)
tree4ae3d27877bd08e92cc0981b80bcc9502e82bff5 /packaging/win/electron-builder.msix.yml
parentd4935aa2a28fcbab8c3556e3532e53667092701e (diff)
downloadmeshbay-edbff1768054afa80efda721cd1011b29c7fe355.tar.gz
feat(packaging): an MSIX target for Microsoft Store submission
Store certification of the NSIS "MSI/EXE" submission failed on three checks (silent-install verification, Add/Remove Programs entry, bundleware check) -- traced and reproduced live to one cause: SmartScreen blocks an unsigned, internet-downloaded installer at the shell layer before Microsoft's own unattended validation bot ever gets to run it. MSIX sidesteps this class of failure entirely: submitted through the Store's native pipeline, there is no browser-download-then-launch step for SmartScreen to intercept, and Microsoft signs the package itself at publish time -- free, and specific to this submission type (Trusted Signing remains a paid service for the MSI/EXE path). Full plan and findings: C:\Users\admin\devel\msix-installer.md (out of repo). electron-builder.msix.yml carries the same bundle as Full (node runtime, ffmpeg, both service scripts) -- an AppX/MSIX install never elevates, by design, but that changes only *when* the two elevated operations can run, not whether the daemon ships. No main.js changes were needed: the on-demand elevation path for service-mode (winElevateServiceMode(), driven from the Node page) already existed for a different reason and depends only on service-mode.ps1 being present as an extraResource, true for any packaged Windows target. identityName/publisher/publisherDisplayName are the real values from Partner Center's app-identity reservation, not placeholders. build-win-msix.ps1 points electron-builder at the system Windows 10 SDK (auto-detected) instead of letting it download its own bundled copy -- that download's 7z extraction creates symlinks this target never uses and fails without SeCreateSymbolicLinkPrivilege, reproduced on this machine. build/appx/ carries the four tile images the AppX target requires regardless of showNameOnTiles, generated once from the existing app icon (see that directory's README) since the system-SDK redirect has no vendor samples to fall back to. build/appx-extensions.xml declares windows.startupTask by hand rather than via electron-builder's addAutoLaunchExtension, which always targets the Electron shell -- this points at the bundled node binary instead, matching what "starts at sign in" already means for Full. Verified live via a signed sideload install (self-signed test cert, cleaned up after): the package installs and the app runs correctly. One finding worth carrying forward -- the declared network capabilities (internetClientServer, privateNetworkClientServer) do not create any firewall exemption for this app, most likely because automatic capability-based exemption is an AppContainer-sandbox property and this app deliberately runs full-trust, outside any sandbox. Not a regression: no install-time elevation was possible either way, so the cost is the same one-time OS firewall prompt firewall.ps1's own header already documents as its fallback today. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Diffstat (limited to 'packaging/win/electron-builder.msix.yml')
-rw-r--r--packaging/win/electron-builder.msix.yml113
1 files changed, 113 insertions, 0 deletions
diff --git a/packaging/win/electron-builder.msix.yml b/packaging/win/electron-builder.msix.yml
new file mode 100644
index 0000000..4026d46
--- /dev/null
+++ b/packaging/win/electron-builder.msix.yml
@@ -0,0 +1,113 @@
+# 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. See C:\Users\admin\devel\msix-installer.md for
+# the plan this implements -- read that first, especially §4 (why the
+# installer can carry none of installer.nsh's elevation logic: an AppX/MSIX
+# install never elevates, by design) and §8 (what is still unverified here).
+#
+# Deliberately NOT layered onto package.json's `build` field, same reasoning
+# as electron-builder.light.yml: --config reads ONLY this file, so nothing
+# here can accidentally inherit or merge with Full's `nsis`/signing config.
+#
+# electron-builder's target key for this is `appx`, not `msix` -- this
+# version (app-builder-lib's AppxTarget.js, checked against the installed
+# ^26.15.3) has no separate `msix` target. It still produces a package
+# Partner Center's MSIX upload flow accepts; the mismatch is a naming
+# artifact of the tool, not a statement about which container format comes
+# out. Re-check this against whatever version is installed if it is ever
+# bumped -- do not assume the target name from memory.
+#
+# No CSC (code-signing cert) is configured for this target, and that is
+# correct, not an oversight: per app-builder-lib's own
+# windowsSignToolManager.js (computePublisherName), an AppX target built
+# with no certificate configured is logged as "Windows Store only build" and
+# left unsigned, with `publisher` written into the manifest as-is. Microsoft
+# signs the package itself at publish time (msix-installer.md §3) -- signing
+# it here first would be pointless work, not extra safety.
+
+appId: org.meshbay.client
+productName: MeshBay
+
+directories:
+ # Full's own build lives in dist/, Light's in dist-light/ -- a third,
+ # separate output dir so no two targets ever race on or clobber each
+ # other's files.
+ output: dist-msix
+
+files:
+ - src/**
+ - ui/**
+
+win:
+ target: appx
+ 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.
+ - 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
+
+appx:
+ # --- Real values, from Partner Center's "App identity" page (App
+ # management -> App identity), not chosen freely -- a mismatch here fails
+ # Store validation outright rather than warning. publisherDisplayName is
+ # "MeshBay" as Partner Center assigned it, NOT package.json's own author
+ # company name ("MeshBay Team") -- AppXOptions.d.ts's default (company
+ # name from app metadata) would silently pick the wrong one if this were
+ # left unset, so it must stay explicit even though it looks redundant
+ # next to `displayName`.
+ identityName: MeshBay.MeshBay
+ publisher: "CN=CE32BB0D-6B7C-4D3A-AA42-E259B778CAC9"
+ publisherDisplayName: MeshBay
+ applicationId: MeshBay
+ displayName: MeshBay
+ languages:
+ - en-US
+ - fr-FR
+ - es-ES
+ - pt-BR
+ - zh-CN
+ - ja-JP
+ - de-DE
+ - 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 msix-installer.md §8's
+ # #1 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 in msix-installer.md §8 -- untested
+ # until sideloaded.
+ customExtensionsPath: build/appx-extensions.xml
+ showNameOnTiles: false