mirror of
https://github.com/YuzuZensai/VRC-Circle.git
synced 2026-09-14 03:10:01 +00:00
60 lines
1.8 KiB
TypeScript
60 lines
1.8 KiB
TypeScript
import type { ApiError, ApiErrorCode, IpcResult } from "../../shared/types/result";
|
|||
|
|
|
||
|
|
interface HttpLike {
|
||
|
|
status?: number;
|
||
|
|
statusCode?: number;
|
||
|
|
status_code?: number;
|
||
|
|
response?: { status?: number; headers?: Record<string, string> };
|
||
|
|
headers?: Record<string, string>;
|
||
|
|
message?: string;
|
||
|
|
code?: ApiErrorCode;
|
||
|
|
methods?: ("totp" | "emailOtp")[];
|
||
|
|
error?: { status_code?: number; statusCode?: number; status?: number };
|
||
|
|
}
|
||
|
|
|
||
|
|
function statusOf(e: HttpLike): number | undefined {
|
||
|
|
return (
|
||
|
|
e.status ??
|
||
|
|
e.statusCode ??
|
||
|
|
e.status_code ??
|
||
|
|
e.response?.status ??
|
||
|
|
e.error?.status_code ??
|
||
|
|
e.error?.statusCode ??
|
||
|
|
e.error?.status
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
export function httpStatusOf(err: unknown): number | undefined {
|
||
|
|
return statusOf((err ?? {}) as HttpLike);
|
||
|
|
}
|
||
|
|
|
||
|
|
function retryAfterOf(e: HttpLike): number | undefined {
|
||
|
|
const raw = e.response?.headers?.["retry-after"] ?? e.headers?.["retry-after"];
|
||
|
|
const n = raw != null ? Number(raw) : NaN;
|
||
|
|
return Number.isFinite(n) ? n : undefined;
|
||
|
|
}
|
||
|
|
|
||
|
|
export function toApiError(err: unknown): ApiError {
|
||
|
|
const e = (err ?? {}) as HttpLike;
|
||
|
|
const status = statusOf(e);
|
||
|
|
const message = e.message ?? "Unexpected error";
|
||
|
|
|
||
|
|
if (e.code) return { code: e.code, message, methods: e.methods };
|
||
|
|
|
||
|
|
let code: ApiErrorCode = "unknown";
|
||
|
|
if (status === 401) code = "unauthorized";
|
||
|
|
else if (status === 404) code = "not_found";
|
||
|
|
else if (status === 429) code = "rate_limited";
|
||
|
|
else if (status === undefined && /network|fetch|ENOTFOUND|ECONN/i.test(message)) code = "network";
|
||
|
|
|
||
|
|
return { code, message, retryAfter: retryAfterOf(e) };
|
||
|
|
}
|
||
|
|
|
||
|
|
export async function guard<T>(fn: () => Promise<T>): Promise<IpcResult<T>> {
|
||
|
|
try {
|
||
|
|
return { ok: true, data: await fn() };
|
||
|
|
} catch (err) {
|
||
|
|
return { ok: false, error: toApiError(err) };
|
||
|
|
}
|
||
|
|
}
|