@vigilbase/cli 0.2.0 → 0.2.2
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/CLOUDFLARE.md +9 -12
- package/COMMANDS.md +192 -111
- package/LOCAL.md +77 -84
- package/ONE.md +5 -6
- package/README.md +349 -173
- package/SECURITY.md +6 -4
- package/dist/auth/device-auth.d.ts +0 -1
- package/dist/auth/device-auth.js +6 -5
- package/dist/auth/index.d.ts +1 -2
- package/dist/auth/index.js +1 -2
- package/dist/auth/provider.d.ts +1 -1
- package/dist/auth/provider.js +16 -7
- package/dist/auth/refresh.d.ts +23 -4
- package/dist/auth/refresh.js +78 -22
- package/dist/auth/store.d.ts +78 -4
- package/dist/auth/store.js +385 -74
- package/dist/auth/token-metadata.d.ts +0 -1
- package/dist/auth/token-metadata.js +0 -1
- package/dist/auth/types.d.ts +0 -1
- package/dist/auth/types.js +0 -1
- package/dist/bin.d.ts +0 -1
- package/dist/bin.js +0 -1
- package/dist/cli.d.ts +4 -2
- package/dist/cli.js +13 -11
- package/dist/commands/account.d.ts +0 -1
- package/dist/commands/account.js +1 -2
- package/dist/commands/auth.d.ts +0 -1
- package/dist/commands/auth.js +71 -22
- package/dist/commands/billing.d.ts +0 -1
- package/dist/commands/billing.js +0 -1
- package/dist/commands/cloudflare.d.ts +1 -2
- package/dist/commands/cloudflare.js +14 -9
- package/dist/commands/helpers.d.ts +0 -1
- package/dist/commands/helpers.js +0 -1
- package/dist/commands/index.d.ts +0 -1
- package/dist/commands/index.js +0 -1
- package/dist/commands/legacy-validation.d.ts +7 -2
- package/dist/commands/legacy-validation.js +15 -3
- package/dist/commands/local.d.ts +6 -1
- package/dist/commands/local.js +36 -12
- package/dist/commands/one.d.ts +0 -1
- package/dist/commands/one.js +39 -13
- package/dist/commands/public-tools.d.ts +0 -1
- package/dist/commands/public-tools.js +63 -29
- package/dist/commands/runs.d.ts +0 -1
- package/dist/commands/runs.js +1 -2
- package/dist/commands/security.d.ts +1 -2
- package/dist/commands/security.js +34 -23
- package/dist/commands/watchdog.d.ts +0 -1
- package/dist/commands/watchdog.js +0 -1
- package/dist/index.d.ts +2 -3
- package/dist/index.js +1 -2
- package/dist/lib/banner.d.ts +0 -1
- package/dist/lib/banner.js +0 -1
- package/dist/lib/client.d.ts +9 -2
- package/dist/lib/client.js +49 -20
- package/dist/lib/cloudflare-client.d.ts +0 -1
- package/dist/lib/cloudflare-client.js +1 -2
- package/dist/lib/config.d.ts +16 -3
- package/dist/lib/config.js +41 -14
- package/dist/lib/format.d.ts +2 -1
- package/dist/lib/format.js +19 -8
- package/dist/lib/help.d.ts +4 -2
- package/dist/lib/help.js +72 -23
- package/dist/lib/network.d.ts +10 -1
- package/dist/lib/network.js +31 -4
- package/dist/lib/one-client.d.ts +4 -1
- package/dist/lib/one-client.js +9 -3
- package/dist/lib/one-error-hints.d.ts +19 -0
- package/dist/lib/one-error-hints.js +47 -0
- package/dist/lib/one-operations.d.ts +0 -1
- package/dist/lib/one-operations.js +0 -1
- package/dist/lib/open-url.d.ts +0 -1
- package/dist/lib/open-url.js +0 -1
- package/dist/lib/platform.d.ts +2 -0
- package/dist/lib/platform.js +4 -0
- package/dist/lib/progress.d.ts +0 -1
- package/dist/lib/progress.js +0 -1
- package/dist/lib/security-client.d.ts +0 -1
- package/dist/lib/security-client.js +0 -1
- package/dist/lib/skill-fetch.d.ts +0 -1
- package/dist/lib/skill-fetch.js +0 -1
- package/dist/lib/system-trust.d.ts +0 -1
- package/dist/lib/system-trust.js +0 -1
- package/dist/lib/tui.d.ts +0 -1
- package/dist/lib/tui.js +0 -1
- package/dist/local/cloudflare-checkup/cf/allowlist.d.ts +0 -1
- package/dist/local/cloudflare-checkup/cf/allowlist.js +0 -1
- package/dist/local/cloudflare-checkup/cf/auth-lifecycle.d.ts +0 -1
- package/dist/local/cloudflare-checkup/cf/auth-lifecycle.js +0 -1
- package/dist/local/cloudflare-checkup/cf/child-env.d.ts +0 -1
- package/dist/local/cloudflare-checkup/cf/child-env.js +0 -1
- package/dist/local/cloudflare-checkup/cf/install.d.ts +0 -1
- package/dist/local/cloudflare-checkup/cf/install.js +0 -1
- package/dist/local/cloudflare-checkup/cf/locate.d.ts +0 -1
- package/dist/local/cloudflare-checkup/cf/locate.js +0 -1
- package/dist/local/cloudflare-checkup/cf/run-cf.d.ts +0 -1
- package/dist/local/cloudflare-checkup/cf/run-cf.js +0 -1
- package/dist/local/cloudflare-checkup/collector.d.ts +0 -1
- package/dist/local/cloudflare-checkup/collector.js +0 -1
- package/dist/local/cloudflare-checkup/contract.d.ts +14 -3
- package/dist/local/cloudflare-checkup/contract.js +9 -3
- package/dist/local/cloudflare-checkup/email-verification.d.ts +0 -1
- package/dist/local/cloudflare-checkup/email-verification.js +0 -1
- package/dist/local/cloudflare-checkup/errors.d.ts +4 -1
- package/dist/local/cloudflare-checkup/errors.js +8 -2
- package/dist/local/cloudflare-checkup/output.d.ts +0 -1
- package/dist/local/cloudflare-checkup/output.js +0 -1
- package/dist/local/cloudflare-checkup/prompts.d.ts +0 -1
- package/dist/local/cloudflare-checkup/prompts.js +0 -1
- package/dist/local/cloudflare-checkup/rate-budget.d.ts +0 -1
- package/dist/local/cloudflare-checkup/rate-budget.js +0 -1
- package/dist/local/cloudflare-checkup/snapshot-file.d.ts +0 -1
- package/dist/local/cloudflare-checkup/snapshot-file.js +5 -4
- package/dist/local/cloudflare-checkup/submit-client.d.ts +19 -5
- package/dist/local/cloudflare-checkup/submit-client.js +63 -17
- package/dist/local/cloudflare-checkup/terminal-ui.d.ts +0 -1
- package/dist/local/cloudflare-checkup/terminal-ui.js +0 -1
- package/dist/types.d.ts +25 -3
- package/dist/types.js +16 -1
- package/dist/version.d.ts +0 -1
- package/dist/version.js +0 -1
- package/package.json +5 -9
- package/dist/auth/device-auth.d.ts.map +0 -1
- package/dist/auth/device-auth.js.map +0 -1
- package/dist/auth/index.d.ts.map +0 -1
- package/dist/auth/index.js.map +0 -1
- package/dist/auth/provider.d.ts.map +0 -1
- package/dist/auth/provider.js.map +0 -1
- package/dist/auth/refresh.d.ts.map +0 -1
- package/dist/auth/refresh.js.map +0 -1
- package/dist/auth/store.d.ts.map +0 -1
- package/dist/auth/store.js.map +0 -1
- package/dist/auth/token-metadata.d.ts.map +0 -1
- package/dist/auth/token-metadata.js.map +0 -1
- package/dist/auth/types.d.ts.map +0 -1
- package/dist/auth/types.js.map +0 -1
- package/dist/bin.d.ts.map +0 -1
- package/dist/bin.js.map +0 -1
- package/dist/cli.d.ts.map +0 -1
- package/dist/cli.js.map +0 -1
- package/dist/commands/account.d.ts.map +0 -1
- package/dist/commands/account.js.map +0 -1
- package/dist/commands/auth.d.ts.map +0 -1
- package/dist/commands/auth.js.map +0 -1
- package/dist/commands/billing.d.ts.map +0 -1
- package/dist/commands/billing.js.map +0 -1
- package/dist/commands/cloudflare.d.ts.map +0 -1
- package/dist/commands/cloudflare.js.map +0 -1
- package/dist/commands/helpers.d.ts.map +0 -1
- package/dist/commands/helpers.js.map +0 -1
- package/dist/commands/index.d.ts.map +0 -1
- package/dist/commands/index.js.map +0 -1
- package/dist/commands/legacy-validation.d.ts.map +0 -1
- package/dist/commands/legacy-validation.js.map +0 -1
- package/dist/commands/local.d.ts.map +0 -1
- package/dist/commands/local.js.map +0 -1
- package/dist/commands/one.d.ts.map +0 -1
- package/dist/commands/one.js.map +0 -1
- package/dist/commands/public-tools.d.ts.map +0 -1
- package/dist/commands/public-tools.js.map +0 -1
- package/dist/commands/runs.d.ts.map +0 -1
- package/dist/commands/runs.js.map +0 -1
- package/dist/commands/security.d.ts.map +0 -1
- package/dist/commands/security.js.map +0 -1
- package/dist/commands/watchdog.d.ts.map +0 -1
- package/dist/commands/watchdog.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/lib/banner.d.ts.map +0 -1
- package/dist/lib/banner.js.map +0 -1
- package/dist/lib/client.d.ts.map +0 -1
- package/dist/lib/client.js.map +0 -1
- package/dist/lib/cloudflare-client.d.ts.map +0 -1
- package/dist/lib/cloudflare-client.js.map +0 -1
- package/dist/lib/config.d.ts.map +0 -1
- package/dist/lib/config.js.map +0 -1
- package/dist/lib/format.d.ts.map +0 -1
- package/dist/lib/format.js.map +0 -1
- package/dist/lib/help.d.ts.map +0 -1
- package/dist/lib/help.js.map +0 -1
- package/dist/lib/network.d.ts.map +0 -1
- package/dist/lib/network.js.map +0 -1
- package/dist/lib/one-client.d.ts.map +0 -1
- package/dist/lib/one-client.js.map +0 -1
- package/dist/lib/one-operations.d.ts.map +0 -1
- package/dist/lib/one-operations.js.map +0 -1
- package/dist/lib/open-url.d.ts.map +0 -1
- package/dist/lib/open-url.js.map +0 -1
- package/dist/lib/progress.d.ts.map +0 -1
- package/dist/lib/progress.js.map +0 -1
- package/dist/lib/security-client.d.ts.map +0 -1
- package/dist/lib/security-client.js.map +0 -1
- package/dist/lib/skill-fetch.d.ts.map +0 -1
- package/dist/lib/skill-fetch.js.map +0 -1
- package/dist/lib/system-trust.d.ts.map +0 -1
- package/dist/lib/system-trust.js.map +0 -1
- package/dist/lib/tui.d.ts.map +0 -1
- package/dist/lib/tui.js.map +0 -1
- package/dist/local/cloudflare-checkup/cf/allowlist.d.ts.map +0 -1
- package/dist/local/cloudflare-checkup/cf/allowlist.js.map +0 -1
- package/dist/local/cloudflare-checkup/cf/auth-lifecycle.d.ts.map +0 -1
- package/dist/local/cloudflare-checkup/cf/auth-lifecycle.js.map +0 -1
- package/dist/local/cloudflare-checkup/cf/child-env.d.ts.map +0 -1
- package/dist/local/cloudflare-checkup/cf/child-env.js.map +0 -1
- package/dist/local/cloudflare-checkup/cf/install.d.ts.map +0 -1
- package/dist/local/cloudflare-checkup/cf/install.js.map +0 -1
- package/dist/local/cloudflare-checkup/cf/locate.d.ts.map +0 -1
- package/dist/local/cloudflare-checkup/cf/locate.js.map +0 -1
- package/dist/local/cloudflare-checkup/cf/run-cf.d.ts.map +0 -1
- package/dist/local/cloudflare-checkup/cf/run-cf.js.map +0 -1
- package/dist/local/cloudflare-checkup/collector.d.ts.map +0 -1
- package/dist/local/cloudflare-checkup/collector.js.map +0 -1
- package/dist/local/cloudflare-checkup/contract.d.ts.map +0 -1
- package/dist/local/cloudflare-checkup/contract.js.map +0 -1
- package/dist/local/cloudflare-checkup/email-verification.d.ts.map +0 -1
- package/dist/local/cloudflare-checkup/email-verification.js.map +0 -1
- package/dist/local/cloudflare-checkup/errors.d.ts.map +0 -1
- package/dist/local/cloudflare-checkup/errors.js.map +0 -1
- package/dist/local/cloudflare-checkup/output.d.ts.map +0 -1
- package/dist/local/cloudflare-checkup/output.js.map +0 -1
- package/dist/local/cloudflare-checkup/prompts.d.ts.map +0 -1
- package/dist/local/cloudflare-checkup/prompts.js.map +0 -1
- package/dist/local/cloudflare-checkup/rate-budget.d.ts.map +0 -1
- package/dist/local/cloudflare-checkup/rate-budget.js.map +0 -1
- package/dist/local/cloudflare-checkup/snapshot-file.d.ts.map +0 -1
- package/dist/local/cloudflare-checkup/snapshot-file.js.map +0 -1
- package/dist/local/cloudflare-checkup/submit-client.d.ts.map +0 -1
- package/dist/local/cloudflare-checkup/submit-client.js.map +0 -1
- package/dist/local/cloudflare-checkup/terminal-ui.d.ts.map +0 -1
- package/dist/local/cloudflare-checkup/terminal-ui.js.map +0 -1
- package/dist/types.d.ts.map +0 -1
- package/dist/types.js.map +0 -1
- package/dist/version.d.ts.map +0 -1
- package/dist/version.js.map +0 -1
package/dist/cli.js
CHANGED
|
@@ -4,7 +4,7 @@ import { VigilbaseApiError, VigilbaseClient } from './lib/client.js';
|
|
|
4
4
|
import { createConfig, createLocalCommandConfig } from './lib/config.js';
|
|
5
5
|
import { renderBanner, shouldShowBanner } from './lib/banner.js';
|
|
6
6
|
import { createWriter, formatError } from './lib/format.js';
|
|
7
|
-
import { HELP_TAGLINE, HELP_TEXT, helpForCommand } from './lib/help.js';
|
|
7
|
+
import { HELP_TAGLINE, HELP_TEXT, HELP_USAGE, helpForCommand, isCatalogTool } from './lib/help.js';
|
|
8
8
|
import { wasRendered } from './lib/tui.js';
|
|
9
9
|
import { getCommandHandler } from './commands/index.js';
|
|
10
10
|
import { LocalCheckupError } from './local/cloudflare-checkup/errors.js';
|
|
@@ -163,7 +163,8 @@ function resolveMode(jsonFlag) {
|
|
|
163
163
|
}
|
|
164
164
|
export async function runCli(options = {}) {
|
|
165
165
|
const argv = options.argv ?? process.argv.slice(2);
|
|
166
|
-
const
|
|
166
|
+
const stdoutStream = options.stdout ?? process.stdout;
|
|
167
|
+
const writer = createWriter(stdoutStream, options.stderr);
|
|
167
168
|
const previousEnv = process.env;
|
|
168
169
|
if (options.env) {
|
|
169
170
|
process.env = options.env;
|
|
@@ -182,12 +183,16 @@ export async function runCli(options = {}) {
|
|
|
182
183
|
if (parsed.values.isVersion && parsed.positionals.length)
|
|
183
184
|
throw new Error('Usage: vigilbase --version');
|
|
184
185
|
if (parsed.positionals[0] === 'help' && parsed.positionals.length > 2)
|
|
185
|
-
throw new Error(
|
|
186
|
+
throw new Error(HELP_USAGE);
|
|
186
187
|
}
|
|
187
188
|
if (parsed.values.isVersion) {
|
|
188
189
|
if (mode === 'json') {
|
|
189
190
|
writer.stdout(JSON.stringify({ name: '@vigilbase/cli', version: CLI_VERSION }, null, 2));
|
|
190
191
|
}
|
|
192
|
+
else if (!stdoutStream.isTTY) {
|
|
193
|
+
// Pipes and files get only the version, for scripts.
|
|
194
|
+
writer.stdout(CLI_VERSION);
|
|
195
|
+
}
|
|
191
196
|
else if (shouldShowBanner(mode)) {
|
|
192
197
|
writer.stdout(renderBanner({ version: CLI_VERSION, tagline: HELP_TAGLINE }));
|
|
193
198
|
}
|
|
@@ -238,7 +243,10 @@ export async function runCli(options = {}) {
|
|
|
238
243
|
const publicClient = new VigilbaseClient(config);
|
|
239
244
|
const handler = getCommandHandler(command);
|
|
240
245
|
if (!handler) {
|
|
241
|
-
|
|
246
|
+
// Tools are not commands of their own (no aliases): point to how they run.
|
|
247
|
+
throw new Error(isCatalogTool(command)
|
|
248
|
+
? `Unknown command "${command}". Run the tool with \`vigilbase run ${command} <target>\`.`
|
|
249
|
+
: `Unknown command "${command}". Run \`vigilbase help\` for usage.`);
|
|
242
250
|
}
|
|
243
251
|
return await handler({
|
|
244
252
|
command,
|
|
@@ -250,7 +258,7 @@ export async function runCli(options = {}) {
|
|
|
250
258
|
publicClient,
|
|
251
259
|
env: process.env,
|
|
252
260
|
stdin: options.stdin,
|
|
253
|
-
stdoutStream
|
|
261
|
+
stdoutStream,
|
|
254
262
|
stderrStream: options.stderr ?? process.stderr,
|
|
255
263
|
loginHandler: options.loginHandler,
|
|
256
264
|
});
|
|
@@ -266,11 +274,6 @@ export async function runCli(options = {}) {
|
|
|
266
274
|
if (error instanceof LocalCheckupError && error.isRateLimited) {
|
|
267
275
|
return EXIT.RATE_LIMITED;
|
|
268
276
|
}
|
|
269
|
-
if (error instanceof DeviceAuthError && error.code === 'not_enabled') {
|
|
270
|
-
if (mode !== 'json') {
|
|
271
|
-
writer.stderr('Public tools remain available without login: `vigilbase list`, `vigilbase run …`');
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
277
|
return EXIT.ERROR;
|
|
275
278
|
}
|
|
276
279
|
finally {
|
|
@@ -279,4 +282,3 @@ export async function runCli(options = {}) {
|
|
|
279
282
|
}
|
|
280
283
|
}
|
|
281
284
|
}
|
|
282
|
-
//# sourceMappingURL=cli.js.map
|
package/dist/commands/account.js
CHANGED
|
@@ -18,7 +18,7 @@ export const handleAccount = async (ctx) => {
|
|
|
18
18
|
else if (action === 'create' || action === 'add') {
|
|
19
19
|
if (ctx.values.email !== undefined && ctx.rest[2] !== undefined)
|
|
20
20
|
throw new Error('Specify the invite email either positionally or with --email, not both.');
|
|
21
|
-
validateArguments(ctx, ctx.values.email === undefined ? 3 : 2, ['email', 'role', 'isConfirm']);
|
|
21
|
+
validateArguments(ctx, ctx.values.email === undefined ? 3 : 2, ['email', 'role', 'isConfirm'], 'vigilbase account invites create <email> --confirm');
|
|
22
22
|
invitation = invitationSchema.parse({ email: ctx.values.email ?? ctx.rest[2], role: ctx.values.role });
|
|
23
23
|
if (!ctx.values.isConfirm)
|
|
24
24
|
throw new Error('Sending an organization invitation requires --confirm.');
|
|
@@ -184,4 +184,3 @@ export const handleAccount = async (ctx) => {
|
|
|
184
184
|
}
|
|
185
185
|
throw new Error('Usage: vigilbase account [services|org|endpoints|sessions|invites|billing] [--json]');
|
|
186
186
|
};
|
|
187
|
-
//# sourceMappingURL=account.js.map
|
package/dist/commands/auth.d.ts
CHANGED
package/dist/commands/auth.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { readIdentityTokenMetadata } from '../auth/token-metadata.js';
|
|
2
2
|
import { discoverAuthProvider } from '../auth/provider.js';
|
|
3
|
-
import { revokeSavedCredentials, withCredentialsLock } from '../auth/refresh.js';
|
|
3
|
+
import { revokeIdentityCredentials, revokeIdentityGrant, revokeSavedCredentials, withCredentialsLock } from '../auth/refresh.js';
|
|
4
|
+
import { checkCredentialsLocation, clearIdentityCredentials, clearOneCredentials, hasIgnoredIdentityCredentials, readReplacedIdentityGrant, readStoredCredentials } from '../auth/store.js';
|
|
4
5
|
import { getOneAccessToken, readCredentials, requestDeviceCode, waitForDeviceAuthorization, writeOneCredentials, } from '../auth/index.js';
|
|
5
6
|
import { VigilbaseOneClient, ONE_AUTH_REQUIRED_TOOLS } from '../lib/one-client.js';
|
|
6
7
|
import { VigilbaseApiError } from '../lib/client.js';
|
|
@@ -22,6 +23,30 @@ export async function readTokenFromStdin(input = process.stdin) {
|
|
|
22
23
|
throw new Error('Token input must contain exactly one nonempty token.');
|
|
23
24
|
return token;
|
|
24
25
|
}
|
|
26
|
+
/**
|
|
27
|
+
* Revoke the Identity grant a new login replaces, before the new grant exists. Identity treats a revoked refresh
|
|
28
|
+
* token presented again as reuse and ends every CLI grant of the user, so revoking after the new grant was issued
|
|
29
|
+
* could end it too. The lock is held from the read to the removal of the old file, so no concurrent command can
|
|
30
|
+
* refresh with the token in between, and no later command presents it again.
|
|
31
|
+
*/
|
|
32
|
+
async function retirePreviousIdentityGrant(ctx) {
|
|
33
|
+
await withCredentialsLock(ctx.config, async () => {
|
|
34
|
+
const previous = await readReplacedIdentityGrant(ctx.config);
|
|
35
|
+
// After a refresh with an uncertain result the token may be rotated already; presenting it trips the same check.
|
|
36
|
+
if (!previous || previous.refreshPending)
|
|
37
|
+
return;
|
|
38
|
+
try {
|
|
39
|
+
await revokeIdentityGrant(ctx.config, previous);
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
ctx.writer.stderr("Warning: Couldn't revoke your previous sign-in; it will expire on its own.");
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
// The grant came from identity-credentials.json, or from a CLI 0.2.0 credentials.json when that file is absent.
|
|
46
|
+
const { identity } = await readStoredCredentials(ctx.config, () => { });
|
|
47
|
+
await (identity ? clearIdentityCredentials(ctx.config) : clearOneCredentials(ctx.config));
|
|
48
|
+
}, true);
|
|
49
|
+
}
|
|
25
50
|
export const handleLogin = async (ctx) => {
|
|
26
51
|
if (ctx.rest.length)
|
|
27
52
|
throw new Error('Usage: vigilbase login [--token-stdin | --token <bearer>] [--no-open]');
|
|
@@ -29,6 +54,9 @@ export const handleLogin = async (ctx) => {
|
|
|
29
54
|
if (ctx.loginHandler) {
|
|
30
55
|
return ctx.loginHandler(ctx.config);
|
|
31
56
|
}
|
|
57
|
+
// Fail on Windows or an unsafe credentials directory or file before validating a token or starting device
|
|
58
|
+
// authorization: once a device grant is approved, a failed save would leave it unsaved and unrevoked.
|
|
59
|
+
await checkCredentialsLocation(ctx.config);
|
|
32
60
|
if (ctx.values.isTokenStdin && (ctx.values.token !== undefined || ctx.env.VIGILBASE_ONE_TOKEN !== undefined)) {
|
|
33
61
|
throw new Error('Use --token-stdin without --token or VIGILBASE_ONE_TOKEN.');
|
|
34
62
|
}
|
|
@@ -50,15 +78,19 @@ export const handleLogin = async (ctx) => {
|
|
|
50
78
|
email: session.user.email ?? undefined,
|
|
51
79
|
name: session.user.name ?? undefined,
|
|
52
80
|
};
|
|
53
|
-
await withCredentialsLock(ctx.config, () =>
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
:
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
81
|
+
await withCredentialsLock(ctx.config, async () => {
|
|
82
|
+
// Identity credentials win when tokens are read, so revoke them before saving this session.
|
|
83
|
+
await revokeIdentityCredentials(ctx.config);
|
|
84
|
+
await writeOneCredentials(ctx.config, {
|
|
85
|
+
accessToken: explicitToken,
|
|
86
|
+
tokenType: 'Bearer',
|
|
87
|
+
expiresAt: typeof session.session?.expiresAt === 'string'
|
|
88
|
+
? session.session.expiresAt
|
|
89
|
+
: undefined,
|
|
90
|
+
user,
|
|
91
|
+
obtainedAt: new Date().toISOString(),
|
|
92
|
+
});
|
|
93
|
+
}, true);
|
|
62
94
|
if (ctx.mode === 'json') {
|
|
63
95
|
outputJson(ctx, {
|
|
64
96
|
success: true,
|
|
@@ -76,6 +108,8 @@ export const handleLogin = async (ctx) => {
|
|
|
76
108
|
const preferNoOpen = Boolean(ctx.values.isNoOpen) || isHeadlessEnvironment(ctx.env);
|
|
77
109
|
ctx.writer.stderr(`login ${ctx.config.oneBaseUrl}`);
|
|
78
110
|
ctx.config.authProvider = await discoverAuthProvider(ctx.config);
|
|
111
|
+
if (ctx.config.authProvider)
|
|
112
|
+
await retirePreviousIdentityGrant(ctx);
|
|
79
113
|
const device = await withSpinner(ctx, 'Requesting device code', () => requestDeviceCode(ctx.config));
|
|
80
114
|
const verifyUrl = resolveDeviceVerificationUrl(ctx.config.authProvider?.issuer ?? ctx.config.oneBaseUrl, device);
|
|
81
115
|
const prettyCode = formatUserCode(device.user_code);
|
|
@@ -131,15 +165,20 @@ export const handleLogin = async (ctx) => {
|
|
|
131
165
|
if (ctx.config.authProvider && (!token.refresh_token || !expiresAt || !token.expires_in || token.expires_in > 300))
|
|
132
166
|
throw new Error('Identity returned an invalid token grant.');
|
|
133
167
|
const identityMetadata = ctx.config.authProvider ? readIdentityTokenMetadata(token.access_token, { issuer: ctx.config.authProvider.issuer, clientId: ctx.config.clientId, resource: ctx.config.authProvider.resource }) : undefined;
|
|
134
|
-
await withCredentialsLock(ctx.config, () =>
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
168
|
+
await withCredentialsLock(ctx.config, async () => {
|
|
169
|
+
// A legacy session is saved in credentials.json, which saved Identity credentials would override.
|
|
170
|
+
if (!ctx.config.authProvider)
|
|
171
|
+
await revokeIdentityCredentials(ctx.config);
|
|
172
|
+
await writeOneCredentials(ctx.config, {
|
|
173
|
+
...(ctx.config.authProvider ? { issuer: ctx.config.authProvider.issuer, clientId: ctx.config.clientId, resource: ctx.config.authProvider.resource, refreshToken: token.refresh_token, orgId: identityMetadata?.organizationId } : {}),
|
|
174
|
+
accessToken: token.access_token,
|
|
175
|
+
tokenType: token.token_type,
|
|
176
|
+
scope: token.scope,
|
|
177
|
+
expiresAt,
|
|
178
|
+
user,
|
|
179
|
+
obtainedAt: new Date().toISOString(),
|
|
180
|
+
});
|
|
181
|
+
}, true);
|
|
143
182
|
if (ctx.mode === 'json') {
|
|
144
183
|
outputJson(ctx, {
|
|
145
184
|
success: true,
|
|
@@ -160,7 +199,10 @@ export const handleLogout = async (ctx) => {
|
|
|
160
199
|
if (ctx.rest.length)
|
|
161
200
|
throw new Error('Usage: vigilbase logout');
|
|
162
201
|
assertCommandFlags(ctx, []);
|
|
163
|
-
const cleared = await revokeSavedCredentials(ctx.config)
|
|
202
|
+
const cleared = await revokeSavedCredentials(ctx.config, (warning) => {
|
|
203
|
+
if (ctx.mode !== 'json')
|
|
204
|
+
ctx.writer.stderr(`Warning: ${warning}`);
|
|
205
|
+
});
|
|
164
206
|
if (ctx.mode === 'json') {
|
|
165
207
|
outputJson(ctx, { success: true, cleared });
|
|
166
208
|
}
|
|
@@ -176,7 +218,7 @@ export const handleWhoami = async (ctx) => {
|
|
|
176
218
|
if (ctx.rest.length)
|
|
177
219
|
throw new Error('Usage: vigilbase whoami');
|
|
178
220
|
assertCommandFlags(ctx, []);
|
|
179
|
-
const
|
|
221
|
+
const legacyIdentityFileIgnored = await hasIgnoredIdentityCredentials(ctx.config);
|
|
180
222
|
const accessToken = await getOneAccessToken(ctx.config);
|
|
181
223
|
let liveUser = null;
|
|
182
224
|
if (accessToken) {
|
|
@@ -199,6 +241,8 @@ export const handleWhoami = async (ctx) => {
|
|
|
199
241
|
}
|
|
200
242
|
}
|
|
201
243
|
const signedIn = Boolean(liveUser);
|
|
244
|
+
// Read after the token and session calls: either may have refreshed the sign-in, which saves a new expiry and scope.
|
|
245
|
+
const credentials = await readCredentials(ctx.config);
|
|
202
246
|
const payload = {
|
|
203
247
|
authenticated: signedIn,
|
|
204
248
|
oneBaseUrl: ctx.config.oneBaseUrl,
|
|
@@ -211,7 +255,10 @@ export const handleWhoami = async (ctx) => {
|
|
|
211
255
|
scope: signedIn ? credentials.one?.scope ?? null : null,
|
|
212
256
|
obtainedAt: signedIn ? credentials.one?.obtainedAt ?? null : null,
|
|
213
257
|
authRequiredTools: signedIn ? [...ONE_AUTH_REQUIRED_TOOLS] : [],
|
|
258
|
+
legacyIdentityFileIgnored,
|
|
214
259
|
};
|
|
260
|
+
// CLI 0.2.0 can save a second Identity grant in credentials.json; logout revokes it.
|
|
261
|
+
const legacyNote = 'Note: found a credentials file from CLI 0.2.0. `vigilbase logout` will revoke and remove it.';
|
|
215
262
|
if (ctx.mode === 'json') {
|
|
216
263
|
outputJson(ctx, payload);
|
|
217
264
|
}
|
|
@@ -219,6 +266,7 @@ export const handleWhoami = async (ctx) => {
|
|
|
219
266
|
outputLines(ctx, [
|
|
220
267
|
'Not signed in. Public tools still work.',
|
|
221
268
|
'Run `vigilbase login` to unlock auth-required tools (website-security, react2shell, fortibleed-check).',
|
|
269
|
+
...(legacyIdentityFileIgnored ? [legacyNote] : []),
|
|
222
270
|
]);
|
|
223
271
|
}
|
|
224
272
|
else {
|
|
@@ -229,8 +277,9 @@ export const handleWhoami = async (ctx) => {
|
|
|
229
277
|
lines.push(`Expires: ${credentials.one.expiresAt}`);
|
|
230
278
|
}
|
|
231
279
|
lines.push(`Auth-required tools: ${ONE_AUTH_REQUIRED_TOOLS.join(', ')}`);
|
|
280
|
+
if (legacyIdentityFileIgnored)
|
|
281
|
+
lines.push(legacyNote);
|
|
232
282
|
outputLines(ctx, lines);
|
|
233
283
|
}
|
|
234
284
|
return ok();
|
|
235
285
|
};
|
|
236
|
-
//# sourceMappingURL=auth.js.map
|
package/dist/commands/billing.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
1
|
import { type CommandHandler } from './helpers.js';
|
|
2
|
-
export declare const CLOUDFLARE_HELP = "Usage: vigilbase cf <command> [options]\nAlias: vigilbase cloudflare\n\nInventory and workspace:\n zones List zones (default); --customer-id, --account-id, --zone-id\n zone <zone-id> Zone detail; --customer-id selects live details, optional --account-id\n accounts
|
|
2
|
+
export declare const CLOUDFLARE_HELP = "Usage: vigilbase cf <command> [options]\nAlias: vigilbase cloudflare\n\nInventory and workspace:\n zones List zones (default); --customer-id, --account-id, --zone-id\n zone <zone-id> Zone detail; --customer-id selects live details, optional --account-id\n accounts List accessible accounts; --customer-id, --account-id\n account <account-id> Stored account detail; --customer-id\n workspace [section] Workspace bootstrap or section; --customer-id, --account-id, --zone-id\n Sections: overview, reports, zones, rule-analyzer, accounts, checkups, settings\n\nZone reads (--customer-id <uuid> required; IDs can use --zone-id):\n dns <zone-id> DNS records, TTL and proxy state\n waf <zone-id> WAF rules, expressions, analytics and suggestions\n speed-settings <zone-id> Performance settings (internal users only)\n\nAccount reads (optional --customer-id; IDs can use --account-id):\n audit-logs <account-id> Latest provider audit events (up to 100; service-read permission)\n zero-trust <account-id> Users, Access applications, tunnels and authentication analytics\n developer-platform <account-id>\n Workers, Workers analytics and Pages\n magic-transit <account-id> Prefixes, routes and traffic analytics\n Zero Trust, Developer Platform and Magic Transit require deployment-read permission.\n\nAnalytics and checkups:\n analytics --customer-id <uuid> [--account-id <id> | --zone-id <id>] [--days 1..30]\n Default 7 days; live zone analytics uses the most recent 23 hours.\n checkup [status] Latest completed checkup; --customer-id, --account-id\n checkup start Start and persist a scan; --customer-id, --account-id\n checkup progress <run-uuid> Read saved progress once\n checkup result <run-uuid> Read the stored Cloudflare checkup result\n checkups aliases checkup; list/show alias status; run aliases start.\n\nCommon options: --json, --one-url <origin>, --timeout <milliseconds>, --help\nCustomer IDs are UUIDs; account and zone IDs are 32 hexadecimal characters.\nOne login, tenant bindings and permissions apply to every command.\nCheckup start creates a scan run. These commands do not edit provider configuration.\nSee CLOUDFLARE.md for full grammar, API mapping, data limits and examples.";
|
|
3
3
|
export declare const handleCloudflare: CommandHandler;
|
|
4
|
-
//# sourceMappingURL=cloudflare.d.ts.map
|
|
@@ -9,12 +9,12 @@ Alias: vigilbase cloudflare
|
|
|
9
9
|
Inventory and workspace:
|
|
10
10
|
zones List zones (default); --customer-id, --account-id, --zone-id
|
|
11
11
|
zone <zone-id> Zone detail; --customer-id selects live details, optional --account-id
|
|
12
|
-
accounts
|
|
12
|
+
accounts List accessible accounts; --customer-id, --account-id
|
|
13
13
|
account <account-id> Stored account detail; --customer-id
|
|
14
|
-
workspace [section]
|
|
14
|
+
workspace [section] Workspace bootstrap or section; --customer-id, --account-id, --zone-id
|
|
15
15
|
Sections: overview, reports, zones, rule-analyzer, accounts, checkups, settings
|
|
16
16
|
|
|
17
|
-
Zone reads (
|
|
17
|
+
Zone reads (--customer-id <uuid> required; IDs can use --zone-id):
|
|
18
18
|
dns <zone-id> DNS records, TTL and proxy state
|
|
19
19
|
waf <zone-id> WAF rules, expressions, analytics and suggestions
|
|
20
20
|
speed-settings <zone-id> Performance settings (internal users only)
|
|
@@ -22,15 +22,16 @@ Zone reads (optional --customer-id; IDs can use --zone-id):
|
|
|
22
22
|
Account reads (optional --customer-id; IDs can use --account-id):
|
|
23
23
|
audit-logs <account-id> Latest provider audit events (up to 100; service-read permission)
|
|
24
24
|
zero-trust <account-id> Users, Access applications, tunnels and authentication analytics
|
|
25
|
-
developer-platform <account-id>
|
|
25
|
+
developer-platform <account-id>
|
|
26
|
+
Workers, Workers analytics and Pages
|
|
26
27
|
magic-transit <account-id> Prefixes, routes and traffic analytics
|
|
27
28
|
Zero Trust, Developer Platform and Magic Transit require deployment-read permission.
|
|
28
29
|
|
|
29
30
|
Analytics and checkups:
|
|
30
31
|
analytics --customer-id <uuid> [--account-id <id> | --zone-id <id>] [--days 1..30]
|
|
31
32
|
Default 7 days; live zone analytics uses the most recent 23 hours.
|
|
32
|
-
checkup [status]
|
|
33
|
-
checkup start
|
|
33
|
+
checkup [status] Latest completed checkup; --customer-id, --account-id
|
|
34
|
+
checkup start Start and persist a scan; --customer-id, --account-id
|
|
34
35
|
checkup progress <run-uuid> Read saved progress once
|
|
35
36
|
checkup result <run-uuid> Read the stored Cloudflare checkup result
|
|
36
37
|
checkups aliases checkup; list/show alias status; run aliases start.
|
|
@@ -110,7 +111,7 @@ export const handleCloudflare = async (ctx) => {
|
|
|
110
111
|
throw new Error('The positional account ID and --account-id must match.');
|
|
111
112
|
accountId = args[0] ?? scope.accountId;
|
|
112
113
|
if (!accountId)
|
|
113
|
-
throw new Error(`Usage: vigilbase cf ${subcommand} <account-id> [--customer-id
|
|
114
|
+
throw new Error(`Missing <account-id>. Usage: vigilbase cf ${subcommand} <account-id> [--customer-id <uuid>] [--json]`);
|
|
114
115
|
validate(cloudflareScopeSchema, { accountId });
|
|
115
116
|
}
|
|
116
117
|
else if (['dns', 'waf', 'zone', 'speed-settings'].includes(subcommand)) {
|
|
@@ -120,9 +121,12 @@ export const handleCloudflare = async (ctx) => {
|
|
|
120
121
|
zoneId = args[0] ?? scope.zoneId;
|
|
121
122
|
// Preserve the historical `cf zone` alias for the zone inventory.
|
|
122
123
|
if (subcommand !== 'zone' && !zoneId)
|
|
123
|
-
throw new Error(`Usage: vigilbase cf ${subcommand} <zone-id>
|
|
124
|
+
throw new Error(`Missing <zone-id>. Usage: vigilbase cf ${subcommand} <zone-id> --customer-id <uuid> [--json]`);
|
|
124
125
|
if (zoneId)
|
|
125
126
|
validate(cloudflareScopeSchema, { zoneId });
|
|
127
|
+
// One answers 400 to every caller that leaves the customer out of a zone read.
|
|
128
|
+
if (subcommand !== 'zone' && !scope.customerId)
|
|
129
|
+
throw new Error(`cf ${subcommand} requires --customer-id <uuid>. Find it with \`vigilbase cf accounts --json\`.`);
|
|
126
130
|
}
|
|
127
131
|
else if (!['workspace', 'checkup', 'checkups'].includes(subcommand)) {
|
|
128
132
|
noExtraArgs(0);
|
|
@@ -143,6 +147,8 @@ export const handleCloudflare = async (ctx) => {
|
|
|
143
147
|
if (subcommand === 'checkup' || subcommand === 'checkups') {
|
|
144
148
|
if (['progress', 'result'].includes(action)) {
|
|
145
149
|
noExtraArgs(2, checkupUsage);
|
|
150
|
+
if (args[1] === undefined)
|
|
151
|
+
throw new Error(`Missing <run-uuid>. Usage: vigilbase cf checkup ${action} <run-uuid> [--json]`);
|
|
146
152
|
runId = validate(z.string().uuid('A checkup run UUID is required.'), args[1]);
|
|
147
153
|
if (scope.customerId || scope.accountId)
|
|
148
154
|
throw new Error(`cf checkup ${action} is scoped by run ID and does not accept --customer-id or --account-id.`);
|
|
@@ -338,4 +344,3 @@ export const handleCloudflare = async (ctx) => {
|
|
|
338
344
|
fields(ctx, report);
|
|
339
345
|
});
|
|
340
346
|
};
|
|
341
|
-
//# sourceMappingURL=cloudflare.js.map
|
|
@@ -96,4 +96,3 @@ export declare function requireOneClient(ctx: CommandContext): Promise<Vigilbase
|
|
|
96
96
|
export declare function withSpinner<T>(ctx: CommandContext, label: string, work: () => Promise<T>): Promise<T>;
|
|
97
97
|
export declare function ok(): ExitCode;
|
|
98
98
|
export { EXIT };
|
|
99
|
-
//# sourceMappingURL=helpers.d.ts.map
|
package/dist/commands/helpers.js
CHANGED
package/dist/commands/index.d.ts
CHANGED
package/dist/commands/index.js
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { type CommandContext } from './helpers.js';
|
|
3
|
-
|
|
3
|
+
/**
|
|
4
|
+
* Exactly `count` positional arguments. When some are missing, they are named from the trailing `<placeholders>`
|
|
5
|
+
* of `usage` (for example `vigilbase run <tool> <target>`), so `usage` lists only positional placeholders.
|
|
6
|
+
*/
|
|
7
|
+
export declare function validateArguments(ctx: CommandContext, count: number, flags?: readonly string[], usage?: string): void;
|
|
8
|
+
/** "Missing <target>. Usage: vigilbase headers <url>", or a pointer to --help without a usage. */
|
|
9
|
+
export declare function missingArguments(command: string, missingCount: number, usage?: string): string;
|
|
4
10
|
export declare function limitValue(raw: string | undefined, fallback: number, max: number): number;
|
|
5
11
|
export declare const invitationSchema: z.ZodObject<{
|
|
6
12
|
email: z.ZodString;
|
|
@@ -18,4 +24,3 @@ export declare const invitationSchema: z.ZodObject<{
|
|
|
18
24
|
}>>;
|
|
19
25
|
}, z.core.$strip>;
|
|
20
26
|
export declare const toolNameSchema: z.ZodString;
|
|
21
|
-
//# sourceMappingURL=legacy-validation.d.ts.map
|
|
@@ -1,10 +1,23 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { assertCommandFlags } from './helpers.js';
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
/**
|
|
4
|
+
* Exactly `count` positional arguments. When some are missing, they are named from the trailing `<placeholders>`
|
|
5
|
+
* of `usage` (for example `vigilbase run <tool> <target>`), so `usage` lists only positional placeholders.
|
|
6
|
+
*/
|
|
7
|
+
export function validateArguments(ctx, count, flags = [], usage) {
|
|
8
|
+
if (ctx.rest.length < count)
|
|
9
|
+
throw new Error(missingArguments(ctx.command, count - ctx.rest.length, usage));
|
|
10
|
+
if (ctx.rest.length > count)
|
|
5
11
|
throw new Error(`Unexpected arguments. Run \`vigilbase ${ctx.command} --help\` for usage.`);
|
|
6
12
|
assertCommandFlags(ctx, flags);
|
|
7
13
|
}
|
|
14
|
+
/** "Missing <target>. Usage: vigilbase headers <url>", or a pointer to --help without a usage. */
|
|
15
|
+
export function missingArguments(command, missingCount, usage) {
|
|
16
|
+
const missing = usage?.match(/<[^>]+>/g)?.slice(-missingCount) ?? [];
|
|
17
|
+
if (!usage || missing.length !== missingCount)
|
|
18
|
+
return `Missing arguments. Run \`vigilbase ${command} --help\` for usage.`;
|
|
19
|
+
return `Missing ${missing.join(' and ')}. Usage: ${usage}`;
|
|
20
|
+
}
|
|
8
21
|
export function limitValue(raw, fallback, max) {
|
|
9
22
|
if (raw === undefined)
|
|
10
23
|
return fallback;
|
|
@@ -17,4 +30,3 @@ export const invitationSchema = z.object({
|
|
|
17
30
|
role: z.enum(['admin', 'member', 'readonly', 'partner_owner', 'partner_sales', 'partner_operations', 'partner_finance', 'partner_readonly', 'billing_only', 'sales_only']).default('member'),
|
|
18
31
|
});
|
|
19
32
|
export const toolNameSchema = z.string().trim().min(1).max(128).regex(/^[a-z0-9-]+$/, 'Tool names must contain lowercase letters, digits, or hyphens.');
|
|
20
|
-
//# sourceMappingURL=legacy-validation.js.map
|
package/dist/commands/local.d.ts
CHANGED
|
@@ -27,4 +27,9 @@ export declare function displayPath(path: string, env?: NodeJS.ProcessEnv, platf
|
|
|
27
27
|
* `-2`, `-3`, … only when a run in the same second already used the name.
|
|
28
28
|
*/
|
|
29
29
|
export declare function defaultSnapshotName(accountId: string, at: Date, attempt?: number): string;
|
|
30
|
-
|
|
30
|
+
/**
|
|
31
|
+
* `submit` for a saved file. A loopback origin is named with `--base-url`, so a
|
|
32
|
+
* development run never suggests an upload to production; production is the
|
|
33
|
+
* CLI's default and is not named.
|
|
34
|
+
*/
|
|
35
|
+
export declare function submitCommand(path: string, origin: string): string;
|
package/dist/commands/local.js
CHANGED
|
@@ -33,7 +33,7 @@ import { buildSnapshot, collectAccount, estimateRequests, listAccounts } from '.
|
|
|
33
33
|
import { accountName, countEntries, countEntriesByKind, dataCategories, loadSnapshotFile, writeSnapshotFile, zoneCount, } from '../local/cloudflare-checkup/snapshot-file.js';
|
|
34
34
|
import { confirmDefaultYes, confirmUpload, hasInteractiveInput, promptLine } from '../local/cloudflare-checkup/prompts.js';
|
|
35
35
|
import { SAME_ADDRESS_WAIT, emailLocale, parseEmailFlag, verifyEmail } from '../local/cloudflare-checkup/email-verification.js';
|
|
36
|
-
import { SubmitClient, VerificationClient,
|
|
36
|
+
import { SubmitClient, VerificationClient, assertServerAccepts, displayRequester, isLoopbackOrigin, resolveSubmitOrigin, } from '../local/cloudflare-checkup/submit-client.js';
|
|
37
37
|
import { displayText, formatBytes, formatClock, formatDuration, maskId, readsSummary, shortSha, startCountsProgress } from '../local/cloudflare-checkup/output.js';
|
|
38
38
|
import { CheckupTui } from '../local/cloudflare-checkup/terminal-ui.js';
|
|
39
39
|
import { EXIT, assertCommandFlags, ok, outputJson } from './helpers.js';
|
|
@@ -134,7 +134,8 @@ function parse(schema, value) {
|
|
|
134
134
|
function parseLocalOptions(ctx, subcommand, args) {
|
|
135
135
|
const takesFile = subcommand === 'inspect' || subcommand === 'submit';
|
|
136
136
|
if (takesFile ? args.length !== 1 : args.length !== 0) {
|
|
137
|
-
|
|
137
|
+
const fileUsage = `Usage: vigilbase cloudflare-checkup ${subcommand} <file>`;
|
|
138
|
+
throw new Error(!takesFile ? usage : args.length === 0 ? `Missing <file>. ${fileUsage}` : fileUsage);
|
|
138
139
|
}
|
|
139
140
|
const values = ctx.values;
|
|
140
141
|
const requested = parse(z.enum(['auto', 'profile', 'env', 'default'], { message: '--cf-auth must be auto, profile, env or default.' }), values['cf-auth'] ?? (subcommand === 'run' ? 'auto' : 'profile'));
|
|
@@ -1159,10 +1160,23 @@ function clientOptions(ctx, origin) {
|
|
|
1159
1160
|
...(ctx.values.timeout !== undefined ? { timeoutMs: ctx.config.timeoutMs } : {}),
|
|
1160
1161
|
};
|
|
1161
1162
|
}
|
|
1163
|
+
/**
|
|
1164
|
+
* Before the email is asked for (or `--email` is used): vigilbase.com says
|
|
1165
|
+
* whether local checkups are on and which CLI and snapshot schema it accepts,
|
|
1166
|
+
* so a switched-off local mode (LOCAL_MODE_DISABLED) or an old CLI
|
|
1167
|
+
* (CLI_UPGRADE_REQUIRED) never costs an emailed code. Without a usable answer
|
|
1168
|
+
* the run goes on, and the session check after the email decides as before.
|
|
1169
|
+
*/
|
|
1170
|
+
async function checkAvailability(ctx, origin, schemaVersion) {
|
|
1171
|
+
const client = new VerificationClient(clientOptions(ctx, origin));
|
|
1172
|
+
const availability = await busy(ctx, 'Checking vigilbase.com', () => client.availability());
|
|
1173
|
+
if (availability)
|
|
1174
|
+
assertServerAccepts(availability, CLI_VERSION, schemaVersion);
|
|
1175
|
+
}
|
|
1162
1176
|
/**
|
|
1163
1177
|
* The email verification (prompts on stderr, answers from piped stdin
|
|
1164
|
-
* without a terminal), then `✓ Verified j***@acme.com`.
|
|
1165
|
-
* before
|
|
1178
|
+
* without a terminal), then `✓ Verified j***@acme.com`. No address is sent
|
|
1179
|
+
* before one is entered, and cf is not touched before it is verified.
|
|
1166
1180
|
*/
|
|
1167
1181
|
async function verifyRequester(ctx, options, origin) {
|
|
1168
1182
|
const verified = await verifyEmail({
|
|
@@ -1230,16 +1244,25 @@ class CheckupSession {
|
|
|
1230
1244
|
/** Failures after the snapshot is saved that a later `submit <file>` can fix without collecting again. */
|
|
1231
1245
|
const UPLOAD_LATER_CODES = new Set(['SESSION_INVALID', 'SESSION_EXPIRED', 'SESSION_CLOSED', 'VERIFICATION_EXPIRED', 'VERIFICATION_INVALID',
|
|
1232
1246
|
'SUBMIT_FAILED', 'VIGILBASE_RATE_LIMITED', 'VIGILBASE_CHALLENGED', 'LOCAL_MODE_DISABLED']);
|
|
1247
|
+
/**
|
|
1248
|
+
* `submit` for a saved file. A loopback origin is named with `--base-url`, so a
|
|
1249
|
+
* development run never suggests an upload to production; production is the
|
|
1250
|
+
* CLI's default and is not named.
|
|
1251
|
+
*/
|
|
1252
|
+
export function submitCommand(path, origin) {
|
|
1253
|
+
const baseUrl = isLoopbackOrigin(origin) ? ` --base-url ${shellArg(origin)}` : '';
|
|
1254
|
+
return `${NPX_COMMAND} cloudflare-checkup submit ${shellArg(path)}${baseUrl}`;
|
|
1255
|
+
}
|
|
1233
1256
|
/**
|
|
1234
1257
|
* Right before such an error is reported (stderr, both modes): the `submit`
|
|
1235
1258
|
* command for the saved file. A line of its own, because hints are capped at
|
|
1236
1259
|
* 300 characters and a path has no fixed length; in the terminal UI, the
|
|
1237
1260
|
* command has a line of its own too, never wrapped, so it can be copied.
|
|
1238
1261
|
*/
|
|
1239
|
-
function noteSavedSnapshot(ctx, error, path) {
|
|
1262
|
+
function noteSavedSnapshot(ctx, error, path, origin) {
|
|
1240
1263
|
if (!(error instanceof LocalCheckupError) || !UPLOAD_LATER_CODES.has(error.code))
|
|
1241
1264
|
return;
|
|
1242
|
-
const submit =
|
|
1265
|
+
const submit = submitCommand(path, origin);
|
|
1243
1266
|
if (ctx.tui)
|
|
1244
1267
|
ctx.tui.uploadLater(submit);
|
|
1245
1268
|
else
|
|
@@ -1247,7 +1270,7 @@ function noteSavedSnapshot(ctx, error, path) {
|
|
|
1247
1270
|
}
|
|
1248
1271
|
/** Session checks that need no upload: CLI version, single use, and the bound account. */
|
|
1249
1272
|
function assertSessionUsable(session, accountId) {
|
|
1250
|
-
|
|
1273
|
+
assertServerAccepts(session, CLI_VERSION, SNAPSHOT_SCHEMA_VERSION);
|
|
1251
1274
|
if (session.state === 'completed')
|
|
1252
1275
|
throw new LocalCheckupError('SESSION_USED', 'This checkup already has results, so it cannot accept a new snapshot.');
|
|
1253
1276
|
// A checkup the email verification just started is never processing; this guards any other state.
|
|
@@ -1288,7 +1311,8 @@ async function runOneCommand(ctx, options) {
|
|
|
1288
1311
|
// A bad --out never costs an emailed code (collectSnapshot checks it again).
|
|
1289
1312
|
if (options.out !== undefined)
|
|
1290
1313
|
await assertOutWritable(options.out, Boolean(ctx.values.isOverwrite));
|
|
1291
|
-
// 1-3.
|
|
1314
|
+
// 1-3. Availability, then the email, then the checkup it started are checked before cf is touched.
|
|
1315
|
+
await checkAvailability(ctx, origin, SNAPSHOT_SCHEMA_VERSION);
|
|
1292
1316
|
const checkup = new CheckupSession(ctx, origin, await verifyRequester(ctx, options, origin));
|
|
1293
1317
|
const early = await busy(ctx, 'Checking the checkup', () => checkup.getSession());
|
|
1294
1318
|
assertSessionUsable(early, options.accountId);
|
|
@@ -1312,7 +1336,7 @@ async function runOneCommand(ctx, options) {
|
|
|
1312
1336
|
result = await uploadLoaded(ctx, { checkup, session, origin, loaded });
|
|
1313
1337
|
}
|
|
1314
1338
|
catch (error) {
|
|
1315
|
-
noteSavedSnapshot(ctx, error, outcome.path);
|
|
1339
|
+
noteSavedSnapshot(ctx, error, outcome.path, origin);
|
|
1316
1340
|
throw error;
|
|
1317
1341
|
}
|
|
1318
1342
|
if (ctx.mode === 'json') {
|
|
@@ -1410,7 +1434,8 @@ async function submitFile(ctx, options) {
|
|
|
1410
1434
|
ctx.writer.stderr(head);
|
|
1411
1435
|
else
|
|
1412
1436
|
ctx.writer.stdout(head);
|
|
1413
|
-
// The file
|
|
1437
|
+
// The file, then vigilbase.com's availability, are checked before the email is verified, so neither costs a code.
|
|
1438
|
+
await checkAvailability(ctx, origin, loaded.snapshot.schemaVersion);
|
|
1414
1439
|
const checkup = new CheckupSession(ctx, origin, await verifyRequester(ctx, options, origin));
|
|
1415
1440
|
const session = await busy(ctx, 'Checking the checkup', () => checkup.getSession());
|
|
1416
1441
|
const result = await uploadLoaded(ctx, { checkup, session, origin, loaded });
|
|
@@ -1455,7 +1480,7 @@ async function uploadLoaded(ctx, input) {
|
|
|
1455
1480
|
const { checkup, session, origin, loaded } = input;
|
|
1456
1481
|
const { snapshot } = loaded;
|
|
1457
1482
|
assertFresh(snapshot);
|
|
1458
|
-
|
|
1483
|
+
assertServerAccepts(session, CLI_VERSION, snapshot.schemaVersion);
|
|
1459
1484
|
if (session.accountId !== null && session.accountId !== snapshot.accountId) {
|
|
1460
1485
|
throw new LocalCheckupError('ACCOUNT_MISMATCH', `This checkup is bound to Cloudflare account ${maskId(session.accountId)}, but the snapshot is for ${maskId(snapshot.accountId)}. Nothing was uploaded.`);
|
|
1461
1486
|
}
|
|
@@ -1517,4 +1542,3 @@ async function uploadLoaded(ctx, input) {
|
|
|
1517
1542
|
...(result.resultsUrl !== undefined ? { resultsUrl: result.resultsUrl } : {}),
|
|
1518
1543
|
};
|
|
1519
1544
|
}
|
|
1520
|
-
//# sourceMappingURL=local.js.map
|
package/dist/commands/one.d.ts
CHANGED
|
@@ -3,4 +3,3 @@ import { type CommandContext, type CommandHandler } from './helpers.js';
|
|
|
3
3
|
export declare function buildOneOperation(ctx: CommandContext): OneOperation;
|
|
4
4
|
export declare const handleOne: CommandHandler;
|
|
5
5
|
export declare const ONE_HELP: Record<string, string>;
|
|
6
|
-
//# sourceMappingURL=one.d.ts.map
|