@vigilbase/cli
Version:
Vigilbase CLI — security scanners, agent tools, and Vigilbase One from the terminal.
106 lines (105 loc) • 8.59 kB
JavaScript
/**
* Stable error codes for `vigilbase cloudflare-checkup` (spec §F8).
*
* Every code matches `formatError`'s code pattern. Messages and hints are
* authored here; cf stderr and Vigilbase server text are never echoed. Hints
* point at the one command ("run the same command again", `--yes`,
* `--account-id`), not at the advanced subcommands. The browser
* troubleshooting accordion mirrors the code set.
*/
import { CF_TOKEN_ENV } from './cf/child-env.js';
import { PRODUCTION_ORIGIN } from './contract.js';
export const LOCAL_ERROR_CODES = [
// Environment and cf
'NODE_UNSUPPORTED', 'CF_NOT_FOUND', 'CF_WRONG_BINARY', 'CF_UNSUPPORTED_VERSION', 'CF_ALLOWLIST_MISMATCH',
'CF_INSTALL_FAILED', 'CF_AUTH_REQUIRED', 'CF_PERMISSION_DENIED', 'CF_RATE_LIMITED', 'CF_ERROR',
// Account
'ACCOUNT_SELECTION_REQUIRED', 'ACCOUNT_NOT_VISIBLE', 'ACCOUNT_TOO_LARGE', 'ACCOUNT_MISMATCH',
// Files and snapshots
'OUTPUT_EXISTS', 'SNAPSHOT_INVALID', 'SNAPSHOT_TOO_LARGE', 'SNAPSHOT_STALE', 'SNAPSHOT_SECRET_LIKE_VALUE',
// Email verification
'EMAIL_INVALID', 'EMAIL_CODE_INVALID', 'VERIFICATION_INVALID', 'VERIFICATION_EXPIRED',
// Session
'SESSION_INVALID', 'SESSION_EXPIRED', 'SESSION_USED', 'SESSION_BUSY', 'SESSION_CLOSED',
// Submission
'SUBMIT_ORIGIN_UNTRUSTED', 'CONFIRMATION_REQUIRED', 'CLI_UPGRADE_REQUIRED', 'LOCAL_MODE_DISABLED',
'VIGILBASE_RATE_LIMITED', 'VIGILBASE_CHALLENGED', 'SUBMIT_FAILED',
];
const INSTALL_CF = '`npm install --global cf@1.0.0-beta.13`';
/** LOCAL_MODE_DISABLED: the browser checkup on the origin the CLI talks to (vigilbase.com, or a loopback dev server). */
export function browserCheckupHint(origin) {
return `Run the Cloudflare Checkup in your browser instead: ${origin}/tools/cloudflare-checkup`;
}
/** One fix per code; shown after the error and in `--json` as `hint`. */
export const LOCAL_ERROR_HINTS = {
NODE_UNSUPPORTED: 'Install Node.js 22.18 or newer from https://nodejs.org (cf runs under the same Node), then run the same command again.',
CF_NOT_FOUND: `Run the same command again in a terminal and let it install cf (add --yes when no terminal is available), or install it yourself with ${INSTALL_CF}.`,
CF_WRONG_BINARY: `Another program named cf (for example the Cloud Foundry CLI, or a pnpm or Volta shim) was found. Run the same command again without --cf-bin and let it install cf, or pass --cf-bin "$(npm root -g)/cf".`,
CF_UNSUPPORTED_VERSION: `Run the same command again without --cf-bin and let it install the tested cf 1.0.0-beta.13, or install it yourself with ${INSTALL_CF}.`,
// Without --cf-bin the one command offers the managed install itself; the user's own cf is left alone.
CF_ALLOWLIST_MISMATCH: 'This cf release renamed commands the checkup needs. Run the same command again without --cf-bin and let it install the tested cf 1.0.0-beta.13 for Vigilbase; your own cf is left alone.',
CF_INSTALL_FAILED: `Install cf yourself with ${INSTALL_CF}, then run the same command again.`,
CF_AUTH_REQUIRED: `Run the same command again in a terminal to sign in to Cloudflare with a read-only login, or set ${CF_TOKEN_ENV} in this shell first.`,
CF_PERMISSION_DENIED: 'Your Cloudflare login cannot read this account\'s zones. Check its permissions, then run the same command again.',
CF_RATE_LIMITED: 'Cloudflare paused your API access. Wait 5 minutes, then run the same command again; add --max-requests-per-5min 600 if it repeats.',
CF_ERROR: 'Run the same command again in a few minutes. If it persists, contact help@vigilbase.com.',
ACCOUNT_SELECTION_REQUIRED: 'Run the same command again in a terminal to choose the account, or add --account-id <ACCOUNT_ID> with one of the IDs listed.',
ACCOUNT_NOT_VISIBLE: 'Check that your Cloudflare user can read the account and its zones, then run the same command again.',
ACCOUNT_TOO_LARGE: 'Local collection supports up to 100 zones. Use the browser token mode on vigilbase.com instead.',
ACCOUNT_MISMATCH: 'This checkup is for a different Cloudflare account. Run the same command again without --account-id to start a new checkup.',
OUTPUT_EXISTS: 'Choose another --out path, or pass --overwrite to replace the file.',
SNAPSHOT_INVALID: 'The file is not a valid snapshot. Run the same command again to collect a fresh one.',
SNAPSHOT_TOO_LARGE: 'The snapshot is over the upload limit. Use the browser token mode on vigilbase.com instead.',
SNAPSHOT_STALE: 'Snapshots are accepted for 24 hours. Run the same command again to collect a fresh one.',
SNAPSHOT_SECRET_LIKE_VALUE: 'The snapshot contains a value that looks like a credential. Remove it from the Cloudflare rule description or name, then run the same command again.',
EMAIL_INVALID: 'Use your work email address (personal and disposable addresses are not accepted), then run the same command again.',
EMAIL_CODE_INVALID: 'Run the same command again to get a new code, and enter the 6 digits from the newest email.',
VERIFICATION_INVALID: 'Run the same command again to get a new code by email.',
VERIFICATION_EXPIRED: 'Run the same command again to get a new code by email, and enter it before the time shown.',
SESSION_INVALID: 'Run the same command again to verify your email and start a new checkup.',
SESSION_EXPIRED: 'Run the same command again to verify your email and start a new checkup.',
SESSION_USED: 'This checkup already has results. Run the same command again to start a new checkup.',
SESSION_BUSY: 'A snapshot for this checkup is still being processed. Wait for the results email, or run the same command again to start a new checkup.',
SESSION_CLOSED: 'This checkup was cancelled or has expired. Run the same command again to start a new one.',
SUBMIT_ORIGIN_UNTRUSTED: 'Upload only to https://vigilbase.com (or a loopback origin for local testing).',
CONFIRMATION_REQUIRED: 'Run the command in a terminal to confirm the upload, or add --yes.',
CLI_UPGRADE_REQUIRED: 'Run `npx @vigilbase/cli@latest cloudflare-checkup`, or upgrade with `npm install --global @vigilbase/cli@latest`.',
LOCAL_MODE_DISABLED: browserCheckupHint(PRODUCTION_ORIGIN),
VIGILBASE_RATE_LIMITED: 'Too many requests to vigilbase.com. Wait as long as the error says (a few minutes if it says nothing), then run the same command again.',
VIGILBASE_CHALLENGED: 'vigilbase.com asked for a browser challenge. Try another network, or contact help@vigilbase.com.',
SUBMIT_FAILED: 'Run the same command again in a few minutes. If it persists, contact help@vigilbase.com.',
};
/**
* CF_AUTH_REQUIRED in env mode (`--cf-auth env`, or `auto` with the variable
* set): the browser sign-in is never offered while the token is used, so the
* hint names both ways out.
*/
export const ENV_TOKEN_AUTH_HINT = `Set ${CF_TOKEN_ENV} in this shell to a valid read-only Cloudflare API token (read -rs ${CF_TOKEN_ENV} && export ${CF_TOKEN_ENV}) and run the same command again, or unset it (or use --cf-auth profile) to sign in with your browser instead.`;
/** SNAPSHOT_INVALID for an `inspect` or `submit` path with no file: nothing to collect again, so how to make one. */
export const SNAPSHOT_MISSING_HINT = 'Check the file path. To collect a snapshot into a file, run `npx @vigilbase/cli cloudflare-checkup collect --out <file>`.';
/** CF_PERMISSION_DENIED in env mode: the token lacks a read permission; the browser sign-in is the other way out. */
export const ENV_TOKEN_PERMISSION_HINT = `The API token in ${CF_TOKEN_ENV} cannot read everything the checkup needs. Add the read permissions to it, or unset it (or use --cf-auth profile) to sign in with your browser instead, then run the same command again.`;
export class LocalCheckupError extends Error {
code;
hint;
/** HTTP status of the Cloudflare or Vigilbase response, when one caused the error. */
status;
retryAfterSec;
constructor(code, message, options = {}) {
super(message);
this.name = 'LocalCheckupError';
this.code = code;
this.hint = options.hint ?? LOCAL_ERROR_HINTS[code];
if (options.status !== undefined)
this.status = options.status;
if (options.retryAfterSec !== undefined)
this.retryAfterSec = options.retryAfterSec;
}
/** Mapped to exit code 2 by `runCli`. */
get isRateLimited() {
return this.code === 'CF_RATE_LIMITED' || this.code === 'VIGILBASE_RATE_LIMITED';
}
}
export function isLocalCheckupError(error) {
return error instanceof LocalCheckupError;
}