nxapi/src/api/util.ts
2023-07-13 00:00:04 +01:00

71 lines
2.2 KiB
TypeScript

import * as util from 'node:util';
import { Response as UndiciResponse } from 'undici';
export const ResponseSymbol = Symbol('Response');
const ErrorResponseSymbol = Symbol('IsErrorResponse');
export interface ResponseData<R> {
[ResponseSymbol]: R;
}
export type HasResponse<T, R> = T & ResponseData<R>;
export function defineResponse<T, R>(data: T, response: R) {
Object.defineProperty(data, ResponseSymbol, {enumerable: false, value: response});
return data as HasResponse<T, R>;
}
export class ErrorResponse<T = unknown> extends Error {
readonly body: string | undefined;
readonly data: T | undefined = undefined;
constructor(
message: string,
readonly response: Response | UndiciResponse,
body?: string | ArrayBuffer | T
) {
super(message);
Object.defineProperty(this, ErrorResponseSymbol, {enumerable: false, value: ErrorResponseSymbol});
if (body instanceof ArrayBuffer) {
body = (new TextDecoder()).decode(body);
}
if (typeof body === 'string') {
this.body = body;
try {
this.data = body ? JSON.parse(body) : undefined;
} catch (err) {}
} else if (typeof body !== 'undefined') {
this.data = body;
}
const stack = this.stack ?? (this.name + ': ' + message);
const lines = stack.split('\n');
const head = lines.shift()!;
Object.defineProperty(this, 'stack', {
value: head + '\n' +
' from ' + response.url + ' (' + response.status + ' ' + response.statusText + ')\n' +
' ' + util.inspect(this.data ? this.data : this.body, {
compact: true,
maxStringLength: 100,
}).replace(/\n/g, '\n ') +
(lines.length ? '\n' + lines.join('\n') : ''),
});
}
static async fromResponse(response: UndiciResponse, message: string) {
const body = await response.arrayBuffer();
return new this(message, response, body);
}
}
Object.defineProperty(ErrorResponse, Symbol.hasInstance, {
configurable: true,
value: (instance: ErrorResponse) => {
return instance && ErrorResponseSymbol in instance;
},
});