/**
* Every failure raised by this client is a plain `Error` tagged with a
* `kind`, so callers narrow with the type guards below (or on `kind`):
*
* try { await domains.check(client, 'x.ro') }
* catch (e) { if (isApiError(e) && e.status === 402) ... }
*/
const NAMES = {
api: 'IrdApiError',
transport: 'IrdTransportError',
config: 'IrdConfigError',
domainDenied: 'IrdDomainDeniedError',
timeout: 'IrdTimeoutError',
jobFailed: 'IrdJobFailedError',
uploadFailed: 'IrdUploadFailedError',
};
const tagged = (message, fields, cause) => {
const error = cause === undefined ? new Error(message) : new Error(message, { cause });
return Object.assign(error, { name: NAMES[fields.kind] }, fields);
};
/** Error returned by the ird API (non-2xx HTTP status). */
export const apiError = (message, code, status, response) => tagged(message, { kind: 'api', code, status, response });
/** Low-level failure talking to the API (connection failure, non-JSON body, ...). */
export const transportError = (message, detail, cause) => tagged(message, { kind: 'transport', detail }, cause);
/** Invalid client configuration or call arguments. */
export const configError = (message, detail) => tagged(message, { kind: 'config', detail });
/**
* Client-side domain gate violation: the operation targets a domain that the
* client's deniedDomains/allowedDomains configuration forbids. Thrown before
* any request reaches the API.
*/
export const domainDenied = (domain, matchedPattern, op) => tagged(`Domain gate: ${domain ?? '(unknown domain)'} may not be touched by ${op}`, {
kind: 'domainDenied',
domain,
matchedPattern,
op,
});
/** A polling helper ran past its deadline; `last` is the last response seen. */
export const timeoutError = (message, last) => tagged(message, { kind: 'timeout', last });
/** An async job reached a terminal failed status. */
export const jobFailed = (message, job) => tagged(message, { kind: 'jobFailed', job });
/** An IPFS upload failed or expired. */
export const uploadFailed = (message, upload) => tagged(message, { kind: 'uploadFailed', upload });
const KINDS = new Set(Object.keys(NAMES));
export const isIrdError = (e) => e instanceof Error && KINDS.has(e.kind);
export const isApiError = (e) => isIrdError(e) && e.kind === 'api';
export const isTransportError = (e) => isIrdError(e) && e.kind === 'transport';
export const isConfigError = (e) => isIrdError(e) && e.kind === 'config';
export const isDomainDeniedError = (e) => isIrdError(e) && e.kind === 'domainDenied';
export const isTimeoutError = (e) => isIrdError(e) && e.kind === 'timeout';
export const isJobFailedError = (e) => isIrdError(e) && e.kind === 'jobFailed';
export const isUploadFailedError = (e) => isIrdError(e) && e.kind === 'uploadFailed';