import { APIStatusError } from '@moonshot-ai/kosong'; import { describe, expect, it } from 'vitest'; import { toKimiErrorPayload } from '#/errors/serialize'; const NGINX_413_HTML = '413 \r\n413 Request Entity Too Large\r\n' + '\r\n

413 Request Entity Too Large

\r\n' + '
nginx
\r\n\r\n\r\n'; describe('toKimiErrorPayload — APIStatusError message sanitization', () => { it('extracts the from an nginx 413 HTML body and strips CR', () => { const payload = toKimiErrorPayload(new APIStatusError(413, NGINX_413_HTML)); expect(payload.code).toBe('provider.api_error'); expect(payload.message).toBe('413 Request Entity Too Large'); expect(payload.details).toMatchObject({ statusCode: 413 }); }); it('extracts the <title> from other nginx HTML error pages', () => { const html = '<html>\r\n<head><title>502 Bad Gateway\r\n' + '

502 Bad Gateway

'; const payload = toKimiErrorPayload(new APIStatusError(502, html)); expect(payload.message).toBe('502 Bad Gateway'); }); it('leaves a plain-text message unchanged', () => { const payload = toKimiErrorPayload(new APIStatusError(500, 'Internal Server Error')); expect(payload.message).toBe('Internal Server Error'); }); it('strips carriage returns from a non-HTML message', () => { const payload = toKimiErrorPayload(new APIStatusError(500, 'line1\r\nline2\r')); expect(payload.message).toBe('line1\nline2'); }); it('falls back to the original message when the is empty', () => { const html = '<html><head><title> x'; const payload = toKimiErrorPayload(new APIStatusError(500, html)); expect(payload.message).toContain(''); }); it('does not affect 429 / 401 code mapping, only the message', () => { const html = '429 Too Many Requests'; expect(toKimiErrorPayload(new APIStatusError(429, html)).code).toBe('provider.rate_limit'); expect(toKimiErrorPayload(new APIStatusError(401, 'Unauthorized')).code).toBe( 'provider.auth_error', ); }); });