@vltpkg/cli-sdk 1.0.0-rc.32 → 1.0.0-rc.33
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/commands/access.d.ts +1 -0
- package/dist/commands/access.js +11 -6
- package/dist/commands/build.d.ts +1 -0
- package/dist/commands/build.js +1 -0
- package/dist/commands/cache.d.ts +1 -0
- package/dist/commands/cache.js +1 -0
- package/dist/commands/ci.d.ts +1 -0
- package/dist/commands/ci.js +1 -0
- package/dist/commands/create.d.ts +1 -0
- package/dist/commands/create.js +1 -0
- package/dist/commands/deprecate.d.ts +1 -0
- package/dist/commands/deprecate.js +4 -1
- package/dist/commands/dist-tag.d.ts +1 -0
- package/dist/commands/dist-tag.js +3 -1
- package/dist/commands/exec-cache.d.ts +1 -0
- package/dist/commands/exec-cache.js +1 -0
- package/dist/commands/exec.d.ts +1 -0
- package/dist/commands/exec.js +1 -0
- package/dist/commands/install.d.ts +1 -0
- package/dist/commands/install.js +12 -0
- package/dist/commands/list.d.ts +1 -0
- package/dist/commands/list.js +1 -0
- package/dist/commands/login.js +16 -3
- package/dist/commands/logout.d.ts +1 -0
- package/dist/commands/logout.js +7 -2
- package/dist/commands/pack.d.ts +1 -0
- package/dist/commands/pack.js +1 -0
- package/dist/commands/ping.d.ts +1 -0
- package/dist/commands/ping.js +5 -2
- package/dist/commands/profile.d.ts +1 -0
- package/dist/commands/profile.js +4 -2
- package/dist/commands/publish.d.ts +1 -0
- package/dist/commands/publish.js +3 -1
- package/dist/commands/query.d.ts +1 -0
- package/dist/commands/query.js +1 -0
- package/dist/commands/registry.d.ts +26 -0
- package/dist/commands/registry.js +99 -0
- package/dist/commands/run-exec.d.ts +1 -0
- package/dist/commands/run-exec.js +1 -0
- package/dist/commands/setup.d.ts +25 -0
- package/dist/commands/setup.js +142 -0
- package/dist/commands/token.d.ts +1 -0
- package/dist/commands/token.js +8 -3
- package/dist/commands/uninstall.d.ts +1 -0
- package/dist/commands/uninstall.js +1 -0
- package/dist/commands/unpublish.d.ts +1 -0
- package/dist/commands/unpublish.js +4 -1
- package/dist/commands/update.d.ts +1 -0
- package/dist/commands/update.js +1 -0
- package/dist/commands/view.d.ts +1 -0
- package/dist/commands/view.js +3 -2
- package/dist/commands/whoami.d.ts +1 -0
- package/dist/commands/whoami.js +7 -2
- package/dist/config/definition.d.ts +38 -0
- package/dist/config/definition.js +88 -11
- package/dist/config/index.js +6 -0
- package/dist/custom-help.js +17 -1
- package/dist/index.js +4 -0
- package/dist/load-command.d.ts +6 -0
- package/dist/output.js +15 -1
- package/dist/print-err.js +10 -1
- package/dist/require-registry.d.ts +48 -0
- package/dist/require-registry.js +122 -0
- package/dist/select-registry.d.ts +23 -0
- package/dist/select-registry.js +40 -0
- package/dist/verbose-log.d.ts +31 -0
- package/dist/verbose-log.js +62 -0
- package/package.json +33 -26
package/dist/custom-help.js
CHANGED
|
@@ -198,6 +198,14 @@ const allCommands = [
|
|
|
198
198
|
showByDefault: true,
|
|
199
199
|
defaultOrder: 3,
|
|
200
200
|
},
|
|
201
|
+
{
|
|
202
|
+
name: 'registry',
|
|
203
|
+
aliases: [],
|
|
204
|
+
args: '<alias> <command>',
|
|
205
|
+
desc: 'Run an account command against a named registry',
|
|
206
|
+
showByDefault: true,
|
|
207
|
+
defaultOrder: 9,
|
|
208
|
+
},
|
|
201
209
|
{
|
|
202
210
|
name: 'repo',
|
|
203
211
|
aliases: [],
|
|
@@ -220,6 +228,14 @@ const allCommands = [
|
|
|
220
228
|
desc: 'Run a script &/or fallback to executing a binary',
|
|
221
229
|
showByDefault: false,
|
|
222
230
|
},
|
|
231
|
+
{
|
|
232
|
+
name: 'setup',
|
|
233
|
+
aliases: [],
|
|
234
|
+
args: '[<account>]',
|
|
235
|
+
desc: 'Configure your vlt.io account registries',
|
|
236
|
+
showByDefault: true,
|
|
237
|
+
defaultOrder: 0,
|
|
238
|
+
},
|
|
223
239
|
{
|
|
224
240
|
name: 'token',
|
|
225
241
|
aliases: [],
|
|
@@ -348,7 +364,7 @@ export const generateFullHelp = (colors = false) => {
|
|
|
348
364
|
shorts: [],
|
|
349
365
|
long: 'registry',
|
|
350
366
|
args: '<url>',
|
|
351
|
-
desc: '
|
|
367
|
+
desc: 'Set the registry to resolve packages against',
|
|
352
368
|
},
|
|
353
369
|
{
|
|
354
370
|
shorts: ['v'],
|
package/dist/index.js
CHANGED
|
@@ -66,6 +66,10 @@ const run = async () => {
|
|
|
66
66
|
}
|
|
67
67
|
return process.exit(process.exitCode || 1);
|
|
68
68
|
}
|
|
69
|
+
if (vlt.command === 'registry') {
|
|
70
|
+
const { dispatchRegistry } = await import("./commands/registry.js");
|
|
71
|
+
await dispatchRegistry(vlt);
|
|
72
|
+
}
|
|
69
73
|
const command = await loadCommand(vlt.command);
|
|
70
74
|
await outputCommand(command, vlt, { start, vltVersion: version });
|
|
71
75
|
};
|
package/dist/load-command.d.ts
CHANGED
|
@@ -11,5 +11,11 @@ export type Command<T> = {
|
|
|
11
11
|
command: CommandFn<T>;
|
|
12
12
|
usage: CommandUsage;
|
|
13
13
|
views: Views<T>;
|
|
14
|
+
/**
|
|
15
|
+
* Set to `true` by commands that hit a registry or resolve registry
|
|
16
|
+
* specs. There is no default registry, so `outputCommand()` fails
|
|
17
|
+
* early with an `ECONFIG` error when one of these runs unconfigured.
|
|
18
|
+
*/
|
|
19
|
+
needsRegistry?: boolean;
|
|
14
20
|
};
|
|
15
21
|
export declare const loadCommand: <T>(command: Commands[keyof Commands] | undefined) => Promise<Command<T>>;
|
package/dist/output.js
CHANGED
|
@@ -2,9 +2,11 @@ import { formatWithOptions, styleText as utilStyleText, } from 'node:util';
|
|
|
2
2
|
import { createSupportsColor } from 'supports-color';
|
|
3
3
|
import { defaultView } from "./config/definition.js";
|
|
4
4
|
import { printErr, formatOptions } from "./print-err.js";
|
|
5
|
+
import { hasConfiguredRegistry, missingRegistryError, } from "./require-registry.js";
|
|
5
6
|
import { isViewClass } from "./view.js";
|
|
6
7
|
import { generateDefaultHelp, generateFullHelp, } from "./custom-help.js";
|
|
7
8
|
import { flush as flushTelemetry, trackCommand, trackError, } from "./telemetry.js";
|
|
9
|
+
import { startRequestLog } from "./verbose-log.js";
|
|
8
10
|
/* c8 ignore start - CI env detection is a best-effort heuristic */
|
|
9
11
|
const isCI = () => !!(process.env.CI ||
|
|
10
12
|
process.env.GITHUB_ACTIONS ||
|
|
@@ -90,7 +92,7 @@ const startView = (conf, opts, views, { start } = { start: Date.now() }) => {
|
|
|
90
92
|
export const outputCommand = async (cliCommand, conf, { start, vltVersion } = {
|
|
91
93
|
start: Date.now(),
|
|
92
94
|
}) => {
|
|
93
|
-
const { usage, views, command } = cliCommand;
|
|
95
|
+
const { usage, views, command, needsRegistry } = cliCommand;
|
|
94
96
|
const stdoutColor = conf.values.color ?? supportsColor(process.stdout);
|
|
95
97
|
const stderrColor = conf.values.color ?? supportsColor(process.stderr);
|
|
96
98
|
if (conf.values.help) {
|
|
@@ -111,13 +113,24 @@ export const outputCommand = async (cliCommand, conf, { start, vltVersion } = {
|
|
|
111
113
|
if (stderrColor)
|
|
112
114
|
styleTextStderr = styleText;
|
|
113
115
|
/* c8 ignore stop */
|
|
116
|
+
// Stream per-request diagnostics to stderr when `--loglevel` is verbose
|
|
117
|
+
// or higher (e.g. via `--verbose`). No-op otherwise.
|
|
118
|
+
const stopRequestLog = startRequestLog(conf.values.loglevel, line => stderr(line), styleTextStderr);
|
|
114
119
|
const { onDone, onError } = startView(conf,
|
|
115
120
|
// assume views will always output to stdout so use color support from there
|
|
116
121
|
{ colors: stdoutColor }, views, { start });
|
|
117
122
|
const telemetryEnabled = conf.values.telemetry;
|
|
118
123
|
const commandName = conf.command;
|
|
119
124
|
try {
|
|
125
|
+
// checked here rather than in run() so that the missing-registry
|
|
126
|
+
// error is rendered, tracked and exited like any other command
|
|
127
|
+
// error, and so that the `--help` return above still works when
|
|
128
|
+
// nothing is configured.
|
|
129
|
+
if (needsRegistry && !hasConfiguredRegistry(conf)) {
|
|
130
|
+
throw missingRegistryError();
|
|
131
|
+
}
|
|
120
132
|
const output = await onDone(await command(conf));
|
|
133
|
+
stopRequestLog();
|
|
121
134
|
const duration_ms = Date.now() - start;
|
|
122
135
|
trackCommand({
|
|
123
136
|
command: commandName,
|
|
@@ -145,6 +158,7 @@ export const outputCommand = async (cliCommand, conf, { start, vltVersion } = {
|
|
|
145
158
|
await flushTelemetry();
|
|
146
159
|
}
|
|
147
160
|
catch (err) {
|
|
161
|
+
stopRequestLog();
|
|
148
162
|
onError?.(err);
|
|
149
163
|
process.exitCode ||= 1;
|
|
150
164
|
const duration_ms = Date.now() - start;
|
package/dist/print-err.js
CHANGED
|
@@ -13,6 +13,15 @@ export const formatOptions = {
|
|
|
13
13
|
};
|
|
14
14
|
const isNonEmptyString = (v) => !!v && typeof v === 'string';
|
|
15
15
|
const formatURL = (v, format) => v instanceof URL ? v.toString() : /* c8 ignore next */ format(v);
|
|
16
|
+
// True when `v` overrides the default `Object.prototype.toString`, i.e.
|
|
17
|
+
// stringifying it yields something meaningful (like a `Spec` → `next@*`)
|
|
18
|
+
// rather than `[object Object]`.
|
|
19
|
+
const hasCustomToString = (v) => isObject(v) && v.toString !== Object.prototype.toString;
|
|
20
|
+
// Render a value that has a meaningful custom `toString()` (such as a
|
|
21
|
+
// `Spec`, e.g. `next@*`) as a concise string rather than dumping its
|
|
22
|
+
// entire internal structure via util.inspect. Falls back to `format`
|
|
23
|
+
// for plain values/objects.
|
|
24
|
+
const formatToString = (v, format) => hasCustomToString(v) ? v.toString() : format(v);
|
|
16
25
|
const formatArray = (v, format, joiner = ', ') => Array.isArray(v) ? v.join(joiner) : /* c8 ignore next */ format(v);
|
|
17
26
|
export const indent = (lines, num = 2) => lines
|
|
18
27
|
.split('\n')
|
|
@@ -147,7 +156,7 @@ const printCode = (err, usage, stderr, format) => {
|
|
|
147
156
|
stderr(indent(`While fetching: ${formatURL(url, format)}`));
|
|
148
157
|
}
|
|
149
158
|
if (spec) {
|
|
150
|
-
stderr(indent(`To satisfy: ${
|
|
159
|
+
stderr(indent(`To satisfy: ${formatToString(spec, format)}`));
|
|
151
160
|
}
|
|
152
161
|
if (from) {
|
|
153
162
|
stderr(indent(`From: ${format(from)}`));
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { RegistryCandidate } from './select-registry.ts';
|
|
2
|
+
import type { LoadedConfig } from './config/index.ts';
|
|
3
|
+
/**
|
|
4
|
+
* There is no default registry. This is the single message used
|
|
5
|
+
* everywhere a registry is required but missing.
|
|
6
|
+
*/
|
|
7
|
+
export declare const missingRegistryError: () => Error;
|
|
8
|
+
/**
|
|
9
|
+
* Multiple registries are configured and none was selected. Used in
|
|
10
|
+
* non-interactive contexts where we cannot prompt and there is no
|
|
11
|
+
* `default-registry-alias` to fall back to.
|
|
12
|
+
*/
|
|
13
|
+
export declare const ambiguousRegistryError: (candidates: RegistryCandidate[]) => Error;
|
|
14
|
+
/**
|
|
15
|
+
* Resolve a named registry alias to its URL, throwing an `ECONFIG`
|
|
16
|
+
* error (listing the known aliases) when the alias is not configured.
|
|
17
|
+
*/
|
|
18
|
+
export declare const resolveRegistryAlias: (conf: LoadedConfig, alias: string) => string;
|
|
19
|
+
/**
|
|
20
|
+
* Whether the current config provides a registry a `needsRegistry`
|
|
21
|
+
* command could act against without prompting for setup. True when an
|
|
22
|
+
* explicit `--registry` URL is set or the user has configured at least
|
|
23
|
+
* one non-default registry alias. Kept consistent with
|
|
24
|
+
* {@link resolveRegistry} so the pre-command gate never rejects a config
|
|
25
|
+
* the resolver would otherwise accept or prompt for.
|
|
26
|
+
*/
|
|
27
|
+
export declare const hasConfiguredRegistry: (conf: LoadedConfig) => boolean;
|
|
28
|
+
/**
|
|
29
|
+
* Synchronous, non-interactive registry resolution used by
|
|
30
|
+
* programmatic callers. Precedence: explicit alias > `--registry`
|
|
31
|
+
* scalar > single configured alias > `default-registry-alias`. Throws
|
|
32
|
+
* when nothing is configured or the choice is ambiguous.
|
|
33
|
+
*/
|
|
34
|
+
export declare const requireRegistry: (conf: LoadedConfig, alias?: string) => string;
|
|
35
|
+
/**
|
|
36
|
+
* Resolve the registry a command should act against.
|
|
37
|
+
*
|
|
38
|
+
* Precedence: explicit `alias` (from `vlt registry <alias> <cmd>`) >
|
|
39
|
+
* `--registry` URL scalar > the single configured alias. When multiple
|
|
40
|
+
* aliases are configured and none was chosen, prompt interactively on a
|
|
41
|
+
* TTY, otherwise fall back to `default-registry-alias`, else error.
|
|
42
|
+
*/
|
|
43
|
+
export declare const resolveRegistry: (conf: LoadedConfig, { alias, interactive, input, output, }?: {
|
|
44
|
+
alias?: string;
|
|
45
|
+
interactive?: boolean;
|
|
46
|
+
input?: NodeJS.ReadableStream;
|
|
47
|
+
output?: NodeJS.WritableStream;
|
|
48
|
+
}) => Promise<string>;
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { error } from '@vltpkg/error-cause';
|
|
2
|
+
import { defaultRegistries } from '@vltpkg/spec';
|
|
3
|
+
import { selectRegistry } from "./select-registry.js";
|
|
4
|
+
/**
|
|
5
|
+
* There is no default registry. This is the single message used
|
|
6
|
+
* everywhere a registry is required but missing.
|
|
7
|
+
*/
|
|
8
|
+
export const missingRegistryError = () => error([
|
|
9
|
+
'Missing registry configuration.',
|
|
10
|
+
'',
|
|
11
|
+
'vlt has no default registry. Run `vlt setup` to get configured.',
|
|
12
|
+
'',
|
|
13
|
+
'See https://docs.vlt.sh/cli for other ways to set a registry.',
|
|
14
|
+
].join('\n'), { code: 'ECONFIG' });
|
|
15
|
+
/**
|
|
16
|
+
* Multiple registries are configured and none was selected. Used in
|
|
17
|
+
* non-interactive contexts where we cannot prompt and there is no
|
|
18
|
+
* `default-registry-alias` to fall back to.
|
|
19
|
+
*/
|
|
20
|
+
export const ambiguousRegistryError = (candidates) => error([
|
|
21
|
+
'Multiple registries are configured; specify which one to use.',
|
|
22
|
+
'',
|
|
23
|
+
'Run `vlt registry <alias> <command>` with one of:',
|
|
24
|
+
...candidates.map(c => ` ${c.alias} -> ${c.url}`),
|
|
25
|
+
].join('\n'), {
|
|
26
|
+
code: 'ECONFIG',
|
|
27
|
+
validOptions: candidates.map(c => c.alias),
|
|
28
|
+
});
|
|
29
|
+
/**
|
|
30
|
+
* Resolve a named registry alias to its URL, throwing an `ECONFIG`
|
|
31
|
+
* error (listing the known aliases) when the alias is not configured.
|
|
32
|
+
*/
|
|
33
|
+
export const resolveRegistryAlias = (conf, alias) => {
|
|
34
|
+
const url = conf.options.registries[alias];
|
|
35
|
+
if (!url) {
|
|
36
|
+
throw error(`Unknown registry alias: ${alias}`, {
|
|
37
|
+
code: 'ECONFIG',
|
|
38
|
+
found: alias,
|
|
39
|
+
validOptions: Object.keys(conf.options.registries),
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
return url;
|
|
43
|
+
};
|
|
44
|
+
/**
|
|
45
|
+
* The registries the user has actually configured, when no explicit
|
|
46
|
+
* `--registry` URL is set. Order follows the `registries` config (which
|
|
47
|
+
* preserves insertion order).
|
|
48
|
+
*
|
|
49
|
+
* Built-in defaults (eg `gh`) are excluded so they don't implicitly
|
|
50
|
+
* satisfy "a registry is configured" for account/auth commands. A
|
|
51
|
+
* built-in alias the user has overridden to a different URL counts as
|
|
52
|
+
* configured. Built-in aliases can still be targeted explicitly via
|
|
53
|
+
* `vlt registry <alias> <cmd>` (which resolves through
|
|
54
|
+
* {@link resolveRegistryAlias}).
|
|
55
|
+
*/
|
|
56
|
+
const gatherCandidates = (conf) => {
|
|
57
|
+
const builtins = defaultRegistries;
|
|
58
|
+
return Object.entries(conf.options.registries)
|
|
59
|
+
.filter(([alias, url]) => builtins[alias] !== url)
|
|
60
|
+
.map(([alias, url]) => ({ alias, url }));
|
|
61
|
+
};
|
|
62
|
+
/**
|
|
63
|
+
* Whether the current config provides a registry a `needsRegistry`
|
|
64
|
+
* command could act against without prompting for setup. True when an
|
|
65
|
+
* explicit `--registry` URL is set or the user has configured at least
|
|
66
|
+
* one non-default registry alias. Kept consistent with
|
|
67
|
+
* {@link resolveRegistry} so the pre-command gate never rejects a config
|
|
68
|
+
* the resolver would otherwise accept or prompt for.
|
|
69
|
+
*/
|
|
70
|
+
export const hasConfiguredRegistry = (conf) => !!conf.options.registry || gatherCandidates(conf).length > 0;
|
|
71
|
+
/**
|
|
72
|
+
* Synchronous, non-interactive registry resolution used by
|
|
73
|
+
* programmatic callers. Precedence: explicit alias > `--registry`
|
|
74
|
+
* scalar > single configured alias > `default-registry-alias`. Throws
|
|
75
|
+
* when nothing is configured or the choice is ambiguous.
|
|
76
|
+
*/
|
|
77
|
+
export const requireRegistry = (conf, alias) => {
|
|
78
|
+
if (alias !== undefined)
|
|
79
|
+
return resolveRegistryAlias(conf, alias);
|
|
80
|
+
const { registry } = conf.options;
|
|
81
|
+
if (registry)
|
|
82
|
+
return registry;
|
|
83
|
+
const candidates = gatherCandidates(conf);
|
|
84
|
+
const [first, second] = candidates;
|
|
85
|
+
if (!first)
|
|
86
|
+
throw missingRegistryError();
|
|
87
|
+
if (!second)
|
|
88
|
+
return first.url;
|
|
89
|
+
const defaultUrl = conf.options.registries[conf.options['default-registry-alias']];
|
|
90
|
+
if (defaultUrl)
|
|
91
|
+
return defaultUrl;
|
|
92
|
+
throw ambiguousRegistryError(candidates);
|
|
93
|
+
};
|
|
94
|
+
/**
|
|
95
|
+
* Resolve the registry a command should act against.
|
|
96
|
+
*
|
|
97
|
+
* Precedence: explicit `alias` (from `vlt registry <alias> <cmd>`) >
|
|
98
|
+
* `--registry` URL scalar > the single configured alias. When multiple
|
|
99
|
+
* aliases are configured and none was chosen, prompt interactively on a
|
|
100
|
+
* TTY, otherwise fall back to `default-registry-alias`, else error.
|
|
101
|
+
*/
|
|
102
|
+
export const resolveRegistry = async (conf, { alias, interactive = process.stdin.isTTY, input, output, } = {}) => {
|
|
103
|
+
if (alias !== undefined)
|
|
104
|
+
return resolveRegistryAlias(conf, alias);
|
|
105
|
+
const { registry } = conf.options;
|
|
106
|
+
if (registry)
|
|
107
|
+
return registry;
|
|
108
|
+
const candidates = gatherCandidates(conf);
|
|
109
|
+
const [first, second] = candidates;
|
|
110
|
+
if (!first)
|
|
111
|
+
throw missingRegistryError();
|
|
112
|
+
if (!second)
|
|
113
|
+
return first.url;
|
|
114
|
+
const defaultAlias = conf.options['default-registry-alias'];
|
|
115
|
+
if (interactive) {
|
|
116
|
+
return selectRegistry(candidates, { defaultAlias, input, output });
|
|
117
|
+
}
|
|
118
|
+
const defaultUrl = conf.options.registries[defaultAlias];
|
|
119
|
+
if (defaultUrl)
|
|
120
|
+
return defaultUrl;
|
|
121
|
+
throw ambiguousRegistryError(candidates);
|
|
122
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/** A configured registry the user can act against. */
|
|
2
|
+
export type RegistryCandidate = {
|
|
3
|
+
/** the configured alias name (a key in `registries`) */
|
|
4
|
+
alias: string;
|
|
5
|
+
/** the resolved registry URL */
|
|
6
|
+
url: string;
|
|
7
|
+
};
|
|
8
|
+
export type SelectStreams = {
|
|
9
|
+
input: NodeJS.ReadableStream;
|
|
10
|
+
output: NodeJS.WritableStream;
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* Interactively prompt the user to choose one of the configured
|
|
14
|
+
* registries. `defaultAlias` (when present in `candidates`) is
|
|
15
|
+
* pre-selected so pressing enter accepts it.
|
|
16
|
+
*
|
|
17
|
+
* Streams are injectable so tests can drive the prompt deterministically.
|
|
18
|
+
*/
|
|
19
|
+
export declare const selectRegistry: (candidates: RegistryCandidate[], { defaultAlias, input, output, }?: {
|
|
20
|
+
defaultAlias?: string;
|
|
21
|
+
input?: NodeJS.ReadableStream;
|
|
22
|
+
output?: NodeJS.WritableStream;
|
|
23
|
+
}) => Promise<string>;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { error } from '@vltpkg/error-cause';
|
|
2
|
+
import { createInterface } from 'node:readline/promises';
|
|
3
|
+
/**
|
|
4
|
+
* Interactively prompt the user to choose one of the configured
|
|
5
|
+
* registries. `defaultAlias` (when present in `candidates`) is
|
|
6
|
+
* pre-selected so pressing enter accepts it.
|
|
7
|
+
*
|
|
8
|
+
* Streams are injectable so tests can drive the prompt deterministically.
|
|
9
|
+
*/
|
|
10
|
+
export const selectRegistry = async (candidates, { defaultAlias, input = process.stdin, output = process.stdout, } = {}) => {
|
|
11
|
+
const defaultIndex = Math.max(candidates.findIndex(c => c.alias === defaultAlias), 0);
|
|
12
|
+
const fallback = candidates[defaultIndex] ?? candidates[0];
|
|
13
|
+
if (!fallback) {
|
|
14
|
+
throw error('No registries to select from', { code: 'ECONFIG' });
|
|
15
|
+
}
|
|
16
|
+
const rl = createInterface({ input, output });
|
|
17
|
+
try {
|
|
18
|
+
output.write('Multiple registries are configured. Select one:\n');
|
|
19
|
+
for (const [i, c] of candidates.entries()) {
|
|
20
|
+
const marker = i === defaultIndex ? ' (default)' : '';
|
|
21
|
+
output.write(` ${i + 1}) ${c.alias} -> ${c.url}${marker}\n`);
|
|
22
|
+
}
|
|
23
|
+
const answer = (await rl.question(`Registry [${defaultIndex + 1}]: `)).trim();
|
|
24
|
+
if (!answer)
|
|
25
|
+
return fallback.url;
|
|
26
|
+
const choice = Number(answer);
|
|
27
|
+
const picked = candidates[choice - 1];
|
|
28
|
+
if (!Number.isInteger(choice) || !picked) {
|
|
29
|
+
throw error('Invalid registry selection', {
|
|
30
|
+
found: answer,
|
|
31
|
+
validOptions: candidates.map((_, i) => String(i + 1)),
|
|
32
|
+
code: 'EUSAGE',
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
return picked.url;
|
|
36
|
+
}
|
|
37
|
+
finally {
|
|
38
|
+
rl.close();
|
|
39
|
+
}
|
|
40
|
+
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { Events } from '@vltpkg/output';
|
|
2
|
+
/**
|
|
3
|
+
* Diagnostic logging levels, ordered from least to most verbose.
|
|
4
|
+
* Mirrors the `loglevel` option in the config definition.
|
|
5
|
+
*/
|
|
6
|
+
export type LogLevel = 'silent' | 'error' | 'warn' | 'info' | 'verbose' | 'debug';
|
|
7
|
+
/** True when the given level should emit per-request logging. */
|
|
8
|
+
export declare const isVerbose: (level: LogLevel) => boolean;
|
|
9
|
+
/** The subset of `styleText` color names this module applies. */
|
|
10
|
+
export type StyleColor = 'green' | 'red' | 'gray';
|
|
11
|
+
/**
|
|
12
|
+
* Minimal signature compatible with the `styleText` helpers exported by
|
|
13
|
+
* `./output.ts` (which accept a wider set of format names). Defaults to an
|
|
14
|
+
* identity function so this module can be tested without color support.
|
|
15
|
+
*/
|
|
16
|
+
export type StyleFn = (format: StyleColor, s: string) => string;
|
|
17
|
+
/**
|
|
18
|
+
* Format a single `request` event into a human-readable log line.
|
|
19
|
+
* Exported for testing.
|
|
20
|
+
*/
|
|
21
|
+
export declare const formatRequestEvent: (event: Events["request"], style?: StyleFn) => string;
|
|
22
|
+
/**
|
|
23
|
+
* Subscribe to registry request events and stream them to `write` when
|
|
24
|
+
* the configured `level` is `verbose` or higher. The `start` event is only
|
|
25
|
+
* logged at `debug` level to avoid duplicate lines (each network request
|
|
26
|
+
* also emits a `complete`/`304` line with its status and duration).
|
|
27
|
+
*
|
|
28
|
+
* Returns a cleanup function that detaches the subscription. When `level`
|
|
29
|
+
* is below `verbose`, nothing is subscribed and the cleanup is a no-op.
|
|
30
|
+
*/
|
|
31
|
+
export declare const startRequestLog: (level: LogLevel, write: (line: string) => void, style?: StyleFn) => (() => void);
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { emitter } from '@vltpkg/output';
|
|
2
|
+
const rank = {
|
|
3
|
+
silent: 0,
|
|
4
|
+
error: 1,
|
|
5
|
+
warn: 2,
|
|
6
|
+
info: 3,
|
|
7
|
+
verbose: 4,
|
|
8
|
+
debug: 5,
|
|
9
|
+
};
|
|
10
|
+
/** True when the given level should emit per-request logging. */
|
|
11
|
+
export const isVerbose = (level) => rank[level] >= rank.verbose;
|
|
12
|
+
const isDebug = (level) => rank[level] >= rank.debug;
|
|
13
|
+
const identityStyle = (_f, s) => s;
|
|
14
|
+
const tagStyle = (state, statusCode) => {
|
|
15
|
+
switch (state) {
|
|
16
|
+
case 'cache':
|
|
17
|
+
case 'stale':
|
|
18
|
+
case '304':
|
|
19
|
+
return 'green';
|
|
20
|
+
case 'start':
|
|
21
|
+
return 'gray';
|
|
22
|
+
case 'complete':
|
|
23
|
+
return statusCode !== undefined && statusCode >= 400 ?
|
|
24
|
+
'red'
|
|
25
|
+
: 'green';
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* Format a single `request` event into a human-readable log line.
|
|
30
|
+
* Exported for testing.
|
|
31
|
+
*/
|
|
32
|
+
export const formatRequestEvent = (event, style = identityStyle) => {
|
|
33
|
+
const { url, state, method = 'GET', statusCode, durationMs } = event;
|
|
34
|
+
// For completed network requests show the status code rather than the
|
|
35
|
+
// literal word "complete"; everything else shows the cache/fetch state.
|
|
36
|
+
const tag = state === 'complete' ? String(statusCode ?? '') : state;
|
|
37
|
+
const duration = durationMs === undefined ? '' : (style('gray', ` (${durationMs}ms)`));
|
|
38
|
+
return `${style(tagStyle(state, statusCode), tag.padEnd(8))} ${method} ${String(url)}${duration}`;
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* Subscribe to registry request events and stream them to `write` when
|
|
42
|
+
* the configured `level` is `verbose` or higher. The `start` event is only
|
|
43
|
+
* logged at `debug` level to avoid duplicate lines (each network request
|
|
44
|
+
* also emits a `complete`/`304` line with its status and duration).
|
|
45
|
+
*
|
|
46
|
+
* Returns a cleanup function that detaches the subscription. When `level`
|
|
47
|
+
* is below `verbose`, nothing is subscribed and the cleanup is a no-op.
|
|
48
|
+
*/
|
|
49
|
+
export const startRequestLog = (level, write, style = identityStyle) => {
|
|
50
|
+
if (!isVerbose(level))
|
|
51
|
+
return () => { };
|
|
52
|
+
const debug = isDebug(level);
|
|
53
|
+
const handler = (event) => {
|
|
54
|
+
// At verbose level, skip the `start` event so each request produces a
|
|
55
|
+
// single completion line; at debug level, show it too.
|
|
56
|
+
if (event.state === 'start' && !debug)
|
|
57
|
+
return;
|
|
58
|
+
write(formatRequestEvent(event, style));
|
|
59
|
+
};
|
|
60
|
+
emitter.on('request', handler);
|
|
61
|
+
return () => emitter.off('request', handler);
|
|
62
|
+
};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vltpkg/cli-sdk",
|
|
3
3
|
"description": "The source for the vlt CLI",
|
|
4
|
-
"version": "1.0.0-rc.
|
|
4
|
+
"version": "1.0.0-rc.33",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
7
7
|
"url": "git+https://github.com/vltpkg/vltpkg.git",
|
|
@@ -14,30 +14,30 @@
|
|
|
14
14
|
},
|
|
15
15
|
"dependencies": {
|
|
16
16
|
"@resvg/resvg-wasm": "^2.6.2",
|
|
17
|
-
"@vltpkg/config": "1.0.0-rc.
|
|
18
|
-
"@vltpkg/dep-id": "1.0.0-rc.
|
|
19
|
-
"@vltpkg/dot-prop": "1.0.0-rc.
|
|
20
|
-
"@vltpkg/error-cause": "1.0.0-rc.
|
|
21
|
-
"@vltpkg/git": "1.0.0-rc.
|
|
22
|
-
"@vltpkg/graph": "1.0.0-rc.
|
|
23
|
-
"@vltpkg/graph-run": "1.0.0-rc.
|
|
24
|
-
"@vltpkg/init": "1.0.0-rc.
|
|
25
|
-
"@vltpkg/output": "1.0.0-rc.
|
|
26
|
-
"@vltpkg/package-info": "1.0.0-rc.
|
|
27
|
-
"@vltpkg/package-json": "1.0.0-rc.
|
|
28
|
-
"@vltpkg/promise-spawn": "1.0.0-rc.
|
|
29
|
-
"@vltpkg/query": "1.0.0-rc.
|
|
30
|
-
"@vltpkg/registry-client": "1.0.0-rc.
|
|
31
|
-
"@vltpkg/rollback-remove": "1.0.0-rc.
|
|
32
|
-
"@vltpkg/run": "1.0.0-rc.
|
|
33
|
-
"@vltpkg/security-archive": "1.0.0-rc.
|
|
34
|
-
"@vltpkg/spec": "1.0.0-rc.
|
|
35
|
-
"@vltpkg/types": "1.0.0-rc.
|
|
36
|
-
"@vltpkg/url-open": "1.0.0-rc.
|
|
37
|
-
"@vltpkg/vlt-json": "1.0.0-rc.
|
|
38
|
-
"@vltpkg/vlx": "1.0.0-rc.
|
|
39
|
-
"@vltpkg/workspaces": "1.0.0-rc.
|
|
40
|
-
"@vltpkg/xdg": "1.0.0-rc.
|
|
17
|
+
"@vltpkg/config": "1.0.0-rc.33",
|
|
18
|
+
"@vltpkg/dep-id": "1.0.0-rc.33",
|
|
19
|
+
"@vltpkg/dot-prop": "1.0.0-rc.33",
|
|
20
|
+
"@vltpkg/error-cause": "1.0.0-rc.33",
|
|
21
|
+
"@vltpkg/git": "1.0.0-rc.33",
|
|
22
|
+
"@vltpkg/graph": "1.0.0-rc.33",
|
|
23
|
+
"@vltpkg/graph-run": "1.0.0-rc.33",
|
|
24
|
+
"@vltpkg/init": "1.0.0-rc.33",
|
|
25
|
+
"@vltpkg/output": "1.0.0-rc.33",
|
|
26
|
+
"@vltpkg/package-info": "1.0.0-rc.33",
|
|
27
|
+
"@vltpkg/package-json": "1.0.0-rc.33",
|
|
28
|
+
"@vltpkg/promise-spawn": "1.0.0-rc.33",
|
|
29
|
+
"@vltpkg/query": "1.0.0-rc.33",
|
|
30
|
+
"@vltpkg/registry-client": "1.0.0-rc.33",
|
|
31
|
+
"@vltpkg/rollback-remove": "1.0.0-rc.33",
|
|
32
|
+
"@vltpkg/run": "1.0.0-rc.33",
|
|
33
|
+
"@vltpkg/security-archive": "1.0.0-rc.33",
|
|
34
|
+
"@vltpkg/spec": "1.0.0-rc.33",
|
|
35
|
+
"@vltpkg/types": "1.0.0-rc.33",
|
|
36
|
+
"@vltpkg/url-open": "1.0.0-rc.33",
|
|
37
|
+
"@vltpkg/vlt-json": "1.0.0-rc.33",
|
|
38
|
+
"@vltpkg/vlx": "1.0.0-rc.33",
|
|
39
|
+
"@vltpkg/workspaces": "1.0.0-rc.33",
|
|
40
|
+
"@vltpkg/xdg": "1.0.0-rc.33",
|
|
41
41
|
"ansi-to-pre": "^1.0.6",
|
|
42
42
|
"beautiful-mermaid": "^1.1.3",
|
|
43
43
|
"chalk": "^5.6.2",
|
|
@@ -120,5 +120,12 @@
|
|
|
120
120
|
],
|
|
121
121
|
"keywords": [
|
|
122
122
|
"vltpkg"
|
|
123
|
-
]
|
|
123
|
+
],
|
|
124
|
+
"bugs": [
|
|
125
|
+
{
|
|
126
|
+
"type": "link",
|
|
127
|
+
"url": "https://github.com/vltpkg/vltpkg/issues"
|
|
128
|
+
}
|
|
129
|
+
],
|
|
130
|
+
"homepage": "https://github.com/vltpkg/vltpkg/tree/main/src/cli-sdk#readme"
|
|
124
131
|
}
|