// One error class for the package. exitCode follows docs/TOOLS.md: 1 operation // failed, 2 invalid data or configuration, 3 refused by a brake (STOP or a // held binding; a supervisor must not retry), 4 usage. // A refusal that names an unknown key quotes it only when it is a plain name; // a key that could carry a host path or a secret is described, never echoed (#1873). export const plainKey = (k) => (/^[A-Za-z_][A-Za-z0-9_-]{0,63}$/.test(String(k)) ? JSON.stringify(k) : "that is not a plain name"); // A binding (and seat) name. Defined here, not in binding.mjs, so journal.mjs can label a // journal directory without importing binding.mjs and its config readers; copies of // journal.mjs + errors.mjs (the queue test repo) stay self-contained. binding.mjs re-exports it. export const BINDING_NAME = /^[a-z0-9][a-z0-9._-]{0,63}$/; // A filesystem call that fails names the file by label, the call and the // error code, never the path Node puts in the message. The same error object // is rethrown, so its type, code and the exit it maps to are unchanged, and // it is marked so the CLI's top-level handler prints it as it is (#1873). const QUIET = Symbol("discord.quiet"); const SYSCALL = /^[a-z][a-z0-9_]{0,31}$/; const CODE = /^[A-Z][A-Z0-9_]{0,63}$/; const callOf = (e) => { const word = typeof e.syscall === "string" ? e.syscall.split(" ")[0] : ""; return SYSCALL.test(word) ? word : "access"; }; const codeOf = (e) => (typeof e.code === "string" && CODE.test(e.code) ? e.code : "UNKNOWN"); export function quietFs(e, label, verb = null) { if (e && typeof e === "object" && typeof e.code === "string") { e.message = `cannot ${verb ?? callOf(e)} ${label} (${codeOf(e)})`; e[QUIET] = true; } return e; } export const quietRead = (e, label) => quietFs(e, label, "read"); // What a top-level handler prints for an error (#1873). Our refusals and an // error already labelled at its source print their own message. A native // Node error (it carries a syscall, or a code and a path) that slipped past // every source label prints only its call and code, never its message, // which carries the path; `label` names the file when the error has one. export function printable(err, label = "a discord file") { if (err instanceof DiscordError || (err && err[QUIET] === true)) return String(err.message); if (err && typeof err === "object" && (typeof err.syscall === "string" || (typeof err.code === "string" && typeof err.path === "string"))) { return typeof err.path === "string" ? `cannot ${callOf(err)} ${label} (${codeOf(err)})` : `cannot ${callOf(err)} (${codeOf(err)})`; } return err && typeof err.message === "string" ? err.message : String(err); } export class DiscordError extends Error { constructor(message, exitCode = 2, details = undefined) { super(message); this.name = "DiscordError"; this.exitCode = exitCode; if (details !== undefined) this.details = details; } }