| @@ -1,11 +1,19 @@ | ||
| 1 | 1 | import { __ } from '@wordpress/i18n' |
| 2 | -import { isAxiosError } from 'axios' | |
| 2 | +import { isAxiosError, isCancel } from 'axios' | |
| 3 | 3 | |
| 4 | 4 | export const handleUnknownError = (error: unknown) => { |
| 5 | 5 | console.error(error) |
| 6 | 6 | } |
| 7 | 7 | |
| 8 | +/** | |
| 9 | + * Whether a rejection came from the caller aborting the request rather than | |
| 10 | + * from a failure — axios rejects cancelled requests with no response attached, | |
| 11 | + * so these must not be surfaced to the user as errors. | |
| 12 | + */ | |
| 13 | +export const isAbortError = (error: unknown): boolean => | |
| 14 | + isCancel(error) || error instanceof DOMException && 'AbortError' === error.name | |
| 15 | + | |
| 8 | 16 | export const unpackErrorResponse = (error: unknown): string => { |
| 9 | 17 | if (isAxiosError(error)) { |
| 10 | 18 | if (error.response) { |
| 11 | 19 | const responseData: unknown = error.response.data |
| @@ -18,5 +26,38 @@ | ||
| 18 | 26 | return error.message |
| 19 | 27 | } |
| 20 | 28 | |
| 21 | 29 | return __('An unknown error occurred.', 'code-snippets') |
| 30 | +} | |
| 31 | + | |
| 32 | +/** | |
| 33 | + * Explain a failed request in terms the reader can act on. | |
| 34 | + * | |
| 35 | + * An expired session is the common case worth naming: the snippet editor is a | |
| 36 | + * screen people leave open, and once the session lapses WordPress rejects every | |
| 37 | + * write with a 403 that says only "Cookie check failed". Reporting the raw | |
| 38 | + * status left people believing the plugin had ignored them. | |
| 39 | + */ | |
| 40 | +export const describeRequestError = (error: unknown): string => { | |
| 41 | + if (!isAxiosError(error)) { | |
| 42 | + return unpackErrorResponse(error) | |
| 43 | + } | |
| 44 | + | |
| 45 | + if (!error.response) { | |
| 46 | + return __( | |
| 47 | + 'The request did not reach your site. Check your connection, or whether a security plugin is blocking it.', | |
| 48 | + 'code-snippets' | |
| 49 | + ) | |
| 50 | + } | |
| 51 | + | |
| 52 | + const data: unknown = error.response.data | |
| 53 | + const code = data && 'object' === typeof data && 'code' in data ? String(data.code) : '' | |
| 54 | + | |
| 55 | + if ('rest_cookie_invalid_nonce' === code || 'rest_not_logged_in' === code) { | |
| 56 | + return __( | |
| 57 | + 'You have been signed out, so nothing was saved. Sign in again in another tab, then save. Your changes are still here.', | |
| 58 | + 'code-snippets' | |
| 59 | + ) | |
| 60 | + } | |
| 61 | + | |
| 62 | + return unpackErrorResponse(error) | |
| 22 | 63 | } |