@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.
Files changed (68) hide show
  1. package/dist/commands/access.d.ts +1 -0
  2. package/dist/commands/access.js +11 -6
  3. package/dist/commands/build.d.ts +1 -0
  4. package/dist/commands/build.js +1 -0
  5. package/dist/commands/cache.d.ts +1 -0
  6. package/dist/commands/cache.js +1 -0
  7. package/dist/commands/ci.d.ts +1 -0
  8. package/dist/commands/ci.js +1 -0
  9. package/dist/commands/create.d.ts +1 -0
  10. package/dist/commands/create.js +1 -0
  11. package/dist/commands/deprecate.d.ts +1 -0
  12. package/dist/commands/deprecate.js +4 -1
  13. package/dist/commands/dist-tag.d.ts +1 -0
  14. package/dist/commands/dist-tag.js +3 -1
  15. package/dist/commands/exec-cache.d.ts +1 -0
  16. package/dist/commands/exec-cache.js +1 -0
  17. package/dist/commands/exec.d.ts +1 -0
  18. package/dist/commands/exec.js +1 -0
  19. package/dist/commands/install.d.ts +1 -0
  20. package/dist/commands/install.js +12 -0
  21. package/dist/commands/list.d.ts +1 -0
  22. package/dist/commands/list.js +1 -0
  23. package/dist/commands/login.js +16 -3
  24. package/dist/commands/logout.d.ts +1 -0
  25. package/dist/commands/logout.js +7 -2
  26. package/dist/commands/pack.d.ts +1 -0
  27. package/dist/commands/pack.js +1 -0
  28. package/dist/commands/ping.d.ts +1 -0
  29. package/dist/commands/ping.js +5 -2
  30. package/dist/commands/profile.d.ts +1 -0
  31. package/dist/commands/profile.js +4 -2
  32. package/dist/commands/publish.d.ts +1 -0
  33. package/dist/commands/publish.js +3 -1
  34. package/dist/commands/query.d.ts +1 -0
  35. package/dist/commands/query.js +1 -0
  36. package/dist/commands/registry.d.ts +26 -0
  37. package/dist/commands/registry.js +99 -0
  38. package/dist/commands/run-exec.d.ts +1 -0
  39. package/dist/commands/run-exec.js +1 -0
  40. package/dist/commands/setup.d.ts +25 -0
  41. package/dist/commands/setup.js +142 -0
  42. package/dist/commands/token.d.ts +1 -0
  43. package/dist/commands/token.js +8 -3
  44. package/dist/commands/uninstall.d.ts +1 -0
  45. package/dist/commands/uninstall.js +1 -0
  46. package/dist/commands/unpublish.d.ts +1 -0
  47. package/dist/commands/unpublish.js +4 -1
  48. package/dist/commands/update.d.ts +1 -0
  49. package/dist/commands/update.js +1 -0
  50. package/dist/commands/view.d.ts +1 -0
  51. package/dist/commands/view.js +3 -2
  52. package/dist/commands/whoami.d.ts +1 -0
  53. package/dist/commands/whoami.js +7 -2
  54. package/dist/config/definition.d.ts +38 -0
  55. package/dist/config/definition.js +88 -11
  56. package/dist/config/index.js +6 -0
  57. package/dist/custom-help.js +17 -1
  58. package/dist/index.js +4 -0
  59. package/dist/load-command.d.ts +6 -0
  60. package/dist/output.js +15 -1
  61. package/dist/print-err.js +10 -1
  62. package/dist/require-registry.d.ts +48 -0
  63. package/dist/require-registry.js +122 -0
  64. package/dist/select-registry.d.ts +23 -0
  65. package/dist/select-registry.js +40 -0
  66. package/dist/verbose-log.d.ts +31 -0
  67. package/dist/verbose-log.js +62 -0
  68. package/package.json +33 -26
@@ -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: 'Override default registry',
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
  };
@@ -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: ${format(spec)}`));
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.32",
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.32",
18
- "@vltpkg/dep-id": "1.0.0-rc.32",
19
- "@vltpkg/dot-prop": "1.0.0-rc.32",
20
- "@vltpkg/error-cause": "1.0.0-rc.32",
21
- "@vltpkg/git": "1.0.0-rc.32",
22
- "@vltpkg/graph": "1.0.0-rc.32",
23
- "@vltpkg/graph-run": "1.0.0-rc.32",
24
- "@vltpkg/init": "1.0.0-rc.32",
25
- "@vltpkg/output": "1.0.0-rc.32",
26
- "@vltpkg/package-info": "1.0.0-rc.32",
27
- "@vltpkg/package-json": "1.0.0-rc.32",
28
- "@vltpkg/promise-spawn": "1.0.0-rc.32",
29
- "@vltpkg/query": "1.0.0-rc.32",
30
- "@vltpkg/registry-client": "1.0.0-rc.32",
31
- "@vltpkg/rollback-remove": "1.0.0-rc.32",
32
- "@vltpkg/run": "1.0.0-rc.32",
33
- "@vltpkg/security-archive": "1.0.0-rc.32",
34
- "@vltpkg/spec": "1.0.0-rc.32",
35
- "@vltpkg/types": "1.0.0-rc.32",
36
- "@vltpkg/url-open": "1.0.0-rc.32",
37
- "@vltpkg/vlt-json": "1.0.0-rc.32",
38
- "@vltpkg/vlx": "1.0.0-rc.32",
39
- "@vltpkg/workspaces": "1.0.0-rc.32",
40
- "@vltpkg/xdg": "1.0.0-rc.32",
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
  }