mirror of
https://github.com/samuelthomas2774/nxapi.git
synced 2026-07-04 09:01:00 -05:00
105 lines
3.5 KiB
TypeScript
105 lines
3.5 KiB
TypeScript
import * as util from 'node:util';
|
|
import { errors } from 'undici';
|
|
import createDebug from './debug.js';
|
|
import Loop, { LoopResult } from './loop.js';
|
|
import { TemporaryErrorSymbol } from './misc.js';
|
|
import { ErrorResponse } from '../api/util.js';
|
|
|
|
const debug = createDebug('nxapi:util:errors');
|
|
|
|
export class ErrorDescription {
|
|
constructor(
|
|
readonly type: string,
|
|
readonly message: string,
|
|
) {}
|
|
|
|
static getErrorDescription(err: Error | unknown) {
|
|
if (err instanceof HasErrorDescription) {
|
|
const description = err[ErrorDescriptionSymbol];
|
|
|
|
if (description) {
|
|
return description.message +
|
|
(err instanceof Error ? '\n\n--\n\n' + util.inspect(err) : '');
|
|
}
|
|
}
|
|
|
|
if (err instanceof Error) {
|
|
return util.inspect(err);
|
|
}
|
|
|
|
return util.inspect(err, {compact: true});
|
|
}
|
|
}
|
|
|
|
export const ErrorDescriptionSymbol = Symbol('ErrorDescription');
|
|
|
|
export abstract class HasErrorDescription {
|
|
abstract get [ErrorDescriptionSymbol](): ErrorDescription | null;
|
|
}
|
|
|
|
Object.defineProperty(HasErrorDescription, Symbol.hasInstance, {
|
|
configurable: true,
|
|
value: (instance: HasErrorDescription) => {
|
|
return instance && ErrorDescriptionSymbol in instance;
|
|
},
|
|
});
|
|
|
|
export const temporary_system_errors = {
|
|
'ETIMEDOUT': 'request timed out',
|
|
'ENOTFOUND': null,
|
|
'EAI_AGAIN': 'name resolution failed',
|
|
'ECONNRESET': 'connection reset',
|
|
'ENETUNREACH': 'network unreachable',
|
|
};
|
|
export const temporary_http_errors = [
|
|
502, // Bad Gateway
|
|
503, // Service Unavailable
|
|
504, // Gateway Timeout
|
|
|
|
// Non-standard Cloudflare status codes
|
|
521, // Web Server Is Down
|
|
522, // Connection Timed Out
|
|
523, // Origin Is Unreachable
|
|
524, // A Timeout Occurred
|
|
530, // Unknown (1xxx error)
|
|
];
|
|
|
|
export async function handleError(
|
|
err: ErrorResponse | NodeJS.ErrnoException,
|
|
loop: Loop,
|
|
): Promise<LoopResult> {
|
|
if (TemporaryErrorSymbol in err && err[TemporaryErrorSymbol]) {
|
|
debug('Temporary error, waiting %ds before retrying', loop.update_interval, err);
|
|
|
|
return LoopResult.OK;
|
|
} else if (err instanceof errors.ConnectTimeoutError) {
|
|
debug('Request timeout (connect), waiting %ds before retrying', loop.update_interval, err);
|
|
|
|
return LoopResult.OK;
|
|
} else if (err instanceof errors.HeadersTimeoutError) {
|
|
debug('Request timeout (headers), waiting %ds before retrying', loop.update_interval, err);
|
|
|
|
return LoopResult.OK;
|
|
} else if (err instanceof errors.BodyTimeoutError) {
|
|
debug('Request timeout (body), waiting %ds before retrying', loop.update_interval, err);
|
|
|
|
return LoopResult.OK;
|
|
} else if (err instanceof errors.RequestAbortedError) {
|
|
debug('Request aborted, waiting %ds before retrying', loop.update_interval, err);
|
|
|
|
return LoopResult.OK;
|
|
} else if ('code' in err && (err as any).type === 'system' && err.code && err.code in temporary_system_errors) {
|
|
const desc = temporary_system_errors[err.code as keyof typeof temporary_system_errors];
|
|
debug('Request error%s, waiting %ds before retrying', desc ? ' - ' + desc : '', loop.update_interval, err);
|
|
|
|
return LoopResult.OK;
|
|
} else if (err instanceof ErrorResponse && temporary_http_errors.includes(err.response.status)) {
|
|
debug('Request error - HTTP %s (%s), waiting %ds before retrying',
|
|
err.response.status, err.response.statusText, loop.update_interval, err);
|
|
|
|
return LoopResult.OK;
|
|
} else {
|
|
throw err;
|
|
}
|
|
}
|