mirror of
https://github.com/fluxerapp/fluxer
synced 2026-10-17 21:15:32 +09:00
48 lines
1.9 KiB
TypeScript
48 lines
1.9 KiB
TypeScript
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
|
|
import type {HttpError} from '@app/features/platform/types/EndpointError';
|
|
|
|
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
}
|
|
|
|
function parseSeconds(value: unknown): number | null {
|
|
if (typeof value !== 'number' || !Number.isFinite(value) || value <= 0) return null;
|
|
return value;
|
|
}
|
|
|
|
function parseNestedSeconds(body: Record<string, unknown> | undefined): number | null {
|
|
if (body === undefined || !isRecord(body.details)) return null;
|
|
const retry = body.details.retry;
|
|
if (!isRecord(retry)) return null;
|
|
return parseSeconds(retry.after_seconds);
|
|
}
|
|
|
|
function parseHeaderSeconds(value: string | undefined): number | null {
|
|
if (value === undefined || value.trim() === '') return null;
|
|
const numeric = Number(value);
|
|
if (Number.isFinite(numeric)) return parseSeconds(numeric);
|
|
const deadline = Date.parse(value);
|
|
if (!Number.isFinite(deadline)) return null;
|
|
return parseSeconds((deadline - Date.now()) / 1000);
|
|
}
|
|
|
|
function resolveRetryAfterSeconds(error: HttpError): number | null {
|
|
const body = isRecord(error.body) ? error.body : undefined;
|
|
const nestedSeconds = parseNestedSeconds(body);
|
|
if (nestedSeconds !== null) return nestedSeconds;
|
|
const bodySeconds = body === undefined ? null : parseSeconds(body.retry_after);
|
|
if (bodySeconds !== null) return bodySeconds;
|
|
const headerSeconds = parseHeaderSeconds(error.responseHeaders['retry-after']);
|
|
if (headerSeconds !== null) return headerSeconds;
|
|
return parseHeaderSeconds(error.responseHeaders['x-ratelimit-reset-after']);
|
|
}
|
|
|
|
export function resolveRetryAfterMs(error: HttpError): number | null {
|
|
const retryAfterSeconds = resolveRetryAfterSeconds(error);
|
|
if (retryAfterSeconds === null) return null;
|
|
const retryAfterMs = Math.ceil(retryAfterSeconds * 1000);
|
|
if (!Number.isSafeInteger(retryAfterMs)) return null;
|
|
return retryAfterMs;
|
|
}
|