ocean-brain 0.13.2 → 0.14.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 (158) hide show
  1. package/README.md +66 -2
  2. package/dist/mcp.js +439 -480
  3. package/package.json +2 -2
  4. package/server/client/dist/assets/{ArrowRight.es-BlNsZQFs.js → ArrowRight.es-nBJws3ws.js} +1 -1
  5. package/server/client/dist/assets/{AuxiliaryPanelHeader-HAttwVby.js → AuxiliaryPanelHeader-BN_2axQu.js} +1 -1
  6. package/server/client/dist/assets/{Calendar-DH3eSSRs.js → Calendar-vA4Xa4Qr.js} +1 -1
  7. package/server/client/dist/assets/{Callout-CcYyvHQP.js → Callout-Bo2P960P.js} +1 -1
  8. package/server/client/dist/assets/{CaretUp.es-C8iY5OlB.js → CaretUp.es-DDbqKn78.js} +1 -1
  9. package/server/client/dist/assets/{CheckCircle.es-Dqr3WImn.js → CheckCircle.es-CyY9aLBF.js} +1 -1
  10. package/server/client/dist/assets/{Copy.es-fMv0ETir.js → Copy.es-BwX4tEoU.js} +1 -1
  11. package/server/client/dist/assets/{File.es-CHtXXafR.js → File.es-DeTgvUnI.js} +1 -1
  12. package/server/client/dist/assets/{FileText.es-DPIwDCEe.js → FileText.es-C-bpw8dQ.js} +1 -1
  13. package/server/client/dist/assets/{FlowArrow.es-Dxee98ir.js → FlowArrow.es-CKcMBOmX.js} +1 -1
  14. package/server/client/dist/assets/{Graph-hVj6vAYJ.js → Graph-BNoSRJP3.js} +1 -1
  15. package/server/client/dist/assets/{Graph-CdEu8eAn.js → Graph-DYYxNAWn.js} +1 -1
  16. package/server/client/dist/assets/{Image.es-CjXY1JVf.js → Image.es-d4jWnijM.js} +1 -1
  17. package/server/client/dist/assets/{Info.es-CYxg-Vku.js → Info.es-DVzN2joA.js} +1 -1
  18. package/server/client/dist/assets/Integration-gDDtIJYJ.js +1 -0
  19. package/server/client/dist/assets/{LinkSimple.es-B-P-7Iem.js → LinkSimple.es-BD4aGTc3.js} +1 -1
  20. package/server/client/dist/assets/Note-FL31jb2U.js +19 -0
  21. package/server/client/dist/assets/{NotePropertiesPanel-6P7UfRBR.js → NotePropertiesPanel-os22Ppnu.js} +1 -1
  22. package/server/client/dist/assets/{Plus.es-Dy6onD-Z.js → Plus.es-Cl8zOOZa.js} +1 -1
  23. package/server/client/dist/assets/Reminders-Dt2JuGci.js +1 -0
  24. package/server/client/dist/assets/{Search-D9detGWk.js → Search-CPPTW2PO.js} +2 -2
  25. package/server/client/dist/assets/{SurfaceCard-D5QxOte_.js → SurfaceCard-jL2qzrzF.js} +1 -1
  26. package/server/client/dist/assets/{Tag-Bquqtx23.js → Tag-3DbGmuxa.js} +1 -1
  27. package/server/client/dist/assets/{TagNotes-CbjfxqAN.js → TagNotes-DLwRF8pT.js} +1 -1
  28. package/server/client/dist/assets/Trash.es-fxukjAO6.js +1 -0
  29. package/server/client/dist/assets/{ViewChip-BVkZAXyx.js → ViewChip-CVe_HNyd.js} +1 -1
  30. package/server/client/dist/assets/Views-8ghLRax7.js +1 -0
  31. package/server/client/dist/assets/{abnfDiagram-N423BO3Z-D44O4T7q.js → abnfDiagram-N423BO3Z-CPgGmCbn.js} +1 -1
  32. package/server/client/dist/assets/app-Bcl0U7r9.css +1 -0
  33. package/server/client/dist/assets/app-DzChh-V0.js +151 -0
  34. package/server/client/dist/assets/{arc-Cil9fXuW.js → arc-DqTgRpuF.js} +1 -1
  35. package/server/client/dist/assets/{architectureDiagram-T3A2C74G-Cjq6ayF2.js → architectureDiagram-T3A2C74G-rTYMAQ-J.js} +1 -1
  36. package/server/client/dist/assets/{blockDiagram-VBNYF7ZC-B2Xm5N0i.js → blockDiagram-VBNYF7ZC-BOluytVz.js} +1 -1
  37. package/server/client/dist/assets/{c4Diagram-5PPSVZJV-Dp0y-lCR.js → c4Diagram-5PPSVZJV-C8gbPpcb.js} +1 -1
  38. package/server/client/dist/assets/{calendar-data-wB0ifXdo.js → calendar-data-BQ24n348.js} +1 -1
  39. package/server/client/dist/assets/channel--aI9fJWX.js +1 -0
  40. package/server/client/dist/assets/{chunk-2GRJ4B5K-CWaaNkFx.js → chunk-2GRJ4B5K-CRER5Ka0.js} +1 -1
  41. package/server/client/dist/assets/{chunk-2Q5K7J3B-Ces-xz2S.js → chunk-2Q5K7J3B-hxmJWGu_.js} +1 -1
  42. package/server/client/dist/assets/{chunk-5RXB4S5H-B-4Chlfc.js → chunk-5RXB4S5H-Bpr5Us8Y.js} +1 -1
  43. package/server/client/dist/assets/{chunk-5VM5RSS4-C8_HVwuz.js → chunk-5VM5RSS4-CKUz9fAb.js} +1 -1
  44. package/server/client/dist/assets/{chunk-6Q2QTUOP-xZ8ofRqk.js → chunk-6Q2QTUOP-B8XEOHPN.js} +1 -1
  45. package/server/client/dist/assets/{chunk-GF5L2VYU-Bpa43a7s.js → chunk-GF5L2VYU-BBUD-HJi.js} +1 -1
  46. package/server/client/dist/assets/{chunk-JWPE2WC7-DsyTXbuq.js → chunk-JWPE2WC7-Dq6_B8-d.js} +1 -1
  47. package/server/client/dist/assets/{chunk-KBJHAD2P-BDhjm9-8.js → chunk-KBJHAD2P--2VZEwNJ.js} +1 -1
  48. package/server/client/dist/assets/{chunk-RYQCIY6F-Cn-jdp6I.js → chunk-RYQCIY6F-CKCwnKiC.js} +1 -1
  49. package/server/client/dist/assets/{chunk-XXDRQBXY-BKsc_0wh.js → chunk-XXDRQBXY-VDufR1Oi.js} +1 -1
  50. package/server/client/dist/assets/classDiagram-JCYQIIEL-BsbwE38V.js +1 -0
  51. package/server/client/dist/assets/classDiagram-v2-OCEON4UE-BsbwE38V.js +1 -0
  52. package/server/client/dist/assets/{cose-bilkent-JH36ORCC-jmn3Q4zj.js → cose-bilkent-JH36ORCC-D4nqOx8S.js} +1 -1
  53. package/server/client/dist/assets/{cynefinDiagram-MW4NZA55-BpLstuBJ.js → cynefinDiagram-MW4NZA55-CUuLMs-6.js} +1 -1
  54. package/server/client/dist/assets/{dagre-VZM6K2ZE-B5ft5Yzm.js → dagre-VZM6K2ZE-CUSkhZgS.js} +1 -1
  55. package/server/client/dist/assets/{diagram-7IWD3JNH-B_W9IsWZ.js → diagram-7IWD3JNH-D95eVcKx.js} +4 -4
  56. package/server/client/dist/assets/{diagram-B4RE2ZJO-32chS3GX.js → diagram-B4RE2ZJO-7OH_fb0K.js} +1 -1
  57. package/server/client/dist/assets/{diagram-LBJQPF4R-Bqupdb3-.js → diagram-LBJQPF4R-D9UwEIMd.js} +1 -1
  58. package/server/client/dist/assets/{diagram-Q27KOJAE-BD8jKBsv.js → diagram-Q27KOJAE-Dx7WFDuX.js} +1 -1
  59. package/server/client/dist/assets/{diagram-UB23O5K3-C40jAU8D.js → diagram-UB23O5K3-D2BYwAKT.js} +1 -1
  60. package/server/client/dist/assets/{ebnfDiagram-BXEA7PRR-BQfW9mFA.js → ebnfDiagram-BXEA7PRR-DbeA-fk4.js} +1 -1
  61. package/server/client/dist/assets/{erDiagram-JOGREHBK-ILZnLzz2.js → erDiagram-JOGREHBK-jWW-ICGO.js} +1 -1
  62. package/server/client/dist/assets/{flowDiagram-UKHOOZJN-CDmwr2dI.js → flowDiagram-UKHOOZJN-68iZdxxw.js} +1 -1
  63. package/server/client/dist/assets/{ganttDiagram-PKOTCBZU-DBcrUc49.js → ganttDiagram-PKOTCBZU-CxwY3VXg.js} +1 -1
  64. package/server/client/dist/assets/{gitGraphDiagram-DS77QQ5N-_xO6__FK.js → gitGraphDiagram-DS77QQ5N-Ci6o5MfZ.js} +1 -1
  65. package/server/client/dist/assets/{image.api-ChvlfuZg.js → image.api-CyIIEGkG.js} +1 -1
  66. package/server/client/dist/assets/index-Iy_BgP1R.js +1 -0
  67. package/server/client/dist/assets/{infoDiagram-6WML65LV-CuIIcu-L.js → infoDiagram-6WML65LV-DY7aMdjV.js} +1 -1
  68. package/server/client/dist/assets/integrations-LOdTs1T6.js +1 -0
  69. package/server/client/dist/assets/{ishikawaDiagram-WSZJBQD7-BVtRGTOj.js → ishikawaDiagram-WSZJBQD7-Bh5qKh1d.js} +1 -1
  70. package/server/client/dist/assets/{journeyDiagram-NVQOT4AX-D5-Nzb2N.js → journeyDiagram-NVQOT4AX-B_svXTTT.js} +1 -1
  71. package/server/client/dist/assets/{kanban-definition-27J2QSJJ-DmOhgC8H.js → kanban-definition-27J2QSJJ-CaJslHGg.js} +1 -1
  72. package/server/client/dist/assets/manage-image-DXedfr7U.js +1 -0
  73. package/server/client/dist/assets/{manage-image-detail-BIDHUR5-.js → manage-image-detail-DmifOPNU.js} +1 -1
  74. package/server/client/dist/assets/{mcp-admin-adapter-D0R8p9az.js → mcp-admin-adapter-CmKsg1vd.js} +1 -1
  75. package/server/client/dist/assets/mcp-d8IzsoRz.js +5 -0
  76. package/server/client/dist/assets/{mermaid.core-C2tL9tq7.js → mermaid.core-BfUQM5vF.js} +4 -4
  77. package/server/client/dist/assets/{mindmap-definition-FAOFIHXS-DuvsPqrh.js → mindmap-definition-FAOFIHXS-DGbkJda2.js} +1 -1
  78. package/server/client/dist/assets/{note-core-YhYEmI_R.js → note-core-DRBsBf9H.js} +9 -9
  79. package/server/client/dist/assets/{note-runtime-B3ats-dC.js → note-runtime-ztZvXRIu.js} +16 -16
  80. package/server/client/dist/assets/{note-ui-BtzPk8gA.js → note-ui-DRnAnwKv.js} +1 -1
  81. package/server/client/dist/assets/{pegDiagram-VL7TDLO6-D64crEZV.js → pegDiagram-VL7TDLO6-Bip6zQct.js} +1 -1
  82. package/server/client/dist/assets/{pieDiagram-7S7Q4E2Y--kl7vopC.js → pieDiagram-7S7Q4E2Y-CjfjGY8Y.js} +1 -1
  83. package/server/client/dist/assets/{placeholder-DKgxoe_f.js → placeholder-G6iEBbDy.js} +1 -1
  84. package/server/client/dist/assets/{properties-B7Fv95qY.js → properties-BPobx_Qk.js} +1 -1
  85. package/server/client/dist/assets/{quadrantDiagram-CIZ2JOQS-DuvJ4M2y.js → quadrantDiagram-CIZ2JOQS-B6F1yUT-.js} +1 -1
  86. package/server/client/dist/assets/{railroadDiagram-AXF67PYL-BMKmCOY7.js → railroadDiagram-AXF67PYL-D-0fLe0F.js} +1 -1
  87. package/server/client/dist/assets/{requirementDiagram-LRYGKXZP-DY1eJcy0.js → requirementDiagram-LRYGKXZP-tm4mnCyJ.js} +1 -1
  88. package/server/client/dist/assets/route-preload.js +2 -2
  89. package/server/client/dist/assets/{sankeyDiagram-W5VNT64P-C3Ka4GKM.js → sankeyDiagram-W5VNT64P-DSBWFurb.js} +1 -1
  90. package/server/client/dist/assets/{search-ddYl3qH-.js → search-DanMKCC8.js} +1 -1
  91. package/server/client/dist/assets/{search-admin-adapter-Daf7e2YQ.js → search-admin-adapter-7sTcWTmv.js} +1 -1
  92. package/server/client/dist/assets/{sequenceDiagram-SI44F4Z6-Bhpwtk2s.js → sequenceDiagram-SI44F4Z6-KrwjjJIV.js} +1 -1
  93. package/server/client/dist/assets/{sizeCapture-X5ZJPWSS-BFta71TW.js → sizeCapture-X5ZJPWSS-DL2cn_Q6.js} +1 -1
  94. package/server/client/dist/assets/{stateDiagram-OKZ733FA-D6GCn1io.js → stateDiagram-OKZ733FA-CKuNDH85.js} +1 -1
  95. package/server/client/dist/assets/{stateDiagram-v2-UEYNNEHI-g4yinGDn.js → stateDiagram-v2-UEYNNEHI-BFaj2wbM.js} +1 -1
  96. package/server/client/dist/assets/{swimlanes-SLNWSIFB-DLFvOjUl.js → swimlanes-SLNWSIFB-5S17nqhK.js} +2 -2
  97. package/server/client/dist/assets/swimlanesDiagram-ULZ7WXOC-dexsHJq2.js +8 -0
  98. package/server/client/dist/assets/{tag.api-DEUROVKQ.js → tag.api-kKZl04yY.js} +1 -1
  99. package/server/client/dist/assets/{time-PxWila4-.js → time-BwwQGbK-.js} +38 -38
  100. package/server/client/dist/assets/{timeline-definition-Z64GVDOM-DTSIekSM.js → timeline-definition-Z64GVDOM-CU1hp_7d.js} +3 -3
  101. package/server/client/dist/assets/{trash-BHida7BG.js → trash-Cepvi7G8.js} +1 -1
  102. package/server/client/dist/assets/url-Bp8sXMb4.js +1 -0
  103. package/server/client/dist/assets/{useNoteMutate-BjvZUmtX.js → useNoteMutate-D-mZKXjl.js} +3 -3
  104. package/server/client/dist/assets/{useReminderMutate-C5n-5LM-.js → useReminderMutate-Cexk1ydX.js} +1 -1
  105. package/server/client/dist/assets/{vennDiagram-T6HMQDX7-CMNqSI2X.js → vennDiagram-T6HMQDX7-MoiVLnil.js} +1 -1
  106. package/server/client/dist/assets/{wardleyDiagram-T6FBY63Y-DV-JOYqB.js → wardleyDiagram-T6FBY63Y-cZkfdI6C.js} +1 -1
  107. package/server/client/dist/assets/{xychartDiagram-ELKLHX3M-BUIniF4m.js → xychartDiagram-ELKLHX3M-B63hxD-r.js} +1 -1
  108. package/server/client/dist/index.html +6 -6
  109. package/server/dist/app.js +2 -0
  110. package/server/dist/features/integration/auth.js +21 -0
  111. package/server/dist/features/integration/manifest.js +87 -0
  112. package/server/dist/features/integration/schema.js +54 -0
  113. package/server/dist/features/integration/service.js +173 -0
  114. package/server/dist/features/mcp-admin/service.js +19 -83
  115. package/server/dist/features/note/graphql/note.field.resolver.js +1 -1
  116. package/server/dist/features/note/graphql/note.query.resolver.js +6 -0
  117. package/server/dist/features/note/graphql/note.type-defs.js +13 -1
  118. package/server/dist/features/note/http/authoring.js +493 -0
  119. package/server/dist/features/note/http/mcp.js +15 -463
  120. package/server/dist/features/note/services/authoring.js +17 -1
  121. package/server/dist/features/note/services/markdown-intent-write.js +1 -0
  122. package/server/dist/features/note/services/markdown-read.js +85 -0
  123. package/server/dist/features/note/services/properties.js +36 -30
  124. package/server/dist/features/note/services/search.js +17 -0
  125. package/server/dist/features/search/graphql/resolver.js +10 -1
  126. package/server/dist/features/search/graphql/type-defs.js +3 -0
  127. package/server/dist/features/tag/graphql/tag.query.resolver.js +10 -0
  128. package/server/dist/features/tag/graphql/tag.type-defs.js +1 -0
  129. package/server/dist/features/view/graphql/mcp.query.resolver.js +22 -0
  130. package/server/dist/features/view/graphql/view.query.resolver.js +2 -0
  131. package/server/dist/features/view/graphql/view.type-defs.js +27 -0
  132. package/server/dist/features/view/services/mcp-read.js +142 -0
  133. package/server/dist/features/view/services/workspace.js +12 -4
  134. package/server/dist/modules/auth-guard.js +24 -1
  135. package/server/dist/modules/integration-token.js +27 -0
  136. package/server/dist/modules/mcp-auth.js +37 -23
  137. package/server/dist/modules/mcp-token.js +6 -25
  138. package/server/dist/routes/api.js +2 -0
  139. package/server/dist/routes/graphql.js +2 -1
  140. package/server/dist/routes/integrations.js +117 -0
  141. package/server/dist/routes/mcp.js +29 -9
  142. package/server/prisma/migrations/20260917120000_0020_plugin_installations/migration.sql +39 -0
  143. package/server/prisma/migrations/20260917150000_0021_integration_connections/migration.sql +29 -0
  144. package/server/prisma/schema.prisma +34 -10
  145. package/server/client/dist/assets/Note-CpzLtGVM.js +0 -19
  146. package/server/client/dist/assets/Reminders-DnuALBL6.js +0 -1
  147. package/server/client/dist/assets/Trash.es-XEcWG_aq.js +0 -1
  148. package/server/client/dist/assets/Views-L4eC96Lx.js +0 -1
  149. package/server/client/dist/assets/app-BFM2V_Rx.js +0 -151
  150. package/server/client/dist/assets/app-DjDwGe0t.css +0 -1
  151. package/server/client/dist/assets/channel-DZFalh-h.js +0 -1
  152. package/server/client/dist/assets/classDiagram-JCYQIIEL-CkEhFvVV.js +0 -1
  153. package/server/client/dist/assets/classDiagram-v2-OCEON4UE-CkEhFvVV.js +0 -1
  154. package/server/client/dist/assets/index-CJPl3MJE.js +0 -1
  155. package/server/client/dist/assets/manage-image-CSJ3Flgc.js +0 -1
  156. package/server/client/dist/assets/mcp-D8footel.js +0 -5
  157. package/server/client/dist/assets/swimlanesDiagram-ULZ7WXOC-Ci4mcvmo.js +0 -8
  158. package/server/client/dist/assets/url-DKUMNVCI.js +0 -1
@@ -0,0 +1,493 @@
1
+ import { createNoteFromMarkdown, InvalidNoteAuthoringInputError } from "../../../features/note/services/authoring.js";
2
+ import { deleteNoteById } from "../../../features/note/services/cleanup.js";
3
+ import {
4
+ appendNoteMarkdown,
5
+ patchNoteMarkdown,
6
+ replaceNoteMarkdown,
7
+ updateNoteMetadata
8
+ } from "../../../features/note/services/markdown-intent-write.js";
9
+ import {
10
+ InvalidNotePropertyInputError
11
+ } from "../../../features/note/services/properties.js";
12
+ import models from "../../../models.js";
13
+ import { createAppError } from "../../../modules/error-handler.js";
14
+ import { emitServerEvent } from "../../../modules/server-events.js";
15
+ const NOTE_LAYOUTS = /* @__PURE__ */ new Set(["narrow", "wide", "full"]);
16
+ const POSITION_HINTS = /* @__PURE__ */ new Set(["first", "last"]);
17
+ const PRESERVATION_POLICIES = /* @__PURE__ */ new Set([true, false, "warn"]);
18
+ const isRecord = (value) => {
19
+ return typeof value === "object" && value !== null;
20
+ };
21
+ const resolveNoteLayout = (value) => {
22
+ if (value === void 0) {
23
+ return void 0;
24
+ }
25
+ if (typeof value === "string" && NOTE_LAYOUTS.has(value)) {
26
+ return value;
27
+ }
28
+ return null;
29
+ };
30
+ const resolveOptionalString = (value, code, message) => {
31
+ if (value === void 0) {
32
+ return void 0;
33
+ }
34
+ if (typeof value === "string") {
35
+ return value;
36
+ }
37
+ throw createAppError(400, code, message);
38
+ };
39
+ const resolveMetadataPropertyPatch = (value) => {
40
+ if (value === void 0) {
41
+ return void 0;
42
+ }
43
+ if (!isRecord(value)) {
44
+ throw createAppError(400, "INVALID_NOTE_PROPERTIES", "Properties patch must be an object.");
45
+ }
46
+ const set = value.set === void 0 ? void 0 : Array.isArray(value.set) ? value.set.map((item) => {
47
+ if (!isRecord(item) || typeof item.key !== "string" || typeof item.value !== "string") {
48
+ throw createAppError(
49
+ 400,
50
+ "INVALID_NOTE_PROPERTIES",
51
+ "Property set items must include string key and value fields."
52
+ );
53
+ }
54
+ return {
55
+ key: item.key,
56
+ value: item.value
57
+ };
58
+ }) : null;
59
+ if (set === null) {
60
+ throw createAppError(400, "INVALID_NOTE_PROPERTIES", "Property set must be an array.");
61
+ }
62
+ const deleteKeys = value.deleteKeys === void 0 ? void 0 : Array.isArray(value.deleteKeys) ? value.deleteKeys.map((key) => {
63
+ if (typeof key !== "string") {
64
+ throw createAppError(400, "INVALID_NOTE_PROPERTIES", "Property deleteKeys must be strings.");
65
+ }
66
+ return key;
67
+ }) : null;
68
+ if (deleteKeys === null) {
69
+ throw createAppError(400, "INVALID_NOTE_PROPERTIES", "Property deleteKeys must be an array.");
70
+ }
71
+ return {
72
+ ...set !== void 0 ? { set } : {},
73
+ ...deleteKeys !== void 0 ? { deleteKeys } : {}
74
+ };
75
+ };
76
+ const resolvePositiveNoteId = (value) => {
77
+ const noteId = Number(value);
78
+ if (!Number.isInteger(noteId) || noteId <= 0) {
79
+ throw createAppError(400, "INVALID_NOTE_ID", "A valid note id is required.");
80
+ }
81
+ return noteId;
82
+ };
83
+ const serializeNoteWriteBaseline = (note) => {
84
+ return {
85
+ id: String(note.id),
86
+ updatedAt: note.updatedAt instanceof Date ? note.updatedAt.toISOString() : note.updatedAt
87
+ };
88
+ };
89
+ const isNonNegativeInteger = (value) => {
90
+ return typeof value === "number" && Number.isInteger(value) && value >= 0;
91
+ };
92
+ const isPositiveInteger = (value) => {
93
+ return typeof value === "number" && Number.isInteger(value) && value > 0;
94
+ };
95
+ const resolveMarkdownWritePolicy = (value) => {
96
+ if (value === void 0) {
97
+ return void 0;
98
+ }
99
+ if (!isRecord(value)) {
100
+ throw createAppError(400, "INVALID_MARKDOWN_POLICY", "Markdown write policy must be an object.");
101
+ }
102
+ const policy = {};
103
+ if (value.allowNoop !== void 0) {
104
+ if (typeof value.allowNoop !== "boolean") {
105
+ throw createAppError(400, "INVALID_MARKDOWN_POLICY", "allowNoop must be a boolean.");
106
+ }
107
+ policy.allowNoop = value.allowNoop;
108
+ }
109
+ if (value.preserveTags !== void 0) {
110
+ if (!PRESERVATION_POLICIES.has(value.preserveTags)) {
111
+ throw createAppError(400, "INVALID_MARKDOWN_POLICY", "preserveTags must be boolean or warn.");
112
+ }
113
+ policy.preserveTags = value.preserveTags;
114
+ }
115
+ if (value.preserveReferences !== void 0) {
116
+ if (!PRESERVATION_POLICIES.has(value.preserveReferences)) {
117
+ throw createAppError(400, "INVALID_MARKDOWN_POLICY", "preserveReferences must be boolean or warn.");
118
+ }
119
+ policy.preserveReferences = value.preserveReferences;
120
+ }
121
+ return policy;
122
+ };
123
+ const resolvePatchSelector = (value) => {
124
+ if (!isRecord(value)) {
125
+ throw createAppError(400, "INVALID_PATCH_SELECTOR", "Patch selector must be an object.");
126
+ }
127
+ if (value.type === "exact_text") {
128
+ if (typeof value.text !== "string") {
129
+ throw createAppError(400, "INVALID_PATCH_SELECTOR", "Exact text selector requires text.");
130
+ }
131
+ return {
132
+ type: "exact_text",
133
+ text: value.text,
134
+ ...value.before !== void 0 ? {
135
+ before: resolveOptionalString(
136
+ value.before,
137
+ "INVALID_PATCH_SELECTOR",
138
+ "Selector before must be a string."
139
+ )
140
+ } : {},
141
+ ...value.after !== void 0 ? {
142
+ after: resolveOptionalString(
143
+ value.after,
144
+ "INVALID_PATCH_SELECTOR",
145
+ "Selector after must be a string."
146
+ )
147
+ } : {}
148
+ };
149
+ }
150
+ if (value.type === "match_candidate") {
151
+ const { text, matchIndex, lineStart, matchSha256, surroundingHash, positionHint } = value;
152
+ if (typeof text !== "string" || !isNonNegativeInteger(matchIndex) || !isPositiveInteger(lineStart) || typeof matchSha256 !== "string" || typeof surroundingHash !== "string") {
153
+ throw createAppError(400, "INVALID_PATCH_SELECTOR", "Match candidate selector has invalid fields.");
154
+ }
155
+ if (positionHint !== void 0 && !POSITION_HINTS.has(String(positionHint))) {
156
+ throw createAppError(400, "INVALID_PATCH_SELECTOR", "positionHint must be first or last.");
157
+ }
158
+ return {
159
+ type: "match_candidate",
160
+ text,
161
+ matchIndex,
162
+ lineStart,
163
+ matchSha256,
164
+ surroundingHash,
165
+ ...positionHint ? { positionHint } : {}
166
+ };
167
+ }
168
+ throw createAppError(400, "INVALID_PATCH_SELECTOR", "Unsupported patch selector type.");
169
+ };
170
+ const resolvePatchOperation = (value) => {
171
+ if (!isRecord(value)) {
172
+ throw createAppError(400, "INVALID_PATCH_OPERATION", "Patch operation must be an object.");
173
+ }
174
+ if (value.type === "replace") {
175
+ if (typeof value.replacement !== "string") {
176
+ throw createAppError(400, "INVALID_PATCH_OPERATION", "Replace operation requires replacement.");
177
+ }
178
+ return {
179
+ type: "replace",
180
+ replacement: value.replacement
181
+ };
182
+ }
183
+ if (value.type === "insert_before" || value.type === "insert_after") {
184
+ if (typeof value.insertion !== "string") {
185
+ throw createAppError(400, "INVALID_PATCH_OPERATION", "Insert operation requires insertion.");
186
+ }
187
+ return {
188
+ type: value.type,
189
+ insertion: value.insertion
190
+ };
191
+ }
192
+ throw createAppError(400, "INVALID_PATCH_OPERATION", "Unsupported patch operation type.");
193
+ };
194
+ const resolveAppendPlacement = (value) => {
195
+ if (value === void 0) {
196
+ return void 0;
197
+ }
198
+ if (!isRecord(value)) {
199
+ throw createAppError(400, "INVALID_APPEND_PLACEMENT", "Append placement must be an object.");
200
+ }
201
+ if (value.type === "end") {
202
+ return { type: "end" };
203
+ }
204
+ if (value.type === "after_heading") {
205
+ if (typeof value.heading !== "string") {
206
+ throw createAppError(400, "INVALID_APPEND_PLACEMENT", "after_heading placement requires heading.");
207
+ }
208
+ const { heading, level } = value;
209
+ if (typeof heading !== "string") {
210
+ throw createAppError(400, "INVALID_APPEND_PLACEMENT", "after_heading placement requires heading.");
211
+ }
212
+ if (level !== void 0 && (typeof level !== "number" || !Number.isInteger(level) || level < 1 || level > 6)) {
213
+ throw createAppError(400, "INVALID_APPEND_PLACEMENT", "Heading level must be an integer from 1 to 6.");
214
+ }
215
+ return {
216
+ type: "after_heading",
217
+ heading,
218
+ ...level !== void 0 ? { level } : {}
219
+ };
220
+ }
221
+ throw createAppError(400, "INVALID_APPEND_PLACEMENT", "Unsupported append placement type.");
222
+ };
223
+ const resolveSeparator = (value) => {
224
+ if (value === void 0) {
225
+ return void 0;
226
+ }
227
+ if (value === "\n" || value === "\n\n") {
228
+ return value;
229
+ }
230
+ throw createAppError(400, "INVALID_SEPARATOR", 'Separator must be "\\n" or "\\n\\n".');
231
+ };
232
+ const emitAuthoringEvent = (request, emit, event) => {
233
+ if (request.integration && request.integration.connectionId !== "mcp") {
234
+ const shared = {
235
+ noteId: event.noteId,
236
+ source: "integration",
237
+ connectionId: request.integration.connectionId
238
+ };
239
+ if (event.type === "mcp.note.deleted") emit({ ...shared, type: "integration.note.deleted" });
240
+ else
241
+ emit({
242
+ ...shared,
243
+ type: event.type === "mcp.note.created" ? "integration.note.created" : "integration.note.updated",
244
+ updatedAt: event.updatedAt
245
+ });
246
+ return;
247
+ }
248
+ emit(event);
249
+ };
250
+ const createCreateNoteHandler = (createNote = createNoteFromMarkdown, emitEvent = emitServerEvent) => {
251
+ return async (req, reply) => {
252
+ const { title, markdown, layout, properties } = req.body ?? {};
253
+ const resolvedProperties = resolveMetadataPropertyPatch(properties);
254
+ if (resolvedProperties?.deleteKeys !== void 0)
255
+ throw createAppError(400, "INVALID_NOTE_PROPERTIES", "Create accepts properties.set only.");
256
+ const resolvedLayout = resolveNoteLayout(layout);
257
+ if (typeof title !== "string") {
258
+ throw createAppError(400, "INVALID_NOTE_TITLE", "A note title is required.");
259
+ }
260
+ if (markdown !== void 0 && typeof markdown !== "string") {
261
+ throw createAppError(400, "INVALID_NOTE_MARKDOWN", "Note markdown must be a string.");
262
+ }
263
+ if (layout !== void 0 && resolvedLayout === null) {
264
+ throw createAppError(400, "INVALID_NOTE_LAYOUT", "Note layout must be one of narrow, wide, or full.");
265
+ }
266
+ try {
267
+ const note = await createNote({
268
+ title,
269
+ ...markdown !== void 0 ? { markdown } : {},
270
+ ...resolvedProperties ? { properties: resolvedProperties } : {},
271
+ ...resolvedLayout ? { layout: resolvedLayout } : {}
272
+ });
273
+ emitAuthoringEvent(req, emitEvent, {
274
+ type: "mcp.note.created",
275
+ source: "mcp",
276
+ noteId: note.id,
277
+ updatedAt: note.updatedAt
278
+ });
279
+ return reply.status(200).send({
280
+ created: true,
281
+ note
282
+ });
283
+ } catch (error) {
284
+ if (error instanceof InvalidNotePropertyInputError)
285
+ throw createAppError(400, "INVALID_NOTE_PROPERTIES", error.message);
286
+ if (error instanceof InvalidNoteAuthoringInputError) {
287
+ throw createAppError(400, "INVALID_NOTE_INPUT", error.message);
288
+ }
289
+ throw error;
290
+ }
291
+ };
292
+ };
293
+ const createNoteWriteBaselineHandler = (findNoteBaseline = async (id) => models.note.findUnique({
294
+ where: { id },
295
+ select: {
296
+ id: true,
297
+ updatedAt: true
298
+ }
299
+ })) => {
300
+ return async (req, reply) => {
301
+ const noteId = resolvePositiveNoteId(req.body?.id);
302
+ const note = await findNoteBaseline(noteId);
303
+ if (!note) {
304
+ throw createAppError(404, "NOTE_NOT_FOUND", "The requested note was not found.");
305
+ }
306
+ return reply.status(200).send({
307
+ note: serializeNoteWriteBaseline(note)
308
+ });
309
+ };
310
+ };
311
+ const createPatchNoteMarkdownHandler = (patchMarkdown = patchNoteMarkdown, emitEvent = emitServerEvent) => {
312
+ return async (req, reply) => {
313
+ const { id, expectedUpdatedAt, baseMarkdownSha256, intent, selector, operation, policy } = req.body ?? {};
314
+ const noteId = resolvePositiveNoteId(id);
315
+ const resolvedExpectedUpdatedAt = resolveOptionalString(
316
+ expectedUpdatedAt,
317
+ "INVALID_NOTE_VERSION",
318
+ "expectedUpdatedAt must be a string."
319
+ );
320
+ const resolvedBaseMarkdownSha256 = resolveOptionalString(
321
+ baseMarkdownSha256,
322
+ "INVALID_MARKDOWN_HASH",
323
+ "baseMarkdownSha256 must be a string."
324
+ );
325
+ if (typeof intent !== "string") {
326
+ throw createAppError(400, "INVALID_PATCH_INTENT", "Patch intent must be a string.");
327
+ }
328
+ const result = await patchMarkdown({
329
+ id: noteId,
330
+ expectedUpdatedAt: resolvedExpectedUpdatedAt,
331
+ baseMarkdownSha256: resolvedBaseMarkdownSha256,
332
+ intent,
333
+ selector: resolvePatchSelector(selector),
334
+ operation: resolvePatchOperation(operation),
335
+ policy: resolveMarkdownWritePolicy(policy)
336
+ });
337
+ if (result.status === "applied") {
338
+ emitAuthoringEvent(req, emitEvent, {
339
+ type: "mcp.note.updated",
340
+ source: "mcp",
341
+ noteId: result.note.id,
342
+ updatedAt: result.note.updatedAt
343
+ });
344
+ }
345
+ return reply.status(200).send(result);
346
+ };
347
+ };
348
+ const createAppendNoteMarkdownHandler = (appendMarkdown = appendNoteMarkdown, emitEvent = emitServerEvent) => {
349
+ return async (req, reply) => {
350
+ const { id, expectedUpdatedAt, baseMarkdownSha256, intent, insertion, placement, separator, policy } = req.body ?? {};
351
+ const noteId = resolvePositiveNoteId(id);
352
+ const resolvedExpectedUpdatedAt = resolveOptionalString(
353
+ expectedUpdatedAt,
354
+ "INVALID_NOTE_VERSION",
355
+ "expectedUpdatedAt must be a string."
356
+ );
357
+ const resolvedBaseMarkdownSha256 = resolveOptionalString(
358
+ baseMarkdownSha256,
359
+ "INVALID_MARKDOWN_HASH",
360
+ "baseMarkdownSha256 must be a string."
361
+ );
362
+ if (typeof intent !== "string") {
363
+ throw createAppError(400, "INVALID_APPEND_INTENT", "Append intent must be a string.");
364
+ }
365
+ if (typeof insertion !== "string") {
366
+ throw createAppError(400, "INVALID_APPEND_INSERTION", "Append insertion must be a string.");
367
+ }
368
+ const result = await appendMarkdown({
369
+ id: noteId,
370
+ expectedUpdatedAt: resolvedExpectedUpdatedAt,
371
+ baseMarkdownSha256: resolvedBaseMarkdownSha256,
372
+ intent,
373
+ insertion,
374
+ placement: resolveAppendPlacement(placement),
375
+ separator: resolveSeparator(separator),
376
+ policy: resolveMarkdownWritePolicy(policy)
377
+ });
378
+ if (result.status === "applied") {
379
+ emitAuthoringEvent(req, emitEvent, {
380
+ type: "mcp.note.updated",
381
+ source: "mcp",
382
+ noteId: result.note.id,
383
+ updatedAt: result.note.updatedAt
384
+ });
385
+ }
386
+ return reply.status(200).send(result);
387
+ };
388
+ };
389
+ const createReplaceNoteMarkdownHandler = (replaceMarkdown = replaceNoteMarkdown, emitEvent = emitServerEvent) => {
390
+ return async (req, reply) => {
391
+ const { id, expectedUpdatedAt, baseMarkdownSha256, intent, replacement, policy } = req.body ?? {};
392
+ const noteId = resolvePositiveNoteId(id);
393
+ const resolvedExpectedUpdatedAt = resolveOptionalString(
394
+ expectedUpdatedAt,
395
+ "INVALID_NOTE_VERSION",
396
+ "expectedUpdatedAt must be a string."
397
+ );
398
+ const resolvedBaseMarkdownSha256 = resolveOptionalString(
399
+ baseMarkdownSha256,
400
+ "INVALID_MARKDOWN_HASH",
401
+ "baseMarkdownSha256 must be a string."
402
+ );
403
+ if (typeof intent !== "string") {
404
+ throw createAppError(400, "INVALID_REPLACE_INTENT", "Replace intent must be a string.");
405
+ }
406
+ if (typeof replacement !== "string") {
407
+ throw createAppError(400, "INVALID_REPLACE_MARKDOWN", "Replacement markdown must be a string.");
408
+ }
409
+ const result = await replaceMarkdown({
410
+ id: noteId,
411
+ expectedUpdatedAt: resolvedExpectedUpdatedAt,
412
+ baseMarkdownSha256: resolvedBaseMarkdownSha256,
413
+ intent,
414
+ replacement,
415
+ policy: resolveMarkdownWritePolicy(policy)
416
+ });
417
+ if (result.status === "applied") {
418
+ emitAuthoringEvent(req, emitEvent, {
419
+ type: "mcp.note.updated",
420
+ source: "mcp",
421
+ noteId: result.note.id,
422
+ updatedAt: result.note.updatedAt
423
+ });
424
+ }
425
+ return reply.status(200).send(result);
426
+ };
427
+ };
428
+ const createUpdateNoteMetadataHandler = (updateMetadata = updateNoteMetadata, emitEvent = emitServerEvent) => {
429
+ return async (req, reply) => {
430
+ const { id, expectedUpdatedAt, title, layout, properties } = req.body ?? {};
431
+ const noteId = resolvePositiveNoteId(id);
432
+ const resolvedLayout = resolveNoteLayout(layout);
433
+ const resolvedProperties = resolveMetadataPropertyPatch(properties);
434
+ if (typeof expectedUpdatedAt !== "string") {
435
+ throw createAppError(400, "INVALID_NOTE_VERSION", "expectedUpdatedAt must be a string.");
436
+ }
437
+ if (title !== void 0 && typeof title !== "string") {
438
+ throw createAppError(400, "INVALID_NOTE_TITLE", "Note title must be a string.");
439
+ }
440
+ if (layout !== void 0 && resolvedLayout === null) {
441
+ throw createAppError(400, "INVALID_NOTE_LAYOUT", "Note layout must be one of narrow, wide, or full.");
442
+ }
443
+ if (title === void 0 && layout === void 0 && resolvedProperties === void 0) {
444
+ throw createAppError(400, "INVALID_NOTE_INPUT", "At least one metadata field must be provided.");
445
+ }
446
+ const result = await updateMetadata({
447
+ id: noteId,
448
+ expectedUpdatedAt,
449
+ ...title !== void 0 ? { title } : {},
450
+ ...resolvedLayout ? { layout: resolvedLayout } : {},
451
+ ...resolvedProperties !== void 0 ? { properties: resolvedProperties } : {}
452
+ });
453
+ if (result.status === "applied") {
454
+ emitAuthoringEvent(req, emitEvent, {
455
+ type: "mcp.note.updated",
456
+ source: "mcp",
457
+ noteId: result.note.id,
458
+ updatedAt: result.note.updatedAt
459
+ });
460
+ }
461
+ return reply.status(200).send(result);
462
+ };
463
+ };
464
+ const createDeleteNoteHandler = (deleteNote = deleteNoteById, emitEvent = emitServerEvent) => {
465
+ return async (req, reply) => {
466
+ const id = Number(req.body?.id);
467
+ if (!Number.isInteger(id) || id <= 0) {
468
+ throw createAppError(400, "INVALID_NOTE_ID", "A valid note id is required.");
469
+ }
470
+ const deletedNote = await deleteNote(id);
471
+ if (!deletedNote) {
472
+ throw createAppError(404, "NOTE_NOT_FOUND", "The requested note was not found.");
473
+ }
474
+ emitAuthoringEvent(req, emitEvent, {
475
+ type: "mcp.note.deleted",
476
+ source: "mcp",
477
+ noteId: deletedNote.id
478
+ });
479
+ return reply.status(200).send({
480
+ deleted: true,
481
+ note: deletedNote
482
+ });
483
+ };
484
+ };
485
+ export {
486
+ createAppendNoteMarkdownHandler,
487
+ createCreateNoteHandler,
488
+ createDeleteNoteHandler,
489
+ createNoteWriteBaselineHandler,
490
+ createPatchNoteMarkdownHandler,
491
+ createReplaceNoteMarkdownHandler,
492
+ createUpdateNoteMetadataHandler
493
+ };