/
githubmirror
/
wp-calypso
Обзор
Документация
Войти
/
githubmirror
/
wp-calypso
Код
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
trunk
packages/api-core/src/reader-fediverse/errors.ts
104 строки
3 KB
Matthias Pfefferle
Reader Fediverse: slice 2 — standalone publish composer (#110637)
12 май 2026, 12:39
Не верифицирован
12 май 2026, 12:39
1255859
Код
Авторство
О чём код?
/** * Narrow error union for the Reader Fediverse surface. * * Backend (CM-684) emits exactly two custom codes today: * - `not_authenticated` (401) on the permission callback * - `connection_not_found` (404) on `GET /connections/{id}` * * Generic transients (`rate_limited`, `upstream_unavailable`, `unknown`) * are carried for future slices when downstream calls hit federated * remotes — keeping them in the union now means the per-protocol UI * can render the same error vocabulary already used by the like / * repost adapters. * * Unknown wpcom error codes collapse to `{ kind: 'unknown', cause }` * rather than throwing or losing the original error object. */ export type FediverseError = | { kind: 'auth_required' } | { kind: 'connection_not_found' } | { kind: 'not_found' } | { kind: 'rate_limited'; retry_after?: number } | { kind: 'upstream_unavailable' } // Slice 2 composer write paths add bad-request flavours surfaced by the // `POST /posts` endpoint. The classifier reads the wpcom body-level // `error` code to pick the right variant; all 400-flavour errors map // here. | { kind: 'bad_request'; message?: string } | { kind: 'text_too_long' } | { kind: 'summary_too_long' } | { kind: 'visibility_invalid' } | { kind: 'publish_disabled' } | { kind: 'target_unavailable' } | { kind: 'unknown'; cause: unknown }; interface WpErrorLike { error?: string; code?: string; statusCode?: number; status?: number; message?: string; data?: { retry_after?: number } & Record< string, unknown >; } function isWpErrorLike( e: unknown ): e is WpErrorLike { if ( typeof e !== 'object' || e === null ) { return false; } const obj = e as object; return 'error' in obj || 'code' in obj || 'statusCode' in obj || 'status' in obj; } export function classifyFediverseError( raw: unknown ): FediverseError { if ( ! isWpErrorLike( raw ) ) { return { kind: 'unknown', cause: raw }; } const rateLimited = ( source: WpErrorLike ): FediverseError => { const retryAfter = source.data?.retry_after; return typeof retryAfter === 'number' ? { kind: 'rate_limited', retry_after: retryAfter } : { kind: 'rate_limited' }; }; const errorCode = raw.error ?? raw.code; switch ( errorCode ) { case 'not_authenticated': return { kind: 'auth_required' }; case 'connection_not_found': return { kind: 'connection_not_found' }; // Slice 2 composer write paths. case 'fediverse_text_too_long': case 'reader_fediverse_text_too_long': return { kind: 'text_too_long' }; case 'fediverse_summary_too_long': case 'reader_fediverse_summary_too_long': return { kind: 'summary_too_long' }; case 'fediverse_visibility_invalid': case 'reader_fediverse_visibility_invalid': return { kind: 'visibility_invalid' }; case 'fediverse_publish_disabled': case 'reader_fediverse_publish_disabled': return { kind: 'publish_disabled' }; case 'fediverse_target_unavailable': case 'reader_fediverse_target_unavailable': return { kind: 'target_unavailable' }; case 'fediverse_bad_request': case 'reader_fediverse_bad_request': return { kind: 'bad_request', message: raw.message }; } const status = raw.statusCode ?? raw.status; switch ( status ) { case 401: return { kind: 'auth_required' }; case 403: return { kind: 'publish_disabled' }; case 404: return { kind: 'not_found' }; case 429: return rateLimited( raw ); case 502: case 503: case 504: return { kind: 'upstream_unavailable' }; } return { kind: 'unknown', cause: raw }; }