feat: 收口文档桥接与 OnlyOffice/Sidebar 回归

- 为 documents.save/meta/content、blocks.patch 与 sidebar.dataset.list 补齐 Rust 协议映射、共享契约与桥接执行器

- 对齐 BlockNote、Mindmap、OnlyOffice 的保存/路由元信息,并补真实浏览器回归脚本与 OnlyOffice 部署基线

- 忽略 Rust 本地构建产物与 Harness 调试状态文件,避免临时产物进入仓库历史
This commit is contained in:
lix-2026
2026-04-15 03:06:29 +08:00
parent 84a8454fa9
commit b33ffb99e7
51 changed files with 3260 additions and 379 deletions
@@ -3,11 +3,10 @@ import crypto from "crypto";
import { api } from "@/lib/convex/api";
import { HttpError } from "@/lib/auth/authContext";
import { getAuthedConvexClient } from "@/lib/convex/route";
import { resolveOnlyOfficeInternalUrl } from "@/lib/onlyoffice/internal-url";
export const dynamic = "force-dynamic";
const ONLYOFFICE_INTERNAL_URL = (process.env.ONLYOFFICE_INTERNAL_URL || "http://127.0.0.1:8081").replace(/\/+$/, "");
const base64Url = (input: Buffer | string) =>
Buffer.from(input)
.toString("base64")
@@ -38,6 +37,7 @@ const normalizeSecret = (raw: string) => {
};
export async function POST(request: Request) {
const onlyofficeInternalUrl = await resolveOnlyOfficeInternalUrl();
let auth;
let client;
try {
@@ -82,7 +82,7 @@ export async function POST(request: Request) {
// 优先按文档推荐:使用 /command + token
if (secret) {
const token = signHs256(payload, secret);
const r = await fetch(`${ONLYOFFICE_INTERNAL_URL}/command`, {
const r = await fetch(`${onlyofficeInternalUrl}/command`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ token }),
@@ -93,7 +93,7 @@ export async function POST(request: Request) {
}
// 兜底:部分环境可能暴露 /forcesave 直连接口
const r2 = await fetch(`${ONLYOFFICE_INTERNAL_URL}/forcesave`, {
const r2 = await fetch(`${onlyofficeInternalUrl}/forcesave`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(payload),
@@ -110,7 +110,7 @@ export async function POST(request: Request) {
}
// JWT 未启用:尝试 /forcesave 直连
const r = await fetch(`${ONLYOFFICE_INTERNAL_URL}/forcesave`, {
const r = await fetch(`${onlyofficeInternalUrl}/forcesave`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(payload),
@@ -121,7 +121,7 @@ export async function POST(request: Request) {
}
// 最后兜底:部分部署可能仍接受不带 token 的 /command(不保证)
const r2 = await fetch(`${ONLYOFFICE_INTERNAL_URL}/command`, {
const r2 = await fetch(`${onlyofficeInternalUrl}/command`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(payload),
@@ -140,4 +140,3 @@ export async function POST(request: Request) {
return NextResponse.json({ error: "触发 forcesave 失败" }, { status: 502 });
}
}