@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.
- package/dist/cli.gjs.mjs +136 -126
- package/lib/actions/build.d.ts +19 -0
- package/lib/actions/build.js +2 -2
- package/lib/bundler-pick.js +72 -98
- package/lib/cli-fail.d.ts +4 -7
- package/lib/cli-fail.js +29 -55
- package/lib/commands/affected.js +161 -286
- package/lib/commands/install.d.ts +63 -66
- package/lib/commands/install.js +372 -536
- package/lib/commands/run.d.ts +1 -0
- package/lib/commands/run.js +37 -0
- package/lib/templates/install.mjs.tmpl +38 -68
- package/lib/types/cli-build-options.d.ts +33 -67
- package/lib/types/command.d.ts +9 -12
- package/lib/types/config-data.d.ts +125 -221
- package/lib/utils/auth-npmrc.d.ts +5 -10
- package/lib/utils/auth-npmrc.js +11 -21
- package/lib/utils/check-system-deps.d.ts +16 -0
- package/lib/utils/check-system-deps.js +49 -0
- package/lib/utils/clear-targets.d.ts +8 -11
- package/lib/utils/clear-targets.js +22 -29
- package/lib/utils/copy-targets.d.ts +13 -19
- package/lib/utils/copy-targets.js +31 -44
- package/lib/utils/dep-aggregation.d.ts +7 -15
- package/lib/utils/dep-aggregation.js +9 -22
- package/lib/utils/detect-native-packages.d.ts +83 -116
- package/lib/utils/detect-native-packages.js +111 -149
- package/lib/utils/dir-link.d.ts +29 -48
- package/lib/utils/dir-link.js +33 -56
- package/lib/utils/discover-showcases.d.ts +6 -7
- package/lib/utils/discover-showcases.js +11 -15
- package/lib/utils/dlx-cache.d.ts +29 -38
- package/lib/utils/dlx-cache.js +53 -63
- package/lib/utils/force-exit.d.ts +0 -3
- package/lib/utils/force-exit.js +13 -24
- package/lib/utils/gi-search-path.d.ts +16 -24
- package/lib/utils/gi-search-path.js +54 -82
- package/lib/utils/gjs-bundle-guard.d.ts +5 -13
- package/lib/utils/gjs-bundle-guard.js +35 -57
- package/lib/utils/gjs-source-escape.d.ts +2 -2
- package/lib/utils/gjs-source-escape.js +21 -39
- package/lib/utils/gjsify-shim.d.ts +26 -8
- package/lib/utils/gjsify-shim.js +128 -80
- package/lib/utils/html-entry.d.ts +8 -12
- package/lib/utils/html-entry.js +19 -28
- package/lib/utils/install-backend-native.d.ts +123 -161
- package/lib/utils/install-backend-native.js +536 -737
- package/lib/utils/install-backend.d.ts +42 -57
- package/lib/utils/install-backend.js +16 -21
- package/lib/utils/install-cache-fs.d.ts +10 -15
- package/lib/utils/install-cache-fs.js +18 -26
- package/lib/utils/install-lock.d.ts +5 -6
- package/lib/utils/install-lock.js +46 -65
- package/lib/utils/install-packument-cache.d.ts +27 -33
- package/lib/utils/install-packument-cache.js +44 -57
- package/lib/utils/install-progress.d.ts +2 -9
- package/lib/utils/install-progress.js +14 -39
- package/lib/utils/install-tarball-cache.d.ts +14 -20
- package/lib/utils/install-tarball-cache.js +41 -59
- package/lib/utils/library-output.d.ts +9 -22
- package/lib/utils/library-output.js +19 -37
- package/lib/utils/load-npmrc.d.ts +5 -6
- package/lib/utils/load-npmrc.js +18 -27
- package/lib/utils/node-bundle-guard.d.ts +4 -8
- package/lib/utils/node-bundle-guard.js +21 -35
- package/lib/utils/node-script.d.ts +12 -0
- package/lib/utils/node-script.js +95 -0
- package/lib/utils/node-version.d.ts +5 -14
- package/lib/utils/node-version.js +15 -24
- package/lib/utils/normalize-bundler-options.d.ts +7 -11
- package/lib/utils/normalize-bundler-options.js +24 -42
- package/lib/utils/npm-oidc.d.ts +23 -37
- package/lib/utils/npm-oidc.js +28 -53
- package/lib/utils/npm-otp-cache.d.ts +4 -4
- package/lib/utils/npm-otp-cache.js +20 -25
- package/lib/utils/npm-otp.d.ts +20 -30
- package/lib/utils/npm-otp.js +32 -51
- package/lib/utils/onboard-probe.d.ts +7 -13
- package/lib/utils/onboard-probe.js +16 -27
- package/lib/utils/parse-spec.d.ts +3 -3
- package/lib/utils/parse-spec.js +4 -5
- package/lib/utils/pkg-json-edit.d.ts +7 -12
- package/lib/utils/pkg-json-edit.js +13 -26
- package/lib/utils/pkg-json.d.ts +11 -18
- package/lib/utils/pkg-json.js +19 -28
- package/lib/utils/prefixed-output.d.ts +3 -4
- package/lib/utils/prefixed-output.js +13 -19
- package/lib/utils/prompt.d.ts +3 -4
- package/lib/utils/prompt.js +14 -18
- package/lib/utils/publish-diagnose.d.ts +11 -16
- package/lib/utils/publish-diagnose.js +15 -28
- package/lib/utils/publish-headers.d.ts +7 -11
- package/lib/utils/publish-headers.js +36 -65
- package/lib/utils/publishable-packages.d.ts +4 -6
- package/lib/utils/publishable-packages.js +14 -18
- package/lib/utils/resolve-gjs-entry.d.ts +5 -8
- package/lib/utils/resolve-gjs-entry.js +10 -27
- package/lib/utils/resolve-npm-package.d.ts +6 -11
- package/lib/utils/resolve-npm-package.js +29 -63
- package/lib/utils/resolve-plugin-by-name.d.ts +11 -19
- package/lib/utils/resolve-plugin-by-name.js +9 -14
- package/lib/utils/run-gjs.d.ts +19 -17
- package/lib/utils/run-gjs.js +37 -51
- package/lib/utils/run-lifecycle-script.d.ts +5 -9
- package/lib/utils/run-lifecycle-script.js +23 -42
- package/lib/utils/run-node.d.ts +23 -33
- package/lib/utils/run-node.js +56 -60
- package/lib/utils/runtimes.d.ts +25 -35
- package/lib/utils/runtimes.js +34 -46
- package/lib/utils/spawn.d.ts +32 -48
- package/lib/utils/spawn.js +51 -84
- package/lib/utils/stdin.d.ts +2 -2
- package/lib/utils/stdin.js +10 -25
- package/lib/utils/suggest.d.ts +6 -7
- package/lib/utils/suggest.js +8 -10
- package/lib/utils/system-gi.d.ts +18 -27
- package/lib/utils/system-gi.js +60 -114
- package/lib/utils/trust-registry.d.ts +4 -8
- package/lib/utils/trust-registry.js +7 -15
- package/lib/utils/win32-command.d.ts +8 -14
- package/lib/utils/win32-command.js +29 -43
- package/lib/utils/workspace-root.js +7 -12
- package/package.json +18 -17
- package/showcases.json +6 -0
|
@@ -8,10 +8,9 @@
|
|
|
8
8
|
// ]
|
|
9
9
|
// }
|
|
10
10
|
//
|
|
11
|
-
// Lets `package.json#gjsify` describe the full plugin chain without dropping
|
|
12
|
-
//
|
|
13
|
-
//
|
|
14
|
-
// `node_modules` wins over the CLI's own dependencies.
|
|
11
|
+
// Lets `package.json#gjsify` describe the full plugin chain without dropping to a JS-form config
|
|
12
|
+
// file (`gjsify.config.mjs`). Resolution is anchored at the project root, so the project's own
|
|
13
|
+
// `node_modules` wins over the CLI's dependencies.
|
|
15
14
|
import { createRequire } from 'node:module';
|
|
16
15
|
import { join } from 'node:path';
|
|
17
16
|
import { pathToFileURL } from 'node:url';
|
|
@@ -22,9 +21,8 @@ export function isPluginByName(value) {
|
|
|
22
21
|
return (typeof value === 'object' &&
|
|
23
22
|
value !== null &&
|
|
24
23
|
typeof value.name === 'string' &&
|
|
25
|
-
//
|
|
26
|
-
//
|
|
27
|
-
// with our shape, so we additionally require absence of plugin-shape fields.
|
|
24
|
+
// `name` alone does not discriminate — a real Rolldown plugin has it too — so the
|
|
25
|
+
// absence of every plugin-shape hook is what separates the two.
|
|
28
26
|
!('apply' in value) &&
|
|
29
27
|
!('resolveId' in value) &&
|
|
30
28
|
!('load' in value) &&
|
|
@@ -33,13 +31,10 @@ export function isPluginByName(value) {
|
|
|
33
31
|
!('generateBundle' in value));
|
|
34
32
|
}
|
|
35
33
|
/**
|
|
36
|
-
* Resolve a list of mixed user plugins
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
* the
|
|
40
|
-
*
|
|
41
|
-
* Throws when a name fails to resolve, when the chosen export is not a
|
|
42
|
-
* function, or when the factory returns nothing.
|
|
34
|
+
* Resolve a list of mixed user plugins, anchored at `projectDir`. Plugin objects pass through
|
|
35
|
+
* unchanged; `PluginByName` entries are imported, instantiated with their `options`, and returned
|
|
36
|
+
* in the same position. Throws when a name fails to resolve, the chosen export is not a function,
|
|
37
|
+
* or the factory returns nothing.
|
|
43
38
|
*/
|
|
44
39
|
export async function resolveUserPlugins(plugins, projectDir, options = {}) {
|
|
45
40
|
const loadModule = options.loadModule ?? defaultLoadModule;
|
package/lib/utils/run-gjs.d.ts
CHANGED
|
@@ -1,32 +1,34 @@
|
|
|
1
1
|
import { type NativeEnv } from './detect-native-packages.js';
|
|
2
2
|
/**
|
|
3
|
-
* Pure env computation
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* (`LD_LIBRARY_PATH` / `DYLD_LIBRARY_PATH` / `PATH`) — see `buildNativeEnv`.
|
|
3
|
+
* Pure env computation: the typelib + shared-library search paths {@link runGjsBundle} would
|
|
4
|
+
* inject into the spawned `gjs`, plus the formatted prefix for the `$ …` echo. Which library
|
|
5
|
+
* variable is set is host-dependent (`LD_LIBRARY_PATH` / `DYLD_LIBRARY_PATH` / `PATH`) — see
|
|
6
|
+
* `buildNativeEnv`.
|
|
8
7
|
*/
|
|
9
8
|
export declare function computeNativeEnvForBundle(bundlePath: string, cwd?: string, inherited?: Record<string, string | undefined>): {
|
|
10
9
|
env: NativeEnv;
|
|
11
10
|
envPrefix: string;
|
|
12
11
|
};
|
|
13
12
|
/**
|
|
14
|
-
*
|
|
15
|
-
* for any
|
|
16
|
-
*
|
|
13
|
+
* Options for {@link runGjsBundle}, which runs a GJS bundle with `GI_TYPELIB_PATH` and the
|
|
14
|
+
* host's library variable set for any native gjsify packages discoverable from the CWD or the
|
|
15
|
+
* bundle's own node_modules tree.
|
|
17
16
|
*/
|
|
18
17
|
export interface RunGjsBundleOptions {
|
|
19
18
|
/**
|
|
20
|
-
* Exit this process with code 0 once the child succeeds. Under GJS,
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
* continue after the bundle (e.g. `gjsify test`'s multi-runtime
|
|
27
|
-
* aggregation loop) MUST leave this false — an unconditional exit here
|
|
28
|
-
* truncated `gjsify test` after the first gjs bundle.
|
|
19
|
+
* Exit this process with code 0 once the child succeeds. Under GJS, `ensureMainLoop()`
|
|
20
|
+
* (armed by spawn) keeps the parent's GLib loop alive after the child exits, so a TERMINAL
|
|
21
|
+
* caller (`gjsify run <file>`, `dlx`) must opt in or it parks forever — this gap hung CI's
|
|
22
|
+
* WebGL conformance job for 83 min on a suite that finished in 1.35 s. Callers that
|
|
23
|
+
* continue after the bundle (`gjsify test`'s multi-runtime loop) MUST leave this false; an
|
|
24
|
+
* unconditional exit truncated `gjsify test` after the first gjs bundle.
|
|
29
25
|
*/
|
|
30
26
|
exitOnSuccess?: boolean;
|
|
27
|
+
/**
|
|
28
|
+
* Suppress the `$ <env> gjs -m …` echo. Worth its ~2 kB of env prefix for a one-shot
|
|
29
|
+
* `gjsify run <bundle>`; pure noise for a build script invoked a dozen times per chain
|
|
30
|
+
* (`utils/node-script.ts`).
|
|
31
|
+
*/
|
|
32
|
+
quiet?: boolean;
|
|
31
33
|
}
|
|
32
34
|
export declare function runGjsBundle(bundlePath: string, extraArgs?: string[], options?: RunGjsBundleOptions): Promise<void>;
|
package/lib/utils/run-gjs.js
CHANGED
|
@@ -1,30 +1,22 @@
|
|
|
1
1
|
// Shared utility for running a GJS bundle with native package env vars.
|
|
2
2
|
// Used by `gjsify run`, `gjsify dlx`, and the showcase command (via dlx).
|
|
3
3
|
//
|
|
4
|
-
// Detection runs
|
|
5
|
-
//
|
|
4
|
+
// Detection runs `detectNativePackages` from two starting points and merges by package name
|
|
5
|
+
// (CWD shadows bundle): `process.cwd()` for native deps in the user's project, and
|
|
6
|
+
// `dirname(bundlePath)` for those in whatever node_modules the bundle lives in — critical for
|
|
7
|
+
// `gjsify dlx`, where the bundle sits under `~/.cache/gjsify/dlx/<sha>/…` and the user's CWD
|
|
8
|
+
// is unrelated. The bundle-side walk also catches transitive deps' typelibs.
|
|
6
9
|
//
|
|
7
|
-
//
|
|
8
|
-
//
|
|
9
|
-
// 2. dirname(bundlePath) — picks up native deps in whatever node_modules
|
|
10
|
-
// the bundle lives in. Critical for `gjsify dlx`
|
|
11
|
-
// where the bundle resides in
|
|
12
|
-
// `~/.cache/gjsify/dlx/<sha>/.../node_modules/<pkg>/dist/`
|
|
13
|
-
// and the user's CWD is unrelated. The bundle-side
|
|
14
|
-
// walk also catches transitive deps' typelibs.
|
|
15
|
-
//
|
|
16
|
-
// Env composition is split out as `computeNativeEnvForBundle()` — a pure
|
|
17
|
-
// function that takes a bundle path + cwd and returns the env it would inject.
|
|
18
|
-
// This lets the e2e tests assert the env without spawning gjs.
|
|
10
|
+
// Env composition is split out as the pure `computeNativeEnvForBundle()` so the e2e tests can
|
|
11
|
+
// assert the env without spawning gjs.
|
|
19
12
|
import { spawn } from 'node:child_process';
|
|
20
13
|
import { dirname, resolve } from 'node:path';
|
|
21
14
|
import { detectNativePackages, buildNativeEnv } from './detect-native-packages.js';
|
|
22
15
|
/**
|
|
23
|
-
* Pure env computation
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
* (`LD_LIBRARY_PATH` / `DYLD_LIBRARY_PATH` / `PATH`) — see `buildNativeEnv`.
|
|
16
|
+
* Pure env computation: the typelib + shared-library search paths {@link runGjsBundle} would
|
|
17
|
+
* inject into the spawned `gjs`, plus the formatted prefix for the `$ …` echo. Which library
|
|
18
|
+
* variable is set is host-dependent (`LD_LIBRARY_PATH` / `DYLD_LIBRARY_PATH` / `PATH`) — see
|
|
19
|
+
* `buildNativeEnv`.
|
|
28
20
|
*/
|
|
29
21
|
export function computeNativeEnvForBundle(bundlePath, cwd = process.cwd(), inherited = process.env) {
|
|
30
22
|
const resolvedBundle = resolve(bundlePath);
|
|
@@ -32,23 +24,16 @@ export function computeNativeEnvForBundle(bundlePath, cwd = process.cwd(), inher
|
|
|
32
24
|
const bundlePackages = detectNativePackages(dirname(resolvedBundle));
|
|
33
25
|
const seen = new Set(cwdPackages.map((p) => p.name));
|
|
34
26
|
const nativePackages = [...cwdPackages, ...bundlePackages.filter((p) => !seen.has(p.name))];
|
|
35
|
-
// `inherited` feeds BOTH halves —
|
|
36
|
-
//
|
|
37
|
-
// the
|
|
38
|
-
//
|
|
39
|
-
// look up a key that is not there and call every run a change.
|
|
27
|
+
// `inherited` feeds BOTH halves — composition and comparison. Split them and the win32
|
|
28
|
+
// branch disagrees with itself: `buildNativeEnv` writes the library variable back under
|
|
29
|
+
// the host's own spelling (`Path` in a stock env block), so a comparison keyed on the
|
|
30
|
+
// canonical `PATH` would look up a key that is not there and call every run a change.
|
|
40
31
|
const env = buildNativeEnv(nativePackages, { env: inherited });
|
|
41
|
-
// Show only what this CLI actually CHANGED
|
|
42
|
-
//
|
|
43
|
-
//
|
|
44
|
-
// variable
|
|
45
|
-
//
|
|
46
|
-
// Harmless on Linux, where `LD_LIBRARY_PATH` is usually unset and the empty
|
|
47
|
-
// filter caught it. On Windows the library variable IS `PATH`, which is
|
|
48
|
-
// never empty, so every run printed a ~2 kB dump of the host PATH in front
|
|
49
|
-
// of a command the user is invited to copy — burying the command, and
|
|
50
|
-
// claiming a change that never happened. Comparing against the inherited
|
|
51
|
-
// value is what makes the echo honest on both.
|
|
32
|
+
// Show only what this CLI actually CHANGED: `buildNativeEnv` prepends to the inherited
|
|
33
|
+
// value unconditionally, so with no native packages it hands back the host's own variable
|
|
34
|
+
// verbatim. Harmless on Linux, where `LD_LIBRARY_PATH` is usually unset; on Windows the
|
|
35
|
+
// library variable IS `PATH`, never empty, so every run printed a ~2 kB dump of the host
|
|
36
|
+
// PATH in front of a command the user is invited to copy.
|
|
52
37
|
const envPrefix = Object.entries(env)
|
|
53
38
|
.filter(([key, value]) => value !== undefined && value !== '' && value !== inherited[key])
|
|
54
39
|
.map(([key, value]) => `${key}=${value}`)
|
|
@@ -62,18 +47,21 @@ export async function runGjsBundle(bundlePath, extraArgs = [], options = {}) {
|
|
|
62
47
|
...nativeEnv,
|
|
63
48
|
};
|
|
64
49
|
const gjsArgs = ['-m', bundlePath, ...extraArgs];
|
|
65
|
-
//
|
|
66
|
-
//
|
|
67
|
-
// actually set any (i.e. native gjsify packages were detected).
|
|
68
|
-
// Use stderr so that children speaking a protocol on stdout (e.g. an
|
|
69
|
-
// MCP stdio server) receive an uncontaminated stdout stream.
|
|
50
|
+
// Echo the exact command so users can copy-paste it and run gjs without the wrapper.
|
|
51
|
+
// stderr, so children speaking a protocol on stdout (an MCP stdio server) keep a clean one.
|
|
70
52
|
const gjsCommand = ['gjs', ...gjsArgs.map((a) => (a.includes(' ') ? `"${a}"` : a))].join(' ');
|
|
71
|
-
|
|
53
|
+
if (!options.quiet)
|
|
54
|
+
console.error(`$ ${envPrefix ? `${envPrefix} ` : ''}${gjsCommand}`);
|
|
72
55
|
const child = spawn('gjs', gjsArgs, { env, stdio: 'inherit' });
|
|
73
56
|
let failed = false;
|
|
57
|
+
// The CHILD's own exit code, re-raised verbatim; a spawn error (no `gjs` on PATH) has none
|
|
58
|
+
// of its own and falls back to 1. Collapsing every failure to 1 lost information callers
|
|
59
|
+
// act on — a chain reading `$?` to tell "tool failed" from "tool says no" saw 1 for both.
|
|
60
|
+
let childCode = 1;
|
|
74
61
|
await new Promise((resolvePromise, reject) => {
|
|
75
62
|
child.on('close', (code) => {
|
|
76
63
|
if (code !== 0) {
|
|
64
|
+
childCode = code ?? 1;
|
|
77
65
|
reject(new Error(`gjs exited with code ${code}`));
|
|
78
66
|
}
|
|
79
67
|
else {
|
|
@@ -86,16 +74,14 @@ export async function runGjsBundle(bundlePath, extraArgs = [], options = {}) {
|
|
|
86
74
|
failed = true;
|
|
87
75
|
});
|
|
88
76
|
if (failed) {
|
|
89
|
-
// Set `process.exitCode` synchronously BEFORE exiting: under GJS
|
|
90
|
-
//
|
|
91
|
-
//
|
|
92
|
-
//
|
|
93
|
-
//
|
|
94
|
-
//
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
process.exitCode = 1;
|
|
98
|
-
return process.exit(1);
|
|
77
|
+
// Set `process.exitCode` synchronously BEFORE exiting: under GJS `process.exit()` is
|
|
78
|
+
// deferred (the GLib main loop is armed), so under run.ts's in-process script dispatch
|
|
79
|
+
// execution returns to the caller, which propagates by reading `process.exitCode`.
|
|
80
|
+
// Without it, `gjsify run <script>` wrapping `gjsify run <bundle>` swallowed a non-zero
|
|
81
|
+
// gjs exit and returned 0 — masking a failing `test:gjs` in the `test` chain, and via
|
|
82
|
+
// `gjsify foreach test` in CI. The `return` guards a fall-through second `exit`.
|
|
83
|
+
process.exitCode = childCode;
|
|
84
|
+
return process.exit(childCode);
|
|
99
85
|
}
|
|
100
86
|
// See RunGjsBundleOptions.exitOnSuccess — terminal callers opt in,
|
|
101
87
|
// mid-flow callers (test.ts's runtime loop) keep the process alive.
|
|
@@ -2,20 +2,16 @@ export interface RunLifecycleScriptOptions {
|
|
|
2
2
|
/** When true, do not throw on missing scripts — return `false` instead. */
|
|
3
3
|
optional?: boolean;
|
|
4
4
|
/**
|
|
5
|
-
* Stdio
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* `gjsify pack --json` and `gjsify publish` so the parent's stdout stays
|
|
9
|
-
* a clean JSON stream (script log lines would otherwise corrupt the
|
|
10
|
-
* machine-readable output that callers `JSON.parse`).
|
|
5
|
+
* Stdio for the spawned script; default `'inherit'`. `'inherit-stderr'` redirects the
|
|
6
|
+
* child's stdout → parent's stderr, used by `gjsify pack --json` and `gjsify publish` so
|
|
7
|
+
* script log lines cannot corrupt the JSON stream callers `JSON.parse`.
|
|
11
8
|
*/
|
|
12
9
|
stdio?: 'inherit' | 'inherit-stderr' | 'pipe' | 'ignore';
|
|
13
10
|
/** Extra environment variables layered on top of the defaults. */
|
|
14
11
|
env?: Record<string, string>;
|
|
15
12
|
}
|
|
16
13
|
/**
|
|
17
|
-
* Run
|
|
18
|
-
*
|
|
19
|
-
* `optional: true` and the script is missing. Throws on non-zero exit.
|
|
14
|
+
* Run the lifecycle script `pkg.scripts[name]` from `wsDir`. `true` when it existed and exited
|
|
15
|
+
* 0, `false` when it is missing and `optional` is set; throws on a non-zero exit.
|
|
20
16
|
*/
|
|
21
17
|
export declare function runLifecycleScript(wsDir: string, pkg: Record<string, unknown>, name: string, opts?: RunLifecycleScriptOptions): Promise<boolean>;
|
|
@@ -2,47 +2,31 @@
|
|
|
2
2
|
// `postpack`, `postpublish`, …) from inside a `gjsify pack` / `gjsify
|
|
3
3
|
// publish` flow.
|
|
4
4
|
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
// case where pack/publish needs the lifecycle script to finish, then keep
|
|
9
|
-
// running its own logic. This helper resolves to a Promise that settles
|
|
10
|
-
// when the child exits.
|
|
5
|
+
// Separate from `gjsify run` because that ends with `process.exit(<code>)` so it can act as a
|
|
6
|
+
// CLI entrypoint like `yarn run`. Pack/publish instead needs the lifecycle script to finish and
|
|
7
|
+
// then keep running its own logic, so this settles a Promise when the child exits.
|
|
11
8
|
//
|
|
12
|
-
//
|
|
13
|
-
//
|
|
14
|
-
//
|
|
15
|
-
//
|
|
16
|
-
//
|
|
17
|
-
//
|
|
18
|
-
//
|
|
19
|
-
//
|
|
20
|
-
//
|
|
21
|
-
// that spawns asynchronously and deliberately does NOT exit leaves the loop
|
|
22
|
-
// armed forever: `gjsify pack` on a package with a `prepack` wrote its tarball,
|
|
23
|
-
// printed its complete JSON, and then parked at 0% CPU until killed at 5m30s.
|
|
24
|
-
// A package with no lifecycle script exited in under a second, and the same
|
|
25
|
-
// pack under Node exited in 0.68s.
|
|
26
|
-
//
|
|
27
|
-
// `utils/spawn.ts` already owns that contract and makes every call site DECLARE
|
|
28
|
-
// which side of it they are on. This helper was the one spawn in the CLI that
|
|
29
|
-
// bypassed it — the seventh of the "six near-identical wrappers" that file was
|
|
30
|
-
// written to consolidate. It now goes through it with `completion: 'return'`,
|
|
31
|
-
// which is what "settle, then keep running our own logic" means.
|
|
9
|
+
// NOT calling `process.exit()` is what ARMS a hang, not what avoids it (#1010):
|
|
10
|
+
// `@gjsify/child_process`'s async `spawn()` calls `ensureMainLoop()` unconditionally — the
|
|
11
|
+
// caller has no say — and that main-loop hook's blocking `g_main_loop_run()` is torn down only
|
|
12
|
+
// by `process.exit()`. A helper that spawns asynchronously and deliberately does not exit
|
|
13
|
+
// therefore leaves the loop armed forever: `gjsify pack` on a package with a `prepack` wrote
|
|
14
|
+
// its tarball, printed its complete JSON, then parked at 0% CPU until killed at 5m30s (no
|
|
15
|
+
// lifecycle script: under a second; the same pack under Node: 0.68s). `utils/spawn.ts` owns
|
|
16
|
+
// that contract and makes every call site DECLARE which side of it it is on; this goes through
|
|
17
|
+
// it with `completion: 'return'`.
|
|
32
18
|
//
|
|
33
19
|
// Matches yarn / npm script semantics:
|
|
34
20
|
// - `shell: true` so `&&` / `|` / env-var refs work
|
|
35
21
|
// - PATH prepended with `<wsDir>/node_modules/.bin` + monorepo-root bin
|
|
36
|
-
// - `npm_lifecycle_event` / `npm_package_name` / `npm_package_version`
|
|
37
|
-
// env vars set
|
|
22
|
+
// - `npm_lifecycle_event` / `npm_package_name` / `npm_package_version` set
|
|
38
23
|
// - FORCE_COLOR=1 default unless caller overrides
|
|
39
24
|
import { delimiter, join } from 'node:path';
|
|
40
25
|
import { describeExit, spawnToCompletion } from './spawn.js';
|
|
41
26
|
import { findWorkspaceRoot } from './workspace-root.js';
|
|
42
27
|
/**
|
|
43
|
-
* Run
|
|
44
|
-
*
|
|
45
|
-
* `optional: true` and the script is missing. Throws on non-zero exit.
|
|
28
|
+
* Run the lifecycle script `pkg.scripts[name]` from `wsDir`. `true` when it existed and exited
|
|
29
|
+
* 0, `false` when it is missing and `optional` is set; throws on a non-zero exit.
|
|
46
30
|
*/
|
|
47
31
|
export async function runLifecycleScript(wsDir, pkg, name, opts = {}) {
|
|
48
32
|
const scripts = pkg.scripts ?? {};
|
|
@@ -57,11 +41,9 @@ export async function runLifecycleScript(wsDir, pkg, name, opts = {}) {
|
|
|
57
41
|
if (monorepoRoot && monorepoRoot !== wsDir) {
|
|
58
42
|
binDirs.push(join(monorepoRoot, 'node_modules', '.bin'));
|
|
59
43
|
}
|
|
60
|
-
// Match yarn / npm color-forcing
|
|
61
|
-
//
|
|
62
|
-
//
|
|
63
|
-
// (CI logs, redirected output) because `process.stdout.isTTY` is
|
|
64
|
-
// false for the spawned child.
|
|
44
|
+
// Match yarn / npm color-forcing — see `runScript()` in run.ts. Without it, scripts calling
|
|
45
|
+
// biome / esbuild / tsc lose ANSI color in piped contexts (CI logs, redirected output)
|
|
46
|
+
// because `process.stdout.isTTY` is false for the spawned child.
|
|
65
47
|
const colorEnv = process.env.FORCE_COLOR !== undefined || process.env.NO_COLOR !== undefined ? {} : { FORCE_COLOR: '1' };
|
|
66
48
|
const env = {
|
|
67
49
|
...process.env,
|
|
@@ -72,16 +54,15 @@ export async function runLifecycleScript(wsDir, pkg, name, opts = {}) {
|
|
|
72
54
|
npm_package_version: pkg.version ?? '',
|
|
73
55
|
...opts.env,
|
|
74
56
|
};
|
|
75
|
-
// `'ignore'` has no `spawnToCompletion` equivalent and no call site
|
|
76
|
-
//
|
|
77
|
-
//
|
|
57
|
+
// `'ignore'` has no `spawnToCompletion` equivalent and no call site; folding it onto
|
|
58
|
+
// `'inherit'` would start printing where a caller asked for silence, so it is rejected
|
|
59
|
+
// rather than approximated.
|
|
78
60
|
if (opts.stdio === 'ignore') {
|
|
79
61
|
throw new Error('gjsify lifecycle-script: stdio "ignore" is not supported — see utils/spawn.ts');
|
|
80
62
|
}
|
|
81
63
|
const result = await spawnToCompletion(literal, [], {
|
|
82
|
-
//
|
|
83
|
-
//
|
|
84
|
-
// keeps the armed main loop from outliving us — see the header.
|
|
64
|
+
// pack/publish waits for the script, then keeps running. Under GJS that is the blocking
|
|
65
|
+
// path, which is what keeps the armed main loop from outliving us — see the header.
|
|
85
66
|
completion: 'return',
|
|
86
67
|
cwd: wsDir,
|
|
87
68
|
env: env,
|
package/lib/utils/run-node.d.ts
CHANGED
|
@@ -1,25 +1,19 @@
|
|
|
1
1
|
import { type ExampleRuntime } from './runtimes.js';
|
|
2
2
|
/**
|
|
3
|
-
* Walk up from `startDir`
|
|
4
|
-
*
|
|
5
|
-
* A plain fs walk (works identically on Node and GJS) — Node's own resolver is
|
|
6
|
-
* not available under the GJS-bundled CLI.
|
|
3
|
+
* Walk up from `startDir` for `<node_modules>/@gjsify/node-gi`, returning its package directory
|
|
4
|
+
* or null. A plain fs walk because Node's own resolver is not available under the GJS-bundled CLI.
|
|
7
5
|
*/
|
|
8
6
|
export declare function resolveNodeGi(startDir: string): string | null;
|
|
9
7
|
/**
|
|
10
|
-
* Resolve `@gjsify/node-gi` for a bundle
|
|
11
|
-
*
|
|
8
|
+
* Resolve `@gjsify/node-gi` for a bundle about to launch: the BUNDLE's own directory first, then
|
|
9
|
+
* `cwd`.
|
|
12
10
|
*
|
|
13
|
-
* The bundle's directory is the correct base
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
* sitting right beside the bundle and nothing at all under the user's cwd, so a
|
|
20
|
-
* cwd-only probe rejected a run that would have worked. The cwd probe is kept
|
|
21
|
-
* because a project-local `node_modules` legitimately satisfies a bundle built
|
|
22
|
-
* into a `dist/` outside it (a `--outfile /tmp/…` build from a project root).
|
|
11
|
+
* The bundle's directory is the correct base for the same reason {@link computeNativeEnvForBundle}
|
|
12
|
+
* walks both: node-gi is kept EXTERNAL, so what must be satisfiable is the RUNTIME's resolution
|
|
13
|
+
* of a bare specifier from inside the bundle, which Node performs relative to the importing file,
|
|
14
|
+
* never to cwd. A dlx-cache layout has node-gi beside the bundle and nothing under the user's
|
|
15
|
+
* cwd, so a cwd-only probe rejected a run that would have worked. The cwd probe stays because a
|
|
16
|
+
* project-local `node_modules` legitimately satisfies a bundle built into a `dist/` outside it.
|
|
23
17
|
*/
|
|
24
18
|
export declare function resolveNodeGiForBundle(bundlePath: string, cwd: string): string | null;
|
|
25
19
|
/** Pick the node executable: the current one when on Node, else PATH `node`. */
|
|
@@ -27,31 +21,27 @@ export declare function nodeBinary(): string;
|
|
|
27
21
|
export interface RunNodeBundleOptions {
|
|
28
22
|
/** Exit this process with code 0 once the child succeeds (terminal callers). */
|
|
29
23
|
exitOnSuccess?: boolean;
|
|
24
|
+
/** Suppress the `$ <env> node …` echo — see `RunGjsBundleOptions.quiet`. */
|
|
25
|
+
quiet?: boolean;
|
|
30
26
|
}
|
|
31
27
|
/**
|
|
32
|
-
* Run a `--app node` bundle on Node.js
|
|
33
|
-
*
|
|
34
|
-
* {@link runGjsBundle}). Verifies `@gjsify/node-gi` is resolvable first and
|
|
35
|
-
* throws a clear, actionable error otherwise.
|
|
28
|
+
* Run a `--app node` bundle on Node.js with the native typelib env set (same detection as
|
|
29
|
+
* {@link runGjsBundle}). Throws when `@gjsify/node-gi` is not resolvable.
|
|
36
30
|
*/
|
|
37
31
|
export declare function runNodeBundle(bundlePath: string, extraArgs?: string[], options?: RunNodeBundleOptions): Promise<void>;
|
|
38
32
|
/**
|
|
39
|
-
* Whether a `--app node` bundle actually consumes `@gjsify/node-gi`
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
* conditional on this, not unconditional like the storybook path.
|
|
33
|
+
* Whether a `--app node` bundle actually consumes `@gjsify/node-gi` — kept EXTERNAL, so a bundle
|
|
34
|
+
* using gi:// imports the shim by name. A plain Node app does NOT, and must run on node/bun/deno
|
|
35
|
+
* WITHOUT node-gi installed, which is why the check is conditional here and not unconditional
|
|
36
|
+
* like the storybook path.
|
|
44
37
|
*/
|
|
45
38
|
export declare function bundleRequiresNodeGi(bundlePath: string): boolean;
|
|
46
39
|
/**
|
|
47
|
-
* Run a built bundle on a non-gjs runtime (node / bun / deno). All three consume
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
* node
|
|
51
|
-
* (so a bundle pulling an `@gjsify/*` Vala bridge resolves its prebuild), and
|
|
52
|
-
* `@gjsify/node-gi` is required ONLY when the bundle actually uses gi://.
|
|
40
|
+
* Run a built bundle on a non-gjs runtime (node / bun / deno). All three consume the SAME
|
|
41
|
+
* `--app node` bundle — Node-API is their common ABI — so this is the shared launcher for
|
|
42
|
+
* `gjsify run --runtime` and `gjsify showcase --runtime`. Native typelib env is wired as in
|
|
43
|
+
* {@link runGjsBundle}; `@gjsify/node-gi` is required ONLY when the bundle actually uses gi://.
|
|
53
44
|
*
|
|
54
|
-
* `gjs` is intentionally NOT handled here — the caller dispatches it to
|
|
55
|
-
* {@link runGjsBundle}.
|
|
45
|
+
* `gjs` is intentionally NOT handled here — the caller dispatches it to {@link runGjsBundle}.
|
|
56
46
|
*/
|
|
57
47
|
export declare function runRuntimeBundle(runtime: Exclude<ExampleRuntime, 'gjs'>, bundlePath: string, extraArgs?: string[], options?: RunNodeBundleOptions): Promise<void>;
|