@fgbg/mdocs 0.7.8 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. package/bin/mdocs.js +0 -0
  2. package/dist/server/documents/commit-graph.js +44 -13
  3. package/dist/server/documents/commit-graph.js.map +1 -1
  4. package/dist/server/documents/commit-graph.test.js +7 -2
  5. package/dist/server/documents/commit-graph.test.js.map +1 -1
  6. package/dist/server/documents/document-commit.integration.test.js +70 -17
  7. package/dist/server/documents/document-commit.integration.test.js.map +1 -1
  8. package/dist/server/documents/document.service.js +85 -37
  9. package/dist/server/documents/document.service.js.map +1 -1
  10. package/dist/server/routes/documents.routes.js +44 -10
  11. package/dist/server/routes/documents.routes.js.map +1 -1
  12. package/dist/server/storage/file-store.js +20 -1
  13. package/dist/server/storage/file-store.js.map +1 -1
  14. package/dist/web/assets/{_baseUniq-Bt5mr5Sg.js → _baseUniq-CJKNOD1q.js} +1 -1
  15. package/dist/web/assets/{arc-DngOgKkd.js → arc-BSTUZ8vq.js} +1 -1
  16. package/dist/web/assets/{architectureDiagram-Q4EWVU46-IT7muYzK.js → architectureDiagram-Q4EWVU46-Di8Xlyl5.js} +1 -1
  17. package/dist/web/assets/{blockDiagram-DXYQGD6D-Beo5sULj.js → blockDiagram-DXYQGD6D-ZF5fC9Pa.js} +1 -1
  18. package/dist/web/assets/{c4Diagram-AHTNJAMY-BJ-7wJwT.js → c4Diagram-AHTNJAMY-f4BtRGqQ.js} +1 -1
  19. package/dist/web/assets/channel-CC9YDRol.js +1 -0
  20. package/dist/web/assets/{chunk-4BX2VUAB-CKozhjJC.js → chunk-4BX2VUAB-C9vZaXrt.js} +1 -1
  21. package/dist/web/assets/{chunk-4TB4RGXK-PQDNT7_Q.js → chunk-4TB4RGXK-AuXGx94-.js} +1 -1
  22. package/dist/web/assets/{chunk-55IACEB6-YSSe9cKE.js → chunk-55IACEB6-C6HqGEbC.js} +1 -1
  23. package/dist/web/assets/{chunk-EDXVE4YY-BhqUHLMZ.js → chunk-EDXVE4YY-CBuQGMbF.js} +1 -1
  24. package/dist/web/assets/{chunk-FMBD7UC4-7IM24lYb.js → chunk-FMBD7UC4-DImfvV9Y.js} +1 -1
  25. package/dist/web/assets/{chunk-OYMX7WX6-DwRSKz5j.js → chunk-OYMX7WX6-BXB7Lalj.js} +1 -1
  26. package/dist/web/assets/{chunk-QZHKN3VN-DHYKFJMD.js → chunk-QZHKN3VN-D3-iHoV_.js} +1 -1
  27. package/dist/web/assets/{chunk-YZCP3GAM-DLg5pjoy.js → chunk-YZCP3GAM-DRfuXRwg.js} +1 -1
  28. package/dist/web/assets/classDiagram-6PBFFD2Q-DSK9m5pj.js +1 -0
  29. package/dist/web/assets/classDiagram-v2-HSJHXN6E-DSK9m5pj.js +1 -0
  30. package/dist/web/assets/clone-CTsZZpQf.js +1 -0
  31. package/dist/web/assets/{cose-bilkent-S5V4N54A-DueL5HgY.js → cose-bilkent-S5V4N54A-CKXOhawd.js} +1 -1
  32. package/dist/web/assets/{dagre-KV5264BT-CvTMrLUl.js → dagre-KV5264BT-BYCBVC56.js} +1 -1
  33. package/dist/web/assets/{diagram-5BDNPKRD-q4NHEVUW.js → diagram-5BDNPKRD-XhBrm65s.js} +1 -1
  34. package/dist/web/assets/{diagram-G4DWMVQ6-a8nJl1e5.js → diagram-G4DWMVQ6-CGbxizxQ.js} +1 -1
  35. package/dist/web/assets/{diagram-MMDJMWI5-TBImmTdz.js → diagram-MMDJMWI5-CLyKsrJB.js} +1 -1
  36. package/dist/web/assets/{diagram-TYMM5635-BF1sUiOW.js → diagram-TYMM5635-D9ncu2lv.js} +1 -1
  37. package/dist/web/assets/{erDiagram-SMLLAGMA-Bv2B8Exy.js → erDiagram-SMLLAGMA-4Jlnrszd.js} +1 -1
  38. package/dist/web/assets/{flowDiagram-DWJPFMVM-C_vyRbo9.js → flowDiagram-DWJPFMVM-DcZvLb4F.js} +1 -1
  39. package/dist/web/assets/{ganttDiagram-T4ZO3ILL-CWdSaU12.js → ganttDiagram-T4ZO3ILL-Dw7Zc7xo.js} +1 -1
  40. package/dist/web/assets/{gitGraphDiagram-UUTBAWPF-BevLTyQU.js → gitGraphDiagram-UUTBAWPF-Ftc1gioV.js} +1 -1
  41. package/dist/web/assets/{graph-CblvkuNX.js → graph-D9a8-HhF.js} +1 -1
  42. package/dist/web/assets/index-CaRsgF0A.css +1 -0
  43. package/dist/web/assets/{index-Cv3eJNuk.js → index-DDVYimXd.js} +1184 -1191
  44. package/dist/web/assets/{infoDiagram-42DDH7IO-BKac3Yhz.js → infoDiagram-42DDH7IO-BOWu6CZc.js} +1 -1
  45. package/dist/web/assets/{ishikawaDiagram-UXIWVN3A-DersdL4Q.js → ishikawaDiagram-UXIWVN3A-f_P4Hv5V.js} +1 -1
  46. package/dist/web/assets/{journeyDiagram-VCZTEJTY-CQpBsOyx.js → journeyDiagram-VCZTEJTY-D3Gjgb3t.js} +1 -1
  47. package/dist/web/assets/{kanban-definition-6JOO6SKY-BejAWn9C.js → kanban-definition-6JOO6SKY-JaFivQmV.js} +1 -1
  48. package/dist/web/assets/{layout-D2aBaGbB.js → layout-DnKRMZlc.js} +1 -1
  49. package/dist/web/assets/{linear-BS6JsWa0.js → linear-CzU9ZCYG.js} +1 -1
  50. package/dist/web/assets/{min-CL06Vx8J.js → min-CbYw71ss.js} +1 -1
  51. package/dist/web/assets/{mindmap-definition-QFDTVHPH-O6ljclCO.js → mindmap-definition-QFDTVHPH-BA1rL4W9.js} +1 -1
  52. package/dist/web/assets/{pieDiagram-DEJITSTG-DjZMjzvi.js → pieDiagram-DEJITSTG-C164MrXt.js} +1 -1
  53. package/dist/web/assets/{quadrantDiagram-34T5L4WZ-z3A5Dnao.js → quadrantDiagram-34T5L4WZ-URQJg9YA.js} +1 -1
  54. package/dist/web/assets/{requirementDiagram-MS252O5E-DoM2kgbQ.js → requirementDiagram-MS252O5E-LgbP4sh2.js} +1 -1
  55. package/dist/web/assets/{sankeyDiagram-XADWPNL6-fviGw2kn.js → sankeyDiagram-XADWPNL6-DUIw0zkt.js} +1 -1
  56. package/dist/web/assets/{sequenceDiagram-FGHM5R23-CgtOcbDY.js → sequenceDiagram-FGHM5R23-BTzdpMq_.js} +1 -1
  57. package/dist/web/assets/{stateDiagram-FHFEXIEX-UpnR040Y.js → stateDiagram-FHFEXIEX-CmrCJk8c.js} +1 -1
  58. package/dist/web/assets/stateDiagram-v2-QKLJ7IA2-B2lUq_Mb.js +1 -0
  59. package/dist/web/assets/{timeline-definition-GMOUNBTQ-CjtkZKIX.js → timeline-definition-GMOUNBTQ-D0SQHe-v.js} +1 -1
  60. package/dist/web/assets/{vennDiagram-DHZGUBPP-BSxx1uwH.js → vennDiagram-DHZGUBPP-8C1P6BpB.js} +1 -1
  61. package/dist/web/assets/{wardley-RL74JXVD-BABpJ4WY.js → wardley-RL74JXVD-CcK1nJva.js} +1 -1
  62. package/dist/web/assets/{wardleyDiagram-NUSXRM2D-DyT1ySrj.js → wardleyDiagram-NUSXRM2D-n_8Mywtv.js} +1 -1
  63. package/dist/web/assets/{xychartDiagram-5P7HB3ND-TAmB0u0X.js → xychartDiagram-5P7HB3ND-Csstb1uX.js} +1 -1
  64. package/dist/web/index.html +2 -2
  65. package/package.json +8 -1
  66. package/dist/web/assets/channel-epQ5ykWT.js +0 -1
  67. package/dist/web/assets/classDiagram-6PBFFD2Q-CiHf1uhs.js +0 -1
  68. package/dist/web/assets/classDiagram-v2-HSJHXN6E-CiHf1uhs.js +0 -1
  69. package/dist/web/assets/clone-BgUoGhin.js +0 -1
  70. package/dist/web/assets/index-CLOOI7eJ.css +0 -1
  71. package/dist/web/assets/stateDiagram-v2-QKLJ7IA2-gFGG7JgL.js +0 -1
package/bin/mdocs.js CHANGED
File without changes
@@ -7,7 +7,6 @@ import { findCommitById, listParentCommitIds } from "../db/repositories/commit.r
7
7
  export function isAncestorOf(db, ancestorId, nodeId) {
8
8
  if (ancestorId === nodeId)
9
9
  return true;
10
- // hash set优化
11
10
  const visited = new Set();
12
11
  const queue = [nodeId];
13
12
  while (queue.length > 0) {
@@ -16,7 +15,6 @@ export function isAncestorOf(db, ancestorId, nodeId) {
16
15
  for (const p of parents) {
17
16
  if (p === ancestorId)
18
17
  return true;
19
- // bfs的时候会存在重复遍历的情况,set 去重
20
18
  if (!visited.has(p)) {
21
19
  visited.add(p);
22
20
  queue.push(p);
@@ -32,21 +30,54 @@ export function assertCommitBelongsToDocument(db, commitId, documentId) {
32
30
  throw new DocumentError("INVALID_COMMIT", "提交节点不存在或不属于该文档", 400);
33
31
  }
34
32
  }
33
+ /**
34
+ * 求两提交在 DAG 上的最近公共祖先(LCA),用于 merge 三路 diff 的 mergeBaseCommitId。
35
+ * 若一方是另一方的祖先,返回祖先侧节点。
36
+ */
37
+ export function findMergeBaseCommitId(db, commitA, commitB) {
38
+ if (commitA === commitB)
39
+ return commitA;
40
+ if (isAncestorOf(db, commitA, commitB))
41
+ return commitA;
42
+ if (isAncestorOf(db, commitB, commitA))
43
+ return commitB;
44
+ const ancestorsOfA = new Set();
45
+ const queueA = [commitA];
46
+ while (queueA.length > 0) {
47
+ const cur = queueA.shift();
48
+ if (ancestorsOfA.has(cur))
49
+ continue;
50
+ ancestorsOfA.add(cur);
51
+ for (const p of listParentCommitIds(db, cur)) {
52
+ queueA.push(p);
53
+ }
54
+ }
55
+ const visitedB = new Set();
56
+ const queueB = [commitB];
57
+ while (queueB.length > 0) {
58
+ const cur = queueB.shift();
59
+ if (ancestorsOfA.has(cur))
60
+ return cur;
61
+ if (visitedB.has(cur))
62
+ continue;
63
+ visitedB.add(cur);
64
+ for (const p of listParentCommitIds(db, cur)) {
65
+ queueB.push(p);
66
+ }
67
+ }
68
+ throw new DocumentError("BAD_REQUEST", "无法计算 mergeBaseCommitId:两提交无公共祖先", 400);
69
+ }
35
70
  /**
36
71
  * merge 发布前校验分叉关系。
37
- * - baseexpectedHead 不能相同(否则应走普通线性发布)
38
- * - base 必须是 expectedHead 的祖先(共同祖先之后分两路改)
72
+ * - localBaseCommitIdremoteCommitId 不能相同(否则应走普通线性发布)
73
+ * - localBaseCommitId 必须是 remoteCommitId 的祖先(允许远端在分叉后线性前进)
39
74
  */
40
- export function assertMergeFork(db, baseCommitId, expectedHeadCommitId) {
41
- /*
42
- * 如果 base(本地 commit 的父节点) expect(远端文章最新的节点)相同
43
- * 则不走 conflict merge逻辑, 应该走普通线性发布逻辑
44
- */
45
- if (baseCommitId === expectedHeadCommitId) {
46
- throw new DocumentError("BAD_REQUEST", "合并发布要求 base 与 expectedHead 不同", 400);
75
+ export function assertMergeFork(db, localBaseCommitId, remoteCommitId) {
76
+ if (localBaseCommitId === remoteCommitId) {
77
+ throw new DocumentError("BAD_REQUEST", "合并发布要求 localBaseCommitId remoteCommitId 不同", 400);
47
78
  }
48
- if (!isAncestorOf(db, baseCommitId, expectedHeadCommitId)) {
49
- throw new DocumentError("BAD_REQUEST", "base 不是 expectedHead 的祖先,无法合并", 400);
79
+ if (!isAncestorOf(db, localBaseCommitId, remoteCommitId)) {
80
+ throw new DocumentError("BAD_REQUEST", "localBaseCommitId 不是 remoteCommitId 的祖先,无法合并", 400);
50
81
  }
51
82
  }
52
83
  //# sourceMappingURL=commit-graph.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"commit-graph.js","sourceRoot":"","sources":["../../../src/server/documents/commit-graph.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAC5D,OAAO,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,mCAAmC,CAAC;AAExF;;;GAGG;AACH,MAAM,UAAU,YAAY,CAC1B,EAAqB,EACrB,UAAkB,EAClB,MAAc;IAEd,IAAI,UAAU,KAAK,MAAM;QAAE,OAAO,IAAI,CAAC;IACvC,aAAa;IACb,MAAM,OAAO,GAAG,IAAI,GAAG,EAAU,CAAC;IAClC,MAAM,KAAK,GAAG,CAAC,MAAM,CAAC,CAAC;IACvB,OAAO,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACxB,MAAM,GAAG,GAAG,KAAK,CAAC,KAAK,EAAG,CAAC;QAC3B,MAAM,OAAO,GAAG,mBAAmB,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC;QAC7C,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;YACxB,IAAI,CAAC,KAAK,UAAU;gBAAE,OAAO,IAAI,CAAC;YAClC,0BAA0B;YAC1B,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;gBACpB,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;gBACf,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAChB,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,kCAAkC;AAClC,MAAM,UAAU,6BAA6B,CAC3C,EAAqB,EACrB,QAAgB,EAChB,UAAkB;IAElB,MAAM,GAAG,GAAG,cAAc,CAAC,EAAE,EAAE,QAAQ,CAAC,CAAC;IACzC,IAAI,CAAC,GAAG,IAAI,GAAG,CAAC,WAAW,KAAK,UAAU,EAAE,CAAC;QAC3C,MAAM,IAAI,aAAa,CAAC,gBAAgB,EAAE,gBAAgB,EAAE,GAAG,CAAC,CAAC;IACnE,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAC7B,EAAqB,EACrB,YAAoB,EACpB,oBAA4B;IAE5B;;;OAGG;IACH,IAAI,YAAY,KAAK,oBAAoB,EAAE,CAAC;QAC1C,MAAM,IAAI,aAAa,CACrB,aAAa,EACb,+BAA+B,EAC/B,GAAG,CACJ,CAAC;IACJ,CAAC;IACD,IAAI,CAAC,YAAY,CAAC,EAAE,EAAE,YAAY,EAAE,oBAAoB,CAAC,EAAE,CAAC;QAC1D,MAAM,IAAI,aAAa,CACrB,aAAa,EACb,+BAA+B,EAC/B,GAAG,CACJ,CAAC;IACJ,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"commit-graph.js","sourceRoot":"","sources":["../../../src/server/documents/commit-graph.ts"],"names":[],"mappings":"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"}
@@ -2,7 +2,7 @@ import { describe, it, expect, beforeAll } from "vitest";
2
2
  import Database from "better-sqlite3";
3
3
  import { applySchema } from "../db/schema.js";
4
4
  import { insertCommit, insertCommitParent } from "../db/repositories/commit.repo.js";
5
- import { isAncestorOf, assertMergeFork } from "./commit-graph.js";
5
+ import { isAncestorOf, assertMergeFork, findMergeBaseCommitId } from "./commit-graph.js";
6
6
  import { DocumentError } from "../access/access-control.js";
7
7
  describe("commit-graph", () => {
8
8
  let db;
@@ -43,10 +43,15 @@ describe("commit-graph", () => {
43
43
  expect(isAncestorOf(db, "commit-c", "commit-d")).toBe(true);
44
44
  expect(isAncestorOf(db, "commit-d", "commit-a")).toBe(false);
45
45
  });
46
- it("assertMergeFork:base 必须是 expectedHead 的真祖先", () => {
46
+ it("assertMergeFork:localBase 必须是 remote 的真祖先", () => {
47
47
  expect(() => assertMergeFork(db, "commit-a", "commit-d")).not.toThrow();
48
48
  expect(() => assertMergeFork(db, "commit-d", "commit-d")).toThrow(DocumentError);
49
49
  expect(() => assertMergeFork(db, "commit-d", "commit-a")).toThrow(DocumentError);
50
50
  });
51
+ it("findMergeBaseCommitId:线性链与 reset 方向", () => {
52
+ expect(findMergeBaseCommitId(db, "commit-a", "commit-d")).toBe("commit-a");
53
+ expect(findMergeBaseCommitId(db, "commit-d", "commit-a")).toBe("commit-a");
54
+ expect(findMergeBaseCommitId(db, "commit-c", "commit-d")).toBe("commit-c");
55
+ });
51
56
  });
52
57
  //# sourceMappingURL=commit-graph.test.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"commit-graph.test.js","sourceRoot":"","sources":["../../../src/server/documents/commit-graph.test.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"commit-graph.test.js","sourceRoot":"","sources":["../../../src/server/documents/commit-graph.test.ts"],"names":[],"mappings":"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"}
@@ -8,8 +8,10 @@ import { createHash } from "node:crypto";
8
8
  const testDbRef = vi.hoisted(() => ({ db: null }));
9
9
  const fileStoreMocks = vi.hoisted(() => ({
10
10
  lastWriteContent: "",
11
+ commitBlobs: new Map(),
11
12
  reset() {
12
13
  fileStoreMocks.lastWriteContent = "";
14
+ fileStoreMocks.commitBlobs.clear();
13
15
  },
14
16
  }));
15
17
  vi.mock("../db/connection.js", () => ({
@@ -27,18 +29,28 @@ vi.mock("../storage/file-store.js", () => ({
27
29
  .update(fileStoreMocks.lastWriteContent || "{}")
28
30
  .digest("hex"),
29
31
  }),
30
- writeCommitBlob: (contentHash, content) => ({
31
- blobRef: `${contentHash.slice(0, 2)}/${contentHash.slice(2)}`,
32
- bytes: content.length,
33
- }),
32
+ writeCommitBlob: (contentHash, content) => {
33
+ const blobRef = `${contentHash.slice(0, 2)}/${contentHash.slice(2)}`;
34
+ fileStoreMocks.commitBlobs.set(blobRef, content);
35
+ return { blobRef, bytes: content.length };
36
+ },
37
+ readCommitBlob: (blobRef) => {
38
+ const content = fileStoreMocks.commitBlobs.get(blobRef);
39
+ if (!content)
40
+ throw new Error("commit blob not found");
41
+ return content;
42
+ },
34
43
  deleteDocumentFile: () => { },
35
44
  sha256: (buf) => createHash("sha256").update(buf).digest("hex"),
36
45
  }));
37
46
  import { DocumentError } from "../access/access-control.js";
38
- import { createDocument, updateDocument } from "./document.service.js";
47
+ import { createDocument, getDocumentMergeContext, updateDocument } from "./document.service.js";
48
+ import { findCommitById } from "../db/repositories/commit.repo.js";
39
49
  import { findDocumentById } from "../db/repositories/document.repo.js";
50
+ import { insertDocumentInvite } from "../db/repositories/document.repo.js";
40
51
  import { countParents, listParentCommitIds, } from "../db/repositories/commit.repo.js";
41
52
  const OWNER = "owner-commit-test";
53
+ const INVITED_EDITOR = "invited-editor";
42
54
  beforeAll(() => {
43
55
  const db = new Database(":memory:");
44
56
  applySchema(db);
@@ -46,6 +58,8 @@ beforeAll(() => {
46
58
  const now = new Date().toISOString();
47
59
  db.prepare(`INSERT INTO visitors (visitor_id, visitor_name, visitor_token_hash, created_at)
48
60
  VALUES (?, ?, ?, ?)`).run(OWNER, "Owner", "hash", now);
61
+ db.prepare(`INSERT INTO visitors (visitor_id, visitor_name, visitor_token_hash, created_at)
62
+ VALUES (?, ?, ?, ?)`).run(INVITED_EDITOR, "Invited", "hash2", now);
49
63
  });
50
64
  afterEach(() => {
51
65
  const db = testDbRef.db;
@@ -56,6 +70,22 @@ afterEach(() => {
56
70
  fileStoreMocks.reset();
57
71
  });
58
72
  describe("updateDocument 版本冲突", () => {
73
+ it("invite 编辑者发布后返回 invitedEdit=true", () => {
74
+ const created = createDocument({
75
+ actorVisitorId: OWNER,
76
+ fileName: "invite-edit.md",
77
+ content: '{"v":1}',
78
+ domainId: "default",
79
+ });
80
+ insertDocumentInvite(testDbRef.db, created.documentId, INVITED_EDITOR, "edit");
81
+ const updated = updateDocument({
82
+ actorVisitorId: INVITED_EDITOR,
83
+ documentId: created.documentId,
84
+ content: '{"v":2}',
85
+ version: { localBaseCommitId: created.headCommitId },
86
+ });
87
+ expect(updated.invitedEdit).toBe(true);
88
+ });
59
89
  it("base 与 head 一致时成功并推进 head", () => {
60
90
  const created = createDocument({
61
91
  actorVisitorId: OWNER,
@@ -68,7 +98,7 @@ describe("updateDocument 版本冲突", () => {
68
98
  actorVisitorId: OWNER,
69
99
  documentId: created.documentId,
70
100
  content: '{"v":2}',
71
- version: { baseCommitId: base },
101
+ version: { localBaseCommitId: base },
72
102
  });
73
103
  expect(updated.headCommitId).not.toBe(base);
74
104
  const row = findDocumentById(testDbRef.db, created.documentId);
@@ -86,21 +116,21 @@ describe("updateDocument 版本冲突", () => {
86
116
  actorVisitorId: OWNER,
87
117
  documentId: created.documentId,
88
118
  content: '{"v":2}',
89
- version: { baseCommitId: base },
119
+ version: { localBaseCommitId: base },
90
120
  });
91
121
  fileStoreMocks.lastWriteContent = '{"v":2}';
92
122
  expect(() => updateDocument({
93
123
  actorVisitorId: OWNER,
94
124
  documentId: created.documentId,
95
125
  content: '{"v":3}',
96
- version: { baseCommitId: base },
126
+ version: { localBaseCommitId: base },
97
127
  })).toThrow(DocumentError);
98
128
  try {
99
129
  updateDocument({
100
130
  actorVisitorId: OWNER,
101
131
  documentId: created.documentId,
102
132
  content: '{"v":3}',
103
- version: { baseCommitId: base },
133
+ version: { localBaseCommitId: base },
104
134
  });
105
135
  }
106
136
  catch (e) {
@@ -140,7 +170,7 @@ describe("updateDocument merge 发布", () => {
140
170
  actorVisitorId: OWNER,
141
171
  documentId: created.documentId,
142
172
  content: '{"remote":true}',
143
- version: { baseCommitId: base },
173
+ version: { localBaseCommitId: base },
144
174
  });
145
175
  const head = remote.headCommitId;
146
176
  const merged = updateDocument({
@@ -148,9 +178,9 @@ describe("updateDocument merge 发布", () => {
148
178
  documentId: created.documentId,
149
179
  content: '{"merged":true}',
150
180
  version: {
151
- baseCommitId: base,
181
+ localBaseCommitId: base,
152
182
  merge: {
153
- expectedHeadCommitId: head,
183
+ remoteCommitId: head,
154
184
  localSnapshotContent: '{"local":true}',
155
185
  },
156
186
  },
@@ -163,7 +193,7 @@ describe("updateDocument merge 发布", () => {
163
193
  expect(localCommitId).toBeTruthy();
164
194
  expect(listParentCommitIds(testDbRef.db, localCommitId)).toEqual([base]);
165
195
  });
166
- it("expectedHead 与当前 head 不一致时 409", () => {
196
+ it("remoteCommitId 与当前 head 不一致时 409", () => {
167
197
  const created = createDocument({
168
198
  actorVisitorId: OWNER,
169
199
  fileName: "merge-stale.md",
@@ -175,23 +205,46 @@ describe("updateDocument merge 发布", () => {
175
205
  actorVisitorId: OWNER,
176
206
  documentId: created.documentId,
177
207
  content: '{"r":1}',
178
- version: { baseCommitId: base },
208
+ version: { localBaseCommitId: base },
179
209
  });
180
210
  updateDocument({
181
211
  actorVisitorId: OWNER,
182
212
  documentId: created.documentId,
183
213
  content: '{"r":2}',
184
- version: { baseCommitId: remote.headCommitId },
214
+ version: { localBaseCommitId: remote.headCommitId },
185
215
  });
186
216
  expect(() => updateDocument({
187
217
  actorVisitorId: OWNER,
188
218
  documentId: created.documentId,
189
219
  content: '{"m":1}',
190
220
  version: {
191
- baseCommitId: base,
192
- merge: { expectedHeadCommitId: remote.headCommitId },
221
+ localBaseCommitId: base,
222
+ merge: { remoteCommitId: remote.headCommitId },
193
223
  },
194
224
  })).toThrow(DocumentError);
195
225
  });
196
226
  });
227
+ describe("getDocumentMergeContext", () => {
228
+ it("线性落后:LCA 为 localBase 并返回其 blob 正文", () => {
229
+ const created = createDocument({
230
+ actorVisitorId: OWNER,
231
+ fileName: "merge-ctx.md",
232
+ content: '{"v":1}',
233
+ domainId: "default",
234
+ });
235
+ const localBase = created.headCommitId;
236
+ const remote = updateDocument({
237
+ actorVisitorId: OWNER,
238
+ documentId: created.documentId,
239
+ content: '{"v":2}',
240
+ version: { localBaseCommitId: localBase },
241
+ });
242
+ const ctx = getDocumentMergeContext(created.documentId, localBase, remote.headCommitId);
243
+ expect(ctx.mode).toBe("three_way");
244
+ expect(ctx.mergeBaseCommitId).toBe(localBase);
245
+ const baseCommit = findCommitById(testDbRef.db, localBase);
246
+ expect(ctx.mergeBaseContent).toBe(fileStoreMocks.commitBlobs.get(baseCommit.blob_ref));
247
+ expect(ctx.mergeBaseContent).toBe('{"v":1}');
248
+ });
249
+ });
197
250
  //# sourceMappingURL=document-commit.integration.test.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"document-commit.integration.test.js","sourceRoot":"","sources":["../../../src/server/documents/document-commit.integration.test.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"document-commit.integration.test.js","sourceRoot":"","sources":["../../../src/server/documents/document-commit.integration.test.ts"],"names":[],"mappings":"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"}
@@ -2,12 +2,13 @@ import { randomUUID } from "node:crypto";
2
2
  import { getDb } from "../db/connection.js";
3
3
  import { deleteDocument, findDocumentById, findDocumentByPath, findDocumentInvite, findChildrenByParent, insertDocument, insertDocumentInvite, deleteDocumentInvite, listDocumentInvites, listDocumentsByDomain, listDocumentsByPathPrefix, updateDocumentContent, updateDocumentHeadCommit, } from "../db/repositories/document.repo.js";
4
4
  import { insertCommit, insertCommitParent } from "../db/repositories/commit.repo.js";
5
- import { assertCommitBelongsToDocument, assertMergeFork, isAncestorOf, } from "./commit-graph.js";
5
+ import { assertCommitBelongsToDocument, assertMergeFork, findMergeBaseCommitId, isAncestorOf, } from "./commit-graph.js";
6
+ import { findCommitById } from "../db/repositories/commit.repo.js";
6
7
  import { findDomainById, isDomainMember, } from "../db/repositories/domain.repo.js";
7
8
  import { resolveDomainAccess, canEnterDomainTree, } from "../access/domain-access.js";
8
9
  import { DocumentError, Permission, canReadDocument, canEditDocument, validateDomainPermission, } from "../access/access-control.js";
9
10
  import { insertAuditLog } from "../db/repositories/audit.repo.js";
10
- import { deleteDocumentFile, readDocument, sha256, writeCommitBlob, writeDocument, } from "../storage/file-store.js";
11
+ import { deleteDocumentFile, readCommitBlob, readDocument, sha256, writeCommitBlob, writeDocument, } from "../storage/file-store.js";
11
12
  import { markDirty, removeIndex, rebuildDocument, } from "../search/document-index-manager.js";
12
13
  import { getConfig } from "../config/index.js";
13
14
  import { markdownToLexicalJson } from "./markdown-to-lexical.js";
@@ -263,12 +264,12 @@ export function updateDocument(params) {
263
264
  const displayName = params.displayName?.trim() || row.display_name;
264
265
  const now = new Date().toISOString();
265
266
  const version = params.version;
266
- const baseCommitId = version?.baseCommitId;
267
+ const localBaseCommitId = version?.localBaseCommitId;
267
268
  const mergeCtx = version?.merge;
268
269
  // 冲突解决后的合并发布:插 r_local + 双父 merge 节点
269
270
  if (mergeCtx) {
270
- if (!baseCommitId) {
271
- throw new DocumentError("BAD_REQUEST", "merge 发布需要在 version 中提供 baseCommitId", 400);
271
+ if (!localBaseCommitId) {
272
+ throw new DocumentError("BAD_REQUEST", "merge 发布需要在 version 中提供 localBaseCommitId", 400);
272
273
  }
273
274
  const localSnapshotContent = mergeCtx.localSnapshotContent !== undefined
274
275
  ? normalizeDocumentContent(mergeCtx.localSnapshotContent, params.contentFormat)
@@ -279,14 +280,14 @@ export function updateDocument(params) {
279
280
  content,
280
281
  displayName,
281
282
  permission: params.permission,
282
- baseCommitId,
283
- expectedHeadCommitId: mergeCtx.expectedHeadCommitId,
283
+ localBaseCommitId,
284
+ remoteCommitId: mergeCtx.remoteCommitId,
284
285
  localSnapshotContent,
285
286
  now,
286
287
  });
287
288
  }
288
289
  // 普通线性发布:客户端 base 必须等于当前 head(未传 version 则跳过校验)
289
- assertNoVersionConflict(db, row, baseCommitId);
290
+ assertNoVersionConflict(db, row, localBaseCommitId);
290
291
  const write = writeDocument(row.domain_id, row.relative_path, content);
291
292
  const commitId = randomUUID();
292
293
  const blob = writeCommitBlob(write.contentHash, content);
@@ -339,6 +340,10 @@ export function updateDocument(params) {
339
340
  // ignore
340
341
  }
341
342
  });
343
+ // 写后直接返回最新 DocumentDetail(而非要求前端再 GET):
344
+ // 1) 降低竞争态:避免 PUT 与后续 GET 间隙被他人再次推进 head;
345
+ // 2) 单一真相:以后端实际落库结果为准(权限、head、invite 派生字段等)。
346
+ const invitedEdit = resolveInvitedEditFlag(db, row, params.actorVisitorId);
342
347
  return buildDocumentDetail(row, {
343
348
  displayName,
344
349
  content,
@@ -347,6 +352,7 @@ export function updateDocument(params) {
347
352
  updatedAt: now,
348
353
  permission: params.permission !== undefined ? params.permission : row.permission,
349
354
  headCommitId: commitId,
355
+ invitedEdit,
350
356
  });
351
357
  }
352
358
  // ============================================================
@@ -505,6 +511,7 @@ function buildDocumentDetail(row, overrides) {
505
511
  updatedBy: overrides.updatedBy,
506
512
  updatedAt: overrides.updatedAt,
507
513
  permission: overrides.permission,
514
+ ...(overrides.invitedEdit ? { invitedEdit: true } : {}),
508
515
  };
509
516
  }
510
517
  /**
@@ -519,19 +526,19 @@ function throwVersionConflict(row, serverContent, serverContentHash) {
519
526
  });
520
527
  }
521
528
  /**
522
- * 普通发布前的乐观锁:baseCommitId 与 head 不一致则冲突。
523
- * 未传 baseCommitId 时跳过(兼容尚未接入的前端)。
529
+ * 普通发布前的乐观锁:localBaseCommitId 与 head 不一致则冲突。
530
+ * 未传 localBaseCommitId 时跳过(兼容尚未接入的前端)。
524
531
  */
525
- function assertNoVersionConflict(db, row, baseCommitId) {
526
- // 客户端没传 base:旧版前端或未启用冲突检测,直接放行(不进行冲突校验)
532
+ function assertNoVersionConflict(db, row, localBaseCommitId) {
533
+ // 客户端没传 localBase:旧版前端或未启用冲突检测,直接放行(不进行冲突校验)
527
534
  // 文档尚无 head:历史数据/异常态,无法比对,也放行
528
- if (!baseCommitId || !row.head_commit_id)
535
+ if (!localBaseCommitId || !row.head_commit_id)
529
536
  return;
530
537
  // 客户端认为的「我基于的那一版」仍等于服务端当前 head → 无人插队,可 fast-forward 发布
531
- if (baseCommitId === row.head_commit_id)
538
+ if (localBaseCommitId === row.head_commit_id)
532
539
  return;
533
- // 走到这里:base 有值且与 head 不同 → 说明在你编辑期间 head 已被别人/另一标签推进 → 409
534
- assertCommitBelongsToDocument(db, baseCommitId, row.document_id);
540
+ // 走到这里:localBase 有值且与 head 不同 → 说明在你编辑期间 head 已被别人/另一标签推进 → 409
541
+ assertCommitBelongsToDocument(db, localBaseCommitId, row.document_id);
535
542
  const { content, contentHash } = readDocument(row.domain_id, row.relative_path);
536
543
  throwVersionConflict(row, content, contentHash);
537
544
  }
@@ -540,14 +547,14 @@ function assertNoVersionConflict(db, row, baseCommitId) {
540
547
  *
541
548
  * 提交图(merge 完成后)示意:
542
549
  *
543
- * base(开编时的 head,version.baseCommitId
544
- * ├── expectedHead(冲突时远端最新,version.merge.expectedHeadCommitId
545
- * └── r_local(本地支,本次首次落库;父 = base
550
+ * localBaseCommitId(开编分叉点,version.localBaseCommitId
551
+ * ├── remoteCommitId(冲突时远端 tip,version.merge.remoteCommitId
552
+ * └── localCommitId(r_local,本次首次落库;父 = localBaseCommitId
546
553
  * \ /
547
- * merge(合成稿,新 head;父 = expectedHead + r_local
554
+ * mergeCommitId(合成稿,新 head;父 = remoteCommitId + localCommitId
548
555
  *
549
556
  * 步骤:
550
- * 1. 校验:expectedHead 仍为当前 head;baseexpectedHead 的祖先(assertMergeFork)
557
+ * 1. 校验:remoteCommitId 仍为当前 head;localBaseremote 的祖先(assertMergeFork)
551
558
  * 2. 写盘:工作区 = 合成稿;commits 目录落 r_local / merge 快照(writeCommitBlob)
552
559
  * 3. 事务:插 r_local + merge 节点与边,更新 documents.head_commit_id
553
560
  */
@@ -559,13 +566,13 @@ function publishMergeDocument(params) {
559
566
  throw new DocumentError("BAD_REQUEST", "文档尚无提交历史,无法合并发布", 400);
560
567
  }
561
568
  // 合并过程中若 head 又被别人推进,同样 409
562
- if (params.expectedHeadCommitId !== row.head_commit_id) {
569
+ if (params.remoteCommitId !== row.head_commit_id) {
563
570
  const { content: serverContent, contentHash } = readDocument(row.domain_id, row.relative_path);
564
571
  throwVersionConflict(row, serverContent, contentHash);
565
572
  }
566
- assertCommitBelongsToDocument(db, params.baseCommitId, row.document_id);
567
- assertCommitBelongsToDocument(db, params.expectedHeadCommitId, row.document_id);
568
- assertMergeFork(db, params.baseCommitId, params.expectedHeadCommitId);
573
+ assertCommitBelongsToDocument(db, params.localBaseCommitId, row.document_id);
574
+ assertCommitBelongsToDocument(db, params.remoteCommitId, row.document_id);
575
+ assertMergeFork(db, params.localBaseCommitId, params.remoteCommitId);
569
576
  // 写盘:工作区 + 两份历史快照(r_local 支 / merge 结果)
570
577
  const localContent = params.localSnapshotContent ?? content;
571
578
  const localHash = sha256(Buffer.from(localContent, "utf8"));
@@ -597,7 +604,7 @@ function publishMergeDocument(params) {
597
604
  });
598
605
  insertCommitParent(db, {
599
606
  childCommitId: localCommitId,
600
- parentCommitId: params.baseCommitId,
607
+ parentCommitId: params.localBaseCommitId,
601
608
  });
602
609
  updateDocumentContent(db, {
603
610
  documentId: row.document_id,
@@ -620,7 +627,7 @@ function publishMergeDocument(params) {
620
627
  // 这里存储的是远端head
621
628
  insertCommitParent(db, {
622
629
  childCommitId: mergeCommitId,
623
- parentCommitId: params.expectedHeadCommitId,
630
+ parentCommitId: params.remoteCommitId,
624
631
  });
625
632
  // 这里存储的是r_local
626
633
  insertCommitParent(db, {
@@ -639,8 +646,8 @@ function publishMergeDocument(params) {
639
646
  targetType: "document",
640
647
  targetId: row.document_id,
641
648
  metadata: {
642
- baseCommitId: params.baseCommitId,
643
- expectedHeadCommitId: params.expectedHeadCommitId,
649
+ localBaseCommitId: params.localBaseCommitId,
650
+ remoteCommitId: params.remoteCommitId,
644
651
  localCommitId,
645
652
  mergeCommitId,
646
653
  },
@@ -657,6 +664,10 @@ function publishMergeDocument(params) {
657
664
  // ignore
658
665
  }
659
666
  });
667
+ // merge 发布同样采用“写后即返回最新资源”:
668
+ // - 避免前端二次查询引入时序偏差;
669
+ // - 确保 UI 使用服务端合并后的最终状态作为唯一真相。
670
+ const invitedEdit = resolveInvitedEditFlag(db, row, actorVisitorId);
660
671
  return buildDocumentDetail(row, {
661
672
  displayName,
662
673
  content,
@@ -665,6 +676,7 @@ function publishMergeDocument(params) {
665
676
  updatedAt: now,
666
677
  permission: params.permission !== undefined ? params.permission : row.permission,
667
678
  headCommitId: mergeCommitId,
679
+ invitedEdit,
668
680
  });
669
681
  }
670
682
  function deriveDisplayName(raw, relativePath) {
@@ -678,32 +690,68 @@ function deriveDisplayName(raw, relativePath) {
678
690
  function normalizeDocumentContent(content, contentFormat) {
679
691
  return contentFormat === "markdown" ? markdownToLexicalJson(content) : content;
680
692
  }
693
+ function resolveInvitedEditFlag(db, row, actorVisitorId) {
694
+ if (row.owner_visitor_id === actorVisitorId)
695
+ return false;
696
+ const invite = findDocumentInvite(db, row.document_id, actorVisitorId);
697
+ return invite?.permission === "edit";
698
+ }
681
699
  // ============================================================
682
700
  // 同步状态(轻量轮询,不返回正文)
683
701
  // ============================================================
684
702
  /**
685
- * 比较客户端 baseCommitId 与服务端 head,用于 Sync 指示。
686
- * - up_to_date:base 未传、无 head、或 base === head
687
- * - behind:base 是 head 的祖先(远端有更新)
688
- * - ahead:其余(含分叉、脏 base)
703
+ * 比较客户端 localBaseCommitId 与服务端 head(remoteCommitId),用于 Sync 指示。
704
+ * - up_to_date:localBase 未传、无 head、或 localBase === head
705
+ * - behind:localBase 是 head 的祖先(远端有更新)
706
+ * - ahead:其余(含分叉、历史回退等)
689
707
  */
690
- export function getDocumentSyncStatus(documentId, baseCommitId) {
708
+ export function getDocumentSyncStatus(documentId, localBaseCommitId) {
691
709
  const row = findDocumentById(getDb(), documentId);
692
710
  if (!row)
693
711
  throw new DocumentError("DOC_NOT_FOUND", "文档不存在", 404);
694
712
  const head = row.head_commit_id;
695
- if (!baseCommitId || !head) {
713
+ if (!localBaseCommitId || !head) {
696
714
  return { status: "up_to_date", headCommitId: head };
697
715
  }
698
- if (baseCommitId === head) {
716
+ if (localBaseCommitId === head) {
699
717
  return { status: "up_to_date", headCommitId: head };
700
718
  }
701
719
  const db = getDb();
702
- if (isAncestorOf(db, baseCommitId, head)) {
720
+ if (isAncestorOf(db, localBaseCommitId, head)) {
703
721
  return { status: "behind", headCommitId: head };
704
722
  }
705
723
  return { status: "ahead", headCommitId: head };
706
724
  }
725
+ /**
726
+ * 为 merge UI 提供 LCA 正文:根据 localBase / remote 在 DAG 上求 mergeBase,读取 blob。
727
+ * 无法求 LCA 或读 blob 失败时返回 two_way(前端可退化为开编快照或两方 diff)。
728
+ */
729
+ export function getDocumentMergeContext(documentId, localBaseCommitId, remoteCommitId) {
730
+ const row = findDocumentById(getDb(), documentId);
731
+ if (!row)
732
+ throw new DocumentError("DOC_NOT_FOUND", "文档不存在", 404);
733
+ const db = getDb();
734
+ assertCommitBelongsToDocument(db, localBaseCommitId, documentId);
735
+ assertCommitBelongsToDocument(db, remoteCommitId, documentId);
736
+ let mergeBaseCommitId;
737
+ try {
738
+ mergeBaseCommitId = findMergeBaseCommitId(db, localBaseCommitId, remoteCommitId);
739
+ }
740
+ catch {
741
+ return { mode: "two_way", mergeBaseCommitId: null, mergeBaseContent: null };
742
+ }
743
+ const baseCommit = findCommitById(db, mergeBaseCommitId);
744
+ if (!baseCommit) {
745
+ return { mode: "two_way", mergeBaseCommitId: null, mergeBaseContent: null };
746
+ }
747
+ try {
748
+ const mergeBaseContent = readCommitBlob(baseCommit.blob_ref);
749
+ return { mode: "three_way", mergeBaseCommitId, mergeBaseContent };
750
+ }
751
+ catch {
752
+ return { mode: "two_way", mergeBaseCommitId: null, mergeBaseContent: null };
753
+ }
754
+ }
707
755
  /** 内容格式转换(merge 发布:markdown → Lexical)。 */
708
756
  export function convertDocumentContent(params) {
709
757
  if (params.from === params.to)