first
This commit is contained in:
@@ -0,0 +1,68 @@
|
||||
import axios, { AxiosError, Method } from "axios";
|
||||
|
||||
export interface SapB1ErrorDetails {
|
||||
status?: number;
|
||||
code?: string;
|
||||
message?: string;
|
||||
method?: string;
|
||||
url?: string;
|
||||
retryable?: boolean;
|
||||
cause?: unknown;
|
||||
}
|
||||
|
||||
export class SapB1Error extends Error {
|
||||
public readonly status?: number;
|
||||
public readonly code?: string;
|
||||
public readonly method?: string;
|
||||
public readonly url?: string;
|
||||
public readonly retryable: boolean;
|
||||
public override readonly cause?: unknown;
|
||||
|
||||
public constructor(details: SapB1ErrorDetails) {
|
||||
super(details.message || "SAP Business One Service Layer request failed");
|
||||
this.name = "SapB1Error";
|
||||
this.status = details.status;
|
||||
this.code = details.code;
|
||||
this.method = details.method;
|
||||
this.url = details.url;
|
||||
this.retryable = details.retryable ?? false;
|
||||
this.cause = details.cause;
|
||||
}
|
||||
}
|
||||
|
||||
// Shared normalizer so every SAP call (including login) surfaces the SAP status/code
|
||||
// and message when the Service Layer actively rejected the request, and falls back to
|
||||
// the transport-level message (ECONNREFUSED, timeout, TLS, ...) otherwise. This is what
|
||||
// lets a caller tell "SAP rejected it" apart from "we never reached SAP".
|
||||
export function toSapB1Error(
|
||||
error: unknown,
|
||||
method?: Method,
|
||||
path?: string,
|
||||
fallbackMessage = "SAP B1 request failed"
|
||||
): SapB1Error {
|
||||
if (error instanceof SapB1Error) {
|
||||
return error;
|
||||
}
|
||||
|
||||
if (axios.isAxiosError(error)) {
|
||||
const axiosError = error as AxiosError<{ error?: { code?: string; message?: { value?: string } | string } }>;
|
||||
const status = axiosError.response?.status;
|
||||
const sapError = axiosError.response?.data?.error;
|
||||
const message =
|
||||
typeof sapError?.message === "string"
|
||||
? sapError.message
|
||||
: sapError?.message?.value || axiosError.message || fallbackMessage;
|
||||
|
||||
return new SapB1Error({
|
||||
status,
|
||||
code: sapError?.code,
|
||||
message,
|
||||
method,
|
||||
url: path,
|
||||
retryable: status === 408 || status === 429 || (status !== undefined && status >= 500),
|
||||
cause: error
|
||||
});
|
||||
}
|
||||
|
||||
return new SapB1Error({ message: fallbackMessage, method, url: path, cause: error });
|
||||
}
|
||||
Reference in New Issue
Block a user