@vltpkg/cli-sdk 1.0.0-rc.3 → 1.0.0-rc.30
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 +22 -0
- package/dist/commands/access.js +246 -0
- package/dist/commands/bugs.d.ts +17 -0
- package/dist/commands/bugs.js +163 -0
- package/dist/{esm/commands → commands}/build.d.ts +0 -1
- package/dist/{esm/commands → commands}/build.js +0 -1
- package/dist/{esm/commands → commands}/cache.d.ts +0 -1
- package/dist/{esm/commands → commands}/cache.js +0 -1
- package/dist/{esm/commands → commands}/ci.d.ts +0 -1
- package/dist/{esm/commands → commands}/ci.js +11 -3
- package/dist/{esm/commands → commands}/config.d.ts +0 -1
- package/dist/{esm/commands → commands}/config.js +6 -1
- package/dist/commands/create.d.ts +8 -0
- package/dist/commands/create.js +102 -0
- package/dist/commands/deprecate.d.ts +13 -0
- package/dist/commands/deprecate.js +139 -0
- package/dist/commands/dist-tag.d.ts +21 -0
- package/dist/commands/dist-tag.js +177 -0
- package/dist/{esm/commands → commands}/docs.d.ts +0 -1
- package/dist/{esm/commands → commands}/docs.js +2 -3
- package/dist/{esm/commands → commands}/exec-cache.d.ts +0 -1
- package/dist/{esm/commands → commands}/exec-cache.js +0 -1
- package/dist/{esm/commands → commands}/exec-local.d.ts +0 -1
- package/dist/{esm/commands → commands}/exec-local.js +23 -1
- package/dist/{esm/commands → commands}/exec.d.ts +0 -1
- package/dist/{esm/commands → commands}/exec.js +84 -10
- package/dist/{esm/commands → commands}/help.d.ts +0 -1
- package/dist/{esm/commands → commands}/help.js +5 -1
- package/dist/{esm/commands → commands}/init.d.ts +0 -1
- package/dist/{esm/commands → commands}/init.js +31 -10
- package/dist/{esm/commands → commands}/install/reporter.d.ts +0 -1
- package/dist/{esm/commands → commands}/install/reporter.js +0 -1
- package/dist/{esm/commands → commands}/install.d.ts +21 -3
- package/dist/commands/install.js +140 -0
- package/dist/{esm/commands → commands}/list.d.ts +4 -2
- package/dist/{esm/commands → commands}/list.js +8 -10
- package/dist/{esm/commands → commands}/login.d.ts +0 -1
- package/dist/{esm/commands → commands}/login.js +10 -1
- package/dist/{esm/commands/token.d.ts → commands/logout.d.ts} +0 -1
- package/dist/{esm/commands → commands}/logout.js +10 -1
- package/dist/{esm/commands → commands}/pack.d.ts +0 -1
- package/dist/{esm/commands → commands}/pack.js +90 -32
- package/dist/commands/ping.d.ts +17 -0
- package/dist/commands/ping.js +114 -0
- package/dist/{esm/commands → commands}/pkg.d.ts +0 -1
- package/dist/{esm/commands → commands}/pkg.js +27 -1
- package/dist/commands/profile.d.ts +13 -0
- package/dist/commands/profile.js +104 -0
- package/dist/{esm/commands → commands}/publish.d.ts +1 -2
- package/dist/{esm/commands → commands}/publish.js +63 -12
- package/dist/{esm/commands → commands}/query.d.ts +4 -2
- package/dist/{esm/commands → commands}/query.js +12 -10
- package/dist/commands/repo.d.ts +17 -0
- package/dist/commands/repo.js +157 -0
- package/dist/{esm/commands → commands}/run-exec.d.ts +0 -1
- package/dist/commands/run-exec.js +40 -0
- package/dist/{esm/commands → commands}/run.d.ts +0 -1
- package/dist/{esm/commands → commands}/run.js +27 -1
- package/dist/commands/token.d.ts +31 -0
- package/dist/commands/token.js +186 -0
- package/dist/{esm/commands → commands}/uninstall.d.ts +0 -1
- package/dist/{esm/commands → commands}/uninstall.js +16 -3
- package/dist/commands/unpublish.d.ts +15 -0
- package/dist/commands/unpublish.js +200 -0
- package/dist/{esm/commands → commands}/update.d.ts +0 -1
- package/dist/{esm/commands → commands}/update.js +6 -1
- package/dist/{esm/commands → commands}/version.d.ts +0 -1
- package/dist/{esm/commands → commands}/version.js +27 -1
- package/dist/commands/view.d.ts +22 -0
- package/dist/commands/view.js +334 -0
- package/dist/{esm/commands → commands}/whoami.d.ts +0 -1
- package/dist/{esm/commands → commands}/whoami.js +10 -1
- package/dist/{esm/config → config}/definition.d.ts +39 -19
- package/dist/{esm/config → config}/definition.js +74 -39
- package/dist/{esm/config → config}/index.d.ts +0 -1
- package/dist/{esm/config → config}/index.js +37 -2
- package/dist/{esm/config → config}/merge.d.ts +0 -1
- package/dist/{esm/config → config}/merge.js +0 -1
- package/dist/{esm/config → config}/usage.d.ts +0 -1
- package/dist/{esm/config → config}/usage.js +0 -1
- package/dist/{esm/custom-help.d.ts → custom-help.d.ts} +0 -1
- package/dist/{esm/custom-help.js → custom-help.js} +35 -9
- package/dist/{esm/exec-command.d.ts → exec-command.d.ts} +0 -1
- package/dist/{esm/exec-command.js → exec-command.js} +14 -8
- package/dist/{esm/index.d.ts → index.d.ts} +0 -1
- package/dist/{esm/index.js → index.js} +1 -2
- package/dist/{esm/load-command.d.ts → load-command.d.ts} +0 -1
- package/dist/{esm/load-command.js → load-command.js} +0 -1
- package/dist/mermaid-image-view.d.ts +18 -0
- package/dist/mermaid-image-view.js +36 -0
- package/dist/{esm/output.d.ts → output.d.ts} +2 -2
- package/dist/{esm/output.js → output.js} +55 -2
- package/dist/{esm/pack-tarball.d.ts → pack-tarball.d.ts} +15 -1
- package/dist/{esm/pack-tarball.js → pack-tarball.js} +133 -91
- package/dist/{esm/parse-add-remove-args.d.ts → parse-add-remove-args.d.ts} +9 -3
- package/dist/{esm/parse-add-remove-args.js → parse-add-remove-args.js} +43 -11
- package/dist/{esm/print-err.d.ts → print-err.d.ts} +0 -1
- package/dist/{esm/print-err.js → print-err.js} +18 -3
- package/dist/query-diff-files.d.ts +17 -0
- package/dist/query-diff-files.js +63 -0
- package/dist/{esm/query-host-contexts.d.ts → query-host-contexts.d.ts} +0 -1
- package/dist/{esm/query-host-contexts.js → query-host-contexts.js} +8 -7
- package/dist/{esm/read-password.d.ts → read-password.d.ts} +0 -1
- package/dist/{esm/read-password.js → read-password.js} +0 -1
- package/dist/read-project-folders.d.ts +17 -0
- package/dist/read-project-folders.js +100 -0
- package/dist/reload-config.d.ts +2 -0
- package/dist/reload-config.js +11 -0
- package/dist/render-mermaid.d.ts +22 -0
- package/dist/render-mermaid.js +68 -0
- package/dist/telemetry.d.ts +58 -0
- package/dist/telemetry.js +170 -0
- package/dist/{esm/view.d.ts → view.d.ts} +0 -1
- package/dist/{esm/view.js → view.js} +1 -2
- package/package.json +69 -83
- package/dist/esm/commands/build.d.ts.map +0 -1
- package/dist/esm/commands/build.js.map +0 -1
- package/dist/esm/commands/cache.d.ts.map +0 -1
- package/dist/esm/commands/cache.js.map +0 -1
- package/dist/esm/commands/ci.d.ts.map +0 -1
- package/dist/esm/commands/ci.js.map +0 -1
- package/dist/esm/commands/config.d.ts.map +0 -1
- package/dist/esm/commands/config.js.map +0 -1
- package/dist/esm/commands/docs.d.ts.map +0 -1
- package/dist/esm/commands/docs.js.map +0 -1
- package/dist/esm/commands/exec-cache.d.ts.map +0 -1
- package/dist/esm/commands/exec-cache.js.map +0 -1
- package/dist/esm/commands/exec-local.d.ts.map +0 -1
- package/dist/esm/commands/exec-local.js.map +0 -1
- package/dist/esm/commands/exec.d.ts.map +0 -1
- package/dist/esm/commands/exec.js.map +0 -1
- package/dist/esm/commands/help.d.ts.map +0 -1
- package/dist/esm/commands/help.js.map +0 -1
- package/dist/esm/commands/init.d.ts.map +0 -1
- package/dist/esm/commands/init.js.map +0 -1
- package/dist/esm/commands/install/reporter.d.ts.map +0 -1
- package/dist/esm/commands/install/reporter.js.map +0 -1
- package/dist/esm/commands/install.d.ts.map +0 -1
- package/dist/esm/commands/install.js +0 -45
- package/dist/esm/commands/install.js.map +0 -1
- package/dist/esm/commands/list.d.ts.map +0 -1
- package/dist/esm/commands/list.js.map +0 -1
- package/dist/esm/commands/login.d.ts.map +0 -1
- package/dist/esm/commands/login.js.map +0 -1
- package/dist/esm/commands/logout.d.ts +0 -4
- package/dist/esm/commands/logout.d.ts.map +0 -1
- package/dist/esm/commands/logout.js.map +0 -1
- package/dist/esm/commands/pack.d.ts.map +0 -1
- package/dist/esm/commands/pack.js.map +0 -1
- package/dist/esm/commands/pkg.d.ts.map +0 -1
- package/dist/esm/commands/pkg.js.map +0 -1
- package/dist/esm/commands/publish.d.ts.map +0 -1
- package/dist/esm/commands/publish.js.map +0 -1
- package/dist/esm/commands/query.d.ts.map +0 -1
- package/dist/esm/commands/query.js.map +0 -1
- package/dist/esm/commands/run-exec.d.ts.map +0 -1
- package/dist/esm/commands/run-exec.js +0 -14
- package/dist/esm/commands/run-exec.js.map +0 -1
- package/dist/esm/commands/run.d.ts.map +0 -1
- package/dist/esm/commands/run.js.map +0 -1
- package/dist/esm/commands/serve.d.ts +0 -14
- package/dist/esm/commands/serve.d.ts.map +0 -1
- package/dist/esm/commands/serve.js +0 -103
- package/dist/esm/commands/serve.js.map +0 -1
- package/dist/esm/commands/token.d.ts.map +0 -1
- package/dist/esm/commands/token.js +0 -30
- package/dist/esm/commands/token.js.map +0 -1
- package/dist/esm/commands/uninstall.d.ts.map +0 -1
- package/dist/esm/commands/uninstall.js.map +0 -1
- package/dist/esm/commands/update.d.ts.map +0 -1
- package/dist/esm/commands/update.js.map +0 -1
- package/dist/esm/commands/version.d.ts.map +0 -1
- package/dist/esm/commands/version.js.map +0 -1
- package/dist/esm/commands/whoami.d.ts.map +0 -1
- package/dist/esm/commands/whoami.js.map +0 -1
- package/dist/esm/config/definition.d.ts.map +0 -1
- package/dist/esm/config/definition.js.map +0 -1
- package/dist/esm/config/index.d.ts.map +0 -1
- package/dist/esm/config/index.js.map +0 -1
- package/dist/esm/config/merge.d.ts.map +0 -1
- package/dist/esm/config/merge.js.map +0 -1
- package/dist/esm/config/usage.d.ts.map +0 -1
- package/dist/esm/config/usage.js.map +0 -1
- package/dist/esm/custom-help.d.ts.map +0 -1
- package/dist/esm/custom-help.js.map +0 -1
- package/dist/esm/exec-command.d.ts.map +0 -1
- package/dist/esm/exec-command.js.map +0 -1
- package/dist/esm/index.d.ts.map +0 -1
- package/dist/esm/index.js.map +0 -1
- package/dist/esm/load-command.d.ts.map +0 -1
- package/dist/esm/load-command.js.map +0 -1
- package/dist/esm/output.d.ts.map +0 -1
- package/dist/esm/output.js.map +0 -1
- package/dist/esm/pack-tarball.d.ts.map +0 -1
- package/dist/esm/pack-tarball.js.map +0 -1
- package/dist/esm/package.json +0 -3
- package/dist/esm/parse-add-remove-args.d.ts.map +0 -1
- package/dist/esm/parse-add-remove-args.js.map +0 -1
- package/dist/esm/print-err.d.ts.map +0 -1
- package/dist/esm/print-err.js.map +0 -1
- package/dist/esm/query-host-contexts.d.ts.map +0 -1
- package/dist/esm/query-host-contexts.js.map +0 -1
- package/dist/esm/read-password.d.ts.map +0 -1
- package/dist/esm/read-password.js.map +0 -1
- package/dist/esm/start-gui.d.ts +0 -10
- package/dist/esm/start-gui.d.ts.map +0 -1
- package/dist/esm/start-gui.js +0 -60
- package/dist/esm/start-gui.js.map +0 -1
- package/dist/esm/view.d.ts.map +0 -1
- package/dist/esm/view.js.map +0 -1
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { CommandFn, CommandUsage } from '../index.ts';
|
|
2
|
+
export declare const usage: CommandUsage;
|
|
3
|
+
export type AccessResult = {
|
|
4
|
+
package: string;
|
|
5
|
+
access: string;
|
|
6
|
+
} | {
|
|
7
|
+
packages: Record<string, string>;
|
|
8
|
+
} | {
|
|
9
|
+
granted: {
|
|
10
|
+
team: string;
|
|
11
|
+
permissions: string;
|
|
12
|
+
};
|
|
13
|
+
} | {
|
|
14
|
+
revoked: {
|
|
15
|
+
team: string;
|
|
16
|
+
};
|
|
17
|
+
};
|
|
18
|
+
export declare const views: {
|
|
19
|
+
readonly human: (result: AccessResult) => string;
|
|
20
|
+
readonly json: (r: AccessResult) => AccessResult;
|
|
21
|
+
};
|
|
22
|
+
export declare const command: CommandFn<AccessResult>;
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
import { error } from '@vltpkg/error-cause';
|
|
2
|
+
import { RegistryClient } from '@vltpkg/registry-client';
|
|
3
|
+
import { commandUsage } from "../config/usage.js";
|
|
4
|
+
export const usage = () => commandUsage({
|
|
5
|
+
command: 'access',
|
|
6
|
+
usage: '<command> [<args>]',
|
|
7
|
+
description: `Set or get access levels for published packages
|
|
8
|
+
and manage team-based package permissions.`,
|
|
9
|
+
subcommands: {
|
|
10
|
+
'list packages': {
|
|
11
|
+
usage: '[<scope|user|org>]',
|
|
12
|
+
description: 'List packages with access info for a scope, user, or org.',
|
|
13
|
+
},
|
|
14
|
+
'get status': {
|
|
15
|
+
usage: '<package>',
|
|
16
|
+
description: 'Get the access/visibility status of a package.',
|
|
17
|
+
},
|
|
18
|
+
'set status': {
|
|
19
|
+
usage: '<package>',
|
|
20
|
+
description: `Set the access/visibility of a package. Use --access to specify the level.`,
|
|
21
|
+
},
|
|
22
|
+
grant: {
|
|
23
|
+
usage: '<read-only|read-write> <scope:team> [<package>]',
|
|
24
|
+
description: 'Grant access to a scope:team for a package.',
|
|
25
|
+
},
|
|
26
|
+
revoke: {
|
|
27
|
+
usage: '<scope:team> [<package>]',
|
|
28
|
+
description: 'Revoke access from a scope:team for a package.',
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
options: {
|
|
32
|
+
registry: {
|
|
33
|
+
value: '<url>',
|
|
34
|
+
description: 'Registry URL to manage access on.',
|
|
35
|
+
},
|
|
36
|
+
otp: {
|
|
37
|
+
description: 'Provide an OTP for access changes.',
|
|
38
|
+
value: '<otp>',
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
});
|
|
42
|
+
export const views = {
|
|
43
|
+
human: (result) => {
|
|
44
|
+
if ('packages' in result) {
|
|
45
|
+
const entries = Object.entries(result.packages);
|
|
46
|
+
if (entries.length === 0)
|
|
47
|
+
return 'No packages found.';
|
|
48
|
+
return entries
|
|
49
|
+
.map(([name, access]) => `${name}: ${access}`)
|
|
50
|
+
.join('\n');
|
|
51
|
+
}
|
|
52
|
+
if ('granted' in result) {
|
|
53
|
+
return `Granted ${result.granted.permissions} access to ${result.granted.team}.`;
|
|
54
|
+
}
|
|
55
|
+
if ('revoked' in result) {
|
|
56
|
+
return `Revoked access from ${result.revoked.team}.`;
|
|
57
|
+
}
|
|
58
|
+
return `${result.package}: ${result.access}`;
|
|
59
|
+
},
|
|
60
|
+
json: (r) => r,
|
|
61
|
+
};
|
|
62
|
+
export const command = async (conf) => {
|
|
63
|
+
const [sub, ...args] = conf.positionals;
|
|
64
|
+
switch (sub) {
|
|
65
|
+
case 'list':
|
|
66
|
+
return listPackages(conf, args);
|
|
67
|
+
case 'get':
|
|
68
|
+
return getStatus(conf, args);
|
|
69
|
+
case 'set':
|
|
70
|
+
return setStatus(conf, args);
|
|
71
|
+
case 'grant':
|
|
72
|
+
return grant(conf, args);
|
|
73
|
+
case 'revoke':
|
|
74
|
+
return revoke(conf, args);
|
|
75
|
+
default: {
|
|
76
|
+
throw error('Invalid access subcommand', {
|
|
77
|
+
found: sub,
|
|
78
|
+
validOptions: ['list', 'get', 'set', 'grant', 'revoke'],
|
|
79
|
+
code: 'EUSAGE',
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
const encodePkgName = (name) => name.startsWith('@') ?
|
|
85
|
+
`@${encodeURIComponent(name.slice(1))}`
|
|
86
|
+
: encodeURIComponent(name);
|
|
87
|
+
const listPackages = async (conf, args) => {
|
|
88
|
+
const [keyword, entity] = args;
|
|
89
|
+
if (keyword !== 'packages') {
|
|
90
|
+
throw error('Expected `list packages [<scope|user|org>]`', {
|
|
91
|
+
found: keyword,
|
|
92
|
+
code: 'EUSAGE',
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
const rc = new RegistryClient(conf.options);
|
|
96
|
+
const registryUrl = new URL(conf.options.registry);
|
|
97
|
+
// Determine who to list for — use entity arg or fall back to scope from package.json
|
|
98
|
+
const scope = entity ?? getDefaultScope(conf);
|
|
99
|
+
const url = new URL(`-/org/${encodeURIComponent(scope)}/package`, registryUrl);
|
|
100
|
+
const response = await rc.request(url, { useCache: false });
|
|
101
|
+
const data = response.json();
|
|
102
|
+
return { packages: data };
|
|
103
|
+
};
|
|
104
|
+
const getStatus = async (conf, args) => {
|
|
105
|
+
const [keyword, pkg] = args;
|
|
106
|
+
if (keyword !== 'status') {
|
|
107
|
+
throw error('Expected `get status <package>`', {
|
|
108
|
+
found: keyword,
|
|
109
|
+
code: 'EUSAGE',
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
if (!pkg) {
|
|
113
|
+
throw error('Package name is required for `get status`', {
|
|
114
|
+
code: 'EUSAGE',
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
const rc = new RegistryClient(conf.options);
|
|
118
|
+
const registryUrl = new URL(conf.options.registry);
|
|
119
|
+
const url = new URL(`-/package/${encodePkgName(pkg)}/access`, registryUrl);
|
|
120
|
+
const response = await rc.request(url, { useCache: false });
|
|
121
|
+
const data = response.json();
|
|
122
|
+
return { package: pkg, access: data.access };
|
|
123
|
+
};
|
|
124
|
+
const setStatus = async (conf, args) => {
|
|
125
|
+
// vlt access set status=<public|restricted> <package>
|
|
126
|
+
const [statusArg, pkg] = args;
|
|
127
|
+
if (!statusArg?.startsWith('status=')) {
|
|
128
|
+
throw error('Expected `set status=<public|restricted> <package>`', { found: statusArg, code: 'EUSAGE' });
|
|
129
|
+
}
|
|
130
|
+
const accessLevel = statusArg.slice('status='.length);
|
|
131
|
+
if (accessLevel !== 'public' && accessLevel !== 'restricted') {
|
|
132
|
+
throw error('Access level must be `public` or `restricted`', {
|
|
133
|
+
found: accessLevel,
|
|
134
|
+
validOptions: ['public', 'restricted'],
|
|
135
|
+
code: 'EUSAGE',
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
if (!pkg) {
|
|
139
|
+
throw error('Package name is required for `set status`', {
|
|
140
|
+
code: 'EUSAGE',
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
const rc = new RegistryClient(conf.options);
|
|
144
|
+
const registryUrl = new URL(conf.options.registry);
|
|
145
|
+
const url = new URL(`-/package/${encodePkgName(pkg)}/access`, registryUrl);
|
|
146
|
+
await rc.request(url, {
|
|
147
|
+
method: 'PUT',
|
|
148
|
+
headers: { 'content-type': 'application/json' },
|
|
149
|
+
body: JSON.stringify({ access: accessLevel }),
|
|
150
|
+
otp: conf.options.otp,
|
|
151
|
+
useCache: false,
|
|
152
|
+
});
|
|
153
|
+
return { package: pkg, access: accessLevel };
|
|
154
|
+
};
|
|
155
|
+
const grant = async (conf, args) => {
|
|
156
|
+
// vlt access grant <read-only|read-write> <scope:team> [<package>]
|
|
157
|
+
const [permissions, scopeTeam, pkg] = args;
|
|
158
|
+
if (permissions !== 'read-only' && permissions !== 'read-write') {
|
|
159
|
+
throw error('Permissions must be `read-only` or `read-write`', {
|
|
160
|
+
found: permissions,
|
|
161
|
+
validOptions: ['read-only', 'read-write'],
|
|
162
|
+
code: 'EUSAGE',
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
if (!scopeTeam?.includes(':')) {
|
|
166
|
+
throw error('Team must be in the format `<scope>:<team>`', {
|
|
167
|
+
found: scopeTeam,
|
|
168
|
+
code: 'EUSAGE',
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
const [scope, team] = scopeTeam.split(':');
|
|
172
|
+
if (!scope || !team) {
|
|
173
|
+
throw error('Team must be in the format `<scope>:<team>`', {
|
|
174
|
+
found: scopeTeam,
|
|
175
|
+
code: 'EUSAGE',
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
const pkgName = pkg ?? getDefaultPkgName(conf);
|
|
179
|
+
const rc = new RegistryClient(conf.options);
|
|
180
|
+
const registryUrl = new URL(conf.options.registry);
|
|
181
|
+
const url = new URL(`-/team/${encodeURIComponent(scope)}/${encodeURIComponent(team)}/package`, registryUrl);
|
|
182
|
+
await rc.request(url, {
|
|
183
|
+
method: 'PUT',
|
|
184
|
+
headers: { 'content-type': 'application/json' },
|
|
185
|
+
body: JSON.stringify({
|
|
186
|
+
package: pkgName,
|
|
187
|
+
permissions,
|
|
188
|
+
}),
|
|
189
|
+
otp: conf.options.otp,
|
|
190
|
+
useCache: false,
|
|
191
|
+
});
|
|
192
|
+
return {
|
|
193
|
+
granted: {
|
|
194
|
+
team: `${scope}:${team}`,
|
|
195
|
+
permissions,
|
|
196
|
+
},
|
|
197
|
+
};
|
|
198
|
+
};
|
|
199
|
+
const revoke = async (conf, args) => {
|
|
200
|
+
// vlt access revoke <scope:team> [<package>]
|
|
201
|
+
const [scopeTeam, pkg] = args;
|
|
202
|
+
if (!scopeTeam?.includes(':')) {
|
|
203
|
+
throw error('Team must be in the format `<scope>:<team>`', {
|
|
204
|
+
found: scopeTeam,
|
|
205
|
+
code: 'EUSAGE',
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
const [scope, team] = scopeTeam.split(':');
|
|
209
|
+
if (!scope || !team) {
|
|
210
|
+
throw error('Team must be in the format `<scope>:<team>`', {
|
|
211
|
+
found: scopeTeam,
|
|
212
|
+
code: 'EUSAGE',
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
const pkgName = pkg ?? getDefaultPkgName(conf);
|
|
216
|
+
const rc = new RegistryClient(conf.options);
|
|
217
|
+
const registryUrl = new URL(conf.options.registry);
|
|
218
|
+
const url = new URL(`-/team/${encodeURIComponent(scope)}/${encodeURIComponent(team)}/package`, registryUrl);
|
|
219
|
+
await rc.request(url, {
|
|
220
|
+
method: 'DELETE',
|
|
221
|
+
headers: { 'content-type': 'application/json' },
|
|
222
|
+
body: JSON.stringify({ package: pkgName }),
|
|
223
|
+
otp: conf.options.otp,
|
|
224
|
+
useCache: false,
|
|
225
|
+
});
|
|
226
|
+
return {
|
|
227
|
+
revoked: {
|
|
228
|
+
team: `${scope}:${team}`,
|
|
229
|
+
},
|
|
230
|
+
};
|
|
231
|
+
};
|
|
232
|
+
const getDefaultScope = (conf) => {
|
|
233
|
+
const name = conf.options.packageJson.maybeRead(conf.projectRoot)?.name;
|
|
234
|
+
if (name?.startsWith('@')) {
|
|
235
|
+
const scope = name.split('/')[0];
|
|
236
|
+
if (scope)
|
|
237
|
+
return scope;
|
|
238
|
+
}
|
|
239
|
+
throw error('Could not determine scope. Provide a scope, user, or org.', { code: 'EUSAGE' });
|
|
240
|
+
};
|
|
241
|
+
const getDefaultPkgName = (conf) => {
|
|
242
|
+
const name = conf.options.packageJson.maybeRead(conf.projectRoot)?.name;
|
|
243
|
+
if (name)
|
|
244
|
+
return name;
|
|
245
|
+
throw error('Could not determine package name. Provide a package name or run from a package directory.', { code: 'EUSAGE' });
|
|
246
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { CommandFn, CommandUsage } from '../index.ts';
|
|
2
|
+
export declare const usage: CommandUsage;
|
|
3
|
+
type CommandResultSingle = {
|
|
4
|
+
url: string;
|
|
5
|
+
name: string;
|
|
6
|
+
};
|
|
7
|
+
type CommandResultMultiple = {
|
|
8
|
+
url: string;
|
|
9
|
+
name: string;
|
|
10
|
+
}[];
|
|
11
|
+
export type CommandResult = CommandResultSingle | CommandResultMultiple;
|
|
12
|
+
export declare const views: {
|
|
13
|
+
readonly human: (r: CommandResult) => string;
|
|
14
|
+
readonly json: (r: CommandResult) => CommandResult;
|
|
15
|
+
};
|
|
16
|
+
export declare const command: CommandFn<CommandResult>;
|
|
17
|
+
export {};
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import { error } from '@vltpkg/error-cause';
|
|
2
|
+
import { PackageInfoClient } from '@vltpkg/package-info';
|
|
3
|
+
import { Spec } from '@vltpkg/spec';
|
|
4
|
+
import { urlOpen } from '@vltpkg/url-open';
|
|
5
|
+
import { actual } from '@vltpkg/graph';
|
|
6
|
+
import { Query } from '@vltpkg/query';
|
|
7
|
+
import { SecurityArchive } from '@vltpkg/security-archive';
|
|
8
|
+
import { createHostContextsMap } from "../query-host-contexts.js";
|
|
9
|
+
import { commandUsage } from "../config/usage.js";
|
|
10
|
+
import hostedGitInfo from 'hosted-git-info';
|
|
11
|
+
const { fromUrl: hostedGitInfoFromUrl } = hostedGitInfo;
|
|
12
|
+
export const usage = () => commandUsage({
|
|
13
|
+
command: 'bugs',
|
|
14
|
+
usage: ['[<spec>]', '[--target=<query>]'],
|
|
15
|
+
description: `Open bug tracker for a package in a web browser.
|
|
16
|
+
Reads bug tracker information from package.json or fetches
|
|
17
|
+
manifest data for the specified package.`,
|
|
18
|
+
options: {
|
|
19
|
+
target: {
|
|
20
|
+
value: '<query>',
|
|
21
|
+
description: 'Query selector to filter packages using DSS syntax.',
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
examples: {
|
|
25
|
+
'': {
|
|
26
|
+
description: 'Open bugs for the current package (reads local package.json)',
|
|
27
|
+
},
|
|
28
|
+
'abbrev@2.0.0': {
|
|
29
|
+
description: 'Open bugs for a specific package version',
|
|
30
|
+
},
|
|
31
|
+
'--target=":root > *"': {
|
|
32
|
+
description: 'List bug tracker URLs for all direct dependencies',
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
});
|
|
36
|
+
export const views = {
|
|
37
|
+
human: r => {
|
|
38
|
+
if (Array.isArray(r)) {
|
|
39
|
+
let msg = 'Multiple package bug trackers found:\n';
|
|
40
|
+
msg += r.map(item => `• ${item.name}: ${item.url}`).join('\n');
|
|
41
|
+
return msg;
|
|
42
|
+
}
|
|
43
|
+
return '';
|
|
44
|
+
},
|
|
45
|
+
json: r => r,
|
|
46
|
+
};
|
|
47
|
+
const getUrlFromManifest = (manifest) => {
|
|
48
|
+
const { name, bugs, repository } = manifest;
|
|
49
|
+
if (!name) {
|
|
50
|
+
throw error('No package name found');
|
|
51
|
+
}
|
|
52
|
+
let url;
|
|
53
|
+
// Check bugs field first
|
|
54
|
+
if (bugs) {
|
|
55
|
+
if (typeof bugs === 'string') {
|
|
56
|
+
url = bugs;
|
|
57
|
+
}
|
|
58
|
+
else if (typeof bugs === 'object') {
|
|
59
|
+
if ('url' in bugs && bugs.url) {
|
|
60
|
+
url = bugs.url;
|
|
61
|
+
}
|
|
62
|
+
else if ('email' in bugs && bugs.email) {
|
|
63
|
+
url = `mailto:${bugs.email}`;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
// Try repository if no bugs field
|
|
68
|
+
if (!url && repository) {
|
|
69
|
+
const repoUrl = typeof repository === 'string' ? repository
|
|
70
|
+
: typeof repository === 'object' && 'url' in repository ?
|
|
71
|
+
repository.url
|
|
72
|
+
: /* c8 ignore next */ undefined;
|
|
73
|
+
if (repoUrl) {
|
|
74
|
+
const info = hostedGitInfoFromUrl(repoUrl.replace(/^git\+/, ''));
|
|
75
|
+
if (info?.bugs && typeof info.bugs === 'function') {
|
|
76
|
+
url = info.bugs();
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
// Fallback to vlt.io package page
|
|
81
|
+
if (!url) {
|
|
82
|
+
url = `https://vlt.io/explore/npm/${name}/overview`;
|
|
83
|
+
}
|
|
84
|
+
return url;
|
|
85
|
+
};
|
|
86
|
+
export const command = async (conf) => {
|
|
87
|
+
const { projectRoot, packageJson } = conf.options;
|
|
88
|
+
const targetOption = conf.get('target');
|
|
89
|
+
// Handle --target query
|
|
90
|
+
if (targetOption) {
|
|
91
|
+
const mainManifest = packageJson.maybeRead(projectRoot);
|
|
92
|
+
if (!mainManifest) {
|
|
93
|
+
throw error('No package.json found in project root', {
|
|
94
|
+
path: projectRoot,
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
const graph = actual.load({
|
|
98
|
+
...conf.options,
|
|
99
|
+
mainManifest,
|
|
100
|
+
monorepo: conf.options.monorepo,
|
|
101
|
+
loadManifests: true,
|
|
102
|
+
});
|
|
103
|
+
const securityArchive = Query.hasSecuritySelectors(targetOption) ?
|
|
104
|
+
await SecurityArchive.start({
|
|
105
|
+
nodes: [...graph.nodes.values()],
|
|
106
|
+
})
|
|
107
|
+
: undefined;
|
|
108
|
+
const hostContexts = await createHostContextsMap(conf);
|
|
109
|
+
const query = new Query({
|
|
110
|
+
nodes: new Set(graph.nodes.values()),
|
|
111
|
+
edges: graph.edges,
|
|
112
|
+
importers: graph.importers,
|
|
113
|
+
securityArchive,
|
|
114
|
+
hostContexts,
|
|
115
|
+
});
|
|
116
|
+
const { nodes } = await query.search(targetOption, {
|
|
117
|
+
signal: new AbortController().signal,
|
|
118
|
+
});
|
|
119
|
+
const results = [];
|
|
120
|
+
for (const node of nodes) {
|
|
121
|
+
if (!node.manifest)
|
|
122
|
+
continue;
|
|
123
|
+
const url = getUrlFromManifest(node.manifest);
|
|
124
|
+
results.push({
|
|
125
|
+
url,
|
|
126
|
+
name: node.name /* c8 ignore next */ ?? '(unknown)',
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
if (results.length === 0) {
|
|
130
|
+
throw error('No packages found matching target query', {
|
|
131
|
+
found: targetOption,
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
// If single result, open it
|
|
135
|
+
if (results.length === 1) {
|
|
136
|
+
const result = results[0];
|
|
137
|
+
/* c8 ignore next 3 */
|
|
138
|
+
if (!result) {
|
|
139
|
+
throw error('Unexpected empty result');
|
|
140
|
+
}
|
|
141
|
+
await urlOpen(result.url);
|
|
142
|
+
return result;
|
|
143
|
+
}
|
|
144
|
+
// Multiple results, return the list
|
|
145
|
+
return results;
|
|
146
|
+
}
|
|
147
|
+
// read the package spec from a positional argument or local package.json
|
|
148
|
+
const specArg = conf.positionals[0];
|
|
149
|
+
const manifest = conf.positionals.length === 0 ? packageJson.read(projectRoot)
|
|
150
|
+
: specArg ?
|
|
151
|
+
await new PackageInfoClient(conf.options).manifest(Spec.parseArgs(specArg, conf.options))
|
|
152
|
+
: /* c8 ignore next */ packageJson.read(projectRoot);
|
|
153
|
+
const url = getUrlFromManifest(manifest);
|
|
154
|
+
const { name } = manifest;
|
|
155
|
+
/* c8 ignore start - getUrlFromManifest already validates name */
|
|
156
|
+
if (!name) {
|
|
157
|
+
throw error('No package name found');
|
|
158
|
+
}
|
|
159
|
+
/* c8 ignore stop */
|
|
160
|
+
// Open the URL
|
|
161
|
+
await urlOpen(url);
|
|
162
|
+
return { url, name };
|
|
163
|
+
};
|
|
@@ -11,6 +11,15 @@ export const usage = () => commandUsage({
|
|
|
11
11
|
examples: {
|
|
12
12
|
'': { description: 'Clean install from lockfile' },
|
|
13
13
|
},
|
|
14
|
+
options: {
|
|
15
|
+
'allow-scripts': {
|
|
16
|
+
value: '<query>',
|
|
17
|
+
description: 'Filter which packages are allowed to run lifecycle scripts using DSS query syntax.',
|
|
18
|
+
},
|
|
19
|
+
'lockfile-only': {
|
|
20
|
+
description: 'Only update lockfile and package.json files; skip node_modules operations.',
|
|
21
|
+
},
|
|
22
|
+
},
|
|
14
23
|
});
|
|
15
24
|
export const views = {
|
|
16
25
|
json: i => i.graph.toJSON(),
|
|
@@ -19,8 +28,8 @@ export const views = {
|
|
|
19
28
|
export const command = async (conf) => {
|
|
20
29
|
const ciOptions = {
|
|
21
30
|
...conf.options,
|
|
22
|
-
// allow
|
|
23
|
-
allowScripts: conf.get('allow-scripts') ?? '
|
|
31
|
+
// allow scripts but filter out malware via security archive
|
|
32
|
+
allowScripts: conf.get('allow-scripts') ?? ':scripts:not(:malware)',
|
|
24
33
|
expectLockfile: true,
|
|
25
34
|
frozenLockfile: true,
|
|
26
35
|
cleanInstall: true,
|
|
@@ -29,4 +38,3 @@ export const command = async (conf) => {
|
|
|
29
38
|
const { graph } = await install(ciOptions);
|
|
30
39
|
return { graph };
|
|
31
40
|
};
|
|
32
|
-
//# sourceMappingURL=ci.js.map
|
|
@@ -18,6 +18,12 @@ export const usage = () => commandUsage({
|
|
|
18
18
|
command: 'config',
|
|
19
19
|
usage: '[<command>] [<args>]',
|
|
20
20
|
description: 'Get or manipulate vlt configuration values',
|
|
21
|
+
options: {
|
|
22
|
+
config: {
|
|
23
|
+
value: '<all | user | project>',
|
|
24
|
+
description: 'Specify which configuration to show or operate on.',
|
|
25
|
+
},
|
|
26
|
+
},
|
|
21
27
|
subcommands: {
|
|
22
28
|
get: {
|
|
23
29
|
usage: '[<key>] [--config=<all | user | project>]',
|
|
@@ -421,4 +427,3 @@ const configLocation = (conf) => {
|
|
|
421
427
|
const configPath = find(effectiveConfig);
|
|
422
428
|
return configPath;
|
|
423
429
|
};
|
|
424
|
-
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { PromptFn } from '@vltpkg/vlx';
|
|
2
|
+
import type { ExecResult } from '../exec-command.ts';
|
|
3
|
+
import type { CommandFn, CommandUsage } from '../index.ts';
|
|
4
|
+
export { views } from '../exec-command.ts';
|
|
5
|
+
export declare const usage: CommandUsage;
|
|
6
|
+
export declare const prettyPath: (path: string) => string;
|
|
7
|
+
export declare const promptFn: PromptFn;
|
|
8
|
+
export declare const command: CommandFn<ExecResult>;
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { exec, execFG } from '@vltpkg/run';
|
|
2
|
+
import * as vlx from '@vltpkg/vlx';
|
|
3
|
+
import { homedir } from 'node:os';
|
|
4
|
+
import { createInterface } from 'node:readline/promises';
|
|
5
|
+
import { commandUsage } from "../config/usage.js";
|
|
6
|
+
import { ExecCommand } from "../exec-command.js";
|
|
7
|
+
import { styleTextStdout } from "../output.js";
|
|
8
|
+
export { views } from "../exec-command.js";
|
|
9
|
+
export const usage = () => commandUsage({
|
|
10
|
+
command: 'create',
|
|
11
|
+
usage: '<initializer> [args...]',
|
|
12
|
+
description: `Initialize a new project from a template package.
|
|
13
|
+
|
|
14
|
+
Works like \`npm create\` and \`bun create\`, automatically
|
|
15
|
+
prepending "create-" to the package name and executing it.
|
|
16
|
+
|
|
17
|
+
For example, \`vlt create react-app my-app\` will fetch and
|
|
18
|
+
execute the \`create-react-app\` package with the arguments
|
|
19
|
+
\`my-app\`.
|
|
20
|
+
|
|
21
|
+
If a satisfying instance of the create package exists in the
|
|
22
|
+
local \`node_modules\` folder, then that will be used.
|
|
23
|
+
|
|
24
|
+
At no point will \`vlt create\` change the locally installed
|
|
25
|
+
dependencies. Any installs it performs is done in vlt's XDG
|
|
26
|
+
data directory.
|
|
27
|
+
`,
|
|
28
|
+
examples: {
|
|
29
|
+
'react-app my-app': {
|
|
30
|
+
description: 'Create a new React app using create-react-app',
|
|
31
|
+
},
|
|
32
|
+
'vite my-project': {
|
|
33
|
+
description: 'Create a new Vite project using create-vite',
|
|
34
|
+
},
|
|
35
|
+
'@scope/template my-app': {
|
|
36
|
+
description: 'Create a new project using @scope/create-template',
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
options: {
|
|
40
|
+
'allow-scripts': {
|
|
41
|
+
value: '<query>',
|
|
42
|
+
description: 'Filter which packages are allowed to run lifecycle scripts using DSS query syntax.',
|
|
43
|
+
},
|
|
44
|
+
yes: {
|
|
45
|
+
description: 'Skip interactive prompts and accept defaults.',
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
});
|
|
49
|
+
const HOME = homedir();
|
|
50
|
+
export const prettyPath = (path) => path.startsWith(HOME) ? `~${path.substring(HOME.length)}` : path;
|
|
51
|
+
export const promptFn = async (pkgSpec, path, resolution) => {
|
|
52
|
+
const response = await createInterface(process.stdin, process.stdout).question(`About to install: ${styleTextStdout(['bgWhiteBright', 'black', 'bold'], String(pkgSpec))}
|
|
53
|
+
from: ${styleTextStdout(['bgWhiteBright', 'black', 'bold'], resolution)}
|
|
54
|
+
into: ${styleTextStdout(['bgWhiteBright', 'black', 'bold'], prettyPath(path))}
|
|
55
|
+
Is this ok? (y) `);
|
|
56
|
+
process.stdin.pause();
|
|
57
|
+
return response;
|
|
58
|
+
};
|
|
59
|
+
export const command = async (conf) => {
|
|
60
|
+
const [initializer, ...args] = conf.positionals;
|
|
61
|
+
if (!initializer) {
|
|
62
|
+
throw new Error('Missing required argument: <initializer>\n\nUsage: vlt create <initializer> [args...]');
|
|
63
|
+
}
|
|
64
|
+
// Transform the initializer to a create-* package name
|
|
65
|
+
// e.g., "react-app" -> "create-react-app"
|
|
66
|
+
// or "@scope/template" -> "@scope/create-template"
|
|
67
|
+
let packageName;
|
|
68
|
+
if (initializer.startsWith('@')) {
|
|
69
|
+
// Handle scoped packages: @scope/name -> @scope/create-name
|
|
70
|
+
const [scope, name] = initializer.split('/');
|
|
71
|
+
packageName = name ? `${scope}/create-${name}` : `${scope}/create`;
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
// Handle regular packages: name -> create-name
|
|
75
|
+
packageName = `create-${initializer}`;
|
|
76
|
+
}
|
|
77
|
+
/* c8 ignore start */
|
|
78
|
+
const allowScripts = conf.get('allow-scripts') ?
|
|
79
|
+
String(conf.get('allow-scripts'))
|
|
80
|
+
: ':not(*)';
|
|
81
|
+
/* c8 ignore stop */
|
|
82
|
+
const yesFlag = conf.get('yes');
|
|
83
|
+
// Resolve the create-* package using vlx. We pass the package name as
|
|
84
|
+
// a synthetic positional so vlx treats it as the command to resolve —
|
|
85
|
+
// NOT the user's args (like "app"). Without this, vlx would mistake
|
|
86
|
+
// the first user arg as the executable to spawn.
|
|
87
|
+
const arg0 = await vlx.resolve([packageName], {
|
|
88
|
+
...conf.options,
|
|
89
|
+
query: undefined,
|
|
90
|
+
allowScripts,
|
|
91
|
+
}, yesFlag ? async () => 'y' : promptFn);
|
|
92
|
+
// Set positionals to the resolved executable and the user's args
|
|
93
|
+
if (arg0) {
|
|
94
|
+
conf.positionals = [arg0, ...args];
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
throw new Error(`Could not resolve executable for package "${packageName}"`);
|
|
98
|
+
}
|
|
99
|
+
// Execute the create package
|
|
100
|
+
delete conf.options['script-shell'];
|
|
101
|
+
return await new ExecCommand(conf, exec, execFG).run();
|
|
102
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { CommandFn, CommandUsage } from '../index.ts';
|
|
2
|
+
export declare const usage: CommandUsage;
|
|
3
|
+
export type CommandResult = {
|
|
4
|
+
name: string;
|
|
5
|
+
version: string;
|
|
6
|
+
message: string;
|
|
7
|
+
versions: string[];
|
|
8
|
+
};
|
|
9
|
+
export declare const views: {
|
|
10
|
+
readonly human: (result: CommandResult) => string;
|
|
11
|
+
readonly json: (r: CommandResult) => CommandResult;
|
|
12
|
+
};
|
|
13
|
+
export declare const command: CommandFn<CommandResult>;
|