@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
|
@@ -1,15 +1,13 @@
|
|
|
1
1
|
import { type NpmrcConfig } from '@gjsify/npm-registry';
|
|
2
2
|
/**
|
|
3
3
|
* Percent-encode a package name for the publish PUT path, matching
|
|
4
|
-
* npm-package-arg's `escapedName` convention
|
|
5
|
-
* `this.escapedName = name.replace('/', '%2f')`.
|
|
4
|
+
* npm-package-arg's `escapedName` convention.
|
|
6
5
|
*
|
|
7
6
|
* Scoped: `@scope/name` → `@scope%2fname` (literal `@`, lowercase `%2f`, the
|
|
8
7
|
* scope/name segments NOT otherwise re-encoded — npm only replaces the slash).
|
|
9
|
-
* Unscoped: returned unchanged
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* URL — `%2F` (uppercase) or a re-encoded `@` would miss the create route.
|
|
8
|
+
* Unscoped: returned unchanged. The registry is picky about this exact shape on
|
|
9
|
+
* the publish PUT URL — uppercase `%2F` or a re-encoded `@` misses the create
|
|
10
|
+
* route.
|
|
13
11
|
*/
|
|
14
12
|
export declare function escapePackageName(name: string): string;
|
|
15
13
|
export interface PublishHeaderOptions {
|
|
@@ -19,8 +17,7 @@ export interface PublishHeaderOptions {
|
|
|
19
17
|
otp?: string;
|
|
20
18
|
/**
|
|
21
19
|
* Override the `authorization` header (e.g. an OIDC Bearer token resolved
|
|
22
|
-
* after `buildHeaders` ran)
|
|
23
|
-
* resolution produced.
|
|
20
|
+
* after `buildHeaders` ran), replacing whatever npmrc auth resolution produced.
|
|
24
21
|
*/
|
|
25
22
|
authorization?: string;
|
|
26
23
|
/**
|
|
@@ -37,8 +34,7 @@ export interface PublishHeaderOptions {
|
|
|
37
34
|
* `npm-command: publish`, `npm-auth-type` (`web`, or `legacy` when `--otp`),
|
|
38
35
|
* `user-agent`, and `npm-otp` when an OTP is supplied.
|
|
39
36
|
*
|
|
40
|
-
* Notably
|
|
41
|
-
*
|
|
42
|
-
* is dropped to match.
|
|
37
|
+
* Notably NO `accept` header: `npm-registry-fetch` sends none on the publish PUT,
|
|
38
|
+
* and a wildcard here misses the create route.
|
|
43
39
|
*/
|
|
44
40
|
export declare function buildPublishHeaders(url: string, opts: PublishHeaderOptions): Record<string, string>;
|
|
@@ -3,48 +3,30 @@
|
|
|
3
3
|
// package correctly.
|
|
4
4
|
//
|
|
5
5
|
// Root cause this fixes: a first-publish of a never-before-published
|
|
6
|
-
// `@scope/<name>` via token auth
|
|
7
|
-
// `Not Found`, NOT a JSON npm error). That is a
|
|
8
|
-
// payload-validation failure — npm's write frontdoor keys the create path on
|
|
9
|
-
//
|
|
10
|
-
//
|
|
6
|
+
// `@scope/<name>` via token auth returned a bare `404 Not Found` (body
|
|
7
|
+
// `Not Found`, NOT a JSON npm error). That is a ROUTING miss, not a
|
|
8
|
+
// payload-validation failure — npm's write frontdoor keys the create path on the
|
|
9
|
+
// `npm-command` header, which gjsify was not sending. `npm publish` with the same
|
|
10
|
+
// ~/.npmrc token succeeds because libnpmpublish goes through
|
|
11
11
|
// `npm-registry-fetch`'s `getHeaders`, which always sets `npm-command`
|
|
12
|
-
// (+ `npm-auth-type`, + a real `user-agent`).
|
|
13
|
-
//
|
|
14
|
-
// Evidence (refs/npm-cli):
|
|
15
|
-
// - `lib/npm.js:404` `flat.npmCommand = this.command` → set for EVERY npm
|
|
16
|
-
// command; equals `"publish"` for `npm publish`.
|
|
17
|
-
// - `node_modules/npm-registry-fetch/lib/index.js:231-233`
|
|
18
|
-
// `if (opts.npmCommand) headers['npm-command'] = opts.npmCommand`
|
|
19
|
-
// and `:219-221` `if (opts.authType) headers['npm-auth-type'] = …`
|
|
20
|
-
// and `:215-217` `'user-agent': opts.userAgent`.
|
|
21
|
-
// - `workspaces/config/lib/definitions/definitions.js:282-290` — `auth-type`
|
|
22
|
-
// default `'web'`, flattened to `flatOptions.authType`.
|
|
23
|
-
// - `:1581-1587` — when `--otp` is set, npm forces `auth-type` to `'legacy'`
|
|
24
|
-
// before flattening, so an OTP publish sends `npm-auth-type: legacy`.
|
|
25
|
-
// - `node_modules/npm-package-arg/lib/npa.js:188`
|
|
26
|
-
// `this.escapedName = name.replace('/', '%2f')` — lowercase `%2f`,
|
|
27
|
-
// literal `@`. (gjsify's URL encoding already matches this — it was never
|
|
28
|
-
// the bug.)
|
|
12
|
+
// (+ `npm-auth-type`, + a real `user-agent`). Reference: `refs/npm-cli`.
|
|
29
13
|
//
|
|
30
14
|
// This module pulls in no `gi://` and no runtime fetch/Soup stack, so it is
|
|
31
|
-
// unit-testable on both Node and GJS. Its one filesystem touch is the
|
|
32
|
-
//
|
|
15
|
+
// unit-testable on both Node and GJS. Its one filesystem touch is the manifest
|
|
16
|
+
// walk backing the user-agent version — see `cliVersion()`.
|
|
33
17
|
import { readFileSync } from 'node:fs';
|
|
34
18
|
import { dirname } from 'node:path';
|
|
35
19
|
import { fileURLToPath } from 'node:url';
|
|
36
20
|
import { buildHeaders } from '@gjsify/npm-registry';
|
|
37
21
|
/**
|
|
38
22
|
* Percent-encode a package name for the publish PUT path, matching
|
|
39
|
-
* npm-package-arg's `escapedName` convention
|
|
40
|
-
* `this.escapedName = name.replace('/', '%2f')`.
|
|
23
|
+
* npm-package-arg's `escapedName` convention.
|
|
41
24
|
*
|
|
42
25
|
* Scoped: `@scope/name` → `@scope%2fname` (literal `@`, lowercase `%2f`, the
|
|
43
26
|
* scope/name segments NOT otherwise re-encoded — npm only replaces the slash).
|
|
44
|
-
* Unscoped: returned unchanged
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
* URL — `%2F` (uppercase) or a re-encoded `@` would miss the create route.
|
|
27
|
+
* Unscoped: returned unchanged. The registry is picky about this exact shape on
|
|
28
|
+
* the publish PUT URL — uppercase `%2F` or a re-encoded `@` misses the create
|
|
29
|
+
* route.
|
|
48
30
|
*/
|
|
49
31
|
export function escapePackageName(name) {
|
|
50
32
|
return name.replace('/', '%2f');
|
|
@@ -57,34 +39,26 @@ export function escapePackageName(name) {
|
|
|
57
39
|
* `npm-command: publish`, `npm-auth-type` (`web`, or `legacy` when `--otp`),
|
|
58
40
|
* `user-agent`, and `npm-otp` when an OTP is supplied.
|
|
59
41
|
*
|
|
60
|
-
* Notably
|
|
61
|
-
*
|
|
62
|
-
* is dropped to match.
|
|
42
|
+
* Notably NO `accept` header: `npm-registry-fetch` sends none on the publish PUT,
|
|
43
|
+
* and a wildcard here misses the create route.
|
|
63
44
|
*/
|
|
64
45
|
export function buildPublishHeaders(url, opts) {
|
|
65
46
|
const headers = buildHeaders(url, { npmrc: opts.npmrc });
|
|
66
|
-
//
|
|
67
|
-
//
|
|
68
|
-
//
|
|
69
|
-
//
|
|
70
|
-
// we keep it harmless and explicit by leaving it as buildHeaders set it.)
|
|
71
|
-
// content-type: application/json — npm-registry-fetch sets this for any
|
|
72
|
-
// non-string/non-stream/non-buffer body (index.js:63-67); our body is a
|
|
73
|
-
// JSON string, so we set it explicitly.
|
|
47
|
+
// `buildHeaders`' `accept-encoding: identity` default is left as it set it —
|
|
48
|
+
// the PUT body is JSON we generated, so the encoding header is irrelevant here.
|
|
49
|
+
// npm-registry-fetch sets this for any non-string/non-stream/non-buffer body;
|
|
50
|
+
// ours is a JSON string, so it is set explicitly.
|
|
74
51
|
headers['content-type'] = 'application/json';
|
|
75
|
-
//
|
|
76
|
-
//
|
|
77
|
-
//
|
|
52
|
+
// THE routing header: npm sets it for every command, and the registry's write
|
|
53
|
+
// frontdoor uses it to route the create-package PUT. Missing it = bare
|
|
54
|
+
// `404 Not Found` on a new package.
|
|
78
55
|
headers['npm-command'] = 'publish';
|
|
79
|
-
// npm
|
|
80
|
-
// (definitions.js:1583-1586). Sent by getHeaders (index.js:219-221).
|
|
56
|
+
// npm forces auth-type `legacy` whenever `--otp` is set, `web` otherwise.
|
|
81
57
|
headers['npm-auth-type'] = opts.otp ? 'legacy' : 'web';
|
|
82
|
-
// user-agent — a real npm-shaped UA (getHeaders index.js:215-217).
|
|
83
58
|
headers['user-agent'] = opts.userAgent ?? defaultUserAgent();
|
|
84
|
-
// npm-otp — only when an OTP is supplied (index.js:243-245).
|
|
85
59
|
if (opts.otp)
|
|
86
60
|
headers['npm-otp'] = opts.otp;
|
|
87
|
-
//
|
|
61
|
+
// OIDC token resolved after npmrc auth.
|
|
88
62
|
if (opts.authorization)
|
|
89
63
|
headers['authorization'] = opts.authorization;
|
|
90
64
|
return headers;
|
|
@@ -94,21 +68,18 @@ export function buildPublishHeaders(url, opts) {
|
|
|
94
68
|
* `@gjsify/cli` is a DUAL-ENTRY package and neither layer covers both entries:
|
|
95
69
|
*
|
|
96
70
|
* 1. **`__PACKAGE_VERSION__`** — the compile-time define
|
|
97
|
-
* (`package.json#gjsify.defineFromPackageJson`), the
|
|
98
|
-
*
|
|
99
|
-
*
|
|
100
|
-
*
|
|
101
|
-
* define alone would therefore have left the Node entry — the one `npm
|
|
102
|
-
* install @gjsify/cli` actually runs — on a permanent placeholder.
|
|
71
|
+
* (`package.json#gjsify.defineFromPackageJson`). Zero I/O, but the bundler only
|
|
72
|
+
* writes `dist/cli.gjs.mjs`; the npm-wired Node bin under `lib/` comes from
|
|
73
|
+
* plain `tsc`, which knows nothing about defines. A define alone would leave the
|
|
74
|
+
* Node entry — the one `npm install @gjsify/cli` runs — on a permanent placeholder.
|
|
103
75
|
*
|
|
104
76
|
* 2. **an upward manifest walk** for the nearest `package.json` naming
|
|
105
77
|
* `@gjsify/cli`, covering `lib/`. Deliberately NOT a fixed
|
|
106
|
-
* `new URL('../../package.json', import.meta.url)` read: that resolves
|
|
107
|
-
*
|
|
108
|
-
*
|
|
109
|
-
*
|
|
110
|
-
*
|
|
111
|
-
* `dist/`, and from an installed `node_modules/@gjsify/cli/**` alike.
|
|
78
|
+
* `new URL('../../package.json', import.meta.url)` read: that resolves correctly
|
|
79
|
+
* from `lib/utils/` but points one directory too high from `dist/`, and the
|
|
80
|
+
* build-time `inlineStaticReads` pass that would have frozen it is scoped to
|
|
81
|
+
* `node_modules` paths. The walk is depth-independent, so it works from `src/`,
|
|
82
|
+
* `lib/`, `dist/` and an installed `node_modules/@gjsify/cli/**` alike.
|
|
112
83
|
*
|
|
113
84
|
* `GJSIFY_CLI_PACKAGE_JSON` overrides both, matching `self-update.ts`.
|
|
114
85
|
*/
|
|
@@ -147,10 +118,10 @@ function walkForCliVersion() {
|
|
|
147
118
|
return '';
|
|
148
119
|
}
|
|
149
120
|
/**
|
|
150
|
-
* npm-CLI-shaped user-agent
|
|
151
|
-
* `
|
|
152
|
-
*
|
|
153
|
-
*
|
|
121
|
+
* npm-CLI-shaped user-agent, mirroring npm-registry-fetch's
|
|
122
|
+
* `npm@<v>/node@<v>+<arch> (<platform>)` with the gjsify CLI identity substituted.
|
|
123
|
+
* The registry does not validate the value; it must merely be a non-placeholder UA,
|
|
124
|
+
* which some WAF / CDN frontdoors require.
|
|
154
125
|
*/
|
|
155
126
|
function defaultUserAgent() {
|
|
156
127
|
const proc = globalThis.process;
|
|
@@ -1,18 +1,16 @@
|
|
|
1
1
|
import type { Workspace } from '@gjsify/workspace';
|
|
2
2
|
/**
|
|
3
3
|
* Package-group directories holding publishable packages that are NOT root
|
|
4
|
-
* workspaces.
|
|
5
|
-
*
|
|
6
|
-
* silently broken first release.
|
|
4
|
+
* workspaces. Extend this the moment a new such group appears — the list is the
|
|
5
|
+
* only thing standing between one and a silently broken first release.
|
|
7
6
|
*/
|
|
8
7
|
export declare const NON_WORKSPACE_PUBLISHABLE_DIRS: readonly [readonly ["packages", "node-gi"], readonly ["packages", "napi"]];
|
|
9
8
|
/**
|
|
10
9
|
* Publishable packages in {@link NON_WORKSPACE_PUBLISHABLE_DIRS}, shaped as
|
|
11
10
|
* `Workspace` entries so callers can treat them like any other package.
|
|
12
11
|
*
|
|
13
|
-
* Best-effort by design
|
|
14
|
-
*
|
|
15
|
-
* value is covering everything they can reach.
|
|
12
|
+
* Best-effort by design — a missing directory or malformed manifest is skipped,
|
|
13
|
+
* not thrown: this runs inside sweeps whose value is covering everything reachable.
|
|
16
14
|
*/
|
|
17
15
|
export declare function discoverNonWorkspacePublishables(cwd: string): Workspace[];
|
|
18
16
|
/**
|
|
@@ -1,23 +1,20 @@
|
|
|
1
1
|
// Publishable-package discovery shared by `gjsify trust` and `gjsify onboard`.
|
|
2
2
|
//
|
|
3
|
-
// `discoverWorkspaces` only sees ROOT WORKSPACES
|
|
3
|
+
// `discoverWorkspaces` only sees ROOT WORKSPACES, and some publishable packages
|
|
4
4
|
// deliberately are not: each is an independent native engine with its own CI
|
|
5
|
-
// workflow, kept out of the
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
//
|
|
9
|
-
//
|
|
10
|
-
//
|
|
11
|
-
//
|
|
12
|
-
// done" on 2026-07-26 while `@gjsify/napi` was neither in the list nor
|
|
13
|
-
// published at all, because only `packages/node-gi/*` was carved out.
|
|
5
|
+
// workflow, kept out of the graph so a full `gjsify foreach` never tries to build
|
|
6
|
+
// it. They still publish through `release.yml`, so a sweep that reasons about
|
|
7
|
+
// "what do we publish" must include them — otherwise it silently under-reports and
|
|
8
|
+
// the package's first release fails the OIDC exchange with `404 — package not
|
|
9
|
+
// found`. Measured: `gjsify onboard` called 127 packages "already done" while
|
|
10
|
+
// `@gjsify/napi` was neither listed nor published, because only
|
|
11
|
+
// `packages/node-gi/*` had been carved out.
|
|
14
12
|
import { existsSync, readdirSync, readFileSync } from 'node:fs';
|
|
15
13
|
import { dirname, join } from 'node:path';
|
|
16
14
|
/**
|
|
17
15
|
* Package-group directories holding publishable packages that are NOT root
|
|
18
|
-
* workspaces.
|
|
19
|
-
*
|
|
20
|
-
* silently broken first release.
|
|
16
|
+
* workspaces. Extend this the moment a new such group appears — the list is the
|
|
17
|
+
* only thing standing between one and a silently broken first release.
|
|
21
18
|
*/
|
|
22
19
|
export const NON_WORKSPACE_PUBLISHABLE_DIRS = [
|
|
23
20
|
['packages', 'node-gi'], // @gjsify/node-gi + the @gjsify/gtk-runtime-* bundles
|
|
@@ -27,13 +24,12 @@ export const NON_WORKSPACE_PUBLISHABLE_DIRS = [
|
|
|
27
24
|
* Publishable packages in {@link NON_WORKSPACE_PUBLISHABLE_DIRS}, shaped as
|
|
28
25
|
* `Workspace` entries so callers can treat them like any other package.
|
|
29
26
|
*
|
|
30
|
-
* Best-effort by design
|
|
31
|
-
*
|
|
32
|
-
* value is covering everything they can reach.
|
|
27
|
+
* Best-effort by design — a missing directory or malformed manifest is skipped,
|
|
28
|
+
* not thrown: this runs inside sweeps whose value is covering everything reachable.
|
|
33
29
|
*/
|
|
34
30
|
export function discoverNonWorkspacePublishables(cwd) {
|
|
35
|
-
// Walk up to the repo root
|
|
36
|
-
//
|
|
31
|
+
// Walk up to the repo root, anchored on the FIRST configured group rather than
|
|
32
|
+
// on `packages/` itself, which also exists inside individual packages.
|
|
37
33
|
let root = cwd;
|
|
38
34
|
const anchor = NON_WORKSPACE_PUBLISHABLE_DIRS[0];
|
|
39
35
|
for (let i = 0; i < 8; i++) {
|
|
@@ -5,14 +5,11 @@ interface ResolvedEntry {
|
|
|
5
5
|
}
|
|
6
6
|
export declare function resolveGjsEntry(pkgDir: string, binName: string | null): ResolvedEntry;
|
|
7
7
|
/**
|
|
8
|
-
* Resolve the `--app node` bundle
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* `build:node → dist/<name>.node.mjs` convention; the GJS entry is
|
|
14
|
-
* `dist/<name>.gjs.js`, so the extension can differ).
|
|
15
|
-
* Hard-fails with an actionable hint when neither is found.
|
|
8
|
+
* Resolve the `--app node` bundle, which node/bun/deno all consume. An explicit
|
|
9
|
+
* `gjsify.example.node` wins; otherwise the node twin of the GJS entry is derived by
|
|
10
|
+
* swapping the `.gjs.<ext>` infix for `.node.<ext>` and probing `mjs`/`js`/`cjs` —
|
|
11
|
+
* the extension can differ, since `build:node` emits `dist/<name>.node.mjs` while the
|
|
12
|
+
* GJS entry is `dist/<name>.gjs.js`.
|
|
16
13
|
*/
|
|
17
14
|
export declare function resolveNodeEntry(pkgDir: string): string;
|
|
18
15
|
export {};
|
|
@@ -1,20 +1,8 @@
|
|
|
1
|
-
// Resolve the GJS entry point of an installed package
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
// "gjsify": {
|
|
7
|
-
// "main": "dist/gjs.js",
|
|
8
|
-
// "bin": { "name-a": "dist/a.js", "name-b": "dist/b.js" }
|
|
9
|
-
// }
|
|
10
|
-
// }
|
|
11
|
-
//
|
|
12
|
-
// Resolution order:
|
|
13
|
-
// 1. user-supplied bin name + `gjsify.bin[name]` → that path
|
|
14
|
-
// 2. single-entry `gjsify.bin` → the only path
|
|
15
|
-
// 3. `gjsify.main` → that path
|
|
16
|
-
// 4. fallback: `package.json#main` → that path (advisory warning)
|
|
17
|
-
// 5. otherwise: hard-fail with a fix hint
|
|
1
|
+
// Resolve the GJS entry point of an installed package, per the `gjsify` field
|
|
2
|
+
// convention. In order: a requested `gjsify.bin[name]`, a single-entry
|
|
3
|
+
// `gjsify.bin`, `gjsify.main`, then `package.json#main` — the last flagged
|
|
4
|
+
// `fromFallback` so the caller can warn (`commands/dlx.ts` does). No entry at all,
|
|
5
|
+
// or several bins with none named, hard-fails with a fix hint.
|
|
18
6
|
import { readFileSync } from 'node:fs';
|
|
19
7
|
import { existsSync } from 'node:fs';
|
|
20
8
|
import { join, resolve } from 'node:path';
|
|
@@ -64,14 +52,11 @@ export function resolveGjsEntry(pkgDir, binName) {
|
|
|
64
52
|
return { bundlePath, binName: resolvedBin, fromFallback };
|
|
65
53
|
}
|
|
66
54
|
/**
|
|
67
|
-
* Resolve the `--app node` bundle
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
-
*
|
|
71
|
-
*
|
|
72
|
-
* `build:node → dist/<name>.node.mjs` convention; the GJS entry is
|
|
73
|
-
* `dist/<name>.gjs.js`, so the extension can differ).
|
|
74
|
-
* Hard-fails with an actionable hint when neither is found.
|
|
55
|
+
* Resolve the `--app node` bundle, which node/bun/deno all consume. An explicit
|
|
56
|
+
* `gjsify.example.node` wins; otherwise the node twin of the GJS entry is derived by
|
|
57
|
+
* swapping the `.gjs.<ext>` infix for `.node.<ext>` and probing `mjs`/`js`/`cjs` —
|
|
58
|
+
* the extension can differ, since `build:node` emits `dist/<name>.node.mjs` while the
|
|
59
|
+
* GJS entry is `dist/<name>.gjs.js`.
|
|
75
60
|
*/
|
|
76
61
|
export function resolveNodeEntry(pkgDir) {
|
|
77
62
|
const pkgJsonPath = join(pkgDir, 'package.json');
|
|
@@ -79,7 +64,6 @@ export function resolveNodeEntry(pkgDir) {
|
|
|
79
64
|
throw new Error(`no package.json found at ${pkgDir}`);
|
|
80
65
|
}
|
|
81
66
|
const pkg = JSON.parse(readFileSync(pkgJsonPath, 'utf-8'));
|
|
82
|
-
// 1. Explicit declaration wins.
|
|
83
67
|
const explicit = pkg.gjsify?.example?.node;
|
|
84
68
|
if (explicit) {
|
|
85
69
|
const p = resolve(pkgDir, explicit);
|
|
@@ -88,7 +72,6 @@ export function resolveNodeEntry(pkgDir) {
|
|
|
88
72
|
}
|
|
89
73
|
return p;
|
|
90
74
|
}
|
|
91
|
-
// 2. Derive from the GJS entry.
|
|
92
75
|
const gjsEntry = pkg.gjsify?.main ?? (pkg.gjsify?.bin ? Object.values(pkg.gjsify.bin)[0] : undefined) ?? pkg.main;
|
|
93
76
|
if (!gjsEntry) {
|
|
94
77
|
throw new Error(`package "${pkg.name ?? pkgDir}" has no entry to derive a node bundle from — ` +
|
|
@@ -2,20 +2,15 @@ export interface ResolveNpmPackageOptions {
|
|
|
2
2
|
/** Anchor directory to search from (typically the caller's cwd). */
|
|
3
3
|
cwd?: string;
|
|
4
4
|
/**
|
|
5
|
-
* Bundle path or module URL to anchor the bundle-side createRequire
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* invoked from an unrelated cwd.
|
|
5
|
+
* Bundle path or module URL to anchor the bundle-side createRequire at. Pass
|
|
6
|
+
* `import.meta.url` from the call site so the bundle's own node_modules chain stays
|
|
7
|
+
* reachable even when the CLI is invoked from an unrelated cwd.
|
|
9
8
|
*/
|
|
10
9
|
bundleUrl?: string;
|
|
11
10
|
}
|
|
12
11
|
/**
|
|
13
|
-
* Resolve a bare npm specifier through
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
* Each anchor is tried in priority order — `GJSIFY_NODE_PATH` (highest)
|
|
18
|
-
* → caller cwd → workspace root → bundle URL → parent-dir walk from
|
|
19
|
-
* cwd. The first anchor whose `require.resolve()` succeeds wins.
|
|
12
|
+
* Resolve a bare npm specifier through the anchors listed above, returning the resolved
|
|
13
|
+
* module's absolute path or null when every anchor failed. Callers usually wrap the result in
|
|
14
|
+
* `pathToFileURL().href` before a dynamic `import(...)`.
|
|
20
15
|
*/
|
|
21
16
|
export declare function resolveNpmPackage(specifier: string, opts?: ResolveNpmPackageOptions): string | null;
|
|
@@ -1,88 +1,59 @@
|
|
|
1
1
|
// Multi-anchor npm-package resolver for the GJS-bundled CLI.
|
|
2
2
|
//
|
|
3
|
-
// GJS's native ESM loader has no node_modules walker — a bare
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
// physically present in a node_modules above the caller's cwd.
|
|
3
|
+
// GJS's native ESM loader has no node_modules walker — a bare `await import('rolldown')`
|
|
4
|
+
// from inside the bundle throws `ImportError: Module not found: rolldown` even when the
|
|
5
|
+
// package is physically present in a node_modules above the caller's cwd.
|
|
7
6
|
//
|
|
8
|
-
// `createRequire(import.meta.url)` works
|
|
9
|
-
//
|
|
10
|
-
//
|
|
11
|
-
//
|
|
12
|
-
//
|
|
13
|
-
//
|
|
14
|
-
// unrelated cwd (`/tmp/sandbox/`) whose `node_modules` is the only
|
|
15
|
-
// place rolldown is present, anchoring on the bundle URL misses it.
|
|
7
|
+
// `createRequire(import.meta.url)` works under Node, and under GJS with `@gjsify/module`'s
|
|
8
|
+
// polyfill it walks the node_modules chain from the URL it was anchored at — but only ONE
|
|
9
|
+
// chain, the one rooted at the anchor's parent. When the bundle lives at
|
|
10
|
+
// `<install>/dist/cli.gjs.mjs` and the user runs it from an unrelated cwd whose
|
|
11
|
+
// `node_modules` is the only place rolldown is present, anchoring on the bundle URL misses
|
|
12
|
+
// it. So a bare specifier is tried against several anchors, first hit wins:
|
|
16
13
|
//
|
|
17
|
-
//
|
|
18
|
-
//
|
|
19
|
-
//
|
|
20
|
-
// 1. `GJSIFY_NODE_PATH` env override (colon-separated dir list,
|
|
21
|
-
// matches Node's NODE_PATH semantics — each entry is treated as a
|
|
22
|
-
// synthetic `node_modules` parent).
|
|
14
|
+
// 1. `GJSIFY_NODE_PATH` env override (NODE_PATH semantics — each entry is a synthetic
|
|
15
|
+
// `node_modules` parent).
|
|
23
16
|
// 2. Caller-supplied anchor dir (typically process.cwd()).
|
|
24
|
-
// 3. Workspace root from `findWorkspaceRoot(anchorDir)` —
|
|
25
|
-
//
|
|
17
|
+
// 3. Workspace root from `findWorkspaceRoot(anchorDir)` — the monorepo top when invoked
|
|
18
|
+
// from a sub-package directory.
|
|
26
19
|
// 4. Bundle path's parent chain (`import.meta.url` of THIS module).
|
|
27
|
-
// 5. Parent dirs of the anchor (
|
|
28
|
-
// setups — matches `oxc-resolve.ts`'s walker).
|
|
29
|
-
//
|
|
30
|
-
// Returns the absolute path on success (the caller usually wraps it in
|
|
31
|
-
// `pathToFileURL().href` before passing to dynamic `import(...)`).
|
|
32
|
-
// Returns null when every anchor failed.
|
|
20
|
+
// 5. Parent dirs of the anchor (nested-without-workspace layouts).
|
|
33
21
|
//
|
|
34
|
-
//
|
|
35
|
-
//
|
|
36
|
-
// (parent-dir walker precedent).
|
|
22
|
+
// Precedents: `commands/tsc.ts` (workspace-root + cwd anchoring), `utils/oxc-resolve.ts`
|
|
23
|
+
// (parent-dir walker).
|
|
37
24
|
import { createRequire } from 'node:module';
|
|
38
25
|
import { pathToFileURL } from 'node:url';
|
|
39
26
|
import { delimiter, join, resolve } from 'node:path';
|
|
40
27
|
import { findWorkspaceRoot } from './workspace-root.js';
|
|
41
28
|
/**
|
|
42
|
-
* Resolve a bare npm specifier through
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
* Each anchor is tried in priority order — `GJSIFY_NODE_PATH` (highest)
|
|
47
|
-
* → caller cwd → workspace root → bundle URL → parent-dir walk from
|
|
48
|
-
* cwd. The first anchor whose `require.resolve()` succeeds wins.
|
|
29
|
+
* Resolve a bare npm specifier through the anchors listed above, returning the resolved
|
|
30
|
+
* module's absolute path or null when every anchor failed. Callers usually wrap the result in
|
|
31
|
+
* `pathToFileURL().href` before a dynamic `import(...)`.
|
|
49
32
|
*/
|
|
50
33
|
export function resolveNpmPackage(specifier, opts = {}) {
|
|
51
34
|
const cwd = opts.cwd ?? process.cwd();
|
|
52
|
-
// 1. GJSIFY_NODE_PATH env override (NODE_PATH-like) — each entry is
|
|
53
|
-
// treated as a directory whose own `node_modules` participates
|
|
54
|
-
// in the lookup. Mirrors Node's NODE_PATH semantics.
|
|
55
35
|
const envPath = process.env['GJSIFY_NODE_PATH'];
|
|
56
36
|
if (envPath) {
|
|
57
|
-
// `path.delimiter`, not `':'` —
|
|
58
|
-
//
|
|
59
|
-
//
|
|
60
|
-
// becomes `['C', '\tools']`, neither of which resolves, so the documented
|
|
61
|
-
// override silently did nothing on Windows and fell through to anchor 2.
|
|
62
|
-
// `commands/run.ts` and `utils/run-lifecycle-script.ts` already get this
|
|
63
|
-
// right; this was the site that was missed.
|
|
37
|
+
// `path.delimiter`, not `':'` — NODE_PATH uses `;` on Windows, where splitting on a
|
|
38
|
+
// colon destroys even a SINGLE entry (`C:\tools` → `['C', '\tools']`), so the
|
|
39
|
+
// documented override silently did nothing there and fell through to anchor 2.
|
|
64
40
|
for (const dir of envPath.split(delimiter).filter(Boolean)) {
|
|
65
41
|
const hit = tryResolveFromDir(specifier, resolve(dir));
|
|
66
42
|
if (hit)
|
|
67
43
|
return hit;
|
|
68
44
|
}
|
|
69
45
|
}
|
|
70
|
-
// 2. Caller cwd → walk up for nearest node_modules/<pkg>.
|
|
71
46
|
const fromCwd = tryResolveFromDir(specifier, cwd);
|
|
72
47
|
if (fromCwd)
|
|
73
48
|
return fromCwd;
|
|
74
|
-
// 3. Workspace root (monorepo top, if any).
|
|
75
49
|
const wsRoot = findWorkspaceRoot(cwd);
|
|
76
50
|
if (wsRoot && wsRoot !== cwd) {
|
|
77
51
|
const fromWsRoot = tryResolveFromDir(specifier, wsRoot);
|
|
78
52
|
if (fromWsRoot)
|
|
79
53
|
return fromWsRoot;
|
|
80
54
|
}
|
|
81
|
-
//
|
|
82
|
-
//
|
|
83
|
-
// `<install>/node_modules/rolldown` next to the CLI bundle)
|
|
84
|
-
// is reachable even when the user runs the bundle directly from
|
|
85
|
-
// an unrelated cwd.
|
|
55
|
+
// Anchored at the bundle URL so the install-time layout (`<install>/node_modules/rolldown`
|
|
56
|
+
// next to the CLI bundle) stays reachable when the bundle is run from an unrelated cwd.
|
|
86
57
|
if (opts.bundleUrl) {
|
|
87
58
|
try {
|
|
88
59
|
const req = createRequire(opts.bundleUrl);
|
|
@@ -92,11 +63,8 @@ export function resolveNpmPackage(specifier, opts = {}) {
|
|
|
92
63
|
// Fall through.
|
|
93
64
|
}
|
|
94
65
|
}
|
|
95
|
-
//
|
|
96
|
-
//
|
|
97
|
-
// levels to avoid runaway filesystem walks on pathological
|
|
98
|
-
// layouts. Matches the depth `oxc-resolve.ts` uses for its
|
|
99
|
-
// equivalent walker.
|
|
66
|
+
// Last resort for nested layouts without a workspace marker. Depth-capped so a
|
|
67
|
+
// pathological layout cannot turn a failed resolve into a filesystem walk to `/`.
|
|
100
68
|
let dir = resolve(cwd, '..');
|
|
101
69
|
for (let i = 0; i < 8; i++) {
|
|
102
70
|
const hit = tryResolveFromDir(specifier, dir);
|
|
@@ -110,11 +78,9 @@ export function resolveNpmPackage(specifier, opts = {}) {
|
|
|
110
78
|
return null;
|
|
111
79
|
}
|
|
112
80
|
/**
|
|
113
|
-
*
|
|
114
|
-
*
|
|
115
|
-
*
|
|
116
|
-
* so seeding it inside `<dir>` makes `<dir>/node_modules/<pkg>` the
|
|
117
|
-
* first hit.
|
|
81
|
+
* Resolve `specifier` as if a fictional source file at `<dir>/__gjsify_resolve__.js` were
|
|
82
|
+
* doing the lookup: createRequire walks up from the anchor's PARENT for `node_modules/<pkg>`,
|
|
83
|
+
* so seeding it inside `<dir>` makes `<dir>/node_modules/<pkg>` the first hit.
|
|
118
84
|
*/
|
|
119
85
|
function tryResolveFromDir(specifier, dir) {
|
|
120
86
|
try {
|
|
@@ -10,32 +10,24 @@ export interface PluginByName {
|
|
|
10
10
|
/**
|
|
11
11
|
* Strategy for turning a resolved plugin file path into its module namespace.
|
|
12
12
|
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
* single self-contained ESM file (Rolldown resolves the exports map at
|
|
20
|
-
* bundle time), then imports that. See `BuildAction.loadPluginViaGjsBundle`.
|
|
13
|
+
* A plain dynamic `import()` on Node, but under GJS it cannot be: GJS's native ESM loader does not
|
|
14
|
+
* follow npm `package.json#exports` subpath maps for bare specifiers, so a plugin whose source
|
|
15
|
+
* does `import … from '@scope/pkg/internal-subpath'` throws `Module not found` even with the file
|
|
16
|
+
* on disk. The CLI injects a GJS strategy that first bundles the plugin to one self-contained ESM
|
|
17
|
+
* file (Rolldown resolves the exports map at bundle time), then imports that — see
|
|
18
|
+
* `BuildAction.loadPluginViaGjsBundle`.
|
|
21
19
|
*/
|
|
22
20
|
export type LoadPluginModule = (resolvedPath: string, pluginName: string) => Promise<Record<string, unknown>>;
|
|
23
21
|
export interface ResolveUserPluginsOptions {
|
|
24
|
-
/**
|
|
25
|
-
* Override how a resolved plugin path is turned into its module
|
|
26
|
-
* namespace. Defaults to a direct dynamic `import()` (correct on Node).
|
|
27
|
-
*/
|
|
22
|
+
/** Defaults to a direct dynamic `import()`, which is correct on Node. */
|
|
28
23
|
loadModule?: LoadPluginModule;
|
|
29
24
|
}
|
|
30
25
|
/** Type-guard: a `PluginByName` shape rather than a Rolldown plugin object. */
|
|
31
26
|
export declare function isPluginByName(value: unknown): value is PluginByName;
|
|
32
27
|
/**
|
|
33
|
-
* Resolve a list of mixed user plugins
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
* the
|
|
37
|
-
*
|
|
38
|
-
* Throws when a name fails to resolve, when the chosen export is not a
|
|
39
|
-
* function, or when the factory returns nothing.
|
|
28
|
+
* Resolve a list of mixed user plugins, anchored at `projectDir`. Plugin objects pass through
|
|
29
|
+
* unchanged; `PluginByName` entries are imported, instantiated with their `options`, and returned
|
|
30
|
+
* in the same position. Throws when a name fails to resolve, the chosen export is not a function,
|
|
31
|
+
* or the factory returns nothing.
|
|
40
32
|
*/
|
|
41
33
|
export declare function resolveUserPlugins(plugins: ReadonlyArray<RolldownPluginOption | PluginByName>, projectDir: string, options?: ResolveUserPluginsOptions): Promise<RolldownPluginOption[]>;
|