@gjsify/cli 0.43.0 → 0.45.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 (87) hide show
  1. package/dist/cli.gjs.mjs +453 -425
  2. package/lib/actions/build.js +2 -1
  3. package/lib/commands/affected-classify.js +7 -5
  4. package/lib/commands/build.js +6 -0
  5. package/lib/commands/flatpak/ci.js +10 -2
  6. package/lib/commands/flatpak/init.js +15 -16
  7. package/lib/commands/flatpak/utils.d.ts +0 -26
  8. package/lib/commands/flatpak/utils.js +4 -29
  9. package/lib/commands/gettext.d.ts +2 -1
  10. package/lib/commands/gettext.js +105 -47
  11. package/lib/commands/onboard.d.ts +7 -0
  12. package/lib/commands/onboard.js +349 -96
  13. package/lib/commands/ship.d.ts +3 -0
  14. package/lib/commands/ship.js +911 -70
  15. package/lib/commands/trust.d.ts +6 -0
  16. package/lib/commands/trust.js +1 -1
  17. package/lib/config.js +25 -0
  18. package/lib/types/cli-build-options.d.ts +11 -0
  19. package/lib/types/config-data.d.ts +137 -3
  20. package/lib/utils/flatpak-runtime.d.ts +41 -0
  21. package/lib/utils/flatpak-runtime.js +54 -0
  22. package/lib/utils/msgfmt-merge.d.ts +35 -0
  23. package/lib/utils/msgfmt-merge.js +102 -0
  24. package/lib/utils/npm-otp.d.ts +27 -2
  25. package/lib/utils/npm-otp.js +82 -7
  26. package/lib/utils/onboard-discovery.d.ts +68 -0
  27. package/lib/utils/onboard-discovery.js +178 -0
  28. package/lib/utils/onboard-probe.d.ts +118 -1
  29. package/lib/utils/onboard-probe.js +153 -4
  30. package/lib/utils/prompt-output.d.ts +12 -0
  31. package/lib/utils/prompt-output.js +54 -0
  32. package/lib/utils/prompt.js +22 -2
  33. package/lib/utils/publishable-packages.d.ts +1 -1
  34. package/lib/utils/publishable-packages.js +1 -0
  35. package/lib/utils/resolve-npm-package.d.ts +56 -0
  36. package/lib/utils/resolve-npm-package.js +69 -0
  37. package/lib/utils/ship/app-runtime.d.ts +214 -0
  38. package/lib/utils/ship/app-runtime.js +429 -0
  39. package/lib/utils/ship/depends.d.ts +54 -7
  40. package/lib/utils/ship/depends.js +120 -6
  41. package/lib/utils/ship/discover.js +18 -1
  42. package/lib/utils/ship/dmg.d.ts +71 -0
  43. package/lib/utils/ship/dmg.js +181 -0
  44. package/lib/utils/ship/flatpak-config.d.ts +66 -0
  45. package/lib/utils/ship/flatpak-config.js +132 -0
  46. package/lib/utils/ship/flatpak.d.ts +45 -0
  47. package/lib/utils/ship/flatpak.js +148 -0
  48. package/lib/utils/ship/formats.d.ts +116 -3
  49. package/lib/utils/ship/formats.js +869 -11
  50. package/lib/utils/ship/launcher.d.ts +13 -3
  51. package/lib/utils/ship/launcher.js +362 -17
  52. package/lib/utils/ship/layout.d.ts +268 -0
  53. package/lib/utils/ship/layout.js +351 -0
  54. package/lib/utils/ship/localize-metadata.d.ts +22 -0
  55. package/lib/utils/ship/localize-metadata.js +126 -0
  56. package/lib/utils/ship/mime.js +1 -9
  57. package/lib/utils/ship/msi.d.ts +126 -0
  58. package/lib/utils/ship/msi.js +417 -0
  59. package/lib/utils/ship/node-runtime.d.ts +71 -0
  60. package/lib/utils/ship/node-runtime.js +122 -0
  61. package/lib/utils/ship/payload.d.ts +156 -5
  62. package/lib/utils/ship/payload.js +580 -14
  63. package/lib/utils/ship/plan.d.ts +21 -0
  64. package/lib/utils/ship/plan.js +20 -7
  65. package/lib/utils/ship/plist.d.ts +58 -0
  66. package/lib/utils/ship/plist.js +198 -0
  67. package/lib/utils/ship/rpm.js +9 -3
  68. package/lib/utils/ship/schemas.d.ts +61 -0
  69. package/lib/utils/ship/schemas.js +118 -0
  70. package/lib/utils/ship/scripts.js +7 -3
  71. package/lib/utils/ship/settings.d.ts +19 -1
  72. package/lib/utils/ship/settings.js +19 -1
  73. package/lib/utils/ship/share-dirs.d.ts +23 -0
  74. package/lib/utils/ship/share-dirs.js +46 -0
  75. package/lib/utils/ship/signing.d.ts +195 -0
  76. package/lib/utils/ship/signing.js +317 -0
  77. package/lib/utils/ship/stage-manifest.d.ts +50 -13
  78. package/lib/utils/ship/stage-manifest.js +137 -14
  79. package/lib/utils/ship/stage-writer.d.ts +48 -0
  80. package/lib/utils/ship/stage-writer.js +71 -1
  81. package/lib/utils/ship/types.d.ts +264 -16
  82. package/lib/utils/ship/xml.d.ts +7 -0
  83. package/lib/utils/ship/xml.js +25 -0
  84. package/lib/utils/ship/zip.d.ts +69 -0
  85. package/lib/utils/ship/zip.js +245 -0
  86. package/lib/utils/trust-registry.js +5 -0
  87. package/package.json +19 -19
@@ -1,3 +1,4 @@
1
+ import { type Layout, type LayoutIdentity } from './layout.js';
1
2
  /** One file in the payload, with its bytes. */
2
3
  export interface PayloadEntry {
3
4
  /** Prefix-relative path, POSIX-separated, e.g. `bin/learn6502`. */
@@ -46,6 +47,14 @@ export declare function buildTimestamp(bundlePath: string, env?: Record<string,
46
47
  * Path-only, on purpose — `isArchIndependent` is the sibling that reads BYTES, and the two answer
47
48
  * different questions from the same payload. The same split as `plan.ts`'s `isExecutableAsset`
48
49
  * (by name) versus this module's magic sniffing (by content).
50
+ *
51
+ * NOT EVERY QUESTION BELONGS HERE, and one that does not was briefly added: "does this package need
52
+ * a Node interpreter", derived from a `*.node.mjs` filename anywhere in the tree. Every fact above
53
+ * is about something the package INSTALLS at a well-known path, which is why a path answers it.
54
+ * That one was about what the launcher EXECS — and `discoverPayload` stages the whole directory
55
+ * beside the bundle, so a `--app gjs` project that also builds a Node bundle carried the file and
56
+ * ran neither. It lives on `settings.app` now, with `assertLauncherMatchesInterpreter` below as the
57
+ * check. Before adding a field here, ask whether a path can answer it or only correlate with it.
49
58
  */
50
59
  export interface PayloadFacts {
51
60
  /** The payload installs a `share/applications/*.desktop`. */
@@ -70,6 +79,123 @@ export interface PayloadFacts {
70
79
  export declare function readPayloadFacts(entries: readonly {
71
80
  path: string;
72
81
  }[]): PayloadFacts;
82
+ /**
83
+ * Every interpreter the STAGED launcher could exec, resolved to a bare name.
84
+ *
85
+ * WHY THIS IS READ BACK AT ALL, when `settings.app` already says so. Because
86
+ * `settings.app` says what the launcher was RENDERED from, and the dependency is
87
+ * a claim about what the installed package will RUN. Those were once two
88
+ * different things: the Node dependency was derived from a filename glob over
89
+ * the staged tree while `renderLauncher` execed `gjs` unconditionally, and the
90
+ * packer emitted `Depends: gjs (>= 1.86), nodejs (>= 24)` for a package that
91
+ * runs neither combination. Nothing in the pipeline compared them, and no
92
+ * structural check could: both artifacts were individually well-formed.
93
+ *
94
+ * A LIST, and every `exec` rather than one of them. The first cut took the first
95
+ * match while its own comment claimed the last — `/\nexec\s+/` is not global, so
96
+ * the two disagreed and the comment was the wrong one. Neither is right for a
97
+ * script this tree did not write: a launcher may exec different interpreters on
98
+ * different branches, and picking one branch's answer is a guess. Collecting
99
+ * them lets {@link assertLauncherMatchesInterpreter} ask the only question that
100
+ * is safe on a foreign script — see there.
101
+ *
102
+ * NAMES, not the tokens as written. `exec /usr/bin/gjs -m …` execs gjs, and an
103
+ * `env` prefix (`exec env NODE_OPTIONS=… node …`) execs whatever follows its
104
+ * assignments. Both are things `gjsify.ship.extraFiles` legitimately writes, and
105
+ * the raw-token version REFUSED them: measured, an untouched `--app gjs` project
106
+ * whose `extraFiles` replaced the launcher with `exec /usr/bin/gjs -m …` failed
107
+ * the pack at exit 1 with "execs `/usr/bin/gjs`, but this package would declare
108
+ * a dependency on `gjs`" — a working artifact rejected over a parser, which is
109
+ * exactly what the `null` branch was written to prevent and did not.
110
+ */
111
+ export declare function readLauncherInterpreters(payload: readonly PayloadEntry[], layout: Layout, identity: LayoutIdentity): string[];
112
+ /**
113
+ * Refuse a package whose launcher execs an interpreter the package does not
114
+ * depend on.
115
+ *
116
+ * THE RULE, and it is deliberately asymmetric: fail ONLY when the launcher
117
+ * positively names the OTHER known interpreter and never names the declared one.
118
+ * Everything else passes — no launcher, no `exec` this reader resolves, a program
119
+ * that is neither `gjs` nor `node`, or a script whose branches include the
120
+ * declared one.
121
+ *
122
+ * That asymmetry is the correction. The first cut failed whenever the resolved
123
+ * token was not equal to the declared interpreter, and its own doc comment
124
+ * claimed the opposite ("`null` is SILENT ... refusing a package because this
125
+ * function did not understand a launcher somebody else wrote would fail a
126
+ * working artifact over a parser"). The parser's failure mode is not `null` — it
127
+ * answers confidently wrong. Measured on an otherwise untouched `--app gjs`
128
+ * project whose `gjsify.ship.extraFiles` replaced `bin/<name>`:
129
+ *
130
+ * exec /usr/bin/gjs -m … → exit 1, "execs `/usr/bin/gjs`"
131
+ * exec env NODE_OPTIONS=… node… → exit 1, "execs `env`"
132
+ *
133
+ * Both worked before the check existed. A guard that turns working packages into
134
+ * failures buys nothing over the defect it prevents.
135
+ *
136
+ * The advice in the message is also fixed. It used to say "re-run the `--stage`
137
+ * phase", which is FALSE for the case that actually reaches a user: re-staging
138
+ * an `extraFiles` override reproduces it forever. The two real causes are named
139
+ * instead.
140
+ */
141
+ export declare function assertLauncherMatchesInterpreter(payload: readonly PayloadEntry[], layout: Layout, identity: LayoutIdentity, interpreter: 'gjs' | 'node'): void;
142
+ /**
143
+ * How a `share/` entry behaves once it leaves the layout a Linux package installs.
144
+ *
145
+ * `aborts` and `inert` are not one severity, and printing them as one was a
146
+ * measured presentation defect: every launcher exports `XDG_DATA_DIRS` at the
147
+ * staged `share/`, so a `.app` built from a stage with an UNCOMPILED schema
148
+ * directory points GSettings at an `.xml` with no `gschemas.compiled` beside it —
149
+ * `g_settings_new()` ABORTS. The others merely do nothing. Ranking them
150
+ * identically in a list of five buried the one that stops the app.
151
+ *
152
+ * #1354 M2a compiles that cache into every non-Linux stage, so `aborts` is empty
153
+ * for a stage this gjsify wrote. The variant STAYS, and reachable — see
154
+ * {@link SHARE_VERDICTS}'s schema row.
155
+ */
156
+ export type ShareVerdict = 'aborts' | 'inert' | 'unknown';
157
+ /** One `share/` entry a non-Linux layout carries, and what happens to it there. */
158
+ export interface CarriedShareEntry {
159
+ path: string;
160
+ verdict: ShareVerdict;
161
+ why: string;
162
+ }
163
+ /**
164
+ * Every `share/` entry a non-Linux layout carries, classified — including the
165
+ * ones nothing here has a rule for.
166
+ *
167
+ * WHY THIS EXISTS, and it is the hole the layout axis opened. `planStage` emits
168
+ * one prefix-relative plan and every layout carries it, so the darwin and windows
169
+ * trees hold the same `share/…` files the `.deb` does — and on Linux most of those
170
+ * are only correct because `cacheRefreshCommands` compiles or reindexes them at
171
+ * install time (`scripts.ts`), which is a `.deb`/`.rpm` scriptlet and nothing else.
172
+ *
173
+ * The equality `tests/e2e/ship-layout` checks — same file set, same bytes, modulo
174
+ * the map — is structurally blind to all of it, because SAMENESS IS THE DEFECT:
175
+ * the Linux tree is right for a reason the other two do not have.
176
+ *
177
+ * EXHAUSTIVE, not an allow-list, and that direction is the point. A closed list of
178
+ * five was measured to say "carries 5 file(s)" for a payload carrying six — a
179
+ * `share/dbus-1/services/*.service` added through `gjsify.ship.extraFiles` is
180
+ * meaningful on Linux only because the package installs it into a system prefix,
181
+ * and it went unnamed. Anything under `share/` that is neither classified nor
182
+ * known-portable comes back as `unknown` rather than silently passing.
183
+ *
184
+ * ONE ENTRY IS ANSWERED BY THE SET, not by its own path: the GSettings schema
185
+ * directory aborts the app when it holds a source `.gschema.xml` and no compiled
186
+ * cache, and is merely inert when the cache is beside it. #1354 M2a compiles that
187
+ * cache into every non-Linux stage, so the `aborts` branch is empty for a stage
188
+ * this gjsify wrote — and it is still REACHABLE, which is the point: a stage
189
+ * assembled before the compile step existed, or one whose cache was removed,
190
+ * classifies as `aborts` again with no rule to remember to re-add.
191
+ *
192
+ * What the rest BECOME — an `Info.plist` `CFBundleDocumentTypes`, a Windows
193
+ * registry association, or nothing — is ADR 0024 stages 4 and 5. The `.app`
194
+ * container exists as of M2a; the file-type and icon halves do not.
195
+ */
196
+ export declare function linuxInstallDependent(entries: readonly {
197
+ path: string;
198
+ }[]): CarriedShareEntry[];
73
199
  /**
74
200
  * The interpreters the payload's own executables need, read off their shebangs.
75
201
  *
@@ -108,11 +234,22 @@ export declare function isArchIndependent(payload: readonly PayloadEntry[]): boo
108
234
  * The `process.arch` token an image says it is built for, or `null` when the
109
235
  * question cannot be answered from the bytes.
110
236
  *
111
- * `null` covers three different things on purpose, and all three must stay
112
- * silent: a file that is not a native binary at all (most of a payload), a PE
113
- * (whose COFF machine field this tree has never parsed — `isNativeBinary` reads
114
- * `MZ` and stops), and a Mach-O fat archive, which carries several
115
- * architectures and therefore matches any label a caller could pass.
237
+ * `null` still covers three different things on purpose, and all three must stay
238
+ * silent: a file that is not a native binary at all (most of a payload), an image
239
+ * whose machine constant is not in the tables above, and a Mach-O fat archive,
240
+ * which carries several architectures and therefore matches any label a caller
241
+ * could pass.
242
+ *
243
+ * PE WAS A FOURTH, AND IT WAS THE WORST ONE. This comment used to say PE was
244
+ * silent because "this tree has never parsed" the COFF machine field — true, and
245
+ * it made `assertPayloadMatchesArch` VACUOUS on the one layout whose native format
246
+ * IS PE. #1354 M2b made that check non-vacuous for darwin by staging Mach-O into a
247
+ * `.app`; M3 stages `node.exe` and a win32 GTK closure into a Windows program
248
+ * directory, so a windows stage built with the wrong `--arch` would have carried
249
+ * x64 DLLs under an `arm64` label with nothing to notice. Two reads — `e_lfanew`
250
+ * at 0x3c, then `Machine` four bytes past the `PE\0\0` signature — close it. A
251
+ * truncated `MZ` with no reachable PE header stays `null`, which is what
252
+ * `packers.spec.ts` has always asserted and still does.
116
253
  */
117
254
  export declare function readBinaryArch(data: Uint8Array): string | null;
118
255
  /**
@@ -139,3 +276,17 @@ export declare function readBinaryArch(data: Uint8Array): string | null;
139
276
  * comparison would refuse the very case the split exists to allow.
140
277
  */
141
278
  export declare function assertPayloadMatchesArch(payload: readonly PayloadEntry[], arch: string): void;
279
+ /**
280
+ * Which executable format these bytes are, or `null` for anything else.
281
+ *
282
+ * The FAMILY and not merely "is it native", because the signer needs the
283
+ * distinction: `codesign` signs Mach-O and `signtool` signs PE, and an ELF in a
284
+ * darwin payload is neither — it is a file that should not be there. A caller
285
+ * asking only "is this native" would have handed one to `codesign`, whose
286
+ * refusal names a file rather than the mistake.
287
+ *
288
+ * Magic numbers rather than suffixes, and that is load-bearing on darwin: a GTK
289
+ * closure names its images `.dylib`, `.so`, `.node` and nothing at all (the
290
+ * interpreter), so a suffix list signs three of those four.
291
+ */
292
+ export declare function classifyBinary(data: Uint8Array): 'elf' | 'macho' | 'pe' | null;