408 lines
15 KiB
Markdown
408 lines
15 KiB
Markdown
|
|
# Modrinth 新建版本 API 使用文档
|
|||
|
|
|
|||
|
|
本文档详细描述如何通过 Modrinth API 创建一个新版本,包括上传模组主文件(`.jar`)和一个 `-sources.jar` 附属文件。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 基本信息
|
|||
|
|
|
|||
|
|
| 项目 | 内容 |
|
|||
|
|
|------|------|
|
|||
|
|
| **端点** | `POST /version` |
|
|||
|
|
| **生产环境** | `https://api.modrinth.com/v2/version` |
|
|||
|
|
| **测试环境** | `https://staging-api.modrinth.com/v2/version` |
|
|||
|
|
| **Content-Type** | `multipart/form-data` |
|
|||
|
|
| **认证** | 必需 — Personal Access Token (PAT) |
|
|||
|
|
| **所需 Scope** | `VERSION_CREATE` |
|
|||
|
|
| **成功响应码** | `200` |
|
|||
|
|
| **成功响应体** | [Version](#响应格式) 对象 |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 认证
|
|||
|
|
|
|||
|
|
所有创建数据的请求都需要认证。你需要一个 **Personal Access Token**(PAT),在 [Modrinth 用户设置](https://modrinth.com/settings/account) 中生成。
|
|||
|
|
|
|||
|
|
创建版本需要 PAT 具有 `VERSION_CREATE` 权限范围。
|
|||
|
|
|
|||
|
|
将 Token 放在 `Authorization` 请求头中:
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
Authorization: mrp_RNtLRSPmGj2pd1v1ubi52nX7TJJM9sznrmwhAuj511oe4t1jAqAQ3D6Wc8Ic
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
> **注意:** 需要在 `upload.md` 中提供有效的 Token。
|
|||
|
|
|
|||
|
|
同时,Modrinth **要求**提供一个可唯一标识的 `User-Agent` 请求头:
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
User-Agent: github_username/project_name/1.0.0 (contact@example.com)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 请求格式
|
|||
|
|
|
|||
|
|
请求是一个 **multipart/form-data** 请求,必须包含至少两个表单字段:
|
|||
|
|
|
|||
|
|
- **`data`**:一个 JSON 字符串,包含版本元数据(见下方 [data JSON 结构](#data-json-结构))。
|
|||
|
|
- **一个或多个文件字段**:包含要上传的 `.jar`、`.mrpack`、`.zip` 或 `.litemod` 文件。文件字段名可自定义。
|
|||
|
|
|
|||
|
|
### 重要概念区分:multipart 字段名 vs 文件名
|
|||
|
|
|
|||
|
|
在 multipart 请求中,每个文件字段都有**两个不同的名字**:
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
-F "main-file=@./build/libs/my-mod-1.0.0.jar"
|
|||
|
|
^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^
|
|||
|
|
multipart 字段名 (field name) 文件名 (filename)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
- **multipart 字段名**(如 `main-file`):在请求体中标识这一部分数据的 key,由你自定义。
|
|||
|
|
- **文件名**(如 `my-mod-1.0.0.jar`):被上传文件的原始名称。
|
|||
|
|
|
|||
|
|
> **关键规则:`file_parts`、`primary_file`、`file_types` 的 key 全部使用 multipart 字段名,而不是文件名。**
|
|||
|
|
|
|||
|
|
### `file_parts` — 声明有哪些文件
|
|||
|
|
|
|||
|
|
在 `data` JSON 的 `file_parts` 数组中列出所有承载文件的 **multipart 字段名**,并在 `primary_file` 中指定哪个是主文件。
|
|||
|
|
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"file_parts": ["main-file", "sources-file", "dev-file"],
|
|||
|
|
"primary_file": "main-file"
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### `file_types` — 标记附属文件类型
|
|||
|
|
|
|||
|
|
`file_types` 是一个 **对象(map)**,**key 是 multipart 字段名**(与 `file_parts` 中的值一致),value 是该文件的类型枚举值。用于标记 `-sources.jar`、`-dev.jar` 等附属文件。
|
|||
|
|
|
|||
|
|
可用的文件类型(`FileTypeEnum`):
|
|||
|
|
|
|||
|
|
| 值 | 含义 |
|
|||
|
|
|----|------|
|
|||
|
|
| `required-resource-pack` | 必需资源包 |
|
|||
|
|
| `optional-resource-pack` | 可选资源包 |
|
|||
|
|
| `sources-jar` | 源代码 JAR |
|
|||
|
|
| `dev-jar` | 开发版 JAR(包含未混淆的类) |
|
|||
|
|
| `javadoc-jar` | Javadoc JAR |
|
|||
|
|
| `unknown` | 未知类型 |
|
|||
|
|
| `signature` | 签名文件 |
|
|||
|
|
|
|||
|
|
**标记 sources.jar 的示例:**
|
|||
|
|
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"file_types": {
|
|||
|
|
"sources-file": "sources-jar"
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
> 上例中 `"sources-file"` 是 multipart 字段名,需要在 `file_parts` 中同步出现。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## data JSON 结构
|
|||
|
|
|
|||
|
|
`data` 字段的值是一个 JSON 字符串,对应 `CreatableVersion` schema,它扩展了 `BaseVersion`。
|
|||
|
|
|
|||
|
|
### 顶层结构(`CreateVersionBody`)
|
|||
|
|
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"data": "{ ... CreatableVersion JSON ... }"
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### CreatableVersion 字段一览
|
|||
|
|
|
|||
|
|
#### 必填字段
|
|||
|
|
|
|||
|
|
| 字段 | 类型 | 说明 | 示例 |
|
|||
|
|
|------|------|------|------|
|
|||
|
|
| `project_id` | `string` | 目标项目的 ID(8 位 base62) | `"AABBCCDD"` |
|
|||
|
|
| `file_parts` | `string[]` | 所有承载文件的 **multipart 字段名** 列表 | `["main-file", "sources-file"]` |
|
|||
|
|
| `name` | `string` | 版本名称 | `"Version 1.0.0"` |
|
|||
|
|
| `version_number` | `string` | 版本号,建议遵循语义化版本 | `"1.0.0"` |
|
|||
|
|
| `game_versions` | `string[]` | 支持的 Minecraft 版本列表 | `["1.20.1", "1.20.4"]` |
|
|||
|
|
| `version_type` | `string` | 发布渠道:`release`、`beta`、`alpha` | `"release"` |
|
|||
|
|
| `loaders` | `string[]` | 支持的模组加载器列表 | `["fabric", "forge"]` |
|
|||
|
|
| `featured` | `boolean` | 是否为精选版本 | `false` |
|
|||
|
|
| `dependencies` | `object[]` | 依赖列表(可为空数组 `[]`) | 见下方 [依赖结构](#依赖结构) |
|
|||
|
|
|
|||
|
|
#### 可选字段
|
|||
|
|
|
|||
|
|
| 字段 | 类型 | 说明 | 示例 |
|
|||
|
|
|------|------|------|------|
|
|||
|
|
| `primary_file` | `string` | 主文件的 **multipart 字段名**。不提供时推断第一个文件为主文件 | `"main-file"` |
|
|||
|
|
| `changelog` | `string \| null` | 更新日志(Markdown/纯文本) | `"修复了若干 Bug"` |
|
|||
|
|
| `status` | `string` | 版本状态:`listed`、`archived`、`draft`、`unlisted`、`scheduled`、`unknown`。默认为 `listed` | `"listed"` |
|
|||
|
|
| `requested_status` | `string \| null` | 请求的状态(用于审核流程):`listed`、`archived`、`draft`、`unlisted` | `"listed"` |
|
|||
|
|
| `environment` | `string` | 目标环境,见下方枚举 | `"client_and_server"` |
|
|||
|
|
| `file_types` | `object` | **multipart 字段名** → 文件类型的映射 | `{"sources-file": "sources-jar"}` |
|
|||
|
|
|
|||
|
|
#### `environment` 枚举值
|
|||
|
|
|
|||
|
|
所有值来自 Modrinth 前端源码 [environments.ts](https://github.com/modrinth/code/blob/main/packages/ui/src/components/project/settings/environment/environments.ts)。以下按前端 UI 的层级结构排列,只有 **Server-side only** 和 **Client and server** 是带子选项的大类,其余为单选:
|
|||
|
|
|
|||
|
|
| 大类(前端 UI) | 子项标题 | API 值 | 说明 |
|
|||
|
|
|----------------|---------|--------|------|
|
|||
|
|
| *(无分类,单选)* | Unknown environment | `unknown` | 未指定或无法确定环境 |
|
|||
|
|
| Client-side only | — | `client_only` | 所有功能在客户端运行,兼容原版服务端 |
|
|||
|
|
| **Server-side only** | Works in singleplayer too | `server_only` | 所有功能在服务端运行,兼容原版客户端;也支持单人模式的内置服务端 |
|
|||
|
|
| | Dedicated server only | `dedicated_server_only` | 所有功能在服务端运行,兼容原版客户端;仅在专用服务器上工作 |
|
|||
|
|
| **Client and server** | Required on both | `client_and_server` | 客户端和服务端都必须安装 |
|
|||
|
|
| | Optional on client | `server_only_client_optional` | 主要为服务端功能,客户端安装可增强体验 |
|
|||
|
|
| | Optional on server | `client_only_server_optional` | 主要为客户端功能,服务端安装可增强体验 |
|
|||
|
|
| | Optional on both, works best when installed on both sides | `client_or_server_prefers_both` | 双方都装体验最佳 |
|
|||
|
|
| | Optional on both, works the same if installed on either side | `client_or_server` | 单独安装任一侧效果相同 |
|
|||
|
|
| Singleplayer only | — | `singleplayer_only` | 仅在单人模式或未连接多人服务器时可用 |
|
|||
|
|
|
|||
|
|
### 依赖结构
|
|||
|
|
|
|||
|
|
`dependencies` 数组中每个依赖对象至少需要 `dependency_type` 字段:
|
|||
|
|
|
|||
|
|
| 字段 | 类型 | 必填 | 说明 | 示例 |
|
|||
|
|
|------|------|------|------|------|
|
|||
|
|
| `dependency_type` | `string` | ✅ | 依赖类型:`required`、`optional`、`incompatible`、`embedded` | `"required"` |
|
|||
|
|
| `project_id` | `string \| null` | ❌ | 依赖的项目 ID | `"P7dR8mSH"` (Fabric API) |
|
|||
|
|
| `version_id` | `string \| null` | ❌ | 依赖的具体版本 ID;为 `null` 时匹配最新版 | `"IIJJKKLL"` |
|
|||
|
|
| `file_name` | `string \| null` | ❌ | 依赖文件名,主要用于整合包中的外部依赖 | `"fabric-api-0.92.0.jar"` |
|
|||
|
|
|
|||
|
|
> **注意:** `project_id` 和 `version_id` 二者至少提供一个,否则依赖关系无法解析。
|
|||
|
|
|
|||
|
|
**Fabric API 依赖示例:**
|
|||
|
|
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"dependency_type": "required",
|
|||
|
|
"project_id": "P7dR8mSH"
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 完整请求示例
|
|||
|
|
|
|||
|
|
以下是一个使用 cURL 上传一个主 jar 和一个 sources.jar 的完整请求。
|
|||
|
|
|
|||
|
|
### 准备
|
|||
|
|
|
|||
|
|
假设:
|
|||
|
|
- 项目 ID 为 `AABBCCDD`
|
|||
|
|
- 主文件为 `my-mod-1.0.0.jar`
|
|||
|
|
- 源代码文件为 `my-mod-1.0.0-sources.jar`
|
|||
|
|
|
|||
|
|
### cURL 命令
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
curl -X POST "https://api.modrinth.com/v2/version" \
|
|||
|
|
-H "Authorization: YOUR_PAT_TOKEN" \
|
|||
|
|
-H "User-Agent: your_username/your_project/1.0.0" \
|
|||
|
|
-F "data={
|
|||
|
|
\"project_id\": \"AABBCCDD\",
|
|||
|
|
\"file_parts\": [\"main-file\", \"sources-file\"],
|
|||
|
|
\"primary_file\": \"main-file\",
|
|||
|
|
\"name\": \"Version 1.0.0\",
|
|||
|
|
\"version_number\": \"1.0.0\",
|
|||
|
|
\"changelog\": \"## 更新内容\n\n- 新增了某某功能\n- 修复了某某 Bug\",
|
|||
|
|
\"dependencies\": [
|
|||
|
|
{
|
|||
|
|
\"dependency_type\": \"required\",
|
|||
|
|
\"project_id\": \"P7dR8mSH\"
|
|||
|
|
}
|
|||
|
|
],
|
|||
|
|
\"game_versions\": [\"1.20.1\", \"1.20.4\"],
|
|||
|
|
\"version_type\": \"release\",
|
|||
|
|
\"loaders\": [\"fabric\"],
|
|||
|
|
\"featured\": false,
|
|||
|
|
\"status\": \"listed\",
|
|||
|
|
\"environment\": \"client_and_server\",
|
|||
|
|
\"file_types\": {
|
|||
|
|
\"sources-file\": \"sources-jar\"
|
|||
|
|
}
|
|||
|
|
}" \
|
|||
|
|
-F "main-file=@./build/libs/my-mod-1.0.0.jar" \
|
|||
|
|
-F "sources-file=@./build/libs/my-mod-1.0.0-sources.jar"
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### Node.js (fetch) 示例
|
|||
|
|
|
|||
|
|
```js
|
|||
|
|
const fs = require("fs");
|
|||
|
|
|
|||
|
|
const TOKEN = "YOUR_PAT_TOKEN";
|
|||
|
|
const PROJECT_ID = "AABBCCDD";
|
|||
|
|
|
|||
|
|
const form = new FormData();
|
|||
|
|
|
|||
|
|
const metadata = {
|
|||
|
|
project_id: PROJECT_ID,
|
|||
|
|
file_parts: ["main-file", "sources-file"],
|
|||
|
|
primary_file: "main-file",
|
|||
|
|
name: "Version 1.0.0",
|
|||
|
|
version_number: "1.0.0",
|
|||
|
|
changelog: "## 更新内容\n\n- 新增了某某功能\n- 修复了某某 Bug",
|
|||
|
|
dependencies: [
|
|||
|
|
{ dependency_type: "required", project_id: "P7dR8mSH" }
|
|||
|
|
],
|
|||
|
|
game_versions: ["1.20.1", "1.20.4"],
|
|||
|
|
version_type: "release",
|
|||
|
|
loaders: ["fabric"],
|
|||
|
|
featured: false,
|
|||
|
|
status: "listed",
|
|||
|
|
environment: "client_and_server",
|
|||
|
|
file_types: {
|
|||
|
|
"sources-file": "sources-jar"
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
form.append("data", JSON.stringify(metadata));
|
|||
|
|
form.append("main-file", new Blob([fs.readFileSync("./build/libs/my-mod-1.0.0.jar")]), "my-mod-1.0.0.jar");
|
|||
|
|
form.append("sources-file", new Blob([fs.readFileSync("./build/libs/my-mod-1.0.0-sources.jar")]), "my-mod-1.0.0-sources.jar");
|
|||
|
|
|
|||
|
|
const response = await fetch("https://api.modrinth.com/v2/version", {
|
|||
|
|
method: "POST",
|
|||
|
|
headers: {
|
|||
|
|
"Authorization": TOKEN,
|
|||
|
|
"User-Agent": "your_username/your_project/1.0.0"
|
|||
|
|
},
|
|||
|
|
body: form
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
const result = await response.json();
|
|||
|
|
console.log(result);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 响应格式
|
|||
|
|
|
|||
|
|
成功创建后返回一个 [Version](#version-对象) 对象,HTTP 状态码 `200`。
|
|||
|
|
|
|||
|
|
### Version 对象
|
|||
|
|
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"id": "IIJJKKLL",
|
|||
|
|
"project_id": "AABBCCDD",
|
|||
|
|
"author_id": "EEFFGGHH",
|
|||
|
|
"name": "Version 1.0.0",
|
|||
|
|
"version_number": "1.0.0",
|
|||
|
|
"changelog": "## 更新内容\n\n- 新增了某某功能\n- 修复了某某 Bug",
|
|||
|
|
"date_published": "2025-01-01T00:00:00Z",
|
|||
|
|
"downloads": 0,
|
|||
|
|
"version_type": "release",
|
|||
|
|
"status": "listed",
|
|||
|
|
"requested_status": null,
|
|||
|
|
"game_versions": ["1.20.1", "1.20.4"],
|
|||
|
|
"loaders": ["fabric"],
|
|||
|
|
"featured": false,
|
|||
|
|
"files": [
|
|||
|
|
{
|
|||
|
|
"hashes": {
|
|||
|
|
"sha512": "93ecf5fe...",
|
|||
|
|
"sha1": "c84dd4b3..."
|
|||
|
|
},
|
|||
|
|
"url": "https://cdn.modrinth.com/data/AABBCCDD/versions/1.0.0/my-mod-1.0.0.jar",
|
|||
|
|
"filename": "my-mod-1.0.0.jar",
|
|||
|
|
"primary": true,
|
|||
|
|
"size": 1097270,
|
|||
|
|
"file_type": null
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"hashes": {
|
|||
|
|
"sha512": "ab12cd34...",
|
|||
|
|
"sha1": "ef56gh78..."
|
|||
|
|
},
|
|||
|
|
"url": "https://cdn.modrinth.com/data/AABBCCDD/versions/1.0.0/my-mod-1.0.0-sources.jar",
|
|||
|
|
"filename": "my-mod-1.0.0-sources.jar",
|
|||
|
|
"primary": false,
|
|||
|
|
"size": 543210,
|
|||
|
|
"file_type": "sources-jar"
|
|||
|
|
}
|
|||
|
|
]
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
响应中 `files` 数组的每个文件对象包含:
|
|||
|
|
|
|||
|
|
| 字段 | 说明 |
|
|||
|
|
|------|------|
|
|||
|
|
| `hashes` | 文件哈希,包含 `sha512` 和 `sha1` |
|
|||
|
|
| `url` | 文件直链 |
|
|||
|
|
| `filename` | 文件名 |
|
|||
|
|
| `primary` | 是否为主文件 |
|
|||
|
|
| `size` | 文件大小(字节) |
|
|||
|
|
| `file_type` | 文件类型(对于 sources.jar 为 `"sources-jar"`) |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 错误码
|
|||
|
|
|
|||
|
|
| 状态码 | 错误类型 | 说明 |
|
|||
|
|
|--------|----------|------|
|
|||
|
|
| `400` | `InvalidInputError` | 请求参数无效,详见响应中的 `description`。常见原因:缺少必填字段、`game_versions` 或 `loaders` 值不合法、文件格式不被接受 |
|
|||
|
|
| `401` | `AuthError` | Token 无效、未提供 Token,或 Token 不包含 `VERSION_CREATE` 权限范围 |
|
|||
|
|
| `404` | — | 目标项目 `project_id` 不存在 |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 注意事项与最佳实践
|
|||
|
|
|
|||
|
|
### 1. 必须至少上传一个文件
|
|||
|
|
|
|||
|
|
除非版本 `status` 设置为 `draft`,否则每个新版本必须附带至少一个文件。接受的格式:`.mrpack`、`.jar`、`.zip`、`.litemod`。
|
|||
|
|
|
|||
|
|
### 2. `file_parts` / `file_types` / `primary_file` 全部使用 multipart 字段名
|
|||
|
|
|
|||
|
|
这三处字符串和实际表单字段名必须**严格匹配**,且它们指向的都是 **multipart 字段名**(如 `"main-file"`),不是文件名(如 `"my-mod-1.0.0.jar"`)。否则上传的文件不会被正确关联。
|
|||
|
|
|
|||
|
|
### 3. sources.jar 的正确做法
|
|||
|
|
|
|||
|
|
- 给 sources 文件随意命名 multipart 字段名(如 `"sources-file"`),将其列入 `file_parts`。
|
|||
|
|
- 在 `file_types` 中映射该 **multipart 字段名** → `"sources-jar"`。
|
|||
|
|
- **不要**将 sources 文件设为主文件(`primary_file` 应指向主 jar 的 multipart 字段名)。
|
|||
|
|
|
|||
|
|
### 4. `dependencies` 可以是空数组
|
|||
|
|
|
|||
|
|
如果该模组没有依赖(极少数情况),直接传 `[]` 即可。但 `dependencies` 字段本身是必填的。
|
|||
|
|
|
|||
|
|
### 5. 文件大小限制
|
|||
|
|
|
|||
|
|
Modrinth 对上传文件有大小限制。如果文件过大,可能收到 `400` 错误。建议保持在合理范围内(一般单个文件不超过 100MB)。
|
|||
|
|
|
|||
|
|
### 6. 版本号建议
|
|||
|
|
|
|||
|
|
`version_number` 理想上应遵循[语义化版本规范](https://semver.org/lang/zh-CN/),便于 Modrinth 进行版本比较和用户理解。
|
|||
|
|
|
|||
|
|
### 7. 草稿版本
|
|||
|
|
|
|||
|
|
如果你想先上传版本而不立即公开,可将 `status` 设为 `draft`。草稿版本可以不附带文件。后续可通过 PATCH `/version/{id}` 修改状态为 `listed` 来发布。
|
|||
|
|
|
|||
|
|
### 8. 已有版本追加文件
|
|||
|
|
|
|||
|
|
如果版本已创建但需要追加文件,应使用 `POST /version/{id}/file` 端点(需要 `VERSION_WRITE` 权限范围)。
|
|||
|
|
|
|||
|
|
### 9. 环境与加载器的校验
|
|||
|
|
|
|||
|
|
`loaders` 和 `game_versions` 必须使用 Modrinth 认可的值。你可以通过以下端口查询可用值:
|
|||
|
|
- `GET /tag/loader` — 可用加载器
|
|||
|
|
- `GET /tag/game_version` — 可用 Minecraft 版本
|
|||
|
|
|
|||
|
|
### 10. Rate Limit
|
|||
|
|
|
|||
|
|
Modrinth API 有频率限制:每 IP 每分钟最多 **300** 个请求。响应头中包含 `X-Ratelimit-Limit`、`X-Ratelimit-Remaining`、`X-Ratelimit-Reset`。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 参考
|
|||
|
|
|
|||
|
|
- [Modrinth API 文档](https://docs.modrinth.com)
|
|||
|
|
- [Modrinth 创建 PAT](https://modrinth.com/settings/account)
|
|||
|
|
- [OpenAPI 规范文件](openapi.yml)
|
|||
|
|
- [Modrinth Labrinth 源码](https://github.com/modrinth/labrinth)
|
|||
|
|
- [语义化版本规范](https://semver.org)
|