ModReleaser/src/lib/modrinth/client.ts
2026-07-17 17:00:05 +08:00

64 lines
1.9 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { isPublishDryRun, interceptUpload } from "../utils/dryRun";
import { readErrorBody, summarizeFormData } from "../utils/fetch";
/** Modrinth API v2 的基础请求客户端,封装鉴权与 User-Agent。 */
export class ModrinthClient {
private base = "https://api.modrinth.com/v2";
private token: string;
private userAgent?: string;
constructor(token: string, userAgent?: string) {
this.token = token;
this.userAgent = userAgent;
}
/** 构造通用请求头Authorization以及可选的 User-Agent。 */
private headers(): Record<string, string> {
const h: Record<string, string> = {
Authorization: this.token,
};
if (this.userAgent) {
h["User-Agent"] = this.userAgent;
}
return h;
}
/** 发送 GET 请求并解析 JSON 响应体。 */
async get<T>(path: string): Promise<T> {
const res = await fetch(`${this.base}${path}`, {
headers: this.headers(),
});
if (!res.ok) {
const body = await readErrorBody(res);
throw new Error(
`Modrinth API GET ${path} failed: ${res.status} ${res.statusText}\n${body}`,
);
}
return res.json() as Promise<T>;
}
/**
* 发送 POST 请求body 为 FormDatamultipart/form-data
* 不手动设置 Content-Type让 fetch 自动生成含 boundary 的头。
*/
async post<T>(path: string, body: FormData): Promise<T> {
const url = `${this.base}${path}`;
if (isPublishDryRun()) {
return interceptUpload("Modrinth", "POST", url, body) as Promise<T>;
}
const res = await fetch(url, {
method: "POST",
headers: this.headers(),
body,
});
if (!res.ok) {
const reqBody = summarizeFormData(body);
const resBody = await readErrorBody(res);
throw new Error(
`Modrinth API POST ${path} failed: ${res.status} ${res.statusText}\n\n--Request--:\n${reqBody}\n\n--Response--:\n${resBody}`,
);
}
return res.json() as Promise<T>;
}
}