@nativedesktop/cli 0.4.45 → 0.4.46

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nativedesktop/cli",
3
- "version": "0.4.45",
3
+ "version": "0.4.46",
4
4
  "description": "The nd CLI: dev-runs, builds, and packages NativeDesktop apps",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -25,6 +25,6 @@
25
25
  "./config": "./src/config.ts"
26
26
  },
27
27
  "dependencies": {
28
- "@nativedesktop/host": "0.4.45"
28
+ "@nativedesktop/host": "0.4.46"
29
29
  }
30
30
  }
@@ -5,7 +5,7 @@ import { mkdirSync, mkdtempSync, writeFileSync } from "node:fs";
5
5
  import { tmpdir } from "node:os";
6
6
  import { join } from "node:path";
7
7
  import type { NativeDesktopConfig } from "../config.ts";
8
- import { builtBundles, type Check, webviewChecks } from "./doctor.ts";
8
+ import { builtBundles, type Check, nixosHostChecks, webviewChecks } from "./doctor.ts";
9
9
 
10
10
  const FRAMEWORK = "Chromium Embedded Framework.framework";
11
11
  const target = process.platform === "darwin" ? "mac" : "linux";
@@ -82,3 +82,46 @@ describe("webviewChecks", () => {
82
82
  expect(find(webviewChecks(config, empty), "cef-bytes")[0]!.status).toBe("error");
83
83
  });
84
84
  });
85
+
86
+ describe("nixosHostChecks", () => {
87
+ const gtk = "/nix/store/a-gtk4/lib";
88
+ const adw = "/nix/store/a-libadwaita/lib";
89
+ const gstPin = "/nix/store/a-gstreamer/lib";
90
+ const gstOther = "/nix/store/b-gstreamer/lib";
91
+ const files = new Set([
92
+ "/etc/NIXOS",
93
+ "/lib64/ld-linux-x86-64.so.2",
94
+ `${gtk}/libgtk-4.so.1`,
95
+ `${adw}/libadwaita-1.so.0`,
96
+ `${gstPin}/libgstreamer-1.0.so.0`,
97
+ `${gstOther}/libgstreamer-1.0.so.0`,
98
+ ]);
99
+ const exists = (p: string) => files.has(p);
100
+
101
+ test("says nothing off NixOS", () => {
102
+ expect(nixosHostChecks({}, () => false)).toEqual([]);
103
+ });
104
+
105
+ test("without nix-ld the generic loader is missing", () => {
106
+ const checks = nixosHostChecks({}, (p) => p === "/etc/NIXOS");
107
+ expect(checks[0]!.status).toBe("error");
108
+ expect(checks[0]!.detail).toContain("programs.nix-ld.enable");
109
+ });
110
+
111
+ test("outside the dev shell nix-ld has no GTK to hand the host", () => {
112
+ const checks = nixosHostChecks({ NIX_LD_LIBRARY_PATH: "/run/current-system/sw/share/nix-ld/lib" }, exists);
113
+ expect(checks[0]!.status).toBe("error");
114
+ expect(checks[0]!.detail).toContain("nix develop");
115
+ });
116
+
117
+ test("GStreamer from another nixpkgs than GTK is the missing-symbol failure", () => {
118
+ const checks = nixosHostChecks({ NIX_LD_LIBRARY_PATH: `${gtk}:${adw}:${gstOther}`, LD_LIBRARY_PATH: gstPin }, exists);
119
+ expect(checks[0]!.status).toBe("error");
120
+ expect(checks[0]!.detail).toContain(gstPin);
121
+ });
122
+
123
+ test("one pin for both is fine", () => {
124
+ const checks = nixosHostChecks({ NIX_LD_LIBRARY_PATH: `${gtk}:${adw}:${gstPin}`, LD_LIBRARY_PATH: gstPin }, exists);
125
+ expect(checks).toEqual([{ name: "nixos", status: "ok", detail: `prebuilt host runs through nix-ld with GTK from ${gtk}` }]);
126
+ });
127
+ });
@@ -74,6 +74,43 @@ export function builtBundles(config: NativeDesktopConfig, cwd: string): string[]
74
74
  * bundle carrying Chromium bytes breaks the framework's central claim about the
75
75
  * default path, so it fails rather than warns.
76
76
  */
77
+ const GENERIC_LOADER = "/lib64/ld-linux-x86-64.so.2";
78
+
79
+ function libDirWith(path: string | undefined, soname: string, exists: (p: string) => boolean): string | undefined {
80
+ return path?.split(":").find((dir) => dir && exists(join(dir, soname)));
81
+ }
82
+
83
+ /** The published Linux host is a generic-distro binary: on NixOS it only runs
84
+ * through nix-ld, and only correctly when GTK (NIX_LD_LIBRARY_PATH) and the
85
+ * GStreamer the dev shell puts on LD_LIBRARY_PATH come from one nixpkgs. */
86
+ export function nixosHostChecks(
87
+ env: Record<string, string | undefined>,
88
+ exists: (path: string) => boolean = existsSync,
89
+ ): Check[] {
90
+ if (!exists("/etc/NIXOS")) return [];
91
+ const shell = "run nd inside the framework dev shell (`nix develop <NativeDesktop checkout>`)";
92
+ if (!exists(GENERIC_LOADER)) {
93
+ return [{
94
+ name: "nixos",
95
+ status: "error",
96
+ detail: `the prebuilt host needs ${GENERIC_LOADER}, which NixOS only provides with nix-ld: set programs.nix-ld.enable = true, then ${shell}`,
97
+ }];
98
+ }
99
+ const gtk = libDirWith(env.NIX_LD_LIBRARY_PATH, "libgtk-4.so.1", exists);
100
+ if (!gtk || !libDirWith(env.NIX_LD_LIBRARY_PATH, "libadwaita-1.so.0", exists)) {
101
+ return [{ name: "nixos", status: "error", detail: `NIX_LD_LIBRARY_PATH has no GTK 4 / libadwaita for the prebuilt host: ${shell}` }];
102
+ }
103
+ const gst = libDirWith(env.LD_LIBRARY_PATH, "libgstreamer-1.0.so.0", exists);
104
+ if (gst && !env.NIX_LD_LIBRARY_PATH!.split(":").includes(gst)) {
105
+ return [{
106
+ name: "nixos",
107
+ status: "error",
108
+ detail: `GStreamer on LD_LIBRARY_PATH (${gst}) is not the one GTK on NIX_LD_LIBRARY_PATH was built against, so GTK fails on a missing symbol: update the NativeDesktop checkout whose dev shell this is`,
109
+ }];
110
+ }
111
+ return [{ name: "nixos", status: "ok", detail: `prebuilt host runs through nix-ld with GTK from ${gtk}` }];
112
+ }
113
+
77
114
  export function webviewChecks(config: NativeDesktopConfig, cwd: string): Check[] {
78
115
  const target = engineTargetFor();
79
116
  if (!target) return [];
@@ -181,7 +218,8 @@ export async function collectChecks(cwd: string): Promise<Check[]> {
181
218
  // ND_HOST_BINARY is what `nd dev` will actually run, so report that rather
182
219
  // than the prebuilt it overrides.
183
220
  const explicit = process.env.ND_HOST_BINARY;
184
- const found = explicit || prebuiltHostBinary(backend) || fresh.find(existsSync);
221
+ const prebuilt = prebuiltHostBinary(backend);
222
+ const found = explicit || prebuilt || fresh.find(existsSync);
185
223
  if (explicit && !existsSync(explicit)) {
186
224
  checks.push({ name: "host", status: "error", detail: `ND_HOST_BINARY points at ${explicit}, which does not exist` });
187
225
  } else {
@@ -189,6 +227,7 @@ export async function collectChecks(cwd: string): Promise<Check[]> {
189
227
  ? { name: "host", status: "ok", detail: explicit ? `${found} (ND_HOST_BINARY)` : found }
190
228
  : { name: "host", status: "warn", detail: `no ${backend} host binary built yet (nd dev / nd package builds it on first run in a source checkout)` });
191
229
  }
230
+ if (process.platform === "linux" && !explicit && prebuilt && found === prebuilt) checks.push(...nixosHostChecks(process.env));
192
231
  } catch (err) {
193
232
  checks.push({ name: "host", status: "error", detail: String(err) });
194
233
  }