(
error: unknown,
context: string,
options?: HandleApiErrorOptions,
)
| 70 | * @param options Optional callbacks and behaviour overrides |
| 71 | */ |
| 72 | export function handleApiError( |
| 73 | error: unknown, |
| 74 | context: string, |
| 75 | options?: HandleApiErrorOptions, |
| 76 | ): void { |
| 77 | // User-initiated abort — nothing to do |
| 78 | if (error instanceof DOMException && error.name === 'AbortError') { |
| 79 | return; |
| 80 | } |
| 81 | |
| 82 | let message: string; |
| 83 | let detail: string | undefined; |
| 84 | let diagnostics: any; |
| 85 | |
| 86 | if (error instanceof ApiRequestError) { |
| 87 | message = getErrorMessage(error.apiError); |
| 88 | detail = [error.apiError.detail, error.apiError.request_id ? `Request ID: ${error.apiError.request_id}` : undefined] |
| 89 | .filter(Boolean) |
| 90 | .join('\n'); |
| 91 | if (!detail) detail = undefined; |
| 92 | diagnostics = error.apiError; |
| 93 | |
| 94 | if (error.isAuthError && options?.onAuth) { |
| 95 | options.onAuth(); |
| 96 | return; |
| 97 | } |
| 98 | if (error.isRetryable && options?.onRetryable) { |
| 99 | options.onRetryable(); |
| 100 | return; |
| 101 | } |
| 102 | } else if (error instanceof Error) { |
| 103 | message = error.message; |
| 104 | } else if (isSerializedError(error)) { |
| 105 | message = error.message; |
| 106 | } else { |
| 107 | message = String(error); |
| 108 | } |
| 109 | |
| 110 | console.error(`[${context}] ${message}`, error); |
| 111 | |
| 112 | if (!options?.silent) { |
| 113 | store.dispatch(dfActions.addMessages({ |
| 114 | type: 'error', |
| 115 | component: context, |
| 116 | timestamp: Date.now(), |
| 117 | value: message, |
| 118 | detail, |
| 119 | diagnostics, |
| 120 | })); |
| 121 | } |
| 122 | } |
no test coverage detected