Something went wrong. Try again.
A fully featured CLI used as an alternative to AppView applications (Bsky.app/mu.social)
Something went wrong. Try again.
TypeScript
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283import type { CommandSpec } from './command.ts';
// What can go wrong, and the exit code each kind of failure leaves.//// Agents branch on exit codes, so they are few and stable://// 0 done// 1 anything else that went wrong (a server error, a file that is not there)// 2 the command line was wrong: an unknown option, a missing argument// 3 not signed in, or the session cannot be used and needs a new login// 4 the thing named does not exist: an unknown handle, a deleted post// 5 the server said to slow down, for longer than is worth waiting// 6 a question needed answering and there was no terminal to ask on//// With --json, every failure is also printed on stdout as// {"error": {"code", "message", "status"?, "exit"}}, so a caller that reads only// stdout still learns what happened.
export const EXIT = { ok: 0, error: 1, usage: 2, auth: 3, notFound: 4, rateLimited: 5, needsInput: 6,} as const;
export class CliError extends Error { exit: number; code: string; constructor(message: string, code = 'Error', exit: number = EXIT.error) { super(message); this.code = code; this.exit = exit; }}
export class UsageError extends CliError { /** The command the mistake was made in, so its help can be pointed at. */ path: CommandSpec[]; constructor(message: string, path: CommandSpec[] = []) { super(message, 'UsageError', EXIT.usage); this.path = path; }}
export class AuthError extends CliError { constructor(message: string, code = 'AuthRequired') { super(message, code, EXIT.auth); }}
export class NotFoundError extends CliError { constructor(message: string, code = 'NotFound') { super(message, code, EXIT.notFound); }}
export class NeedsInputError extends CliError { constructor(message: string) { super(message, 'NeedsInput', EXIT.needsInput); }}
/** An error an XRPC service answered with. */export class XrpcError extends CliError { status: number; nsid: string; constructor(nsid: string, status: number, code: string, message: string) { super(message, code, exitFor(status, code)); this.status = status; this.nsid = nsid; }}
function exitFor(status: number, code: string): number { if (status === 401 || /^(AuthRequired|AuthMissing|ExpiredToken|InvalidToken|invalid_token|AccountTakedown|AccountDeactivated)$/.test(code)) return EXIT.auth; if (status === 404 || /NotFound$|^(UnknownFeed|UnknownList|InvalidUri)$/.test(code)) return EXIT.notFound; if (status === 429) return EXIT.rateLimited; return EXIT.error;}