diff --git a/nix/modules/hive-matrix.nix b/nix/modules/hive-matrix.nix
index c1575d9e..f748fa28 100644
--- a/nix/modules/hive-matrix.nix
+++ b/nix/modules/hive-matrix.nix
@@ -8,6 +8,82 @@ let
cfg = config.services.hyperhive.matrix;
hyperhiveDomain = config.services.hyperhive.domain;
effectiveServerName = if cfg.serverName != null then cfg.serverName else hyperhiveDomain;
+
+ # Two files are missing from nixpkgs's `pkgs.fluffychat-web` dist
+ # because `flutter341.buildFlutterApplication` doesn't run the
+ # native_imaging package's emscripten build (#685):
+ #
+ # - Imaging.js / Imaging.wasm ← emscripten-compiled C library
+ # from the native_imaging dart package (vendored by Famedly).
+ # The package ships only C source + a Makefile that builds
+ # them via emcc; pulling in `pkgs.emscripten` to run that
+ # mid-build adds ~600 MB of closure for two files we can pin
+ # to the upstream release tarball's prebuilt copies (same
+ # fluffychat release version → byte-identical output).
+ #
+ # `native_executor.js` is the other missing file (web worker entry
+ # point), but that one compiles cleanly from source via
+ # `dart compile js` — handled in `fluffychat-web-fixed` below
+ # rather than vendored, since the dart SDK is already in the
+ # flutter341 closure.
+ fluffychat-web-imaging-prebuilt =
+ pkgs.runCommandLocal "fluffychat-web-imaging-prebuilt-${pkgs.fluffychat-web.version}"
+ {
+ src = pkgs.fetchurl {
+ url = "https://github.com/krille-chan/fluffychat/releases/download/v${pkgs.fluffychat-web.version}/fluffychat-web.tar.gz";
+ # v2.6.0 prebuilt tarball; bump in lockstep with
+ # `pkgs.fluffychat-web.version` on any flutter upgrade.
+ hash = "sha256-P3Bt5FZ5TPeE0k05gYxLw7FdEyyi8g5A/r7tGZMezQk=";
+ };
+ }
+ ''
+ mkdir -p $out
+ tar -xzf $src --strip-components=2 -C $out \
+ build/web/Imaging.js build/web/Imaging.wasm
+ '';
+
+ # `pkgs.fluffychat-web` with #685's three missing files patched
+ # in via postInstall, plus the existing `--base-href "/matrix/"`
+ # override (#634) for the sub-path mount. The patches sit in our
+ # tree rather than as a nixpkgs upstream PR because:
+ # - `dart compile js` for web workers is a `buildFlutterApplication`
+ # gap that needs an upstream patch, not a per-package one
+ # - vendoring emscripten output for `native_imaging` is a
+ # workaround for the same builder gap
+ # When `flutter341.buildFlutterApplication` grows worker / emcc
+ # support, drop the postInstall entirely.
+ fluffychat-web-fixed = pkgs.fluffychat-web.overrideAttrs (old: {
+ # `--base-href "/matrix/"` so relative asset paths resolve
+ # under the sub-path mount (#634). Upstream default is `/`,
+ # wrong for hyperhive's `/matrix/` location.
+ flutterBuildFlags = (old.flutterBuildFlags or [ ]) ++ [
+ "--base-href"
+ "/matrix/"
+ ];
+
+ # `dart` from the flutter341 closure (already pulled, no
+ # incremental closure cost) so we can compile the web-worker
+ # entry point that buildFlutterApplication skips.
+ nativeBuildInputs = (old.nativeBuildInputs or [ ]) ++ [ pkgs.flutter341.dart ];
+
+ postInstall =
+ (old.postInstall or "")
+ + ''
+ # #685: compile web/native_executor.dart → native_executor.js.
+ # The flutter web bootstrap loads this from /matrix/native_executor.js
+ # at startup; without it, main.dart.js logs a network-error and
+ # the SPA renders blank (see #643 for the symptom).
+ ${pkgs.flutter341.dart}/bin/dart compile js \
+ -o $out/native_executor.js \
+ $src/web/native_executor.dart
+
+ # #685: vendor Imaging.{js,wasm} from upstream prebuilt — see
+ # comment on `fluffychat-web-imaging-prebuilt` above for the
+ # closure-size rationale vs running emcc here.
+ install -m 644 ${fluffychat-web-imaging-prebuilt}/Imaging.js $out/Imaging.js
+ install -m 644 ${fluffychat-web-imaging-prebuilt}/Imaging.wasm $out/Imaging.wasm
+ '';
+ });
in
{
# Private Matrix homeserver (matrix-tuwunel — the official conduwuit
@@ -202,32 +278,24 @@ in
package = lib.mkOption {
type = lib.types.package;
- default = pkgs.fluffychat-web.overrideAttrs (old: {
- # fluffychat-web ships with `` baked into its
- # index.html — flutter's `--base-href` build flag replaces
- # that placeholder. Default upstream build is `--base-href "/"`
- # which is wrong for hyperhive's `/matrix/` sub-path mount:
- # the browser resolves relative asset paths (`Imaging.js`,
- # `flutter.js`, `splash/*`) against the document ROOT,
- # producing 404s for every asset (#634). Inject the right
- # base-href into the actual `flutter build web` invocation
- # via the upstream derivation's `flutterBuildFlags` string
- # (the buildPhase is literally
- # `flutter build web -v $flutterBuildFlags`). When subdomain
- # routing lands (#609 — `matrix.${hyperhiveDomain}`), drop
- # this override; upstream's `/` base-href is correct at the
- # root of a dedicated subdomain.
- flutterBuildFlags = (old.flutterBuildFlags or [ ]) ++ [
- "--base-href"
- "/matrix/"
- ];
- });
- defaultText = lib.literalMD "`pkgs.fluffychat-web` rebuilt with `--base-href /matrix/` via `flutterBuildFlags`.";
+ default = fluffychat-web-fixed;
+ defaultText = lib.literalMD ''
+ `pkgs.fluffychat-web` rebuilt with `--base-href /matrix/` (#634)
+ and patched via `postInstall` to add the three files
+ `flutter341.buildFlutterApplication` skips: `native_executor.js`
+ (compiled via `dart compile js`), plus `Imaging.js` and
+ `Imaging.wasm` (vendored from the upstream release tarball;
+ they're emscripten output from the `native_imaging` dart
+ package and the alternative is +~600 MB of `pkgs.emscripten` in
+ the build closure for two files). See the `let` block in
+ `nix/modules/hive-matrix.nix` for the full rationale (#685).
+ '';
description = ''
Static web client dist to serve at `/matrix/`. Defaults to
`pkgs.fluffychat-web` rebuilt with `--base-href "/matrix/"`
so relative asset paths resolve under the sub-path mount
- (#634). Override to swap for `hydrogen-web` (lightest),
+ (#634), plus a `postInstall` patch for #685's three missing
+ files. Override to swap for `hydrogen-web` (lightest),
`cinny` (no threads), `element-web` (heaviest, full
features), or an out-of-tree client dist — any replacement
also needs its `` aligned with the mount path.