{ "openapi": "3.1.0", "info": { "title": "RawMark API", "version": "1", "description": "RawMark 的 REST API。自动化调用请在「API 令牌」中创建令牌,以 `Authorization: Bearer ` 访问;只读令牌可使用 GET 和 POST /export(只读导出)。分享与令牌的管理接口只接受登录会话。所有错误响应均为 `{\"error\": \"说明\"}`。" }, "servers": [ { "url": "/api/v1" } ], "security": [ { "bearer": [] }, { "cookie": [] } ], "paths": { "/health": { "get": { "summary": "健康检查", "tags": [ "系统" ], "security": [ {} ], "responses": { "200": { "description": "成功", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Ok" } } } } } } }, "/openapi.json": { "get": { "summary": "本文档", "tags": [ "系统" ], "security": [ {} ], "responses": { "200": { "description": "OpenAPI 文档", "content": { "application/json": { "schema": { "type": "object" } } } } } } }, "/auth/state": { "get": { "summary": "是否已初始化、当前是否已登录", "tags": [ "登录" ], "security": [ {} ], "responses": { "200": { "description": "状态", "content": { "application/json": { "schema": { "type": "object", "properties": { "setUp": { "type": "boolean" }, "authenticated": { "type": "boolean" } } } } } } } } }, "/auth/setup": { "post": { "summary": "首次设置登录密码", "tags": [ "登录" ], "security": [ {} ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "password": { "type": "string" } }, "required": [ "password" ] } } } }, "responses": { "200": { "description": "成功", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Ok" } } } }, "400": { "description": "密码过短", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "已初始化", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } }, "description": "仅未初始化实例可设置密码;首次成功后自动登录,已初始化时返回 409。" } }, "/auth/login": { "post": { "summary": "登录,成功后设置会话 Cookie", "tags": [ "登录" ], "security": [ {} ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "password": { "type": "string" } }, "required": [ "password" ] } } } }, "responses": { "200": { "description": "成功", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Ok" } } } }, "401": { "description": "密码错误", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "失败次数过多", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/auth/logout": { "post": { "summary": "退出登录", "tags": [ "登录" ], "security": [ {} ], "responses": { "200": { "description": "成功", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Ok" } } } } } } }, "/auth/password": { "post": { "summary": "修改登录密码;当前会话保留,其他设备需重新登录", "tags": [ "登录" ], "security": [ { "cookie": [] } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "current": { "type": "string" }, "next": { "type": "string" } }, "required": [ "current", "next" ] } } } }, "responses": { "200": { "description": "成功", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Ok" } } } }, "400": { "description": "新密码过短", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "当前密码错误", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "失败次数过多", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/settings": { "get": { "summary": "应用设置(全部设备共用的一份 JSON 对象)", "tags": [ "设置" ], "responses": { "200": { "description": "设置", "content": { "application/json": { "schema": { "type": "object", "additionalProperties": true } } } } } }, "patch": { "summary": "合并修改设置", "tags": [ "设置" ], "security": [ { "cookie": [] } ], "description": "按顶层键合并:请求中的键覆盖原值,值为 null 的键被删除。成功后经 WebSocket 推送 settings 事件。", "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "additionalProperties": true } } } }, "responses": { "200": { "description": "合并后的设置", "content": { "application/json": { "schema": { "type": "object", "additionalProperties": true } } } }, "400": { "description": "不是 JSON 对象", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "413": { "description": "超过 1 MB", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/tree": { "get": { "summary": "全部笔记、图片与文件夹(含 .assets,不含隐藏条目或符号链接)", "tags": [ "笔记" ], "responses": { "200": { "description": "目录树", "content": { "application/json": { "schema": { "type": "object", "properties": { "entries": { "type": "array", "items": { "$ref": "#/components/schemas/Entry" } } } } } } } } } }, "/files/{path}": { "parameters": [ { "name": "path", "in": "path", "required": true, "description": "仓库内的相对路径,如 `目录/笔记.md`(各段需 URL 编码)", "schema": { "type": "string" } } ], "get": { "summary": "读取笔记", "tags": [ "笔记" ], "responses": { "200": { "description": "Markdown 原文", "headers": { "ETag": { "description": "内容版本(rev),带双引号", "schema": { "type": "string" } } }, "content": { "text/markdown": { "schema": { "type": "string" } } } }, "404": { "description": "不存在", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "put": { "summary": "写入笔记(不存在的上级目录会自动创建)", "tags": [ "笔记" ], "description": "请求体整体作为笔记内容。`If-Match: \"rev\"` 要求当前版本一致,否则返回 412 与最新 rev;`If-None-Match: *` 要求笔记尚不存在;都不带则直接覆盖。", "parameters": [ { "name": "If-Match", "in": "header", "schema": { "type": "string" } }, { "name": "If-None-Match", "in": "header", "schema": { "type": "string", "enum": [ "*" ] } } ], "requestBody": { "required": true, "content": { "text/markdown": { "schema": { "type": "string" } } } }, "responses": { "200": { "description": "已写入", "content": { "application/json": { "schema": { "type": "object", "properties": { "rev": { "type": "string" } } } } }, "headers": { "ETag": { "description": "内容版本(rev),带双引号", "schema": { "type": "string" } } } }, "400": { "description": "路径无效", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "If-None-Match 时已存在", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "412": { "description": "版本冲突", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "string" }, "rev": { "type": "string", "description": "服务器上的当前版本;为空表示已不存在" } } } } } }, "413": { "description": "超过 20 MB", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "delete": { "summary": "把笔记、图片或文件夹移入回收站(笔记连同 .assets)", "tags": [ "笔记" ], "responses": { "200": { "description": "回收站条目", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TrashItem" } } } }, "404": { "description": "不存在", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/move": { "post": { "summary": "移动或重命名笔记、图片或文件夹", "tags": [ "笔记" ], "description": "笔记的 .assets 目录随之移动,改名时改写本篇图片目录链接;图片移动或改名保持扩展名,并更新仓库笔记中的本地引用。分享链接随主体更新。不改写其他笔记指向笔记或文件夹的链接。", "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "from": { "type": "string" }, "to": { "type": "string" } }, "required": [ "from", "to" ] } } } }, "responses": { "200": { "description": "成功", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Ok" } } } }, "404": { "description": "源不存在", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "目标已存在", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/folders": { "post": { "summary": "新建文件夹", "tags": [ "笔记" ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "path": { "type": "string" } }, "required": [ "path" ] } } } }, "responses": { "200": { "description": "成功", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Ok" } } } }, "409": { "description": "已存在", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/assets": { "post": { "summary": "上传图片到笔记的 .assets 目录", "tags": [ "图片" ], "parameters": [ { "name": "note", "in": "query", "required": true, "description": "所属笔记路径", "schema": { "type": "string" } } ], "requestBody": { "required": true, "content": { "multipart/form-data": { "schema": { "type": "object", "properties": { "file": { "type": "string", "format": "binary" } }, "required": [ "file" ] } } } }, "responses": { "200": { "description": "相对笔记所在目录的链接,可直接写入 Markdown", "content": { "application/json": { "schema": { "type": "object", "properties": { "link": { "type": "string" } } } } } }, "413": { "description": "超过 50 MB", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/assets/import": { "post": { "summary": "下载公网图片到笔记的 .assets 目录", "tags": [ "图片" ], "description": "仅接受公网 HTTP/HTTPS 地址,实际连接及重定向均校验;不携带登录凭据或使用环境代理。重定向链最多 5 个请求、2 次下载尝试,单次超时 10 秒;仅超时、429 和 5xx 重试。支持 PNG/JPEG/GIF/WebP,按文件签名识别,最大 50 MB。", "parameters": [ { "name": "note", "in": "query", "required": true, "schema": { "type": "string" } } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": [ "url" ], "properties": { "url": { "type": "string", "format": "uri" } } } } } }, "responses": { "200": { "description": "相对笔记所在目录的图片链接", "content": { "application/json": { "schema": { "type": "object", "properties": { "link": { "type": "string" } } } } } }, "400": { "description": "来源地址或笔记路径无效,或目标不是公网", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "所属笔记不存在", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "413": { "description": "图片超过 50 MB", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "422": { "description": "不支持的图片类型", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "502": { "description": "来源请求失败", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/raw/{path}": { "parameters": [ { "name": "path", "in": "path", "required": true, "description": "仓库内的相对路径,如 `目录/笔记.md`(各段需 URL 编码)", "schema": { "type": "string" } } ], "get": { "summary": "读取仓库中的原始文件(图片等)", "tags": [ "图片" ], "responses": { "200": { "description": "文件内容", "content": { "application/octet-stream": { "schema": { "type": "string", "format": "binary" } } } }, "404": { "description": "不存在", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/search": { "get": { "summary": "全文搜索", "tags": [ "笔记" ], "description": "空格分隔多个词,全部命中才返回;最多 50 条。", "parameters": [ { "name": "q", "in": "query", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "description": "结果", "content": { "application/json": { "schema": { "type": "object", "properties": { "results": { "type": "array", "items": { "$ref": "#/components/schemas/SearchResult" } } } } } } } } } }, "/trash": { "get": { "summary": "回收站列表", "tags": [ "回收站" ], "responses": { "200": { "description": "条目", "content": { "application/json": { "schema": { "type": "object", "properties": { "items": { "type": "array", "items": { "$ref": "#/components/schemas/TrashItem" } } } } } } } } } }, "/trash/{id}/restore": { "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string" } } ], "post": { "summary": "从回收站恢复", "tags": [ "回收站" ], "responses": { "200": { "description": "恢复的条目", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TrashItem" } } } }, "404": { "description": "不存在", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "原位置已有同名文件", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/trash/{id}": { "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string" } } ], "delete": { "summary": "彻底删除回收站条目", "tags": [ "回收站" ], "responses": { "200": { "description": "成功", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Ok" } } } }, "404": { "description": "不存在", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/events": { "get": { "summary": "WebSocket:仓库变更推送", "tags": [ "笔记" ], "description": "升级为 WebSocket 后,服务器推送 JSON 数组,元素为 Event。客户端不发送消息。", "responses": { "101": { "description": "切换为 WebSocket" } } } }, "/shares": { "get": { "summary": "分享列表", "tags": [ "分享" ], "security": [ { "cookie": [] } ], "parameters": [ { "name": "path", "in": "query", "description": "只列出该笔记的分享", "schema": { "type": "string" } } ], "responses": { "200": { "description": "分享", "content": { "application/json": { "schema": { "type": "object", "properties": { "shares": { "type": "array", "items": { "$ref": "#/components/schemas/Share" } } } } } } } } }, "post": { "summary": "创建文件或文件夹的只读分享", "tags": [ "分享" ], "security": [ { "cookie": [] } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "path": { "type": "string", "description": "仓库内的文件或文件夹;文件夹递归公开当前所有普通文件和子目录,含后续新增或移入的内容" }, "password": { "type": "string", "description": "访问密码,留空为不设密码" }, "expiresIn": { "type": "integer", "description": "有效时长(秒),0 为永久" } }, "required": [ "path" ] } } } }, "responses": { "200": { "description": "新分享,token 为 128 位随机数的 URL 安全编码,访问地址为 /s/{token};移动分享主体不改变链接", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Share" } } } }, "400": { "description": "路径或参数无效", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "笔记不存在", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/shares/{token}": { "parameters": [ { "name": "token", "in": "path", "required": true, "schema": { "type": "string" } } ], "delete": { "summary": "撤销分享", "tags": [ "分享" ], "security": [ { "cookie": [] } ], "responses": { "200": { "description": "成功", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Ok" } } } }, "404": { "description": "不存在", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/tokens": { "get": { "summary": "API 令牌列表", "tags": [ "API 令牌" ], "security": [ { "cookie": [] } ], "responses": { "200": { "description": "令牌", "content": { "application/json": { "schema": { "type": "object", "properties": { "tokens": { "type": "array", "items": { "$ref": "#/components/schemas/APIToken" } } } } } } } } }, "post": { "summary": "创建 API 令牌", "tags": [ "API 令牌" ], "security": [ { "cookie": [] } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "name": { "type": "string" }, "scope": { "type": "string", "enum": [ "read", "write" ] } }, "required": [ "name", "scope" ] } } } }, "responses": { "200": { "description": "token 明文只返回这一次", "content": { "application/json": { "schema": { "type": "object", "properties": { "token": { "type": "string" }, "info": { "$ref": "#/components/schemas/APIToken" } } } } } }, "400": { "description": "名称或范围无效", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/tokens/{id}": { "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string" } } ], "delete": { "summary": "吊销 API 令牌", "tags": [ "API 令牌" ], "security": [ { "cookie": [] } ], "responses": { "200": { "description": "成功", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Ok" } } } }, "404": { "description": "不存在", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/public/shares/{token}": { "parameters": [ { "name": "token", "in": "path", "required": true, "schema": { "type": "string" } }, { "name": "path", "in": "query", "description": "文件夹分享中相对主体的子路径;省略时读取主体本身,不允许跳出分享范围", "schema": { "type": "string" } } ], "get": { "summary": "访客读取分享主体或其目录中的当前内容", "tags": [ "分享(公开)" ], "security": [ {} ], "responses": { "200": { "description": "目录返回 dir=true 及递归 entries(路径相对此目录);Markdown 返回 dir=false、content 与 updatedAt;其他文件返回 dir=false,内容经 assets 接口读取或下载", "content": { "application/json": { "schema": { "type": "object", "properties": { "title": { "type": "string" }, "content": { "type": "string" }, "updatedAt": { "type": "integer" }, "dir": { "type": "boolean" }, "entries": { "type": "array", "items": { "$ref": "#/components/schemas/Entry" } } } } } } }, "401": { "description": "需要访问密码", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "string" }, "passwordRequired": { "type": "boolean" } } } } } }, "404": { "description": "分享不存在、已过期、主体已删除或子路径不在分享范围内", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/public/shares/{token}/unlock": { "parameters": [ { "name": "token", "in": "path", "required": true, "schema": { "type": "string" } } ], "post": { "summary": "输入分享密码,成功后设置访客 Cookie", "tags": [ "分享(公开)" ], "security": [ {} ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "password": { "type": "string" } }, "required": [ "password" ] } } } }, "responses": { "200": { "description": "成功", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Ok" } } } }, "401": { "description": "密码错误", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "分享不存在或已失效", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "失败次数过多", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/public/shares/{token}/assets/{path}": { "parameters": [ { "name": "token", "in": "path", "required": true, "schema": { "type": "string" } }, { "name": "path", "in": "path", "required": true, "description": "文件夹分享中相对主体的文件路径;单文件分享仅允许其 .assets 图片,空路径读取该文件本身", "schema": { "type": "string" } }, { "name": "download", "in": "query", "description": "设为 1 时以附件下载;其他情况下以带沙箱 CSP 的原始文件返回", "schema": { "type": "string", "enum": [ "1" ] } } ], "get": { "summary": "访客读取或下载分享范围内的普通文件", "tags": [ "分享(公开)" ], "security": [ {} ], "responses": { "200": { "description": "文件内容", "content": { "application/octet-stream": { "schema": { "type": "string", "format": "binary" } } } }, "404": { "description": "不存在或不在允许范围内", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/themes": { "get": { "summary": "列出主题(含内置默认主题)", "tags": [ "外观" ], "responses": { "200": { "description": "主题列表", "content": { "application/json": { "schema": { "type": "object", "properties": { "themes": { "type": "array", "items": { "$ref": "#/components/schemas/Theme" } } } } } } } } } }, "/themes/{id}": { "get": { "summary": "读取主题 CSS", "tags": [ "外观" ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "description": "主题信息与 CSS", "content": { "application/json": { "schema": { "allOf": [ { "$ref": "#/components/schemas/Theme" }, { "type": "object", "properties": { "css": { "type": "string" } } } ] } } } }, "404": { "description": "主题不存在或文件不完整" } } } }, "/public/shares/{token}/appearance": { "get": { "summary": "读取有效分享使用的外观配置", "description": "仅返回明暗模式、字号、正文宽度、主题 CSS 和启用的 CSS 片段;密码分享需先解锁,不返回其他设置,不加载插件。", "tags": [ "分享" ], "security": [ {} ], "parameters": [ { "name": "token", "in": "path", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "description": "公开的外观配置", "content": { "application/json": { "schema": { "type": "object", "properties": { "colorMode": { "type": "string", "enum": [ "system", "light", "dark" ] }, "fontSize": { "type": "integer" }, "contentWidth": { "type": "integer" }, "themeCSS": { "type": "string" }, "cssSnippets": { "type": [ "array", "null" ], "items": { "type": "object", "properties": { "id": { "type": "string" }, "name": { "type": "string" }, "css": { "type": "string" }, "enabled": { "type": "boolean" } } } }, "theme": { "type": "string" } } } } } }, "401": { "description": "需要访问密码" }, "404": { "description": "分享不存在、已过期或已撤销" } } } }, "/plugins": { "get": { "summary": "列出已安装插件及启用状态", "tags": [ "插件" ], "security": [ { "cookie": [] } ], "responses": { "200": { "description": "成功", "content": { "application/json": { "schema": { "type": "object", "properties": { "plugins": { "type": "array", "items": { "$ref": "#/components/schemas/Plugin" } } } } } } }, "401": { "description": "需要登录会话" }, "400": { "description": "请求或插件包无效" }, "403": { "description": "不接受 API 令牌" } } }, "post": { "summary": "安装 ZIP 插件;安装后默认停用,同 id 拒绝覆盖", "tags": [ "插件" ], "security": [ { "cookie": [] } ], "responses": { "201": { "description": "成功", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Plugin" } } } }, "401": { "description": "需要登录会话" }, "400": { "description": "请求或插件包无效" }, "403": { "description": "不接受 API 令牌" }, "409": { "description": "同名插件已安装" }, "413": { "description": "ZIP 超过 10 MiB" } }, "requestBody": { "required": true, "content": { "multipart/form-data": { "schema": { "type": "object", "required": [ "file" ], "properties": { "file": { "type": "string", "format": "binary" } } } } } } } }, "/plugins/{id}": { "patch": { "summary": "修改全设备插件启用偏好", "tags": [ "插件" ], "security": [ { "cookie": [] } ], "responses": { "200": { "description": "成功", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Plugin" } } } }, "401": { "description": "需要登录会话" }, "400": { "description": "请求或插件包无效" }, "403": { "description": "不接受 API 令牌" }, "404": { "description": "插件或指定版本的资源不存在" } }, "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string" } } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": [ "enabled" ], "properties": { "enabled": { "type": "boolean" } } } } } } }, "delete": { "summary": "停用并卸载插件包,保留插件私有数据", "tags": [ "插件" ], "security": [ { "cookie": [] } ], "responses": { "200": { "description": "成功" }, "401": { "description": "需要登录会话" }, "400": { "description": "请求或插件包无效" }, "403": { "description": "不接受 API 令牌" }, "404": { "description": "插件或指定版本的资源不存在" } }, "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string" } } ] } }, "/plugins/{id}/data": { "get": { "summary": "读取插件私有 JSON,无数据时为 null", "tags": [ "插件" ], "security": [ { "cookie": [] } ], "responses": { "200": { "description": "成功", "content": { "application/json": { "schema": { "type": "object", "required": [ "data" ], "properties": { "data": {} } } } } }, "401": { "description": "需要登录会话" }, "400": { "description": "请求或插件包无效" }, "403": { "description": "不接受 API 令牌" }, "404": { "description": "插件或指定版本的资源不存在" } }, "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string" } } ] }, "put": { "summary": "替换插件私有 JSON,最多 1 MiB", "tags": [ "插件" ], "security": [ { "cookie": [] } ], "responses": { "200": { "description": "成功", "content": { "application/json": { "schema": { "type": "object", "required": [ "data" ], "properties": { "data": {} } } } } }, "401": { "description": "需要登录会话" }, "400": { "description": "请求或插件包无效" }, "403": { "description": "不接受 API 令牌" }, "404": { "description": "插件或指定版本的资源不存在" } }, "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string" } } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": [ "data" ], "properties": { "data": {} } } } } } } }, "/plugins/{id}/assets/{revision}/{path}": { "get": { "summary": "鉴权读取指定安装版本的包内资源", "tags": [ "插件" ], "security": [ { "cookie": [] } ], "responses": { "200": { "description": "成功" }, "401": { "description": "需要登录会话" }, "400": { "description": "请求或插件包无效" }, "403": { "description": "不接受 API 令牌" }, "404": { "description": "插件或指定版本的资源不存在" } }, "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }, { "name": "revision", "in": "path", "required": true, "schema": { "type": "string" } }, { "name": "path", "in": "path", "required": true, "schema": { "type": "string" } } ] } }, "/import": { "post": { "summary": "导入 Markdown 文件或 ZIP 知识库", "tags": [ "文件" ], "description": "多选 .md 或单个 ZIP,总上传不超过 100 MB;ZIP 必须指定新建文件夹名称。目标目录必须存在,冲突不覆盖。解压及整理后上限 512 MiB、10,000 项,单篇笔记 20 MiB、附件 50 MiB。Markdown 与 ZIP 文件名须为 UTF-8。ZIP 层级保留,本地图片生成笔记独立附件,原附件保留;外部链接不下载,缺失本地目标以警告返回。", "requestBody": { "required": true, "content": { "multipart/form-data": { "schema": { "type": "object", "required": [ "files" ], "properties": { "dir": { "type": "string", "description": "目标目录,空字符串为根目录" }, "folder": { "type": "string", "description": "ZIP 的新建文件夹名称;普通 Markdown 留空" }, "files": { "type": "array", "items": { "type": "string", "format": "binary" } } } } } } }, "responses": { "201": { "description": "导入成功", "content": { "application/json": { "schema": { "type": "object", "required": [ "paths", "notes", "assets", "warnings" ], "properties": { "paths": { "type": "array", "items": { "type": "string" } }, "notes": { "type": "integer" }, "assets": { "type": "integer", "description": "附件文件总数,包含原始附件和独立副本" }, "warnings": { "type": "array", "items": { "type": "string" } } } } } } }, "400": { "description": "格式、路径或编码无效" }, "401": { "description": "未登录或令牌无效" }, "403": { "description": "只读令牌不能导入" }, "404": { "description": "目标目录不存在" }, "409": { "description": "目标已存在,不覆盖" }, "413": { "description": "超过上传、解压、文件数量或单文件大小限制" } } } }, "/assets/{path}": { "put": { "summary": "原位替换已有图片,保留路径和引用", "tags": [ "图片" ], "parameters": [ { "name": "path", "in": "path", "required": true, "description": "仓库中的图片路径", "schema": { "type": "string" } } ], "description": "multipart file 字段的扩展名须与目标图片一致;不创建新文件,最大 50 MB。旧图片不会进入回收站。", "requestBody": { "required": true, "content": { "multipart/form-data": { "schema": { "type": "object", "properties": { "file": { "type": "string", "format": "binary" } }, "required": [ "file" ] } } } }, "responses": { "200": { "description": "替换成功" }, "400": { "description": "非法路径、空文件或扩展名不一致" }, "404": { "description": "目标图片不存在" }, "413": { "description": "超过 50 MB" } } } }, "/export": { "post": { "summary": "导出原始 Markdown 和本地附件", "description": "接收非空路径列表;单篇无附件返回 .md,目录、多选或含附件返回 ZIP。ZIP 保留仓库相对路径;不下载外部资源,不跟随其他未选中笔记。缺失附件或非法路径返回错误。此 POST 接口不修改数据,只读令牌可调用。", "tags": [ "文件" ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": [ "paths" ], "properties": { "paths": { "type": "array", "minItems": 1, "items": { "type": "string" } } } } } } }, "responses": { "200": { "description": "原始 Markdown 或 ZIP 附件", "content": { "application/zip": { "schema": { "type": "string", "format": "binary" } }, "text/markdown": { "schema": { "type": "string" } } } }, "400": { "description": "路径无效" }, "404": { "description": "文件或附件不存在" } } } } }, "components": { "securitySchemes": { "bearer": { "type": "http", "scheme": "bearer", "description": "API 令牌(rm_ 开头)" }, "cookie": { "type": "apiKey", "in": "cookie", "name": "rawmark_session", "description": "浏览器登录会话" } }, "schemas": { "Error": { "type": "object", "properties": { "error": { "type": "string" } }, "required": [ "error" ] }, "Ok": { "type": "object", "properties": { "ok": { "type": "boolean" } } }, "Entry": { "type": "object", "properties": { "path": { "type": "string" }, "dir": { "type": "boolean" }, "size": { "type": "integer" }, "mtime": { "type": "integer", "description": "修改时间(Unix 毫秒)" } } }, "TrashItem": { "type": "object", "properties": { "id": { "type": "string" }, "path": { "type": "string", "description": "原路径" }, "dir": { "type": "boolean" }, "deletedAt": { "type": "integer", "description": "Unix 毫秒" } } }, "SearchResult": { "type": "object", "properties": { "path": { "type": "string" }, "line": { "type": "integer", "description": "第一处匹配所在行(从 1 开始);只有路径匹配时为 0" }, "snippet": { "type": "string" } } }, "Event": { "type": "object", "description": "tree:目录结构变化;changed:内容变化(rev 为新版本);deleted:删除;moved:移动(from → path);settings:设置变化", "properties": { "type": { "type": "string", "enum": [ "tree", "changed", "deleted", "moved", "settings" ] }, "path": { "type": "string" }, "from": { "type": "string" }, "rev": { "type": "string" } } }, "Share": { "type": "object", "properties": { "token": { "type": "string", "description": "新分享使用完全随机的 URL 安全标识,不包含文件名称或目录" }, "path": { "type": "string", "description": "分享主体在仓库中的路径(只在登录后的管理接口返回)" }, "createdAt": { "type": "integer" }, "expiresAt": { "type": "integer", "description": "Unix 毫秒,0 为永久" }, "hasPassword": { "type": "boolean" }, "exists": { "type": "boolean", "description": "分享的文件或文件夹是否仍存在" } } }, "APIToken": { "type": "object", "properties": { "id": { "type": "string" }, "name": { "type": "string" }, "scope": { "type": "string", "enum": [ "read", "write" ] }, "createdAt": { "type": "integer" }, "lastUsedAt": { "type": "integer", "description": "Unix 毫秒,0 为从未使用" } } }, "Theme": { "type": "object", "required": [ "id", "name", "version" ], "properties": { "id": { "type": "string" }, "name": { "type": "string" }, "version": { "type": "string" } } }, "Plugin": { "type": "object", "required": [ "id", "name", "version", "apiVersion", "revision", "enabled" ], "properties": { "id": { "type": "string" }, "name": { "type": "string" }, "version": { "type": "string" }, "revision": { "type": "string" }, "apiVersion": { "type": "integer", "const": 1 }, "enabled": { "type": "boolean" } } } } } }