@gjsify/cli 0.35.0 → 0.37.0

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.
Files changed (124) hide show
  1. package/dist/cli.gjs.mjs +136 -126
  2. package/lib/actions/build.d.ts +19 -0
  3. package/lib/actions/build.js +2 -2
  4. package/lib/bundler-pick.js +72 -98
  5. package/lib/cli-fail.d.ts +4 -7
  6. package/lib/cli-fail.js +29 -55
  7. package/lib/commands/affected.js +161 -286
  8. package/lib/commands/install.d.ts +63 -66
  9. package/lib/commands/install.js +372 -536
  10. package/lib/commands/run.d.ts +1 -0
  11. package/lib/commands/run.js +37 -0
  12. package/lib/templates/install.mjs.tmpl +38 -68
  13. package/lib/types/cli-build-options.d.ts +33 -67
  14. package/lib/types/command.d.ts +9 -12
  15. package/lib/types/config-data.d.ts +125 -221
  16. package/lib/utils/auth-npmrc.d.ts +5 -10
  17. package/lib/utils/auth-npmrc.js +11 -21
  18. package/lib/utils/check-system-deps.d.ts +16 -0
  19. package/lib/utils/check-system-deps.js +49 -0
  20. package/lib/utils/clear-targets.d.ts +8 -11
  21. package/lib/utils/clear-targets.js +22 -29
  22. package/lib/utils/copy-targets.d.ts +13 -19
  23. package/lib/utils/copy-targets.js +31 -44
  24. package/lib/utils/dep-aggregation.d.ts +7 -15
  25. package/lib/utils/dep-aggregation.js +9 -22
  26. package/lib/utils/detect-native-packages.d.ts +83 -116
  27. package/lib/utils/detect-native-packages.js +111 -149
  28. package/lib/utils/dir-link.d.ts +29 -48
  29. package/lib/utils/dir-link.js +33 -56
  30. package/lib/utils/discover-showcases.d.ts +6 -7
  31. package/lib/utils/discover-showcases.js +11 -15
  32. package/lib/utils/dlx-cache.d.ts +29 -38
  33. package/lib/utils/dlx-cache.js +53 -63
  34. package/lib/utils/force-exit.d.ts +0 -3
  35. package/lib/utils/force-exit.js +13 -24
  36. package/lib/utils/gi-search-path.d.ts +16 -24
  37. package/lib/utils/gi-search-path.js +54 -82
  38. package/lib/utils/gjs-bundle-guard.d.ts +5 -13
  39. package/lib/utils/gjs-bundle-guard.js +35 -57
  40. package/lib/utils/gjs-source-escape.d.ts +2 -2
  41. package/lib/utils/gjs-source-escape.js +21 -39
  42. package/lib/utils/gjsify-shim.d.ts +26 -8
  43. package/lib/utils/gjsify-shim.js +128 -80
  44. package/lib/utils/html-entry.d.ts +8 -12
  45. package/lib/utils/html-entry.js +19 -28
  46. package/lib/utils/install-backend-native.d.ts +123 -161
  47. package/lib/utils/install-backend-native.js +536 -737
  48. package/lib/utils/install-backend.d.ts +42 -57
  49. package/lib/utils/install-backend.js +16 -21
  50. package/lib/utils/install-cache-fs.d.ts +10 -15
  51. package/lib/utils/install-cache-fs.js +18 -26
  52. package/lib/utils/install-lock.d.ts +5 -6
  53. package/lib/utils/install-lock.js +46 -65
  54. package/lib/utils/install-packument-cache.d.ts +27 -33
  55. package/lib/utils/install-packument-cache.js +44 -57
  56. package/lib/utils/install-progress.d.ts +2 -9
  57. package/lib/utils/install-progress.js +14 -39
  58. package/lib/utils/install-tarball-cache.d.ts +14 -20
  59. package/lib/utils/install-tarball-cache.js +41 -59
  60. package/lib/utils/library-output.d.ts +9 -22
  61. package/lib/utils/library-output.js +19 -37
  62. package/lib/utils/load-npmrc.d.ts +5 -6
  63. package/lib/utils/load-npmrc.js +18 -27
  64. package/lib/utils/node-bundle-guard.d.ts +4 -8
  65. package/lib/utils/node-bundle-guard.js +21 -35
  66. package/lib/utils/node-script.d.ts +12 -0
  67. package/lib/utils/node-script.js +95 -0
  68. package/lib/utils/node-version.d.ts +5 -14
  69. package/lib/utils/node-version.js +15 -24
  70. package/lib/utils/normalize-bundler-options.d.ts +7 -11
  71. package/lib/utils/normalize-bundler-options.js +24 -42
  72. package/lib/utils/npm-oidc.d.ts +23 -37
  73. package/lib/utils/npm-oidc.js +28 -53
  74. package/lib/utils/npm-otp-cache.d.ts +4 -4
  75. package/lib/utils/npm-otp-cache.js +20 -25
  76. package/lib/utils/npm-otp.d.ts +20 -30
  77. package/lib/utils/npm-otp.js +32 -51
  78. package/lib/utils/onboard-probe.d.ts +7 -13
  79. package/lib/utils/onboard-probe.js +16 -27
  80. package/lib/utils/parse-spec.d.ts +3 -3
  81. package/lib/utils/parse-spec.js +4 -5
  82. package/lib/utils/pkg-json-edit.d.ts +7 -12
  83. package/lib/utils/pkg-json-edit.js +13 -26
  84. package/lib/utils/pkg-json.d.ts +11 -18
  85. package/lib/utils/pkg-json.js +19 -28
  86. package/lib/utils/prefixed-output.d.ts +3 -4
  87. package/lib/utils/prefixed-output.js +13 -19
  88. package/lib/utils/prompt.d.ts +3 -4
  89. package/lib/utils/prompt.js +14 -18
  90. package/lib/utils/publish-diagnose.d.ts +11 -16
  91. package/lib/utils/publish-diagnose.js +15 -28
  92. package/lib/utils/publish-headers.d.ts +7 -11
  93. package/lib/utils/publish-headers.js +36 -65
  94. package/lib/utils/publishable-packages.d.ts +4 -6
  95. package/lib/utils/publishable-packages.js +14 -18
  96. package/lib/utils/resolve-gjs-entry.d.ts +5 -8
  97. package/lib/utils/resolve-gjs-entry.js +10 -27
  98. package/lib/utils/resolve-npm-package.d.ts +6 -11
  99. package/lib/utils/resolve-npm-package.js +29 -63
  100. package/lib/utils/resolve-plugin-by-name.d.ts +11 -19
  101. package/lib/utils/resolve-plugin-by-name.js +9 -14
  102. package/lib/utils/run-gjs.d.ts +19 -17
  103. package/lib/utils/run-gjs.js +37 -51
  104. package/lib/utils/run-lifecycle-script.d.ts +5 -9
  105. package/lib/utils/run-lifecycle-script.js +23 -42
  106. package/lib/utils/run-node.d.ts +23 -33
  107. package/lib/utils/run-node.js +56 -60
  108. package/lib/utils/runtimes.d.ts +25 -35
  109. package/lib/utils/runtimes.js +34 -46
  110. package/lib/utils/spawn.d.ts +32 -48
  111. package/lib/utils/spawn.js +51 -84
  112. package/lib/utils/stdin.d.ts +2 -2
  113. package/lib/utils/stdin.js +10 -25
  114. package/lib/utils/suggest.d.ts +6 -7
  115. package/lib/utils/suggest.js +8 -10
  116. package/lib/utils/system-gi.d.ts +18 -27
  117. package/lib/utils/system-gi.js +60 -114
  118. package/lib/utils/trust-registry.d.ts +4 -8
  119. package/lib/utils/trust-registry.js +7 -15
  120. package/lib/utils/win32-command.d.ts +8 -14
  121. package/lib/utils/win32-command.js +29 -43
  122. package/lib/utils/workspace-root.js +7 -12
  123. package/package.json +18 -17
  124. package/showcases.json +6 -0
@@ -6,38 +6,32 @@ export interface NativePackage {
6
6
  prebuildsDir: string;
7
7
  }
8
8
  /**
9
- * Which C library an artifact is built against. npm's own `libc` manifest field
10
- * uses exactly these two tokens, and it is LINUX-ONLY there — every other OS has
11
- * one C library, so the axis does not exist off Linux and is `null` there rather
12
- * than defaulted to something.
9
+ * Which C library an artifact is built against. npm's own `libc` manifest field uses
10
+ * exactly these two tokens and is LINUX-ONLY — every other OS has one C library, so
11
+ * the axis is `null` off Linux rather than defaulted to something.
13
12
  */
14
13
  export type HostLibc = 'glibc' | 'musl';
15
14
  /** The host target a resolution is performed for. Defaults to the running process. */
16
15
  export interface HostTarget {
17
- /** `process.platform` value — `linux` | `darwin` | `win32` | … */
18
16
  platform?: string;
19
- /** `process.arch` value — `x64` | `arm64` | `ppc64` | `s390x` | `riscv64` | … */
20
17
  arch?: string;
21
18
  /**
22
- * Host C library, or `undefined`/`null` when the axis does not apply (any
23
- * non-Linux OS) or could not be determined. Both non-values mean the same
24
- * thing to the resolver: behave exactly as before the libc axis existed —
25
- * never offer a `-musl` directory. That is deliberately the conservative
26
- * direction: an unsuffixed directory is the DEFAULT build, so a host we
27
- * cannot classify still resolves what it always did.
19
+ * Host C library, or `undefined`/`null` when the axis does not apply (non-Linux)
20
+ * or could not be determined. Both non-values mean the same thing: never offer a
21
+ * `-musl` directory, exactly as before the axis existed. Conservative on purpose —
22
+ * an unsuffixed directory is the DEFAULT build, so an unclassifiable host still
23
+ * resolves what it always did.
28
24
  */
29
25
  libc?: HostLibc | null;
30
26
  }
31
27
  /**
32
- * Environment a GJS process needs so `gi://Gjsify…` imports resolve against
33
- * the detected prebuilds. `GI_TYPELIB_PATH` is universal (girepository reads
34
- * it on every OS); the *library* search path is whatever the host's dynamic
35
- * loader actually consults, which is a different variable per OS — see
28
+ * Environment a GJS process needs so `gi://Gjsify…` imports resolve against the
29
+ * detected prebuilds. `GI_TYPELIB_PATH` is universal (girepository reads it on every
30
+ * OS); the *library* search path is a different variable per OS — see
36
31
  * {@link buildNativeEnv}.
37
32
  *
38
- * The index signature exists for the Windows case, where the key is the host's
39
- * own `PATH` spelling (`Path` on a stock Windows env block) rather than a
40
- * fixed literal.
33
+ * The index signature exists for Windows, where the key is the host's own `PATH`
34
+ * spelling (`Path` on a stock env block) rather than a fixed literal.
41
35
  */
42
36
  export interface NativeEnv {
43
37
  GI_TYPELIB_PATH: string;
@@ -55,35 +49,27 @@ export interface NativeEnv {
55
49
  [key: string]: string | undefined;
56
50
  }
57
51
  /**
58
- * Split a prebuild target into its three axes.
59
- *
60
- * TOKEN GRAMMAR: `<os>-<arch>[-musl]`.
61
- *
62
- * An UNSUFFIXED token means "the default build". Note what it does NOT mean: it
63
- * is not a synonym for glibc. For an artifact that links `libc.so.6` the default
64
- * build IS glibc; for one that links only GLib/GObject/GIO (plus GnuTLS resp.
65
- * GStreamer) it is libc-AGNOSTIC and loads against whatever libc the host's GLib
66
- * was built for. The directory name cannot express that difference and does not
67
- * need to: the package's own `libc` field answers it at install time, and the
68
- * `prebuild-libc` conformance rule verifies that field against the binaries
69
- * (`readElfNeeded` — the DT_NEEDED list is where the answer actually lives).
70
- *
71
- * DELIBERATELY NOT CHOSEN: renaming every existing `linux-<arch>` directory to
72
- * `linux-<arch>-gnu`, which is what a symmetric grammar would demand. It would
73
- * rename ~60 COMMITTED directories, and — per `status/open-todos.md`'s
74
- * "Nine fixtures re-implement the prebuild-target name instead of importing it"
75
- * — nine e2e fixtures COMPOSE the token themselves instead of importing it, so
76
- * the rename would have to be swept by hand in two shapes (the literal path and
77
- * the computed one), which is exactly how the last vocabulary change missed
78
- * `tests/e2e/self-host/run.mjs`. The asymmetric grammar buys the same
79
- * expressiveness for zero renames, and the cost — that "unsuffixed" is not
80
- * self-describing — is paid by a field that is machine-checked anyway.
81
- *
82
- * A `-musl` suffix is only meaningful when the OS half is `linux`: musl targets
83
- * no other kernel, and npm's own `libc` field is documented as Linux-only. A
84
- * `darwin-arm64-musl` token is therefore not a target with an odd name, it is a
85
- * malformed one, and this returns `libc: null` for it so callers report the
86
- * token rather than half-honouring it.
52
+ * Split a prebuild target into its three axes. TOKEN GRAMMAR: `<os>-<arch>[-musl]`.
53
+ *
54
+ * An UNSUFFIXED token means "the default build", NOT a synonym for glibc. For an
55
+ * artifact linking `libc.so.6` the default build IS glibc; for one linking only
56
+ * GLib/GObject/GIO it is libc-AGNOSTIC and loads against whatever libc the host's GLib
57
+ * was built for. The directory name cannot express that and does not need to — the
58
+ * package's own `libc` field answers it at install time, verified against the binaries'
59
+ * DT_NEEDED list by the `prebuild-libc` conformance rule.
60
+ *
61
+ * DELIBERATELY NOT CHOSEN: the symmetric grammar, renaming every `linux-<arch>` to
62
+ * `linux-<arch>-gnu`. That is ~60 committed directories plus nine e2e fixtures that
63
+ * COMPOSE the token instead of importing it (open-todos: "Nine fixtures re-implement
64
+ * the prebuild-target name instead of importing it"), so the sweep would have to be
65
+ * done by hand in two shapes — the literal path and the computed one — which is
66
+ * exactly how the last vocabulary change missed `tests/e2e/self-host/run.mjs`. The
67
+ * asymmetric grammar is equally expressive for zero renames.
68
+ *
69
+ * A `-musl` suffix is only meaningful when the OS half is `linux`: musl targets no
70
+ * other kernel and npm's `libc` field is documented Linux-only. `darwin-arm64-musl` is
71
+ * therefore malformed rather than oddly named, and this returns `libc: null` for it so
72
+ * callers report the token instead of half-honouring it.
87
73
  */
88
74
  export declare function parsePlatformToken(token: string): {
89
75
  os: string;
@@ -91,83 +77,64 @@ export declare function parsePlatformToken(token: string): {
91
77
  libc: HostLibc | null;
92
78
  };
93
79
  /**
94
- * Canonical `<os>-<arch>[-musl]` form — the node spelling — so `linux-x86_64`
95
- * and `linux-x64` compare equal. Only the *arch* half is normalised: the OS half
96
- * is always a `process.platform` token (`linux`/`darwin`/`win32`), which has no
97
- * competing spelling, and the libc half has exactly one spelling by
98
- * construction.
99
- *
100
- * A `-musl` suffix on a non-Linux token is preserved verbatim rather than
101
- * dropped. Silently canonicalising `darwin-arm64-musl` to `darwin-arm64` would
102
- * make a malformed declaration compare EQUAL to a valid one, so the audit that
103
- * rejects it would never see it — the same class of bug as folding the legacy
104
- * uname spelling on a WRITE path.
80
+ * Canonical `<os>-<arch>[-musl]` (node spelling) so `linux-x86_64` and `linux-x64`
81
+ * compare equal. Only the *arch* half is normalised — the OS half is always a
82
+ * `process.platform` token with no competing spelling, and the libc half has exactly
83
+ * one spelling by construction.
84
+ *
85
+ * A `-musl` suffix on a non-Linux token is preserved rather than dropped: silently
86
+ * canonicalising `darwin-arm64-musl` to `darwin-arm64` would make a malformed
87
+ * declaration compare EQUAL to a valid one, so the audit that rejects it would never
88
+ * see it.
105
89
  */
106
90
  export declare function canonicalPlatformToken(token: string): string;
107
91
  /**
108
- * The target tokens that describe THIS host, most-specific first — the WRITE-side
109
- * vocabulary.
110
- *
111
- * This is the single definition of the musl preference order, and three callers
112
- * share it so it cannot drift: the directory probe ({@link prebuildDirCandidates}),
113
- * the per-platform sibling package probe ({@link platformPackageName}), and
114
- * `scripts/stage-prebuild.mjs`, which must stage a musl build into
115
- * `linux-x64-musl/` and never into `linux-x64/`.
116
- *
117
- * On a musl host the suffixed token comes FIRST and the unsuffixed one stays as a
118
- * fallback: an unsuffixed directory is the default build, which for the
119
- * libc-agnostic bridges (they record no `libc.so.6` at all) genuinely does load
120
- * on musl. On glibc the `-musl` token is not offered at all — a musl artifact
121
- * cannot load against glibc, so probing for it could only ever produce a
122
- * false positive.
123
- *
124
- * @param platform `process.platform` value.
125
- * @param arch `process.arch` value.
126
- * @param libc host C library; `undefined`/`null` behaves as glibc (see
127
- * {@link HostTarget.libc} for why that is the safe default).
92
+ * The target tokens describing THIS host, most-specific first — the WRITE-side
93
+ * vocabulary, and the SINGLE definition of the musl preference order. Three callers
94
+ * share it so it cannot drift: the directory probe ({@link prebuildDirCandidates}), the
95
+ * companion-package probe ({@link platformPackageName}), and `scripts/stage-prebuild.mjs`,
96
+ * which must stage a musl build into `linux-x64-musl/` and never into `linux-x64/`.
97
+ *
98
+ * On a musl host the suffixed token comes FIRST with the unsuffixed one as fallback,
99
+ * because an unsuffixed directory is the default build and the libc-agnostic bridges
100
+ * (no `libc.so.6` recorded at all) genuinely do load on musl. On glibc the `-musl`
101
+ * token is not offered at all — a musl artifact cannot load against glibc, so probing
102
+ * for it could only produce a false positive.
103
+ *
104
+ * @param libc `undefined`/`null` behaves as glibc — see {@link HostTarget.libc}.
128
105
  */
129
106
  export declare function hostPlatformTokens(platform: string, arch: string, libc?: HostLibc | null): string[];
130
107
  /**
131
108
  * The prebuild directory names to probe for a host, most-specific first.
132
109
  *
133
- * The canonical name is `${process.platform}-${process.arch}` — `linux-x64`,
134
- * `linux-arm64`, `darwin-arm64`, `win32-x64`. Every package in the release
135
- * train declares it (`gjsify.platforms`), `scripts/stage-prebuild.mjs` is the
136
- * only thing that creates it, and `scripts/audit-runtimes.mjs --check` rejects
137
- * any other spelling, so the three can no longer drift.
138
- *
139
- * Two probes remain BEHIND that canonical name, and both are backward
140
- * compatibility with tarballs already on npm — not a second convention:
141
- *
142
- * 1. **The package's own declared spelling.** A tarball published before the
143
- * rename declares (and ships) `linux-x86_64`; probing its declaration
144
- * first loads it without the CLI having to guess. This is also what makes
145
- * the rename work in the OTHER direction — an older CLI resolving a newer
146
- * package — because `canonicalPlatformToken` folds both spellings onto
147
- * one form at both ends.
148
- * 2. **The legacy uname spelling.** Only reachable for a package that ships
149
- * a prebuild dir and declares NO `gjsify.platforms` at all — i.e. a
150
- * tarball predating the OS-axis audit, or a third-party package using
151
- * `gjsify.prebuilds` without the declaration. Inside this repo the audit
152
- * makes that state impossible.
153
- *
154
- * Both are pure array entries matched against an already-read directory
155
- * listing — no extra I/O — so tolerance on the READ side costs nothing, while
156
- * the single spelling is enforced everywhere a name is WRITTEN.
157
- *
158
- * The LIBC AXIS rides in front of all of that: on a musl host the
159
- * `<os>-<arch>-musl` token is preferred over `<os>-<arch>`, and on glibc the
160
- * suffixed token is NEVER offered (a musl artifact cannot load against glibc, so
161
- * a probe for it can only produce a false positive). The `libc` value is a
162
- * PARAMETER rather than a `process` read for the same reason `platform` and
163
- * `arch` are: it is the only way the musl branch gets exercised at all, since CI
164
- * and every developer machine here run glibc.
165
- *
166
- * @param platform `process.platform` value.
167
- * @param arch `process.arch` value.
110
+ * The canonical name is `${process.platform}-${process.arch}`. Every package in the
111
+ * release train declares it (`gjsify.platforms`), `scripts/stage-prebuild.mjs` is the
112
+ * only thing that creates it, and `scripts/audit-runtimes.mjs --check` rejects any
113
+ * other spelling, so the three cannot drift.
114
+ *
115
+ * Two probes sit BEHIND it, both backward compatibility with tarballs already on npm
116
+ * rather than a second convention:
117
+ *
118
+ * 1. **The package's own declared spelling.** A pre-rename tarball declares and
119
+ * ships `linux-x86_64`, so probing its declaration first loads it without
120
+ * guessing. This is also what makes the rename work in the OTHER direction (an
121
+ * older CLI, a newer package), since `canonicalPlatformToken` folds both
122
+ * spellings onto one form at both ends.
123
+ * 2. **The legacy uname spelling.** Only reachable for a package that ships a
124
+ * prebuild dir and declares NO `gjsify.platforms` — a tarball predating the
125
+ * OS-axis audit, or a third-party package. The audit makes that state impossible
126
+ * inside this repo.
127
+ *
128
+ * Both are array entries matched against an already-read directory listing, so
129
+ * tolerance on the READ side costs no I/O while the single spelling stays enforced
130
+ * everywhere a name is WRITTEN.
131
+ *
132
+ * The LIBC AXIS rides in front of all of it (see {@link hostPlatformTokens}). `libc` is
133
+ * a PARAMETER rather than a `process` read for the same reason `platform` and `arch`
134
+ * are: it is the only way the musl branch is exercised at all, since CI and every
135
+ * developer machine here run glibc.
136
+ *
168
137
  * @param declaredPlatforms `package.json#gjsify.platforms`, when present.
169
- * @param libc host C library; `undefined`/`null` = behave as before the axis
170
- * existed.
171
138
  */
172
139
  export declare function prebuildDirCandidates(platform: string, arch: string, declaredPlatforms?: readonly string[] | undefined, libc?: HostLibc | null): string[];
173
140
  /**
@@ -1,44 +1,37 @@
1
- // Utility to find npm packages with gjsify native prebuilds.
2
- // Packages declare: "gjsify": { "prebuilds": "<dir>" } in their package.json,
3
- // and (since the OS-axis audit) the `<os>-<arch>[-musl]` targets they promise in
4
- // "gjsify": { "platforms": [...] }. The libc half of that token is the newest
5
- // axis; which libc a package's artifacts actually NEED is a separate, measured
6
- // claim (npm's `libc` field + `gjsify.glibcRequires`, held to the binaries by the
7
- // `prebuild-libc` conformance rule) — this file only resolves DIRECTORIES.
1
+ // Find npm packages carrying gjsify native prebuilds. Packages declare
2
+ // `"gjsify": { "prebuilds": "<dir>" }` plus the `<os>-<arch>[-musl]` targets they
3
+ // promise in `"gjsify": { "platforms": [...] }`. This file only resolves
4
+ // DIRECTORIES — which libc a package's artifacts actually NEED is a separate
5
+ // measured claim (npm's `libc` field + `gjsify.glibcRequires`, held to the binaries
6
+ // by the `prebuild-libc` conformance rule).
8
7
  //
9
- // TWO passes, and the second one exists because the first cannot see an isolated
10
- // (pnpm-style) layout: `detectNativePackages(startDir)` walks up from `startDir`
11
- // and exhaustively scans every `node_modules` it finds, then resolves any package
12
- // that DECLARED a prebuild without shipping one through its per-platform
13
- // companion package (`<name>-<token>`), searching from THAT package's own
14
- // directory. See `resolvePlatformSibling`. Used by:
8
+ // TWO passes. `detectNativePackages(startDir)` walks up from `startDir` scanning
9
+ // every `node_modules`, then resolves any package that DECLARED a prebuild without
10
+ // shipping one through its per-platform companion (`<name>-<token>`), searching
11
+ // from THAT package's own directory (`resolvePlatformSibling`). The second pass
12
+ // exists because the first cannot see an isolated (pnpm-style) layout. Call sites:
15
13
  // * `gjsify run`, `gjsify info`, `gjsify install` — startDir = process.cwd()
16
- // * `runGjsBundle()` — startDir = dirname(bundlePath), so DLX-cache layouts
17
- // (`~/.cache/gjsify/dlx/<sha>/.../node_modules/<pkg>/dist/bundle.js`) get
18
- // their full transitive prebuild set picked up automatically. The
19
- // transitive walk is what makes `gjsify showcase` / `gjsify dlx` work
20
- // for packages whose Vala typelibs live in *indirect* deps.
14
+ // * `runGjsBundle()` — startDir = dirname(bundlePath), so DLX-cache layouts pick
15
+ // up their full transitive prebuild set. That transitive walk is what makes
16
+ // `gjsify showcase` / `gjsify dlx` work for packages whose Vala typelibs live
17
+ // in *indirect* deps.
21
18
  //
22
- // PLATFORM RESOLUTION IS A PURE FUNCTION. Everything that depends on the host
23
- // OS/CPU/libc lives in `resolvePrebuildDirName()` / `buildNativeEnv()` /
24
- // `resolveHostLibc()`, all of which take `platform` / `arch` / `libc` as
25
- // parameters instead of reading `process.platform` inline. That is what makes
26
- // the darwin, win32 AND musl branches unit-testable from a glibc Linux host
27
- // (see `detect-native-packages.spec.ts`) — the host values are only read at the
28
- // outermost call site, as a default.
19
+ // PLATFORM RESOLUTION IS A PURE FUNCTION: `resolvePrebuildDirName()`,
20
+ // `buildNativeEnv()` and `resolveHostLibc()` take `platform`/`arch`/`libc` as
21
+ // parameters instead of reading `process.*` inline, which is what makes the darwin,
22
+ // win32 AND musl branches unit-testable from a glibc Linux host. The host values
23
+ // are read only at the outermost call site, as a default.
29
24
  import { readdirSync, existsSync } from 'node:fs';
30
25
  import { join, resolve } from 'node:path';
31
26
  import { readPackageJson } from './pkg-json.js';
32
27
  import { splitSearchPath, systemGiLibraryDirs } from './system-gi.js';
33
28
  /**
34
- * Map a Node `process.arch` value to the uname-style spelling the Vala/meson
35
- * bridges used to stage into (`prebuilds/linux-x86_64/`, the output of
36
- * `uname -m` on the build host).
37
- *
38
- * LEGACY. Every `@gjsify/*` package now declares and stages the node spelling
39
- * (`linux-x64`); this table exists only so the CLI can still load a prebuild
40
- * out of a tarball published before the rename. See
41
- * {@link prebuildDirCandidates}.
29
+ * Node `process.arch` → the uname-style spelling the Vala/meson bridges used to stage
30
+ * into (`prebuilds/linux-x86_64/`).
31
+ *
32
+ * LEGACY: every `@gjsify/*` package now stages the node spelling (`linux-x64`), and
33
+ * this table exists only so the CLI can still load a prebuild out of a tarball
34
+ * published before the rename. See {@link prebuildDirCandidates}.
42
35
  */
43
36
  const NODE_ARCH_TO_LEGACY_UNAME = {
44
37
  x64: 'x86_64',
@@ -47,16 +40,14 @@ const NODE_ARCH_TO_LEGACY_UNAME = {
47
40
  ia32: 'i686',
48
41
  };
49
42
  /**
50
- * Arch spellings that name the same target, folded onto the NODE spelling.
51
- * Mirrors `ARCH_ALIASES` in `packages/infra/manifest-conformance/lib/platforms.mjs`
52
- * — the table `scripts/audit-runtimes.mjs` canonicalises
53
- * `package.json#gjsify.platforms` through for the platform-support matrix and the
54
- * prebuild rules. The two MUST agree or a package could pass the audit while the
55
- * CLI fails to find its artifact.
56
- *
57
- * The direction matters: `${process.platform}-${process.arch}` is what a
58
- * running process can compute about itself, so folding *onto* it means the
59
- * host identity never has to be translated in the hot path.
43
+ * Arch spellings that name the same target, folded onto the NODE spelling. MUST agree
44
+ * with `ARCH_ALIASES` in `packages/infra/manifest-conformance/lib/platforms.mjs` (what
45
+ * `scripts/audit-runtimes.mjs` canonicalises `gjsify.platforms` through), or a package
46
+ * passes the audit while the CLI fails to find its artifact.
47
+ *
48
+ * The direction matters: `${process.platform}-${process.arch}` is what a running
49
+ * process can compute about itself, so folding *onto* it means the host identity is
50
+ * never translated in the hot path.
60
51
  */
61
52
  const ARCH_ALIASES = {
62
53
  x86_64: 'x64',
@@ -70,35 +61,27 @@ const ARCH_ALIASES = {
70
61
  */
71
62
  const MUSL_SUFFIX = '-musl';
72
63
  /**
73
- * Split a prebuild target into its three axes.
74
- *
75
- * TOKEN GRAMMAR: `<os>-<arch>[-musl]`.
76
- *
77
- * An UNSUFFIXED token means "the default build". Note what it does NOT mean: it
78
- * is not a synonym for glibc. For an artifact that links `libc.so.6` the default
79
- * build IS glibc; for one that links only GLib/GObject/GIO (plus GnuTLS resp.
80
- * GStreamer) it is libc-AGNOSTIC and loads against whatever libc the host's GLib
81
- * was built for. The directory name cannot express that difference and does not
82
- * need to: the package's own `libc` field answers it at install time, and the
83
- * `prebuild-libc` conformance rule verifies that field against the binaries
84
- * (`readElfNeeded` — the DT_NEEDED list is where the answer actually lives).
85
- *
86
- * DELIBERATELY NOT CHOSEN: renaming every existing `linux-<arch>` directory to
87
- * `linux-<arch>-gnu`, which is what a symmetric grammar would demand. It would
88
- * rename ~60 COMMITTED directories, and — per `status/open-todos.md`'s
89
- * "Nine fixtures re-implement the prebuild-target name instead of importing it"
90
- * — nine e2e fixtures COMPOSE the token themselves instead of importing it, so
91
- * the rename would have to be swept by hand in two shapes (the literal path and
92
- * the computed one), which is exactly how the last vocabulary change missed
93
- * `tests/e2e/self-host/run.mjs`. The asymmetric grammar buys the same
94
- * expressiveness for zero renames, and the cost — that "unsuffixed" is not
95
- * self-describing — is paid by a field that is machine-checked anyway.
96
- *
97
- * A `-musl` suffix is only meaningful when the OS half is `linux`: musl targets
98
- * no other kernel, and npm's own `libc` field is documented as Linux-only. A
99
- * `darwin-arm64-musl` token is therefore not a target with an odd name, it is a
100
- * malformed one, and this returns `libc: null` for it so callers report the
101
- * token rather than half-honouring it.
64
+ * Split a prebuild target into its three axes. TOKEN GRAMMAR: `<os>-<arch>[-musl]`.
65
+ *
66
+ * An UNSUFFIXED token means "the default build", NOT a synonym for glibc. For an
67
+ * artifact linking `libc.so.6` the default build IS glibc; for one linking only
68
+ * GLib/GObject/GIO it is libc-AGNOSTIC and loads against whatever libc the host's GLib
69
+ * was built for. The directory name cannot express that and does not need to — the
70
+ * package's own `libc` field answers it at install time, verified against the binaries'
71
+ * DT_NEEDED list by the `prebuild-libc` conformance rule.
72
+ *
73
+ * DELIBERATELY NOT CHOSEN: the symmetric grammar, renaming every `linux-<arch>` to
74
+ * `linux-<arch>-gnu`. That is ~60 committed directories plus nine e2e fixtures that
75
+ * COMPOSE the token instead of importing it (open-todos: "Nine fixtures re-implement
76
+ * the prebuild-target name instead of importing it"), so the sweep would have to be
77
+ * done by hand in two shapes — the literal path and the computed one — which is
78
+ * exactly how the last vocabulary change missed `tests/e2e/self-host/run.mjs`. The
79
+ * asymmetric grammar is equally expressive for zero renames.
80
+ *
81
+ * A `-musl` suffix is only meaningful when the OS half is `linux`: musl targets no
82
+ * other kernel and npm's `libc` field is documented Linux-only. `darwin-arm64-musl` is
83
+ * therefore malformed rather than oddly named, and this returns `libc: null` for it so
84
+ * callers report the token instead of half-honouring it.
102
85
  */
103
86
  export function parsePlatformToken(token) {
104
87
  const isMusl = token.endsWith(MUSL_SUFFIX);
@@ -109,17 +92,15 @@ export function parsePlatformToken(token) {
109
92
  return { os, arch, libc: isMusl && os === 'linux' ? 'musl' : null };
110
93
  }
111
94
  /**
112
- * Canonical `<os>-<arch>[-musl]` form — the node spelling — so `linux-x86_64`
113
- * and `linux-x64` compare equal. Only the *arch* half is normalised: the OS half
114
- * is always a `process.platform` token (`linux`/`darwin`/`win32`), which has no
115
- * competing spelling, and the libc half has exactly one spelling by
116
- * construction.
117
- *
118
- * A `-musl` suffix on a non-Linux token is preserved verbatim rather than
119
- * dropped. Silently canonicalising `darwin-arm64-musl` to `darwin-arm64` would
120
- * make a malformed declaration compare EQUAL to a valid one, so the audit that
121
- * rejects it would never see it — the same class of bug as folding the legacy
122
- * uname spelling on a WRITE path.
95
+ * Canonical `<os>-<arch>[-musl]` (node spelling) so `linux-x86_64` and `linux-x64`
96
+ * compare equal. Only the *arch* half is normalised — the OS half is always a
97
+ * `process.platform` token with no competing spelling, and the libc half has exactly
98
+ * one spelling by construction.
99
+ *
100
+ * A `-musl` suffix on a non-Linux token is preserved rather than dropped: silently
101
+ * canonicalising `darwin-arm64-musl` to `darwin-arm64` would make a malformed
102
+ * declaration compare EQUAL to a valid one, so the audit that rejects it would never
103
+ * see it.
123
104
  */
124
105
  export function canonicalPlatformToken(token) {
125
106
  const { os, arch, libc } = parsePlatformToken(token);
@@ -128,37 +109,30 @@ export function canonicalPlatformToken(token) {
128
109
  const canonical = `${os}-${ARCH_ALIASES[arch] ?? arch}`;
129
110
  if (libc === 'musl')
130
111
  return `${canonical}${MUSL_SUFFIX}`;
131
- // Not a Linux musl token, so `-musl` (if present at all) is not a libc
132
- // suffix this grammar recognises — keep the token intact.
112
+ // Not a Linux musl token, so any `-musl` here is not a libc suffix this grammar
113
+ // recognises — keep the token intact.
133
114
  return token.endsWith(MUSL_SUFFIX) ? `${canonical}${MUSL_SUFFIX}` : canonical;
134
115
  }
135
116
  /**
136
- * The target tokens that describe THIS host, most-specific first — the WRITE-side
137
- * vocabulary.
138
- *
139
- * This is the single definition of the musl preference order, and three callers
140
- * share it so it cannot drift: the directory probe ({@link prebuildDirCandidates}),
141
- * the per-platform sibling package probe ({@link platformPackageName}), and
142
- * `scripts/stage-prebuild.mjs`, which must stage a musl build into
143
- * `linux-x64-musl/` and never into `linux-x64/`.
144
- *
145
- * On a musl host the suffixed token comes FIRST and the unsuffixed one stays as a
146
- * fallback: an unsuffixed directory is the default build, which for the
147
- * libc-agnostic bridges (they record no `libc.so.6` at all) genuinely does load
148
- * on musl. On glibc the `-musl` token is not offered at all — a musl artifact
149
- * cannot load against glibc, so probing for it could only ever produce a
150
- * false positive.
151
- *
152
- * @param platform `process.platform` value.
153
- * @param arch `process.arch` value.
154
- * @param libc host C library; `undefined`/`null` behaves as glibc (see
155
- * {@link HostTarget.libc} for why that is the safe default).
117
+ * The target tokens describing THIS host, most-specific first — the WRITE-side
118
+ * vocabulary, and the SINGLE definition of the musl preference order. Three callers
119
+ * share it so it cannot drift: the directory probe ({@link prebuildDirCandidates}), the
120
+ * companion-package probe ({@link platformPackageName}), and `scripts/stage-prebuild.mjs`,
121
+ * which must stage a musl build into `linux-x64-musl/` and never into `linux-x64/`.
122
+ *
123
+ * On a musl host the suffixed token comes FIRST with the unsuffixed one as fallback,
124
+ * because an unsuffixed directory is the default build and the libc-agnostic bridges
125
+ * (no `libc.so.6` recorded at all) genuinely do load on musl. On glibc the `-musl`
126
+ * token is not offered at all — a musl artifact cannot load against glibc, so probing
127
+ * for it could only produce a false positive.
128
+ *
129
+ * @param libc `undefined`/`null` behaves as glibc — see {@link HostTarget.libc}.
156
130
  */
157
131
  export function hostPlatformTokens(platform, arch, libc) {
158
132
  const canonical = `${platform}-${arch}`;
159
- // The suffix is Linux-only by construction, so a `libc: 'musl'` handed in
160
- // for darwin/win32 is ignored rather than trusted — the caller's host facts
161
- // do not get to invent a target the grammar does not have.
133
+ // The suffix is Linux-only by construction, so a `libc: 'musl'` handed in for
134
+ // darwin/win32 is ignored rather than trusted: the caller's host facts do not get
135
+ // to invent a target the grammar does not have.
162
136
  if (libc === 'musl' && platform === 'linux')
163
137
  return [`${canonical}${MUSL_SUFFIX}`, canonical];
164
138
  return [canonical];
@@ -166,44 +140,34 @@ export function hostPlatformTokens(platform, arch, libc) {
166
140
  /**
167
141
  * The prebuild directory names to probe for a host, most-specific first.
168
142
  *
169
- * The canonical name is `${process.platform}-${process.arch}` — `linux-x64`,
170
- * `linux-arm64`, `darwin-arm64`, `win32-x64`. Every package in the release
171
- * train declares it (`gjsify.platforms`), `scripts/stage-prebuild.mjs` is the
172
- * only thing that creates it, and `scripts/audit-runtimes.mjs --check` rejects
173
- * any other spelling, so the three can no longer drift.
174
- *
175
- * Two probes remain BEHIND that canonical name, and both are backward
176
- * compatibility with tarballs already on npm — not a second convention:
177
- *
178
- * 1. **The package's own declared spelling.** A tarball published before the
179
- * rename declares (and ships) `linux-x86_64`; probing its declaration
180
- * first loads it without the CLI having to guess. This is also what makes
181
- * the rename work in the OTHER direction — an older CLI resolving a newer
182
- * package — because `canonicalPlatformToken` folds both spellings onto
183
- * one form at both ends.
184
- * 2. **The legacy uname spelling.** Only reachable for a package that ships
185
- * a prebuild dir and declares NO `gjsify.platforms` at all — i.e. a
186
- * tarball predating the OS-axis audit, or a third-party package using
187
- * `gjsify.prebuilds` without the declaration. Inside this repo the audit
188
- * makes that state impossible.
189
- *
190
- * Both are pure array entries matched against an already-read directory
191
- * listing — no extra I/O — so tolerance on the READ side costs nothing, while
192
- * the single spelling is enforced everywhere a name is WRITTEN.
193
- *
194
- * The LIBC AXIS rides in front of all of that: on a musl host the
195
- * `<os>-<arch>-musl` token is preferred over `<os>-<arch>`, and on glibc the
196
- * suffixed token is NEVER offered (a musl artifact cannot load against glibc, so
197
- * a probe for it can only produce a false positive). The `libc` value is a
198
- * PARAMETER rather than a `process` read for the same reason `platform` and
199
- * `arch` are: it is the only way the musl branch gets exercised at all, since CI
200
- * and every developer machine here run glibc.
201
- *
202
- * @param platform `process.platform` value.
203
- * @param arch `process.arch` value.
143
+ * The canonical name is `${process.platform}-${process.arch}`. Every package in the
144
+ * release train declares it (`gjsify.platforms`), `scripts/stage-prebuild.mjs` is the
145
+ * only thing that creates it, and `scripts/audit-runtimes.mjs --check` rejects any
146
+ * other spelling, so the three cannot drift.
147
+ *
148
+ * Two probes sit BEHIND it, both backward compatibility with tarballs already on npm
149
+ * rather than a second convention:
150
+ *
151
+ * 1. **The package's own declared spelling.** A pre-rename tarball declares and
152
+ * ships `linux-x86_64`, so probing its declaration first loads it without
153
+ * guessing. This is also what makes the rename work in the OTHER direction (an
154
+ * older CLI, a newer package), since `canonicalPlatformToken` folds both
155
+ * spellings onto one form at both ends.
156
+ * 2. **The legacy uname spelling.** Only reachable for a package that ships a
157
+ * prebuild dir and declares NO `gjsify.platforms` — a tarball predating the
158
+ * OS-axis audit, or a third-party package. The audit makes that state impossible
159
+ * inside this repo.
160
+ *
161
+ * Both are array entries matched against an already-read directory listing, so
162
+ * tolerance on the READ side costs no I/O while the single spelling stays enforced
163
+ * everywhere a name is WRITTEN.
164
+ *
165
+ * The LIBC AXIS rides in front of all of it (see {@link hostPlatformTokens}). `libc` is
166
+ * a PARAMETER rather than a `process` read for the same reason `platform` and `arch`
167
+ * are: it is the only way the musl branch is exercised at all, since CI and every
168
+ * developer machine here run glibc.
169
+ *
204
170
  * @param declaredPlatforms `package.json#gjsify.platforms`, when present.
205
- * @param libc host C library; `undefined`/`null` = behave as before the axis
206
- * existed.
207
171
  */
208
172
  export function prebuildDirCandidates(platform, arch, declaredPlatforms, libc) {
209
173
  const hostTokens = hostPlatformTokens(platform, arch, libc);
@@ -213,10 +177,8 @@ export function prebuildDirCandidates(platform, arch, declaredPlatforms, libc) {
213
177
  if (!out.includes(name))
214
178
  out.push(name);
215
179
  };
216
- // 1. The package's own declared spelling for each host token, most-specific
217
- // token first. Keyed off the SAME host-token list as step 2, so a musl
218
- // host that finds `linux-x64-musl` in `gjsify.platforms` prefers it over
219
- // a declared `linux-x64` — the declaration probe must not be able to
180
+ // 1. The package's own declared spelling per host token, most-specific first. Keyed
181
+ // off the SAME host-token list as step 2, so the declaration probe cannot
220
182
  // reorder the libc preference.
221
183
  for (const token of hostTokens) {
222
184
  for (const declared of declaredPlatforms ?? []) {