From 627fcfa4e26540654509f9a225420546ad0295d6 Mon Sep 17 00:00:00 2001 From: r4bbit <445106+0x-r4bbit@users.noreply.github.com> Date: Wed, 19 Aug 2026 14:09:15 +0200 Subject: [PATCH] fix(apps/amm): make the AMM UI load in Basecamp Stage Logos.Wallet at the plugin root as pure QML (Basecamp rejects the prefer :/qt/qml/... resource), move NavBar into qml/chrome/ so it stops colliding in Basecamp's shared import path, and add a QML_IMPORT_PATH wrapper so standalone still resolves the root module. Adds amm-ui-lgx / amm-module-lgx aliases for addressable Basecamp installs. --- apps/amm/qml/Logos/Wallet/qmldir | 5 ---- apps/amm/qml/Main.qml | 1 + apps/amm/qml/{ => chrome}/NavBar.qml | 0 flake.nix | 41 ++++++++++++++++++++++++++++ 4 files changed, 42 insertions(+), 5 deletions(-) delete mode 100644 apps/amm/qml/Logos/Wallet/qmldir rename apps/amm/qml/{ => chrome}/NavBar.qml (100%) diff --git a/apps/amm/qml/Logos/Wallet/qmldir b/apps/amm/qml/Logos/Wallet/qmldir deleted file mode 100644 index 866351b..0000000 --- a/apps/amm/qml/Logos/Wallet/qmldir +++ /dev/null @@ -1,5 +0,0 @@ -module Logos.Wallet -optional plugin logos_wallet_qmlplugin ../../../Logos/Wallet -classname Logos_WalletPlugin -prefer :/qt/qml/Logos/Wallet/ -depends QtQuick diff --git a/apps/amm/qml/Main.qml b/apps/amm/qml/Main.qml index aaf44b8..63465dd 100644 --- a/apps/amm/qml/Main.qml +++ b/apps/amm/qml/Main.qml @@ -4,6 +4,7 @@ import QtQuick.Layouts 1.15 import Logos.Theme +import "chrome" import "pages" Item { diff --git a/apps/amm/qml/NavBar.qml b/apps/amm/qml/chrome/NavBar.qml similarity index 100% rename from apps/amm/qml/NavBar.qml rename to apps/amm/qml/chrome/NavBar.qml diff --git a/flake.nix b/flake.nix index 5212fa5..977db33 100644 --- a/flake.nix +++ b/flake.nix @@ -152,9 +152,20 @@ exit 1 fi walletQmlDir="$(dirname "$walletQmlDescriptor")" + # Stage Logos.Wallet at the plugin ROOT as PURE QML (strip every + # plugin/resource directive). Same rationale as tokenAppOutputs below: + # Basecamp rejects `prefer :/qt/qml/...` with "Invalid null URL", and + # keeping the module at the root (never under qml/) avoids leaking + # qml/NavBar.qml et al. into Basecamp's shared import path where it + # would collide with other plugins' identically-named types. Standalone + # reaches this root module via QML_IMPORT_PATH (see the amm-ui app + # wrapper). Keep in sync with tokenAppOutputs / apps/amm/flake.nix. walletQmlInstallDir="$out/lib/Logos/Wallet" mkdir -p "$walletQmlInstallDir" cp -r "$walletQmlDir/." "$walletQmlInstallDir/" + grep -vE '^(linktarget|optional plugin|plugin|classname|typeinfo|prefer)([[:space:]]|$)' \ + "$walletQmlInstallDir/qmldir" > "$walletQmlInstallDir/qmldir.pureqml" + mv "$walletQmlInstallDir/qmldir.pureqml" "$walletQmlInstallDir/qmldir" test -f "$walletQmlInstallDir/qmldir" ''; }; @@ -229,6 +240,16 @@ // (if attrs ? install-portable then { token-ui-install-portable = attrs.install-portable; } else { }) ) tokenAppPkgs; + # Same aliasing for the AMM UI's Basecamp install artifacts, so its lgx + # isn't shadowed by the amm core module's bare `lgx` in the merged set. + ammUiPackages = builtins.mapAttrs ( + system: attrs: + (if attrs ? lgx then { amm-ui-lgx = attrs.lgx; } else { }) + // (if attrs ? lgx-portable then { amm-ui-lgx-portable = attrs.lgx-portable; } else { }) + // (if attrs ? install then { amm-ui-install = attrs.install; } else { }) + // (if attrs ? install-portable then { amm-ui-install-portable = attrs.install-portable; } else { }) + ) appPkgs; + # AMM core module (modules/amm): the AMM business logic as a headless # `core` Logos module. It links the amm_ffi crate (the transport- # independent AMM brain, resolved via `self`) and depends on the @@ -245,6 +266,15 @@ }; ammModulePkgs = ammModuleOutputs.packages or { }; + # Alias the AMM core module's Basecamp install artifacts (explicit + # `amm-module-lgx` / `amm-module-install`), same collision reason as the + # token module aliases below. + ammModuleAliases = builtins.mapAttrs ( + system: attrs: + (if attrs ? lgx then { amm-module-lgx = attrs.lgx; } else { }) + // (if attrs ? install then { amm-module-install = attrs.install; } else { }) + ) ammModulePkgs; + # Token core module (modules/token): complete Token Program inspection # and transaction planning/orchestration surface. The Qt-free universal # module links token_ffi and reuses the host-loaded wallet module. @@ -278,14 +308,21 @@ # plugin-dir it loads at runtime, so dlopen fails with "Failed to load UI # plugin". Adding the crate's store lib dir to DYLD's fallback search path # lets the loader find it (the store path stays in the closure). + # Also prepend the AMM UI module's `lib` dir to QML_IMPORT_PATH so the + # standalone shell resolves `import Logos.Wallet` from the plugin ROOT + # (staged there, never under qml/, by the appOutputs postInstall — see the + # wrapTokenQmlImportPath rationale). logos-standalone-app appends any + # pre-existing QML_IMPORT_PATH to what it sets. wrapWithDyld = system: app: let pkgs = import nixpkgs { inherit system; overlays = [ rust-overlay.overlays.default ]; }; ammFfi = crateOutputs.packages.${system}.amm_ffi; + moduleDir = appPkgs.${system}.default; in app // { program = "${pkgs.writeShellScript "run-amm-ui" '' export DYLD_FALLBACK_LIBRARY_PATH="${ammFfi}/lib''${DYLD_FALLBACK_LIBRARY_PATH:+:$DYLD_FALLBACK_LIBRARY_PATH}" + export QML_IMPORT_PATH="${moduleDir}/lib''${QML_IMPORT_PATH:+:$QML_IMPORT_PATH}" exec ${app.program} "$@" ''}"; }; @@ -331,20 +368,24 @@ system: cratePkgs: let appSysPkgs = appPkgs.${system} or { }; + ammUiSysPkgs = ammUiPackages.${system} or { }; tokenAppSysPkgs = tokenAppPkgs.${system} or { }; tokenUiSysPkgs = tokenUiPackages.${system} or { }; ammModSysPkgs = ammModulePkgs.${system} or { }; + ammModAliasPkgs = ammModuleAliases.${system} or { }; tokenModSysPkgs = tokenModulePkgs.${system} or { }; tokenModAliasPkgs = tokenModuleAliases.${system} or { }; in (builtins.removeAttrs cratePkgs [ "default" ]) // (builtins.removeAttrs appSysPkgs [ "default" ]) // (if appSysPkgs ? default then { amm-ui = appSysPkgs.default; } else { }) + // ammUiSysPkgs // (builtins.removeAttrs tokenAppSysPkgs [ "default" ]) // (if tokenAppSysPkgs ? default then { token-ui = tokenAppSysPkgs.default; } else { }) // tokenUiSysPkgs // (builtins.removeAttrs ammModSysPkgs [ "default" ]) // (if ammModSysPkgs ? default then { amm-module = ammModSysPkgs.default; } else { }) + // ammModAliasPkgs // (builtins.removeAttrs tokenModSysPkgs [ "default" ]) // (if tokenModSysPkgs ? default then { token-module = tokenModSysPkgs.default; } else { }) // tokenModAliasPkgs