import { APIStatusError } from '@moonshot-ai/kosong';
import { describe, expect, it } from 'vitest';
import { toKimiErrorPayload } from '#/errors/serialize';
const NGINX_413_HTML =
'413 \r\n
413 Request Entity Too Large\r\n' +
'\r\n413 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 from other nginx HTML error pages', () => {
const html =
'\r\n502 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 = ' 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',
);
});
});