diff --git a/nix/modules/hive-matrix.nix b/nix/modules/hive-matrix.nix index c1575d9e..7e670aa6 100644 --- a/nix/modules/hive-matrix.nix +++ b/nix/modules/hive-matrix.nix @@ -8,6 +8,135 @@ let cfg = config.services.hyperhive.matrix; hyperhiveDomain = config.services.hyperhive.domain; effectiveServerName = if cfg.serverName != null then cfg.serverName else hyperhiveDomain; + + # Three files are missing from nixpkgs's `pkgs.fluffychat-web` dist + # because `flutter341.buildFlutterApplication` doesn't run the dart + # web-worker compile pass + doesn't run the native_imaging package's + # emscripten build (#685): + # + # - native_executor.js ← flutter web worker entry, compiled + # from web/native_executor.dart via + # `dart compile js` (handled inline + # in `fluffychat-web-fixed.postInstall` + # below — dart SDK is already in the + # flutter341 closure) + # + # - Imaging.js / Imaging.wasm ← emscripten-compiled C library from + # the native_imaging dart package + # (vendored by Famedly). The package + # ships C source + a Makefile that + # builds them via emcc; nixpkgs's + # flutter builder doesn't run that + # pipeline. Built from source via + # `fluffychat-web-imaging` below + # (per mara's #685 call: "fix the + # compile … dont use the prebuilt + # binary"). + # + # When `flutter341.buildFlutterApplication` grows worker + emcc + # support upstream, drop both this derivation and the postInstall. + + # Imaging.{js,wasm} built from source: native_imaging's `js/Makefile` + # runs `emcmake cmake` → `make -C build` → `emcc` to produce the + # emscripten-wrapped C library that fluffychat's main.dart.js + # references at runtime. + # + # Source: the exact native_imaging derivation that `pkgs.fluffychat-web` + # already pulls in via its `pubspecLock` (resolved by nixpkgs's flutter + # pub-cache machinery), reached via `passthru.pubspecLock.dependencySources`. + # This means **no parallel hash pin** — when nixpkgs bumps + # `pkgs.fluffychat-web` (and with it the pubspec.lock-resolved + # native_imaging version), our build automatically picks up the + # matching source. Version is also pulled from passthru for the + # derivation's `version` attr so it stays in lockstep. + # + # Closure cost: `pkgs.emscripten` is ~3.6 GiB build-time (LLVM + + # toolchain). Runtime closure is only the two produced files — + # nothing emscripten-shaped survives into the deployed dist. + fluffychat-web-imaging = pkgs.stdenv.mkDerivation { + pname = "fluffychat-web-imaging"; + version = pkgs.fluffychat-web.passthru.pubspecLock.dependencyVersions.native_imaging; + + # The pub-cache derivation that fluffychat-web's flutter build uses. + # Already in the build closure; no `fetchurl` or own hash pin. + src = pkgs.fluffychat-web.passthru.pubspecLock.dependencySources.native_imaging; + + nativeBuildInputs = with pkgs; [ + emscripten + cmake + gnumake + jq + ]; + + # cmake config runs inside `js/Makefile` (via `emcmake cmake`) — + # skip the default `configurePhase` which would try to invoke + # cmake against the package root and fail (no CMakeLists at top). + dontConfigure = true; + + buildPhase = '' + runHook preBuild + # emscripten needs HOME + a writable cache dir for its sysroot + # build (libc, libc++, etc. compiled to wasm on demand). + export HOME=$TMPDIR + export EM_CACHE=$TMPDIR/.emscriptencache + mkdir -p $EM_CACHE + # `make -C js` keeps the build phase pwd at the source root so + # installPhase doesn't have to know about the cd (argus 🟡 on + # PR #697 v2 — robust against future reorders / `dontBuild`). + make -C js Imaging.js Imaging.wasm + runHook postBuild + ''; + + installPhase = '' + runHook preInstall + mkdir -p $out + install -m 644 js/Imaging.js $out/Imaging.js + install -m 644 js/Imaging.wasm $out/Imaging.wasm + runHook postInstall + ''; + + meta = with pkgs.lib; { + description = "Imaging.js + Imaging.wasm built from the native_imaging dart package for fluffychat-web (#685)"; + homepage = "https://pub.dev/packages/native_imaging"; + license = licenses.agpl3Plus; + }; + }; + + # `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. + 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: install Imaging.{js,wasm} built from the native_imaging + # dart package's C source via emscripten (see + # `fluffychat-web-imaging` above for the build-time rationale). + install -m 644 ${fluffychat-web-imaging}/Imaging.js $out/Imaging.js + install -m 644 ${fluffychat-web-imaging}/Imaging.wasm $out/Imaging.wasm + ''; + }); in { # Private Matrix homeserver (matrix-tuwunel — the official conduwuit @@ -202,32 +331,23 @@ 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` from `web/native_executor.dart`), + plus `Imaging.js` + `Imaging.wasm` (built from the + `native_imaging` dart package's C source via `pkgs.emscripten`). + 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.