feat(claude): merge client anthropic-beta flags and forward rate-limit headers

This commit is contained in:
DavidArthurCole
2026-09-26 11:07:46 +07:00
parent 4a57df8bf9
commit dc198dff1f
9 changed files with 122 additions and 13 deletions

View File

@@ -27,12 +27,13 @@ export function buildErrorBody(statusCode, message) {
* @param {string} message - Error message
* @returns {Response} HTTP Response object
*/
export function errorResponse(statusCode, message) {
export function errorResponse(statusCode, message, extraHeaders = null) {
return new Response(JSON.stringify(buildErrorBody(statusCode, message)), {
status: statusCode,
headers: {
"Content-Type": "application/json",
"Access-Control-Allow-Origin": "*"
"Access-Control-Allow-Origin": "*",
...extraHeaders
}
});
}
@@ -95,13 +96,13 @@ export async function parseUpstreamError(response, executor = null) {
* @param {number} [resetsAtMs] - Optional precise cooldown expiry (ms epoch) for provider-specific quota errors
* @returns {{ success: false, status: number, error: string, response: Response, resetsAtMs?: number }}
*/
export function createErrorResult(statusCode, message, resetsAtMs) {
export function createErrorResult(statusCode, message, resetsAtMs, extraHeaders = null) {
return {
success: false,
status: statusCode,
error: message,
resetsAtMs,
response: errorResponse(statusCode, message)
response: errorResponse(statusCode, message, extraHeaders)
};
}
@@ -113,7 +114,7 @@ export function createErrorResult(statusCode, message, resetsAtMs) {
* @param {string} retryAfterHuman - Human-readable retry info e.g. "reset after 30s"
* @returns {Response}
*/
export function unavailableResponse(statusCode, message, retryAfter, retryAfterHuman) {
export function unavailableResponse(statusCode, message, retryAfter, retryAfterHuman, extraHeaders = null) {
const retryAfterSec = Math.max(Math.ceil((new Date(retryAfter).getTime() - Date.now()) / 1000), 1);
const msg = `${message} (${retryAfterHuman})`;
return new Response(
@@ -121,8 +122,10 @@ export function unavailableResponse(statusCode, message, retryAfter, retryAfterH
{
status: statusCode,
headers: {
...extraHeaders,
"Content-Type": "application/json",
"Retry-After": String(retryAfterSec)
// Intentionally mis-cased to prevent duplicate headers
"retry-after": String(retryAfterSec)
}
}
);

View File

@@ -0,0 +1,12 @@
const FORWARDED = new Set(["retry-after", "x-should-retry"]);
const FORWARDED_PREFIX = "anthropic-ratelimit-";
export function upstreamResponseHeaders(headers) {
const out = {};
if (typeof headers?.forEach !== "function") return out;
headers.forEach((value, name) => {
const key = name.toLowerCase();
if (FORWARDED.has(key) || key.startsWith(FORWARDED_PREFIX)) out[key] = value;
});
return out;
}