src/errors.js
Rama main · réplica de lectura del repositorio original.
import { WeaveError } from './store.js';
export const ERROR_CONTRACT = Object.freeze({
invalid: { http: 400, mcp: -32602, exit: 40 },
ambiguous: { http: 400, mcp: -32602, exit: 41 },
slug_invalid: { http: 400, mcp: -32602, exit: 40 },
slug_reserved: { http: 400, mcp: -32602, exit: 40 },
forbidden: { http: 403, mcp: -32003, exit: 46 },
'not-found': { http: 404, mcp: -32001, exit: 44 },
conflict: { http: 409, mcp: -32002, exit: 45 },
slug_taken: { http: 409, mcp: -32002, exit: 45 },
stale: { http: 412, mcp: -32004, exit: 47 },
'too-large': { http: 413, mcp: -32005, exit: 48 },
'unsupported-type': { http: 415, mcp: -32006, exit: 49 },
'rate-limited': { http: 429, mcp: -32007, exit: 50 },
'weave-error': { http: 400, mcp: -32000, exit: 1 },
'storage-full': { http: 507, mcp: -32008, exit: 51 },
internal: { http: 500, mcp: -32603, exit: 70 },
});
export const storageFull = (err) => err?.code === 'ENOSPC' || err?.code === 'SQLITE_FULL' || err?.errcode === 13 || /database or disk is full/.test(String(err?.message ?? ''));
const codeOf = (err) => {
if (err instanceof WeaveError) return Object.hasOwn(ERROR_CONTRACT, err.code) ? err.code : 'weave-error';
return storageFull(err) ? 'storage-full' : 'internal';
};
export function contractFor(err) {
const code = codeOf(err);
return { code, ...ERROR_CONTRACT[code] };
}
export const statusFor = (err) => contractFor(err).http;
export function errorBody(err) {
if (err instanceof WeaveError) return { error: err.message, code: err.code ?? 'weave-error' };
const id = crypto.randomUUID().slice(0, 8);
if (typeof console !== 'undefined') console.error(`weave: request ${id} failed:`, err);
if (storageFull(err)) return { error: 'The weave server is out of storage, so nothing was saved. Ask whoever runs your weave to add storage.', code: 'storage-full', id };
return { error: `Internal error (request ${id})`, code: 'internal', id };
}
export function mcpToolError(err) {
const error = err?.message ?? String(err);
const { code, mcp } = contractFor(err);
const named = err instanceof WeaveError ? err.code ?? code : code;
return { content: [{ type: 'text', text: `Error: ${error}` }], isError: true, structuredContent: { error, code: named, rpc: mcp } };
}
export function cliFailure(err) {
const { code, exit } = contractFor(err);
const named = err instanceof WeaveError ? err.code ?? code : code;
return { line: `weave: error [${named}]: ${err?.message ?? String(err)}`, exit };
}
export function nonNegativeInteger(name, value, fallback = 0) {
if (value == null) return fallback;
const n = Number(value);
if (!Number.isInteger(n) || n < 0) throw new WeaveError(`${name} must be a whole number of rows, not '${value}'`, 'invalid');
return n;
}